import { ct as AssistantMessageEventStream, f as __createPiAiRuntimeRegistry } from "./pi-ai-BHgA3JWd.mjs"; import { N as Theme, p as ExtensionRunner } from "./pi-coding-agent-Cas0oHSx.mjs"; import { t as FileCredentialStore } from "./oauth-bridge-hOnT3acY.mjs"; import { i as GeneratedRuntimeManifest } from "./types-B9VBF8le.mjs"; import { EventEmitter } from "node:events"; import { AsyncLocalStorage } from "node:async_hooks"; import { ContentBlock } from "@deepseek-ai/dsh-llm"; import { Context } from "@deepseek-ai/cordis"; //#region src/capability.d.ts type PackageHealthStatus = 'ok' | 'degraded' | 'unusable'; interface PackageHealth { status: PackageHealthStatus; /** Pi capability names this package has hit, in first-hit order. */ gaps: readonly string[]; } interface CapabilityGapOptions { /** The Pi capability, as the package sees it (e.g. "ctx.fork"). */ capability: string; /** Why DSH has no mapping, in one sentence. */ reason: string; /** What the caller can do about it, in one sentence. */ guidance: string; /** The migrated package that hit the gap, when known. */ packageName?: string; } /** * Host-level record of capability gaps, one instance per DSH host (it lives in * SharedHostState). Emits ONE user-facing notice per (package, capability): * repeated hits of the same gap change nothing the user needs to hear again. */ declare class CapabilityLedger { private readonly emit; private readonly noticed; private readonly packages; constructor(emit: (message: string) => void); /** * Record a degraded capability: this feature of the package does not work on * DSH, the rest of the package keeps working. Reported to the user once. */ reportDegraded(options: CapabilityGapOptions): void; /** * Record a host-owned decision (e.g. shutdown): the host refused or absorbed * the request through a channel Pi itself defines. Not a package defect, so * package health stays untouched; the user still learns what happened, once. */ reportHostDecision(options: CapabilityGapOptions): void; /** * Startup-time reference detection: the package's source imports a * host-owned symbol that cannot work on DSH. Reported at mount so the user * learns BEFORE any code path runs into it; health is untouched because an * import alone proves nothing about usage — construction still fails * structurally and marks the package then. */ reportStartupReference(options: CapabilityGapOptions): void; /** * Record that a package could not even mount because its entry code needs a * missing capability. The package is marked unusable for this run. */ reportUnusable(options: CapabilityGapOptions): void; healthOf(packageName: string): PackageHealth; /** Every package with a recorded gap, for surfacing in mount summaries. */ snapshot(): ReadonlyMap; private mark; private notice; } //#endregion //#region src/session-bridge.d.ts type UnknownRecord$4 = Record; interface DshSessionLike { id: string; events?: readonly UnknownRecord$4[] | (() => readonly UnknownRecord$4[]); snapshotEvents?(): readonly UnknownRecord$4[]; append?(type: string, data: unknown, opts?: unknown): unknown; header?: UnknownRecord$4; } interface PiProjectedEntry { type: string; id: string; parentId: string | null; timestamp: string; [key: string]: unknown; } /** Only public persistence reads; never resume or load-with-recovery for indexing. */ interface SessionExportPersistence { list(): Promise; inspect?(id: string): Promise<{ meta: UnknownRecord$4; events: readonly UnknownRecord$4[]; }>; open?(id: string, access: 'read'): Promise<{ header: UnknownRecord$4; read(): Promise<{ events: readonly UnknownRecord$4[]; }>; close(): Promise; }>; } declare class PiSessionBridge { private readonly fileContent; constructor(fileContent?: (ref: unknown) => unknown); private readonly records; private readonly loaded; private readonly exportedSessions; exportStoredSessions(persistence: SessionExportPersistence): Promise; /** Materialize the public Pi file contract from the native session, never vice versa. */ exportSessionFile(session: DshSessionLike, cwd: string): string; private sidecarPath; /** * The Pi-visible archive file for one DSH session — the established * `.jsonl` convention (getSessionFile/switchSession use the same one). * Guaranteed to EXIST on return, and to start with a genuine Pi * `{type:"session"}` header line: Pi consumers treat the session file as * the durable identity a conversation can be reopened by (pi-subagents * guards its tombstone resurrect with existsSync), and real Pi parsing * (`SessionManager.open` reads the header for id/cwd) must see a Pi file, * not a bare inode. An empty pre-existing file is upgraded in place. */ archiveFileFor(sessionId: string, cwd?: string): string; /** * The DSH session id an archive-file path names, or undefined for any path * this bridge did not mint (a genuine Pi session file, an in-memory * manager's undefined). The reverse of {@link archiveFileFor} — ids that * survive its sanitization round-trip exactly, which every id this bridge * mints does. */ sessionIdOfArchiveFile(path: unknown): string | undefined; /** * Retire one archive this bridge minted: the file whose existence tells Pi * consumers "this conversation can be reopened". Called ONLY on a positive * persistence-layer verdict that the DSH session is gone, so existsSync * answers honestly again. */ discardArchive(sessionId: string): void; load(sessionId: string): void; private persist; appendCustomEntry(sessionId: string, customType: string, data: unknown): string; /** * The custom entries a package appended to one session, oldest first. * * Addressed by id alone: the browser half asks for a session it is showing, * and has no DSH session object to hand over. * @param sessionId - session whose sidecar to read. * @returns each custom entry with its type, data and id. */ customEntries(sessionId: string): Array<{ id: string; customType: string; data: unknown; timestamp: string; }>; appendBranchSummary(sessionId: string, summary: string, fromId: string): string; appendLabel(sessionId: string, targetId: string, label: string | undefined): void; setName(sessionId: string, name: string): void; getName(sessionId: string): string | undefined; labels(sessionId: string): Map; /** * Project the DSH durable log plus sidecar records into Pi's entry-chain * shape. DSH history is linear, so the projection is a single-branch tree: * every entry's parent is its predecessor. */ /** * The seqs still on the model-visible surface, via DSH's own canonical fold. * @param session - the session to project. * @returns the visible seqs, or undefined when the fold cannot run (a * projection built from a partial event list, e.g. in a test double) — in * which case nothing is filtered out rather than everything. */ visibleSeqs(session: DshSessionLike): Set | undefined; projectEntries(session: DshSessionLike): PiProjectedEntry[]; /** The exact 14-method surface Pi exposes as ctx.sessionManager. */ readonlySessionManager(session: DshSessionLike, cwd: string): UnknownRecord$4; } //#endregion //#region src/subagent-bridge.d.ts type UnknownRecord$3 = Record; type PiSessionEventHandler = (event: UnknownRecord$3) => void; interface SubagentHost { cordis: Context; cwd(): string; parentSessionId(): string | undefined; /** The delegating parent's delegation depth (DSH's recursion budget); 0 for a top-level parent. */ parentDelegationDepth(): number; piContentToDsh(content: unknown): Promise; deliver(agent: UnknownRecord$3, message: unknown, mode: 'inject' | 'steer' | 'followup'): void; messageFromSessionEvent(event: UnknownRecord$3): Promise; messageSource: string; /** The Pi package that asked for the child, used to label it in DSH's catalog. */ packageName?: string; /** The delegating parent Agent's own ctx (undefined outside an agent scope). */ parentAgentContext(): unknown; /** The live parent identity required by newer DSH agent ownership. */ parentAgent?(): UnknownRecord$3 | undefined; /** * Translate the child's Pi custom tools into DSH tool definitions and * register them THROUGH the unpublished child ctx, so they land in the * child Agent's scope and unwind with it. */ registerChildTools(childCtx: unknown, tools: readonly unknown[]): void; /** * DSH's official delegation policy capture (dsh-subagent semantics): the * parent session's explicit sandbox override, and the approval policy * pinned to 'never' when an approval service exists. */ delegatedPolicyOverrides(): { sandboxMode?: unknown; approvalPolicy?: string; }; /** * Pi-shaped readonly sessionManager projection over one DSH session. Its * getSessionFile() returns the durable archive path (`.jsonl` * convention) Pi consumers treat as the conversation's reopenable identity * — pi-subagents records it per child and resurrects `@handle` mentions by * reopening exactly that file. */ sessionManagerFor?(session: unknown): UnknownRecord$3; /** * The DSH session id an archive path names, or undefined for any path the * bridge did not mint (a genuine Pi session file, an in-memory manager). */ resumeSessionIdFor?(file: unknown): string | undefined; /** * Serve the child the extension set a real Pi createAgentSession loads: * the host's installed Pi packages, filtered by the creator's resource * loader (its own getExtensions applies noExtensions/extensionsOverride — * the creator's code decides, not this bridge). No loader means Pi's * default: everything discovered. Resolves with per-extension failures * (Pi's per-extension error isolation — a failed extension never takes * the child down). */ mountChildExtensions?(childAgent: UnknownRecord$3, loader: unknown): Promise>; /** * Whether the host's session persistence POSITIVELY lacks this session — * DSH's own post-resume-failure verdict shape (`persistence.list()` in * agent-loop's restoreOrCreateConfigured). undefined = cannot tell (no * persistence service or list failed), and nothing may be retired on it. */ sessionGoneFromPersistence?(sessionId: string): Promise; /** Retire a stale archive identity this bridge minted, so existsSync answers honestly again. */ discardStaleArchive?(sessionId: string): void; /** * The delegating parent's own model route. Pi's default for a child session * is the caller's current model; without it the child agent has no model * option and prompt sections keyed on {{model}} fail the first assembly. */ parentModelRoute?(): { provider?: string; model?: string; } | undefined; /** * Claim a freshly created child agent for this instance: its requests join * the instance's agent/request waterfall (which is what carries a per-child * thinking level), and only the creating instance claims it. */ adoptChildAgent?(child: unknown, thinkingLevel?: string): void; } interface BeforeToolCallDecision { block?: boolean; reason?: string; } interface PiSubagentFacade { beforeToolCall?: (context: { toolCall: { name: string; id: string; arguments: unknown; }; }, signal: AbortSignal | undefined) => Promise | BeforeToolCallDecision | undefined; /** Pi's AgentState — the same object `session.state` returns. */ state?: UnknownRecord$3; } declare class PiBridgedAgentSession { #private; readonly agent: PiSubagentFacade; readonly messages: UnknownRecord$3[]; /** * Pi's AgentSession.sessionManager surface, projected over the child's DSH * session. getSessionFile() names the durable archive — what pi-subagents * stores as the conversation's reopenable identity (tombstone resurrect). */ readonly sessionManager: UnknownRecord$3 | undefined; constructor(host: SubagentHost, handle: { agent: UnknownRecord$3; dispose(): Promise; }, tools: unknown[], thinkingLevel?: string); /** Pi's AgentState projection, shared by `session.state` and `session.agent.state`. */ get state(): UnknownRecord$3; /** * Whether one transcript entry is carried context rather than part of the * exchange in this child session. * @param message - an entry of {@link messages}. * @returns true for a seeded transcript entry or a host runtime snapshot. */ isCarriedContext(message: UnknownRecord$3): boolean; subscribe(handler: PiSessionEventHandler): () => void; prompt(text: string): Promise; steer(text: string, images?: readonly UnknownRecord$3[]): Promise; followUp(text: string, images?: readonly UnknownRecord$3[]): Promise; abort(): void; setSessionName(name: string): void; getSessionName(): string; getSessionStats(): UnknownRecord$3; getAllTools(): unknown[]; getActiveToolNames(): string[]; /** Hand over the creation-time restriction so a later setActiveToolsByName * retires it instead of intersecting with it. */ adoptRestriction(dispose: (() => void) | undefined): void; setActiveToolsByName(names: string[]): void; adoptExtensionFailures(failures: ReadonlyArray<{ name: string; error: string; }>): void; bindExtensions(bindings?: UnknownRecord$3): Promise; dispose(): Promise; } //#endregion //#region src/browser-surfaces.d.ts /** One side thread as the panel renders it. */ interface PanelThreadView { /** The child session's id, stable for the life of the thread. */ id: string; /** Human label, already the one DSH's catalog shows. */ label: string; /** Pi package that opened it, when known. */ package?: string; /** Whether the child is mid-turn. */ running: boolean; messages: Array<{ role: string; text: string; }>; } interface TrackedThread { id: string; label: string; package: string | undefined; session: PiBridgedAgentSession; } /** Executes one Pi command by its Pi-side name; resolves the notices text. */ type PiCommandRunner = (command: string, args: string) => Promise; /** * Live side threads, keyed by the parent session they belong to. * * Host-level (one per engine instance, like the provider directory): the panel * is one surface, however many Pi packages contribute threads to it. */ declare class BrowserSurfaces { #private; /** Last time a browser client touched the /pi2dsh route (ms epoch). */ lastClientContactMs?: number; /** Register one known image tool's exact DSH wire name. */ registerImageTool(name: string): void; /** Exact wire names needing the generic Pi image-result browser view. */ imageToolNames(): string[]; /** * Track one child session under its parent. * @param parentSessionId - the session the panel floats over. * @param thread - the child's identity and live session object. * @returns a disposer that removes the thread from the panel. */ track(parentSessionId: string, thread: TrackedThread): () => void; /** * Register the executor for one package's Pi commands on one session, so * product UI (a side-chat window's input, its action buttons) can run the * package's OWN command handlers — the same code path the composer takes. * Generic by construction: the runner closure carries the package runtime; * this registry only routes (session, package) to it. * @param sessionId - the root session the package is mounted for. * @param packageName - the Pi package owning the commands. * @param runner - executes one registered Pi command by its Pi name. * @returns a disposer that unregisters the runner. */ registerCommandRunner(sessionId: string, packageName: string, runner: PiCommandRunner): () => void; /** * The registered runner for (session, package), when one is mounted. * * An empty sessionId means "any session where the package is mounted": * session-free product UI (a Settings page) invoking a package command * whose effect is global state — the handler itself is the package's own * either way, and every mounted copy routes to the same package storage. */ commandRunner(sessionId: string, packageName: string): PiCommandRunner | undefined; /** * The panel's view of one parent session. * @param parentSessionId - session the browser is currently showing. * @returns every side thread opened under it, oldest first. */ snapshot(parentSessionId: string): PanelThreadView[]; /** * Pi's `setStatus(key, text)`: one keyed status entry in the status bar. * The key is the entry's identity; passing undefined removes that entry, * exactly like Pi clears one status. * @param sessionId - session the calling agent belongs to. * @param packageName - Pi package making the call, when known. * @param key - the status entry's key. * @param text - the text to show, or undefined to remove the entry. */ setStatus(sessionId: string, packageName: string | undefined, key: string, text: unknown): void; /** * Pi's `setWidget(key, content)`: one keyed widget. Only string arrays are * recorded — anything else is ignored exactly like Pi's own rpc mode, where * widgets are transmitted to a host as lines and factory content needs TUI * access the host never provides. * @param sessionId - session the calling agent belongs to. * @param packageName - Pi package making the call, when known. * @param key - the widget's key. * @param content - the widget's lines, or undefined to remove the widget. */ setWidget(sessionId: string, packageName: string | undefined, key: string, content: unknown, theme?: unknown): void; /** * Record one simple presentation call (working chrome, title, header, * footer). The value is a string, a Pi component, a working-indicator * options object, or a header/footer factory; each renders to text here so * the browser half never runs Pi code. * @param sessionId - session the calling agent belongs to. * @param packageName - Pi package making the call, when known. * @param key - which surface. * @param value - the value the package passed; undefined clears it. * @param theme - the bridge's headless theme, for factories that style with it. */ setSurface(sessionId: string, packageName: string | undefined, key: SurfaceKey, value: unknown, theme?: unknown): void; /** * Pi's `setWorkingVisible`: hide the working chrome without forgetting it. * @param sessionId - session the calling agent belongs to. * @param packageName - Pi package making the call, when known. * @param visible - whether the working chrome should show. */ setWorkingVisible(sessionId: string, packageName: string | undefined, visible: boolean): void; /** * Register one package's custom-entry renderer. * * Pulled rather than pushed: a renderer's output depends on the session being * looked at, and the package registers once at mount for every session it * will ever be asked about. * @param packageName - owning Pi package. * @param source - called with the session id the browser is showing. * @returns a disposer that unregisters the source. */ trackEntries(packageName: string, source: EntrySource): () => void; /** * Custom entries every package renders for one session, in package order. * @param sessionId - session the browser is showing. * @returns rendered entries; a renderer that throws contributes nothing. */ entries(sessionId: string): RenderedEntry[]; /** * Ask the browser to put text in the composer. * * A revision rather than a flag: the seat applies a request once, and the * next call — even with identical text — is a new request rather than a * no-op, which is what a package retrying a paste means. * @param sessionId - session whose composer to write. * @param text - the full next draft. */ requestDraft(sessionId: string, text: string): void; /** * The pending composer write for one session, if any. * @param sessionId - session the browser is showing. * @returns the request, or undefined when nothing is pending. */ draftRequest(sessionId: string): DraftRequest | undefined; /** * Record what the composer actually holds, as reported by the browser. * @param sessionId - session the report is about. * @param text - the live draft. */ reportDraft(sessionId: string, text: string): void; /** * The composer text for one session. * @param sessionId - session to read. * @returns the browser's last report, or the last requested text. */ liveDraft(sessionId: string): string; /** * Register one package's completion provider. * @param packageName - owning Pi package. * @param source - asked with the trigger character and the typed query. * @returns a disposer that unregisters the source. */ trackCompletions(packageName: string, source: CompletionSource): () => void; /** * Completions every package offers for one trigger token. * @param trigger - the trigger character the menu opened on. * @param query - what the user has typed after it. * @returns candidates in package order; a provider that throws contributes none. */ completions(trigger: string, query: string): Promise; /** * What packages have put on screen for one session. * @param sessionId - session the browser is showing. * @returns one entry per package that has driven a surface, empties dropped. */ surfaces(sessionId: string): SurfaceView[]; } /** * Presentation slots a Pi package can drive, in DSH's browser shell. The * keyed surfaces (status, widget) live on {@link SurfaceView.statuses} and * {@link SurfaceView.widgets}; the simple ones live in `values`. */ type SurfaceKey = 'workingMessage' | 'workingIndicator' | 'hiddenThinkingLabel' | 'title' | 'header' | 'footer'; /** One package's presentation state for one session. */ interface SurfaceView { package?: string; /** Simple string surfaces: working chrome, transient title, header, footer. */ values: Partial>; /** Pi's `setStatus` entries, keyed by the entry key. */ statuses: Record; /** Pi's `setWidget` entries, keyed by the widget key. */ widgets: Record; /** Pi's setWorkingVisible: false hides the working chrome without clearing it. */ workingVisible: boolean; } /** One custom entry a package rendered for the conversation. */ interface RenderedEntry { id: string; customType: string; package?: string; text: string; } /** One pending composer write, with the revision the browser acknowledges. */ interface DraftRequest { text: string; rev: number; } /** One completion a Pi provider offered for a trigger token. */ interface CompletionItem { value: string; label: string; description?: string; } /** A package's completion provider, asked with the token the user is typing. */ type CompletionSource = (trigger: string, query: string) => Promise; /** A package's renderer, pulled at snapshot time for the session on screen. */ type EntrySource = (sessionId: string) => RenderedEntry[]; //#endregion //#region src/model-bridge.d.ts type UnknownRecord$2 = Record; interface DshLlmLike { listProviders(): Array<{ id: string; name: string; }>; listModels(provider: string): Promise; resolveModelInfo(provider: string, model: string, signal?: AbortSignal): Promise; stream(options: UnknownRecord$2): AsyncIterable; } /** A DSH catalog entry in Pi's Model shape. */ interface PiModelShape { id: string; name: string; provider: string; api: string; input: Array<'text' | 'image'>; reasoning: boolean; contextWindow?: number; maxTokens?: number; [key: string]: unknown; } /** * Cached projection of DSH's advisory model catalog as Pi Model objects. * `refresh()` re-reads providers and models; the runtime subscribes it to * `llm/adapters-updated`. Reads are synchronous (Pi's getAll contract). */ declare class ModelCatalog { #private; constructor(llm: DshLlmLike | undefined); get present(): boolean; all(): PiModelShape[]; find(provider: string, modelId: string): PiModelShape | undefined; refresh(): Promise; /** Exact-route metadata (context window, reasoning efforts), cached per route. */ resolve(provider: string, modelId: string): Promise; } interface PiStreamRequest { model: UnknownRecord$2; context: UnknownRecord$2; options?: UnknownRecord$2 | undefined; } /** * Run one hand-built pi-ai model call on DSH's native llm service, translating * the chunk stream into Pi's AssistantMessageEventStream vocabulary. */ declare function streamViaDshLlm(llm: DshLlmLike, request: PiStreamRequest): AssistantMessageEventStream; //#endregion //#region src/provider-adapter.d.ts /** * A registered route's disposer, plus the ability to announce it again. * * A package's model list is not always known when the route is registered: * gateway discovery needs a credential, and a credential may only arrive later * (a `/login` mid-session). DSH publishes `llm/adapters-updated` when a route * set is committed, and every directory observer — the browser's model picker * included — refreshes on exactly that event. So a later discovery needs the * route ANNOUNCED again, or the models exist and nobody looks. */ interface PiRouteHandle { (): void; /** Re-commit this route so directory observers re-read its models. */ reannounce?(): void; } //#endregion //#region src/tui-surfaces.d.ts type UnknownRecord$1 = Record; interface PiCustomComponent { render(width: number): string[]; invalidate?(): void; handleInput?(data: string): void; dispose?(): void; } interface PiTuiDriver { requestRender(): void; } interface PiCustomOptions { overlay?: boolean; overlayOptions?: UnknownRecord$1 | (() => UnknownRecord$1); } type PiCustomFactory = (tui: PiTuiDriver, theme: unknown, keybindings: unknown, done: (result: T) => void) => PiCustomComponent | Promise; /** One optional terminal front door behind the public Pi UI contract. */ interface TerminalSurfaceAdapter { readonly kind: string; readonly available: boolean; /** Commands the active terminal owns natively; incoming Pi commands alias. */ readonly nativeCommands: ReadonlySet; setStatus(key: string, text: unknown): void; custom(factory: PiCustomFactory, theme: unknown, keybindings: unknown, options?: PiCustomOptions): Promise; dispose(): void; } //#endregion //#region src/runtime.d.ts type UnknownRecord = Record; type PiHandler = (event: UnknownRecord, context: UnknownRecord) => unknown | Promise; declare function isKnownImageTool(packageName: string, toolName: string): boolean; interface RuntimeOptions { rootUrl: URL; manifest: GeneratedRuntimeManifest; config?: UnknownRecord; /** Exact Agent owner supplied by the pre-publication setup host. */ ownerAgent?: UnknownRecord; /** * Host-anchor mount: the once-per-host instance that carries a package's * HOST-level contributions — provider routes, OAuth accounts, `/login` * availability, credential recovery, companion routes, skills — so they * exist from engine apply with zero live Agents and survive Agent churn * (SharedHostState keeps them single-instance and refcounted alongside the * per-Agent instances). The anchor serves no Agent: it never bridges * session lifecycles and its agent-facing surfaces (DSH tools, commands, * prompt sections) are not projected — those belong to the per-Agent * instances that own real sessions. */ hostAnchor?: boolean; } interface PiTool { name: string; label?: string; description: string; parameters: unknown; /** Pi: one line for the system prompt's "Available tools" list. */ promptSnippet?: string; /** Pi: guideline bullets that apply while this tool is active. */ promptGuidelines?: string[]; executionMode?: 'parallel' | 'sequential'; prepareArguments?: (args: unknown) => unknown; execute(toolCallId: string, args: unknown, signal: AbortSignal | undefined, onUpdate: ((result: unknown) => void) | undefined, context: UnknownRecord): Promise; } interface PiCommand { name: string; description: string; argumentHint?: string; handler(args: string, context: UnknownRecord): unknown | Promise; } interface RuntimeState { packageName: string; /** Exact DSH Agent that owns this runtime; absent only for legacy root mounts. */ ownerAgent: UnknownRecord | undefined; /** Host-anchor mount: host-level contributions only, serves no Agent (see RuntimeOptions.hostAnchor). */ hostAnchor: boolean; /** The session-event projector, exposed for the mount-time backlog replay. */ projectSessionEvent?: (session: UnknownRecord, event: UnknownRecord) => void; /** Owned mounts: live session-event delivery starts after the backlog replay. */ sessionEventsLive?: boolean; handlers: Map; tools: Map; runner: ExtensionRunner; toolDisposers: Map void>; toolRestrictions: WeakMap void>; pendingActiveTools?: string[]; commands: Map; nativeSkillCommands: UnknownRecord[]; commandDisposers: Map void>; /** DSH command name -> Pi command that currently owns that public name. */ dshCommandOwners: Map; flags: Map; notifications: string[]; activeAgents: Set; /** Latest non-child Agent whose Pi session owns this package instance. */ hostAgent: UnknownRecord | undefined; /** Agents whose linear Pi session_shutdown has already been projected. */ piShutdownAgents: WeakSet; shutdownTasks: WeakMap>; pendingShutdowns: Set>; disposedAgents: WeakSet; /** Durable sessions that have already received Pi's session_start event. */ startedSessions: Set; /** In-flight session_start handlers, so an immediate command can await initialization. */ sessionStartTasks: Map>; /** Fallback dedupe for command agents whose composition has no durable session. */ startedSessionlessAgents: WeakSet; /** In-flight session_start handlers for agents without a durable session id. */ sessionlessStartTasks: WeakMap>; /** Extension entries are async imports; lifecycle events wait until handlers exist. */ extensionsReady: boolean; /** Agent starts observed while extension entries are still loading. */ pendingSessionStarts: Map; /** Skill roots already handed to DSH's skills service through resources_discover. */ discoveredSkillRoots: Set; /** Count of discovered-root provider mounts, for unique provider names. */ discoveredSkillProviders: number; currentSystemPrompt: string; messageSource: string; /** Pi's cross-extension bus: shared by every package instance of one agent * (host/anchor instances share the host bus), matching Pi's one-bus-per- * session contract. NEVER removeAllListeners on it — that would strip the * other packages' subscriptions; unwind through eventBusOffs instead. */ eventBus: EventEmitter; /** This instance's own bus subscriptions, for scoped unwind on dispose/reload. */ eventBusOffs: Array<() => void>; agentScope: AsyncLocalStorage; /** Per-Agent bridge used by Pi's designated-model calls. */ llmBridge: PiAiLlmBridge | undefined; /** Per-Agent copy of Pi's compat and API-provider registries. */ piAiRegistry: ReturnType; /** Per-Agent factory used by Pi's createAgentSession(). */ subagentSessionFactory: SubagentSessionFactory | undefined; bridge: PiSessionBridge; theme: Theme; shortcuts: Map; messageRenderers: Map; entryRenderers: Map; markdownTransformer?: unknown; providers: Map; /** Ids in `providers` registered as pi-ai native Provider objects (Pi's second ledger). */ nativeProviders: Set; autocompleteProviders: unknown[]; editorComponentFactory?: unknown; editorBuffers: WeakMap; toolsExpanded: boolean; modelOverrides: WeakMap; thinkingLevels: WeakMap; childAgents: WeakSet; turnSystemPromptOverrides: WeakMap; /** * The single ordered stream for projections that must keep durable-log * order. Several of them now await the attachment service (Pi's content * blocks carry image bytes inline), and the subscribers that feed them are * synchronous — without one shared chain a tool result with an image can be * announced after the turn that produced it has already ended. */ projection: Promise; /** * Pi's `terminate` hint, accumulated across the current tool batch. Pi stops * the loop only when EVERY finalized call in the batch asked for it, and a * single call cannot know that — so the calls record here and the next step * boundary reads the verdict. */ terminateBatch: WeakMap; /** Pi's turnIndex: reset when a DSH turn opens, incremented after each step. */ piTurnIndex: WeakMap; /** Messages DSH claimed for the step that is about to be assembled. */ claimedForStep: WeakMap; /** The turn each agent's before_agent_start has already fired for. */ promptedTurn: WeakMap; /** Custom messages a before_agent_start handler returned, awaiting the step. */ pendingInjections: WeakMap; globalThinkingLevel: string; argMutations: WeakMap; streamingTexts: Map; lastLoggedModels: WeakMap; modelCatalog?: ModelCatalog; companionRoutes: Map; providerRouteDisposers: Map; /** Host-shared provider routes this Agent runtime owns one reference to. */ ownedProviderRoutes: Set; publishedOAuthKeys: Map; shared: SharedHostState; tuiSurfaces: TerminalSurfaceAdapter | undefined; } type PiAiLlmBridge = (model: UnknownRecord, context: UnknownRecord, options: UnknownRecord | undefined) => ReturnType; type SubagentSessionFactory = (options: Record) => Promise<{ session: unknown; }>; declare function textBlocks(content: unknown): Array<{ type: 'text'; text: string; }>; declare function normalizeToolResult(result: unknown): UnknownRecord; declare function normalizeToolSchema(schema: unknown): { schema: UnknownRecord; warnings: string[]; }; declare function isSubagentOrigin(subject: UnknownRecord | undefined): boolean; declare function currentPiModel(state: RuntimeState, agent: UnknownRecord): UnknownRecord | undefined; /** * The provider/model of a session's LAST model request, read off the durable * log's request/header — the authority on what the caller is ACTUALLY running. * A UI/`/model` switch never touches the creation-time AgentOptions snapshot, * so a child inheriting the snapshot runs on a stale route (the exact * inheritance bug DSH's own subagent line reports); the durable header is * where the live truth lands, in either of its two observed nestings. */ declare function lastRequestRouteOf(session: UnknownRecord | undefined): { provider?: string; model?: string; } | undefined; /** * The route a spawned child inherits, by authority: an explicit Pi * ctx.setModel() override wins, then the caller's last durable request * (UI/`/model` switches land there), then the creation-time snapshot. */ declare function resolveCallerRoute(override: { provider?: string; model?: string; } | undefined, durable: { provider?: string; model?: string; } | undefined, snapshot: { provider?: string; model?: string; } | undefined): { provider?: string; model?: string; } | undefined; /** * What triggered a compaction, in Pi's vocabulary. * * DSH's durable lifecycle events say two things about the trigger: a manual * compaction runs with no open turn (`turn: null`), and one a command drove * cites that command. Both are Pi's "manual". * * The limit, stated rather than papered over: DSH's automatic trigger is * `'pressure' | 'context-overflow'` at the call site but is NOT written to the * log, so Pi's `threshold` and `overflow` cannot be told apart after the fact. * Automatic compactions report `threshold`, the far more common of the two — * and `willRetry` stays false for the same reason. A package keying behavior * on `overflow` specifically will not see it. * @param data - the `compaction/start` or `compaction/summary` event data. */ declare function compactionReason(data: UnknownRecord): 'manual' | 'threshold' | 'overflow'; /** * DSH content → the Pi content blocks packages read. * * Asynchronous because Pi's image block carries the bytes inline while DSH's * carries only an attachment reference, and the bytes come from the attachment * service. The sync version this replaced projected an image as a bare * `{type:'image'}` — a block that announces an image and contains none, which * is the exact shape a package cannot tell from a real one. * @param ctx - context used to reach the attachment service. * @param content - the DSH blocks to project. */ declare function dshToPiContent(ctx: Context, content: readonly ContentBlock[]): Promise>; interface SharedHostState { companionRoutes: Map; providerRouteDisposers: Map; /** Coalesced dynamic-catalog refreshes, shared by startup and first use. */ providerModelDiscoveries: Map>; /** Agent-runtime owners for each host-global provider route. */ providerRouteOwners: Map>; /** Per-session Pi runtimes, in package mount order, for provider waterfalls. */ runtimeStatesBySession: Map>; publishedOAuthKeys: Map; /** Composed canonical provider configs — the ONLY read surface. Maintained * exclusively by recomposeSharedProvider from the layered ledger below. */ providers: Map; /** Base layer: the engine's built-in OAuth directory entries (Pi's * `builtins` map). Survives any package overlay; restored on unregister. */ providerBuiltins?: Map; /** Extension layer, one slot per package so a package's per-agent instances * re-registering the same content stay idempotent instead of perturbing * cross-package overlay order. Slot content follows Pi's re-registration * contract: defined values merge over the previous registration. */ providerPackages?: Map>; /** Package overlay order = first-registration order, mirroring Pi where * "last registration wins" is load order (per-session rebuilds keep it stable). */ providerPackageOrder?: string[]; /** Pi's cross-extension event bus is ONE bus per session; ours is one per * agent (host/anchor instances share the host bus). */ agentEventBuses?: WeakMap; hostEventBus?: EventEmitter; /** Pi's theme is session-shared UI state, not per-extension. */ agentThemes?: WeakMap; hostTheme?: Theme; /** Provider ids whose DSH authorization-seam projection is armed (an * inject scope waiting on — or holding — the authorization service). */ authorizationArmedIds?: Set; /** Provider ids whose deferred route restore is armed (an inject scope * waiting for the credentials service to compose). */ routeRestoreArmedIds?: Set; modelCatalog?: ModelCatalog; catalogSubscribed?: boolean; loginCommandRegistered?: boolean; oauthRefreshHooked?: boolean; companionSweepSubscribed?: boolean; oauthStore?: FileCredentialStore; capabilityLedger?: CapabilityLedger; packageRemounts?: WeakMap Promise>>; browserSurfaces?: BrowserSurfaces; browserSurfacesRouted?: boolean; activeLogin?: ActiveLogin | undefined; browserLogin?: BrowserLoginFlow | undefined; childExtensions?: ChildExtensionCatalog; childPackageTools?: WeakMap>>; } interface ActiveLogin { providerName: string; controller: AbortController; /** Settles when the flow has released its callback port. */ finished: Promise; /** Short links this flow published, retired when it ends. */ published: string[]; } /** * What the login card polls: the flow's running transcript, one pending * question at most, and the outcome once the spine settles. Notices carry the * exact strings the /login command would print — URLs inside them are the * short links the spine already publishes on this same web server. */ interface BrowserLoginFlow { provider: string; providerName: string; notices: Array<{ message: string; code?: string; }>; question?: { id: number; kind: 'input' | 'select'; title: string; placeholder?: string; options?: string[]; }; /** Resolves the ui call the question belongs to; cleared with the question. */ answer?: ((value: string | undefined) => void) | undefined; done?: { ok: boolean; summary: string; }; } /** * The engine's installed-package extension catalog, for serving CHILD * sessions: real Pi's createAgentSession loads the default-discovered * extensions into every child unless the creator's loader narrows them. * The catalog is what "default-discovered" means on this host. */ interface ChildExtensionCatalog { /** Absolute declared-entry path → installed package name. */ packageByEntryPath: ReadonlyMap; /** * Mount the named packages onto one child agent (its own agent-local ctx — * contributions unwind with the agent, DSH's documented scope semantics). * @returns per-package failures, Pi's per-extension error isolation. */ mount(childAgent: UnknownRecord, packageNames: readonly string[]): Promise>; } declare function registerChildExtensionCatalog(ctx: Context, catalog: ChildExtensionCatalog): void; /** Read the installed-package catalog registered on shared host state, or undefined. */ declare function getSharedChildExtensionCatalog(ctx: Context): ChildExtensionCatalog | undefined; /** * Which installed packages a creator's resource loader selects for its child * — the creator's OWN filter code decides (the loader's getExtensions applies * noExtensions and extensionsOverride), this only maps the surviving entry * paths back to package names. No loader at all means Pi's default: the full * discovered set (sdk.ts builds a default loader and loads everything). */ declare function resolveChildExtensionPackages(loader: unknown, catalog: ChildExtensionCatalog): { names: string[]; failures: Array<{ name: string; error: string; }>; }; /** * Pi's provider ledger is layered, not flat (model-runtime.ts:742-786 at the * pinned upstream): a builtin base map, an extension overlay where defined * fields merge over the base (undefined fields expose the base — a package * overriding only baseUrl keeps the builtin OAuth flow), later registrations * overriding earlier ones, and unregistration restoring the builtin. These * helpers vendor that contract for the shared host ledger. One deliberate * adaptation: the overlay is slotted per PACKAGE and folded in package * first-registration order, because in Pi "last wins" is load order (each * session rebuilds the runtime so registration order is always load order), * while our host ledger accumulates across sessions — folding raw arrival * order would let a later agent's re-registration of package A overturn * package B for no Pi-semantic reason. */ declare function mergeProviderRegistration(previous: UnknownRecord | undefined, config: UnknownRecord): UnknownRecord; declare function overlayProviderConfig(base: UnknownRecord | undefined, overlay: UnknownRecord): UnknownRecord; /** Companion configuration: default (auto), `false` (off), or an explicit narrow map. */ type VisionCompanionsConfig = false | Record | undefined; /** * Image-admission companion routes: for every text-only route in the DSH * llm directory, a `-vision` route that admits images at the host's * admission checks, replaces image blocks with explicit path-carrying * notices, and forwards text-only to the original route. What happens to * an admitted image is decided at run time by whatever is mounted — a * vision extension analyzes it through the turn's entering messages, and * without one the notice's file path lets any image-capable tool read it — * so companions need no knowledge of any particular plugin and are * registered AUTOMATICALLY (zero configuration). `visionCompanions: false` * turns them off; an explicit `{ : [modelIds] }` map narrows them. * The directory is live: adapters-updated re-sweeps, adding companions for * new text-only routes and disposing companions whose original vanished. * The companion is an ordinary directory entry (single-directory * contract); Pi's ctx.model reports the original route for it * (companionRoutes). Idempotent per host. */ declare function registerVisionCompanions(ctx: Context, config: VisionCompanionsConfig): void; /** * Turn what the user answered into one of the offered options. * @param answer - the label, a differently-cased label, or a 1-based position. * @param offered - the options as they were shown, in order. * @returns the matching option, or undefined when nothing matches. */ declare function resolveOfferedChoice(answer: string, offered: readonly string[]): string | undefined; /** * Cancel the login already in flight, if any, and wait for it to let go. * * Waiting matters: the next flow binds the same fixed callback port, and Pi's * flow answers a taken port by silently degrading to a listener that never * receives a code. Starting the new flow before the old one has closed * reproduces exactly that. * @param state - the mounting package's state, holding the shared host state. * @returns the cancelled provider's name, or undefined when nothing was running. */ declare function supersedeActiveLogin(state: RuntimeState): Promise; /** The dialog surface a login flow talks to — the /login command hands the * DSH command UI, the authorization-seam flow hands a session adapter. */ interface ProviderLoginUi { input(title: unknown, placeholder?: unknown, signal?: AbortSignal): Promise; select(title: unknown, options: unknown[], signal?: AbortSignal): Promise; notify(message: unknown): void; deviceCode?(title: unknown, detail: unknown, signal?: AbortSignal): Promise; } declare function splitArguments(input: string): string[]; declare function expandPrompt(text: string, rawInput: string): string; declare function applyPiPackage(ctx: Context, options: RuntimeOptions): Promise; declare const runtimeInternals: { compactionReason: typeof compactionReason; resolveOfferedChoice: typeof resolveOfferedChoice; currentPiModel: typeof currentPiModel; lastRequestRouteOf: typeof lastRequestRouteOf; resolveCallerRoute: typeof resolveCallerRoute; resolveChildExtensionPackages: typeof resolveChildExtensionPackages; dshToPiContent: typeof dshToPiContent; expandPrompt: typeof expandPrompt; isKnownImageTool: typeof isKnownImageTool; isSubagentOrigin: typeof isSubagentOrigin; normalizeToolResult: typeof normalizeToolResult; splitArguments: typeof splitArguments; supersedeActiveLogin: typeof supersedeActiveLogin; textBlocks: typeof textBlocks; }; //#endregion export { ChildExtensionCatalog, ProviderLoginUi, VisionCompanionsConfig, applyPiPackage, getSharedChildExtensionCatalog, mergeProviderRegistration, normalizeToolSchema, overlayProviderConfig, registerChildExtensionCatalog, registerVisionCompanions, runtimeInternals }; //# sourceMappingURL=runtime.d.mts.map