import { type ChatTools, type ToolContext, type ResolvedToolContext } from "../shared/agent/tool.factory.js"; import type { IterationContext } from "./chat.prompt.modules.js"; /** * Orchestrator-specific behaviors that live in the agent loop itself * (not in the prompt or toolset). Each persona opts in explicitly. */ export interface ChatPersonaLoopBehaviors { /** * Detect hallucinated ```opportunity / ```intent_proposal code blocks in model * text, auto-invoke the corresponding tool, and strip unbacked blocks from the * final response. Only meaningful for personas whose toolset can legitimately * produce those blocks. */ hallucinationRecovery: boolean; } /** * Persona configuration injected into `ChatAgent.create()`. * * A persona bundles the three orchestrator-coupled seams of the chat runtime: * system-prompt construction, toolset creation, and loop behaviors. */ export interface ChatPersonaConfig { /** * Stable persona identifier. Matches the `conversations.persona` column value * for sessions driven by this persona. */ id: string; /** Builds the system prompt for each agent-loop iteration. */ buildSystemContent: (ctx: ResolvedToolContext, iterCtx: IterationContext) => string; /** Creates the persona's toolset bound to the resolved user context. */ createTools: (deps: ToolContext, preResolvedContext?: ResolvedToolContext) => Promise; /** * Optionally resolves a turn without an LLM or tools. Use only for narrow, * deterministic safety redirects derived entirely from iteration context. */ resolveDeterministicResponse?: (ctx: ResolvedToolContext, iterCtx: IterationContext) => string | null; /** Orchestrator-specific loop behaviors this persona opts into. */ loopBehaviors: ChatPersonaLoopBehaviors; } /** Persona id for the default orchestrator ("You are Index…"). */ export declare const ORCHESTRATOR_PERSONA_ID = "orchestrator"; /** * The orchestrator persona — exactly the pre-personafication wiring: * `buildSystemContent` from chat.prompt, `createChatTools` from tool.factory, * and all loop behaviors enabled. * * Both functions delegate lazily (arrow wrappers) instead of capturing the * imported symbols at module-load time. This preserves ESM live-binding * semantics: the pre-refactor code read `createChatTools` through its import * binding at call time, which is what lets test suites swap the module via * `mock.module` — a snapshot in this object literal would pin whichever * version was loaded first. */ export declare const ORCHESTRATOR_PERSONA: ChatPersonaConfig;