import type { PilotSwarmClientOptions, ManagedSessionConfig, SerializableSessionConfig, PilotSwarmSessionInfo, UserInputHandler, SessionOwnerInfo, PromptAttachmentRef } from "./types.js"; import type { SessionCatalog, SessionEvent, SessionVisibility } from "./cms.js"; import type { MessageSender } from "./message-sender.js"; import { type PilotSwarmWebOptions } from "./web/api-connection.js"; /** * PilotSwarmClient — pure client-side session handle. * * Talks to duroxide only through the Client API (startOrchestration, * enqueueEvent, waitForStatusChange, getStatus). Does NOT own * SessionManager, Runtime, or CopilotSession. * * Creates its own duroxide Client and CMS catalog from the store URL. * Completely independent of PilotSwarmWorker. */ /** * Project a full (in-memory) session config down to the serializable shape * the durable orchestration input carries. * * ONE function on purpose: this exact projection is (a) persisted to the * catalog row at create (migration 0072 `creation_config`) and (b) built at * orchestration start. Before 0072 the start-side copy was the only one, fed * from an in-memory map — and when the first message landed on a different * API-server process than the create, the map missed and the orchestration * started from an empty config: no agent binding, no system message, no tool * names. Persisting the SAME projection at create is what makes the start * reproducible from durable state on any process. * * reasoningEffort was historically omitted from the start-side copy, which * silently dropped the user's creation-time effort on the worker side — * this seam has eaten fields before, which is why it is now one function. * * @internal exported for tests */ export declare function projectSerializableSessionConfig(fullConfig: ManagedSessionConfig | undefined, fallbackWaitThreshold: number | undefined): SerializableSessionConfig; export declare class PilotSwarmClient { private config; private _catalog; private _factStore; private _modelProviderTypes; private duroxideClient; private sessionConfigs; /** parentSessionId for sub-agent sessions. */ private parentSessionIds; /** nestingLevel for sub-agent sessions. */ private nestingLevels; /** System session flag. */ systemSessions: Set; private activeOrchestrations; private lastSeenStatusVersion; private lastSeenIteration; private lastSeenResponseVersion; private activeWaitControllers; private activeWaitPromises; private started; /** Tracks agentId bound to each session (for policy and title prefixing). */ private sessionAgentIds; /** Effective session policy (set via config from worker). */ private get _sessionPolicy(); /** Allowed agent names (set via config from worker). */ private get _allowedAgentNames(); constructor(options: PilotSwarmClientOptions | PilotSwarmWebOptions); createSession(config?: ManagedSessionConfig & { sessionId?: string; onUserInputRequest?: UserInputHandler; /** Names of tools registered on the worker via worker.registerTools(). */ toolNames?: string[]; /** If this session is a sub-agent, the parent session ID. */ parentSessionId?: string; /** Nesting level for sub-agent depth tracking. */ nestingLevel?: number; /** Agent ID to bind this session to (for policy validation and title prefixing). */ agentId?: string; /** Authenticated owner to associate with the new session. */ owner?: SessionOwnerInfo | null; /** Optional visual session group assignment. */ groupId?: string | null; /** Sharing level for a new ROOT session (children resolve through their root). */ visibility?: SessionVisibility | null; }): Promise; /** * Create a session bound to a named agent. * * Validates that the agent exists in the loaded (non-system) agent list. * Sets the agentId on the session and applies a prefixed title: * `"Agent Title: "`. * * @throws If the agent is not found, is a system agent, or policy rejects it. */ createSessionForAgent(agentName: string, opts?: { model?: string; reasoningEffort?: ManagedSessionConfig["reasoningEffort"]; contextTier?: ManagedSessionConfig["contextTier"]; onUserInputRequest?: UserInputHandler; toolNames?: string[]; title?: string; splash?: string; splashMobile?: string; initialPrompt?: string; owner?: SessionOwnerInfo | null; groupId?: string | null; visibility?: SessionVisibility | null; }): Promise; /** * Create a system session (e.g. Sweeper Agent). * * System sessions are protected from deletion and appear with distinct * styling in the TUI. They use the same orchestration as regular sessions. * Idempotent: if a system session already exists, it is resumed. */ createSystemSession(config: { model?: string; reasoningEffort?: ManagedSessionConfig["reasoningEffort"]; systemMessage?: string; toolNames?: string[]; title?: string; onUserInputRequest?: UserInputHandler; }): Promise; resumeSession(sessionId: string, config?: ManagedSessionConfig & { onUserInputRequest?: UserInputHandler; }): Promise; private _syncTurnCursors; listSessions(): Promise; deleteSession(sessionId: string): Promise; /** * Delete a single session row: CMS soft-delete, session-fact cleanup, * best-effort duroxide cancel. No descendant handling — deleteSession() * cascades before calling this. */ private _deleteOneSession; /** * Cancel one or more queued (durable) pending messages for a session by * their UI-generated client message ids. Convenience wrapper around * `PilotSwarmSession.cancelPendingMessage`. */ cancelPendingMessage(sessionId: string, clientMessageIds: string[]): Promise; start(): Promise; private _resolveCreationModel; stop(): Promise; /** * Creation and first send may land on different API processes. Restore the * child boundary from durable lineage before starting an orchestration; * otherwise the child silently becomes a root with a reset nesting budget. */ private _restoreLineageForStart; /** @internal — ensure orchestration exists, update CMS, enqueue prompt. */ private _ensureOrchestrationAndSend; /** @internal */ _startAndWait(sessionId: string, prompt: string, onUserInput: UserInputHandler | undefined, timeout?: number, onIntermediateContent?: (content: string) => void, opts?: { bootstrap?: boolean; signal?: AbortSignal; requiredTool?: string; }): Promise; /** @internal */ _startTurn(sessionId: string, prompt: string, opts?: { bootstrap?: boolean; requiredTool?: string; clientMessageIds?: string[]; sender?: MessageSender; attachments?: PromptAttachmentRef[]; }): Promise; /** @internal */ _getDuroxideClient(): any; /** @internal */ _getCatalog(): SessionCatalog; /** @internal — exposed for PilotSwarmSession.wait() */ _waitForTurnResult_external(orchestrationId: string, sessionId: string, onUserInput: UserInputHandler | undefined, timeout: number, signal?: AbortSignal): Promise; private _createWaitSignal; /** @internal */ private _getLatestResponse; /** @internal */ _getSessionInfo(sessionId: string, options?: { includeResultSource?: boolean; }): Promise; /** @internal */ private _waitForTurnResult; } /** * PilotSwarmSession — session handle. * Mirrors CopilotSession API, routes through duroxide orchestration. * * Event delivery: * on(eventType, handler) — polls CMS session_events table for new events. * on(handler) — catch-all, receives every event type. * Returns unsubscribe function. Polling starts on first subscription. */ export type SessionEventHandler = (event: SessionEvent) => void; export declare class PilotSwarmSession { readonly sessionId: string; private client; private onUserInput?; lastOrchestrationId?: string; private handlers; private lastSeenSeq; private pollTimer; private polling; private static POLL_INTERVAL; /** @internal */ constructor(sessionId: string, client: PilotSwarmClient, onUserInput?: UserInputHandler); sendAndWait(prompt: string, timeout?: number, onIntermediateContent?: (content: string) => void, opts?: { signal?: AbortSignal; requiredTool?: string; }): Promise; send(prompt: string, opts?: { bootstrap?: boolean; requiredTool?: string; clientMessageIds?: string[]; sender?: MessageSender; attachments?: PromptAttachmentRef[]; }): Promise; wait(timeout?: number, opts?: { signal?: AbortSignal; }): Promise; /** * Subscribe to session events. * * Overloads: * on(eventType, handler) — typed subscription (e.g. "assistant.message") * on(handler) — catch-all subscription * * Returns an unsubscribe function. Polling starts automatically. */ on(eventType: string, handler: SessionEventHandler): () => void; on(handler: SessionEventHandler): () => void; sendEvent(eventName: string, data: unknown): Promise; /** * Cancel one or more queued (durable) pending messages by their * UI-generated client message ids. * * Enqueues a tombstone envelope on the same durable messages queue. The * orchestration drain marks the matching ids as cancelled and drops any * matching prompts before they reach the LLM. Already-processed messages * are unaffected (no-op). Idempotent and safe to call repeatedly. */ cancelPendingMessage(clientMessageIds: string[]): Promise; abort(): Promise; destroy(): Promise; /** Get a provider-capped latest page of persisted events from CMS. Use event paging to drain complete history. */ getMessages(limit?: number): Promise; getInfo(): Promise; private _startPolling; private _stopPolling; private _poll; private _dispatch; } //# sourceMappingURL=client.d.ts.map