/** * Plan review in the chat. * * The host's `exit_plan_mode` presents a finished plan and leaves plan mode * once its human approves. It asks through `ctx.userQuestions` — the same * single-provider seam `ask_user_question` reaches for, owned by whichever UI * registered it first — so in a chat the tool either waits on a surface nobody * here is watching, or, with no provider composed at all, simply fails. That is * why the tool used to be denied outright, with the model told to seek approval * in prose. * * It is SHADOWED instead, exactly as the question tool is: an agent-scoped * registration of the same name, which the host's layered tool registry * resolves before the global one. The review becomes the card this channel * already asks with, and approval calls the plan service's own public switch, * so the state transition stays the host's rather than a copy of it. * * The plan itself does NOT ride the card. It is markdown a model wrote, and * this module's rule is that model text inside a card renders literally — which * would strip a plan of the headings and lists that make it readable. So the * plan is sent as an ordinary chat message first, at the same trust level as * every other assistant reply this channel delivers, and the card carries only * the decision. * @module dsh-lark-channel/plan */ import type { HostAgent, HostSessionEvent } from './host.ts'; /** The host tool this module shadows. */ export declare const PLAN_TOOL = "exit_plan_mode"; /** The plan service, narrowed to the one call this module makes. */ export interface HostPlanMode { /** * Switch one agent's plan mode. Public by the service's own contract — the * `/plan` command drives it through this same method. * @param agent - the agent whose session carries the state. * @param active - the state to move to. * @returns how the switch landed; mid-turn it queues to the next step. */ set(agent: HostAgent, active: boolean): 'committed' | 'queued' | 'cancelled' | 'noop'; } /** What the shadow needs from the bridge to ask, and to switch. */ export interface PlanReviewPorts { /** * Send the plan to the chat as an ordinary message. * @param sessionId - the agent's session, which names the chat. * @param plan - the plan markdown, exactly as the model wrote it. */ publish(sessionId: string, plan: string): Promise; /** * Ask the chat to decide, returning the labels chosen and anything typed. * @param sessionId - the agent's session, which names the chat. * @param heading - the plan's own heading, which titles the card. * @param signal - the tool execution's cancellation. */ review(sessionId: string, heading: string | undefined, signal: AbortSignal | undefined): Promise<{ readonly selected: readonly string[]; readonly custom?: string | undefined; }>; /** The plan service, when this deployment composed one. */ planMode(): HostPlanMode | undefined; } /** Whether plan mode is active, folded from the session log; the last one wins. */ export declare function planModeActive(events: readonly HostSessionEvent[]): boolean; /** * The review question this channel asks, in the shape its card takes. * @param heading - the plan's own first heading, when it has one. * @returns the question to hand the chat's question store. */ export declare function planReviewQuestion(heading: string | undefined): { readonly id: string; readonly header: string; readonly question: string; readonly options: readonly { readonly label: string; readonly description: string; }[]; }; /** The plan's first markdown heading, which titles the card. */ export declare function firstHeading(plan: string): string | undefined; /** * Build the agent-scoped `exit_plan_mode` that reviews in the chat. * * The refusals are thrown rather than returned, and their wording is the host * tool's: a tool result is what steers the model's next move, so "keep * planning" has to read to the model exactly as it would have from the tool * this one stands in for. * @param ports - how to publish the plan, ask, and switch the mode. * @returns the tool object, for `tools.register` on an agent's context. */ export declare function shadowPlanTool(ports: PlanReviewPorts): object; //# sourceMappingURL=plan.d.ts.map