/** * AgentHost — multiplexes many interactiveSession loops in one serve * process: dispatch new agents, reply to running ones, stream their * events to subscribers, and answer their permission/approval requests * remotely (the parked-Promise broker pattern). * * Unlike the legacy single-window desktop path (which runs in trust * mode), hosted agents default to permissionMode 'default' — permission * prompts and trade-plan approvals surface as ApprovalRequests a * dashboard client answers over the wire. * * Known v1 constraint: a few session-scoped subsystems keep module-level * state (monitor registry, scheduler/goal current-session slots, tool * dedup caches reset at session start). Concurrent hosted agents share a * process, so those degrade last-writer-wins across agents — dedup may * miss, monitors/goals are effectively single-agent features here. The * money paths (trade-plan gate, spend caps) take explicit session ids * and stay correct under concurrency. */ import { type ApprovalRequest } from '../agent/approvals.js'; import { type AgentRunState } from '../events/types.js'; import type { AgentConfig, StreamEvent } from '../agent/types.js'; export interface DispatchOptions { prompt: string; model?: string; label?: string; maxSpendUsd?: number; /** Default 'default' — permission prompts flow to the dashboard. */ permissionMode?: AgentConfig['permissionMode']; } export interface AgentSummary { sessionId: string; label: string; model: string; state: AgentRunState; startedAt: number; lastEventAt: number; pendingApprovals: ApprovalRequest[]; } export declare class AgentHost { private opts; private agents; constructor(opts: { workDir: string; chain: 'base' | 'solana'; apiUrl: string; defaultModel: string; debug?: boolean; }); private setState; /** Start a new hosted agent; resolves with its sessionId once known. */ dispatch(options: DispatchOptions): Promise; list(): AgentSummary[]; get(sessionId: string): AgentSummary | null; /** Queue a follow-up prompt for a hosted agent (idle → starts a turn). */ reply(sessionId: string, text: string): boolean; cancel(sessionId: string): boolean; respond(sessionId: string, requestId: string, choice: string, message?: string): boolean; subscribe(sessionId: string, cb: (event: StreamEvent) => void): (() => void) | null; /** Ring-buffer replay for peek panels. */ output(sessionId: string): StreamEvent[]; shutdown(): void; }