/** * `PiAgentAdapter` — the in-process Pi agent-loop embed (T11761 · S2 · T11898). * * THE KEYSTONE of the Pi-harness work: the Pi agent loop runs **in-process** * inside the Cleo daemon as the body of the `SkillRunner` strategy slot, with * ZERO authority. It: * * - resolves its LLM ONLY through the E9 chokepoint (`resolveLLMForSystem` → * `ModelRunner`) via the Cleo-owned {@link createPiStreamFn} — `pi-ai`'s * registry env-fallback is never reached; * - touches the filesystem/shell ONLY through the deny-first * {@link GuardedExecutionEnv} (S1) bound to the injected guarded tool surface; * - reads its session identity from the daemon-stamped env (NEVER mints one); * - runs under {@link wrapPiCall} containment so a `process.exit()` from any Pi * code path becomes a thrown typed error, not a daemon-fatal exit; * - is gated behind a **default-OFF** feature flag ({@link isPiRunnerEnabled}). * * The `SkillRunner` slot (`SkillExecutorAdapterOptions.runner`, line 124 of * `skill-executor-adapter.ts`) CALLS this adapter via {@link createPiSkillRunner}; * the adapter is NOT hosted inside `defaultSkillRunner` (which stays untouched). * * Session durability is S3's concern: this subtask uses * {@link InMemorySessionStorage} (in-RAM, no DB writer, no lease) so the * read/stream path is buildable with ZERO write authority. * * @epic T10403 * @task T11761 * @task T11898 */ import type { GuardedToolSurface } from '@cleocode/contracts/tools/skill-executor'; import type { SkillRunner } from '../../skills/skill-executor-adapter.js'; import type { AgentToolRegistry } from '../../tools/agent-registry.js'; import { type ToolBudgetLimits } from '../../tools/dispatch.js'; import type { PiAgentResult, PiAgentRunContext } from './pi-types.js'; /** * Default-OFF feature flag controlling whether the Pi runner is constructed and * used. Reads `CLEO_PI_RUNNER_ENABLED === '1'`. The whole adapter is gated by * this — when disabled, {@link createPiSkillRunner} is never wired into the * dispatcher and `defaultSkillRunner` runs instead. * * @returns `true` when the Pi runner is explicitly enabled. */ export declare function isPiRunnerEnabled(): boolean; /** * Construction dependencies for {@link PiAgentAdapter}. */ export interface PiAgentAdapterDeps { /** * The {@link SystemOfUseLabel} this adapter resolves its LLM through (E9). * Defaults to `'task-executor'` when the SkillRunner closure builds the ctx. */ readonly system?: PiAgentRunContext['system']; /** * Project root for config + credential resolution. Defaults to * `process.cwd()` inside `resolveLLMForSystem`. */ readonly projectRoot?: string; /** * The frozen {@link AgentToolRegistry} whose tools the loop may CALL (T1740 · * AC6). When supplied, {@link run} builds a {@link ToolDispatchEngine} over it * + the injected guarded surface and projects executable `AgentTool`s onto the * loop, so a model tool-call actually runs through the dispatch engine. When * omitted the loop is text-only (no tools offered for execution) — the prior * behaviour, preserved so existing callers are unchanged. */ readonly registry?: AgentToolRegistry; /** * Optional per-run tool-call budget limits (T1740 · AC5) applied to the * dispatch engine: max call count, per-call timeout, total time. Omitted → * unbounded. */ readonly budget?: ToolBudgetLimits; } /** * In-process Pi agent-loop adapter with ZERO authority. * * {@link run} drives `pi-agent-core`'s `runAgentLoop` with a Cleo-owned streamFn * (Gate-13), an in-RAM session (no DB writer), and `wrapPiCall` exit/error * containment, then projects the terminal assistant message onto a * {@link PiAgentResult}. It NEVER throws past the containment boundary for a Pi * failure — a Pi error becomes a `{ status: 'failure', error }` result. */ export declare class PiAgentAdapter { #private; /** * Construct the adapter. * * `deps` supplies the construction-time defaults (resolution system + project * root) that {@link run} merges UNDER the per-call context — a field the call * supplies on `ctx` always wins. The factory {@link createPiSkillRunner} builds * the full `ctx` from these same deps; a direct caller may pass a partial `ctx` * and rely on the deps for the rest. * * @param deps - Resolution system + optional project root defaults. */ constructor(deps?: PiAgentAdapterDeps); /** * Run one Pi agent turn over the guarded tool surface. * * The `tools` surface is the injected {@link GuardedToolSurface}; the v0 * read/stream path threads it into the loop for future tool wiring (S3+ maps * Pi's `ExecutionEnv` onto it). Resolution + streaming are owned by * {@link createPiStreamFn} (Gate-13). The session id MUST already be * daemon-stamped (read from env in {@link createPiSkillRunner}); the adapter * never mints one. * * @param prompt - The user prompt for this turn. * @param tools - The deny-first guarded tool surface (injected, never built here). * @param ctx - The run context (system label + daemon-stamped identity + signal). * @returns The terminal {@link PiAgentResult}; never throws for a Pi failure. */ run(prompt: string, tools: GuardedToolSurface, ctx: PiAgentRunContext): Promise; } /** * Factory returning a {@link SkillRunner} whose body delegates to * {@link PiAgentAdapter.run}. * * This is the seam adaptation: the real `SkillRunner` shape is * `(skill, input) => Promise` — it carries NO free `prompt` * / `ctx`, so the closure DERIVES the prompt from the skill+context and reads * the daemon-stamped identity from env. When the env is un-stamped the runner * fails closed (it NEVER mints a session id). * * Wire it into the dispatcher behind the default-OFF flag: * ```ts * new SkillExecutorAdapter({ * runner: isPiRunnerEnabled() ? createPiSkillRunner(deps) : undefined, * }); * ``` * * @param deps - Adapter construction deps (resolution system + project root). * @returns A `SkillRunner` that runs the Pi loop in-process. */ export declare function createPiSkillRunner(deps?: PiAgentAdapterDeps): SkillRunner; //# sourceMappingURL=pi-agent-adapter.d.ts.map