mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 10:39:32 +01:00
fix(agent): keep the error code when a request fails without a message
Node 22 rejects a refused connection to a host that resolves to both ::1 and 127.0.0.1 with an AggregateError whose message is empty and whose code is ECONNREFUSED. The readiness fallback dropped that code, and the agent CLI's top-level error line and the MCP server's "Cannot reach Codeman" error printed nothing at all for it. Add describeRequestError() (message, else code, else a generic line) and use it at all three sites.
This commit is contained in:
1 parent
d25d71b595
commit
77ce4816a8
4 files changed
+54
-4
No files matched your search
+27
-1
@@ -30,6 +30,7 @@ import {
|
||||
buildSendBody,
|
||||
deleteRefusal,
|
||||
describeFailure,
|
||||
describeRequestError,
|
||||
httpRequest,
|
||||
inboxCell,
|
||||
inputRefusal,
|
||||
@@ -589,9 +590,34 @@ describe('agent spawn', () => {
|
||||
|
||||
expect(await agentSpawn(deps, { caseName: 'c', mode: 'claude', ready: true, timeoutMs: 1000 })).toBe(EXIT.error);
|
||||
expect(deps.out).toHaveLength(1);
|
||||
expect(JSON.parse(deps.out[0])).toEqual({ sessionId: OTHER, readinessError: 'Readiness request failed' });
|
||||
expect(JSON.parse(deps.out[0])).toEqual({ sessionId: OTHER, readinessError: 'request failed without a message' });
|
||||
expect(deps.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('keeps the error code when a refused connection rejects with an empty AggregateError', async () => {
|
||||
// Node 22 on a host resolving to ::1 and 127.0.0.1: message '', code ECONNREFUSED.
|
||||
const refused = Object.assign(new AggregateError([new Error('connect ECONNREFUSED ::1:3000')], ''), {
|
||||
code: 'ECONNREFUSED',
|
||||
});
|
||||
const deps = fakeDeps((options) => {
|
||||
if (options.path === '/api/v1/quick-start') return ok({ sessionId: OTHER });
|
||||
throw refused;
|
||||
}, true);
|
||||
|
||||
expect(await agentSpawn(deps, { caseName: 'c', mode: 'claude', ready: true, timeoutMs: 1000 })).toBe(EXIT.error);
|
||||
expect(JSON.parse(deps.out[0])).toEqual({ sessionId: OTHER, readinessError: 'ECONNREFUSED' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('describeRequestError', () => {
|
||||
it('prefers the message, then the code, then a generic line', () => {
|
||||
expect(describeRequestError(new Error('socket hang up'))).toBe('socket hang up');
|
||||
expect(describeRequestError(Object.assign(new AggregateError([], ''), { code: 'ECONNREFUSED' }))).toBe(
|
||||
'ECONNREFUSED'
|
||||
);
|
||||
expect(describeRequestError(new Error(''))).toBe('request failed without a message');
|
||||
expect(describeRequestError('')).toBe('request failed without a message');
|
||||
});
|
||||
});
|
||||
|
||||
describe('session id prefixes', () => {
|
||||
|
||||
@@ -248,6 +248,17 @@ describe('protocol: both eras', () => {
|
||||
expect(result.isError).toBe(true);
|
||||
expect(result.content[0].text).toContain('CODEMAN_API_URL');
|
||||
});
|
||||
|
||||
it('a refused connection with an empty AggregateError still names the error code', async () => {
|
||||
const refused: ApiRequest = async () => {
|
||||
throw Object.assign(new AggregateError([new Error('connect ECONNREFUSED ::1:9')], ''), { code: 'ECONNREFUSED' });
|
||||
};
|
||||
const { out, send } = server(config(), { request: refused, calls: [] });
|
||||
await send({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'list_sessions', arguments: {} } });
|
||||
const result = (out[0] as { result: { isError: boolean; content: Array<{ text: string }> } }).result;
|
||||
expect(result.isError).toBe(true);
|
||||
expect(result.content[0].text).toContain('Cannot reach Codeman at http://127.0.0.1:9: ECONNREFUSED.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('tool definitions', () => {
|
||||
|
||||
Reference in new issue
Block a user