Agents: fix subagent spawn hook typing

This commit is contained in:
Gustavo Madeira Santana 2026-03-29 19:59:46 -04:00
parent 19113637e8
commit f9bf76067f
No known key found for this signature in database
2 changed files with 23 additions and 10 deletions

View File

@ -11,11 +11,10 @@ import {
} from "./subagent-announce.js";
import { __testing as subagentRegistryTesting } from "./subagent-registry.js";
import { __testing as subagentSpawnTesting } from "./subagent-spawn.js";
import type { SubagentLifecycleHookRunner } from "./subagent-spawn.js";
type SessionsSpawnTestConfig = ReturnType<(typeof import("../config/config.js"))["loadConfig"]>;
type SessionsSpawnHookRunner = ReturnType<
(typeof import("../plugins/hook-runner-global.js"))["getGlobalHookRunner"]
>;
type SessionsSpawnHookRunner = SubagentLifecycleHookRunner | null;
type CreateSessionsSpawnTool =
(typeof import("./tools/sessions-spawn-tool.js"))["createSessionsSpawnTool"];
export type CreateOpenClawToolsOpts = Parameters<CreateSessionsSpawnTool>[0];
@ -87,7 +86,7 @@ const hoisted = vi.hoisted(() => {
set configOverride(next: SessionsSpawnTestConfig) {
configOverride = next;
},
hookRunnerOverride: undefined as SessionsSpawnHookRunner,
hookRunnerOverride: null as SessionsSpawnHookRunner,
defaultRunSubagentAnnounceFlow,
runSubagentAnnounceFlowOverride: defaultRunSubagentAnnounceFlow,
};
@ -123,7 +122,7 @@ export function resetSessionsSpawnAnnounceFlowOverride(): void {
}
export function resetSessionsSpawnHookRunnerOverride(): void {
hoisted.state.hookRunnerOverride = undefined;
hoisted.state.hookRunnerOverride = null;
}
export function setSessionsSpawnHookRunnerOverride(next: SessionsSpawnHookRunner): void {

View File

@ -52,11 +52,16 @@ export { decodeStrictBase64 };
type SubagentSpawnDeps = {
callGateway: typeof callGateway;
getGlobalHookRunner: typeof getGlobalHookRunner;
getGlobalHookRunner: () => SubagentLifecycleHookRunner | null;
loadConfig: typeof loadConfig;
updateSessionStore: typeof updateSessionStore;
};
export type SubagentLifecycleHookRunner = Pick<
NonNullable<ReturnType<typeof getGlobalHookRunner>>,
"hasHooks" | "runSubagentSpawning" | "runSubagentSpawned" | "runSubagentEnded"
>;
const defaultSubagentSpawnDeps: SubagentSpawnDeps = {
callGateway,
getGlobalHookRunner,
@ -150,6 +155,14 @@ async function callSubagentGateway(
return await subagentSpawnDeps.callGateway(params);
}
function readGatewayRunId(response: Awaited<ReturnType<typeof callGateway>>): string | undefined {
if (!response || typeof response !== "object") {
return undefined;
}
const { runId } = response as { runId?: unknown };
return typeof runId === "string" && runId ? runId : undefined;
}
function loadSubagentConfig() {
return subagentSpawnDeps.loadConfig();
}
@ -264,7 +277,7 @@ function summarizeError(err: unknown): string {
}
async function ensureThreadBindingForSubagentSpawn(params: {
hookRunner: ReturnType<typeof getGlobalHookRunner>;
hookRunner: SubagentLifecycleHookRunner | null;
childSessionKey: string;
agentId: string;
label?: string;
@ -687,7 +700,7 @@ export async function spawnSubagentDirect(
workspaceDir: _workspaceDir,
...publicSpawnedMetadata
} = spawnedMetadata;
const response = await callSubagentGateway<{ runId: string }>({
const response = await callSubagentGateway({
method: "agent",
params: {
message: childTaskMessage,
@ -707,8 +720,9 @@ export async function spawnSubagentDirect(
},
timeoutMs: 10_000,
});
if (typeof response?.runId === "string" && response.runId) {
childRunId = response.runId;
const runId = readGatewayRunId(response);
if (runId) {
childRunId = runId;
}
} catch (err) {
if (attachmentAbsDir) {