import type { PlanManager } from '../../manager/plan/lifecycle.js'; import type { PendingAnswers, QuestionParkRecorder } from '../../runtime/query/question-park.js'; import type { CompletionInbox } from '../../scheduler/completion-inbox.js'; import type { AgentRuntimeContext } from '../../types/agent/base.js'; import type { TaskScheduler } from '../../types/agent/scheduler.js'; import type { ResumeHandler } from '../../types/hitl/index.js'; import type { SessionId, TaskId, TurnId } from '../../types/ids/index.js'; import type { TaskStore } from '../../types/task/index.js'; import type { ToolDefinition } from '../../types/tool/index.js'; export { ASK_USER_QUESTION_TOOL_NAME } from './ask-user-question.js'; export type TaskLaunchedCallback = (agentTaskId: TaskId, meta: { agentId: string; description: string; planTaskId?: string; /** * The assistant `tool_use_id` that dispatched this task. * Threaded from `ToolContext.toolUseId` so the runtime can * later emit a canonical `tool_result` content block bound * to the same id when the background task completes. */ originalToolUseId?: string; }) => void; export interface CoordinatorToolsOptions { gateway: TaskScheduler; workingDirectory: string; runtimeContext?: AgentRuntimeContext; allowedAgentIds: string[]; /** * May this turn delegate at all? Defaults to true. * * Same field, same name, as SupervisorAgentConfig.allowDelegation — the * name is kept identical deliberately. This options bag already renames * agentIds to allowedAgentIds, and a second rename on the road between * the config and the decision would make the road untraceable. */ allowDelegation?: boolean; taskStore?: TaskStore; /** * Called when a plan is APPROVED, so the turn can leave plan mode. * * A callback rather than a store handle, because what "leaving plan * mode" means belongs to whoever owns the mode — a turn flipping its own * box, a host persisting to a topic record, both, or neither. This file * knows only that approval happened. */ onPlanApproved?: () => Promise | void; /** * The session and turn these tools act for: a delegated plan step is * filed as a task of this session, created by this turn, and a question * park is addressed to them. */ sessionId?: SessionId; turnId?: TurnId; getPlanManager?: () => PlanManager | undefined; onTaskLaunched?: TaskLaunchedCallback; /** * Where a completion goes when no call is left waiting for it. * * These tools claim a completion the moment they hand it to the model as a * `tool_result`; anything unclaimed is delivered to the transcript as a * notification instead. Without an inbox the tools still work and the * blocking path is unchanged — only the abandoned and background * completions go unheard, which is the behaviour before this existed. */ completionInbox?: CompletionInbox; /** * HITL park channel for `ask_user_question`. The tool is registered * only when `resumeHandler`, `sessionId` and `turnId` are all present — * without a handler there is no one to route the question to, and * without the turn the park request cannot be addressed. */ resumeHandler?: ResumeHandler; /** * Makes a question park durable and visible. * * Without it the park exists only as a suspended `await` inside one * process — nothing on disk says a human owes this turn an answer, and a * remote host cannot observe the question at all. Optional because a * host driving the tools directly may have no checkpoint store. */ questionParks?: QuestionParkRecorder; /** * Answers carried in from a resumed turn, keyed by `questionId`. * * Consulted BEFORE the park handler: a re-entered `ask_user_question` * must return the answer that was already given rather than asking * again. Without it, resuming re-parks a question the user answered — * and in a headless resume that either deadlocks or auto-answers with * the no-consent sentinel, discarding the real answer. */ pendingAnswers?: PendingAnswers; } /** * How long a coordinator tool may wait on a delegated agent. * * The executor's own default is two minutes, sized for a file read or a * test run, and its docstring says outright that a tool which legitimately * runs longer declares its own. This one runs an entire agent, and did not. * * Measured on real traffic: three delegated children took 4m21s, 5m58s and * 8m04s; all three parents timed out at 120s. The children were never * killed — only the parent's wait was — so the blocking path was not * occasionally missed, it was structurally unreachable, and the model was * left polling a listing because that was the only move left to it. * * An hour rather than "a bit more than eight minutes" because a generic * stopwatch is the wrong instrument for a child that is making progress: * a failure should come from what the child is doing, not from the clock * the parent happens to be holding. Peer runtimes agree — the ones that * bound a delegated child at all land on an hour, and several impose no * wall-clock bound whatsoever, bounding turns or depth instead. * * A wedged child is still caught, an hour later, and the turn budget and * iteration ceiling both still apply above this. */ export declare const DELEGATION_TIMEOUT_MS: number; /** * How long a delegated worker may say nothing before the wait gives up. * * The hour above answers "how long is too long". It cannot also answer * "how quiet is too quiet", because it has to be generous enough for a * child doing real work — which makes it useless as a stall detector. A * worker wedged in its second minute held the supervisor for another * fifty-eight under that number alone. * * Five minutes of silence, because a worker between tool calls can be * quiet for a while legitimately — a long model turn emits nothing until * it starts streaming — and the cost of guessing low is killing a wait on * a worker that was fine. Guessing high only delays a diagnosis. Set * `NAMZU_DELEGATION_IDLE_MS` to change it. * * Only armed when the gateway can report progress at all; see * `TaskScheduler.onTaskProgress`. */ export declare const DELEGATION_IDLE_MS: number; export declare function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefinition[]; //# sourceMappingURL=index.d.ts.map