agents 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/browser/tools/pi.d.ts +6 -2
  2. package/dist/browser/tools/pi.js +6 -2
  3. package/dist/browser/tools/pi.js.map +1 -1
  4. package/dist/chat-sdk/index.js +1 -1
  5. package/dist/cli.js +46 -45
  6. package/dist/experimental/channels/web/index.js +1 -1
  7. package/dist/harness/container/index.js +1 -1
  8. package/dist/harness/opencode/index.js +1 -1
  9. package/dist/harness/pi/index.d.ts +57 -35
  10. package/dist/harness/pi/index.js +261 -119
  11. package/dist/harness/pi/index.js.map +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/lifecycle/index.js +1 -1
  14. package/dist/{lifecycle-ClT4DmF2.js → lifecycle-v1rKHV2C.js} +57 -17
  15. package/dist/lifecycle-v1rKHV2C.js.map +1 -0
  16. package/dist/mcp/index.js +1 -1
  17. package/dist/models/pi-ai/index.js +2 -2
  18. package/dist/models/pi-ai/index.js.map +1 -1
  19. package/dist/{src-6lr7MtM_.js → src-DfLzdwlK.js} +3 -3
  20. package/dist/{src-6lr7MtM_.js.map → src-DfLzdwlK.js.map} +1 -1
  21. package/dist/web/fetch/tools/pi.d.ts +10 -6
  22. package/dist/web/fetch/tools/pi.js +10 -6
  23. package/dist/web/fetch/tools/pi.js.map +1 -1
  24. package/dist/web/search/tools/pi.d.ts +10 -6
  25. package/dist/web/search/tools/pi.js +10 -6
  26. package/dist/web/search/tools/pi.js.map +1 -1
  27. package/dist/websockets/index.js +1 -1
  28. package/dist/{websockets-CqxnntmE.js → websockets-CyoeosdO.js} +2 -2
  29. package/dist/{websockets-CqxnntmE.js.map → websockets-CyoeosdO.js.map} +1 -1
  30. package/dist/workflows.js +1 -1
  31. package/docs/harnesses/pi.md +62 -28
  32. package/docs/lifecycle.md +7 -1
  33. package/docs/models-pi-ai.md +5 -1
  34. package/package.json +11 -6
  35. package/dist/lifecycle-ClT4DmF2.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/harness/pi/context.ts","../../../src/harness/pi/session-store.ts","../../../src/harness/pi/harness.ts","../../../src/harness/pi/skills.ts"],"sourcesContent":["import type { Harness } from \"@earendil-works/pi-durable\";\n\n/**\n * pi's invocation context, as `@earendil-works/chord` defines it.\n *\n * pi-durable takes a chord `Context` on every call but does not re-export\n * the type or its constructors. The harness needs only a background context\n * and a way to add an abort signal, so both are inlined here instead of\n * depending on chord directly. A chord `Context` is a plain structural\n * interface (an abort signal, keyed values, and a name), so these interoperate\n * with chord's own contexts inside pi.\n *\n * One limit: chord's own derived contexts read the abort signal through a\n * private key rather than `abortSignal`, so a chord `withContextValue`\n * wrapped around one of these would not see its signal. pi-durable does not\n * use `withContextValue` to wrap a caller's context that way; `withAbortSignal`\n * and `withCancel` read `abortSignal` and work.\n *\n * If pi-durable starts re-exporting chord's context helpers, replace this\n * file with those.\n */\nexport type Context = Parameters<Harness[\"close\"]>[0];\n\n/** chord's `BACKGROUND_CONTEXT`: no values, never cancelled. */\nexport const BACKGROUND_CONTEXT: Context = Object.freeze({\n abortSignal: undefined,\n value: () => undefined,\n toString: () => \"[Context pi-harness background]\"\n});\n\n/**\n * chord's `withAbortSignal`: a context cancelled by either the parent's\n * signal or `signal`, carrying the parent's values.\n */\nexport function withAbortSignal(signal: AbortSignal, parent: Context): Context {\n const abortSignal =\n parent.abortSignal === undefined\n ? signal\n : AbortSignal.any([parent.abortSignal, signal]);\n return Object.freeze({\n abortSignal,\n value: parent.value.bind(parent),\n toString: () => `${parent}.WithAbortSignal`\n });\n}\n","import type { SqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite\";\nimport { openDurableObjectSqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite/cloudflare\";\n\n/**\n * pi's session store on a Durable Object's SQLite database.\n *\n * pi owns its sessions: conversations, entries, tasks, submissions, and\n * documents live in pi's own schema, created and migrated by pi's portable\n * `SqliteStorage` through pi's own Durable Object adapter. The store keeps\n * pi's tables under a prefix, so they cannot collide with the SDK's or the\n * host's tables in the same object.\n *\n * It is the Durable Object counterpart of `agents/sessions` for a harness\n * that brings its own session model, and has nothing pi-harness specific in\n * it: any harness built on pi-durable can open its storage with it.\n */\nexport type PiSessionStoreOptions = {\n /**\n * Prefix for every table and index pi creates. Must not start with `_cf_`,\n * which Durable Objects reserve. Default `pi_`.\n */\n readonly prefix?: string;\n};\n\nconst DEFAULT_PREFIX = \"pi_\";\n\n/** Open pi-durable's storage over this object's SQLite database. */\nexport function openPiSessionStore(\n storage: DurableObjectStorage,\n options: PiSessionStoreOptions = {}\n): Promise<SqliteStorage> {\n const prefix = options.prefix ?? DEFAULT_PREFIX;\n // pi validates the prefix as a SQLite identifier; Durable Objects also\n // reserve `_cf_` in any case, which pi does not know about.\n if (prefix.toLowerCase().startsWith(\"_cf_\")) {\n return Promise.reject(\n new Error(\"The pi session store prefix must not start with _cf_\")\n );\n }\n return openDurableObjectSqliteStorage(storage, { prefix });\n}\n","import type { Api, Model, ModelThinkingLevel } from \"@earendil-works/pi-ai\";\nimport {\n LiveDoc,\n ROOT_CONVERSATION_ID,\n watchEvents,\n type AgentEventStream,\n type Conversation,\n type ConversationId,\n type AgentChange,\n type EntryRecord,\n type Harness,\n type ModelRef,\n type SettledSubmissionRecord,\n type UserInput\n} from \"@earendil-works/pi-durable\";\nimport type { SqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite\";\nimport {\n LifecycleCapability,\n type CapabilityStartContext,\n type LifecycleJobContext,\n type LifecycleJobOutcome\n} from \"../../lifecycle\";\nimport { BACKGROUND_CONTEXT, withAbortSignal, type Context } from \"./context\";\nimport { openPiSessionStore } from \"./session-store\";\nimport type {\n PiOperationResult,\n PiPendingOperation,\n PiPromptResponse,\n PiReceipt,\n PiSessionId,\n PiSessionInfo,\n PiSessionOptions,\n PiSubmitOptions\n} from \"./types\";\n\nconst BG = BACKGROUND_CONTEXT;\n\n/** The root session's id. */\nexport const ROOT_SESSION: PiSessionId = String(ROOT_CONVERSATION_ID);\n\n/**\n * The three wake timings. They suit a real deployment; only tests change\n * them, with `setWakeTimingForTests`, so a suite does not sit on the real\n * heartbeat.\n *\n * A pi long wait further away than this is handed to the alarm, so the\n * alarm, not pi's in-memory timer, is what wakes the object.\n */\nconst SLEEP_THRESHOLD_MS = 60_000;\n\n/**\n * Longest one wake waits on pi. It waits inside an alarm invocation, which\n * has a 15 minute wall-time limit, so a longer run is waited on across\n * several alarms.\n */\nconst WAIT_BUDGET_MS = 10 * 60_000;\n\n/**\n * The wake job's heartbeat while it waits, and how often it re-checks work\n * it cannot wait on, such as background tasks. If the object is evicted, the\n * job is still due and its alarm restarts the object.\n */\nconst HEARTBEAT_MS = 30_000;\n\nlet setWakeTiming: (harness: PiHarness, timing: WakeTiming) => void;\n\n/**\n * @internal Shorten a harness's wake timings, so a test suite does not sit\n * on the real heartbeat. Not exported from `agents/harness/pi`.\n */\nexport function setWakeTimingForTests(\n harness: PiHarness,\n timing: WakeTiming\n): void {\n setWakeTiming(harness, timing);\n}\n\nconst WAKE_FN = \"wake\";\n\nfunction wakeJobId(session: PiSessionId): string {\n return `pi-wake:${session}`;\n}\n\nfunction sessionOfJob(payload: unknown): PiSessionId | undefined {\n return typeof payload === \"object\" &&\n payload !== null &&\n \"session\" in payload &&\n typeof payload.session === \"string\"\n ? payload.session\n : undefined;\n}\n\n/**\n * What the factory is handed: the two things only the harness can build.\n * Everything else `Harness.open` takes (models, registry, settings, env,\n * onReport) the factory builds itself.\n */\nexport type PiHarnessContext = {\n /** pi's storage over this object's SQLite, its migrations already run. */\n readonly storage: SqliteStorage;\n /** Background context, for the open itself. */\n readonly context: Context;\n};\n\n/**\n * Opens pi's `Harness`. The harness adopts what it returns.\n *\n * ```ts\n * harness: async ({ storage, context }) => {\n * const registry = createRegistry();\n * registry.install(await skills(sources));\n * return Harness.open(storage, { models, registry }, context);\n * }\n * ```\n */\nexport type PiHarnessFactory = (\n context: PiHarnessContext\n) => Harness | Promise<Harness>;\n\n/**\n * A model, as pi-ai describes one: `createAI`'s `ai(\"@cf/…\")` returns one.\n *\n * Only its `provider` and `id` are used. pi stores that reference with\n * the session and resolves it, at each request, against the `Models` the\n * factory opened pi with. So the model must be one those `Models` list,\n * and options passed to `ai(id, options)` here, such as `fallback`, are not\n * applied.\n */\nexport type PiModel = Pick<Model<Api>, \"provider\" | \"id\">;\n\n/**\n * Applied to a session the first time it is created. Without a model, a\n * session's generation fails as unanswered until `session.setModel` sets one.\n */\nexport type PiSessionDefaults = {\n /**\n * Model for new sessions, by its `provider` and `id`; it must be on the\n * `Models` the factory opens pi with (see `PiModel`). Change one\n * session's with `session.setModel`.\n */\n readonly model?: PiModel;\n readonly thinkingLevel?: ModelThinkingLevel;\n};\n\n/** How long the wake waits, and when it hands a wait to the alarm. */\ntype WakeTiming = {\n /** A pi wait further away than this goes to the alarm. Default 60_000. */\n readonly sleepThresholdMs?: number;\n /** Longest one wake waits inside an alarm. Default 600_000. */\n readonly waitBudgetMs?: number;\n /** Heartbeat while waiting, and the re-check for background work. Default 30_000. */\n readonly heartbeatMs?: number;\n};\n\n/** `PiHarness`'s options. Only `harness`, which opens pi, is required. */\nexport type PiHarnessOptions = {\n /** Opens pi's `Harness` over the storage this object prepared. */\n readonly harness: PiHarnessFactory;\n /** What a new session starts with. */\n readonly defaults?: PiSessionDefaults;\n};\n\ntype Opened = {\n readonly pi: Harness;\n readonly storage: SqliteStorage;\n};\n\n/** pi-durable's stored reference to a pi-ai model. */\nfunction modelRef(model: PiModel): ModelRef {\n return { provider: model.provider, modelId: model.id };\n}\n\nfunction conversationId(session: PiSessionId): ConversationId {\n const id = Number(session);\n if (!Number.isSafeInteger(id) || id < 1) {\n throw new Error(`Invalid pi session ${JSON.stringify(session)}`);\n }\n return id as ConversationId;\n}\n\n/** The text of an assistant entry, for an operation's result. */\nfunction assistantText(entry: EntryRecord | undefined): string {\n const message = entry?.model?.[0];\n if (message?.role !== \"assistant\") return \"\";\n return message.content\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\");\n}\n\nfunction signalContext(signal: AbortSignal | undefined): Context {\n return signal ? withAbortSignal(signal, BG) : BG;\n}\n\n/**\n * pi-durable hosted in a Durable Object, behind a small harness interface:\n * `harness.prompt()`, `harness.sessions`, `harness.session(id)`. How a session reaches a\n * client (sockets, SSE, RPC) is the host's glue, built on `session.events()`.\n *\n * pi owns everything about a run: the transcript, the inbox of steers and\n * follow-ups, generation and tool tasks, retries, crash recovery, and the\n * live view. It keeps all of it in its own tables in this object's SQLite\n * database (see `session-store.ts`).\n *\n * What pi cannot do on a Durable Object is wake itself: its scheduler runs\n * in memory, and an evicted object has no memory. The harness is that wake,\n * with one Lifecycle job per session. Input goes to pi once, in `submit()`,\n * after the session's job is scheduled. The job waits while pi has live\n * tasks in the session, rescheduling itself as a heartbeat, and completes\n * when there are none. An eviction mid-run leaves the job due, so its alarm\n * restarts the object, pi reopens and resumes its own tasks, and the job\n * waits again.\n *\n * @beta The API may change between releases.\n */\nexport class PiHarness extends LifecycleCapability {\n readonly sessions: PiSessions;\n readonly #options: PiHarnessOptions;\n /** In-memory waits on pi, per session, each inside an alarm's work. */\n readonly #waits = new Map<PiSessionId, Promise<void>>();\n /** Submissions between their wake and pi's admission, per session. */\n readonly #admitting = new Map<PiSessionId, number>();\n #sleepThresholdMs = SLEEP_THRESHOLD_MS;\n #waitBudgetMs = WAIT_BUDGET_MS;\n #heartbeatMs = HEARTBEAT_MS;\n #opening: Promise<Opened> | undefined;\n\n static {\n setWakeTiming = (harness, timing) => harness.#setWakeTiming(timing);\n }\n\n constructor(options: PiHarnessOptions) {\n super(\"pi-harness\");\n this.#options = options;\n this.sessions = new PiSessions(this);\n }\n\n #setWakeTiming(timing: WakeTiming): void {\n for (const [name, value] of Object.entries(timing)) {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(`PiHarness timing.${name} must be a positive number`);\n }\n }\n this.#sleepThresholdMs = timing.sleepThresholdMs ?? this.#sleepThresholdMs;\n this.#waitBudgetMs = timing.waitBudgetMs ?? this.#waitBudgetMs;\n this.#heartbeatMs = timing.heartbeatMs ?? this.#heartbeatMs;\n }\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n override async onStart(_context: CapabilityStartContext): Promise<void> {\n const { pi } = await this.#open();\n // Every session with live work gets a wake, including ones whose wake\n // failed out or that a subagent created without going through submit().\n const inspection = await pi.inspect(BG);\n const sessions = new Set(\n inspection.tasks.map((task) => String(task.record.conversationId))\n );\n for (const session of sessions) await this.#wake(session);\n }\n\n async onJob(\n context: LifecycleJobContext\n ): Promise<LifecycleJobOutcome | void> {\n if (context.job.fn !== WAKE_FN) return;\n const session = sessionOfJob(context.job.payload);\n if (session !== undefined) return this.#wakeStep(session);\n }\n\n /** Close pi's in-memory resources. Durable state is untouched. */\n async dispose(): Promise<void> {\n const opening = this.#opening;\n this.#opening = undefined;\n const opened = await opening?.catch(() => undefined);\n await opened?.pi.close(BG);\n }\n\n // ── The harness interface ────────────────────────────────────────────────\n\n /** A handle on one session. No I/O until you call it. */\n session(id: PiSessionId = ROOT_SESSION): PiSession {\n return new PiSession(this, id);\n }\n\n /** Submit a prompt and wait for its answer. */\n prompt(\n input: UserInput,\n options: PiSubmitOptions = {}\n ): Promise<PiPromptResponse> {\n return this.session(options.session).prompt(input, options);\n }\n\n /** Durably submit a prompt. Resolves before the model runs. */\n submit(input: UserInput, options: PiSubmitOptions = {}): Promise<PiReceipt> {\n return this.session(options.session).submit(input, options);\n }\n\n /** Stop one operation, or everything running in a session. */\n abort(\n options: PiSessionOptions & { readonly operationId?: string } = {}\n ): Promise<boolean> {\n return this.session(options.session).abort(options.operationId);\n }\n\n wait(\n operationId: string,\n options: PiSessionOptions & { readonly signal?: AbortSignal } = {}\n ): Promise<PiOperationResult> {\n return this.session(options.session).wait(operationId, options.signal);\n }\n\n /** The session's active transcript, as pi's entries. */\n messages(options: PiSessionOptions = {}): Promise<EntryRecord[]> {\n return this.session(options.session).messages();\n }\n\n /** Submissions pi has not settled yet, oldest first. */\n async pending(options: PiSessionOptions = {}): Promise<PiPendingOperation[]> {\n const { pi } = await this.#open();\n const id =\n options.session === undefined\n ? undefined\n : conversationId(options.session);\n return (await pi.inspect(BG)).submissions\n .filter(\n (record) =>\n record.requestId !== undefined &&\n (id === undefined || record.conversationId === id)\n )\n .map((record) => ({\n operationId: record.requestId as string,\n session: String(record.conversationId),\n status: record.status === \"queued\" ? \"queued\" : \"running\"\n }));\n }\n\n /** The opened pi Harness, for anything the interface does not cover. */\n async pi(): Promise<Harness> {\n return (await this.#open()).pi;\n }\n\n // ── Used by PiSession and PiSessions ─────────────────────────────────────\n\n /** @internal */\n async conversation(session: PiSessionId): Promise<Conversation> {\n const { pi } = await this.#open();\n const conversation = await pi.conversation(conversationId(session), BG);\n if (!conversation) throw new Error(`Unknown pi session ${session}`);\n return conversation;\n }\n\n /** @internal */\n async storage(): Promise<SqliteStorage> {\n return (await this.#open()).storage;\n }\n\n /** @internal */\n async enqueue(\n session: PiSessionId,\n input: UserInput,\n options: PiSubmitOptions\n ): Promise<PiReceipt> {\n const operationId = options.operationId ?? crypto.randomUUID();\n const { storage } = await this.#open();\n const conversation = await this.conversation(session);\n this.#admitting.set(session, (this.#admitting.get(session) ?? 0) + 1);\n let accepted: boolean;\n try {\n // 1. The wake first, so a job is scheduled before pi has the work.\n // If the object dies after pi admits the input, that job restarts\n // it. While this admission is in flight the step will not park.\n await this.#wake(session);\n // 2. The one admission. pi deduplicates by request id.\n accepted =\n (await storage.submissionByRequest(\n conversation.id,\n operationId,\n BG\n )) === undefined;\n await conversation.submit(\n {\n type: \"input\",\n content: input,\n whenBusy: options.whenBusy ?? \"followUp\",\n requestId: operationId,\n ...(options.entry ? { entry: options.entry } : {})\n },\n BG\n );\n } finally {\n const left = (this.#admitting.get(session) ?? 1) - 1;\n if (left === 0) this.#admitting.delete(session);\n else this.#admitting.set(session, left);\n }\n // 3. Step now, so the wake sees the work even if it just parked.\n await this.#wake(session);\n return { operationId, session, accepted };\n }\n\n /** @internal Withdraw a queued input, or abort the run it joined. */\n async withdraw(session: PiSessionId, operationId: string): Promise<boolean> {\n const { pi, storage } = await this.#open();\n const id = conversationId(session);\n const record = await storage.submissionByRequest(id, operationId, BG);\n if (!record || record.status === \"done\" || record.status === \"unanswered\") {\n return false;\n }\n const withdrawn = await pi.abortSubmission(record.id, BG, id);\n if (withdrawn === \"already_placed\") {\n await (await pi.conversation(id, BG))?.abort(BG);\n }\n return withdrawn !== \"settled\" && withdrawn !== \"not_found\";\n }\n\n /** @internal Wait for pi to settle an operation, by its request id. */\n async settled(\n session: PiSessionId,\n operationId: string,\n signal?: AbortSignal\n ): Promise<PiOperationResult> {\n const conversation = await this.conversation(session);\n const context = signalContext(signal);\n const submission = await this.#findSubmission(\n conversation.id,\n operationId,\n context\n );\n if (!submission) {\n return {\n operationId,\n session,\n status: \"unanswered\",\n reason: \"not_found\"\n };\n }\n return this.#result(\n session,\n operationId,\n await submission.wait(context),\n context\n );\n }\n\n // ── The wake ─────────────────────────────────────────────────────────────\n\n /** Schedule the session's wake job now, or pull it forward. */\n #wake(session: PiSessionId, time = Date.now()): Promise<unknown> {\n // A push made while the job is dispatching supersedes that dispatch's\n // outcome, so a submit is never lost to a wake that is completing.\n return this.lifecycle.jobs.push({\n id: wakeJobId(session),\n fn: WAKE_FN,\n time,\n payload: { session },\n singleflight: true,\n recoveryLoop: true\n });\n }\n\n /**\n * One run of a session's wake job. It never admits or replays anything:\n * it waits while pi has live tasks in the session and completes when it\n * has none. pi does all the work in between.\n */\n async #wakeStep(session: PiSessionId): Promise<LifecycleJobOutcome> {\n const heartbeat = { rescheduleAt: Date.now() + this.#heartbeatMs };\n if (this.#waits.has(session)) return heartbeat;\n const { pi } = await this.#open();\n const conversation = await pi.conversation(conversationId(session), BG);\n if (!conversation) return undefined;\n\n const tasks = (await pi.inspect(BG)).tasks.filter(\n (task) => task.record.conversationId === conversation.id\n );\n if (tasks.length === 0) {\n // A submit between its wake and pi's admission: check again later.\n return this.#admitting.has(session) ? heartbeat : undefined;\n }\n const wakeAt = await this.#longWait(pi, conversation.id, BG);\n if (wakeAt !== undefined) return { rescheduleAt: wakeAt };\n // Background tasks are outside the conversation's idle wait.\n if (tasks.every((task) => task.record.background)) return heartbeat;\n\n const wait = this.#waitForIdle(conversation).finally(() => {\n this.#waits.delete(session);\n // Re-check now: pi may have started more work, such as a follow-up.\n void this.#wake(session);\n });\n this.#waits.set(session, wait);\n // The wait runs past this dispatch, inside the alarm's work, so the\n // object stays alive for it. The heartbeat covers an eviction.\n this.lifecycle.trackAlarmWork(wait);\n return heartbeat;\n }\n\n async #waitForIdle(conversation: Conversation): Promise<void> {\n const budget = new AbortController();\n const timer = setTimeout(() => budget.abort(), this.#waitBudgetMs);\n try {\n // Cancelling the wait never cancels pi's work.\n await conversation.waitForIdle(withAbortSignal(budget.signal, BG));\n } catch (error) {\n if (!budget.signal.aborted) {\n this.lifecycle.events.emit(\"pi:wake_error\", {\n session: String(conversation.id),\n error: error instanceof Error ? error.message : String(error)\n });\n }\n } finally {\n clearTimeout(timer);\n }\n }\n\n // ── pi ───────────────────────────────────────────────────────────────────\n\n /**\n * pi, opened. Waits for Lifecycle startup first, so pi is only ever\n * opened inside it: startup holds the input gate (`blockConcurrencyWhile`)\n * and awaits the open in `onStart`, so an open begun before startup would\n * be awaited behind a closed gate, with its timers and I/O held back, and\n * never finish.\n */\n async #open(): Promise<Opened> {\n await this.lifecycle.ready();\n this.#opening ??= this.#doOpen().catch((error: unknown) => {\n this.#opening = undefined;\n throw error;\n });\n return this.#opening;\n }\n\n async #doOpen(): Promise<Opened> {\n const storage = await openPiSessionStore(this.lifecycle.storage);\n const pi = await this.#options.harness({ storage, context: BG });\n await pi.root(BG, { agent: this.agentDefaults() });\n // Continue whatever the last isolate left: pi reconciles tasks that were\n // running to pending and schedules them again.\n pi.resume();\n return { pi, storage };\n }\n\n /** @internal The per-conversation defaults supported by pi-durable. */\n agentDefaults(): AgentChange {\n const defaults = this.#options.defaults;\n return {\n ...(defaults?.model === undefined\n ? {}\n : { model: modelRef(defaults.model) }),\n ...(defaults?.thinkingLevel === undefined\n ? {}\n : { thinkingLevel: defaults.thinkingLevel })\n };\n }\n\n async #findSubmission(\n id: ConversationId,\n operationId: string,\n context: Context\n ) {\n const { pi, storage } = await this.#open();\n // Read from pi's storage: the Harness only reacquires submissions by id.\n const record = await storage.submissionByRequest(id, operationId, context);\n return record ? pi.submission(record.id, context) : undefined;\n }\n\n /** When pi's current wait is far enough away to hand to the alarm. */\n async #longWait(\n pi: Harness,\n id: ConversationId,\n context: Context\n ): Promise<number | undefined> {\n const live = await pi.snapshot(LiveDoc, id, context);\n const at =\n live?.generation?.deferred?.pollAt ?? live?.generation?.retry?.at;\n return at !== undefined && at - Date.now() > this.#sleepThresholdMs\n ? at\n : undefined;\n }\n\n async #result(\n session: PiSessionId,\n operationId: string,\n settled: SettledSubmissionRecord,\n context: Context\n ): Promise<PiOperationResult> {\n if (settled.status === \"unanswered\") {\n return {\n operationId,\n session,\n status: \"unanswered\",\n reason: settled.reason\n };\n }\n if (settled.type !== \"input\")\n return { operationId, session, status: \"done\" };\n const conversation = await this.conversation(session);\n const page = await conversation.entries(\n { minEntryId: settled.answer, maxEntryId: settled.answer },\n 1,\n undefined,\n context\n );\n return {\n operationId,\n session,\n status: \"done\",\n text: assistantText(page.items[0])\n };\n }\n}\n\n/** One pi conversation, addressed through the harness. */\nexport class PiSession {\n readonly #harness: PiHarness;\n readonly id: PiSessionId;\n\n constructor(harness: PiHarness, id: PiSessionId) {\n this.#harness = harness;\n this.id = id;\n }\n\n /** Durably submit a prompt. Resolves before the model runs. */\n submit(input: UserInput, options: PiSubmitOptions = {}): Promise<PiReceipt> {\n return this.#harness.enqueue(this.id, input, options);\n }\n\n /** Submit and wait for the answer and the updated transcript. */\n async prompt(\n input: UserInput,\n options: PiSubmitOptions = {}\n ): Promise<PiPromptResponse> {\n const receipt = await this.submit(input, options);\n const result = await this.wait(receipt.operationId);\n return { ...result, messages: await this.messages() };\n }\n\n /** Join the running work after its current tool round. */\n steer(input: UserInput, options: Omit<PiSubmitOptions, \"whenBusy\"> = {}) {\n return this.submit(input, { ...options, whenBusy: \"steer\" });\n }\n\n /** Wait for an operation to settle. Aborting `signal` stops only the wait. */\n wait(operationId: string, signal?: AbortSignal): Promise<PiOperationResult> {\n return this.#harness.settled(this.id, operationId, signal);\n }\n\n /**\n * Withdraw one queued operation (or abort the run it joined), or, with no\n * id, abort the session: pi withdraws queued inputs and aborts the\n * running work.\n */\n async abort(operationId?: string): Promise<boolean> {\n if (operationId !== undefined) {\n return this.#harness.withdraw(this.id, operationId);\n }\n const conversation = await this.#harness.conversation(this.id);\n await conversation.abort(BG);\n return true;\n }\n\n /** Start a new context, optionally from a handoff note. */\n async reset(handoff?: string): Promise<void> {\n await (await this.#harness.conversation(this.id)).reset(handoff, BG);\n }\n\n /**\n * Change this session's model, by its `provider` and `id`; it must be on\n * the `Models` the factory opened pi with (see `PiModel`).\n */\n async setModel(model: PiModel): Promise<void> {\n await (\n await this.#harness.conversation(this.id)\n ).configure({ model: modelRef(model) }, BG);\n }\n\n /** The active transcript, as pi's entries since the newest reset. */\n async messages(): Promise<EntryRecord[]> {\n const view = await (await this.#harness.conversation(this.id)).context(BG);\n return [...view.entries];\n }\n\n /** pi's agent events for this session: a snapshot, then one batch per commit. */\n async events(context: Context = BG): Promise<AgentEventStream> {\n const pi = await this.#harness.pi();\n return watchEvents(pi, conversationId(this.id), context);\n }\n\n async busy(): Promise<boolean> {\n const pi = await this.#harness.pi();\n const live = await pi.snapshot(LiveDoc, conversationId(this.id), BG);\n return live?.run !== undefined;\n }\n}\n\n/** Every pi conversation in this object. */\nexport class PiSessions {\n readonly #harness: PiHarness;\n\n constructor(harness: PiHarness) {\n this.#harness = harness;\n }\n\n get(id: PiSessionId): PiSession {\n return this.#harness.session(id);\n }\n\n /** A new top-level session, configured like the root. */\n async create(): Promise<PiSession> {\n const pi = await this.#harness.pi();\n const conversation = await pi.createConversation(\n {\n ownership: { kind: \"ownerless\" },\n agent: this.#harness.agentDefaults()\n },\n BG\n );\n return this.#harness.session(String(conversation.id));\n }\n\n /** A new session that sees `from`'s history up to its newest entry. */\n async fork(from: PiSessionId): Promise<PiSession> {\n const conversation = await this.#harness.conversation(from);\n const newest = await conversation.entries({}, 1, undefined, BG);\n const at = newest.items[0];\n if (!at) throw new Error(`Session ${from} has no entries to fork from`);\n const fork = await conversation.fork(\n at.id,\n { ownership: { kind: \"ownerless\" } },\n BG\n );\n return this.#harness.session(String(fork.id));\n }\n\n /**\n * Every conversation, including ones subagent tools own. Read from pi's\n * storage directly: the Harness has no conversation listing.\n */\n async list(): Promise<PiSessionInfo[]> {\n const storage = await this.#harness.storage();\n const pi = await this.#harness.pi();\n const sessions: PiSessionInfo[] = [];\n let cursor: Parameters<SqliteStorage[\"scanConversations\"]>[2];\n for (;;) {\n const page = await storage.scanConversations({}, 100, cursor, BG);\n for (const record of page.items) {\n const live = await pi.snapshot(LiveDoc, record.id, BG);\n sessions.push({\n id: String(record.id),\n ...(record.parent\n ? { parent: String(record.parent.conversationId) }\n : {}),\n busy: live?.run !== undefined\n });\n }\n if (page.next === undefined) return sessions;\n cursor = page.next;\n }\n }\n}\n","import { Type } from \"@earendil-works/pi-ai\";\nimport type {\n Extension,\n ToolExecutionResult,\n ToolRegistration\n} from \"@earendil-works/pi-durable\";\nimport type {\n SkillContent,\n SkillDescriptor,\n SkillResourceDescriptor,\n SkillSource\n} from \"../../skills\";\n\n/** Skills resolved from `agents/skills` sources for one process lifetime. */\nexport type ResolvedSkills = {\n /** Changes when any source's fingerprint changes. */\n readonly fingerprint: string;\n /** Model-facing activation tools; empty when there are no skills. */\n readonly tools: readonly ToolRegistration[];\n /** System-prompt catalog, or null when there are no skills. */\n readonly catalog: string | null;\n readonly warnings: readonly string[];\n};\n\ntype ResolvedSkill = {\n readonly descriptor: SkillDescriptor;\n readonly content: SkillContent;\n readonly source: SkillSource;\n};\n\nexport function skillsFingerprint(sources: readonly SkillSource[]): string {\n return sources\n .map((source) => `${source.id}:${source.fingerprint}`)\n .join(\"|\");\n}\n\nfunction textResult(text: string): ToolExecutionResult {\n return { output: [{ type: \"text\", text }] };\n}\n\nfunction attributes(\n pairs: ReadonlyArray<readonly [string, string | undefined]>\n) {\n return pairs\n .filter((pair): pair is readonly [string, string] => pair[1] !== undefined)\n .map(([key, value]) => ` ${key}=\"${value.replace(/\"/g, \"&quot;\")}\"`)\n .join(\"\");\n}\n\nfunction describeResource(resource: SkillResourceDescriptor): string {\n const details = [\n resource.kind,\n resource.encoding ?? \"text\",\n resource.mimeType,\n resource.size === undefined ? undefined : `${resource.size} bytes`\n ].filter((value): value is string => value !== undefined);\n return `- ${resource.path} (${details.join(\", \")})`;\n}\n\nfunction renderSkillContent(skill: ResolvedSkill): string {\n const resources = skill.content.resources ?? [];\n const lines = [\n `<skill_content${attributes([\n [\"name\", skill.descriptor.name],\n [\"version\", skill.descriptor.version]\n ])}>`,\n skill.content.body.trim()\n ];\n if (resources.length > 0) {\n lines.push(\"<skill_resources>\");\n for (const resource of resources) {\n lines.push(\n ` <file${attributes([\n [\"kind\", resource.kind],\n [\"encoding\", resource.encoding ?? \"text\"],\n [\n \"size\",\n resource.size === undefined ? undefined : String(resource.size)\n ]\n ])}>${resource.path}</file>`\n );\n }\n lines.push(\"</skill_resources>\");\n }\n lines.push(\"</skill_content>\", \"\");\n lines.push(\n resources.length === 0\n ? \"No bundled resources.\"\n : [\"Bundled resources:\", ...resources.map(describeResource)].join(\"\\n\")\n );\n return lines.join(\"\\n\");\n}\n\n/**\n * Resolve `agents/skills` sources into a system-prompt catalog and two\n * tools.\n *\n * The first source to list a name wins, as in `SkillRegistry`. pi-durable\n * has no skill concept of its own, so the model activates skills through\n * `activate_skill` and reads bundled files through `read_skill_resource` —\n * the same tools `@cloudflare/think` offers, so skills authored for one\n * framework work in the other.\n */\nexport async function resolveSkillSources(\n sources: readonly SkillSource[]\n): Promise<ResolvedSkills> {\n const fingerprint = skillsFingerprint(sources);\n const warnings: string[] = [];\n const resolved = new Map<string, ResolvedSkill>();\n for (const source of sources) {\n let descriptors: SkillDescriptor[];\n try {\n descriptors = await source.list();\n } catch (error) {\n warnings.push(\n `Skill source \"${source.id}\" failed to list skills: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n continue;\n }\n for (const descriptor of descriptors) {\n if (resolved.has(descriptor.name)) {\n warnings.push(\n `Skill \"${descriptor.name}\" from source \"${source.id}\" is shadowed by an earlier source`\n );\n continue;\n }\n let content: SkillContent | null;\n try {\n content = await source.load(descriptor.name);\n } catch (error) {\n warnings.push(\n `Skill \"${descriptor.name}\" from source \"${source.id}\" failed to load: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n continue;\n }\n if (!content) continue;\n resolved.set(descriptor.name, { descriptor, content, source });\n }\n }\n\n const visible = [...resolved.values()].filter(\n (skill) => skill.descriptor.metadata?.[\"disable-model-invocation\"] !== true\n );\n if (visible.length === 0) {\n return { fingerprint, tools: [], catalog: null, warnings };\n }\n\n const names = visible.map((skill) => skill.descriptor.name);\n const nameSchema = Type.Union(names.map((name) => Type.Literal(name)));\n const byName = new Map(\n visible.map((skill) => [skill.descriptor.name, skill])\n );\n\n const activateParameters = Type.Object({ name: nameSchema });\n const activateSkill: ToolRegistration<typeof activateParameters> = {\n name: \"activate_skill\",\n description:\n \"Activate a skill by name. Use this when the user's task matches one of the available skills; the response contains the skill's full instructions.\",\n parameters: activateParameters,\n replay: \"safe\",\n async execute(input) {\n const skill = byName.get(input.name);\n return textResult(\n skill ? renderSkillContent(skill) : `Skill not found: ${input.name}`\n );\n }\n };\n\n const resourceParameters = Type.Object({\n name: Type.Optional(nameSchema),\n path: Type.String({ minLength: 1 })\n });\n const readResource: ToolRegistration<typeof resourceParameters> = {\n name: \"read_skill_resource\",\n description:\n \"Read a file bundled with a skill, such as a reference document or template. Provide the skill name and the file's path from the skill's resource list.\",\n parameters: resourceParameters,\n replay: \"safe\",\n async execute(input) {\n const target = resolveResourceTarget(byName, input.name, input.path);\n if (!target) {\n return textResult(\n `Skill resource not found: ${input.name ? `${input.name}/` : \"\"}${input.path}`\n );\n }\n const resource = await target.skill.source\n .readResource?.(target.skill.descriptor.name, target.path)\n .catch(() => null);\n if (!resource) {\n return textResult(\n `Skill resource not found: ${target.skill.descriptor.name}/${target.path}`\n );\n }\n return textResult(\n [\n `<skill_resource${attributes([\n [\"name\", target.skill.descriptor.name],\n [\"path\", resource.path],\n [\"kind\", resource.kind],\n [\"encoding\", resource.encoding ?? \"text\"],\n [\"mimeType\", resource.mimeType]\n ])}>`,\n resource.content,\n \"</skill_resource>\"\n ].join(\"\\n\")\n );\n }\n };\n\n const catalog = [\n \"Available skills. When a task matches a skill, use activate_skill with its name before proceeding.\",\n \"\",\n ...visible.map(\n (skill) => `- ${skill.descriptor.name}: ${skill.descriptor.description}`\n )\n ].join(\"\\n\");\n\n return {\n fingerprint,\n tools: [activateSkill, readResource],\n catalog,\n warnings\n };\n}\n\nfunction resolveResourceTarget(\n byName: ReadonlyMap<string, ResolvedSkill>,\n name: string | undefined,\n path: string\n): { readonly skill: ResolvedSkill; readonly path: string } | undefined {\n if (path.split(\"/\").some((segment) => segment === \"..\")) return undefined;\n if (name !== undefined) {\n const skill = byName.get(name);\n return skill && hasResource(skill, path) ? { skill, path } : undefined;\n }\n // A qualified path names the skill in its first segment.\n const [head, ...rest] = path.split(\"/\");\n const skill = head === undefined ? undefined : byName.get(head);\n const relative = rest.join(\"/\");\n return skill && relative && hasResource(skill, relative)\n ? { skill, path: relative }\n : undefined;\n}\n\nfunction hasResource(skill: ResolvedSkill, path: string): boolean {\n return (skill.content.resources ?? []).some(\n (resource) => resource.path === path\n );\n}\n\n/**\n * `agents/skills` sources as a pi extension, named `agents.skills`: the\n * activation tools and a `skills` system prompt section. Install it on\n * pi's registry in the harness factory.\n *\n * ```ts\n * registry.install(await skills(sources));\n * ```\n */\nexport async function skills(\n sources: readonly SkillSource[]\n): Promise<Extension> {\n const resolved = await resolveSkillSources(sources);\n for (const warning of resolved.warnings) {\n console.warn(`pi skills: ${warning}`);\n }\n const catalog = resolved.catalog;\n return {\n name: \"agents.skills\",\n tools: resolved.tools,\n sections: catalog === null ? [] : [{ key: \"skills\", render: () => catalog }]\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/harness/pi/session-store.ts","../../../src/harness/pi/harness.ts","../../../src/harness/pi/skills.ts"],"sourcesContent":["import type { SqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite\";\nimport { openDurableObjectSqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite/cloudflare\";\n\n/**\n * pi's session store on a Durable Object's SQLite database.\n *\n * pi owns its sessions: conversations, entries, tasks, submissions, and\n * documents live in pi's own schema, created and migrated by pi's portable\n * `SqliteStorage` through pi's own Durable Object adapter. The store keeps\n * pi's tables under a prefix, so they cannot collide with the SDK's or the\n * host's tables in the same object.\n *\n * It is the Durable Object counterpart of `agents/sessions` for a harness\n * that brings its own session model, and has nothing pi-harness specific in\n * it: any harness built on pi-durable can open its storage with it.\n */\nexport type PiSessionStoreOptions = {\n /**\n * Prefix for every table and index pi creates. Must not start with `_cf_`,\n * which Durable Objects reserve. Default `pi_`.\n */\n readonly prefix?: string;\n};\n\nconst DEFAULT_PREFIX = \"pi_\";\n\n/** Open pi-durable's storage over this object's SQLite database. */\nexport function openPiSessionStore(\n storage: DurableObjectStorage,\n options: PiSessionStoreOptions = {}\n): Promise<SqliteStorage> {\n const prefix = options.prefix ?? DEFAULT_PREFIX;\n // pi validates the prefix as a SQLite identifier; Durable Objects also\n // reserve `_cf_` in any case, which pi does not know about.\n if (prefix.toLowerCase().startsWith(\"_cf_\")) {\n return Promise.reject(\n new Error(\"The pi session store prefix must not start with _cf_\")\n );\n }\n return openDurableObjectSqliteStorage(storage, { prefix });\n}\n","import type { Api, Model, ModelThinkingLevel } from \"@earendil-works/pi-ai\";\nimport {\n LiveDoc,\n ROOT_CONVERSATION_ID,\n watchEvents,\n type AgentEventStream,\n type Conversation,\n type ConversationId,\n type AgentChange,\n type EntryRecord,\n type Harness,\n type HarnessInspection,\n type ModelRef,\n type SettledSubmissionRecord,\n type TaskId,\n type UserInput,\n type Wake\n} from \"@earendil-works/pi-durable\";\nimport type { SqliteStorage } from \"@earendil-works/pi-durable/storage/sqlite\";\nimport {\n LifecycleCapability,\n type CapabilityStartContext,\n type LifecycleJobContext,\n type LifecycleJobOutcome\n} from \"../../lifecycle\";\nimport { isDurableObjectMemoryLimitReset } from \"../../retries\";\nimport {\n BACKGROUND_CONTEXT,\n withAbortSignal,\n type Context\n} from \"@earendil-works/chord/context\";\nimport { openPiSessionStore } from \"./session-store\";\nimport type {\n PiOperationResult,\n PiPendingOperation,\n PiPromptResponse,\n PiReceipt,\n PiSessionId,\n PiSessionInfo,\n PiSessionOptions,\n PiSubmitOptions\n} from \"./types\";\n\nconst BG = BACKGROUND_CONTEXT;\n\n/** The root session's id. */\nexport const ROOT_SESSION: PiSessionId = String(ROOT_CONVERSATION_ID);\n\n/**\n * The wake timings. They suit a real deployment; only tests change them,\n * with `setWakeTimingForTests`, so a suite does not sit on the real\n * heartbeat.\n *\n * Longest one wake waits on pi. It waits inside an alarm invocation, which\n * has a 15 minute wall-time limit, so a longer run is waited on across\n * several alarms.\n */\nconst WAIT_BUDGET_MS = 10 * 60_000;\n\n/**\n * The wake job's heartbeat while it waits, and how often it re-checks work\n * it cannot wait on, such as background tasks. If the object is evicted, the\n * job is still due and its alarm restarts the object.\n */\nconst HEARTBEAT_MS = 30_000;\n\n/**\n * How often a wait re-reads `pi.wake()` when the factory did not pass\n * `onWake`, so nothing tells the harness when it changes.\n */\nconst POLL_MS = 1_000;\n\n/**\n * The longest a wake job whose dispatch keeps failing waits before it tries\n * again. Its delay starts at the heartbeat and doubles up to this.\n */\nconst MAX_WAKE_BACKOFF_MS = 10 * 60_000;\n\n/**\n * Wake dispatches that failed in a row. Stored, so the backoff holds across\n * restarts, and outside the job: a push that saved it in the job's payload\n * could overwrite a submit's due-now push.\n */\nconst WAKE_ERRORS_KEY = \"pi-harness:wake-errors\";\n\nlet setWakeTiming: (harness: PiHarness, timing: WakeTiming) => void;\n\n/**\n * @internal Shorten a harness's wake timings, so a test suite does not sit\n * on the real heartbeat. Not exported from `agents/harness/pi`.\n */\nexport function setWakeTimingForTests(\n harness: PiHarness,\n timing: WakeTiming\n): void {\n setWakeTiming(harness, timing);\n}\n\nconst WAKE_FN = \"wake\";\n\n/**\n * The one wake job. Before Pi 1.4 there was one per session, with ids\n * `pi-wake:<session>`; a left-over one hands over to this one.\n */\nconst WAKE_JOB_ID = \"pi-wake\";\n\n/**\n * What the factory is handed: the things only the harness can build.\n * Everything else `Harness.open` takes (models, registry, settings, env,\n * onReport) the factory builds itself.\n */\nexport type PiHarnessContext = {\n /** pi's storage over this object's SQLite, its migrations already run. */\n readonly storage: SqliteStorage;\n /** Background context, for the open itself. */\n readonly context: Context;\n /**\n * Pass this to `Harness.open` as its `onWake` option. pi calls it when it\n * next needs to run, and the harness sets this object's alarm for then.\n *\n * With it, pi sets no in-memory timer for a sleeping task (a retry\n * backoff, a poll, a `sleepUntil`), so the object can hibernate until the\n * alarm. Without it the harness still works, but pi's timer keeps the\n * object in memory, and billed, while a task sleeps, and the harness logs\n * a warning when it opens pi.\n */\n readonly onWake: (wake: Wake) => void;\n};\n\n/**\n * Opens pi's `Harness`. The harness adopts what it returns. Pass `onWake`\n * through to `Harness.open`.\n *\n * ```ts\n * harness: async ({ storage, context, onWake }) => {\n * const registry = createRegistry();\n * registry.install(await skills(sources));\n * return Harness.open(storage, { models, registry, onWake }, context);\n * }\n * ```\n */\nexport type PiHarnessFactory = (\n context: PiHarnessContext\n) => Harness | Promise<Harness>;\n\n/**\n * A model, as pi-ai describes one: `createAI`'s `ai(\"@cf/…\")` returns one.\n *\n * Only its `provider` and `id` are used. pi stores that reference with\n * the session and resolves it, at each request, against the `Models` the\n * factory opened pi with. So the model must be one those `Models` list,\n * and options passed to `ai(id, options)` here, such as `fallback`, are not\n * applied.\n */\nexport type PiModel = Pick<Model<Api>, \"provider\" | \"id\">;\n\n/**\n * Applied to a session the first time it is created. Without a model, a\n * session's generation fails as unanswered until `session.setModel` sets one.\n */\nexport type PiSessionDefaults = {\n /**\n * Model for new sessions, by its `provider` and `id`; it must be on the\n * `Models` the factory opens pi with (see `PiModel`). Change one\n * session's with `session.setModel`.\n */\n readonly model?: PiModel;\n readonly thinkingLevel?: ModelThinkingLevel;\n};\n\n/** How long the wake waits on pi, and how often it checks. */\ntype WakeTiming = {\n /** Longest one wake waits inside an alarm. Default 600_000. */\n readonly waitBudgetMs?: number;\n /** Heartbeat while waiting. Default 30_000. */\n readonly heartbeatMs?: number;\n /** How often a wait re-reads `pi.wake()` without `onWake`. Default 1_000. */\n readonly pollMs?: number;\n};\n\n/** `PiHarness`'s options. Only `harness`, which opens pi, is required. */\nexport type PiHarnessOptions = {\n /** Opens pi's `Harness` over the storage this object prepared. */\n readonly harness: PiHarnessFactory;\n /** What a new session starts with. */\n readonly defaults?: PiSessionDefaults;\n};\n\ntype Opened = {\n readonly pi: Harness;\n readonly storage: SqliteStorage;\n};\n\n/** pi-durable's stored reference to a pi-ai model. */\nfunction modelRef(model: PiModel): ModelRef {\n return { provider: model.provider, modelId: model.id };\n}\n\nfunction conversationId(session: PiSessionId): ConversationId {\n const id = Number(session);\n if (!Number.isSafeInteger(id) || id < 1) {\n throw new Error(`Invalid pi session ${JSON.stringify(session)}`);\n }\n return id as ConversationId;\n}\n\n/** The text of an assistant entry, for an operation's result. */\nfunction assistantText(entry: EntryRecord | undefined): string {\n const message = entry?.model?.[0];\n if (message?.role !== \"assistant\") return \"\";\n return message.content\n .map((part) => (part.type === \"text\" ? part.text : \"\"))\n .join(\"\");\n}\n\nfunction signalContext(signal: AbortSignal | undefined): Context {\n return signal ? withAbortSignal(signal, BG) : BG;\n}\n\n/**\n * pi-durable hosted in a Durable Object, behind a small harness interface:\n * `harness.prompt()`, `harness.sessions`, `harness.session(id)`. How a session reaches a\n * client (sockets, SSE, RPC) is the host's glue, built on `session.events()`.\n *\n * pi owns everything about a run: the transcript, the inbox of steers and\n * follow-ups, generation and tool tasks, retries, crash recovery, and the\n * live view. It keeps all of it in its own tables in this object's SQLite\n * database (see `session-store.ts`).\n *\n * What pi cannot do on a Durable Object is wake itself: its scheduler runs\n * in memory, and an evicted object has no memory. The harness is that wake,\n * with one Lifecycle job driven by `pi.wake()`. Input goes to pi once, in\n * `submit()`, after the job is scheduled. While pi has work running, the\n * job waits on it, rescheduling itself as a heartbeat. While pi's tasks\n * sleep, the job is due when the first one wakes; pi tells the harness\n * through the `onWake` the factory passes to `Harness.open`. When pi has\n * nothing to do, the job completes. An eviction mid-run leaves the job due,\n * so its alarm restarts the object, pi reopens and resumes its own tasks,\n * and the job waits again.\n *\n * @beta The API may change between releases.\n */\nexport class PiHarness extends LifecycleCapability {\n readonly sessions: PiSessions;\n readonly #options: PiHarnessOptions;\n /** The in-memory wait on pi's running work, inside an alarm's work. */\n #waiting: Promise<void> | undefined;\n /** Resolves the current wait's sleep early: `pi.wake()` changed. */\n #changed: (() => void) | undefined;\n /** Submissions between their wake and pi's admission. */\n #admitting = 0;\n /** Whether pi has called `onWake`, so the factory passed it. */\n #onWakeWired = false;\n #waitBudgetMs = WAIT_BUDGET_MS;\n #heartbeatMs = HEARTBEAT_MS;\n #pollMs = POLL_MS;\n #opening: Promise<Opened> | undefined;\n /** Settles once the last pi that closed on its own has closed. */\n #lastClose: Promise<unknown> = Promise.resolve();\n /** Every pi that has begun closing, on its own or by `dispose()`. */\n readonly #closing = new WeakSet<Harness>();\n\n static {\n setWakeTiming = (harness, timing) => harness.#setWakeTiming(timing);\n }\n\n constructor(options: PiHarnessOptions) {\n super(\"pi-harness\");\n this.#options = options;\n this.sessions = new PiSessions(this);\n }\n\n #setWakeTiming(timing: WakeTiming): void {\n for (const [name, value] of Object.entries(timing)) {\n if (!Number.isFinite(value) || value <= 0) {\n throw new Error(`PiHarness timing.${name} must be a positive number`);\n }\n }\n this.#waitBudgetMs = timing.waitBudgetMs ?? this.#waitBudgetMs;\n this.#heartbeatMs = timing.heartbeatMs ?? this.#heartbeatMs;\n this.#pollMs = timing.pollMs ?? this.#pollMs;\n }\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n override async onStart(_context: CapabilityStartContext): Promise<void> {\n await this.#open();\n }\n\n async onJob(\n context: LifecycleJobContext\n ): Promise<LifecycleJobOutcome | void> {\n if (context.job.fn !== WAKE_FN) return;\n let outcome: LifecycleJobOutcome;\n if (context.job.id !== WAKE_JOB_ID) {\n // A per-session wake from before Pi 1.4: hand over to the one wake.\n await this.#wake();\n outcome = undefined;\n } else {\n outcome = await this.#wakeStep();\n }\n // It got through, so a failing wake's backoff starts over.\n const kv = this.lifecycle.storage.kv;\n if (kv.get(WAKE_ERRORS_KEY) !== undefined) kv.delete(WAKE_ERRORS_KEY);\n return outcome;\n }\n\n /**\n * A wake dispatch that failed through Lifecycle's retries, as when pi\n * cannot be opened. Lifecycle would complete the job, and pi's work would\n * never be woken again, so try again later: at the heartbeat, doubling\n * while the failures continue, up to 10 minutes.\n */\n onJobError(\n context: LifecycleJobContext,\n error: unknown\n ): LifecycleJobOutcome | void {\n if (context.job.fn !== WAKE_FN) return;\n console.error(\n `pi wake job \"${context.job.id}\" failed after ${context.attempt} ` +\n \"attempts; retrying with backoff\",\n error\n );\n this.#wakeError(error);\n const kv = this.lifecycle.storage.kv;\n const errors = (kv.get<number>(WAKE_ERRORS_KEY) ?? 0) + 1;\n kv.put(WAKE_ERRORS_KEY, errors);\n const delay = Math.min(\n this.#heartbeatMs * 2 ** (errors - 1),\n MAX_WAKE_BACKOFF_MS\n );\n return { rescheduleAt: Date.now() + delay };\n }\n\n /** Close pi's in-memory resources. Durable state is untouched. */\n async dispose(): Promise<void> {\n const opening = this.#opening;\n this.#opening = undefined;\n const opened = await opening?.catch(() => undefined);\n // Closing calls #piClosing, which also ends a wait sleeping on this pi.\n await opened?.pi.close(BG);\n }\n\n // ── The harness interface ────────────────────────────────────────────────\n\n /** A handle on one session. No I/O until you call it. */\n session(id: PiSessionId = ROOT_SESSION): PiSession {\n return new PiSession(this, id);\n }\n\n /** Submit a prompt and wait for its answer. */\n prompt(\n input: UserInput,\n options: PiSubmitOptions = {}\n ): Promise<PiPromptResponse> {\n return this.session(options.session).prompt(input, options);\n }\n\n /** Durably submit a prompt. Resolves before the model runs. */\n submit(input: UserInput, options: PiSubmitOptions = {}): Promise<PiReceipt> {\n return this.session(options.session).submit(input, options);\n }\n\n /** Stop one operation, or everything running in a session. */\n abort(\n options: PiSessionOptions & { readonly operationId?: string } = {}\n ): Promise<boolean> {\n return this.session(options.session).abort(options.operationId);\n }\n\n /**\n * Run again the tasks pi's crash-loop guard parked in a session's work.\n * False when nothing was parked.\n */\n retry(options: PiSessionOptions = {}): Promise<boolean> {\n return this.session(options.session).retry();\n }\n\n wait(\n operationId: string,\n options: PiSessionOptions & { readonly signal?: AbortSignal } = {}\n ): Promise<PiOperationResult> {\n return this.session(options.session).wait(operationId, options.signal);\n }\n\n /** The session's active transcript, as pi's entries. */\n messages(options: PiSessionOptions = {}): Promise<EntryRecord[]> {\n return this.session(options.session).messages();\n }\n\n /** Submissions pi has not settled yet, oldest first. */\n async pending(options: PiSessionOptions = {}): Promise<PiPendingOperation[]> {\n const { pi } = await this.#open();\n const id =\n options.session === undefined\n ? undefined\n : conversationId(options.session);\n const inspection = await pi.inspect(BG);\n const parked = await this.#parked(inspection);\n return inspection.submissions\n .filter(\n (record) =>\n record.requestId !== undefined &&\n (id === undefined || record.conversationId === id)\n )\n .map((record) => ({\n operationId: record.requestId as string,\n session: String(record.conversationId),\n status:\n record.status === \"queued\"\n ? \"queued\"\n : parked.some((task) => task.sessions.has(record.conversationId))\n ? \"parked\"\n : \"running\"\n }));\n }\n\n /** The opened pi Harness, for anything the interface does not cover. */\n async pi(): Promise<Harness> {\n return (await this.#open()).pi;\n }\n\n // ── Used by PiSession and PiSessions ─────────────────────────────────────\n\n /** @internal */\n async conversation(session: PiSessionId): Promise<Conversation> {\n const { pi } = await this.#open();\n const conversation = await pi.conversation(conversationId(session), BG);\n if (!conversation) throw new Error(`Unknown pi session ${session}`);\n return conversation;\n }\n\n /** @internal */\n async storage(): Promise<SqliteStorage> {\n return (await this.#open()).storage;\n }\n\n /** @internal */\n async enqueue(\n session: PiSessionId,\n input: UserInput,\n options: PiSubmitOptions\n ): Promise<PiReceipt> {\n const operationId = options.operationId ?? crypto.randomUUID();\n const { storage } = await this.#open();\n const conversation = await this.conversation(session);\n const accepted = await this.#admit(async () => {\n // The one admission. pi deduplicates by request id.\n const accepted =\n (await storage.submissionByRequest(\n conversation.id,\n operationId,\n BG\n )) === undefined;\n await conversation.submit(\n {\n type: \"input\",\n content: input,\n whenBusy: options.whenBusy ?? \"followUp\",\n requestId: operationId,\n ...(options.entry ? { entry: options.entry } : {})\n },\n BG\n );\n return accepted;\n });\n return { operationId, session, accepted };\n }\n\n /** @internal Run again the tasks pi's restart limit parked in a session. */\n async retryParked(session: PiSessionId): Promise<boolean> {\n const { pi } = await this.#open();\n const id = conversationId(session);\n const parked = (await this.#parked(await pi.inspect(BG))).filter((task) =>\n task.sessions.has(id)\n );\n if (parked.length === 0) return false;\n await this.#admit(async () => {\n for (const task of parked) await pi.retryTask(task.id, BG);\n });\n return true;\n }\n\n /** @internal Withdraw a queued input, or abort the run it joined. */\n async withdraw(session: PiSessionId, operationId: string): Promise<boolean> {\n const { pi, storage } = await this.#open();\n const id = conversationId(session);\n const record = await storage.submissionByRequest(id, operationId, BG);\n if (!record || record.status === \"done\" || record.status === \"unanswered\") {\n return false;\n }\n const withdrawn = await pi.abortSubmission(record.id, BG, id);\n if (withdrawn === \"already_placed\") {\n await (await pi.conversation(id, BG))?.abort(BG);\n }\n return withdrawn !== \"settled\" && withdrawn !== \"not_found\";\n }\n\n /** @internal Wait for pi to settle an operation, by its request id. */\n async settled(\n session: PiSessionId,\n operationId: string,\n signal?: AbortSignal\n ): Promise<PiOperationResult> {\n const conversation = await this.conversation(session);\n const context = signalContext(signal);\n const submission = await this.#findSubmission(\n conversation.id,\n operationId,\n context\n );\n if (!submission) {\n return {\n operationId,\n session,\n status: \"unanswered\",\n reason: \"not_found\"\n };\n }\n return this.#result(\n session,\n operationId,\n await submission.wait(context),\n context\n );\n }\n\n // ── The wake ─────────────────────────────────────────────────────────────\n\n /**\n * Hand pi work inside the wake. The wake is scheduled first, so if the\n * object dies after pi has the work, that job restarts it; while `hand`\n * is in flight the step will not complete. The wake steps again after, so\n * it sees the work even if it just completed.\n */\n async #admit<T>(hand: () => Promise<T>): Promise<T> {\n this.#admitting++;\n let result: T;\n try {\n await this.#wake();\n result = await hand();\n } finally {\n this.#admitting--;\n }\n await this.#wake();\n return result;\n }\n\n /** Schedule the wake job now, or at `time`. */\n #wake(time = Date.now()): Promise<unknown> {\n // A push made while the job is dispatching supersedes that dispatch's\n // outcome, so a submit is never lost to a wake that is completing.\n return this.lifecycle.jobs.push({\n id: WAKE_JOB_ID,\n fn: WAKE_FN,\n time,\n singleflight: true,\n recoveryLoop: true\n });\n }\n\n /** Schedule the wake job for what `pi.wake()` says, if pi needs one. */\n async #wakeFor(wake: Wake): Promise<void> {\n if (wake.active) await this.#wake();\n else if (wake.at !== undefined) await this.#wake(wake.at);\n }\n\n /**\n * pi's `onWake`, handed to the factory. pi calls it after open and\n * whenever `pi.wake()` changes. It must not block, so the job push is\n * left running.\n */\n readonly #onWake = (wake: Wake): void => {\n this.#onWakeWired = true;\n this.#changed?.();\n // A running wait re-reads pi.wake() and steps again when it ends.\n if (this.#waiting) return;\n this.#wakeFor(wake).catch((error: unknown) => this.#wakeError(error));\n };\n\n /**\n * One run of the wake job. It never admits or replays anything: it reads\n * `pi.wake()`, which is all of pi's sessions at once. Running work is\n * waited on; a sleep reschedules the job for when it ends; no work\n * completes the job. pi does all the work in between.\n */\n async #wakeStep(): Promise<LifecycleJobOutcome> {\n const heartbeat = { rescheduleAt: Date.now() + this.#heartbeatMs };\n if (this.#waiting) return heartbeat;\n const { pi } = await this.#open();\n // The alarm may be for a sleeping task: make due ones runnable.\n pi.resume();\n const wake = pi.wake();\n if (wake.active) {\n const wait = this.#waitWhileActive(pi).then(\n (ended) => {\n this.#waiting = undefined;\n // Step again now: pi may be sleeping, or have nothing left. After\n // a failed wait, as when pi's Session fails, the heartbeat that is\n // already due steps instead, so a pi that keeps failing is not\n // reopened in a loop.\n if (ended) void this.#wake();\n },\n (error: unknown) => {\n // A memory-limit reset: the alarm's breaker backs the job off.\n this.#waiting = undefined;\n throw error;\n }\n );\n this.#waiting = wait;\n // The wait runs past this dispatch, inside the alarm's work, so the\n // object stays alive for it, and a memory-limit reset it ends with\n // counts against the alarm's breaker. The heartbeat covers an\n // eviction.\n if (!this.lifecycle.trackAlarmWork(wait)) wait.catch(() => {});\n return heartbeat;\n }\n // A submit between its wake and pi's admission: check again later.\n if (this.#admitting > 0) return heartbeat;\n if (wake.at !== undefined) return { rescheduleAt: wake.at };\n // Nothing to do. A task parked by pi's restart limit is not work: it\n // waits for `retry()`.\n return undefined;\n }\n\n /**\n * Wait while pi has work running, up to the wait budget. With `onWake`, a\n * change ends each sleep early, and so does pi closing; without it, the\n * sleep is `pollMs`. Whether the wait ended, with pi idle or at the\n * budget, rather than failing. Rejects with a memory-limit reset.\n */\n async #waitWhileActive(pi: Harness): Promise<boolean> {\n const deadline = Date.now() + this.#waitBudgetMs;\n try {\n // Once pi begins closing, pi.wake() throws (SessionFailed after a\n // storage error), which is what ends this loop: a closed pi's wake does\n // not go inactive. Closing kicks `#changed` only so the loop reads it\n // again now rather than at the end of its sleep.\n while (pi.wake().active) {\n const left = deadline - Date.now();\n if (left <= 0) return true;\n await new Promise<void>((resolve) => {\n const timer = setTimeout(\n resolve,\n this.#onWakeWired ? left : Math.min(left, this.#pollMs)\n );\n this.#changed = () => {\n clearTimeout(timer);\n resolve();\n };\n });\n this.#changed = undefined;\n }\n return true;\n } catch (error) {\n // A pi that began closing is expected to throw; it is no longer the\n // harness's pi, and Pi reports a failure itself (`session_failed`).\n if (!this.#closing.has(pi)) this.#wakeError(error);\n // Only Lifecycle's alarm breaker can act on a memory-limit reset,\n // including one that failed pi's Session (SessionFailed's cause).\n if (isDurableObjectMemoryLimitReset(error)) throw error;\n return false;\n }\n }\n\n #wakeError(error: unknown): void {\n this.lifecycle.events.emit(\"pi:wake_error\", {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n\n // ── pi ───────────────────────────────────────────────────────────────────\n\n /**\n * pi, opened. Waits for Lifecycle startup first, so pi is only ever\n * opened inside it: startup holds the input gate (`blockConcurrencyWhile`)\n * and awaits the open in `onStart`, so an open begun before startup would\n * be awaited behind a closed gate, with its timers and I/O held back, and\n * never finish.\n *\n * pi stays open until `dispose()`, or until it closes on its own: any\n * storage error fails pi's Session for good. Then the next call, or the\n * wake job's next step, opens pi again once the failed pi has closed, and\n * pi recovers from what it had committed. Closing waits for running task\n * code to return, so code that ignores its abort signal delays the reopen.\n * An open that fails is not kept either, so the next call tries again.\n */\n async #open(): Promise<Opened> {\n await this.lifecycle.ready();\n if (this.#opening === undefined) {\n const opening: Promise<Opened> = this.#doOpen((pi, closed) =>\n this.#piClosing(opening, pi, closed)\n ).catch((error: unknown) => {\n if (this.#opening === opening) this.#opening = undefined;\n throw error;\n });\n this.#opening = opening;\n }\n return this.#opening;\n }\n\n async #doOpen(\n onClose: (pi: Harness, closed: Promise<unknown>) => void\n ): Promise<Opened> {\n // A pi that closed on its own closes its storage last, after its tasks\n // have returned; let it finish before another opens over the same\n // database.\n await this.#lastClose;\n const storage = await openPiSessionStore(this.lifecycle.storage);\n const pi = await this.#options.harness({\n storage,\n context: BG,\n onWake: this.#onWake\n });\n try {\n const closed = pi.closed;\n // Called synchronously when pi begins closing, unlike `closed`, so a\n // closed pi is never handed out. It must not call pi.\n pi.subscribeClose(() => onClose(pi, closed));\n await pi.root(BG, { agent: this.agentDefaults() });\n // Continue whatever the last pi left, in this isolate or the last one:\n // pi reconciles tasks that were running to pending and schedules them\n // again.\n pi.resume();\n // pi calls onWake right after open, from a microtask.\n await new Promise((resolve) => setTimeout(resolve, 0));\n if (!this.#onWakeWired) {\n console.warn(\n \"PiHarness: the harness factory did not pass onWake to Harness.open, \" +\n \"so pi's timers keep this Durable Object in memory while a task \" +\n \"sleeps. Pass it: harness: ({ storage, context, onWake }) => \" +\n \"Harness.open(storage, { ...options, onWake }, context)\"\n );\n }\n // Whatever the last pi left gets a wake, including work whose wake\n // failed out. With `onWake`, pi has already said so; this covers a\n // factory without it. The job id is fixed, so this is idempotent.\n await this.#wakeFor(pi.wake());\n } catch (error) {\n // pi is open and running its tasks: close it, so the next open does\n // not start a second pi over the same database beside it.\n pi.close(BG).catch(() => {});\n throw error;\n }\n return { pi, storage };\n }\n\n /**\n * pi began closing: on its own, as a storage error makes it, or by\n * `dispose()`.\n */\n #piClosing(\n opening: Promise<Opened>,\n pi: Harness,\n closed: Promise<unknown>\n ): void {\n this.#closing.add(pi);\n // End a wait sleeping on this pi now: pi will not call onWake again.\n this.#changed?.();\n // `dispose()` took its pi out of `#opening` already, and an open begun\n // since must stay.\n if (this.#opening !== opening) return;\n // Drop it, so the next call opens pi again once this one has closed.\n this.#opening = undefined;\n this.#lastClose = closed;\n }\n\n /** @internal The per-conversation defaults supported by pi-durable. */\n agentDefaults(): AgentChange {\n const defaults = this.#options.defaults;\n return {\n ...(defaults?.model === undefined\n ? {}\n : { model: modelRef(defaults.model) }),\n ...(defaults?.thinkingLevel === undefined\n ? {}\n : { thinkingLevel: defaults.thinkingLevel })\n };\n }\n\n /**\n * Tasks pi's restart limit parked, each with the sessions whose work it\n * is: its own, and every session that owns that one, such as the session\n * of a tool that started a subagent.\n */\n async #parked(\n inspection: HarnessInspection\n ): Promise<{ id: TaskId; sessions: Set<ConversationId> }[]> {\n const { storage } = await this.#open();\n const parked: { id: TaskId; sessions: Set<ConversationId> }[] = [];\n for (const { record, state } of inspection.tasks) {\n if (state.kind !== \"blocked\" || state.reason !== \"restart_limit\") {\n continue;\n }\n const sessions = new Set<ConversationId>();\n let id: ConversationId | undefined = record.conversationId;\n while (id !== undefined && !sessions.has(id)) {\n sessions.add(id);\n id = (await storage.conversation(id, BG))?.owner?.conversationId;\n }\n parked.push({ id: record.id, sessions });\n }\n return parked;\n }\n\n async #findSubmission(\n id: ConversationId,\n operationId: string,\n context: Context\n ) {\n const { pi, storage } = await this.#open();\n // Read from pi's storage: the Harness only reacquires submissions by id.\n const record = await storage.submissionByRequest(id, operationId, context);\n return record ? pi.submission(record.id, context) : undefined;\n }\n\n async #result(\n session: PiSessionId,\n operationId: string,\n settled: SettledSubmissionRecord,\n context: Context\n ): Promise<PiOperationResult> {\n if (settled.status === \"unanswered\") {\n return {\n operationId,\n session,\n status: \"unanswered\",\n reason: settled.reason\n };\n }\n if (settled.type !== \"input\")\n return { operationId, session, status: \"done\" };\n const conversation = await this.conversation(session);\n const page = await conversation.entries(\n { minEntryId: settled.answer, maxEntryId: settled.answer },\n 1,\n undefined,\n context\n );\n return {\n operationId,\n session,\n status: \"done\",\n text: assistantText(page.items[0])\n };\n }\n}\n\n/** One pi conversation, addressed through the harness. */\nexport class PiSession {\n readonly #harness: PiHarness;\n readonly id: PiSessionId;\n\n constructor(harness: PiHarness, id: PiSessionId) {\n this.#harness = harness;\n this.id = id;\n }\n\n /** Durably submit a prompt. Resolves before the model runs. */\n submit(input: UserInput, options: PiSubmitOptions = {}): Promise<PiReceipt> {\n return this.#harness.enqueue(this.id, input, options);\n }\n\n /** Submit and wait for the answer and the updated transcript. */\n async prompt(\n input: UserInput,\n options: PiSubmitOptions = {}\n ): Promise<PiPromptResponse> {\n const receipt = await this.submit(input, options);\n const result = await this.wait(receipt.operationId);\n return { ...result, messages: await this.messages() };\n }\n\n /** Join the running work after its current tool round. */\n steer(input: UserInput, options: Omit<PiSubmitOptions, \"whenBusy\"> = {}) {\n return this.submit(input, { ...options, whenBusy: \"steer\" });\n }\n\n /** Wait for an operation to settle. Aborting `signal` stops only the wait. */\n wait(operationId: string, signal?: AbortSignal): Promise<PiOperationResult> {\n return this.#harness.settled(this.id, operationId, signal);\n }\n\n /**\n * Withdraw one queued operation (or abort the run it joined), or, with no\n * id, abort the session: pi withdraws queued inputs and aborts the\n * running work.\n */\n async abort(operationId?: string): Promise<boolean> {\n if (operationId !== undefined) {\n return this.#harness.withdraw(this.id, operationId);\n }\n const conversation = await this.#harness.conversation(this.id);\n await conversation.abort(BG);\n return true;\n }\n\n /**\n * Run again the tasks pi's crash-loop guard (`settings.restartLimit`)\n * parked in this session's work, including subagent sessions it owns.\n * False when nothing was parked.\n */\n retry(): Promise<boolean> {\n return this.#harness.retryParked(this.id);\n }\n\n /** Start a new context, optionally from a handoff note. */\n async reset(handoff?: string): Promise<void> {\n await (await this.#harness.conversation(this.id)).reset(handoff, BG);\n }\n\n /**\n * Change this session's model, by its `provider` and `id`; it must be on\n * the `Models` the factory opened pi with (see `PiModel`).\n */\n async setModel(model: PiModel): Promise<void> {\n await (\n await this.#harness.conversation(this.id)\n ).configure({ model: modelRef(model) }, BG);\n }\n\n /** The active transcript, as pi's entries since the newest reset. */\n async messages(): Promise<EntryRecord[]> {\n const view = await (await this.#harness.conversation(this.id)).context(BG);\n return [...view.entries];\n }\n\n /** pi's agent events for this session: a snapshot, then one batch per commit. */\n async events(context: Context = BG): Promise<AgentEventStream> {\n const pi = await this.#harness.pi();\n return watchEvents(pi, conversationId(this.id), context);\n }\n\n async busy(): Promise<boolean> {\n const pi = await this.#harness.pi();\n const live = await pi.snapshot(LiveDoc, conversationId(this.id), BG);\n return live?.run !== undefined;\n }\n}\n\n/** Every pi conversation in this object. */\nexport class PiSessions {\n readonly #harness: PiHarness;\n\n constructor(harness: PiHarness) {\n this.#harness = harness;\n }\n\n get(id: PiSessionId): PiSession {\n return this.#harness.session(id);\n }\n\n /** A new top-level session, configured like the root. */\n async create(): Promise<PiSession> {\n const pi = await this.#harness.pi();\n const conversation = await pi.createConversation(\n {\n ownership: { kind: \"ownerless\" },\n agent: this.#harness.agentDefaults()\n },\n BG\n );\n return this.#harness.session(String(conversation.id));\n }\n\n /** A new session that sees `from`'s history up to its newest entry. */\n async fork(from: PiSessionId): Promise<PiSession> {\n const conversation = await this.#harness.conversation(from);\n const newest = await conversation.entries({}, 1, undefined, BG);\n const at = newest.items[0];\n if (!at) throw new Error(`Session ${from} has no entries to fork from`);\n const fork = await conversation.fork(\n at.id,\n { ownership: { kind: \"ownerless\" } },\n BG\n );\n return this.#harness.session(String(fork.id));\n }\n\n /**\n * Every conversation, including ones subagent tools own. Read from pi's\n * storage directly: the Harness has no conversation listing.\n */\n async list(): Promise<PiSessionInfo[]> {\n const storage = await this.#harness.storage();\n const pi = await this.#harness.pi();\n const sessions: PiSessionInfo[] = [];\n let cursor: Parameters<SqliteStorage[\"scanConversations\"]>[2];\n for (;;) {\n const page = await storage.scanConversations({}, 100, cursor, BG);\n for (const record of page.items) {\n const live = await pi.snapshot(LiveDoc, record.id, BG);\n sessions.push({\n id: String(record.id),\n ...(record.parent\n ? { parent: String(record.parent.conversationId) }\n : {}),\n busy: live?.run !== undefined\n });\n }\n if (page.next === undefined) return sessions;\n cursor = page.next;\n }\n }\n}\n","import { Type } from \"@earendil-works/pi-ai\";\nimport type {\n Extension,\n ToolExecutionResult,\n ToolRegistration\n} from \"@earendil-works/pi-durable\";\nimport type {\n SkillContent,\n SkillDescriptor,\n SkillResourceDescriptor,\n SkillSource\n} from \"../../skills\";\n\n/** Skills resolved from `agents/skills` sources for one process lifetime. */\nexport type ResolvedSkills = {\n /** Changes when any source's fingerprint changes. */\n readonly fingerprint: string;\n /** Model-facing activation tools; empty when there are no skills. */\n readonly tools: readonly ToolRegistration[];\n /** System-prompt catalog, or null when there are no skills. */\n readonly catalog: string | null;\n readonly warnings: readonly string[];\n};\n\ntype ResolvedSkill = {\n readonly descriptor: SkillDescriptor;\n readonly content: SkillContent;\n readonly source: SkillSource;\n};\n\nexport function skillsFingerprint(sources: readonly SkillSource[]): string {\n return sources\n .map((source) => `${source.id}:${source.fingerprint}`)\n .join(\"|\");\n}\n\nfunction textResult(text: string): ToolExecutionResult {\n return { output: [{ type: \"text\", text }] };\n}\n\nfunction attributes(\n pairs: ReadonlyArray<readonly [string, string | undefined]>\n) {\n return pairs\n .filter((pair): pair is readonly [string, string] => pair[1] !== undefined)\n .map(([key, value]) => ` ${key}=\"${value.replace(/\"/g, \"&quot;\")}\"`)\n .join(\"\");\n}\n\nfunction describeResource(resource: SkillResourceDescriptor): string {\n const details = [\n resource.kind,\n resource.encoding ?? \"text\",\n resource.mimeType,\n resource.size === undefined ? undefined : `${resource.size} bytes`\n ].filter((value): value is string => value !== undefined);\n return `- ${resource.path} (${details.join(\", \")})`;\n}\n\nfunction renderSkillContent(skill: ResolvedSkill): string {\n const resources = skill.content.resources ?? [];\n const lines = [\n `<skill_content${attributes([\n [\"name\", skill.descriptor.name],\n [\"version\", skill.descriptor.version]\n ])}>`,\n skill.content.body.trim()\n ];\n if (resources.length > 0) {\n lines.push(\"<skill_resources>\");\n for (const resource of resources) {\n lines.push(\n ` <file${attributes([\n [\"kind\", resource.kind],\n [\"encoding\", resource.encoding ?? \"text\"],\n [\n \"size\",\n resource.size === undefined ? undefined : String(resource.size)\n ]\n ])}>${resource.path}</file>`\n );\n }\n lines.push(\"</skill_resources>\");\n }\n lines.push(\"</skill_content>\", \"\");\n lines.push(\n resources.length === 0\n ? \"No bundled resources.\"\n : [\"Bundled resources:\", ...resources.map(describeResource)].join(\"\\n\")\n );\n return lines.join(\"\\n\");\n}\n\n/**\n * Resolve `agents/skills` sources into a system-prompt catalog and two\n * tools.\n *\n * The first source to list a name wins, as in `SkillRegistry`. pi-durable\n * has no skill concept of its own, so the model activates skills through\n * `activate_skill` and reads bundled files through `read_skill_resource` —\n * the same tools `@cloudflare/think` offers, so skills authored for one\n * framework work in the other.\n */\nexport async function resolveSkillSources(\n sources: readonly SkillSource[]\n): Promise<ResolvedSkills> {\n const fingerprint = skillsFingerprint(sources);\n const warnings: string[] = [];\n const resolved = new Map<string, ResolvedSkill>();\n for (const source of sources) {\n let descriptors: SkillDescriptor[];\n try {\n descriptors = await source.list();\n } catch (error) {\n warnings.push(\n `Skill source \"${source.id}\" failed to list skills: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n continue;\n }\n for (const descriptor of descriptors) {\n if (resolved.has(descriptor.name)) {\n warnings.push(\n `Skill \"${descriptor.name}\" from source \"${source.id}\" is shadowed by an earlier source`\n );\n continue;\n }\n let content: SkillContent | null;\n try {\n content = await source.load(descriptor.name);\n } catch (error) {\n warnings.push(\n `Skill \"${descriptor.name}\" from source \"${source.id}\" failed to load: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n continue;\n }\n if (!content) continue;\n resolved.set(descriptor.name, { descriptor, content, source });\n }\n }\n\n const visible = [...resolved.values()].filter(\n (skill) => skill.descriptor.metadata?.[\"disable-model-invocation\"] !== true\n );\n if (visible.length === 0) {\n return { fingerprint, tools: [], catalog: null, warnings };\n }\n\n const names = visible.map((skill) => skill.descriptor.name);\n const nameSchema = Type.Union(names.map((name) => Type.Literal(name)));\n const byName = new Map(\n visible.map((skill) => [skill.descriptor.name, skill])\n );\n\n const activateParameters = Type.Object({ name: nameSchema });\n const activateSkill: ToolRegistration<typeof activateParameters> = {\n name: \"activate_skill\",\n description:\n \"Activate a skill by name. Use this when the user's task matches one of the available skills; the response contains the skill's full instructions.\",\n parameters: activateParameters,\n replay: \"safe\",\n async execute(input) {\n const skill = byName.get(input.name);\n return textResult(\n skill ? renderSkillContent(skill) : `Skill not found: ${input.name}`\n );\n }\n };\n\n const resourceParameters = Type.Object({\n name: Type.Optional(nameSchema),\n path: Type.String({ minLength: 1 })\n });\n const readResource: ToolRegistration<typeof resourceParameters> = {\n name: \"read_skill_resource\",\n description:\n \"Read a file bundled with a skill, such as a reference document or template. Provide the skill name and the file's path from the skill's resource list.\",\n parameters: resourceParameters,\n replay: \"safe\",\n async execute(input) {\n const target = resolveResourceTarget(byName, input.name, input.path);\n if (!target) {\n return textResult(\n `Skill resource not found: ${input.name ? `${input.name}/` : \"\"}${input.path}`\n );\n }\n const resource = await target.skill.source\n .readResource?.(target.skill.descriptor.name, target.path)\n .catch(() => null);\n if (!resource) {\n return textResult(\n `Skill resource not found: ${target.skill.descriptor.name}/${target.path}`\n );\n }\n return textResult(\n [\n `<skill_resource${attributes([\n [\"name\", target.skill.descriptor.name],\n [\"path\", resource.path],\n [\"kind\", resource.kind],\n [\"encoding\", resource.encoding ?? \"text\"],\n [\"mimeType\", resource.mimeType]\n ])}>`,\n resource.content,\n \"</skill_resource>\"\n ].join(\"\\n\")\n );\n }\n };\n\n const catalog = [\n \"Available skills. When a task matches a skill, use activate_skill with its name before proceeding.\",\n \"\",\n ...visible.map(\n (skill) => `- ${skill.descriptor.name}: ${skill.descriptor.description}`\n )\n ].join(\"\\n\");\n\n return {\n fingerprint,\n tools: [activateSkill, readResource],\n catalog,\n warnings\n };\n}\n\nfunction resolveResourceTarget(\n byName: ReadonlyMap<string, ResolvedSkill>,\n name: string | undefined,\n path: string\n): { readonly skill: ResolvedSkill; readonly path: string } | undefined {\n if (path.split(\"/\").some((segment) => segment === \"..\")) return undefined;\n if (name !== undefined) {\n const skill = byName.get(name);\n return skill && hasResource(skill, path) ? { skill, path } : undefined;\n }\n // A qualified path names the skill in its first segment.\n const [head, ...rest] = path.split(\"/\");\n const skill = head === undefined ? undefined : byName.get(head);\n const relative = rest.join(\"/\");\n return skill && relative && hasResource(skill, relative)\n ? { skill, path: relative }\n : undefined;\n}\n\nfunction hasResource(skill: ResolvedSkill, path: string): boolean {\n return (skill.content.resources ?? []).some(\n (resource) => resource.path === path\n );\n}\n\n/**\n * `agents/skills` sources as a pi extension, named `agents.skills`: the\n * activation tools and a `skills` system prompt section. Install it on\n * pi's registry in the harness factory.\n *\n * ```ts\n * registry.install(await skills(sources));\n * ```\n */\nexport async function skills(\n sources: readonly SkillSource[]\n): Promise<Extension> {\n const resolved = await resolveSkillSources(sources);\n for (const warning of resolved.warnings) {\n console.warn(`pi skills: ${warning}`);\n }\n const catalog = resolved.catalog;\n return {\n name: \"agents.skills\",\n tools: resolved.tools,\n sections: catalog === null ? [] : [{ key: \"skills\", render: () => catalog }]\n };\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { MessageType } from "./types.js";
7
7
  import { createHeaderBasedEmailResolver } from "./email.js";
8
8
  import { n as withInvocationScope } from "./cloudflare-Dzvc7V2N.js";
9
9
  import { SUB_PREFIX, buildAgentPath, buildAgentUrl, getSubAgentByName, parseSubAgentPath, routeSubAgentRequest } from "./sub-routing.js";
10
- import { a as routeAgentEmail, i as getCurrentAgent, n as DEFAULT_AGENT_STATIC_OPTIONS, r as StreamingResponse, t as Agent } from "./src-6lr7MtM_.js";
10
+ import { a as routeAgentEmail, i as getCurrentAgent, n as DEFAULT_AGENT_STATIC_OPTIONS, r as StreamingResponse, t as Agent } from "./src-DfLzdwlK.js";
11
11
  import { isDurableObjectCodeUpdateReset, isDurableObjectMemoryLimitReset, isDurableObjectStorageReset, isPlatformTransientError } from "./retries.js";
12
12
  import { SqlError } from "./sql-error.js";
13
13
  import { i as normalizeServerId, n as MCP_SERVER_ID_MAX_LENGTH } from "./client-BnYbNT3z.js";
@@ -1,4 +1,4 @@
1
1
  import { n as getCurrentAgent } from "../current-agent-DhoDkSnH.js";
2
2
  import { t as LifecycleCapability } from "../capability-DBAKc6UZ.js";
3
- import { t as Lifecycle } from "../lifecycle-ClT4DmF2.js";
3
+ import { t as Lifecycle } from "../lifecycle-v1rKHV2C.js";
4
4
  export { Lifecycle, LifecycleCapability, getCurrentAgent };
@@ -477,16 +477,16 @@ var JobDriver = class {
477
477
  _classPrivateFieldSet2(_options, this, options);
478
478
  }
479
479
  /**
480
- * Run one alarm invocation: initialize the lifecycle, drive due jobs, run
481
- * the host's alarm callback, and re-arm the physical alarm from queue
482
- * state — all inside the alarm memory-limit circuit breaker (#1825). A
483
- * memory-limit reset that propagates here is intercepted — every other
484
- * error re-throws unchanged so platform alarm-retry semantics hold — and
485
- * broken from this outermost frame, where the heavy turn has unwound and
486
- * small writes can land. Initialization runs inside the breaker because a
487
- * severe reset can be thrown before any job runs (boot hydration, #1825);
488
- * left unhandled it would re-throw to the platform, which auto-retries
489
- * the alarm forever.
480
+ * Run one alarm invocation: arm a startup fallback wake, initialize the
481
+ * lifecycle, drive due jobs, run the host's alarm callback, and re-arm the
482
+ * physical alarm from queue state — all inside the alarm memory-limit
483
+ * circuit breaker (#1825). A memory-limit reset that propagates here is
484
+ * intercepted — every other error re-throws unchanged so platform
485
+ * alarm-retry semantics hold — and broken from this outermost frame, where
486
+ * the heavy turn has unwound and small writes can land. Initialization
487
+ * runs inside the breaker because a severe reset can be thrown before any
488
+ * job runs (boot hydration, #1825); left unhandled it would re-throw to
489
+ * the platform, which auto-retries the alarm forever.
490
490
  */
491
491
  async runAlarm(initialize, runHostAlarm) {
492
492
  var _this$alarmsInFlight;
@@ -494,6 +494,7 @@ var JobDriver = class {
494
494
  let clean = false;
495
495
  try {
496
496
  try {
497
+ await this.armStartupFallback();
497
498
  await initialize();
498
499
  await _assertClassBrand(_JobDriver_brand, this, _driveDueJobs).call(this);
499
500
  await _classPrivateFieldGet2(_alarmScope, this).run({ executing: void 0 }, runHostAlarm);
@@ -533,6 +534,28 @@ var JobDriver = class {
533
534
  work.then(() => _assertClassBrand(_JobDriver_brand, this, _settleAlarmWork).call(this, work, void 0, scope.executing), (error) => _assertClassBrand(_JobDriver_brand, this, _settleAlarmWork).call(this, work, error, scope.executing));
534
535
  return true;
535
536
  }
537
+ /**
538
+ * Arm a startup fallback alarm while the queue holds jobs. An alarm arms
539
+ * one before startup runs: the platform clears the alarm when it fires, so
540
+ * a startup that throws (or an isolate that dies mid-startup) would
541
+ * otherwise leave the queue with no wake but the platform's own few, short
542
+ * retries. Lifecycle arms one again after a failed startup that pushed or
543
+ * re-timed jobs, whose deferred re-arm never ran. The fallback keeps the
544
+ * object woken whether or not the platform's retries run: a failed startup
545
+ * is retried at the fallback time. A clean alarm's final re-arm, or any
546
+ * later queue mutation's, replaces it.
547
+ *
548
+ * The fallback is the queue's own next wake, but never sooner than the
549
+ * deadman delay: an overdue job would otherwise make a failing startup
550
+ * retry in a tight loop.
551
+ */
552
+ async armStartupFallback() {
553
+ if (_classPrivateFieldGet2(_options, this).disabled()) return;
554
+ const nowMs = Date.now();
555
+ const next = _classPrivateFieldGet2(_options, this).queue.nextAlarmTime(nowMs);
556
+ if (next === null) return;
557
+ await _classPrivateFieldGet2(_options, this).storage.setAlarm(Math.max(next, nowMs + DEADMAN_ALARM_DELAY_MS));
558
+ }
536
559
  };
537
560
  async function _settleAlarmWork(work, error, executing) {
538
561
  try {
@@ -814,7 +837,13 @@ function decodeProps(header) {
814
837
  const lifecycleEventSinks = /* @__PURE__ */ new WeakMap();
815
838
  const lifecycleRouteTransports = /* @__PURE__ */ new WeakMap();
816
839
  const lifecycleHostInvokers = /* @__PURE__ */ new WeakMap();
817
- /** Lifecycles whose startup the current async context is running inside. */
840
+ /**
841
+ * Startup tokens of the Lifecycles whose startup the current async context
842
+ * is running inside. The scope holds opaque tokens, never a Lifecycle: every
843
+ * promise reaction created during startup keeps this async context, and
844
+ * workerd does not trace async context values during GC. A pending promise
845
+ * stored on a capability would otherwise keep an evicted object alive.
846
+ */
818
847
  const lifecycleStartupScope = new AsyncLocalStorage();
819
848
  /** @internal Adapt the host invocation boundary at a composition root. */
820
849
  function setLifecycleHostInvoker(lifecycle, invoker) {
@@ -853,6 +882,7 @@ var _capabilitiesLocked = /* @__PURE__ */ new WeakMap();
853
882
  var _handlersInstalled = /* @__PURE__ */ new WeakMap();
854
883
  var _Lifecycle_brand = /* @__PURE__ */ new WeakSet();
855
884
  var _startup = /* @__PURE__ */ new WeakMap();
885
+ var _startupToken = /* @__PURE__ */ new WeakMap();
856
886
  var _legacyName = /* @__PURE__ */ new WeakMap();
857
887
  var _props = /* @__PURE__ */ new WeakMap();
858
888
  var Lifecycle = class Lifecycle {
@@ -890,6 +920,7 @@ var Lifecycle = class Lifecycle {
890
920
  _classPrivateFieldInitSpec(this, _capabilitiesLocked, false);
891
921
  _classPrivateFieldInitSpec(this, _handlersInstalled, false);
892
922
  _classPrivateFieldInitSpec(this, _startup, void 0);
923
+ _classPrivateFieldInitSpec(this, _startupToken, {});
893
924
  _classPrivateFieldInitSpec(this, _legacyName, void 0);
894
925
  _classPrivateFieldInitSpec(this, _props, void 0);
895
926
  _classPrivateFieldSet2(_host, this, host);
@@ -1123,14 +1154,12 @@ var Lifecycle = class Lifecycle {
1123
1154
  _classPrivateFieldSet2(_rearmRequestedDuringStart, this, true);
1124
1155
  return;
1125
1156
  }
1126
- const next = _classPrivateFieldGet2(_alarmRearmQueue, this).catch(() => {}).then(async () => {
1157
+ await _assertClassBrand(_Lifecycle_brand, this, _serializeAlarmWrite).call(this, async () => {
1127
1158
  if (_classPrivateFieldGet2(_alarmsDisabled, this)) return;
1128
1159
  const alarm = _classPrivateFieldGet2(_jobQueue, this).nextAlarmTime(Date.now());
1129
1160
  if (alarm === null) await _classPrivateFieldGet2(_ctx, this).storage.deleteAlarm();
1130
1161
  else await _classPrivateFieldGet2(_ctx, this).storage.setAlarm(alarm);
1131
1162
  });
1132
- _classPrivateFieldSet2(_alarmRearmQueue, this, next);
1133
- await next;
1134
1163
  }
1135
1164
  /**
1136
1165
  * Keep work a job handed off at a bounded return inside the current
@@ -1278,7 +1307,7 @@ function _ensureInitialized() {
1278
1307
  _classPrivateFieldSet2(_startup, this, startup);
1279
1308
  return startup;
1280
1309
  }
1281
- if (lifecycleStartupScope.getStore()?.has(this)) return Promise.resolve();
1310
+ if (lifecycleStartupScope.getStore()?.has(_classPrivateFieldGet2(_startupToken, this))) return Promise.resolve();
1282
1311
  return _classPrivateFieldGet2(_startup, this);
1283
1312
  }
1284
1313
  async function _runStartup() {
@@ -1286,7 +1315,7 @@ async function _runStartup() {
1286
1315
  this.name;
1287
1316
  _classPrivateFieldSet2(_capabilitiesLocked, this, true);
1288
1317
  const scope = new Set(lifecycleStartupScope.getStore());
1289
- scope.add(this);
1318
+ scope.add(_classPrivateFieldGet2(_startupToken, this));
1290
1319
  let error;
1291
1320
  await _classPrivateFieldGet2(_ctx, this).blockConcurrencyWhile(() => lifecycleStartupScope.run(scope, async () => {
1292
1321
  _classPrivateFieldSet2(_status, this, "starting");
@@ -1300,8 +1329,10 @@ async function _runStartup() {
1300
1329
  }
1301
1330
  }));
1302
1331
  if (error) {
1332
+ const rearmRequested = _classPrivateFieldGet2(_rearmRequestedDuringStart, this);
1303
1333
  _classPrivateFieldSet2(_rearmRequestedDuringStart, this, false);
1304
1334
  _classPrivateFieldGet2(_pendingEvents, this).length = 0;
1335
+ if (rearmRequested) await _assertClassBrand(_Lifecycle_brand, this, _serializeAlarmWrite).call(this, () => _classPrivateFieldGet2(_jobDriver, this).armStartupFallback()).catch(() => {});
1305
1336
  throw error;
1306
1337
  }
1307
1338
  _assertClassBrand(_Lifecycle_brand, this, _deliverPendingEvents).call(this);
@@ -1326,6 +1357,15 @@ function _jobsForOwner(owner) {
1326
1357
  });
1327
1358
  }
1328
1359
  /**
1360
+ * Run an alarm write after every earlier one settles, so a later
1361
+ * calculation from fresher queue state always lands last.
1362
+ */
1363
+ function _serializeAlarmWrite(write) {
1364
+ const next = _classPrivateFieldGet2(_alarmRearmQueue, this).catch(() => {}).then(write);
1365
+ _classPrivateFieldSet2(_alarmRearmQueue, this, next);
1366
+ return next;
1367
+ }
1368
+ /**
1329
1369
  * Resolve a job owner to its dispatch hooks. Host jobs run inside the
1330
1370
  * host invocation boundary; capability jobs run outside ambient host
1331
1371
  * context, like every other capability hook.
@@ -1346,4 +1386,4 @@ async function _resolveJobDispatch(owner) {
1346
1386
  //#endregion
1347
1387
  export { abortWithoutAlarmRetry as a, setLifecycleRouteTransport as i, setLifecycleEventSink as n, setLifecycleHostInvoker as r, Lifecycle as t };
1348
1388
 
1349
- //# sourceMappingURL=lifecycle-ClT4DmF2.js.map
1389
+ //# sourceMappingURL=lifecycle-v1rKHV2C.js.map