pi-fabric 0.117.1 → 0.117.2

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.
@@ -4,5 +4,5 @@
4
4
  * (see loadHostSdk); awaiting here keeps every importer's own scope
5
5
  * synchronous. Never reach this module from the startup graph.
6
6
  */
7
- export declare const PiCodingAgent: typeof import("pi-fabric-worker-sdk");
7
+ export declare const PiCodingAgent: typeof import("@earendil-works/pi-coding-agent");
8
8
  //# sourceMappingURL=host-sdk-runtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-sdk-runtime.d.ts","sourceRoot":"","sources":["../../src/core/host-sdk-runtime.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,uCAAsB,CAAC"}
1
+ {"version":3,"file":"host-sdk-runtime.d.ts","sourceRoot":"","sources":["../../src/core/host-sdk-runtime.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,kDAAsB,CAAC"}
package/dist/durable.js CHANGED
@@ -150,12 +150,12 @@ async function runtime() {
150
150
  const require2 = createRequire(import.meta.url);
151
151
  for (const name of ["@earendil-works/pi-durable", "@earendil-works/chord"]) {
152
152
  const metadata = require2(`${name}/package.json`);
153
- if (metadata.version !== "1.2.0") throw new Error(`Unsupported ${name} version ${metadata.version ?? "unknown"}; expected 1.2.0`);
153
+ if (metadata.version !== "1.3.0") throw new Error(`Unsupported ${name} version ${metadata.version ?? "unknown"}; expected 1.3.0`);
154
154
  }
155
155
  return Promise.all([import("@earendil-works/pi-durable"), import("@earendil-works/chord/context")]);
156
156
  }).then(([durable, context]) => ({ durable, context })).catch((cause) => {
157
157
  runtimePromise = void 0;
158
- throw new Error(`Pi durable runner requires pinned dependencies @earendil-works/pi-durable@1.2.0 and @earendil-works/chord@1.2.0: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
158
+ throw new Error(`Pi durable runner requires pinned dependencies @earendil-works/pi-durable@1.3.0 and @earendil-works/chord@1.3.0: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
159
159
  });
160
160
  }
161
161
  var hash = (value) => createHash2("sha256").update(value).digest("hex");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/durable.ts", "../src/durable-input.ts", "../src/durable-controls.ts"],
4
- "sourcesContent": ["import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport type { Harness, HarnessOptions, ModelRef, Registry, Storage, Conversation, Submission, ConversationWatch, ConversationView, ToolRegistration } from \"@earendil-works/pi-durable\";\nimport type { FabricHostedRunner, FabricHostedRunContext, FabricHostedReporter, FabricHostedLiveness } from \"./agents/runner-registry.js\";\nimport type { AgentUsage } from \"./agents/types.js\";\nimport { durableInput } from \"./durable-input.js\";\nimport { openDurableControls, type PiDurableControls, type PiDurableMessageOptions } from \"./durable-controls.js\";\nexport type { PiDurableMessageOptions } from \"./durable-controls.js\";\n\n/** The host must hold exclusive ownership until release, including across processes. */\nexport interface PiDurableStorageLease {\n storage: Storage;\n release(): void | Promise<void>;\n}\nexport type PiDurableStorageOptions =\n | { kind: \"jsonl\"; directory: string }\n | { kind: \"factory\"; identity: string; acquire(runId: string): Promise<PiDurableStorageLease> };\nexport interface PiDurableRunnerOptions {\n id?: string;\n label?: string;\n residentModule?: string;\n models: HarnessOptions[\"models\"];\n registry: Registry;\n env: NonNullable<HarnessOptions[\"env\"]>;\n allowedModels: readonly ModelRef[];\n /** Optional host-selected model, which must also appear in allowedModels. */\n defaultModel?: ModelRef;\n storage: PiDurableStorageOptions;\n}\nexport interface PiDurableRunner extends FabricHostedRunner {\n steer(locator: unknown, message: string, options?: PiDurableMessageOptions): Promise<void>;\n followUp(locator: unknown, message: string, options?: PiDurableMessageOptions): Promise<void>;\n /** Seal this instance, join invocations and release storage; never abort work. Create a new runner to reopen. */\n close(): Promise<void>;\n}\nexport interface PiDurableLocator {\n version: 1;\n backend: \"pi-durable\";\n storage: string;\n runId: string;\n}\n\ntype Runtime = { durable: typeof import(\"@earendil-works/pi-durable\"); context: typeof import(\"@earendil-works/chord/context\") };\nlet runtimePromise: Promise<Runtime> | undefined;\nasync function runtime(): Promise<Runtime> {\n return runtimePromise ??= Promise.resolve().then(() => {\n const require = createRequire(import.meta.url);\n for (const name of [\"@earendil-works/pi-durable\", \"@earendil-works/chord\"]) {\n const metadata = require(`${name}/package.json`) as { version?: string };\n if (metadata.version !== \"1.2.0\") throw new Error(`Unsupported ${name} version ${metadata.version ?? \"unknown\"}; expected 1.2.0`);\n }\n return Promise.all([import(\"@earendil-works/pi-durable\"), import(\"@earendil-works/chord/context\")]);\n })\n .then(([durable, context]) => ({ durable, context }))\n .catch((cause: unknown) => {\n runtimePromise = undefined;\n throw new Error(`Pi durable runner requires pinned dependencies @earendil-works/pi-durable@1.2.0 and @earendil-works/chord@1.2.0: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });\n });\n}\nconst hash = (value: string): string => createHash(\"sha256\").update(value).digest(\"hex\");\nconst ownershipSymbol = Symbol.for(\"pi-fabric.durable.owners.v1\");\nconst globals = globalThis as unknown as Record<symbol, Set<string> | undefined>;\nconst owners = globals[ownershipSymbol] ??= new Set<string>();\ninterface OpenRun {\n harness: Harness;\n conversation?: Conversation;\n submission?: Submission;\n controls?: PiDurableControls;\n lease: PiDurableStorageLease;\n ownerKey: string;\n watch?: ConversationWatch;\n reporters: Set<FabricHostedReporter>;\n observing?: Promise<void>;\n fingerprint?: string;\n}\n\n/** Opt-in hosted adapter. No registration or runtime package loading occurs at factory creation. */\nexport function createPiDurableRunner(options: PiDurableRunnerOptions): PiDurableRunner {\n if (!options.models || !options.registry || typeof options.env !== \"function\") throw new Error(\"Pi durable requires host models, registry and environment\");\n const storage = options.storage;\n const directory = storage.kind === \"jsonl\" ? path.resolve(storage.directory) : undefined;\n if (storage.kind === \"factory\" && (!storage.identity || typeof storage.acquire !== \"function\")) throw new Error(\"Storage factory requires identity and exclusive acquire()\");\n const identity = hash(storage.kind === \"jsonl\" ? `jsonl:${directory}` : `factory:${storage.identity}`);\n const allowed = new Map(options.allowedModels.map(model => [`${model.provider}/${model.modelId}`, { ...model }]));\n if (!allowed.size) throw new Error(\"Pi durable requires an explicit model allowlist\");\n const id = options.id ?? \"pi-durable-leaf\";\n const defaultModel = options.defaultModel ? `${options.defaultModel.provider}/${options.defaultModel.modelId}` : undefined;\n if (defaultModel && !allowed.has(defaultModel)) throw new Error(\"Pi durable default model must be allowlisted\");\n const runs = new Map<string, OpenRun>();\n const transcriptSeen = new WeakMap<FabricHostedReporter, Set<import(\"@earendil-works/pi-durable\").EntryId>>();\n let sealed = false;\n let tail: Promise<unknown> = Promise.resolve();\n let closing: Promise<void> | undefined;\n const serial = <T>(fn: () => Promise<T>): Promise<T> => {\n if (sealed) return Promise.reject(new Error(\"Pi durable runner is closed\"));\n const result = tail.then(fn);\n tail = result.catch(() => undefined);\n return result;\n };\n function locator(value: unknown): PiDurableLocator {\n const loc = value as Partial<PiDurableLocator> | null;\n if (!loc || loc.version !== 1 || loc.backend !== \"pi-durable\" || loc.storage !== identity || typeof loc.runId !== \"string\" || !loc.runId || loc.runId.length > 512) throw new Error(\"Invalid Pi durable locator or storage identity\");\n return loc as PiDurableLocator;\n }\n function validate(context: FabricHostedRunContext) {\n if (context.id !== context.idempotencyKey) throw new Error(\"Pi durable requires Fabric run ID as idempotencyKey\");\n if (context.residency === \"durable\" && !options.residentModule) throw new Error(\"Durable residency requires an explicit residentModule\");\n for (const key of [\"kernel\", \"sessionFile\", \"actorId\", \"actorName\", \"writePolicy\", \"scope\"] as const) {\n if (context[key] !== undefined) throw new Error(`Pi durable does not support ${key}`);\n }\n if (context.recursive) throw new Error(\"Pi durable does not support recursiveFabric\");\n const modelKey = context.model ?? defaultModel;\n const model = modelKey ? allowed.get(modelKey) : undefined;\n if (!model || !options.models.getModel(model.provider, model.modelId)) throw new Error(`Unknown or disallowed Pi durable model: ${modelKey ?? \"(missing explicit provider/model)\"}`);\n const catalogModel = options.models.getModel(model.provider, model.modelId)!;\n const input = durableInput(context, catalogModel.input.includes(\"image\"));\n if (context.thinking && ((!catalogModel.reasoning && context.thinking !== \"off\") || catalogModel.thinkingLevelMap?.[context.thinking] === null)) throw new Error(`Unsupported thinking level: ${context.thinking}`);\n const snapshot = options.registry.snapshot();\n const available = new Map(snapshot.tools().map(({ tool }) => [tool.name, tool]));\n const tools = context.tools.map(name => {\n let tool = available.get(name);\n if (!tool) throw new Error(`Unknown Pi durable tool: ${name}`);\n for (const extension of snapshot.installed()) for (const wrap of extension.wraps ?? []) {\n if (\"tool\" in wrap && wrap.tool === name) tool = wrap.wrap(tool);\n }\n if (tool.name !== name) throw new Error(`Registry wrapper renamed tool ${name}`);\n const implementation = tool;\n return { ...implementation, replay: name === \"fabric_exec\" ? \"unsafe\" as const : implementation.replay ?? \"unsafe\", execute: async (...args: Parameters<ToolRegistration[\"execute\"]>) => {\n const result = await implementation.execute(...args);\n if (result.control?.addTools || result.control?.handoff) throw new Error(\"Pi durable adapter does not support tool-set changes or handoff controls\");\n return result;\n } } satisfies ToolRegistration;\n });\n const fingerprint = hash(JSON.stringify({ task: context.task, cwd: context.cwd, model, tools: [...context.tools], thinking: context.thinking ?? \"off\", systemPrompt: context.systemPrompt ?? \"\", ...(input.images?.length ? { images: input.images } : {}), ...(input.schema ? { schema: input.schema } : {}) }));\n return { model, tools, fingerprint, input };\n }\n async function acquire(runId: string, rt: Runtime): Promise<PiDurableStorageLease> {\n if (storage.kind === \"factory\") return storage.acquire(runId);\n const base = directory!;\n await fs.mkdir(base, { recursive: true });\n const canonical = await fs.realpath(base);\n const stem = hash(runId);\n const lock = path.join(canonical, `${stem}.writer`);\n try { await fs.mkdir(lock); } catch (cause) { throw new Error(`Pi durable single-writer lock unavailable: ${lock}. Never remove a stale lock until its owner is verified dead.`, { cause }); }\n try {\n const { openNodeJsonlStorage } = await import(\"@earendil-works/pi-durable/storage/jsonl/node\");\n const opened = await openNodeJsonlStorage(path.join(canonical, stem), rt.context.BACKGROUND_CONTEXT, { fsync: true });\n return { storage: opened, release: () => fs.rmdir(lock) };\n } catch (error) { await fs.rmdir(lock); throw error; }\n }\n async function open(runId: string, selected: ReturnType<typeof validate>): Promise<OpenRun> {\n const existing = runs.get(runId);\n if (existing) {\n if (existing.fingerprint && existing.fingerprint !== selected.fingerprint) throw new Error(\"Fabric run ID already bound to different work\");\n return existing;\n }\n const ownerKey = `${identity}:${runId}`;\n if (owners.has(ownerKey)) throw new Error(\"Pi durable storage already has an active writer\");\n owners.add(ownerKey);\n let lease: PiDurableStorageLease | undefined;\n try {\n const rt = await runtime();\n lease = await acquire(runId, rt);\n // Deliberately import only requested tool implementations; no registry hooks, sections or tasks.\n const registry = rt.durable.createRegistry();\n registry.install(rt.durable.defineExtension({ name: \"fabric.durable.tools\", tools: selected.tools }));\n const harness = await rt.durable.Harness.open(lease.storage, { models: options.models, registry, env: options.env, settings: { compaction: { enabled: false }, retry: { enabled: false }, stream: { maxRetries: 0 } } }, rt.context.BACKGROUND_CONTEXT);\n const run: OpenRun = { harness, lease, ownerKey, reporters: new Set() };\n runs.set(runId, run);\n return run;\n } catch (error) {\n if (lease) {\n try {\n await lease.storage.close((await runtime()).context.BACKGROUND_CONTEXT);\n await lease.release();\n } catch (cleanupError) {\n throw new AggregateError([error, cleanupError], \"Pi durable open failed; cleanup failed, lease remains owned\");\n }\n }\n owners.delete(ownerKey);\n throw error;\n }\n }\n async function bind(value: unknown, context: FabricHostedRunContext, reporter: FabricHostedReporter, admit: boolean): Promise<void> {\n const loc = locator(value);\n if (loc.runId !== context.id) throw new Error(\"Pi durable locator does not match Fabric run ID\");\n const selected = validate(context);\n const rt = await runtime();\n const { getSupportedThinkingLevels } = await import(\"@earendil-works/pi-ai/models\");\n if (!getSupportedThinkingLevels(options.models.getModel(selected.model.provider, selected.model.modelId)!).includes(context.thinking ?? \"off\")) throw new Error(`Unsupported thinking level: ${context.thinking ?? \"off\"}`);\n const ctx = rt.context.BACKGROUND_CONTEXT;\n const run = await open(loc.runId, selected);\n const Manifest = rt.durable.defineDoc<{ fingerprint: string }>({ kind: \"fabric.durable.request\", version: 1, scope: \"conversation\", history: \"latest\", fork: \"initial\", initial: () => ({ fingerprint: selected.fingerprint }) });\n let conversation = await run.harness.conversation(rt.durable.ROOT_CONVERSATION_ID, ctx);\n if (!conversation && admit) conversation = await run.harness.root(ctx, { agent: { model: selected.model, tools: selected.tools, thinkingLevel: context.thinking ?? \"off\", cwd: context.cwd, instructions: selected.input.instructions }, init: async (tx, id) => { await tx.doc(Manifest, id); } });\n if (!conversation) throw new Error(\"Pi durable attach found no existing conversation; outcome indeterminate (not resubmitted)\");\n const manifest = await run.harness.snapshot(Manifest, conversation.id, ctx);\n if (manifest?.fingerprint !== selected.fingerprint) throw new Error(\"Fabric run ID already bound to different work or missing committed manifest\");\n run.fingerprint = selected.fingerprint;\n run.conversation = conversation;\n const found = await conversation.commit(tx => tx.submissionByRequest(conversation!.id, context.id), ctx);\n let submission = found ? await run.harness.submission(found.id, ctx) : undefined;\n if (!submission && admit) submission = await conversation.submit({ type: \"input\", content: selected.input.content, requestId: context.id }, ctx);\n if (!submission) throw new Error(\"Pi durable attach found no existing submission; outcome indeterminate (not resubmitted)\");\n run.submission = submission;\n if (!run.controls) {\n run.controls = await openDurableControls({ durable: rt.durable, context: ctx, harness: run.harness, storage: run.lease.storage, conversation, initial: submission, runId: context.id, serialize: serial, closed: () => sealed });\n }\n run.reporters.add(reporter);\n if (!run.watch) {\n run.watch = await conversation.watch(ctx);\n run.watch.start(async view => { for (const target of run.reporters) report(view, target); });\n }\n report(run.watch.value, reporter);\n if (!run.observing) {\n run.observing = run.controls.wait().then(async result => {\n if (sealed || !result) return;\n const view = await conversation!.context(ctx);\n const answer = result.type === \"input\" && result.status === \"done\" ? view.entries.find(entry => entry.id === result.answer) : undefined;\n const output = answer?.model?.flatMap(message => message.role === \"assistant\" ? message.content.filter(block => block.type === \"text\").map(block => block.text) : []).join(\"\") ?? \"\";\n const completion: { status: \"completed\" | \"stopped\" | \"failed\"; text: string; value?: unknown; error?: string } = {\n status: result.status === \"done\" ? \"completed\" : result.reason === \"aborted\" ? \"stopped\" : \"failed\",\n text: result.status === \"done\" ? output : `Pi durable unanswered: ${result.reason}`,\n };\n if (selected.input.schema) {\n const { validateAgentResult } = await import(\"./agents/result.js\");\n validateAgentResult(completion, selected.input.schema);\n }\n const usage = await run.harness.usage(ctx);\n for (const target of run.reporters) {\n target.usage(totalUsage(usage));\n target.finish({ status: completion.status, output: completion.error ?? completion.text, ...(completion.value !== undefined ? { structured: completion.value } : {}) });\n }\n delete run.observing;\n }).catch(error => { if (!sealed) for (const target of run.reporters) target.fail({ error: `Pi durable observation failed: ${String(error)}` }); });\n }\n }\n function totalUsage(usage: import(\"@earendil-works/pi-durable\").UsageState): AgentUsage {\n const total: AgentUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };\n for (const bucket of [usage.models, usage.tools]) for (const item of Object.values(bucket)) {\n total.input += item.input; total.output += item.output; total.cacheRead += item.cacheRead; total.cacheWrite += item.cacheWrite; total.cost += item.cost.total;\n }\n return total;\n }\n function report(view: ConversationView, reporter: FabricHostedReporter): void {\n let seen = transcriptSeen.get(reporter);\n if (!seen) { seen = new Set(); transcriptSeen.set(reporter, seen); }\n for (const entry of view.entries) {\n if (seen.has(entry.id)) continue;\n seen.add(entry.id);\n for (const message of entry.model ?? []) {\n if (message.role === \"assistant\" || message.role === \"user\") {\n const content = typeof message.content === \"string\" ? message.content : message.content.filter(block => block.type === \"text\").map(block => ({ type: \"text\" as const, text: block.text }));\n reporter.transcript({ type: \"message_end\", message: { role: message.role, content } });\n if (message.role === \"assistant\") for (const block of message.content) if (block.type === \"toolCall\") reporter.transcript({ type: \"tool_execution_start\", toolCallId: block.id, toolName: block.name, args: block.arguments });\n } else if (message.role === \"toolResult\") reporter.transcript({ type: \"tool_execution_end\", toolCallId: message.toolCallId, toolName: message.toolName, result: message.content, isError: message.isError });\n }\n }\n const assistants = view.entries.flatMap(entry => entry.model?.filter(message => message.role === \"assistant\") ?? []);\n const live = view.docs[\"pi.live\"] as unknown as import(\"@earendil-works/pi-durable\").LiveState | undefined;\n const last = live?.generation?.message ?? assistants.at(-1);\n const calls = assistants.flatMap(message => message.role === \"assistant\" ? message.content.filter(block => block.type === \"toolCall\") : []);\n reporter.progress({ turns: assistants.length, toolCalls: calls.length, currentTool: live?.tools?.find(tool => tool.status === \"running\")?.name ?? null, text: last?.role === \"assistant\" ? last.content.filter(block => block.type === \"text\").map(block => block.text).join(\"\") : \"\" });\n const usage = view.docs[\"pi.usage\"];\n if (usage) reporter.usage(totalUsage(usage as unknown as import(\"@earendil-works/pi-durable\").UsageState));\n }\n return {\n id, label: options.label ?? \"Pi durable (opt-in)\", kind: \"hosted\", ...(options.residentModule ? { residentModule: options.residentModule } : {}),\n capabilities: Object.freeze({ recursiveFabric: false, steer: true, followUp: true, persistentSessions: false, kernels: false, handoff: false, modelDiscovery: true, imageInput: true, compaction: false, questions: false, sleep: false, writePolicy: false }),\n defaultModel: () => defaultModel,\n models: () => [...allowed.values()].flatMap(ref => {\n const model = options.models.getModel(ref.provider, ref.modelId);\n return model ? [{ runner: id, provider: ref.provider, id: ref.modelId, key: `${ref.provider}/${ref.modelId}`, name: model.name, input: [...model.input], reasoning: model.reasoning, contextWindow: model.contextWindow, maxTokens: model.maxTokens }] : [];\n }),\n prepare(context) { if (sealed) throw new Error(\"Pi durable runner is closed\"); validate(context); return { version: 1, backend: \"pi-durable\", storage: identity, runId: context.id } satisfies PiDurableLocator; },\n normalizeModel(model) { if (!allowed.has(model)) throw new Error(`Unknown or disallowed Pi durable model: ${model}`); return model; },\n mapTools(tools) { const names = new Set(options.registry.snapshot().tools().map(item => item.tool.name)); for (const tool of tools) if (!names.has(tool)) throw new Error(`Unknown Pi durable tool: ${tool}`); return [...tools]; },\n start: (loc, context, reporter) => serial(() => bind(loc, context, reporter, true)),\n attach: (loc, context, reporter) => serial(() => bind(loc, context, reporter, false)),\n steer: (value, message, data) => serial(async () => {\n const run = runs.get(locator(value).runId);\n if (!run?.controls) throw new Error(\"Pi durable run is not attached\");\n await run.controls.send(\"steer\", message, data);\n }),\n followUp: (value, message, data) => serial(async () => {\n const run = runs.get(locator(value).runId);\n if (!run?.controls) throw new Error(\"Pi durable run is not attached\");\n await run.controls.send(\"followUp\", message, data);\n }),\n liveness: value => serial(async (): Promise<FabricHostedLiveness> => {\n const run = runs.get(locator(value).runId);\n return run?.controls ? run.controls.liveness() : \"unknown\";\n }),\n stop: value => serial(async () => {\n const run = runs.get(locator(value).runId);\n if (!run?.controls) return { confirmed: false };\n await run.controls.stop();\n return { confirmed: true };\n }),\n close() {\n if (closing) return closing;\n sealed = true;\n closing = tail.then(async () => {\n const results = await Promise.allSettled([...runs].map(async ([id, run]) => {\n await run.watch?.stop();\n await run.harness.close((await runtime()).context.BACKGROUND_CONTEXT);\n await run.observing;\n await run.lease.release();\n owners.delete(run.ownerKey);\n runs.delete(id);\n }));\n const failed = results.filter((result): result is PromiseRejectedResult => result.status === \"rejected\");\n if (failed.length) throw new AggregateError(failed.map(result => result.reason), \"Pi durable close failed; failed leases remain owned\");\n });\n return closing;\n },\n };\n}\n", "import type { UserInput } from \"@earendil-works/pi-durable\";\nimport type { FabricHostedRunContext } from \"./agents/runner-registry.js\";\n\nconst MAX_IMAGE_CHARS = 16_777_216;\nconst MAX_SCHEMA_CHARS = 262_144;\n\n/** Snapshot request data before an asynchronous admission; never retain caller-owned image/schema objects. */\nexport function durableInput(context: Pick<FabricHostedRunContext, \"task\" | \"images\" | \"schema\" | \"systemPrompt\">, acceptsImages: boolean) {\n const images = context.images?.map(image => {\n if (!image || image.type !== \"image\" || typeof image.mimeType !== \"string\" ||\n !/^image\\/(png|jpeg|gif|webp)$/.test(image.mimeType) || typeof image.data !== \"string\" ||\n image.data.length === 0 || image.data.length > MAX_IMAGE_CHARS ||\n image.data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(image.data)) {\n throw new Error(\"Pi durable image input requires a base64 PNG, JPEG, GIF or WebP block\");\n }\n return { type: \"image\" as const, data: image.data, mimeType: image.mimeType };\n });\n if (images?.length) {\n if (!acceptsImages) throw new Error(\"Selected Pi durable model does not accept image input\");\n if (images.length > 32 || images.reduce((sum, image) => sum + image.data.length, 0) > MAX_IMAGE_CHARS) {\n throw new Error(\"Pi durable image input exceeds 32 images or 16777216 base64 characters\");\n }\n }\n let schema: Record<string, unknown> | undefined;\n if (context.schema !== undefined) {\n if (!context.schema || typeof context.schema !== \"object\" || Array.isArray(context.schema)) {\n throw new Error(\"Pi durable output schema must be a JSON object\");\n }\n const json = JSON.stringify(context.schema);\n if (json.length > MAX_SCHEMA_CHARS) throw new Error(\"Pi durable output schema exceeds 262144 characters\");\n schema = JSON.parse(json) as Record<string, unknown>;\n }\n const content: UserInput = images?.length\n ? [{ type: \"text\", text: context.task }, ...images]\n : context.task;\n const instructions = [context.systemPrompt ?? \"\", ...(schema ? [\n `Your final response must contain only JSON matching this schema, without Markdown fences:\\n${JSON.stringify(schema)}`,\n ] : [])].filter(Boolean).join(\"\\n\\n\");\n return { content, instructions, schema, images };\n}\n", "import { createHash, randomUUID } from \"node:crypto\";\nimport type { Conversation, Cursor, Harness, Storage, Submission, SubmissionRecord } from \"@earendil-works/pi-durable\";\nimport type { Context } from \"@earendil-works/chord\";\n\nexport interface PiDurableMessageOptions {\n /** Stable caller-issued identity. Retrying the same message is a no-op, including after reattachment. */\n requestId?: string;\n}\n\ntype SettledSubmission = Awaited<ReturnType<Submission[\"wait\"]>>;\nconst MAX_CONTROLS = 128;\nconst digest = (text: string): string => createHash(\"sha256\").update(text).digest(\"hex\");\n\n/** One completion boundary over the initial submission and every host-admitted steer/follow-up. */\nexport async function openDurableControls(options: {\n durable: typeof import(\"@earendil-works/pi-durable\");\n context: Context;\n harness: Harness;\n storage: Storage;\n conversation: Conversation;\n initial: Submission;\n runId: string;\n serialize: <T>(operation: () => Promise<T>) => Promise<T>;\n closed: () => boolean;\n}) {\n const { durable, context, harness, storage, conversation, initial, runId, serialize, closed } = options;\n const prefix = `${runId}:control:`;\n const Boundary = durable.defineDoc<{ closed: boolean }>({\n kind: \"fabric.durable.completion\", version: 1, scope: \"conversation\", history: \"latest\", fork: \"initial\",\n initial: () => ({ closed: false }),\n });\n await conversation.commit(async tx => { await tx.doc(Boundary, conversation.id); }, context);\n let stopping = false;\n\n async function submissions(): Promise<SubmissionRecord[]> {\n const controls: SubmissionRecord[] = [];\n let cursor: Cursor | undefined;\n let scanned = 0;\n do {\n const page = await storage.scanSubmissions({ conversationId: conversation.id }, 64, cursor, context);\n scanned += page.items.length;\n if (scanned > 4096) throw new Error(\"Pi durable submission scan exceeds 4096 records\");\n for (const item of page.items) {\n if (item.type === \"input\" && item.requestId?.startsWith(prefix)) controls.push(item);\n }\n cursor = page.next;\n } while (cursor !== undefined);\n if (controls.length > MAX_CONTROLS) throw new Error(\"Pi durable control count exceeds 128 messages\");\n return [await initial.status(context), ...controls];\n }\n\n async function send(kind: \"steer\" | \"followUp\", message: string, data?: unknown): Promise<void> {\n if (typeof message !== \"string\" || !message.trim() || message.length > 16_384) {\n throw new Error(\"Pi durable control message must contain 1\u201316384 characters\");\n }\n if (data !== undefined && (!data || typeof data !== \"object\" || Array.isArray(data) ||\n Object.keys(data).some(key => key !== \"requestId\"))) {\n throw new Error(\"Pi durable message options support only requestId\");\n }\n const requested = (data as PiDurableMessageOptions | undefined)?.requestId;\n if (requested !== undefined && (typeof requested !== \"string\" || !requested.trim() || requested.length > 256)) {\n throw new Error(\"Pi durable message requestId must contain 1\u2013256 characters\");\n }\n const identity = `${prefix}${digest(requested ?? randomUUID())}:`;\n const requestId = `${identity}${digest(JSON.stringify({ kind, message }))}`;\n const records = await submissions();\n const existing = records.find(item => item.requestId?.startsWith(identity));\n if (existing) {\n if (existing.requestId !== requestId) throw new Error(\"Pi durable message requestId already bound to different work\");\n return;\n }\n const boundary = await harness.snapshot(Boundary, conversation.id, context);\n if (stopping || boundary?.closed || records[0]?.status === \"unanswered\") throw new Error(\"Pi durable run no longer accepts messages\");\n if (records.length > MAX_CONTROLS) throw new Error(\"Pi durable control count exceeds 128 messages\");\n // submit commits the input and its identity atomically. Recovery scans it even\n // if the process dies before this promise returns; no second intent log or replay is needed.\n await conversation.submit({ type: \"input\", content: message, requestId, whenBusy: kind }, context);\n }\n\n async function wait(): Promise<SettledSubmission | undefined> {\n while (!closed()) {\n const records = await submissions();\n let final: SettledSubmission | undefined;\n for (const record of records) {\n const submission = record.id === initial.id ? initial : await harness.submission(record.id, context);\n if (!submission) throw new Error(\"Pi durable admitted submission is missing\");\n const result = await submission.wait(context);\n if (closed()) return;\n if (result.status === \"unanswered\") {\n stopping = true;\n // An unsuccessful generation leaves queued follow-ups in the inbox.\n // Withdraw them rather than hang forever or run them after reporting failure.\n await conversation.abort(context, { background: true });\n final = result;\n break;\n }\n if (result.type !== \"input\") throw new Error(\"Pi durable expected an input submission\");\n // A steer admitted after a follow-up can be answered before it. Entry\n // IDs are session-global monotonic numbers; use answer order, not admission order.\n if (!final || final.type !== \"input\" || final.status !== \"done\" || result.answer > final.answer) final = result;\n }\n if (!final || closed()) return;\n const completed = await serialize(async () => {\n const current = await submissions();\n if (current.length !== records.length) return false;\n await conversation.commit(async tx => { (await tx.doc(Boundary, conversation.id)).closed = true; }, context);\n return true;\n });\n if (completed) return final;\n }\n }\n\n return {\n send,\n wait,\n async stop() {\n stopping = true;\n await conversation.abort(context, { background: true });\n },\n async liveness(): Promise<\"running\" | \"settled\" | \"cancelled\" | \"interrupted\"> {\n const boundary = await harness.snapshot(Boundary, conversation.id, context);\n if (!boundary?.closed) return \"running\";\n const records = await submissions();\n const failure = records.find(item => item.status === \"unanswered\");\n return failure?.status === \"unanswered\" ? failure.reason === \"aborted\" ? \"cancelled\" : \"interrupted\" : \"settled\";\n },\n };\n}\n\nexport type PiDurableControls = Awaited<ReturnType<typeof openDurableControls>>;\n"],
4
+ "sourcesContent": ["import { createHash } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport type { Harness, HarnessOptions, ModelRef, Registry, Storage, Conversation, Submission, ConversationWatch, ConversationView, ToolRegistration } from \"@earendil-works/pi-durable\";\nimport type { FabricHostedRunner, FabricHostedRunContext, FabricHostedReporter, FabricHostedLiveness } from \"./agents/runner-registry.js\";\nimport type { AgentUsage } from \"./agents/types.js\";\nimport { durableInput } from \"./durable-input.js\";\nimport { openDurableControls, type PiDurableControls, type PiDurableMessageOptions } from \"./durable-controls.js\";\nexport type { PiDurableMessageOptions } from \"./durable-controls.js\";\n\n/** The host must hold exclusive ownership until release, including across processes. */\nexport interface PiDurableStorageLease {\n storage: Storage;\n release(): void | Promise<void>;\n}\nexport type PiDurableStorageOptions =\n | { kind: \"jsonl\"; directory: string }\n | { kind: \"factory\"; identity: string; acquire(runId: string): Promise<PiDurableStorageLease> };\nexport interface PiDurableRunnerOptions {\n id?: string;\n label?: string;\n residentModule?: string;\n models: HarnessOptions[\"models\"];\n registry: Registry;\n env: NonNullable<HarnessOptions[\"env\"]>;\n allowedModels: readonly ModelRef[];\n /** Optional host-selected model, which must also appear in allowedModels. */\n defaultModel?: ModelRef;\n storage: PiDurableStorageOptions;\n}\nexport interface PiDurableRunner extends FabricHostedRunner {\n steer(locator: unknown, message: string, options?: PiDurableMessageOptions): Promise<void>;\n followUp(locator: unknown, message: string, options?: PiDurableMessageOptions): Promise<void>;\n /** Seal this instance, join invocations and release storage; never abort work. Create a new runner to reopen. */\n close(): Promise<void>;\n}\nexport interface PiDurableLocator {\n version: 1;\n backend: \"pi-durable\";\n storage: string;\n runId: string;\n}\n\ntype Runtime = { durable: typeof import(\"@earendil-works/pi-durable\"); context: typeof import(\"@earendil-works/chord/context\") };\nlet runtimePromise: Promise<Runtime> | undefined;\nasync function runtime(): Promise<Runtime> {\n return runtimePromise ??= Promise.resolve().then(() => {\n const require = createRequire(import.meta.url);\n for (const name of [\"@earendil-works/pi-durable\", \"@earendil-works/chord\"]) {\n const metadata = require(`${name}/package.json`) as { version?: string };\n if (metadata.version !== \"1.3.0\") throw new Error(`Unsupported ${name} version ${metadata.version ?? \"unknown\"}; expected 1.3.0`);\n }\n return Promise.all([import(\"@earendil-works/pi-durable\"), import(\"@earendil-works/chord/context\")]);\n })\n .then(([durable, context]) => ({ durable, context }))\n .catch((cause: unknown) => {\n runtimePromise = undefined;\n throw new Error(`Pi durable runner requires pinned dependencies @earendil-works/pi-durable@1.3.0 and @earendil-works/chord@1.3.0: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });\n });\n}\nconst hash = (value: string): string => createHash(\"sha256\").update(value).digest(\"hex\");\nconst ownershipSymbol = Symbol.for(\"pi-fabric.durable.owners.v1\");\nconst globals = globalThis as unknown as Record<symbol, Set<string> | undefined>;\nconst owners = globals[ownershipSymbol] ??= new Set<string>();\ninterface OpenRun {\n harness: Harness;\n conversation?: Conversation;\n submission?: Submission;\n controls?: PiDurableControls;\n lease: PiDurableStorageLease;\n ownerKey: string;\n watch?: ConversationWatch;\n reporters: Set<FabricHostedReporter>;\n observing?: Promise<void>;\n fingerprint?: string;\n}\n\n/** Opt-in hosted adapter. No registration or runtime package loading occurs at factory creation. */\nexport function createPiDurableRunner(options: PiDurableRunnerOptions): PiDurableRunner {\n if (!options.models || !options.registry || typeof options.env !== \"function\") throw new Error(\"Pi durable requires host models, registry and environment\");\n const storage = options.storage;\n const directory = storage.kind === \"jsonl\" ? path.resolve(storage.directory) : undefined;\n if (storage.kind === \"factory\" && (!storage.identity || typeof storage.acquire !== \"function\")) throw new Error(\"Storage factory requires identity and exclusive acquire()\");\n const identity = hash(storage.kind === \"jsonl\" ? `jsonl:${directory}` : `factory:${storage.identity}`);\n const allowed = new Map(options.allowedModels.map(model => [`${model.provider}/${model.modelId}`, { ...model }]));\n if (!allowed.size) throw new Error(\"Pi durable requires an explicit model allowlist\");\n const id = options.id ?? \"pi-durable-leaf\";\n const defaultModel = options.defaultModel ? `${options.defaultModel.provider}/${options.defaultModel.modelId}` : undefined;\n if (defaultModel && !allowed.has(defaultModel)) throw new Error(\"Pi durable default model must be allowlisted\");\n const runs = new Map<string, OpenRun>();\n const transcriptSeen = new WeakMap<FabricHostedReporter, Set<import(\"@earendil-works/pi-durable\").EntryId>>();\n let sealed = false;\n let tail: Promise<unknown> = Promise.resolve();\n let closing: Promise<void> | undefined;\n const serial = <T>(fn: () => Promise<T>): Promise<T> => {\n if (sealed) return Promise.reject(new Error(\"Pi durable runner is closed\"));\n const result = tail.then(fn);\n tail = result.catch(() => undefined);\n return result;\n };\n function locator(value: unknown): PiDurableLocator {\n const loc = value as Partial<PiDurableLocator> | null;\n if (!loc || loc.version !== 1 || loc.backend !== \"pi-durable\" || loc.storage !== identity || typeof loc.runId !== \"string\" || !loc.runId || loc.runId.length > 512) throw new Error(\"Invalid Pi durable locator or storage identity\");\n return loc as PiDurableLocator;\n }\n function validate(context: FabricHostedRunContext) {\n if (context.id !== context.idempotencyKey) throw new Error(\"Pi durable requires Fabric run ID as idempotencyKey\");\n if (context.residency === \"durable\" && !options.residentModule) throw new Error(\"Durable residency requires an explicit residentModule\");\n for (const key of [\"kernel\", \"sessionFile\", \"actorId\", \"actorName\", \"writePolicy\", \"scope\"] as const) {\n if (context[key] !== undefined) throw new Error(`Pi durable does not support ${key}`);\n }\n if (context.recursive) throw new Error(\"Pi durable does not support recursiveFabric\");\n const modelKey = context.model ?? defaultModel;\n const model = modelKey ? allowed.get(modelKey) : undefined;\n if (!model || !options.models.getModel(model.provider, model.modelId)) throw new Error(`Unknown or disallowed Pi durable model: ${modelKey ?? \"(missing explicit provider/model)\"}`);\n const catalogModel = options.models.getModel(model.provider, model.modelId)!;\n const input = durableInput(context, catalogModel.input.includes(\"image\"));\n if (context.thinking && ((!catalogModel.reasoning && context.thinking !== \"off\") || catalogModel.thinkingLevelMap?.[context.thinking] === null)) throw new Error(`Unsupported thinking level: ${context.thinking}`);\n const snapshot = options.registry.snapshot();\n const available = new Map(snapshot.tools().map(({ tool }) => [tool.name, tool]));\n const tools = context.tools.map(name => {\n let tool = available.get(name);\n if (!tool) throw new Error(`Unknown Pi durable tool: ${name}`);\n for (const extension of snapshot.installed()) for (const wrap of extension.wraps ?? []) {\n if (\"tool\" in wrap && wrap.tool === name) tool = wrap.wrap(tool);\n }\n if (tool.name !== name) throw new Error(`Registry wrapper renamed tool ${name}`);\n const implementation = tool;\n return { ...implementation, replay: name === \"fabric_exec\" ? \"unsafe\" as const : implementation.replay ?? \"unsafe\", execute: async (...args: Parameters<ToolRegistration[\"execute\"]>) => {\n const result = await implementation.execute(...args);\n if (result.control?.addTools || result.control?.handoff) throw new Error(\"Pi durable adapter does not support tool-set changes or handoff controls\");\n return result;\n } } satisfies ToolRegistration;\n });\n const fingerprint = hash(JSON.stringify({ task: context.task, cwd: context.cwd, model, tools: [...context.tools], thinking: context.thinking ?? \"off\", systemPrompt: context.systemPrompt ?? \"\", ...(input.images?.length ? { images: input.images } : {}), ...(input.schema ? { schema: input.schema } : {}) }));\n return { model, tools, fingerprint, input };\n }\n async function acquire(runId: string, rt: Runtime): Promise<PiDurableStorageLease> {\n if (storage.kind === \"factory\") return storage.acquire(runId);\n const base = directory!;\n await fs.mkdir(base, { recursive: true });\n const canonical = await fs.realpath(base);\n const stem = hash(runId);\n const lock = path.join(canonical, `${stem}.writer`);\n try { await fs.mkdir(lock); } catch (cause) { throw new Error(`Pi durable single-writer lock unavailable: ${lock}. Never remove a stale lock until its owner is verified dead.`, { cause }); }\n try {\n const { openNodeJsonlStorage } = await import(\"@earendil-works/pi-durable/storage/jsonl/node\");\n const opened = await openNodeJsonlStorage(path.join(canonical, stem), rt.context.BACKGROUND_CONTEXT, { fsync: true });\n return { storage: opened, release: () => fs.rmdir(lock) };\n } catch (error) { await fs.rmdir(lock); throw error; }\n }\n async function open(runId: string, selected: ReturnType<typeof validate>): Promise<OpenRun> {\n const existing = runs.get(runId);\n if (existing) {\n if (existing.fingerprint && existing.fingerprint !== selected.fingerprint) throw new Error(\"Fabric run ID already bound to different work\");\n return existing;\n }\n const ownerKey = `${identity}:${runId}`;\n if (owners.has(ownerKey)) throw new Error(\"Pi durable storage already has an active writer\");\n owners.add(ownerKey);\n let lease: PiDurableStorageLease | undefined;\n try {\n const rt = await runtime();\n lease = await acquire(runId, rt);\n // Deliberately import only requested tool implementations; no registry hooks, sections or tasks.\n const registry = rt.durable.createRegistry();\n registry.install(rt.durable.defineExtension({ name: \"fabric.durable.tools\", tools: selected.tools }));\n const harness = await rt.durable.Harness.open(lease.storage, { models: options.models, registry, env: options.env, settings: { compaction: { enabled: false }, retry: { enabled: false }, stream: { maxRetries: 0 } } }, rt.context.BACKGROUND_CONTEXT);\n const run: OpenRun = { harness, lease, ownerKey, reporters: new Set() };\n runs.set(runId, run);\n return run;\n } catch (error) {\n if (lease) {\n try {\n await lease.storage.close((await runtime()).context.BACKGROUND_CONTEXT);\n await lease.release();\n } catch (cleanupError) {\n throw new AggregateError([error, cleanupError], \"Pi durable open failed; cleanup failed, lease remains owned\");\n }\n }\n owners.delete(ownerKey);\n throw error;\n }\n }\n async function bind(value: unknown, context: FabricHostedRunContext, reporter: FabricHostedReporter, admit: boolean): Promise<void> {\n const loc = locator(value);\n if (loc.runId !== context.id) throw new Error(\"Pi durable locator does not match Fabric run ID\");\n const selected = validate(context);\n const rt = await runtime();\n const { getSupportedThinkingLevels } = await import(\"@earendil-works/pi-ai/models\");\n if (!getSupportedThinkingLevels(options.models.getModel(selected.model.provider, selected.model.modelId)!).includes(context.thinking ?? \"off\")) throw new Error(`Unsupported thinking level: ${context.thinking ?? \"off\"}`);\n const ctx = rt.context.BACKGROUND_CONTEXT;\n const run = await open(loc.runId, selected);\n const Manifest = rt.durable.defineDoc<{ fingerprint: string }>({ kind: \"fabric.durable.request\", version: 1, scope: \"conversation\", history: \"latest\", fork: \"initial\", initial: () => ({ fingerprint: selected.fingerprint }) });\n let conversation = await run.harness.conversation(rt.durable.ROOT_CONVERSATION_ID, ctx);\n if (!conversation && admit) conversation = await run.harness.root(ctx, { agent: { model: selected.model, tools: selected.tools, thinkingLevel: context.thinking ?? \"off\", cwd: context.cwd, instructions: selected.input.instructions }, init: async (tx, id) => { await tx.doc(Manifest, id); } });\n if (!conversation) throw new Error(\"Pi durable attach found no existing conversation; outcome indeterminate (not resubmitted)\");\n const manifest = await run.harness.snapshot(Manifest, conversation.id, ctx);\n if (manifest?.fingerprint !== selected.fingerprint) throw new Error(\"Fabric run ID already bound to different work or missing committed manifest\");\n run.fingerprint = selected.fingerprint;\n run.conversation = conversation;\n const found = await conversation.commit(tx => tx.submissionByRequest(conversation!.id, context.id), ctx);\n let submission = found ? await run.harness.submission(found.id, ctx) : undefined;\n if (!submission && admit) submission = await conversation.submit({ type: \"input\", content: selected.input.content, requestId: context.id }, ctx);\n if (!submission) throw new Error(\"Pi durable attach found no existing submission; outcome indeterminate (not resubmitted)\");\n run.submission = submission;\n if (!run.controls) {\n run.controls = await openDurableControls({ durable: rt.durable, context: ctx, harness: run.harness, storage: run.lease.storage, conversation, initial: submission, runId: context.id, serialize: serial, closed: () => sealed });\n }\n run.reporters.add(reporter);\n if (!run.watch) {\n run.watch = await conversation.watch(ctx);\n run.watch.start(async view => { for (const target of run.reporters) report(view, target); });\n }\n report(run.watch.value, reporter);\n if (!run.observing) {\n run.observing = run.controls.wait().then(async result => {\n if (sealed || !result) return;\n const view = await conversation!.context(ctx);\n const answer = result.type === \"input\" && result.status === \"done\" ? view.entries.find(entry => entry.id === result.answer) : undefined;\n const output = answer?.model?.flatMap(message => message.role === \"assistant\" ? message.content.filter(block => block.type === \"text\").map(block => block.text) : []).join(\"\") ?? \"\";\n const completion: { status: \"completed\" | \"stopped\" | \"failed\"; text: string; value?: unknown; error?: string } = {\n status: result.status === \"done\" ? \"completed\" : result.reason === \"aborted\" ? \"stopped\" : \"failed\",\n text: result.status === \"done\" ? output : `Pi durable unanswered: ${result.reason}`,\n };\n if (selected.input.schema) {\n const { validateAgentResult } = await import(\"./agents/result.js\");\n validateAgentResult(completion, selected.input.schema);\n }\n const usage = await run.harness.usage(ctx);\n for (const target of run.reporters) {\n target.usage(totalUsage(usage));\n target.finish({ status: completion.status, output: completion.error ?? completion.text, ...(completion.value !== undefined ? { structured: completion.value } : {}) });\n }\n delete run.observing;\n }).catch(error => { if (!sealed) for (const target of run.reporters) target.fail({ error: `Pi durable observation failed: ${String(error)}` }); });\n }\n }\n function totalUsage(usage: import(\"@earendil-works/pi-durable\").UsageState): AgentUsage {\n const total: AgentUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };\n for (const bucket of [usage.models, usage.tools]) for (const item of Object.values(bucket)) {\n total.input += item.input; total.output += item.output; total.cacheRead += item.cacheRead; total.cacheWrite += item.cacheWrite; total.cost += item.cost.total;\n }\n return total;\n }\n function report(view: ConversationView, reporter: FabricHostedReporter): void {\n let seen = transcriptSeen.get(reporter);\n if (!seen) { seen = new Set(); transcriptSeen.set(reporter, seen); }\n for (const entry of view.entries) {\n if (seen.has(entry.id)) continue;\n seen.add(entry.id);\n for (const message of entry.model ?? []) {\n if (message.role === \"assistant\" || message.role === \"user\") {\n const content = typeof message.content === \"string\" ? message.content : message.content.filter(block => block.type === \"text\").map(block => ({ type: \"text\" as const, text: block.text }));\n reporter.transcript({ type: \"message_end\", message: { role: message.role, content } });\n if (message.role === \"assistant\") for (const block of message.content) if (block.type === \"toolCall\") reporter.transcript({ type: \"tool_execution_start\", toolCallId: block.id, toolName: block.name, args: block.arguments });\n } else if (message.role === \"toolResult\") reporter.transcript({ type: \"tool_execution_end\", toolCallId: message.toolCallId, toolName: message.toolName, result: message.content, isError: message.isError });\n }\n }\n const assistants = view.entries.flatMap(entry => entry.model?.filter(message => message.role === \"assistant\") ?? []);\n const live = view.docs[\"pi.live\"] as unknown as import(\"@earendil-works/pi-durable\").LiveState | undefined;\n const last = live?.generation?.message ?? assistants.at(-1);\n const calls = assistants.flatMap(message => message.role === \"assistant\" ? message.content.filter(block => block.type === \"toolCall\") : []);\n reporter.progress({ turns: assistants.length, toolCalls: calls.length, currentTool: live?.tools?.find(tool => tool.status === \"running\")?.name ?? null, text: last?.role === \"assistant\" ? last.content.filter(block => block.type === \"text\").map(block => block.text).join(\"\") : \"\" });\n const usage = view.docs[\"pi.usage\"];\n if (usage) reporter.usage(totalUsage(usage as unknown as import(\"@earendil-works/pi-durable\").UsageState));\n }\n return {\n id, label: options.label ?? \"Pi durable (opt-in)\", kind: \"hosted\", ...(options.residentModule ? { residentModule: options.residentModule } : {}),\n capabilities: Object.freeze({ recursiveFabric: false, steer: true, followUp: true, persistentSessions: false, kernels: false, handoff: false, modelDiscovery: true, imageInput: true, compaction: false, questions: false, sleep: false, writePolicy: false }),\n defaultModel: () => defaultModel,\n models: () => [...allowed.values()].flatMap(ref => {\n const model = options.models.getModel(ref.provider, ref.modelId);\n return model ? [{ runner: id, provider: ref.provider, id: ref.modelId, key: `${ref.provider}/${ref.modelId}`, name: model.name, input: [...model.input], reasoning: model.reasoning, contextWindow: model.contextWindow, maxTokens: model.maxTokens }] : [];\n }),\n prepare(context) { if (sealed) throw new Error(\"Pi durable runner is closed\"); validate(context); return { version: 1, backend: \"pi-durable\", storage: identity, runId: context.id } satisfies PiDurableLocator; },\n normalizeModel(model) { if (!allowed.has(model)) throw new Error(`Unknown or disallowed Pi durable model: ${model}`); return model; },\n mapTools(tools) { const names = new Set(options.registry.snapshot().tools().map(item => item.tool.name)); for (const tool of tools) if (!names.has(tool)) throw new Error(`Unknown Pi durable tool: ${tool}`); return [...tools]; },\n start: (loc, context, reporter) => serial(() => bind(loc, context, reporter, true)),\n attach: (loc, context, reporter) => serial(() => bind(loc, context, reporter, false)),\n steer: (value, message, data) => serial(async () => {\n const run = runs.get(locator(value).runId);\n if (!run?.controls) throw new Error(\"Pi durable run is not attached\");\n await run.controls.send(\"steer\", message, data);\n }),\n followUp: (value, message, data) => serial(async () => {\n const run = runs.get(locator(value).runId);\n if (!run?.controls) throw new Error(\"Pi durable run is not attached\");\n await run.controls.send(\"followUp\", message, data);\n }),\n liveness: value => serial(async (): Promise<FabricHostedLiveness> => {\n const run = runs.get(locator(value).runId);\n return run?.controls ? run.controls.liveness() : \"unknown\";\n }),\n stop: value => serial(async () => {\n const run = runs.get(locator(value).runId);\n if (!run?.controls) return { confirmed: false };\n await run.controls.stop();\n return { confirmed: true };\n }),\n close() {\n if (closing) return closing;\n sealed = true;\n closing = tail.then(async () => {\n const results = await Promise.allSettled([...runs].map(async ([id, run]) => {\n await run.watch?.stop();\n await run.harness.close((await runtime()).context.BACKGROUND_CONTEXT);\n await run.observing;\n await run.lease.release();\n owners.delete(run.ownerKey);\n runs.delete(id);\n }));\n const failed = results.filter((result): result is PromiseRejectedResult => result.status === \"rejected\");\n if (failed.length) throw new AggregateError(failed.map(result => result.reason), \"Pi durable close failed; failed leases remain owned\");\n });\n return closing;\n },\n };\n}\n", "import type { UserInput } from \"@earendil-works/pi-durable\";\nimport type { FabricHostedRunContext } from \"./agents/runner-registry.js\";\n\nconst MAX_IMAGE_CHARS = 16_777_216;\nconst MAX_SCHEMA_CHARS = 262_144;\n\n/** Snapshot request data before an asynchronous admission; never retain caller-owned image/schema objects. */\nexport function durableInput(context: Pick<FabricHostedRunContext, \"task\" | \"images\" | \"schema\" | \"systemPrompt\">, acceptsImages: boolean) {\n const images = context.images?.map(image => {\n if (!image || image.type !== \"image\" || typeof image.mimeType !== \"string\" ||\n !/^image\\/(png|jpeg|gif|webp)$/.test(image.mimeType) || typeof image.data !== \"string\" ||\n image.data.length === 0 || image.data.length > MAX_IMAGE_CHARS ||\n image.data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(image.data)) {\n throw new Error(\"Pi durable image input requires a base64 PNG, JPEG, GIF or WebP block\");\n }\n return { type: \"image\" as const, data: image.data, mimeType: image.mimeType };\n });\n if (images?.length) {\n if (!acceptsImages) throw new Error(\"Selected Pi durable model does not accept image input\");\n if (images.length > 32 || images.reduce((sum, image) => sum + image.data.length, 0) > MAX_IMAGE_CHARS) {\n throw new Error(\"Pi durable image input exceeds 32 images or 16777216 base64 characters\");\n }\n }\n let schema: Record<string, unknown> | undefined;\n if (context.schema !== undefined) {\n if (!context.schema || typeof context.schema !== \"object\" || Array.isArray(context.schema)) {\n throw new Error(\"Pi durable output schema must be a JSON object\");\n }\n const json = JSON.stringify(context.schema);\n if (json.length > MAX_SCHEMA_CHARS) throw new Error(\"Pi durable output schema exceeds 262144 characters\");\n schema = JSON.parse(json) as Record<string, unknown>;\n }\n const content: UserInput = images?.length\n ? [{ type: \"text\", text: context.task }, ...images]\n : context.task;\n const instructions = [context.systemPrompt ?? \"\", ...(schema ? [\n `Your final response must contain only JSON matching this schema, without Markdown fences:\\n${JSON.stringify(schema)}`,\n ] : [])].filter(Boolean).join(\"\\n\\n\");\n return { content, instructions, schema, images };\n}\n", "import { createHash, randomUUID } from \"node:crypto\";\nimport type { Conversation, Cursor, Harness, Storage, Submission, SubmissionRecord } from \"@earendil-works/pi-durable\";\nimport type { Context } from \"@earendil-works/chord\";\n\nexport interface PiDurableMessageOptions {\n /** Stable caller-issued identity. Retrying the same message is a no-op, including after reattachment. */\n requestId?: string;\n}\n\ntype SettledSubmission = Awaited<ReturnType<Submission[\"wait\"]>>;\nconst MAX_CONTROLS = 128;\nconst digest = (text: string): string => createHash(\"sha256\").update(text).digest(\"hex\");\n\n/** One completion boundary over the initial submission and every host-admitted steer/follow-up. */\nexport async function openDurableControls(options: {\n durable: typeof import(\"@earendil-works/pi-durable\");\n context: Context;\n harness: Harness;\n storage: Storage;\n conversation: Conversation;\n initial: Submission;\n runId: string;\n serialize: <T>(operation: () => Promise<T>) => Promise<T>;\n closed: () => boolean;\n}) {\n const { durable, context, harness, storage, conversation, initial, runId, serialize, closed } = options;\n const prefix = `${runId}:control:`;\n const Boundary = durable.defineDoc<{ closed: boolean }>({\n kind: \"fabric.durable.completion\", version: 1, scope: \"conversation\", history: \"latest\", fork: \"initial\",\n initial: () => ({ closed: false }),\n });\n await conversation.commit(async tx => { await tx.doc(Boundary, conversation.id); }, context);\n let stopping = false;\n\n async function submissions(): Promise<SubmissionRecord[]> {\n const controls: SubmissionRecord[] = [];\n let cursor: Cursor | undefined;\n let scanned = 0;\n do {\n const page = await storage.scanSubmissions({ conversationId: conversation.id }, 64, cursor, context);\n scanned += page.items.length;\n if (scanned > 4096) throw new Error(\"Pi durable submission scan exceeds 4096 records\");\n for (const item of page.items) {\n if (item.type === \"input\" && item.requestId?.startsWith(prefix)) controls.push(item);\n }\n cursor = page.next;\n } while (cursor !== undefined);\n if (controls.length > MAX_CONTROLS) throw new Error(\"Pi durable control count exceeds 128 messages\");\n return [await initial.status(context), ...controls];\n }\n\n async function send(kind: \"steer\" | \"followUp\", message: string, data?: unknown): Promise<void> {\n if (typeof message !== \"string\" || !message.trim() || message.length > 16_384) {\n throw new Error(\"Pi durable control message must contain 1\u201316384 characters\");\n }\n if (data !== undefined && (!data || typeof data !== \"object\" || Array.isArray(data) ||\n Object.keys(data).some(key => key !== \"requestId\"))) {\n throw new Error(\"Pi durable message options support only requestId\");\n }\n const requested = (data as PiDurableMessageOptions | undefined)?.requestId;\n if (requested !== undefined && (typeof requested !== \"string\" || !requested.trim() || requested.length > 256)) {\n throw new Error(\"Pi durable message requestId must contain 1\u2013256 characters\");\n }\n const identity = `${prefix}${digest(requested ?? randomUUID())}:`;\n const requestId = `${identity}${digest(JSON.stringify({ kind, message }))}`;\n const records = await submissions();\n const existing = records.find(item => item.requestId?.startsWith(identity));\n if (existing) {\n if (existing.requestId !== requestId) throw new Error(\"Pi durable message requestId already bound to different work\");\n return;\n }\n const boundary = await harness.snapshot(Boundary, conversation.id, context);\n if (stopping || boundary?.closed || records[0]?.status === \"unanswered\") throw new Error(\"Pi durable run no longer accepts messages\");\n if (records.length > MAX_CONTROLS) throw new Error(\"Pi durable control count exceeds 128 messages\");\n // submit commits the input and its identity atomically. Recovery scans it even\n // if the process dies before this promise returns; no second intent log or replay is needed.\n await conversation.submit({ type: \"input\", content: message, requestId, whenBusy: kind }, context);\n }\n\n async function wait(): Promise<SettledSubmission | undefined> {\n while (!closed()) {\n const records = await submissions();\n let final: SettledSubmission | undefined;\n for (const record of records) {\n const submission = record.id === initial.id ? initial : await harness.submission(record.id, context);\n if (!submission) throw new Error(\"Pi durable admitted submission is missing\");\n const result = await submission.wait(context);\n if (closed()) return;\n if (result.status === \"unanswered\") {\n stopping = true;\n // An unsuccessful generation leaves queued follow-ups in the inbox.\n // Withdraw them rather than hang forever or run them after reporting failure.\n await conversation.abort(context, { background: true });\n final = result;\n break;\n }\n if (result.type !== \"input\") throw new Error(\"Pi durable expected an input submission\");\n // A steer admitted after a follow-up can be answered before it. Entry\n // IDs are session-global monotonic numbers; use answer order, not admission order.\n if (!final || final.type !== \"input\" || final.status !== \"done\" || result.answer > final.answer) final = result;\n }\n if (!final || closed()) return;\n const completed = await serialize(async () => {\n const current = await submissions();\n if (current.length !== records.length) return false;\n await conversation.commit(async tx => { (await tx.doc(Boundary, conversation.id)).closed = true; }, context);\n return true;\n });\n if (completed) return final;\n }\n }\n\n return {\n send,\n wait,\n async stop() {\n stopping = true;\n await conversation.abort(context, { background: true });\n },\n async liveness(): Promise<\"running\" | \"settled\" | \"cancelled\" | \"interrupted\"> {\n const boundary = await harness.snapshot(Boundary, conversation.id, context);\n if (!boundary?.closed) return \"running\";\n const records = await submissions();\n const failure = records.find(item => item.status === \"unanswered\");\n return failure?.status === \"unanswered\" ? failure.reason === \"aborted\" ? \"cancelled\" : \"interrupted\" : \"settled\";\n },\n };\n}\n\nexport type PiDurableControls = Awaited<ReturnType<typeof openDurableControls>>;\n"],
5
5
  "mappings": "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",
6
6
  "names": ["createHash", "require", "createHash", "id"]
7
7
  }
@@ -1,6 +1,6 @@
1
1
  export { FABRIC_MANAGED_HOST_VERSION } from "./extension.js";
2
2
  export type { FabricManagedHostOptions } from "./managed-host.js";
3
- declare const _default: (pi: import("pi-fabric-worker-sdk").ExtensionAPI, options?: {
3
+ declare const _default: (pi: import("@earendil-works/pi-coding-agent").ExtensionAPI, options?: {
4
4
  managedHost?: import("./managed-host.js").FabricManagedHostOptions;
5
5
  }) => Promise<void>;
6
6
  export default _default;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { FABRIC_MANAGED_HOST_VERSION } from "./extension.js";
2
2
  export type { FabricManagedHostOptions } from "./managed-host.js";
3
- declare const _default: (pi: import("pi-fabric-worker-sdk").ExtensionAPI, options?: {
3
+ declare const _default: (pi: import("@earendil-works/pi-coding-agent").ExtensionAPI, options?: {
4
4
  managedHost?: import("./managed-host.js").FabricManagedHostOptions;
5
5
  }) => Promise<void>;
6
6
  export default _default;