mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
fix(mcp): start_session returns the worker's id when only the readiness call fails (#615 merge-time fix)
After quick-start succeeded, a failed wait-output readiness call (a 429 from the waiter cap, a network blip) became an isError result without the session id, so the model could neither prompt nor delete the worker it had just started, and a retry started a second one. It now returns the id with ready: null and a note, as `codeman agent spawn` does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
35e21dd676
commit
71647e090d
2 files changed
+31
-2
No files matched your search
+17
-2
@@ -624,13 +624,28 @@ export function createToolRunner(deps: ToolRunnerDeps) {
|
||||
let note = 'Ready for send_prompt.';
|
||||
const mark = composerReadyMark(mode);
|
||||
if (waitReady && mark) {
|
||||
const { wait } = await waitCall(
|
||||
let wait: WaitResult | undefined;
|
||||
try {
|
||||
({ wait } = await waitCall(
|
||||
data.sessionId,
|
||||
{ match: mark, from: 'buffer' },
|
||||
'wait-output',
|
||||
timeoutMs,
|
||||
signal
|
||||
);
|
||||
));
|
||||
} catch (err) {
|
||||
// The worker is already running: a failed readiness CALL (429, a network blip)
|
||||
// must still hand the model its id, or it cannot prompt or delete it.
|
||||
if (!(err instanceof ToolError)) throw err;
|
||||
return structuredResult({
|
||||
session_id: data.sessionId,
|
||||
mode,
|
||||
case: data.caseName ?? caseName,
|
||||
case_path: data.casePath ?? '',
|
||||
ready: null,
|
||||
note: `Started, but the readiness check failed (${err.message}): read_output with source terminal before send_prompt.`,
|
||||
});
|
||||
}
|
||||
const outcome = waitOutcome(wait);
|
||||
if (outcome === 'exited' || outcome === 'ended') {
|
||||
ready = false;
|
||||
|
||||
@@ -366,6 +366,20 @@ describe('the tools', () => {
|
||||
expect(result.structured).toMatchObject({ session_id: MINE, ready: true });
|
||||
});
|
||||
|
||||
it('start_session still returns the session id when only the readiness call fails', async () => {
|
||||
const busy = fakeCodeman(undefined, {
|
||||
'GET /api/v1/sessions/*': () => ({
|
||||
status: 429,
|
||||
json: { success: false, error: 'too many waiters', errorCode: 'WAIT_CAPACITY' },
|
||||
text: '',
|
||||
}),
|
||||
});
|
||||
const result = await runner(config(), busy).tools.run('start_session', { case: 'review-2', mode: 'claude' });
|
||||
expect(result.isError).toBeFalsy();
|
||||
expect(result.structured).toMatchObject({ session_id: MINE, ready: null });
|
||||
expect(String(result.structured?.note)).toContain('readiness check failed');
|
||||
});
|
||||
|
||||
it('send_prompt refuses a newline or control byte before any request', async () => {
|
||||
const { tools, calls } = runner(config());
|
||||
for (const text of ['line one\nline two', 'esc \u001b[A', 'tab\there']) {
|
||||
|
||||
Reference in new issue
Block a user