mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-06 03:14:00 +00:00
fix(tools): reject cancellation after async interception
This commit is contained in:
1 parent
0796efe603
commit
fffbe67b66
2 files changed
+47
-2
No files matched your search
@@ -39,3 +39,40 @@ test('cancelled catalog calls cannot execute or return late results', async () =
|
|||||||
await assert.rejects(pending, { name: 'AbortError' });
|
await assert.rejects(pending, { name: 'AbortError' });
|
||||||
assert.equal(calls, 1);
|
assert.equal(calls, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('cancellation during an awaited interceptor cannot publish its late result', async () => {
|
||||||
|
const controller = new AbortController();
|
||||||
|
const reason = new Error('interceptor caller canceled');
|
||||||
|
let calls = 0;
|
||||||
|
const action = defineTool({
|
||||||
|
name: 'fixture_intercepted_action',
|
||||||
|
kind: 'action',
|
||||||
|
title: 'Fixture',
|
||||||
|
description: 'Offline fixture',
|
||||||
|
inputSchema: { type: 'object' },
|
||||||
|
run: async () => {
|
||||||
|
calls++;
|
||||||
|
return { summary: 'completed action', data: {} };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const catalog = composeCatalog({
|
||||||
|
tools: [action],
|
||||||
|
interceptors: [
|
||||||
|
async (call, next) => {
|
||||||
|
const result = await next(call);
|
||||||
|
await Promise.resolve();
|
||||||
|
controller.abort(reason);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
await assert.rejects(
|
||||||
|
catalog.call(
|
||||||
|
'fixture_intercepted_action',
|
||||||
|
{},
|
||||||
|
{ signal: controller.signal },
|
||||||
|
),
|
||||||
|
(error) => error === reason,
|
||||||
|
);
|
||||||
|
assert.equal(calls, 1, 'completed actions are not rolled back or rerun');
|
||||||
|
});
|
||||||
+10
-2
@@ -169,13 +169,21 @@ export function composeCatalog({
|
|||||||
);
|
);
|
||||||
const index = new Map(available.map((tool) => [tool.name, tool]));
|
const index = new Map(available.map((tool) => [tool.name, tool]));
|
||||||
|
|
||||||
const invoke = (name, args, signal, parent) => {
|
const invoke = async (name, args, signal, parent) => {
|
||||||
|
signal?.throwIfAborted();
|
||||||
const tool = index.get(name);
|
const tool = index.get(name);
|
||||||
if (!tool)
|
if (!tool)
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new ToolError('unsupported', `No tool named ${name} is available`),
|
new ToolError('unsupported', `No tool named ${name} is available`),
|
||||||
);
|
);
|
||||||
return chain({ tool, args, signal, ...(parent ? { parent } : {}) });
|
const result = await chain({
|
||||||
|
tool,
|
||||||
|
args,
|
||||||
|
signal,
|
||||||
|
...(parent ? { parent } : {}),
|
||||||
|
});
|
||||||
|
signal?.throwIfAborted();
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
const execute = async ({ tool, args, signal }) => {
|
const execute = async ({ tool, args, signal }) => {
|
||||||
signal?.throwIfAborted();
|
signal?.throwIfAborted();
|
||||||
|
|||||||
Reference in new issue
Block a user