summaryrefslogtreecommitdiffhomepage
path: root/packages/tool-shell/src/shell.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-24 14:10:03 +0900
committerAdam Malczewski <[email protected]>2026-06-24 14:10:03 +0900
commitdabcbc79831052effc6ce990021feee07d661f7e (patch)
tree3e74e16f36d6a675abe676f0d04ca169f65f0a71 /packages/tool-shell/src/shell.ts
parentb58fb8373a1f7311cead23aa9a4d1fcd6927634f (diff)
downloaddispatch-dabcbc79831052effc6ce990021feee07d661f7e.tar.gz
dispatch-dabcbc79831052effc6ce990021feee07d661f7e.zip
fix(kernel+tool-shell): abort hanging tool calls without bricking the conversation
kernel: executeToolCall now races tool.execute against the abort signal via Promise.race; on abort resolves (not rejects) with an "Aborted" result so the step completes normally → finishReason "aborted" → turn seals cleanly (done event) → finally clears activeTurns → conversation freed, next message accepted. run-turn strips tool-call chunks from the assistant message on abort (keeps text/thinking) and omits tool-result messages to avoid persisting dangling tool calls that would 400 the provider next turn. tool-shell: realSpawn spawns detached (own process group); on abort AND timeout kills the entire group (process.kill(-pgid, SIGKILL)) and resolves immediately — no child.on("close") dependency, so a grandchild holding the pipes can't stall the spawn promise or leak. Also: ORCHESTRATOR.md migrated to dispatch CLI summon mechanism; .skills summary; bin/sync-env PATH injection; frontend handoff docs. 1453 vitest pass · tsc -b EXIT 0 · biome clean.
Diffstat (limited to 'packages/tool-shell/src/shell.ts')
-rw-r--r--packages/tool-shell/src/shell.ts5
1 files changed, 2 insertions, 3 deletions
diff --git a/packages/tool-shell/src/shell.ts b/packages/tool-shell/src/shell.ts
index d96d73e..cc76bca 100644
--- a/packages/tool-shell/src/shell.ts
+++ b/packages/tool-shell/src/shell.ts
@@ -12,6 +12,7 @@ export interface ValidatedArgs {
export interface SpawnResult {
readonly exitCode: number | null;
readonly timedOut: boolean;
+ readonly aborted: boolean;
}
export type SpawnShell = (params: {
@@ -139,7 +140,6 @@ export function createRunShellTool(deps: {
};
let spawnResult: SpawnResult;
- let aborted = false;
try {
spawnResult = await deps.spawn({
@@ -154,7 +154,6 @@ export function createRunShellTool(deps: {
});
} catch (err: unknown) {
if (ctx.signal.aborted) {
- aborted = true;
return buildResult({
exitCode: null,
timedOut: false,
@@ -172,7 +171,7 @@ export function createRunShellTool(deps: {
return buildResult({
exitCode: spawnResult.exitCode,
timedOut: spawnResult.timedOut,
- aborted,
+ aborted: spawnResult.aborted,
output,
cap,
});