/** * personal-capture/spawn-contract.ts * * What an agent answering a conversational turn is given, and what it is told. * * ## The defect this closes * * A message arriving on a channel is answered by an agent the shared-session * continuation runner spawns with `restrictTools: true` and no tool list. * `AgentManager.deriveEffectiveTools` reads that as "use ONLY the tools named", * and none were, so the effective list was empty and * `AgentOrchestrator.buildScopedRegistry` handed the run a registry with * nothing in it. The agent could emit text and do nothing else, which is why * an itinerary pasted into Telegram was answered warmly and stored nowhere. * * So this file names the tools such a turn actually needs, and the instruction * that makes recording part of answering rather than something to offer. * * ## Why this list and not the default one * * A conversational turn is not a work chain. `conversation-continuation.ts` * already decides that a channel follow-up gets an answer rather than a * write-review-fix-confirm chain, and this list keeps that promise: no `write`, * no `edit`, no `exec`. Nothing here can start a workstream or touch the * project tree. What it can do is read, look things up, and record what the * owner just said about himself. * * Hoisted here rather than written at each spawn site because the daemon and * the SDK's own runtime both spawn these turns, and a capability that exists * on one of those and not the other is the same defect with a smaller * blast radius. */ import { type CaptureAuthorityDecision } from './authority.js'; /** * The tools a conversational turn is spawned with. * * `profile` is the capture tool, occasions, plans and profile facts. * `read`, `find` and `fetch` are what answering a question ordinarily takes. */ export declare const CONVERSATIONAL_TURN_TOOLS: readonly string[]; /** * What to do when the owner answers a reminder. * * The gap this closes: occasion nudges are pushed to Telegram and to the agent's * own conversation, so the reply to one is a SENTENCE. Nothing ever turned a * sentence into a record, the only thing that could write an acknowledgement * was a CLI/webui verb, so the owner could answer a nudge, and answer it again, * and from the sweep's side the owner had said nothing at all. It kept asking. * * Exported so a test can pin the wording. This is behaviour, not decoration. */ export declare const OCCASION_ACKNOWLEDGEMENT_INSTRUCTION: readonly string[]; /** * The remedy ladder for "your reminders are bothering me". * * The defect this closes: the owner complained, angrily, about hourly * reminders for ONE occasion, and the turn set `occasions.enabled = false`, * which also silenced their spouse's birthday, a gift-giving occasion with a * shopping runway, and they would not have found out until it was too late to * matter. * * The general rule underneath it is worth more than the specific fix: the size * of a remedy is matched to the size of a complaint, and turning a whole * capability off is never how one noisy item gets quieter. */ export declare const OCCASION_COMPLAINT_LADDER: readonly string[]; export interface ConversationalSpawnContextInput { /** The shared session this turn belongs to. */ readonly sessionId: string; /** The surface the message arrived on, when it arrived on one. */ readonly surfaceKind?: string | undefined; /** Whether this turn is allowed to write to the profile, and why/why not. */ readonly capture?: { readonly canCapture: boolean; readonly reason: string; } | undefined; } /** * The instruction block for a conversational turn. * * Written as standing behaviour rather than a suggestion, because "would you * like me to save that?" is the failure mode being corrected: the owner had * already told it the thing, and being asked again is not service. * * The last paragraph is the occasions doctrine applied here, nothing * unresolved drops silently. A capture that could not complete has to be said * out loud in the reply, in the same breath as the answer. */ export declare function buildConversationalTurnContext(input: ConversationalSpawnContextInput): string; /** The part of a shared-session input this contract reads. */ export interface ConversationalTurnInputLike { readonly sessionId: string; readonly surfaceKind?: string | undefined; readonly surfaceId?: string | undefined; /** Present when the turn came in over a configured route. See CaptureChannelIdentity.routed. */ readonly routeId?: string | undefined; } /** The settings the authority decision reads, supplied live by the caller. */ export interface ConversationalTurnConfigReader { get(key: 'profile.ownerChannels' | 'occasions.nudgeChannel'): string; } /** * The spawn-input fragment for a conversational turn: the tools, the * instruction, and the bound write authority. * * Spread into the `agentManager.spawn` call in a continuation runner. It * REPLACES the bare `context: 'shared-session:'` and the empty tool list * that `restrictTools: true` with no `tools` produced, those two together are * why a channel turn could neither record anything nor knew it was supposed to. * * `tools` is set explicitly alongside `restrictTools: true`, so the restriction * still means "only these", it just now names some. */ export declare function conversationalTurnSpawnOptions(input: ConversationalTurnInputLike, options?: { readonly configReader?: ConversationalTurnConfigReader | undefined; }): { readonly tools: string[]; readonly restrictTools: true; readonly context: string; readonly captureAuthority: CaptureAuthorityDecision; }; //# sourceMappingURL=spawn-contract.d.ts.map