@orkestrel/agent 0.0.24 → 0.0.26

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/shapers.ts","../../../src/core/contracts.ts","../../../src/core/helpers.ts","../../../src/core/conversations/Conversation.ts","../../../src/core/conversations/ConversationManager.ts","../../../src/core/instructions/Instruction.ts","../../../src/core/instructions/InstructionManager.ts","../../../src/core/AgentContext.ts","../../../src/core/Channel.ts","../../../src/core/Agent.ts","../../../src/core/AgentRegistry.ts","../../../src/core/Authority.ts","../../../src/core/validators.ts","../../../src/core/conversations/stores/DatabaseConversationStore.ts","../../../src/core/conversations/stores/MemoryConversationStore.ts","../../../src/core/AgentProvider.ts","../../../src/core/providers/RelayProvider.ts","../../../src/core/RelayStream.ts","../../../src/core/scopes/Scope.ts","../../../src/core/scopes/ScopeManager.ts","../../../src/core/ThinkSplitter.ts","../../../src/core/factories.ts"],"sourcesContent":["/**\n * Caps an {@link AgentInterface} turn's tool iterations by default — `10` context → provider →\n * tools cycles before the loop stops, so a model that keeps requesting tools can never loop\n * forever. Overridable per agent through `AgentOptions.limit`.\n */\nexport const DEFAULT_AGENT_LIMIT = 10\n\n/**\n * Names the zone an {@link AuthorityInterface}'s default fallback {@link AuthorityDecision}\n * carries — `'default'`, the classification for a tool call that matched no rule. Paired with\n * the default `allowed: true` fallback, an unmatched call is allowed under this zone, so a\n * rules list of denials acts as a denylist; a caller wanting deny-by-default supplies an\n * `allowed: false` `fallback` of their own (see `AuthorityOptions`).\n */\nexport const DEFAULT_AUTHORITY_ZONE = 'default'\n\n/**\n * Sets the default number of recent live messages a {@link ConversationInterface}'s `compact()`\n * retains verbatim — `0`, so a manual `compact()` folds every current live message into one\n * summarized section and keeps no tail. A caller retains a recent tail by passing `keep` (on\n * {@link ConversationOptions}, {@link ConversationManagerOptions}, or per-fold through\n * {@link CompactOptions}), folding only the older `count - keep` messages and leaving the most\n * recent `keep` live for the next turn. Overridable everywhere `keep` is accepted.\n */\nexport const DEFAULT_CONVERSATION_KEEP = 0\n\n/**\n * Names the framing label a {@link ConversationInterface}'s `view()` prefixes onto each compacted\n * section's summary so a small model reads it as a condensed recap of earlier turns — the lean\n * `'[Summary of earlier messages] '` marker, never a literal assistant turn to echo or treat as\n * the live answer.\n *\n * @remarks\n * Deliberately a fixed, lean handful of tokens (a short bracketed marker) so the framing adds a\n * bounded `prefix × sections` overhead and never an open-ended blow-up — the\n * {@link ConversationInterface} no-bloat test guard pins exactly that. Kept here (beside\n * {@link DEFAULT_CONVERSATION_KEEP}) as the conversation layer's one tunable framing constant, so\n * the wording has a single source of truth as it is optimized against real small-model behavior\n * (the `view()` recap framing is distinct from `reference()`'s cross-conversation provenance\n * marker, which is rendered inline since it interpolates the per-call provenance `label`).\n */\nexport const CONVERSATION_RECAP_PREFIX = '[Summary of earlier messages] '\n\n/**\n * Names the opening tag a {@link import('./ThinkSplitter.js').ThinkSplitter} recognizes as the start of\n * an in-content reasoning span — `'<think>'`, the de-facto wire convention thinking models\n * (qwen3, DeepSeek-R1 family) emit their chain-of-thought under when a daemon renders it inline\n * instead of on a separate wire field. Paired with {@link THINK_CLOSE}.\n */\nexport const THINK_OPEN = '<think>'\n\n/**\n * Names the closing tag that ends a {@link THINK_OPEN} reasoning span — `'</think>'`. A span the\n * stream never closes (the model was cut off mid-reasoning) is treated as thinking to its end,\n * and {@link import('./types.js').ThinkSplitterInterface.flush} settles it.\n */\nexport const THINK_CLOSE = '</think>'\n\n/**\n * Names the section header {@link import('./AgentContext.js').AgentContext}'s `build()` renders the\n * active workspace's text files under — `'## Workspace'`, the leading line of the dedicated\n * workspace block in the system message and the carrier-split counterpart to the documents and\n * images section headers.\n *\n * @remarks\n * `build()` owns the workspace render (a `Workspace` / `WorkspaceManager` stays file-focused — no\n * `open` / `format` getters), so this header lives here as the agents module's one\n * workspace-section framing constant rather than on a manager. Each workspace text file renders\n * beneath it as a fenced `` File: <path>\\n```<language>\\n<text>\\n``` `` block — the same framing\n * the documents section uses — placed immediately after the documents section in the system block.\n */\nexport const WORKSPACE_SECTION_HEADER = '## Workspace'\n\n/**\n * Estimates the per-message role and framing overhead {@link import('./helpers.js').estimateMessages}\n * adds on top of a message's content estimate — `4` tokens for the fixed wire framing every\n * conversation turn carries (its role tag, its delimiters) that\n * {@link import('./helpers.js').estimateTokens}'s content-only heuristic does not otherwise\n * capture.\n */\nexport const MESSAGE_TOKEN_OVERHEAD = 4\n\n/**\n * Names the coarse, deliberately approximate per-image token cost\n * {@link import('./helpers.js').estimateMessages} charges for each attached image — `512`, because\n * a base64 payload's length is no reliable token proxy.\n *\n * @remarks\n * A base64 image payload's length is not a reliable token proxy (a vision model's actual image\n * token cost depends on resolution / tiling, not byte size), so this is a fixed, coarse\n * per-image estimate rather than a derivation from `image.length` — a planning heuristic, not an\n * exact count.\n */\nexport const IMAGE_TOKEN_ESTIMATE = 512\n\n/**\n * Holds the default provider deadline in milliseconds — `120_000`, the wall-clock bound a call\n * runs under when `AgentProviderInput.timeout` is omitted, folded with the caller's signal so\n * whichever trips first cancels the call.\n */\nexport const DEFAULT_PROVIDER_TIMEOUT = 120_000\n\n/**\n * Bounds the decoded error excerpt's input in bytes — `2048`, the leading bytes of a non-OK\n * response body handed to the decoder before the read cancels the remainder, so a `ProviderError`\n * message never carries a longer excerpt.\n */\nexport const MAX_ERROR_BODY_LENGTH = 2048\n\n/**\n * Holds the default relay request limit in bytes — `1_048_576`, the byte budget a relay applies\n * to an inbound body when `RelayOptions.limit` is omitted, refusing a body that reaches it.\n */\nexport const DEFAULT_RELAY_LIMIT = 1_048_576\n\n/**\n * Names the relay's newline-delimited JSON content type — `'application/x-ndjson; charset=utf-8'`,\n * the header a relay response carries beside `cache-control: no-store`.\n */\nexport const RELAY_CONTENT_TYPE = 'application/x-ndjson; charset=utf-8'\n\n/**\n * Names the public message for an unexpected upstream relay failure — `'relay provider failed'`,\n * the fixed text every `error` frame carries, so an upstream failure's own message never reaches\n * the browser.\n */\nexport const RELAY_PROVIDER_MESSAGE = 'relay provider failed'\n\n/**\n * Names the status a relay answers when the `authorize` callback returns anything but `true` or throws —\n * `401`, carried with no body and reaching the browser as a `ProviderError` with the `HTTP` code.\n */\nexport const UNAUTHORIZED_RELAY_STATUS = 401\n\n/**\n * Names the status a relay answers when the upstream provider call cannot be constructed — `502`,\n * carried with no body after `provider.stream` was entered and threw before returning its\n * iterator.\n */\nexport const UPSTREAM_RELAY_STATUS = 502\n\n/**\n * Names the status a relay answers for a body that is missing, unreadable, or rejected by\n * `providerRequestContract` — `400`, carried with no body and reaching the browser as a\n * `ProviderError` with the `HTTP` code.\n */\nexport const INVALID_RELAY_STATUS = 400\n\n/**\n * Names the status a relay answers for a request body at or above its byte budget — `413`,\n * carried with no body and answered for an aborted inbound read as well.\n */\nexport const OVERSIZED_RELAY_STATUS = 413\n","import type {\n\tAgentResult,\n\tProviderErrorCode,\n\tProviderErrorOptions,\n\tProviderResult,\n} from './types.js'\nimport { isInstance } from '@orkestrel/contract'\n\n// A real error type, not a sentinel. `stream` throws a\n// ProviderAbortError when its bound signal aborts mid-flight, carrying the partial\n// result it had assembled so far so the agent loop can recover the streamed content\n// on cancellation. The guard narrows a caught value with `instanceof`.\n\n/**\n * Reports a provider stream cancelled mid-flight by its bound signal — thrown by a\n * {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled from\n * whatever streamed before the cancel and the machine-readable `code` `'ABORT'`.\n *\n * @remarks\n * Lets a caller recover the partial content (and any tool calls / usage seen so far)\n * on cancellation: `catch` the throw, narrow with {@link isProviderAbortError}, and\n * read `partial`. `code` is the machine-readable condition (`'ABORT'` — the only one this\n * error reports), so a `catch` branches on it rather than on the message string. `cause`\n * holds the failure the cancel superseded when a throw raced the abort — the wire decoder's\n * {@link ProviderError}, say — and is undefined when the cancel was the only failure.\n */\nexport class ProviderAbortError extends Error {\n\t/** Names the machine-readable condition — `'ABORT'`: a stream cancelled mid-flight. */\n\treadonly code = 'ABORT' as const\n\treadonly partial: ProviderResult\n\n\tconstructor(partial: ProviderResult, options?: ErrorOptions) {\n\t\tsuper('provider stream aborted', options)\n\t\tthis.name = 'ProviderAbortError'\n\t\tthis.partial = partial\n\t}\n}\n\n/**\n * Narrows an unknown caught value to a {@link ProviderAbortError} through `instanceof`, so a\n * `catch` can recover its `partial` result.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns True if `value` is a {@link ProviderAbortError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tfor await (const delta of provider.stream(messages, signal)) render(delta)\n * } catch (error) {\n * \tif (isProviderAbortError(error)) keep(error.partial.content) // recover partial\n * }\n * ```\n */\nexport function isProviderAbortError(value: unknown): value is ProviderAbortError {\n\treturn isInstance(value, ProviderAbortError)\n}\n\n// A real error type, not a sentinel. An agent job treats a partial result\n// (a job committed early from an abort / budget / timeout) as a failure by default — the\n// queue / runner handler throws this so the Queue's retries + a Runner's fail-fast\n// engage. It carries the partial AgentResult so a caller (or a `retries: 0` enqueue that\n// rejects with it) can still inspect what accumulated. The guard narrows with\n// `instanceof`, mirroring ProviderAbortError / isProviderAbortError above.\n\n/**\n * Reports an {@link AgentInterface} run that ended {@link AgentResult.partial} under a\n * `partial` policy of `false` (the default) — thrown by an agent-job handler (a\n * `createAgentQueue` / `createAgentRunner` job), carrying the partial {@link AgentResult} so\n * the failure stays inspectable, and the machine-readable `code` `'PARTIAL'`.\n *\n * @remarks\n * A partial result means the agent was cancelled (an external `signal` abort, a queue /\n * runner abort threaded in, a `timeout` deadline, or an exhausted token `budget`) rather\n * than finishing naturally. For a durable job that is a failure by default: throwing this\n * lets the Queue's retries re-run the job and a Runner's fail-fast abort its siblings.\n * Set `partial: true` (see `AgentQueueOptions` / `AgentRunnerOptions`) to treat a\n * partial as success instead, in which case this is never thrown. Narrow a caught value\n * with {@link isAgentJobError} to read `partial`. `code` is the machine-readable condition\n * (`'PARTIAL'` — the only one this error reports), so a `catch` branches on it rather than on\n * the message string.\n */\nexport class AgentJobError extends Error {\n\t/** Names the machine-readable condition — `'PARTIAL'`: a job that ended partial under a disallowing policy. */\n\treadonly code = 'PARTIAL' as const\n\t/** Holds the partial {@link AgentResult} the cancelled job produced. */\n\treadonly partial: AgentResult\n\n\tconstructor(message: string, partial: AgentResult) {\n\t\tsuper(message)\n\t\tthis.name = 'AgentJobError'\n\t\tthis.partial = partial\n\t}\n}\n\n/**\n * Narrows an unknown caught value to an {@link AgentJobError} through `instanceof`, so a\n * `catch` can recover its `partial` result.\n *\n * @param value - The value to test (typically a `catch` binding or a rejected enqueue)\n * @returns True if `value` is an {@link AgentJobError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tawait queue.enqueue(job) // retries: 0 → a partial rejects with the error\n * } catch (error) {\n * \tif (isAgentJobError(error)) keep(error.partial.content) // recover the partial content\n * }\n * ```\n */\nexport function isAgentJobError(value: unknown): value is AgentJobError {\n\treturn isInstance(value, AgentJobError)\n}\n\n// A real error type, not a sentinel. A `ConversationInterface.compact()` is a\n// programmer error when no `ConversationSummaryHandler` was supplied — there is nothing to fold\n// the messages with — so it throws this, carrying a machine-readable `code` ('SUMMARIZER')\n// so a `catch` branches on `error.code` instead of parsing the message. The guard narrows a\n// caught value with `instanceof`, mirroring the other errors in this file.\n\n/**\n * Reports a conversation with no {@link ConversationSummaryHandler} to fold its messages with,\n * or with a `sections` cap below `1` — thrown by a {@link ConversationInterface}'s `compact()`\n * or its construction, carrying the machine-readable `code`\n * `'SUMMARIZER' | 'SECTIONS'`.\n *\n * @remarks\n * Compaction requires a summarizer (it digests the folded slice into a section summary and\n * regenerates the rollup); a conversation created without one can still store + `view()` its\n * live tail, but a `compact()` is a programmer error and throws this with `'SUMMARIZER'`.\n * A `sections` cap (on {@link import('./types.js').ConversationOptions} /\n * {@link import('./types.js').ConversationManagerOptions} /\n * {@link import('./types.js').CompactOptions}) must be `>= 1` — a sub-1 cap is a programmer\n * error and throws this with `'SECTIONS'`. Narrow a caught value with\n * {@link isConversationError} and branch on `error.code`.\n */\nexport class ConversationError extends Error {\n\t/** Names the machine-readable condition — `'SUMMARIZER'`: a `compact()` with no summarizer; `'SECTIONS'`: a sub-1 `sections` cap. */\n\treadonly code: 'SUMMARIZER' | 'SECTIONS'\n\n\tconstructor(code: 'SUMMARIZER' | 'SECTIONS', message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'ConversationError'\n\t\tthis.code = code\n\t}\n}\n\n/**\n * Narrows an unknown caught value to a {@link ConversationError} through `instanceof`, so a\n * `catch` can branch on its `code`.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns True if `value` is a {@link ConversationError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tawait conversation.compact()\n * } catch (error) {\n * \tif (isConversationError(error) && error.code === 'SUMMARIZER') addSummarizer()\n * }\n * ```\n */\nexport function isConversationError(value: unknown): value is ConversationError {\n\treturn isInstance(value, ConversationError)\n}\n\n// A real error type, not a sentinel. Concurrent runs on one Agent whose\n// construction carries a shared accounting instance (a `window` context budget, or a\n// construction-level `budget` with no per-run override) would corrupt that shared\n// accounting — so `stream()` throws this synchronously, before any state mutation or\n// emit, rather than letting the runs race. An `AgentRegistry` accessor throws it too, when a\n// rehydration name is absent from its pool. Carries a machine-readable `code` so a `catch`\n// branches on `error.code`, mirroring `ConversationError` above.\n\n/**\n * Reports a concurrent run that would corrupt shared per-agent accounting, or a rehydration\n * name absent from its registry pool — thrown synchronously by an {@link AgentInterface}'s\n * `stream()` (and so by `generate()`, which calls it) and by an\n * {@link AgentRegistryInterface}'s accessors, carrying the machine-readable `code`\n * `'CONCURRENCY' | 'REGISTRY'`. Synchronous means a fire-and-forget\n * `agent.generate().catch(…)` never catches it: `await` the call inside `try`/`catch`, or wrap\n * the call expression itself.\n *\n * @remarks\n * `'CONCURRENCY'` reports a run already in flight on the same agent, plus a construction-level\n * `window` (a shared context budget) or a construction-level `budget` with no per-run override\n * (a shared cost budget) — a second concurrent `stream()` would race its charges against the\n * same shared instance, corrupting the accounting. Use separate agents, or per-run `budget`\n * overrides with no `window`, for genuinely concurrent runs. `'REGISTRY'` reports a rehydration\n * name absent from its registry pool, on `provider` / `tool` / `authority` / `scheduler` /\n * `build`. Narrow a caught value with {@link isAgentError} and branch on `error.code`.\n */\nexport class AgentError extends Error {\n\t/** Names the machine-readable condition — `'CONCURRENCY'`: a concurrent run on a shared accounting agent; `'REGISTRY'`: a rehydration name absent from its registry pool. */\n\treadonly code: 'CONCURRENCY' | 'REGISTRY'\n\n\tconstructor(code: 'CONCURRENCY' | 'REGISTRY', message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'AgentError'\n\t\tthis.code = code\n\t}\n}\n\n/**\n * Narrows an unknown caught value to an {@link AgentError} through `instanceof`, so a `catch`\n * can branch on its `code`.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns True if `value` is an {@link AgentError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tagent.stream()\n * } catch (error) {\n * \tif (isAgentError(error) && error.code === 'CONCURRENCY') useSeparateAgents()\n * }\n * ```\n */\nexport function isAgentError(value: unknown): value is AgentError {\n\treturn isInstance(value, AgentError)\n}\n\n/**\n * Reports a coded provider failure with its HTTP status and underlying cause when available.\n *\n * @remarks\n * The provider base throws this error for a non-OK HTTP response, a missing response\n * body, or a missing settled result when strict assembly is enabled. Concrete wire\n * decoders also use it for malformed records and relayed provider failures.\n * `status` is present only for an `HTTP` failure; other codes leave it undefined.\n */\nexport class ProviderError extends Error {\n\t/** Names the machine-readable condition — `'HTTP'`: a non-OK response, including a relay refusing an oversized request with 413; `'PROTOCOL'`: a missing response body, a malformed wire record, or a strict stream with no settled result; `'PROVIDER'`: an upstream failure carried by a relay error record. */\n\treadonly code: ProviderErrorCode\n\t/** Holds the response status for an HTTP failure, or undefined for other codes. */\n\treadonly status: number | undefined\n\n\tconstructor(code: ProviderErrorCode, message: string, options?: ProviderErrorOptions) {\n\t\tsuper(message, options)\n\t\tthis.name = 'ProviderError'\n\t\tthis.code = code\n\t\tthis.status = options?.status\n\t}\n}\n\n/**\n * Narrows a caught value to the provider failure class through instanceof.\n *\n * @param value - The caught value\n * @returns True if the value is a provider failure; false otherwise\n * @example\n * ```ts\n * isProviderError(new ProviderError('HTTP', 'unavailable', { status: 503 })) // true\n * ```\n */\nexport function isProviderError(value: unknown): value is ProviderError {\n\treturn isInstance(value, ProviderError)\n}\n","import type { ContractShape } from '@orkestrel/contract'\nimport {\n\tarrayShape,\n\tbooleanShape,\n\tjsonShape,\n\tliteralShape,\n\tnumberShape,\n\tobjectShape,\n\toptionalShape,\n\trecordShape,\n\tstringShape,\n\tunionShape,\n} from '@orkestrel/contract'\n\n/**\n * Describes a tool call's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than the domain: non-JSON arguments are refused.\n * Calls carry only id, name, and arguments; execution context stays local.\n * The guard refuses every extra member; the contract parser drops extra members.\n */\nexport const toolCallShape = objectShape({\n\tid: stringShape(),\n\tname: stringShape(),\n\targuments: recordShape(jsonShape()),\n}) satisfies ContractShape\n\n/**\n * Describes a conversation message's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than Message: non-JSON call arguments are refused,\n * and execution context stays local. The guard refuses extra members; the parser drops them.\n */\nexport const messageShape = objectShape({\n\tid: stringShape(),\n\trole: literalShape(['system', 'user', 'assistant', 'tool']),\n\tcontent: stringShape(),\n\tcalls: optionalShape(arrayShape(toolCallShape)),\n\timages: optionalShape(arrayShape(stringShape())),\n}) satisfies ContractShape\n\n/**\n * Describes a provider request's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than ProviderRequest: non-JSON arguments, parameters,\n * or schema members are refused. Execution context stays local; the guard refuses\n * extra members, and the parser drops them.\n */\nexport const providerRequestShape = objectShape({\n\tmessages: arrayShape(messageShape),\n\ttools: optionalShape(\n\t\tarrayShape(\n\t\t\tobjectShape({\n\t\t\t\tname: stringShape(),\n\t\t\t\tdescription: optionalShape(stringShape()),\n\t\t\t\tparameters: optionalShape(recordShape(jsonShape())),\n\t\t\t}),\n\t\t),\n\t),\n\toptions: optionalShape(\n\t\tobjectShape({\n\t\t\tthink: optionalShape(booleanShape()),\n\t\t\tschema: optionalShape(recordShape(jsonShape())),\n\t\t}),\n\t),\n}) satisfies ContractShape\n\n/**\n * Describes a provider result's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than ProviderResult: non-JSON call arguments are\n * refused. Execution context stays local; the guard refuses extra members, and the parser drops them.\n */\nexport const providerResultShape = objectShape({\n\tcontent: stringShape(),\n\tthinking: optionalShape(stringShape()),\n\ttools: optionalShape(arrayShape(toolCallShape)),\n\tusage: optionalShape(\n\t\tobjectShape({\n\t\t\tprompt: numberShape(),\n\t\t\tcompletion: numberShape(),\n\t\t\ttotal: numberShape(),\n\t\t}),\n\t),\n}) satisfies ContractShape\n\n/**\n * Describes the channel-discriminated JSON relay wire projection.\n *\n * @remarks\n * The wire is strictly narrower than RelayFrame through its result and partial\n * fields: non-JSON arguments are refused. Execution context stays local; the guard\n * refuses extra members, and the parser drops them.\n */\nexport const relayFrameShape = unionShape(\n\tobjectShape({ channel: literalShape(['content', 'thinking']), text: stringShape() }),\n\tobjectShape({ channel: literalShape(['result']), result: providerResultShape }),\n\tobjectShape({ channel: literalShape(['abort']), partial: providerResultShape }),\n\tobjectShape({ channel: literalShape(['error']), message: stringShape() }),\n) satisfies ContractShape\n","import { createContract } from '@orkestrel/contract'\nimport {\n\tmessageShape,\n\tproviderRequestShape,\n\tproviderResultShape,\n\trelayFrameShape,\n} from './shapers.js'\n\n/** Validates and projects conversation messages at a JSON wire boundary. */\nexport const messageContract = createContract(messageShape)\n\n/** Validates and projects provider requests at a JSON wire boundary. */\nexport const providerRequestContract = createContract(providerRequestShape)\n\n/** Validates and projects provider results at a JSON wire boundary. */\nexport const providerResultContract = createContract(providerResultShape)\n\n/** Validates and projects channel-discriminated relay frames at a JSON wire boundary. */\nexport const relayFrameContract = createContract(relayFrameShape)\n","import type {\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentRegistryInterface,\n\tAgentResult,\n\tContextSectionFormat,\n\tContextSectionSourceInterface,\n\tMessage,\n\tProviderResult,\n\tRunOutcome,\n\tSection,\n\tTextRead,\n} from './types.js'\nimport type { TokenUsage } from '@orkestrel/budget'\nimport type { JSONValue } from '@orkestrel/contract'\nimport type { QueueContext } from '@orkestrel/queue'\nimport type { ToolCall, ToolResult } from '@orkestrel/tool'\nimport type { ControllerInterface } from '@orkestrel/workflow'\nimport type { FileInterface } from '@orkestrel/workspace'\nimport {\n\tattempt,\n\tisBoolean,\n\tisFiniteNumber,\n\tisObject,\n\tisString,\n\tparseJSONValue,\n} from '@orkestrel/contract'\nimport { isBinary } from '@orkestrel/workspace'\nimport {\n\tCONVERSATION_RECAP_PREFIX,\n\tIMAGE_TOKEN_ESTIMATE,\n\tMESSAGE_TOKEN_OVERHEAD,\n} from './constants.js'\nimport { AgentJobError } from './errors.js'\n\n/**\n * Projects an unknown value onto a fresh, exact `JSONValue` representation of an\n * {@link AgentResult} — capturing each structural field once through a total boundary,\n * accepting conforming accessors and inherited properties, preserving finite negative and\n * fractional usage counts, dropping extras, and resolving `undefined` for a malformed field, a\n * non-finite usage number, a throwing getter, or a hostile or revoked proxy.\n *\n * @remarks\n * This is a total hostile-boundary projection. Each structural field is captured once\n * through Contract's sanctioned exception boundary, so conforming accessors and inherited\n * properties are supported while a throwing getter or revoked proxy returns `undefined`.\n * Present usage counts must be finite numbers; negative and fractional values are preserved,\n * not normalized. Extra input properties are dropped while a fresh exact plain object is rebuilt\n * and deep-gated through\n * {@link import('@orkestrel/contract').parseJSONValue}.\n *\n * @param value - The unknown value to project\n * @returns A fresh JSON value containing only AgentResult fields, or `undefined` when invalid\n *\n * @example\n * ```ts\n * import { agentResultToJSON } from '@orkestrel/agent'\n *\n * agentResultToJSON({ content: 'done', usage: { prompt: 2, completion: 1, total: 3 }, partial: false })\n * // { content: 'done', usage: { prompt: 2, completion: 1, total: 3 }, partial: false }\n * ```\n */\nexport function agentResultToJSON(value: unknown): JSONValue | undefined {\n\tconst captured = attempt(() => {\n\t\tif (!isObject(value)) return undefined\n\n\t\tconst content = Reflect.get(value, 'content')\n\t\tconst thinking = Reflect.get(value, 'thinking')\n\t\tconst usage = Reflect.get(value, 'usage')\n\t\tconst partial = Reflect.get(value, 'partial')\n\t\tif (!isString(content) || !isBoolean(partial)) return undefined\n\t\tif (thinking !== undefined && !isString(thinking)) return undefined\n\n\t\tlet projectedUsage: TokenUsage | undefined\n\t\tif (usage !== undefined) {\n\t\t\tif (!isObject(usage)) return undefined\n\t\t\tconst prompt = Reflect.get(usage, 'prompt')\n\t\t\tconst completion = Reflect.get(usage, 'completion')\n\t\t\tconst total = Reflect.get(usage, 'total')\n\t\t\tif (!isFiniteNumber(prompt) || !isFiniteNumber(completion) || !isFiniteNumber(total)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tprojectedUsage = { prompt, completion, total }\n\t\t}\n\n\t\treturn {\n\t\t\tcontent,\n\t\t\t...(thinking === undefined ? {} : { thinking }),\n\t\t\t...(projectedUsage === undefined ? {} : { usage: projectedUsage }),\n\t\t\tpartial,\n\t\t}\n\t})\n\n\treturn captured.success ? parseJSONValue(captured.value) : undefined\n}\n\n/**\n * Filters a list of items by a {@link import('./types.js').ScopeInterface} allow-list of keys —\n * `undefined` passes everything, `[]` passes nothing, and a non-empty list passes the listed keys\n * alone, order preserved. The pure, total set-membership primitive the context's build step and\n * the agent loop's tool-advertise step apply a scope through.\n *\n * @remarks\n * Three-way by the allow-list's shape, so a `Scope` category cleanly expresses \"all /\n * none / only these\":\n * - `undefined` ⇒ no constraint — every item passes (returned unchanged).\n * - `[]` (empty) ⇒ none pass (no key is in an empty set).\n * - a non-empty list ⇒ only items whose `key(item)` is in the list pass.\n *\n * Order-preserving (it filters `items` in place order, never reorders) and total — never\n * throws. Keys are matched by a `Set` for O(1) membership, so a large list is cheap.\n *\n * @typeParam T - The item type being filtered\n * @param allow - The allow-list of keys (`undefined` ⇒ all, `[]` ⇒ none, else only-listed)\n * @param items - The items to filter (returned unchanged when `allow` is `undefined`)\n * @param key - Extracts the key an item is matched on (for example an instruction's `name`)\n * @returns The items that pass the allow-list, in their original order\n *\n * @example\n * ```ts\n * const items = [{ name: 'a' }, { name: 'b' }]\n * filterAllowList(undefined, items, (i) => i.name) // [{ name: 'a' }, { name: 'b' }] (all)\n * filterAllowList([], items, (i) => i.name) // [] (none)\n * filterAllowList(['b'], items, (i) => i.name) // [{ name: 'b' }] (only listed)\n * ```\n */\nexport function filterAllowList<T>(\n\tallow: readonly string[] | undefined,\n\titems: readonly T[],\n\tkey: (item: T) => string,\n): readonly T[] {\n\tif (allow === undefined) return items\n\tif (allow.length === 0) return []\n\tconst set = new Set(allow)\n\treturn items.filter((item) => set.has(key(item)))\n}\n\n/**\n * Estimates the context-token footprint of a string — the deterministic `ceil(length / 4)`\n * character heuristic {@link estimateMessages} sums over a conversation's messages (the default\n * context-budget estimator).\n *\n * @remarks\n * Approximates `ceil(length / 4)` (≈ four characters per token — the rough average for\n * English text), so the same input always yields the same estimate (no model round-trip).\n * Empty text is `0`. This is a planning heuristic for reasoning about how much a turn's\n * messages cost the next request, not an exact tokenizer count — it never calls a provider,\n * so the agent layer stays provider-agnostic and synchronous where it can be.\n *\n * @param text - The text to estimate (a section summary, a message's content)\n * @returns The estimated token count (`ceil(text.length / 4)`; `0` for empty text)\n *\n * @example\n * ```ts\n * estimateTokens('') // 0\n * estimateTokens('hello') // 2 (ceil(5 / 4))\n * estimateTokens('a'.repeat(40)) // 10\n * ```\n */\nexport function estimateTokens(text: string): number {\n\treturn Math.ceil(text.length / 4)\n}\n\n/**\n * Estimates the context-token footprint of a batch of messages — each message's content plus\n * {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD}, a tool-call JSON estimate, and\n * {@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} for each attached image. The default\n * `consumer` estimator for an agent's context budget (the\n * {@link import('./types.js').AgentOptions} `window`), total and never throwing, and a\n * deliberate provider-agnostic approximation rather than an exact tokenizer count.\n *\n * @remarks\n * Sums, per message, {@link estimateTokens} over its `content` (the `ceil(length / 4)` char\n * heuristic) plus {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (a fixed per-message\n * role/framing overhead) plus, when present, {@link estimateTokens} over its JSON-stringified\n * `calls` plus `images.length * `{@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} (a coarse,\n * deliberately-approximate per-image cost — a base64 length is not a token proxy). Deterministic\n * and provider-free — the same messages always yield the same estimate, with an empty batch `0`.\n * It is the fully-swappable default an agent's auto-compaction context budget charges each\n * turn's new messages through; a caller wanting a sharper count supplies its own `consumer` to\n * `createBudget` instead. Total — never throws: a `calls` `JSON.stringify` that throws (a\n * circular `ToolCall.arguments`) is caught and replaced with a conservative fixed contribution of\n * {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (the same per-message overhead scale)\n * instead of estimating the (unreachable) serialized length.\n *\n * @param messages - The messages to estimate (a turn's appended assistant + tool messages)\n * @returns The summed estimated token count (`0` when empty)\n *\n * @example\n * ```ts\n * estimateMessages([]) // 0\n * estimateMessages([{ id: '1', role: 'user', content: 'hello' }]) // 6 (2 content + 4 overhead)\n * ```\n */\nexport function estimateMessages(messages: readonly Message[]): number {\n\treturn messages.reduce((sum, message) => {\n\t\tconst content = estimateTokens(message.content) + MESSAGE_TOKEN_OVERHEAD\n\t\tlet calls = 0\n\t\tif (message.calls?.length) {\n\t\t\t// `JSON.stringify` over `ToolCall.arguments` can throw (a circular reference) even\n\t\t\t// though this function promises never to throw — so the serialization is wrapped; a\n\t\t\t// throw falls back to a conservative fixed contribution (the same per-message overhead\n\t\t\t// scale) instead of an unreachable serialized-length estimate. The happy path (no\n\t\t\t// throw) is byte-identical to the bare estimate below.\n\t\t\ttry {\n\t\t\t\tcalls = estimateTokens(JSON.stringify(message.calls))\n\t\t\t} catch {\n\t\t\t\tcalls = MESSAGE_TOKEN_OVERHEAD\n\t\t\t}\n\t\t}\n\t\tconst images = (message.images?.length ?? 0) * IMAGE_TOKEN_ESTIMATE\n\t\treturn sum + content + calls + images\n\t}, 0)\n}\n\n/**\n * Runs one rehydrated agent and applies the partial-as-configurable-failure policy — a partial\n * run throws an {@link import('./errors.js').AgentJobError} unless the `partial` policy allows\n * it, and a natural finish resolves. The shared job-handler step `createAgentQueue` and\n * `createAgentRunner` both settle each job through, so the policy can never diverge between\n * them.\n *\n * @remarks\n * A turn that committed partial (a cancel — abort / budget / timeout) is by default a\n * failure, so it throws an {@link import('./errors.js').AgentJobError} carrying the partial\n * (the Queue's retries + a Runner's fail-fast then engage); the `partial` policy resolves\n * it as success instead. A natural finish always resolves with its result.\n *\n * @param agent - The rehydrated {@link AgentInterface} to run to its {@link AgentResult}\n * @param partial - The partial policy. If `true`, a partial result resolves as success; if\n * `false` (the default policy), a partial result throws an {@link AgentJobError}\n * @returns The agent's {@link AgentResult} (a natural finish, or a partial one under the\n * `partial` policy)\n * @throws {AgentJobError} Thrown when the run ended partial and the `partial` policy is `false`\n *\n * @example\n * ```ts\n * const result = await settleAgentJob(registry.build(input, signal), false)\n * ```\n */\nexport async function settleAgentJob(\n\tagent: AgentInterface,\n\tpartial: boolean,\n): Promise<AgentResult> {\n\tconst result = await agent.generate()\n\tif (result.partial && !partial) throw new AgentJobError('agent job ended partial', result)\n\treturn result\n}\n\n/**\n * Handles one queued agent job by rehydrating it through a registry with the queue\n * attempt's signal, then applying the shared partial-result policy.\n *\n * @param registry - The registry that rehydrates the serializable job\n * @param partial - The partial policy. If `true`, a partial result resolves; if `false`, it throws\n * @param input - The serializable agent job\n * @param context - The queue attempt whose signal bounds the agent\n * @returns The settled agent result\n */\nexport function handleAgentQueueJob(\n\tregistry: AgentRegistryInterface,\n\tpartial: boolean,\n\tinput: AgentJobInput,\n\tcontext: QueueContext,\n): Promise<AgentResult> {\n\treturn settleAgentJob(registry.build(input, context.signal), partial)\n}\n\n/**\n * Handles one runner agent job by fanning out its declared children, rehydrating the\n * parent through a registry with the controller signal, and applying the shared\n * partial-result policy.\n *\n * @remarks\n * Children are fired and tracked through the runner controller without awaiting them\n * inline, preserving bounded-runner progress.\n *\n * @param registry - The registry that rehydrates serializable jobs\n * @param partial - The partial policy. If `true`, a partial result resolves; if `false`, it throws\n * @param controller - The runner controller for this parent job\n * @returns The settled parent agent result\n */\nexport function handleAgentRunnerJob(\n\tregistry: AgentRegistryInterface,\n\tpartial: boolean,\n\tcontroller: ControllerInterface<AgentJobInput, AgentResult>,\n): Promise<AgentResult> {\n\tconst children = controller.input.children\n\tif (children !== undefined) for (const child of children) void controller.spawn(child)\n\treturn settleAgentJob(registry.build(controller.input, controller.signal), partial)\n}\n\n/**\n * Renders a path-addressed text body as a fenced reference block — a `File: <path>` label line\n * over a language-tagged fence, the framing an\n * {@link import('./AgentContext.js').AgentContext}'s active-workspace text-file render emits.\n *\n * @remarks\n * Produces `` File: <path>\\n```<language>\\n<content>\\n``` `` — the `File:` label line, then a\n * fenced code block tagged with `language`, the `content` verbatim inside. Pure string assembly,\n * total — never throws. The one fenced-file format string for the whole module — `AgentContext.build()`\n * frames an active workspace's text files with it (each carries its own `language` on its\n * {@link import('@orkestrel/workspace').FileContent} text arm).\n *\n * @param path - The file path shown on the `File:` label line\n * @param language - The fenced-code language tag (for example `'typescript'`)\n * @param content - The file body rendered verbatim inside the fence\n * @returns The fenced reference block\n *\n * @example\n * ```ts\n * import { renderFencedFile } from '@orkestrel/agent'\n *\n * renderFencedFile('src/main.ts', 'typescript', 'const x = 1')\n * // 'File: src/main.ts\\n```typescript\\nconst x = 1\\n```'\n * ```\n */\nexport function renderFencedFile(path: string, language: string, content: string): string {\n\treturn `File: ${path}\\n\\`\\`\\`${language}\\n${content}\\n\\`\\`\\``\n}\n\n/**\n * Sanitizes one reported token count into a safe non-negative integer — a non-finite or\n * non-positive value becomes `0`, and a positive fractional value floors down.\n *\n * @param value - The token count to sanitize\n * @returns The floored count, or `0` when the value is non-finite or non-positive\n */\nexport function sanitizeToken(value: number): number {\n\treturn isFiniteNumber(value) && value > 0 ? Math.floor(value) : 0\n}\n\n/**\n * Sanitizes a {@link TokenUsage} into safe, non-negative integers — the guard an agent's\n * abort-usage path applies to a provider's partial usage before it is charged against a\n * budget or folded into the run total.\n *\n * @remarks\n * Per field (`prompt` / `completion` / `total`): a non-finite value (`NaN`, `+Infinity`,\n * `-Infinity`) or a negative value floors to `0`; a fractional value floors to its\n * non-negative integer part. No upper cap is applied. Total — never throws.\n *\n * @param usage - The token usage to sanitize (for example a provider's abort-partial usage)\n * @returns A new {@link TokenUsage} with every field a safe non-negative integer\n *\n * @example\n * ```ts\n * sanitizeUsage({ prompt: -5, completion: NaN, total: 12.7 }) // { prompt: 0, completion: 0, total: 12 }\n * ```\n */\nexport function sanitizeUsage(usage: TokenUsage): TokenUsage {\n\treturn {\n\t\tprompt: sanitizeToken(usage.prompt),\n\t\tcompletion: sanitizeToken(usage.completion),\n\t\ttotal: sanitizeToken(usage.total),\n\t}\n}\n\n/**\n * Joins the reasoning a run's provider calls separated from the answer — the first call\n * seeds the accumulation, a later call appends blank-line separated so each turn's reasoning\n * stays readable.\n *\n * @remarks\n * Pure and total. `running` is `undefined` until a call surfaces reasoning, so the first join\n * returns `next` verbatim (no leading separator). The result is display/audit metadata that\n * never re-enters the conversation.\n *\n * @param running - The reasoning accumulated so far (`undefined` before the first)\n * @param next - This call's separated reasoning\n * @returns The joined reasoning\n *\n * @example\n * ```ts\n * joinThinking(undefined, 'first') // 'first'\n * joinThinking('', 'x') // 'x'\n * joinThinking('first', 'second') // 'first\\n\\nsecond'\n * ```\n */\nexport function joinThinking(running: string | undefined, next: string): string {\n\tif (running === undefined || running.length === 0) return next\n\treturn next.length === 0 ? running : `${running}\\n\\n${next}`\n}\n\n/**\n * Adds two {@link TokenUsage} values field by field — the running total an agent run keeps\n * across its provider calls.\n *\n * @remarks\n * Pure and total: the first call seeds the total (`running` `undefined` returns `next`\n * unchanged), later calls accumulate. No sanitization happens here — charge a provider's\n * reported usage through {@link sanitizeUsage} first.\n *\n * @param running - The total so far (`undefined` before the first usage-bearing call)\n * @param next - This call's reported usage\n * @returns The summed usage\n *\n * @example\n * ```ts\n * sumUsage(undefined, { prompt: 2, completion: 1, total: 3 }) // { prompt: 2, completion: 1, total: 3 }\n * sumUsage({ prompt: 2, completion: 1, total: 3 }, { prompt: 1, completion: 1, total: 2 })\n * // { prompt: 3, completion: 2, total: 5 }\n * ```\n */\nexport function sumUsage(running: TokenUsage | undefined, next: TokenUsage): TokenUsage {\n\tif (running === undefined) return next\n\treturn {\n\t\tprompt: running.prompt + next.prompt,\n\t\tcompletion: running.completion + next.completion,\n\t\ttotal: running.total + next.total,\n\t}\n}\n\n/**\n * Assembles the settled {@link AgentResult} from a run's {@link RunOutcome} — `thinking` and\n * `usage` are carried only when the run surfaced them, and the loop-internal `exhausted` flag is\n * left out.\n *\n * @remarks\n * Pure and total. An absent optional is omitted rather than stored as `undefined` (the\n * present-when-given convention the message store follows), so a settled result JSON\n * round-trips without an explicit `undefined` field. `exhausted` is loop bookkeeping and does\n * not reach the public result — the `exhaust` event carries it instead.\n *\n * @param outcome - The run's settled outcome\n * @returns The public {@link AgentResult}\n *\n * @example\n * ```ts\n * assembleResult({ content: 'hi', thinking: undefined, usage: undefined, partial: false, exhausted: false })\n * // { content: 'hi', partial: false }\n * ```\n */\nexport function assembleResult(outcome: RunOutcome): AgentResult {\n\tconst result: { content: string; thinking?: string; usage?: TokenUsage; partial: boolean } = {\n\t\tcontent: outcome.content,\n\t\tpartial: outcome.partial,\n\t}\n\tif (outcome.thinking !== undefined) result.thinking = outcome.thinking\n\tif (outcome.usage !== undefined) result.usage = outcome.usage\n\treturn result\n}\n\n/**\n * Synthesizes the denial {@link ToolResult} an authority-blocked call is fed back with — the\n * call's `id` / `name` keyed back, carrying a denial `error` instead of a value.\n *\n * @remarks\n * Pure and total. The rule's `reason` is rendered as `denied: <reason>` when one was given,\n * else the generic `denied by authority`. There is no `value`, so the agent loop feeds it back\n * exactly like a tool error and the model can react to it.\n *\n * @param call - The denied {@link ToolCall}\n * @param reason - The rule's explanation, or `undefined` for the generic denial\n * @returns The failure-arm {@link ToolResult}\n *\n * @example\n * ```ts\n * denyCall({ id: '1', name: 'drop', arguments: {} }, 'read-only mode')\n * // { success: false, id: '1', name: 'drop', error: 'denied: read-only mode' }\n * ```\n */\nexport function denyCall(call: ToolCall, reason: string | undefined): ToolResult {\n\treturn {\n\t\tsuccess: false,\n\t\tid: call.id,\n\t\tname: call.name,\n\t\terror: reason !== undefined ? `denied: ${reason}` : 'denied by authority',\n\t}\n}\n\n/**\n * Renders one context section — the resolved `open`, each item's rendering, and the resolved\n * `close` when one exists, blank-line joined; `undefined` when the section has no items.\n *\n * @remarks\n * Pure and total. A section with no items renders nothing (`undefined`), so an empty or fully\n * scoped-out manager stays silent — its `open` / `close` never appear without items. `close`\n * is the only optional slot: an unset one (there is no built-in close) drops the\n * trailing line.\n *\n * @typeParam T - The section item being rendered\n * @param open - The section's resolved leading text\n * @param items - The already scope-filtered items\n * @param render - Renders one item to its prompt text\n * @param close - The section's resolved trailing text, or `undefined` for none\n * @returns The rendered section, or `undefined` when there are no items\n *\n * @example\n * ```ts\n * renderSection('## Instructions', [{ content: 'Be terse.' }], (one) => one.content, undefined)\n * // '## Instructions\\n\\nBe terse.'\n * renderSection('<rules>', [], (one) => one.content, '</rules>') // undefined (no items)\n * ```\n */\nexport function renderSection<T>(\n\topen: string,\n\titems: readonly T[],\n\trender: (item: T) => string,\n\tclose: string | undefined,\n): string | undefined {\n\tif (items.length === 0) return undefined\n\tconst lines = [open, ...items.map(render)]\n\tif (close !== undefined) lines.push(close)\n\treturn lines.join('\\n\\n')\n}\n\n/**\n * Resolves one section's open text through the format cascade — manager-options override >\n * provider default > built-in header.\n *\n * @remarks\n * Pure and total. The leading text has no per-item level. A manager's `open` already\n * encapsulates `[options-override → built-in]`, so it is reached only when neither the\n * override's `open` nor the provider's `open` applies — and there it is the built-in header.\n *\n * @typeParam T - The section item the manager renders\n * @param manager - The section source (its `format` override + its built-in `open`)\n * @param provider - The provider-default framing for this section, or `undefined`\n * @returns The section's leading text\n *\n * @example\n * ```ts\n * resolveOpen(instructions, undefined) // '## Instructions' (the built-in header)\n * resolveOpen(instructions, { open: '<rules>' }) // '<rules>' (the provider default)\n * ```\n */\nexport function resolveOpen<T>(\n\tmanager: ContextSectionSourceInterface<T>,\n\tprovider: ContextSectionFormat<T> | undefined,\n): string {\n\treturn manager.format?.open ?? provider?.open ?? manager.open\n}\n\n/**\n * Resolves one section's close text through the format cascade — manager-options override >\n * provider default; `undefined` when neither sets one, because there is no built-in close.\n *\n * @remarks\n * Pure and total. There is no built-in close, so a section with neither level set returns\n * `undefined` and {@link renderSection} appends no closing line. Paired with\n * {@link resolveOpen}, one level can wrap the whole group.\n *\n * @typeParam T - The section item the manager renders\n * @param manager - The section source (its `format` override)\n * @param provider - The provider-default framing for this section, or `undefined`\n * @returns The section's trailing text, or `undefined` when no level sets one\n *\n * @example\n * ```ts\n * resolveClose(instructions, undefined) // undefined (no built-in close)\n * resolveClose(instructions, { close: '</rules>' }) // '</rules>'\n * ```\n */\nexport function resolveClose<T>(\n\tmanager: ContextSectionSourceInterface<T>,\n\tprovider: ContextSectionFormat<T> | undefined,\n): string | undefined {\n\treturn manager.format?.close ?? provider?.close\n}\n\n/**\n * Resolves one item's rendering through the format cascade — item override > manager-options\n * override > provider default > built-in rendering.\n *\n * @remarks\n * Pure and total. The item's own `override` is the most-specific level (a fully-rendered\n * string for that item alone). A manager's `render(item)` already encapsulates\n * `[options-override → built-in]`, so it is reached only when no higher level applies — and\n * there it is the built-in rendering.\n *\n * @typeParam T - The section item being rendered (it may carry its own `override`)\n * @param manager - The section source (its `format` override + its built-in `render`)\n * @param provider - The provider-default framing for this section, or `undefined`\n * @param item - The item to render\n * @returns The item's prompt text\n *\n * @example\n * ```ts\n * resolveItem(instructions, undefined, terse) // 'Be terse.' (the built-in rendering)\n * resolveItem(instructions, { render: (one) => `<rule>${one.content}</rule>` }, terse)\n * // '<rule>Be terse.</rule>'\n * ```\n */\nexport function resolveItem<T extends { readonly override?: string }>(\n\tmanager: ContextSectionSourceInterface<T>,\n\tprovider: ContextSectionFormat<T> | undefined,\n\titem: T,\n): string {\n\treturn (\n\t\titem.override ??\n\t\tmanager.format?.render?.(item) ??\n\t\tprovider?.render?.(item) ??\n\t\tmanager.render(item)\n\t)\n}\n\n/**\n * Copies a message with image data merged onto its `images` — the message's own images first,\n * then the attached data, carrying `calls` only when present and never mutating the original.\n *\n * @remarks\n * Pure and total: the original message is never mutated. `calls` is carried only when the\n * source message has one (kept omitted otherwise, mirroring the store's present-when-given\n * convention).\n *\n * @param message - The message to copy (left unchanged)\n * @param data - The base64 image data to attach\n * @returns A new message carrying the merged `images`\n *\n * @example\n * ```ts\n * attachImages({ id: '1', role: 'user', content: 'Describe' }, ['<payload>'])\n * // { id: '1', role: 'user', content: 'Describe', images: ['<payload>'] }\n * ```\n */\nexport function attachImages(message: Message, data: readonly string[]): Message {\n\tconst images = [...(message.images ?? []), ...data]\n\treturn message.calls === undefined\n\t\t? { id: message.id, role: message.role, content: message.content, images }\n\t\t: {\n\t\t\t\tid: message.id,\n\t\t\t\trole: message.role,\n\t\t\t\tcontent: message.content,\n\t\t\t\tcalls: message.calls,\n\t\t\t\timages,\n\t\t\t}\n}\n\n/**\n * Attaches image data to a conversation's last user message — the turn a vision provider reads\n * images off — as a new array with that one message replaced by its carrying copy, and unchanged\n * when there is no data or no user turn.\n *\n * @remarks\n * Pure and total: the conversation and its messages are never mutated, and the returned array\n * replaces exactly the one target message with the copy {@link attachImages} builds. Empty\n * data returns the conversation unchanged; a conversation with no user message returns it\n * unchanged too (there is nowhere to attach, and the images already rode the system block).\n *\n * @param conversation - The messages to attach into (left unchanged)\n * @param data - The base64 image data to attach\n * @returns The conversation with its last user message replaced by the carrying copy\n *\n * @example\n * ```ts\n * attachUserImages([{ id: '1', role: 'user', content: 'Describe' }], ['<payload>'])\n * // [{ id: '1', role: 'user', content: 'Describe', images: ['<payload>'] }]\n * ```\n */\nexport function attachUserImages(\n\tconversation: readonly Message[],\n\tdata: readonly string[],\n): readonly Message[] {\n\tif (data.length === 0) return conversation\n\tlet target = -1\n\tfor (let index = conversation.length - 1; index >= 0; index -= 1) {\n\t\tif (conversation[index]?.role === 'user') {\n\t\t\ttarget = index\n\t\t\tbreak\n\t\t}\n\t}\n\tif (target === -1) return conversation\n\treturn conversation.map((message, index) =>\n\t\tindex === target ? attachImages(message, data) : message,\n\t)\n}\n\n/**\n * Collects the `base64` payload of the image files in a workspace file list — the data an agent\n * context attaches to the last user message.\n *\n * @remarks\n * Pure and total. `isBinary` narrows the tagless content to its binary arm (a total guard,\n * never an assertion), then the MIME prefix gates it to an image, so a text file and a non-image\n * binary (a PDF) are both skipped. Order follows the file list.\n *\n * @param files - The (already scope-filtered) workspace files\n * @returns The `base64` payload of each image file, in file order\n *\n * @example\n * ```ts\n * collectImageData([createFile({ path: 'a.png', content: { base64: '<payload>', mime: 'image/png' } })])\n * // ['<payload>']\n * ```\n */\nexport function collectImageData(files: readonly FileInterface[]): readonly string[] {\n\tconst data: string[] = []\n\tfor (const file of files) {\n\t\tif (isBinary(file.content) && file.content.mime.startsWith('image/')) {\n\t\t\tdata.push(file.content.base64)\n\t\t}\n\t}\n\treturn data\n}\n\n/**\n * Builds the raw synthetic summary message for one compacted section — role `'assistant'`, the\n * section's stable `id`, and its `summary` verbatim as content.\n *\n * @remarks\n * Pure and total. This is the unframed form the rollup regeneration digests (a\n * summary-of-summaries over the section summaries); the recap label is a `view()`\n * presentation concern kept out of what the summarizer re-reads — see\n * {@link buildRecapMessage}.\n *\n * @param section - The compacted section to render\n * @returns The synthetic summary message\n *\n * @example\n * ```ts\n * buildSummaryMessage({ id: 's1', summary: 'recap', messages: [] })\n * // { id: 's1', role: 'assistant', content: 'recap' }\n * ```\n */\nexport function buildSummaryMessage(section: Section): Message {\n\treturn { id: section.id, role: 'assistant', content: section.summary }\n}\n\n/**\n * Builds the framed recap message for one compacted section — the same role and stable `id` as\n * {@link buildSummaryMessage}, with the content prefixed by {@link\n * import('./constants.js').CONVERSATION_RECAP_PREFIX}.\n *\n * @remarks\n * Pure and total. The prefix is what makes a small model read the message as a condensed\n * recap of earlier turns rather than a literal assistant turn to echo or answer from. It is a\n * fixed handful of tokens, so a conversation's `view()` stays lean however many sections it\n * carries.\n *\n * @param section - The compacted section to render\n * @returns The framed recap message\n *\n * @example\n * ```ts\n * buildRecapMessage({ id: 's1', summary: 'recap', messages: [] })\n * // { id: 's1', role: 'assistant', content: `${CONVERSATION_RECAP_PREFIX}recap` }\n * ```\n */\nexport function buildRecapMessage(section: Section): Message {\n\treturn {\n\t\tid: section.id,\n\t\trole: 'assistant',\n\t\tcontent: `${CONVERSATION_RECAP_PREFIX}${section.summary}`,\n\t}\n}\n\n/**\n * Intersects two scope category lists under the \"`undefined` is the universal set\" rule — a\n * fresh copy that can only tighten, and the primitive a scope narrows through.\n *\n * @remarks\n * Pure and total, and it can only tighten: `undefined` ∩ `undefined` is `undefined` (still no\n * constraint); `undefined` ∩ a list is a copy of that list (the `undefined` side imposes\n * nothing); a list ∩ a list keeps the child keys the parent also allows, so a parent-excluded\n * key can never be re-admitted. Every returned list is a fresh copy, so a later mutation of\n * either input cannot leak into the result.\n *\n * @param parent - The parent's allow-list (`undefined` ⇒ no constraint)\n * @param child - The narrowing allow-list (`undefined` ⇒ no constraint)\n * @returns The intersected allow-list, or `undefined` when neither side constrains\n *\n * @example\n * ```ts\n * intersectKeys(['read', 'write'], ['write', 'admin']) // ['write']\n * intersectKeys(undefined, ['read']) // ['read']\n * intersectKeys(undefined, undefined) // undefined\n * ```\n */\nexport function intersectKeys(\n\tparent: readonly string[] | undefined,\n\tchild: readonly string[] | undefined,\n): readonly string[] | undefined {\n\tif (parent === undefined) return child === undefined ? undefined : [...child]\n\tif (child === undefined) return [...parent]\n\tconst allowed = new Set(parent)\n\treturn child.filter((key) => allowed.has(key))\n}\n\n/**\n * Assembles a provider result with only populated optional fields.\n *\n * @param content - The authoritative answer\n * @param thinking - The joined reasoning\n * @param tools - The accumulated calls\n * @param usage - The reported token usage\n * @returns The assembled result\n * @example\n * ```ts\n * buildProviderResult('ok', '', [], undefined) // { content: 'ok' }\n * ```\n */\nexport function buildProviderResult(\n\tcontent: string,\n\tthinking: string,\n\ttools: readonly ToolCall[],\n\tusage: TokenUsage | undefined,\n): ProviderResult {\n\treturn {\n\t\tcontent,\n\t\t...(thinking.length === 0 ? {} : { thinking }),\n\t\t...(tools.length === 0 ? {} : { tools }),\n\t\t...(usage === undefined ? {} : { usage }),\n\t}\n}\n\n/**\n * Reads a UTF-8 prefix of a byte stream and cancels its remainder.\n *\n * @remarks\n * The `limit` parameter bounds bytes passed to the decoder, including a partial final\n * character. An omitted limit reads to completion. A source may deliver a chunk larger\n * than the remaining limit; its unused bytes are discarded without decoding.\n * The read can overshoot by one source chunk. An abort leaves completion false.\n *\n * @param body - The readable byte stream\n * @param limit - The maximum byte prefix, or undefined for the complete stream\n * @param signal - The optional cancellation bound; abort returns the decoded prefix\n * @returns The decoded prefix and whether EOF occurred within the byte budget\n * @example\n * ```ts\n * import { readText } from '@orkestrel/agent'\n *\n * const body = new Response('answer').body\n * if (body !== null) await readText(body, 3) // { text: 'ans', complete: false }\n * ```\n */\nexport async function readText(\n\tbody: ReadableStream<Uint8Array>,\n\tlimit?: number,\n\tsignal?: AbortSignal,\n): Promise<TextRead> {\n\tconst reader = body.getReader()\n\tconst decoder = new TextDecoder()\n\tconst cleanup = new AbortController()\n\tlet remaining = limit ?? Infinity\n\tlet text = ''\n\tlet complete = false\n\ttry {\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid reader.cancel(signal.reason).catch(() => {\n\t\t\t\t\t// Preserve the decoded prefix when source cancellation rejects.\n\t\t\t\t})\n\t\t\t},\n\t\t\t{ once: true, signal: cleanup.signal },\n\t\t)\n\t\tif (signal?.aborted) {\n\t\t\tawait reader.cancel(signal.reason).catch(() => {\n\t\t\t\t// An already-aborted read still returns its empty prefix.\n\t\t\t})\n\t\t}\n\t\twhile (remaining > 0) {\n\t\t\tif (signal?.aborted) break\n\t\t\tconst step = await reader.read()\n\t\t\tif (signal?.aborted) break\n\t\t\tif (step.done) {\n\t\t\t\tcomplete = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconst bytes = step.value.subarray(0, remaining)\n\t\t\ttext += decoder.decode(bytes, { stream: true })\n\t\t\tremaining -= bytes.byteLength\n\t\t}\n\t\treturn { text: text + decoder.decode(), complete }\n\t} finally {\n\t\tcleanup.abort()\n\t\ttry {\n\t\t\tawait reader.cancel()\n\t\t} catch {\n\t\t\t// Preserve the read outcome when cancellation fails.\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n}\n\n/**\n * Decodes UTF-8 chunks with a final flush and releases the stream on every exit.\n *\n * @param body - The readable byte stream\n * @param signal - The optional cancellation bound; abort ends iteration without further chunks\n * @returns Decoded text chunks, including a held decoder tail\n * @example\n * ```ts\n * const body = new Response('answer').body\n * if (body !== null) for await (const chunk of readChunks(body)) render(chunk)\n * ```\n */\nexport async function* readChunks(\n\tbody: ReadableStream<Uint8Array>,\n\tsignal?: AbortSignal,\n): AsyncGenerator<string> {\n\tconst reader = body.getReader()\n\tconst decoder = new TextDecoder()\n\tconst cleanup = new AbortController()\n\ttry {\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid reader.cancel(signal.reason).catch(() => {\n\t\t\t\t\t// Preserve the iteration outcome when source cancellation rejects.\n\t\t\t\t})\n\t\t\t},\n\t\t\t{ once: true, signal: cleanup.signal },\n\t\t)\n\t\tif (signal?.aborted) {\n\t\t\tawait reader.cancel(signal.reason).catch(() => {\n\t\t\t\t// An already-aborted iterator still ends without yielding.\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tfor (;;) {\n\t\t\tconst step = await reader.read()\n\t\t\tif (signal?.aborted) return\n\t\t\tif (step.done) break\n\t\t\tconst chunk = decoder.decode(step.value, { stream: true })\n\t\t\tif (chunk.length > 0) yield chunk\n\t\t}\n\t\tconst tail = decoder.decode()\n\t\tif (tail.length > 0) yield tail\n\t} finally {\n\t\tcleanup.abort()\n\t\ttry {\n\t\t\tawait reader.cancel()\n\t\t} catch {\n\t\t\t// Preserve the primary outcome when the source refuses cancellation.\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tCompactOptions,\n\tConversationEventMap,\n\tConversationInterface,\n\tConversationOptions,\n\tConversationReferenceOptions,\n\tConversationSnapshot,\n\tConversationSummaryHandler,\n\tMessageInput,\n\tMessage,\n\tSection,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { DEFAULT_CONVERSATION_KEEP } from '../constants.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { ConversationError } from '../errors.js'\nimport { buildRecapMessage, buildSummaryMessage } from '../helpers.js'\n\n/**\n * Represents a conversation — a live uncompacted tail of messages it owns directly above a flat\n * message store, plus compacted, summarized {@link Section}s, a regenerated rollup `summary`, and\n * a `summarizable` flag, with on-demand `rehydrate` and substring `search`, driven by a\n * provider-agnostic {@link ConversationSummaryHandler} seam so `core` never imports a provider.\n * Observable through its own `emitter`.\n *\n * @remarks\n * - **Live tail + sections.** The conversation owns its live tail directly — `#messages` is an\n * insertion-ordered `Map` of immutable {@link Message}s keyed by their minted id\n * (the same store mechanics a flat manager had, folded in: `add` / `message` / `messages` /\n * `remove` / `clear` / `count`), exactly as a `Workspace` owns its files (no separate\n * per-value manager). `#sections` are the compacted history (oldest → newest), each a\n * summarized slice that retains its originals. `#summary` is the rollup (a\n * summary-of-summaries over all sections), regenerated on each compaction (`undefined`\n * until the first).\n * - **`view()`.** Each section folds to one synthetic summary message (role `'assistant'` — a\n * prior-context recap — keyed by the section's stable `id`), then the live messages\n * verbatim. The rollup `summary` is not injected (it is separately pull-able); `view()`\n * carries the per-section summaries, which are the compaction benefit.\n * - **`compact()`.** Folds the oldest `count - keep` live messages into a new section\n * (its `summary` from `#summarize`), removes them from the live tail by id, regenerates the\n * rollup (a second `#summarize` over all section summaries), and emits `summary` then\n * `compact`. Returns the section, or `undefined` when nothing folds (`count <= keep`).\n * Throws a {@link ConversationError} when no `#summarize` was supplied. A compaction calls\n * the summarizer for the section digest and again for the rollup.\n * - **`rehydrate(id)` / `search(query)`.** `rehydrate` returns a section's full original\n * messages (`[]` for an unknown id) and emits `rehydrate` — a pure read (the caller decides\n * whether to re-add them; `rehydrate` never reinserts). `search` is a case-insensitive\n * substring scan of `content` across all messages (every section's originals + the live tail).\n * - **Observable.** The owned {@link emitter} ({@link ConversationEventMap}) carries\n * `compact` / `summary` / `rehydrate`, emitted directly, strictly after the state change;\n * the emitter isolates a listener throw and routes it to its `error` handler (the `error`\n * option), so a buggy observer can never corrupt a compaction.\n *\n * @example\n * ```ts\n * const conversation = new Conversation({ summarize: async (m) => `recap of ${m.length}` })\n * conversation.add([\n * \t{ role: 'user', content: 'Hello' },\n * \t{ role: 'assistant', content: 'Hi there' },\n * ])\n * const section = await conversation.compact() // folds both into one summarized section\n * conversation.view() // [{ role: 'assistant', content: 'recap of 2' }] — the live tail is empty\n * conversation.summary // 'recap of 1' — the rollup over the one section\n * ```\n */\nexport class Conversation implements ConversationInterface {\n\treadonly #id: string\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into a compaction.\n\treadonly #emitter: Emitter<ConversationEventMap>\n\t// The provider-agnostic summarizer seam — `undefined` ⇒ `compact()` throws (a conversation\n\t// can still store + view a live tail; it cannot fold).\n\treadonly #summarize: ConversationSummaryHandler | undefined\n\t// How many recent live messages a `compact()` retains verbatim (older ones fold).\n\treadonly #keep: number\n\t// The optional cap on the compacted sections list — `undefined` ⇒ unlimited. Enforced\n\t// after pushing a fresh `compact()` fold: an overflow folds the oldest sections into one.\n\treadonly #cap: number | undefined\n\t// The compacted history, oldest → newest — each summarized slice retains its originals.\n\treadonly #sections: Section[] = []\n\t// The rollup (a summary-of-summaries over all sections), regenerated on each compaction.\n\t#summary: string | undefined\n\t// The live uncompacted tail the conversation owns directly — an insertion-ordered Map of\n\t// immutable messages keyed by their minted id (the flat store mechanics folded in).\n\treadonly #messages = new Map<string, Message>()\n\n\tconstructor(options?: ConversationOptions) {\n\t\t// An optional snapshot to hydrate from — its `id` is the conversation's identity (so it\n\t\t// wins over `options.id`), and its rollup `summary` / compacted `sections` / live tail are\n\t\t// restored, with the live `summarize` / `keep` / `on` supplied through `options` alongside it\n\t\t// (a summarizer is a function, not serialized — re-supplied as config). Restoring is silent\n\t\t// (no events — nothing was edited). `ConversationOptions.snapshot` is the one declared seam\n\t\t// every caller reaches it through — `createConversation(options)` hydrates through it, and\n\t\t// `ConversationManager.add` passes a stored snapshot in the same options object.\n\t\tconst snapshot = options?.snapshot\n\t\tthis.#id = snapshot?.id ?? options?.id ?? crypto.randomUUID()\n\t\tthis.#emitter = new Emitter<ConversationEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t\tthis.#summarize = options?.summarize\n\t\tthis.#keep = options?.keep ?? DEFAULT_CONVERSATION_KEEP\n\t\tif (options?.sections !== undefined && options.sections < 1) {\n\t\t\tthrow new ConversationError('SECTIONS', 'a sections cap must be >= 1')\n\t\t}\n\t\tthis.#cap = options?.sections\n\t\tif (snapshot !== undefined) {\n\t\t\tthis.#summary = snapshot.summary\n\t\t\tfor (const section of snapshot.sections) this.#sections.push(section)\n\t\t\tfor (const message of snapshot.messages) this.#messages.set(message.id, message)\n\t\t}\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget emitter(): EmitterInterface<ConversationEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget summary(): string | undefined {\n\t\treturn this.#summary\n\t}\n\n\tget sections(): readonly Section[] {\n\t\treturn [...this.#sections]\n\t}\n\n\tget summarizable(): boolean {\n\t\t// True exactly when a summarizer was supplied — the clean signal the agent loop's automatic\n\t\t// compaction gates on (a non-summarizable conversation is never auto-compacted, so the auto\n\t\t// path never throws the `SUMMARIZER` ConversationError). A manual `compact()` still throws.\n\t\treturn this.#summarize !== undefined\n\t}\n\n\tget count(): number {\n\t\treturn this.#messages.size\n\t}\n\n\tadd(input: MessageInput): Message\n\tadd(inputs: readonly MessageInput[]): readonly Message[]\n\tadd(input: MessageInput | readonly MessageInput[]): Message | readonly Message[] {\n\t\tif (isArray(input)) return input.map((one) => this.#create(one))\n\t\treturn this.#create(input)\n\t}\n\n\tmessage(id: string): Message | undefined {\n\t\treturn this.#messages.get(id)\n\t}\n\n\tmessages(): readonly Message[] {\n\t\treturn [...this.#messages.values()]\n\t}\n\n\tremove(id: string): boolean\n\tremove(ids: readonly string[]): boolean\n\tremove(ids: string | readonly string[]): boolean {\n\t\tif (isArray(ids)) {\n\t\t\t// True only when every supplied id was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one.\n\t\t\tlet removed = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (!this.#messages.delete(id)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#messages.delete(ids)\n\t}\n\n\tclear(): void {\n\t\tthis.#messages.clear()\n\t}\n\n\tview(): readonly Message[] {\n\t\t// Each section → one synthetic recap message (the compaction benefit), then the live\n\t\t// tail verbatim. The rollup `summary` is deliberately not injected here. The recap is\n\t\t// framed (a `[Summary of earlier messages]` label prefix) so a small model reads it as a\n\t\t// condensed recap of prior turns, not as a literal assistant turn it must echo / treat as\n\t\t// the latest answer — a lean label (a handful of tokens), proven no-bloat by a test guard.\n\t\treturn [\n\t\t\t...this.#sections.map((section) => buildRecapMessage(section)),\n\t\t\t...this.#messages.values(),\n\t\t]\n\t}\n\n\tasync compact(options?: CompactOptions): Promise<Section | undefined> {\n\t\tconst summarize = this.#summarize\n\t\tif (summarize === undefined) {\n\t\t\tthrow new ConversationError(\n\t\t\t\t'SUMMARIZER',\n\t\t\t\t'cannot compact a conversation without a summarizer',\n\t\t\t)\n\t\t}\n\t\tconst cap = options?.sections ?? this.#cap\n\t\tif (cap !== undefined && cap < 1) {\n\t\t\tthrow new ConversationError('SECTIONS', 'a sections cap must be >= 1')\n\t\t}\n\t\tconst keep = options?.keep ?? this.#keep\n\t\tconst live = [...this.#messages.values()]\n\t\t// Fold the oldest `count - keep` live messages; nothing to fold ⇒ a no-op.\n\t\tconst fold = keep <= 0 ? live.length : live.length - keep\n\t\tif (fold <= 0) return undefined\n\t\tconst slice = live.slice(0, fold)\n\t\t// 1. Digest the folded slice into the section summary (the first summarizer call).\n\t\tconst summary = await summarize(slice)\n\t\tconst section: Section = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\tsummary,\n\t\t\tmessages: slice,\n\t\t}\n\t\t// 2. Remove the folded messages from the live tail (by their ids) and push the section.\n\t\tfor (const message of slice) this.#messages.delete(message.id)\n\t\tthis.#sections.push(section)\n\t\t// 3. Enforce the bounded-`sections` cap: an overflow past `cap` folds the oldest\n\t\t// overflow sections into one merged section (a further summarizer call over the folded\n\t\t// section summaries), so `#sections.length === cap` afterward.\n\t\tif (cap !== undefined && this.#sections.length > cap) {\n\t\t\tconst overflow = this.#sections.length - cap + 1\n\t\t\tconst folded = this.#sections.slice(0, overflow)\n\t\t\ttry {\n\t\t\t\tconst merged: Section = {\n\t\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\t\tsummary: await summarize(folded.map((one) => buildSummaryMessage(one))),\n\t\t\t\t\tmessages: folded.flatMap((one) => one.messages),\n\t\t\t\t}\n\t\t\t\tthis.#sections.splice(0, overflow, merged)\n\t\t\t\tthis.#emitter.emit('collapse', merged)\n\t\t\t} catch (error) {\n\t\t\t\t// The merge summarizer call threw — the sections stay transiently at `cap + 1`\n\t\t\t\t// (no splice, no loss), but the rollup still regenerates over the current\n\t\t\t\t// (unmerged) sections so it is never left stale, then the error propagates\n\t\t\t\t// (manual `compact()` always surfaces a summarizer failure to its caller; the\n\t\t\t\t// next successful `compact()` self-heals the over-cap count).\n\t\t\t\tthis.#summary = await summarize(this.#sections.map((one) => buildSummaryMessage(one)))\n\t\t\t\tthis.#emitter.emit('summary', this.#summary)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t}\n\t\t// 4. Regenerate the rollup — a summary-of-summaries over all (now-capped) sections\n\t\t// — then observe it, after the mutation, through the guarded path.\n\t\tthis.#summary = await summarize(this.#sections.map((one) => buildSummaryMessage(one)))\n\t\tthis.#emitter.emit('summary', this.#summary)\n\t\t// 5. Observe the new section last, so a swallowed listener throw can't perturb the fold.\n\t\tthis.#emitter.emit('compact', section)\n\t\treturn section\n\t}\n\n\trehydrate(id: string): readonly Message[] {\n\t\tconst section = this.#sections.find((one) => one.id === id)\n\t\t// A pure read — emit `rehydrate` after resolving (no mutation to perturb); `rehydrate`\n\t\t// never reinserts the originals (the caller decides). Unknown id ⇒ an empty list.\n\t\tthis.#emitter.emit('rehydrate', id)\n\t\treturn section === undefined ? [] : section.messages\n\t}\n\n\tsearch(query: string): readonly Message[] {\n\t\t// Case-insensitive substring over `content` across all messages — every section's\n\t\t// retained originals (oldest → newest) first, then the live tail.\n\t\tconst needle = query.toLowerCase()\n\t\tconst all = [\n\t\t\t...this.#sections.flatMap((section) => section.messages),\n\t\t\t...this.#messages.values(),\n\t\t]\n\t\treturn all.filter((message) => message.content.toLowerCase().includes(needle))\n\t}\n\n\treference(options?: ConversationReferenceOptions): string {\n\t\t// Render this conversation as a self-labeled, fenced provenance block to pull into another\n\t\t// conversation (as a `document`). A pure string — never a model call. The leading marker\n\t\t// names the source (`label`, default the `id`) and states it is not part of the live\n\t\t// conversation, so a small model reads the rollup + cherry-picked excerpts as foreign\n\t\t// material it attributes to that source, never as its own latest turns.\n\t\tconst label = options?.label ?? this.#id\n\t\tconst lines = [`[Reference — conversation \"${label}\" — NOT part of this conversation]`]\n\t\t// The rollup `summary` (a summary-of-summaries) — included when opted in (default true) and\n\t\t// one exists (`undefined` until the first compaction drops the line).\n\t\tif (options?.summary !== false && this.#summary !== undefined) {\n\t\t\tlines.push(`Summary: ${this.#summary}`)\n\t\t}\n\t\t// The cherry-picked excerpts (each `- role: content`) — the few relevant turns the caller\n\t\t// selected (through this conversation's own `search` / `rehydrate`), not the whole history.\n\t\tconst messages = options?.messages ?? []\n\t\tif (messages.length > 0) {\n\t\t\tlines.push('Relevant messages:')\n\t\t\tfor (const message of messages) lines.push(`- ${message.role}: ${message.content}`)\n\t\t}\n\t\treturn lines.join('\\n')\n\t}\n\n\tsnapshot(): ConversationSnapshot {\n\t\t// The container serializes itself: its id + the rollup summary + the compacted sections +\n\t\t// the live tail. The summarizer / keep are not serialized — they are live config re-supplied\n\t\t// on hydrate (a ConversationSummaryHandler is a function, not data). The sections + messages are\n\t\t// already plain immutable records, so the snapshot JSON-round-trips losslessly; mutates nothing.\n\t\treturn {\n\t\t\tid: this.#id,\n\t\t\t...(this.#summary === undefined ? {} : { summary: this.#summary }),\n\t\t\tsections: this.sections,\n\t\t\tmessages: this.messages(),\n\t\t}\n\t}\n\n\t// Mint an immutable live-tail message from one input — a fresh UUID id plus the input's\n\t// role / content, carrying `calls` / `images` only when the input supplied them (each\n\t// spread in conditionally, so an absent optional is never stored as `undefined`). Stored\n\t// by id and returned; never mutated after creation.\n\t#create(input: MessageInput): Message {\n\t\tconst message: Message = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\trole: input.role,\n\t\t\tcontent: input.content,\n\t\t\t...(input.calls === undefined ? {} : { calls: input.calls }),\n\t\t\t...(input.images === undefined ? {} : { images: input.images }),\n\t\t}\n\t\tthis.#messages.set(message.id, message)\n\t\treturn message\n\t}\n}\n","import type {\n\tConversationInput,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tConversationManagerOptions,\n\tConversationStoreInterface,\n\tConversationSummaryHandler,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { DEFAULT_CONVERSATION_KEEP } from '../constants.js'\nimport { Conversation } from './Conversation.js'\n\n/**\n * Registers {@link Conversation}s keyed by `id`, in insertion order, with an active pointer —\n * the id-keyed store over the conversation layer, the `active` / `switch` seam the\n * {@link import('../AgentContext.js').AgentContext} renders, and the durable `open` / `save`\n * store seam. Event-free (a registry, like\n * {@link import('@orkestrel/workspace').WorkspaceManager}); the observability lives on each\n * {@link Conversation}.\n *\n * @remarks\n * - **Registry.** Conversations live in an insertion-ordered `Map` keyed by `id`. `add(input?)`\n * mints a {@link Conversation} (its `id` from `input` or `crypto.randomUUID()`), flowing the\n * manager's default `#summarize` / `#keep` in unless the `input` overrides them, and stores\n * it (an already-present `id` overwrites — last write wins). `count` is the map size,\n * `conversation(id)` looks one up, `conversations()` lists them in insertion order.\n * - **Active pointer.** `active` is the active conversation (the agent's message source the\n * context renders), `undefined` until the first `add` (which auto-activates it — a registry\n * with conversations always has one active). A subsequent `add` leaves `active` unchanged.\n * `switch(id)` re-points `active` to the conversation with `id` and returns it; an unknown `id`\n * returns `undefined` and leaves `active` unchanged (the lenient lookup style — never throws,\n * no new error code).\n * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id was\n * removed; removing the active conversation sets `active` to `undefined`. `clear` empties the registry\n * and sets `active` to `undefined`.\n * - **Event-free.** A purely registry store — no Emitter, no events (each conversation owns\n * its own observable `emitter`).\n *\n * @example\n * ```ts\n * const manager = new ConversationManager({ summarize: async (m) => `recap of ${m.length}` })\n * const conversation = manager.add() // auto-activates — active === conversation\n * manager.add({ id: 'scratch' }) // leaves active unchanged\n * manager.switch('scratch') // re-points active to the 'scratch' conversation\n * manager.count // 2\n * ```\n */\nexport class ConversationManager implements ConversationManagerInterface {\n\treadonly #conversations = new Map<string, ConversationInterface>()\n\t// The active conversation's id — the message source the context renders; `undefined` until the\n\t// first `add` auto-activates one (kept as an id, never a stale reference, so a re-add / removal\n\t// of that id is reflected through the live map lookup in `active`).\n\t#active: string | undefined\n\t// The default summarizer flowed into every conversation `add` creates (a per-`add` override\n\t// wins); a conversation created with neither cannot `compact` (it throws a ConversationError).\n\treadonly #summarize: ConversationSummaryHandler | undefined\n\t// The default retained-tail size flowed into every conversation `add` creates (overridable).\n\treadonly #keep: number\n\t// The default `sections` cap flowed into every conversation `add` creates (overridable); `undefined` ⇒ unlimited.\n\treadonly #sections: number | undefined\n\t// The optional durable store backing `open` / `save`; `undefined` ⇒ registry-only (both lenient).\n\treadonly #store: ConversationStoreInterface | undefined\n\n\tconstructor(options?: ConversationManagerOptions) {\n\t\tthis.#summarize = options?.summarize\n\t\tthis.#keep = options?.keep ?? DEFAULT_CONVERSATION_KEEP\n\t\tthis.#sections = options?.sections\n\t\tthis.#store = options?.store\n\t}\n\n\tget count(): number {\n\t\treturn this.#conversations.size\n\t}\n\n\tget active(): ConversationInterface | undefined {\n\t\treturn this.#active === undefined ? undefined : this.#conversations.get(this.#active)\n\t}\n\n\tconversation(id: string): ConversationInterface | undefined {\n\t\treturn this.#conversations.get(id)\n\t}\n\n\tconversations(): readonly ConversationInterface[] {\n\t\treturn [...this.#conversations.values()]\n\t}\n\n\tadd(input?: ConversationInput): ConversationInterface {\n\t\t// The manager's defaults flow in unless the input overrides them — so a conversation\n\t\t// created through the manager inherits its summarizer / keep by default. An optional\n\t\t// `snapshot` hydrates the conversation through the declared `ConversationOptions.snapshot`\n\t\t// seam — its `id` / `summary` / `sections` / live tail restored, the live summarize / keep\n\t\t// re-supplied alongside it in the same options object.\n\t\tconst sections = input?.sections ?? this.#sections\n\t\tconst summarize = input?.summarize ?? this.#summarize\n\t\tconst conversation = new Conversation({\n\t\t\t...(input?.id === undefined ? {} : { id: input.id }),\n\t\t\t...(input?.on === undefined ? {} : { on: input.on }),\n\t\t\t...(summarize === undefined ? {} : { summarize }),\n\t\t\tkeep: input?.keep ?? this.#keep,\n\t\t\t...(sections === undefined ? {} : { sections }),\n\t\t\t...(input?.snapshot === undefined ? {} : { snapshot: input.snapshot }),\n\t\t})\n\t\tthis.#conversations.set(conversation.id, conversation)\n\t\t// First conversation auto-activates: a registry that holds conversations always has one active.\n\t\tif (this.#active === undefined) this.#active = conversation.id\n\t\treturn conversation\n\t}\n\n\tswitch(id: string): ConversationInterface | undefined {\n\t\t// Lenient (mirrors `conversation(id)`): an unknown id re-points nothing and returns undefined.\n\t\tconst conversation = this.#conversations.get(id)\n\t\tif (conversation === undefined) return undefined\n\t\tthis.#active = id\n\t\treturn conversation\n\t}\n\n\tasync open(id: string): Promise<ConversationInterface | undefined> {\n\t\t// Already registered ⇒ activate it (no store hit) — the registry is the live source.\n\t\tconst existing = this.#conversations.get(id)\n\t\tif (existing !== undefined) {\n\t\t\tthis.#active = id\n\t\t\treturn existing\n\t\t}\n\t\t// No store ⇒ a registry miss resolves nothing (lenient, like `switch`/`conversation`).\n\t\tif (this.#store === undefined) return undefined\n\t\t// Store hit ⇒ rehydrate through the `snapshot` option (it restores id / summary /\n\t\t// sections / live tail) by reusing `add`, which registers + auto-activates a fresh\n\t\t// Conversation (flowing the manager's default summarize / keep in); a miss ⇒ undefined.\n\t\tconst snapshot = await this.#store.get(id)\n\t\tif (snapshot === undefined) return undefined\n\t\tconst conversation = this.add({ snapshot })\n\t\t// Re-point `active` explicitly: `add` only auto-activates the first conversation, so an open\n\t\t// into a non-empty registry must still make the rehydrated one active.\n\t\tthis.#active = conversation.id\n\t\treturn conversation\n\t}\n\n\tasync save(id: string): Promise<boolean> {\n\t\t// Lenient: persist only when a store is set and the id is registered; otherwise a no-op.\n\t\tconst conversation = this.#conversations.get(id)\n\t\tif (this.#store === undefined || conversation === undefined) return false\n\t\tawait this.#store.set(conversation.snapshot())\n\t\treturn true\n\t}\n\n\t// The array overload comes first, so a list resolves to the batch form (an `id` is a string,\n\t// never an array, so the two never overlap — but the project declares the array overload\n\t// first by convention).\n\tremove(ids: readonly string[]): boolean\n\tremove(id: string): boolean\n\tremove(ids: string | readonly string[]): boolean {\n\t\tif (isArray(ids)) {\n\t\t\t// True only when every supplied id was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one. Each present id still clears `active`\n\t\t\t// when it was the active conversation.\n\t\t\tlet removed = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (!this.#drop(id)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#drop(ids)\n\t}\n\n\tclear(): void {\n\t\tthis.#conversations.clear()\n\t\t// An emptied registry has no active conversation.\n\t\tthis.#active = undefined\n\t}\n\n\t// Delete one conversation by id; when it was the active one, clear the active pointer (a removed\n\t// conversation can never stay active).\n\t#drop(id: string): boolean {\n\t\tconst removed = this.#conversations.delete(id)\n\t\tif (removed && this.#active === id) this.#active = undefined\n\t\treturn removed\n\t}\n}\n","import type { InstructionInput, InstructionInterface } from '../types.js'\n\n/**\n * Represents an immutable named directive — an {@link InstructionInterface} assembled once from\n * its input (`name` / `content`, an optional `priority` defaulting to `0`), the `id` minted at\n * construction.\n *\n * @remarks\n * A thin immutable value object (mirroring {@link import('@orkestrel/tool').Tool}): the\n * constructor mints a fresh `id` (`crypto.randomUUID()`), copies the input's `name` /\n * `content`, resolves `priority` to the input's value or `0`, and carries the input's\n * per-item `override` only when supplied (assigned when present, mirroring a\n * message's `images` / `calls` present-when-given convention — kept absent otherwise).\n * Never mutated after construction. An\n * {@link import('./InstructionManager.js').InstructionManager} keys it by `name` and\n * renders it (highest `priority` first) under its section header.\n *\n * @example\n * ```ts\n * const instruction = new Instruction({ name: 'tone', content: 'Be concise.', priority: 5 })\n * instruction.priority // 5\n * ```\n */\nexport class Instruction implements InstructionInterface {\n\treadonly id: string\n\treadonly name: string\n\treadonly content: string\n\treadonly priority: number\n\t// The per-item rendered override — the cascade's most-specific level. Assigned only when\n\t// the input supplied one, so it stays absent (not present-but-undefined) otherwise.\n\treadonly override?: string\n\n\tconstructor(input: InstructionInput) {\n\t\tthis.id = crypto.randomUUID()\n\t\tthis.name = input.name\n\t\tthis.content = input.content\n\t\tthis.priority = input.priority ?? 0\n\t\tif (input.override !== undefined) this.override = input.override\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tContextSectionFormat,\n\tInstructionInput,\n\tInstructionInterface,\n\tInstructionManagerEventMap,\n\tInstructionManagerInterface,\n\tInstructionManagerOptions,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Instruction } from './Instruction.js'\n\n/**\n * Registers the immutable {@link Instruction}s a richer context assembles a directives block\n * from — keyed by `name` so a re-`add` overwrites, last write wins, and listed by descending\n * `priority`, carrying the `open` / `render` build contract and an observable `emitter`.\n *\n * @remarks\n * - **Registry.** Instructions live in an insertion-ordered `Map` keyed by `name`;\n * `add` takes one {@link InstructionInput} or a batch, mints each instruction's\n * `id`, and a re-`add` of the same name overwrites it (last write wins). `count` is the\n * map size, `instruction(name)` looks one up, and `instructions()` lists them sorted by\n * descending `priority` (a stable sort, so equal priorities keep insertion order).\n * - **Build contract (with the manager-options override).** `open` is the section\n * header a context renders the instructions under; `render(instruction)` renders one\n * instruction (its `content`). Each encapsulates the cascade's `[options-override →\n * built-in]` half: when `InstructionManagerOptions.format` supplies an `open` /\n * `render`, `open` / `render` return it, else the built-in — so a richer context\n * reads one consistent pair and layers the provider default + per-item override on top\n * (see {@link import('../AgentContext.js').AgentContext}). The per-item\n * {@link InstructionInput.override} is round-tripped onto the stored instruction.\n * - **Removal.** `remove` drops one by name, or a batch — `true` only when every supplied\n * name was removed; `clear` empties the registry.\n * - **Observable.** The owned {@link emitter} ({@link InstructionManagerEventMap})\n * carries `add` (the created instruction) / `remove` (the name) / `clear` for\n * fire-and-forget observers. Every event is emitted directly, strictly after the map\n * mutation completes; the emitter isolates a listener throw and routes it to its `error`\n * handler (the `error` option), so a buggy observer can never corrupt a mutation.\n *\n * @example\n * ```ts\n * const manager = new InstructionManager()\n * manager.add([\n * \t{ name: 'tone', content: 'Be concise.', priority: 1 },\n * \t{ name: 'safety', content: 'Refuse unsafe requests.', priority: 10 },\n * ])\n * manager.instructions().map((one) => one.name) // ['safety', 'tone'] — highest priority first\n * ```\n */\nexport class InstructionManager implements InstructionManagerInterface {\n\treadonly #instructions = new Map<string, InstructionInterface>()\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into a mutation.\n\treadonly #emitter: Emitter<InstructionManagerEventMap>\n\t// The manager-options level of the build cascade — consulted first by `open` /\n\t// `render` (falling back to the built-in), so this manager encapsulates the\n\t// `[options-override → built-in]` half and a context layers the rest on top.\n\treadonly #format: ContextSectionFormat<InstructionInterface> | undefined\n\n\tconstructor(options?: InstructionManagerOptions) {\n\t\tthis.#emitter = new Emitter<InstructionManagerEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t\tthis.#format = options?.format\n\t}\n\n\tget emitter(): EmitterInterface<InstructionManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#instructions.size\n\t}\n\n\tget open(): string {\n\t\t// Manager-options override first, else the built-in header.\n\t\treturn this.#format?.open ?? '## Instructions'\n\t}\n\n\tget format(): ContextSectionFormat<InstructionInterface> | undefined {\n\t\t// The raw override — so a context's `build()` can interleave the provider default\n\t\t// beneath it (this getter / `open` / `render` encapsulate override→built-in).\n\t\treturn this.#format\n\t}\n\n\tadd(input: InstructionInput): InstructionInterface\n\tadd(inputs: readonly InstructionInput[]): readonly InstructionInterface[]\n\tadd(\n\t\tinput: InstructionInput | readonly InstructionInput[],\n\t): InstructionInterface | readonly InstructionInterface[] {\n\t\tif (isArray(input)) return input.map((one) => this.#create(one))\n\t\treturn this.#create(input)\n\t}\n\n\tinstruction(name: string): InstructionInterface | undefined {\n\t\treturn this.#instructions.get(name)\n\t}\n\n\tinstructions(): readonly InstructionInterface[] {\n\t\t// A stable descending-priority sort — Array.prototype.sort is stable, so equal\n\t\t// priorities keep their insertion order (the map's iteration order).\n\t\treturn [...this.#instructions.values()].sort((a, b) => b.priority - a.priority)\n\t}\n\n\trender(instruction: InstructionInterface): string {\n\t\t// Manager-options override first, else the built-in (its `content`).\n\t\treturn this.#format?.render?.(instruction) ?? instruction.content\n\t}\n\n\tremove(name: string): boolean\n\tremove(names: readonly string[]): boolean\n\tremove(names: string | readonly string[]): boolean {\n\t\tif (isArray(names)) {\n\t\t\t// True only when every supplied name was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one. Each present name still emits.\n\t\t\tlet removed = true\n\t\t\tfor (const name of names) {\n\t\t\t\tif (!this.#delete(name)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#delete(names)\n\t}\n\n\tclear(): void {\n\t\tthis.#instructions.clear()\n\t\t// Observe the cleared registry — after the map emptied, so a swallowed listener\n\t\t// throw can never alter the clear (no payload — `clear` is a pure signal).\n\t\tthis.#emitter.emit('clear')\n\t}\n\n\t// Mint an immutable instruction, store it by name (overwriting a same-name one), and\n\t// emit `add` after the map mutation — so a swallowed listener throw can't perturb it.\n\t#create(input: InstructionInput): InstructionInterface {\n\t\tconst instruction = new Instruction(input)\n\t\tthis.#instructions.set(instruction.name, instruction)\n\t\tthis.#emitter.emit('add', instruction)\n\t\treturn instruction\n\t}\n\n\t// Delete one instruction, emitting `remove` only when one was actually removed (a\n\t// delete of an absent name returns `false` and emits nothing) — after the deletion.\n\t#delete(name: string): boolean {\n\t\tconst removed = this.#instructions.delete(name)\n\t\tif (removed) this.#emitter.emit('remove', name)\n\t\treturn removed\n\t}\n}\n","import type {\n\tAgentContextInterface,\n\tAgentContextOptions,\n\tContextFormat,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tInstructionManagerInterface,\n\tMessage,\n\tMessageManagerInterface,\n\tScopeInterface,\n} from './types.js'\nimport type { ToolManagerInterface } from '@orkestrel/tool'\nimport type { WorkspaceManagerInterface } from '@orkestrel/workspace'\nimport { ToolManager } from '@orkestrel/tool'\nimport { isText, WorkspaceManager } from '@orkestrel/workspace'\nimport { WORKSPACE_SECTION_HEADER } from './constants.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport {\n\tattachUserImages,\n\tcollectImageData,\n\tfilterAllowList,\n\trenderFencedFile,\n\trenderSection,\n\tresolveClose,\n\tresolveItem,\n\tresolveOpen,\n} from './helpers.js'\nimport { InstructionManager } from './instructions/InstructionManager.js'\n\n/**\n * Assembles a provider request from the richer turn context — the optional system prompt, the\n * observable context managers (instructions / workspaces), the\n * {@link ConversationManagerInterface} message source whose active conversation is `messages`, the\n * {@link ToolManagerInterface} registry, and an active {@link ScopeInterface} changed through\n * {@link AgentContextInterface.apply}. `build()` folds the scoped managers and the active\n * workspace into one system block, then the conversation, and never reads `tools`.\n *\n * @remarks\n * - **Composition.** `system` is the optional system prompt; `instructions` / `tools` /\n * `workspaces` / `conversations` are the registries passed in `options` (bring your own), or\n * fresh empty ones when omitted (so `workspaces` is always present); `messages` is the active\n * conversation's live tail (always defined — see the following item). `scope` is the active filter —\n * `undefined` (the default) ⇒ no filtering; change it through `apply(scope)`. The structural\n * `workspaces` / `conversations` registries are fixed at construction; switch their active\n * members through their own `switch(id)` methods.\n * - **The message source — the conversation registry's active conversation.** `conversations` is a\n * {@link ConversationManagerInterface}; the context ensures it always has an active conversation\n * (at construction it `add`s a default when the manager has none), so the dynamic `messages`\n * getter — `this.#conversations.active` — is always defined. `messages` returns the active\n * conversation itself (it owns the live tail + the message verbs directly, satisfying\n * {@link MessageManagerInterface} structurally — the same reference, no duplication), and\n * `build()` folds that conversation's `view()` (its per-section summaries + live tail) as the\n * authoritative message inclusion — the scope does not filter the conversation (it owns inclusion\n * through compaction; scope filters only instructions / tools / workspace files). Because `messages`\n * is read dynamically, an agent switches the active\n * conversation between runs (`conversations.switch(id)`) to serve many threads (the real\n * multi-conversation pattern); switch between runs, not during a run, and use separate agents\n * for concurrent threads.\n * - **`build(format?)` — the scoped assembly + the format cascade.** It folds, in order,\n * the system prompt then the scope-filtered instructions → the active workspace's text files\n * (each as a block: the section's resolved `open` text, each item's resolved rendering, then\n * any resolved `close` text) into one leading `system` message (prepended only when at least\n * one part exists), then appends the active conversation's `view()` (the conversation owns\n * message inclusion through compaction — the scope does not filter the conversation). Each\n * `open` / item / `close`\n * resolves independently, most-specific-first — `build()`'s optional `format` (a provider's\n * per-section default) is the provider level: `open` = manager-options-override > provider >\n * built-in; per item = item-override > manager-options-override > provider > built-in; `close` =\n * manager-options-override > provider (no built-in ⇒ no closing line when unset) (see\n * {@link AgentContextInterface.build}). Passing no `format` (and with no overrides / no per-item\n * override) reproduces the built-in framing byte-for-byte (each section is its built-in header +\n * items, no closing line). The active workspace's scoped-in image files' `base64` payload is attached to\n * the last user message (a vision provider reads images off a user turn); when no user message\n * exists the attachment is skipped. Built fresh each call (recomputed, never cached), so it\n * always reflects the current managers / messages / scope / active workspace; it never mutates a\n * manager or the stored messages.\n * - **The active workspace, rendered by carrier — the sole document/image context.**\n * `workspaces.active` (when set) has its {@link import('@orkestrel/workspace').FileInterface}s scope-filtered by `scope.files`,\n * then split: text files fold into a dedicated `## Workspace` system section (fenced reference\n * blocks — placed right after the instructions section), and image files' `base64` payload attaches\n * to the last user message. Active-only — never the other registered workspaces; with no active\n * workspace nothing renders for workspaces. `build()` owns this render (a `Workspace` /\n * `WorkspaceManager` stays file-focused).\n * - **Tools are structural, not in the prompt.** The registry is advertised to the provider\n * through `tools.definitions()` (scope-filtered by the loop), never serialized into the\n * message array — so `build()`'s output carries no tool content, scoped or not.\n * - **Event-free context; observable managers.** The context itself owns no Emitter; the\n * context managers each carry their own (the push observation surface).\n *\n * @example\n * ```ts\n * const context = new AgentContext({ system: 'You are concise.' })\n * context.instructions.add({ name: 'tone', content: 'Be terse.' })\n * context.messages.add({ role: 'user', content: 'Hi' })\n * context.build() // [{ role: 'system', content: 'You are concise.\\n\\n## Instructions\\n\\nBe terse.' }, { role: 'user', content: 'Hi' }]\n * ```\n */\nexport class AgentContext implements AgentContextInterface {\n\treadonly #system: string | undefined\n\treadonly #instructions: InstructionManagerInterface\n\t// The workspace registry whose active workspace `build()` renders by carrier (text files →\n\t// the system block, image files → the last user message). Always present (a fresh empty\n\t// manager when none was supplied). The registry is structural; switch its active workspace\n\t// through `workspaces.switch(id)`. `build()` reads `active` / its `files()` fresh each call.\n\treadonly #workspaces: WorkspaceManagerInterface\n\t// The conversation registry whose active conversation is the message source: the dynamic\n\t// `messages` getter returns `#conversations.active` (always defined — the constructor ensures one)\n\t// and `build()` folds that conversation's `view()`. Always present. The registry is structural;\n\t// switch its active conversation through `conversations.switch(id)`.\n\treadonly #conversations: ConversationManagerInterface\n\treadonly #tools: ToolManagerInterface\n\t#scope: ScopeInterface | undefined\n\n\tconstructor(options?: AgentContextOptions) {\n\t\tthis.#system = options?.system\n\t\tthis.#instructions = options?.instructions ?? new InstructionManager()\n\t\t// Default to a fresh empty registry so `context.workspaces` is always present (mirroring\n\t\t// the always-present instruction manager); a supplied one is reused. The active workspace\n\t\t// is the sole document/image context.\n\t\tthis.#workspaces = options?.workspaces ?? new WorkspaceManager()\n\t\t// The conversation registry the message source flows from — a supplied one is reused, else a\n\t\t// fresh empty one. Ensure an active conversation so `context.messages` (the active conversation's\n\t\t// live tail) is always defined: when the manager has none active, `add()` a default (which\n\t\t// auto-activates it). NB: `messages` is not captured here — it is computed dynamically (the\n\t\t// getter reads `#conversations.active`), so it always tracks the current active conversation's\n\t\t// live tail, no duplication.\n\t\tthis.#conversations = options?.conversations ?? new ConversationManager()\n\t\tif (this.#conversations.active === undefined) this.#conversations.add()\n\t\tthis.#tools = options?.tools ?? new ToolManager()\n\t\tthis.#scope = options?.scope\n\t}\n\n\tget system(): string | undefined {\n\t\treturn this.#system\n\t}\n\n\tget instructions(): InstructionManagerInterface {\n\t\treturn this.#instructions\n\t}\n\n\tget workspaces(): WorkspaceManagerInterface {\n\t\treturn this.#workspaces\n\t}\n\n\t// Dynamic — the active conversation itself (it owns its live tail + the message verbs directly,\n\t// like a `Workspace` owns its files), always defined: the constructor ensures the registry has an\n\t// active conversation. Computed on every read (never captured), so `context.messages` always\n\t// points at the current active conversation (the same reference — no duplication) and follows a\n\t// `conversations.switch(id)`. The active `Conversation` satisfies the message-verb contract\n\t// directly, so this stays a `MessageManagerInterface`. The `?? this.#ensure()` fallback re-seats\n\t// a default if a caller's supplied manager was emptied (for example `clear()`), so the getter is\n\t// total — never undefined.\n\tget messages(): MessageManagerInterface {\n\t\treturn this.#conversations.active ?? this.#ensure()\n\t}\n\n\tget conversations(): ConversationManagerInterface {\n\t\treturn this.#conversations\n\t}\n\n\tget tools(): ToolManagerInterface {\n\t\treturn this.#tools\n\t}\n\n\tget scope(): ScopeInterface | undefined {\n\t\treturn this.#scope\n\t}\n\n\tapply(scope: ScopeInterface | undefined): void {\n\t\tthis.#scope = scope\n\t}\n\n\tbuild(format?: ContextFormat): readonly Message[] {\n\t\tconst scope = this.#scope\n\t\t// 1–2. Assemble the system block parts: the prompt, then each scoped manager's\n\t\t// section (its resolved `open` + each item's resolved rendering + any resolved\n\t\t// `close`) when it has any scoped-in items. Tools are not folded in — they reach the\n\t\t// provider structurally. Each slot resolves through the format cascade (`resolveOpen` /\n\t\t// `resolveItem` / `resolveClose`): open = manager-options-override > provider-default >\n\t\t// built-in; per item = item-override > manager-options-override > provider-default >\n\t\t// built-in; close = manager-options-override > provider-default (no built-in ⇒ no\n\t\t// closing line). With no `format` arg + no overrides + no per-item `override` it is\n\t\t// byte-for-byte the built-ins (each section's header + items, no closing line).\n\t\tconst parts: string[] = []\n\t\t// Configured by `=== undefined`, not falsiness — an explicitly supplied '' (or a\n\t\t// whitespace-only) system is opted in and prepended verbatim, exactly as the lean\n\t\t// context did (a refactor to a truthiness check would wrongly drop it).\n\t\tif (this.#system !== undefined) parts.push(this.#system)\n\t\tconst instructions = filterAllowList(\n\t\t\tscope?.instructions,\n\t\t\tthis.#instructions.instructions(),\n\t\t\t(one) => one.name,\n\t\t)\n\t\tconst instructed = renderSection(\n\t\t\tresolveOpen(this.#instructions, format?.instructions),\n\t\t\tinstructions,\n\t\t\t(one) => resolveItem(this.#instructions, format?.instructions, one),\n\t\t\tresolveClose(this.#instructions, format?.instructions),\n\t\t)\n\t\tif (instructed !== undefined) parts.push(instructed)\n\t\t// The active workspace's files, rendered by carrier — the sole document/image context.\n\t\t// Filter `active.files()` by `scope.files`, then split: text files fold into the\n\t\t// `## Workspace` system section (fenced reference blocks, the `renderFencedFile` framing — placed\n\t\t// right after the instructions section, grouping the in-prompt text content), image files'\n\t\t// `base64` payload attaches to the last user message (collected below, fed to\n\t\t// `attachUserImages`). `build()` owns this render — a `Workspace` / `WorkspaceManager` stays\n\t\t// file-focused (no `open` / `format` getters). No active workspace ⇒ nothing renders\n\t\t// (active-only).\n\t\tconst files = filterAllowList(\n\t\t\tscope?.files,\n\t\t\tthis.#workspaces.active?.files() ?? [],\n\t\t\t(one) => one.path,\n\t\t)\n\t\tconst workspaceTexts = files.filter((file) => isText(file.content))\n\t\t// The text files have no format-cascade level of their own (they are not a manager) — the\n\t\t// header is the fixed `WORKSPACE_SECTION_HEADER` and each item renders through `renderFencedFile`\n\t\t// off its own text arm (`{ text, language }`), narrowed by `isText` (a total guard, never an\n\t\t// assertion; the preceding pre-filter means the defensive arm is never reached). An empty set\n\t\t// contributes nothing (`renderSection` returns `undefined`).\n\t\tconst documented = renderSection(\n\t\t\tWORKSPACE_SECTION_HEADER,\n\t\t\tworkspaceTexts,\n\t\t\t(file) =>\n\t\t\t\tisText(file.content)\n\t\t\t\t\t? renderFencedFile(file.path, file.content.language, file.content.text)\n\t\t\t\t\t: renderFencedFile(file.path, 'text', ''),\n\t\t\tundefined,\n\t\t)\n\t\tif (documented !== undefined) parts.push(documented)\n\n\t\t// 4. The conversation. The active conversation's `view()` is authoritative (the per-section\n\t\t// summaries + the live tail) — the conversation owns message inclusion through compaction, so the\n\t\t// scope does not filter the conversation here (scope filters only the preceding instructions /\n\t\t// tools / workspace files). The active conversation is always present (the constructor ensures\n\t\t// one), with `#ensure()` as a total fallback if a caller emptied its supplied registry.\n\t\tconst active = this.#conversations.active ?? this.#ensure()\n\t\tconst conversation = active.view()\n\t\t// 5. Attach the active workspace's scoped-in image files' `base64` payload to the last user\n\t\t// message (a vision provider reads images off a user turn) — the active workspace is the\n\t\t// sole image source. Skipped when there is none. (Applies to the conversation's view too.)\n\t\tconst tail = attachUserImages(conversation, collectImageData(files))\n\n\t\t// 3. Prepend one assembled system message only when some part exists.\n\t\tif (parts.length === 0) return tail\n\t\tconst system: Message = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\trole: 'system',\n\t\t\tcontent: parts.join('\\n\\n'),\n\t\t}\n\t\treturn [system, ...tail]\n\t}\n\n\t// The total fallback that keeps `messages` / `build()` defined even if a caller's supplied\n\t// conversation registry was emptied after construction (for example `conversations.clear()`): `add()` a\n\t// default (auto-activating it when the registry is empty) and return it. Returns the\n\t// `ConversationInterface` (which satisfies `MessageManagerInterface` structurally for the\n\t// `messages` getter and carries `view()` for `build()`). Normally never reached — the constructor\n\t// already seeds an active conversation.\n\t#ensure(): ConversationInterface {\n\t\tconst conversation = this.#conversations.add()\n\t\treturn this.#conversations.active ?? conversation\n\t}\n}\n","import type { ChannelInterface } from './types.js'\n\n/**\n * Buffers chunks in a minimal unbounded async channel — the eager pump writes them in (`push`)\n * and ends it (`close` / `fail`) regardless of consumption, while a consumer reads them back live\n * through the `drain` async-iterator. Decoupling write from read is what lets a producer make\n * progress without a consumer pulling, and it is why an agent's `result` settles whether or not\n * its `events` are drained.\n *\n * @remarks\n * The standard resolver-swap: a waiting `drain` parks on `#wake` (a void resolver);\n * `push` / `close` / `fail` enqueue/flag, then fire `#wake` so the parked reader wakes,\n * re-reads the buffer, and either yields the next chunk, returns (on `close`), or throws\n * (on `fail`). Event-free, no `!` / `as` / `any`.\n *\n * @example\n * ```ts\n * import { Channel } from '@orkestrel/agent'\n *\n * const channel = new Channel<number>()\n * channel.push(1)\n * channel.close()\n * for await (const value of channel.drain()) {\n * \tvalue // 1\n * }\n * ```\n */\nexport class Channel<T> implements ChannelInterface<T> {\n\treadonly #buffer: Array<{ value: T }> = []\n\t#wake: (() => void) | undefined\n\t#closed = false\n\t#failure: { error: unknown } | undefined\n\n\tpush(value: T): void {\n\t\tthis.#buffer.push({ value })\n\t\tthis.#signal()\n\t}\n\n\tclose(): void {\n\t\tthis.#closed = true\n\t\tthis.#signal()\n\t}\n\n\tfail(error: unknown): void {\n\t\t// First failure wins; a later close / fail can't override a recorded error.\n\t\tif (this.#failure === undefined) this.#failure = { error }\n\t\tthis.#closed = true\n\t\tthis.#signal()\n\t}\n\n\tasync *drain(): AsyncGenerator<T, void> {\n\t\tfor (;;) {\n\t\t\t// Yield everything buffered before checking for end, so a close / fail that\n\t\t\t// arrives alongside the last chunks still delivers those chunks first.\n\t\t\tfor (let cell = this.#buffer.shift(); cell !== undefined; cell = this.#buffer.shift())\n\t\t\t\tyield cell.value\n\t\t\tif (this.#failure !== undefined) throw this.#failure.error\n\t\t\tif (this.#closed) return\n\t\t\tawait this.#parked()\n\t\t}\n\t}\n\n\t// Resolve the parked reader (if any) and clear the slot — a fresh `#parked()` arms\n\t// the next wait. A `signal` with no parked reader is a no-op (the buffer / flags are\n\t// already set, so the next `drain` pass reads them without parking).\n\t#signal(): void {\n\t\tconst wake = this.#wake\n\t\tthis.#wake = undefined\n\t\twake?.()\n\t}\n\n\t#parked(): Promise<void> {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tthis.#wake = resolve\n\t\t})\n\t}\n}\n","import type {\n\tAgentChunk,\n\tAgentContextInterface,\n\tAgentEventMap,\n\tAgentInterface,\n\tAgentOptions,\n\tAgentResult,\n\tAgentRunOptions,\n\tAgentStatus,\n\tAgentStreamInterface,\n\tAuthorityDecision,\n\tAuthorityInterface,\n\tMessage,\n\tProviderInterface,\n\tProviderResult,\n\tRunOutcome,\n} from './types.js'\nimport type { AbortInterface } from '@orkestrel/abort'\nimport type { BudgetInterface, TokenUsage } from '@orkestrel/budget'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { ToolCall, ToolManagerInterface, ToolResult } from '@orkestrel/tool'\nimport type { SchedulerInterface } from '@orkestrel/workflow'\nimport type { TimeoutInterface } from '@orkestrel/timeout'\nimport { createAbort } from '@orkestrel/abort'\nimport { createTimeout } from '@orkestrel/timeout'\nimport { Emitter } from '@orkestrel/emitter'\nimport { errorToMessage } from '@orkestrel/workflow'\nimport { AgentContext } from './AgentContext.js'\nimport { Channel } from './Channel.js'\nimport { DEFAULT_AGENT_LIMIT } from './constants.js'\nimport { AgentError, isProviderAbortError } from './errors.js'\nimport {\n\tassembleResult,\n\tdenyCall,\n\testimateTokens,\n\tfilterAllowList,\n\tjoinThinking,\n\tsanitizeUsage,\n\tsumUsage,\n} from './helpers.js'\n\n/**\n * Composes a {@link ProviderInterface}, an {@link AgentContext}, and a\n * {@link ToolManagerInterface} into a bounded context → provider → tools → repeat turn, exposed\n * as both a one-shot `generate` and a live `stream` that share one private run — bounded by the\n * run `signal`, the `timeout`, and the `budget` folded through `AbortSignal.any`, paced by\n * `scheduler`, with tool iteration capped at `limit`.\n *\n * @remarks\n * - **One loop, two faces.** A single private async generator (`#run`) drives the\n * whole turn. `stream` kicks off an eager pump that iterates `#run` into a private\n * {@link Channel}, settling `result` from the run's outcome — so `result` settles\n * whether or not the live `events` are drained; `generate` awaits that same\n * settled `result` — so the two can never diverge.\n * - **The turn.** `#run` builds the provider input once (`context.build()` into a\n * working array) then loops up to `limit`: drive `provider.stream(...)` accumulating\n * + yielding each content delta as a `token` chunk; fold the turn's usage into the\n * running total + the `budget` and yield a `usage` chunk; if the model requested\n * tools, append the assistant turn, `execute` them, yield a `tool` chunk per call,\n * append each tool result message, and continue; otherwise append the final\n * assistant message and stop.\n * - **Bounded.** Each run arms one cancel through `createAbort({ signal: AbortSignal.any([\n * …]) })` folding the external `signal`, the `timeout` deadline, and the `budget`\n * signal; `abort()` fires it. Any trip stops the loop and commits a partial result\n * (the `result` promise resolves, never rejects, on a cancel) — only a genuine\n * provider / tool error rejects.\n * - **Paced + capped.** The `scheduler` (when given) `yield`s between turns; tool\n * iteration is capped at `limit`.\n * - **Two observation surfaces.** The pull {@link AgentChunk} stream carries per-token\n * deltas (+ usage/tool chunks); the push {@link emitter} ({@link AgentEventMap}) carries\n * lifecycle + usage/tool/deny moments for fire-and-forget observers. Every event is\n * emitted directly, after the relevant state transition / settle; the emitter isolates a\n * listener throw and routes it to its `error` handler (the `error` option), so a buggy\n * observer can never escape into / reorder / corrupt the settle-once loop — observation is\n * purely a side-channel.\n *\n * @example\n * ```ts\n * const agent = new Agent(provider, { system: 'You are concise.' })\n * agent.context.messages.add({ role: 'user', content: 'Say hi.' })\n * const result = await agent.generate()\n * ```\n */\nexport class Agent implements AgentInterface {\n\treadonly #id: string\n\treadonly #provider: ProviderInterface\n\treadonly #context: AgentContextInterface\n\treadonly #limit: number\n\treadonly #timeoutMs: number | undefined\n\treadonly #budget: BudgetInterface<TokenUsage> | undefined\n\treadonly #scheduler: SchedulerInterface | undefined\n\treadonly #signal: AbortSignal | undefined\n\treadonly #authority: AuthorityInterface | undefined\n\t// The context budget for automatic conversation compaction — its `consumer`\n\t// is a token estimator, its `max` the context window. `#trim` re-measures the absolute current\n\t// prompt against it (clear() + consume(messages)) before the first provider request and between\n\t// turns; `undefined` ⇒ disabled: `#trim` is a no-op and the loop is byte-for-byte the prior\n\t// behavior. Reset (`clear()`) at run entry so no stale `consumed` carries across runs / a\n\t// conversation switch. Not the hard cost `budget` ceiling — when the prompt reaches its `max`\n\t// this compacts + continues (non-fatal on a summarizer throw, futile-guarded), never aborts.\n\treadonly #window: BudgetInterface<readonly Message[]> | undefined\n\t// When true, a summarizer failure during automatic compaction rethrows (after the\n\t// `fault` event) instead of skipping compaction and continuing over-window.\n\treadonly #strict: boolean\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into the loop. No\n\t// `destroy()`: the Agent holds no other teardownable resources, and an `Emitter` owns\n\t// only listener `Set`s (no timers / handles), so it is reclaimed with the agent — there\n\t// is no leak to clear, and adding lifecycle the entity does not otherwise need is avoided.\n\treadonly #emitter: Emitter<AgentEventMap>\n\t// The label the last run settled on. `status` derives the live answer from `#runs`, so an\n\t// overlapping run can never report `done` while another is still in flight.\n\t#settled: AgentStatus = 'idle'\n\t// Every in-flight run's abort handle — a run adds its handle on `stream()` and the\n\t// pump removes it when it settles, so `abort()` fires every live run, not only the\n\t// most recent. Per-run, never a single shared slot a later `stream()` could clobber:\n\t// `generate`/`stream` are reusable and may overlap, and each run must cancel\n\t// independently (its own `stream.abort()` fires its own handle; `agent.abort()` fires\n\t// them all).\n\treadonly #runs = new Set<AbortInterface>()\n\n\tconstructor(provider: ProviderInterface, options?: AgentOptions) {\n\t\tthis.#id = crypto.randomUUID()\n\t\tthis.#provider = provider\n\t\tthis.#context = new AgentContext({\n\t\t\t...(options?.system === undefined ? {} : { system: options.system }),\n\t\t\t...(options?.tools === undefined ? {} : { tools: options.tools }),\n\t\t\t...(options?.instructions === undefined ? {} : { instructions: options.instructions }),\n\t\t\t...(options?.workspaces === undefined ? {} : { workspaces: options.workspaces }),\n\t\t\t...(options?.scope === undefined ? {} : { scope: options.scope }),\n\t\t\t...(options?.conversations === undefined ? {} : { conversations: options.conversations }),\n\t\t})\n\t\tthis.#limit = options?.limit ?? DEFAULT_AGENT_LIMIT\n\t\tthis.#timeoutMs = options?.timeout\n\t\tthis.#budget = options?.budget\n\t\tthis.#scheduler = options?.scheduler\n\t\tthis.#signal = options?.signal\n\t\tthis.#authority = options?.authority\n\t\tthis.#window = options?.window\n\t\tthis.#strict = options?.strict ?? false\n\t\tthis.#emitter = new Emitter<AgentEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget emitter(): EmitterInterface<AgentEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget status(): AgentStatus {\n\t\t// Derived, never stored: a live run outranks any settled label, so overlapping runs can\n\t\t// never report `done` while one is still in flight, and a settled `error` is not erased\n\t\t// by a later run's `done` until that later run itself settles.\n\t\treturn this.#runs.size > 0 ? 'running' : this.#settled\n\t}\n\n\tget context(): AgentContextInterface {\n\t\treturn this.#context\n\t}\n\n\tgenerate(options?: AgentRunOptions): Promise<AgentResult> {\n\t\t// Zero loop logic of its own — start the stream (whose eager pump settles `result`\n\t\t// independently of any consumer) and await that same settled result, so `generate`\n\t\t// and `stream` can never diverge. No manual drain needed: the pump runs regardless.\n\t\treturn this.stream(options).result\n\t}\n\n\tstream(options?: AgentRunOptions): AgentStreamInterface {\n\t\t// Concurrency guard: a run already in flight plus a shared construction-level\n\t\t// accounting instance (a `window` context budget, or a construction `budget` with no\n\t\t// per-run override) would race its charges against that shared instance — corrupting\n\t\t// the accounting. Thrown synchronously, before any state mutation or emit, so a\n\t\t// sequential/awaited caller is never affected and a concurrent run with no `window` and\n\t\t// a per-run `budget` override is still allowed.\n\t\tif (\n\t\t\tthis.#runs.size > 0 &&\n\t\t\t(this.#window !== undefined || (this.#budget !== undefined && options?.budget === undefined))\n\t\t) {\n\t\t\tthrow new AgentError(\n\t\t\t\t'CONCURRENCY',\n\t\t\t\t'concurrent runs on one agent with a shared construction window/budget corrupt accounting; use separate agents or per-run budgets',\n\t\t\t)\n\t\t}\n\t\t// Resolve effective per-run bounds — a per-run override wins, else the\n\t\t// construction default. `limit` and `budget` also thread into `#run` (the loop bound\n\t\t// + the mid-stream charging); `budget` here is the same instance folded into `#parents`,\n\t\t// so its trip both aborts the run and is the budget `#run` charges against.\n\t\tconst timeoutMs = options?.timeout ?? this.#timeoutMs\n\t\tconst timeout = timeoutMs === undefined ? undefined : createTimeout({ ms: timeoutMs })\n\t\ttimeout?.start()\n\t\tconst budget = options?.budget ?? this.#budget\n\t\t// A construction-level budget (`this.#budget`, not a per-run `options?.budget` override) is\n\t\t// a shared cumulative tally across every sequential run on this agent — concurrent streams\n\t\t// on one agent race their charges against the same instance. Use separate agents (or a\n\t\t// per-run `options.budget`) for concurrent streams that must not share a budget.\n\t\tbudget?.start()\n\t\tconst limit = options?.limit ?? this.#limit\n\t\t// Fold every present bound (external signal + a per-run signal + deadline + budget)\n\t\t// into one cancel the run races against; this run's own `abort()` fires this handle.\n\t\tconst signal = this.#parents(timeout, budget, options?.signal)\n\t\tconst abort = createAbort(signal === undefined ? {} : { signal })\n\t\tthis.#runs.add(abort)\n\t\t// Observe the run begin — after the run joins `#runs` (which is what `status` derives\n\t\t// `running` from), so a swallowed listener throw can't perturb the state the pump is\n\t\t// about to drive.\n\t\tthis.#emitter.emit('start', this.id)\n\t\tconst channel = new Channel<AgentChunk>()\n\t\tconst settled = Promise.withResolvers<AgentResult>()\n\t\t// Kick off the eager pump synchronously (not lazily on first `events` pull): it\n\t\t// drives `#run` into the channel and settles `settled` regardless of whether anyone\n\t\t// drains `events`. The per-run `think` / `schema` preferences ride through to\n\t\t// `provider.stream`; `limit` / `budget` ride through as the effective run bounds.\n\t\tvoid this.#pump(\n\t\t\tabort,\n\t\t\ttimeout,\n\t\t\tchannel,\n\t\t\tsettled,\n\t\t\toptions?.think,\n\t\t\toptions?.schema,\n\t\t\tlimit,\n\t\t\tbudget,\n\t\t)\n\t\t// An abandoned handle (neither `events` drained nor `result` awaited) must not surface an\n\t\t// unhandledRejection on a genuine error — guard the public result, where the rejection lives\n\t\t// (#pump's finally rejects `settled` without re-throwing, so the pump promise itself resolves).\n\t\t// A caller who awaits `result` still gets the rejection: `.catch` returns a derived promise, it\n\t\t// does not consume the original's rejection.\n\t\tsettled.promise.catch(() => {})\n\t\treturn {\n\t\t\tevents: this.#events(channel, abort),\n\t\t\tresult: settled.promise,\n\t\t\t// Fire this run's own handle (the closed-over `abort`), never a shared field a\n\t\t\t// later `stream()` could have replaced — so a handle's `abort()` always cancels\n\t\t\t// the run it belongs to, even when runs overlap.\n\t\t\tabort: abort.abort.bind(abort),\n\t\t}\n\t}\n\n\tabort(reason?: unknown): void {\n\t\t// Cancel every in-flight run — iterate a snapshot so a settle-driven `#runs.delete`\n\t\t// (a cancelled run unwinding) can't disturb the walk. Aborting is idempotent, so an\n\t\t// already-finished or already-cancelled handle is a harmless no-op.\n\t\tfor (const abort of [...this.#runs]) abort.abort(reason)\n\t}\n\n\t// The eager pump — the drive behind both faces. Kicked off synchronously in `stream`\n\t// (not lazily on an `events` pull), it drives `#run` and `push`es each chunk into the\n\t// channel as it arrives, then settles `result` from the outcome the generator returns: a\n\t// normal / cancelled finish `close`s the channel and resolves the assembled result (status\n\t// `done`); a genuine provider / tool error (the bound signal not aborted) `fail`s the\n\t// channel and rejects (status `error`). The generator is driven by hand rather than with\n\t// `for await`, which discards a generator's return value — the settled `RunOutcome` is that\n\t// return value, so the run owns its state and nothing is threaded through a caller-held box.\n\t// Because the pump runs regardless of whether anyone drains `events`, `result` always\n\t// settles — that is the fix for the no-drain hang. The deadline `clear()` lives in the\n\t// `finally` so it always fires (drained or not), and `result` settles exactly once through\n\t// the shared resolvers (the underlying promise obeys native settle-once — the first resolve\n\t// / reject wins).\n\tasync #pump(\n\t\tabort: AbortInterface,\n\t\ttimeout: TimeoutInterface | undefined,\n\t\tchannel: Channel<AgentChunk>,\n\t\tsettled: PromiseWithResolvers<AgentResult>,\n\t\tthink: boolean | undefined,\n\t\tschema: Readonly<Record<string, unknown>> | undefined,\n\t\tlimit: number,\n\t\tbudget: BudgetInterface<TokenUsage> | undefined,\n\t): Promise<void> {\n\t\tlet failure: { error: unknown } | undefined\n\t\t// The outcome of a run that produced nothing — replaced by whatever `#run` returns, and\n\t\t// read only on the success path (a genuine failure rejects from `failure` instead).\n\t\tlet outcome: RunOutcome = {\n\t\t\tcontent: '',\n\t\t\tthinking: undefined,\n\t\t\tusage: undefined,\n\t\t\tpartial: false,\n\t\t\texhausted: false,\n\t\t}\n\t\ttry {\n\t\t\tconst run = this.#run(abort, think, schema, limit, budget)\n\t\t\tlet next = await run.next()\n\t\t\twhile (next.done !== true) {\n\t\t\t\tchannel.push(next.value)\n\t\t\t\tnext = await run.next()\n\t\t\t}\n\t\t\toutcome = next.value\n\t\t} catch (error) {\n\t\t\tfailure = { error }\n\t\t} finally {\n\t\t\ttimeout?.clear()\n\t\t\t// This run is settling — drop its handle so a later `agent.abort()` no longer\n\t\t\t// fires it (and the set never leaks finished runs).\n\t\t\tthis.#runs.delete(abort)\n\t\t\tif (failure === undefined) {\n\t\t\t\tthis.#settled = 'done'\n\t\t\t\tchannel.close()\n\t\t\t\tconst result = assembleResult(outcome)\n\t\t\t\tsettled.resolve(result)\n\t\t\t\t// Observe the settle — after `settled.resolve(...)` (the result is already\n\t\t\t\t// settled; emit only observes it). A cancel still resolves a partial, so a\n\t\t\t\t// cancelled run emits `abort` (the cancel reason) then `finish` (the settled\n\t\t\t\t// partial) — observers see both \"it was cancelled\" and the partial outcome; a\n\t\t\t\t// natural / cap finish (`partial: false`) emits `finish` only. Limit exhaustion\n\t\t\t\t// (unresolved tool intent at the turn cap) is not a cancel — it emits `exhaust`\n\t\t\t\t// (the turn count) instead of `abort`, still followed by `finish`. Both emits are\n\t\t\t\t// post-settle, so an isolated listener throw can't reorder the latch.\n\t\t\t\tif (outcome.exhausted) this.#emitter.emit('exhaust', limit)\n\t\t\t\telse if (outcome.partial) this.#emitter.emit('abort', abort.signal.reason)\n\t\t\t\tthis.#emitter.emit('finish', result)\n\t\t\t} else {\n\t\t\t\tthis.#settled = 'error'\n\t\t\t\tchannel.fail(failure.error)\n\t\t\t\tsettled.reject(failure.error)\n\t\t\t\t// Observe the genuine (non-cancel) failure — after `settled.reject(...)`.\n\t\t\t\tthis.#emitter.emit('error', failure.error)\n\t\t\t}\n\t\t}\n\t}\n\n\t// The live event stream: drain the channel the pump writes into, yielding each\n\t// `AgentChunk` as it is pushed (and throwing if the pump `fail`ed the channel). Its\n\t// `return()` — fired when a consumer `break`s out early — fires the turn abort, so the\n\t// run stops promptly: the pump then completes the loop with `partial: true`, `clear`s\n\t// the deadline, and settles `result` to a non-misleading `{ partial: true }` (never the\n\t// old `{ content: '', partial: false }`), leaving `status` no longer `running`.\n\tasync *#events(\n\t\tchannel: Channel<AgentChunk>,\n\t\tabort: AbortInterface,\n\t): AsyncGenerator<AgentChunk, void> {\n\t\ttry {\n\t\t\tyield* channel.drain()\n\t\t} finally {\n\t\t\t// Early break (consumer stopped pulling): cancel the run so the pump unwinds and\n\t\t\t// settles partial. A natural end reaches here too with the signal already done, so\n\t\t\t// this abort is a harmless no-op then.\n\t\t\tabort.abort()\n\t\t}\n\t}\n\n\t// The core loop, shared by generate + stream. Builds the provider input once, then\n\t// iterates up to `limit`: stream the provider (yielding token chunks), fold usage,\n\t// dispatch any tool calls (yielding tool chunks) and continue, else finish. A cancel\n\t// (the bound abort) stops the loop and marks the outcome partial — it never throws;\n\t// only a genuine provider / tool error propagates. The run owns its state: every mutable\n\t// field lives in these locals for the length of one call (so concurrent runs share\n\t// nothing), and the settled `RunOutcome` is what the generator returns to `#pump`.\n\tasync *#run(\n\t\tabort: AbortInterface,\n\t\tthink: boolean | undefined,\n\t\tschema: Readonly<Record<string, unknown>> | undefined,\n\t\tlimit: number,\n\t\tbudget: BudgetInterface<TokenUsage> | undefined,\n\t): AsyncGenerator<AgentChunk, RunOutcome> {\n\t\t// Pass the provider's optional context-framing default into `build()` — the\n\t\t// provider level of the format cascade. An agnostic provider supplies no `format`,\n\t\t// so `build(undefined)` reproduces the managers' built-in framing exactly.\n\t\tconst messages: Message[] = [...this.#context.build(this.#provider.format)]\n\t\tconst tools = this.#context.tools\n\t\tlet content = ''\n\t\tlet thinking: string | undefined\n\t\tlet usage: TokenUsage | undefined\n\t\t// Limit-exhaustion tracking — `pending` is `true` while the most recent turn left\n\t\t// unresolved tool intent (the tool branch was taken and the loop is about to `continue`);\n\t\t// `broke` marks whether the loop exited through an explicit `break` (a cancel, or the natural\n\t\t// final-answer finish) rather than the `for` condition failing. Exhaustion is exactly\n\t\t// \"the condition failed (`!broke`) while tool intent was still pending\" — a `limit: 0` run\n\t\t// never enters the loop, so both stay `false` and the outcome is non-partial.\n\t\tlet pending = false\n\t\tlet broke = false\n\t\tlet partial = false\n\t\tlet exhausted = false\n\t\t// Per-run auto-compaction state — a local, so it starts fresh each run (never carried\n\t\t// across runs or a conversation switch). `futile` is the futile-compaction guard:\n\t\t// once a `compact()` returns `undefined` while still over the window, the prompt can't\n\t\t// shrink further, so auto-compaction stops for the rest of this run (no per-turn churn).\n\t\tlet futile = false\n\t\t// Auto-compaction is enabled only when both a `#window` budget is set and the active\n\t\t// conversation can summarize (`summarizable` — it has a summarizer). There is always an\n\t\t// active conversation, but the default one has no summarizer, so this gate preserves the shipped\n\t\t// behavior: a non-summarizable conversation is never auto-compacted (and the loop never throws\n\t\t// the `compact()` SUMMARIZER error from the auto path). Gating the whole auto-compaction path\n\t\t// (the run-entry `clear()` reset + the pre-first-turn `await this.#trim`) behind this flag keeps\n\t\t// the loop purely additive: with no window or a non-summarizable conversation, no extra `await`\n\t\t// is introduced before the first provider request, so the eager-pump / abort timing is\n\t\t// byte-for-byte the prior behavior (a synchronously-fired abort still lands exactly as before).\n\t\t// When enabled: reset `#window` at run entry so no stale `consumed` carries across runs / a\n\t\t// conversation switch, then run a pre-first-turn `#trim` so a resumed / long conversation whose\n\t\t// initial prompt already exceeds the window compacts at once (not only after a tool turn) —\n\t\t// skipped when already aborted (a pre-aborted run commits its empty partial without compaction).\n\t\tconst compacting =\n\t\t\tthis.#window !== undefined && this.#context.conversations.active?.summarizable === true\n\t\tif (compacting) {\n\t\t\tthis.#window?.clear()\n\t\t\t// Pre-first-turn: `latch: false` — an `undefined` fold here means the tail is too short\n\t\t\t// yet (this run's turns haven't accumulated), not permanently futile, so it must not disable\n\t\t\t// auto-compaction for the run; the growing tail can still fold on the between-turns checks.\n\t\t\tif (!abort.signal.aborted) futile = await this.#trim(messages, false)\n\t\t}\n\t\tfor (let turn = 0; turn < limit; turn += 1) {\n\t\t\t// Observe each iteration begin (the turn index). The emitter isolates a listener\n\t\t\t// throw, so it can't perturb the loop that immediately follows.\n\t\t\tthis.#emitter.emit('turn', turn)\n\t\t\t// Pace between expensive turns — never after the last (the loop body decides). A\n\t\t\t// scheduler honours the signal by rejecting a pending yield on abort (the standard\n\t\t\t// AbortSignal convention), so a cancel landing at the turn boundary surfaces here as\n\t\t\t// a throw, not as the `aborted` check that follows. Treat that exactly like a mid-stream\n\t\t\t// cancel: stop and commit a partial (resolve), never reject — a cancel is not an\n\t\t\t// error. A non-abort yield rejection (a genuine scheduler fault) still propagates.\n\t\t\tif (turn > 0) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#scheduler?.yield({ signal: abort.signal })\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (abort.signal.aborted) {\n\t\t\t\t\t\tpartial = true\n\t\t\t\t\t\tbroke = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (abort.signal.aborted) {\n\t\t\t\tpartial = true\n\t\t\t\tbroke = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// Advertise only the tools the active scope admits — a scoped-out tool is filtered\n\t\t\t// from the definitions handed to the provider, so the model never sees it and thus\n\t\t\t// can't call it (neither described nor callable). `undefined` scope ⇒ all pass.\n\t\t\tconst advertised = filterAllowList(\n\t\t\t\tthis.#context.scope?.tools,\n\t\t\t\ttools.definitions(),\n\t\t\t\t(definition) => definition.name,\n\t\t\t)\n\t\t\tconst definitions = advertised.length > 0 ? advertised : undefined\n\t\t\t// Bounded mid-stream budget enforcement — a per-turn local accumulator (`turnContent`,\n\t\t\t// distinct from the run-spanning `content`) so `charged` (the amount already consumed\n\t\t\t// against `budget` this turn) never mixes with prior turns' content. As each content delta\n\t\t\t// arrives, re-estimate the turn's token footprint so far and consume only the increment\n\t\t\t// over what was already charged — the running `budget.consume` therefore mirrors the live\n\t\t\t// stream instead of waiting for the turn's final usage report. Thinking deltas are not\n\t\t\t// metered here: `#provide` never routes a `'thinking'` delta through `onDelta` (only\n\t\t\t// `'content'` deltas are), so there is no live thinking text to estimate mid-stream — the\n\t\t\t// honest choice given the loop's existing delta wiring; thinking is metered, like content,\n\t\t\t// only through the post-turn usage reconcile that follows (which charges the full reported usage).\n\t\t\tlet charged = 0\n\t\t\tlet turnContent = ''\n\t\t\tlet result: ProviderResult\n\t\t\ttry {\n\t\t\t\tresult = yield* this.#provide(\n\t\t\t\t\tmessages,\n\t\t\t\t\tabort.signal,\n\t\t\t\t\tdefinitions,\n\t\t\t\t\tthink,\n\t\t\t\t\tschema,\n\t\t\t\t\t(delta) => {\n\t\t\t\t\t\tcontent += delta\n\t\t\t\t\t\tturnContent += delta\n\t\t\t\t\t\tconst est = estimateTokens(turnContent)\n\t\t\t\t\t\tif (est > charged) {\n\t\t\t\t\t\t\tbudget?.consume({ prompt: 0, completion: est - charged, total: est - charged })\n\t\t\t\t\t\t\tcharged = est\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t} catch (error) {\n\t\t\t\t// A cancel mid-stream (the bound signal aborted): stop and mark partial. The\n\t\t\t\t// deltas streamed before the cancel were already accumulated into `content`\n\t\t\t\t// through `onDelta`, and a ProviderAbortError's `partial.content` is exactly those\n\t\t\t\t// same yielded deltas (the contract) — so `content` already holds the partial;\n\t\t\t\t// do not re-add it (that double-counts). The separated reasoning has no delta\n\t\t\t\t// channel, though — the abort partial is its only carrier, so harvest it. A\n\t\t\t\t// non-abort error (the signal is not aborted) propagates so the run rejects.\n\t\t\t\tif (abort.signal.aborted) {\n\t\t\t\t\tif (isProviderAbortError(error)) {\n\t\t\t\t\t\tif (error.partial.thinking !== undefined && error.partial.thinking.length > 0) {\n\t\t\t\t\t\t\tthinking = joinThinking(thinking, error.partial.thinking)\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// The abort's partial usage — when the provider observed it mid-stream — is\n\t\t\t\t\t\t// folded and reconciled exactly like the normal post-turn path that follows: the\n\t\t\t\t\t\t// full reported usage sums into `usage`, and only the residual over the\n\t\t\t\t\t\t// mid-stream `charged` estimate is consumed against `budget` (never\n\t\t\t\t\t\t// double-counted). A provider that can't observe usage mid-stream (its\n\t\t\t\t\t\t// final counts never arrive) reports none, and none is fabricated here.\n\t\t\t\t\t\tif (error.partial.usage !== undefined) {\n\t\t\t\t\t\t\t// Sanitize the provider's partial usage before charging/folding it: a\n\t\t\t\t\t\t\t// non-finite or negative field floors to `0`, a fractional field floors to its\n\t\t\t\t\t\t\t// integer part. The normal post-turn usage path is untouched.\n\t\t\t\t\t\t\tconst abortUsage = sanitizeUsage(error.partial.usage)\n\t\t\t\t\t\t\tbudget?.consume({\n\t\t\t\t\t\t\t\tprompt: abortUsage.prompt,\n\t\t\t\t\t\t\t\tcompletion: Math.max(0, abortUsage.completion - charged),\n\t\t\t\t\t\t\t\ttotal: Math.max(0, abortUsage.total - charged),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tusage = sumUsage(usage, abortUsage)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpartial = true\n\t\t\t\t\tbroke = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tif (result.thinking !== undefined && result.thinking.length > 0) {\n\t\t\t\tthinking = joinThinking(thinking, result.thinking)\n\t\t\t}\n\t\t\tif (result.usage !== undefined) {\n\t\t\t\t// Sanitize the provider's normal post-turn usage before charging/folding it,\n\t\t\t\t// exactly like the preceding abort path: a non-finite or negative field floors to `0`, a\n\t\t\t\t// fractional field floors to its integer part. Unsanitized, a buggy provider's\n\t\t\t\t// NaN/negative usage would poison `budget.consumed` and `sumUsage`, and never trip\n\t\t\t\t// exhaustion (`Math.max(0, NaN - charged)` is `NaN`).\n\t\t\t\tconst resultUsage = sanitizeUsage(result.usage)\n\t\t\t\t// Residual reconcile — the earlier mid-stream charges already consumed `charged` worth\n\t\t\t\t// of budget against this turn's completion; charge only what remains of the full\n\t\t\t\t// reported usage so the turn's total budget draw matches `resultUsage` exactly (never\n\t\t\t\t// double-counted). `prompt` was never charged mid-stream (no live prompt-delta channel\n\t\t\t\t// exists), so it is charged here in full. `sumUsage` / the emitted `usage` chunk below\n\t\t\t\t// still carry the full sanitized `resultUsage` — reconciliation affects only the\n\t\t\t\t// budget charge, never the reported usage.\n\t\t\t\tbudget?.consume({\n\t\t\t\t\tprompt: resultUsage.prompt,\n\t\t\t\t\tcompletion: Math.max(0, resultUsage.completion - charged),\n\t\t\t\t\ttotal: Math.max(0, resultUsage.total - charged),\n\t\t\t\t})\n\t\t\t\tusage = sumUsage(usage, resultUsage)\n\t\t\t\t// Observe this turn's usage — the result already exists; emit beside the yield.\n\t\t\t\tthis.#emitter.emit('usage', resultUsage)\n\t\t\t\tyield { category: 'usage', usage: resultUsage }\n\t\t\t}\n\t\t\tif (result.tools !== undefined && result.tools.length > 0) {\n\t\t\t\tconst authorization = this.#authorize(result.tools)\n\t\t\t\tif (abort.signal.aborted) {\n\t\t\t\t\tpartial = true\n\t\t\t\t\tbroke = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconst assistant = this.#context.messages.add({\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: result.content,\n\t\t\t\t\tcalls: result.tools,\n\t\t\t\t})\n\t\t\t\tmessages.push(assistant)\n\t\t\t\tconst results = await this.#dispatch(tools, result.tools, abort.signal, authorization)\n\t\t\t\tfor (let index = 0; index < result.tools.length; index += 1) {\n\t\t\t\t\tconst call = result.tools[index]\n\t\t\t\t\tconst outcomeResult = results[index]\n\t\t\t\t\tif (call === undefined || outcomeResult === undefined) continue\n\t\t\t\t\t// Observe the dispatched tool + its result — beside the existing `tool` yield\n\t\t\t\t\t// (the result already exists). Carries the same pair the chunk carries.\n\t\t\t\t\tthis.#emitter.emit('tool', call, outcomeResult)\n\t\t\t\t\tyield { category: 'tool', call, result: outcomeResult }\n\t\t\t\t\tconst toolMessage = this.#context.messages.add({\n\t\t\t\t\t\trole: 'tool',\n\t\t\t\t\t\tcontent: outcomeResult.success\n\t\t\t\t\t\t\t? JSON.stringify(outcomeResult.value)\n\t\t\t\t\t\t\t: outcomeResult.error,\n\t\t\t\t\t})\n\t\t\t\t\tmessages.push(toolMessage)\n\t\t\t\t}\n\t\t\t\t// Automatic compaction — between turns (this `continue` path: another\n\t\t\t\t// turn follows; never after the final assistant turn that ends the loop, where it\n\t\t\t\t// would be wasted). The same `#trim` the run also ran before the first provider request\n\t\t\t\t// (so a resumed / long conversation whose initial prompt already exceeds the window\n\t\t\t\t// compacts at once). Gated behind `compacting` (window + conversation both present), so\n\t\t\t\t// with auto-compaction off this introduces no extra `await` — the loop is byte-for-byte\n\t\t\t\t// the prior behavior. `latch: true` — by now the tail has accumulated this turn's\n\t\t\t\t// appends, so an `undefined` fold here is genuinely futile, and the run stops\n\t\t\t\t// calling `#trim` for the rest of its turns.\n\t\t\t\tif (compacting && !futile) futile = await this.#trim(messages, true)\n\t\t\t\tpending = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// No tools: this turn's content is the final answer — record it and finish.\n\t\t\tmessages.push(this.#context.messages.add({ role: 'assistant', content: result.content }))\n\t\t\tcontent = result.content\n\t\t\tpending = false\n\t\t\tbroke = true\n\t\t\tbreak\n\t\t}\n\t\t// The loop exhausted `limit` (the `for` condition failed, never a `break`) while the\n\t\t// most recent turn still held unresolved tool intent: commit the outcome partial. Flag it\n\t\t// `exhausted` only when the signal did not abort — a cancel that lands during the last turn's\n\t\t// post-provider work (tool authorize/execute, the residual budget reconcile, between-turns\n\t\t// compaction) also takes this `pending=true; continue` path and exits through the `for` condition\n\t\t// (never a `break`), so `broke` stays `false` even though it was a genuine cancel, not a limit\n\t\t// exhaustion. Checking `abort.signal.aborted` here classifies that case correctly: the pump\n\t\t// then emits `abort` (the cancel reason), never `exhaust`. A `limit: 0` run never enters the\n\t\t// loop (`pending` stays `false`), so it stays non-partial either way.\n\t\tif (!broke && pending) {\n\t\t\tpartial = true\n\t\t\texhausted = !abort.signal.aborted\n\t\t}\n\t\treturn { content, thinking, usage, partial, exhausted }\n\t}\n\n\t// Automatic compaction — the production-hardened context-budget check. Called\n\t// both before the first provider request (a resumed / long conversation compacts at once) and\n\t// between turns. Purely additive: with no `#window` budget or a non-summarizable active conversation\n\t// it is a no-op, so the loop is byte-for-byte the prior behavior — and a conversation that cannot\n\t// summarize (the default one has no summarizer) is never auto-compacted, so the auto path never\n\t// throws the `compact()` SUMMARIZER error. The trigger is the context `#window` budget —\n\t// its `consumer` a token estimator (for example `estimateMessages`), its `max` the context window — the\n\t// same consume-to-a-ceiling primitive as the cost `budget`, but the ceiling action is compaction, not\n\t// abort. It measures the absolute current prompt: `clear()` then `consume(messages)` makes\n\t// `#window.consumed` the estimated footprint of the exact next prompt (the working `messages` array\n\t// = the system block + the conversation's `view()` + this turn's appended messages — the real input\n\t// the next `provider.stream` will receive), and `exhausted` means that prompt has reached `max`.\n\t// Production hardening:\n\t// • Non-fatal summarizer failure — `conversation.compact()` is wrapped: a thrown summarizer error\n\t// does not crash the run; it is surfaced as a `fault` event (observable, never lost) and\n\t// compaction is skipped this turn, then the loop continues (the over-window prompt proceeds to\n\t// the provider). (A manual `conversation.compact()` still propagates — only the auto path here is\n\t// resilient.)\n\t// • Futile-compaction guard (the single-level limit) — when a between-turns `compact()` resolves\n\t// `undefined` (nothing left to fold) while the prompt is still over the window — that is, the live tail\n\t// is at/below `keep` and the over-window is structural (the uncompactable system block + the\n\t// section summaries) so compaction can't reduce further — set the per-run `futile` flag so\n\t// auto-compaction stops for the rest of this run (no per-turn churn). The over-window prompt then\n\t// proceeds to the provider, which surfaces a genuine context-length error if it truly can't fit\n\t// (the real limit). The loop does not churn futilely. The returned flag carries that latch back to\n\t// `#run`, which owns the per-run state and stops calling `#trim` after it is set. `latch`\n\t// gates it: the between-turns check passes `true`; the pre-first-turn check passes `false` —\n\t// there an `undefined` fold means \"nothing to fold yet\" (the live tail hasn't\n\t// accumulated this run's turns), not permanently futile, so it reports `false` and the run's\n\t// growing tail can still fold later. (A `compact()` that does fold a section is never futile\n\t// — the tail shrank; if the rebuilt prompt is still over window the next between-turns\n\t// `undefined` fold latches.)\n\t// No post-compact `clear()` is needed: the next check's `clear()` + `consume` re-measures the\n\t// now-shrunken prompt from scratch. The summarizer call is the conversation's configured\n\t// (best-effort) one, not separately bound to this run's abort signal.\n\tasync #trim(messages: Message[], latch: boolean): Promise<boolean> {\n\t\tconst conversation = this.#context.conversations.active\n\t\t// No window or a non-summarizable active conversation (the default one can't fold) ⇒ the\n\t\t// additive no-op. (Both call sites are gated by `compacting`, so here `conversation` is the\n\t\t// active, summarizable one; this guard keeps `#trim` total.)\n\t\tif (this.#window === undefined || conversation?.summarizable !== true) return false\n\t\tthis.#window.clear()\n\t\tthis.#window.consume(messages)\n\t\tif (!this.#window.exhausted) return false\n\t\tlet section: Awaited<ReturnType<typeof conversation.compact>>\n\t\ttry {\n\t\t\tsection = await conversation.compact()\n\t\t} catch (error) {\n\t\t\t// Surface the summarizer failure observably first (always). Lenient (default): skip\n\t\t\t// compaction this turn and continue over-window. Strict: rethrow after the event so\n\t\t\t// the caught error propagates through `#run` and the run settles `error` instead.\n\t\t\tthis.#emitter.emit('fault', error)\n\t\t\tif (this.#strict) throw error\n\t\t\treturn false\n\t\t}\n\t\t// Nothing folded. On a between-turns check (`latch`) the tail had its chance to grow yet\n\t\t// still won't fold ⇒ genuinely futile: report the latch so the run stops churning and the\n\t\t// over-window prompt reaches the provider. On the pre-first-turn check the tail is\n\t\t// too short yet ⇒ report no latch, leaving later turns free to fold as the tail grows.\n\t\tif (section === undefined) return latch\n\t\t// Rebuild the working array from the (now smaller) compacted view through the same projection the\n\t\t// loop opened with — so the run continues on the system block + compacted `view()`.\n\t\tmessages.splice(0, messages.length, ...this.#context.build(this.#provider.format))\n\t\treturn false\n\t}\n\n\t// Evaluate policy and emit denials before the run's final pre-dispatch abort guard:\n\t// policy callbacks and denial listeners can cancel the run synchronously.\n\t#authorize(calls: readonly ToolCall[]) {\n\t\tif (this.#authority === undefined) return undefined\n\t\tconst authority = this.#authority\n\t\tconst allowed: ToolCall[] = []\n\t\tconst denials = new Map<string, ToolResult>()\n\t\tfor (const call of calls) {\n\t\t\t// A security gate must fail closed: if a policy `evaluate` throws, the call is not\n\t\t\t// cleared, so it must not run. Synthesize a denial (carrying the error's message)\n\t\t\t// instead of letting the throw reject the whole run — the tool stays unexecuted and\n\t\t\t// the model still sees a denial it can react to, exactly like an explicit `deny`.\n\t\t\tlet decision: AuthorityDecision\n\t\t\ttry {\n\t\t\t\tdecision = authority.evaluate({ call })\n\t\t\t} catch (error) {\n\t\t\t\t// The declared `@orkestrel/workflow` normalizer, so a fail-closed denial carries a\n\t\t\t\t// non-empty explanation the model can read: an `Error` with an empty `message`\n\t\t\t\t// normalizes to real text, and a throw whose stringification itself fails is caught\n\t\t\t\t// rather than escaping the gate and rejecting the run.\n\t\t\t\tconst reason = errorToMessage(error)\n\t\t\t\tdenials.set(call.id, denyCall(call, reason))\n\t\t\t\t// Observe the fail-closed denial with the thrown reason.\n\t\t\t\tthis.#emitter.emit('deny', call, reason)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (decision.allowed) allowed.push(call)\n\t\t\telse {\n\t\t\t\tdenials.set(call.id, denyCall(call, decision.reason))\n\t\t\t\t// Observe the explicit denial (the call + the rule's reason).\n\t\t\t\tthis.#emitter.emit('deny', call, decision.reason)\n\t\t\t}\n\t\t}\n\t\treturn { allowed, denials }\n\t}\n\n\t// Carry cancellation into entered handlers, then merge executed results and denials\n\t// in call order. An all-denied turn costs no tool run.\n\tasync #dispatch(\n\t\ttools: ToolManagerInterface,\n\t\tcalls: readonly ToolCall[],\n\t\tsignal: AbortSignal,\n\t\tauthorization:\n\t\t\t| {\n\t\t\t\t\treadonly allowed: readonly ToolCall[]\n\t\t\t\t\treadonly denials: ReadonlyMap<string, ToolResult>\n\t\t\t }\n\t\t\t| undefined,\n\t): Promise<readonly ToolResult[]> {\n\t\tif (authorization === undefined) return tools.execute(calls, { signal })\n\t\tconst { allowed, denials } = authorization\n\t\tconst executed = allowed.length > 0 ? await tools.execute(allowed, { signal }) : []\n\t\tconst byId = new Map<string, ToolResult>(denials)\n\t\tfor (const result of executed) byId.set(result.id, result)\n\t\treturn calls.map((call) => byId.get(call.id) ?? denyCall(call, undefined))\n\t}\n\n\t// Drive one provider stream turn: read each {@link ProviderDelta}'s `channel` — a\n\t// `'content'` delta is the answer (fed back through `onDelta`, surfaced as a\n\t// `token` chunk); a `'thinking'` delta is live reasoning (surfaced as a `think` chunk,\n\t// never fed into `onDelta` — reasoning is not answer content) — returning the provider's\n\t// assembled result. The per-run `think` / `schema` preferences ride into `provider.stream`\n\t// as {@link ProviderStreamOptions}, composed together — keys are omitted when undefined, so\n\t// the provider receives no options object at all when both are absent (preserving the prior\n\t// think-only behavior exactly). Kept separate so the loop reads as one straight line.\n\tasync *#provide(\n\t\tmessages: readonly Message[],\n\t\tsignal: AbortSignal,\n\t\tdefinitions: ReturnType<ToolManagerInterface['definitions']> | undefined,\n\t\tthink: boolean | undefined,\n\t\tschema: Readonly<Record<string, unknown>> | undefined,\n\t\tonDelta: (delta: string) => void,\n\t): AsyncGenerator<AgentChunk, ProviderResult> {\n\t\tconst options: { think?: boolean; schema?: Readonly<Record<string, unknown>> } = {}\n\t\tif (think !== undefined) options.think = think\n\t\tif (schema !== undefined) options.schema = schema\n\t\tconst generator = this.#provider.stream(\n\t\t\tmessages,\n\t\t\tsignal,\n\t\t\tdefinitions,\n\t\t\tObject.keys(options).length > 0 ? options : undefined,\n\t\t)\n\t\tlet next = await generator.next()\n\t\twhile (!next.done) {\n\t\t\tconst delta = next.value\n\t\t\tif (delta.channel === 'content') {\n\t\t\t\tonDelta(delta.text)\n\t\t\t\tyield { category: 'token', content: delta.text }\n\t\t\t} else {\n\t\t\t\tyield { category: 'think', content: delta.text }\n\t\t\t}\n\t\t\tnext = await generator.next()\n\t\t}\n\t\treturn next.value\n\t}\n\n\t// The parent signal for a run's abort: the external signal, an optional per-run signal\n\t// (composed with, never replacing, the construction `signal`), the deadline, and the\n\t// effective budget (a per-run override, else the construction `budget`) folded through\n\t// `AbortSignal.any` — or a lone present one, or `undefined` when none.\n\t#parents(\n\t\ttimeout: TimeoutInterface | undefined,\n\t\tbudget: BudgetInterface<TokenUsage> | undefined,\n\t\tsignal: AbortSignal | undefined,\n\t): AbortSignal | undefined {\n\t\tconst signals: AbortSignal[] = []\n\t\tif (this.#signal !== undefined) signals.push(this.#signal)\n\t\tif (signal !== undefined) signals.push(signal)\n\t\tif (timeout !== undefined) signals.push(timeout.signal)\n\t\tif (budget !== undefined) signals.push(budget.signal)\n\t\tif (signals.length === 0) return undefined\n\t\tif (signals.length === 1) return signals[0]\n\t\treturn AbortSignal.any(signals)\n\t}\n}\n","import type {\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentOptions,\n\tAgentRegistryInterface,\n\tAgentRegistryOptions,\n\tAuthorityInterface,\n\tConversationStoreInterface,\n\tProviderInterface,\n} from './types.js'\nimport type { BudgetInterface, TokenUsage } from '@orkestrel/budget'\nimport type { ToolInterface } from '@orkestrel/tool'\nimport type { SchedulerInterface } from '@orkestrel/workflow'\nimport { createTokenBudget } from '@orkestrel/budget'\nimport { ToolManager } from '@orkestrel/tool'\nimport { Agent } from './Agent.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport { AgentError } from './errors.js'\n\n/**\n * Makes a durable, JSON-serializable {@link AgentJobInput} runnable — holds the named pools of\n * live, non-serializable pieces (providers, tools, authorities, schedulers), throws on a name\n * absent from its pool, and `build`s a seeded, signal-wired {@link Agent} from a job's names and\n * data.\n *\n * @remarks\n * - **Why it exists.** An `AgentJobInput` is serializable so it can survive a crash in a\n * Queue's store; the live objects it needs (a provider with sockets, tools / rules /\n * schedulers carrying functions) cannot serialize. The registry closes that gap:\n * construct it once with the live pools, then a queue / runner handler calls `build`\n * on each (possibly restored) job to get a ready agent.\n * - **Accessors throw on a miss.** `provider` / `tool` / `authority` / `scheduler` resolve a\n * name against their pool and throw an {@link AgentError} carrying `code: 'REGISTRY'` and\n * the message `unknown <category>: <name>` when it is absent — an unknown name in a\n * rehydrated job is a programmer / config error that must fail loudly at build time, never\n * silently resolve to `undefined` and run an agent missing a dependency.\n * - **`build` rehydrates.** Resolve the job's `provider`; assemble a fresh\n * {@link ToolManager} from the `tools` names; rebuild the token `budget` from its\n * ceiling (`createTokenBudget({ max })`); resolve the optional `authority` /\n * `scheduler` names; construct the {@link Agent} with `system` / `limit` / `timeout` /\n * the threaded `signal`; seed its context with the job's `messages`; return it. The\n * `signal` is the queue attempt's / runner unit's cancel, so a bounded abort propagates\n * into the agent (which commits a partial — the job's `partial` policy then\n * decides success vs. retry).\n * - **Event-free.** A pure resolver — no Emitter, no events.\n *\n * @example\n * ```ts\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const registry = new AgentRegistry({ providers: { main: provider } })\n * const agent = registry.build({ provider: 'main', messages: [{ role: 'user', content: 'Say ok.' }] })\n * const result = await agent.generate()\n * ```\n */\nexport class AgentRegistry implements AgentRegistryInterface {\n\treadonly #providers: ReadonlyMap<string, ProviderInterface>\n\treadonly #tools: ReadonlyMap<string, ToolInterface>\n\treadonly #authorities: ReadonlyMap<string, AuthorityInterface>\n\treadonly #schedulers: ReadonlyMap<string, SchedulerInterface>\n\treadonly #store: ConversationStoreInterface | undefined\n\n\tconstructor(options: AgentRegistryOptions) {\n\t\tthis.#providers = new Map(Object.entries(options.providers))\n\t\tthis.#tools = new Map(Object.entries(options.tools ?? {}))\n\t\tthis.#authorities = new Map(Object.entries(options.authorities ?? {}))\n\t\tthis.#schedulers = new Map(Object.entries(options.schedulers ?? {}))\n\t\tthis.#store = options.store\n\t}\n\n\tprovider(name: string): ProviderInterface {\n\t\treturn this.#resolve(this.#providers, 'provider', name)\n\t}\n\n\ttool(name: string): ToolInterface {\n\t\treturn this.#resolve(this.#tools, 'tool', name)\n\t}\n\n\tauthority(name: string): AuthorityInterface {\n\t\treturn this.#resolve(this.#authorities, 'authority', name)\n\t}\n\n\tscheduler(name: string): SchedulerInterface {\n\t\treturn this.#resolve(this.#schedulers, 'scheduler', name)\n\t}\n\n\tbuild(input: AgentJobInput, signal?: AbortSignal): AgentInterface {\n\t\tconst provider = this.provider(input.provider)\n\t\tconst agent = new Agent(provider, this.#options(input, signal))\n\t\t// Seed the conversation onto the rehydrated agent's context — the serializable\n\t\t// MessageInputs become stored messages (each id minted by the manager).\n\t\tfor (const message of input.messages) agent.context.messages.add(message)\n\t\treturn agent\n\t}\n\n\t// Assemble the AgentOptions for one job: a fresh ToolManager loaded from the named\n\t// tools, the rebuilt token budget, the resolved authority / scheduler, plus the data\n\t// fields and the threaded cancel. Optional fields are omitted (not set to `undefined`)\n\t// so the Agent's `?? default` fallbacks behave exactly as for a hand-built agent. When\n\t// the registry carries a conversation store, thread a fresh store-backed\n\t// ConversationManager for this build (a fresh conversation id per build ⇒ no\n\t// collisions in the shared store) — omitted when no store is set, so the shape stays\n\t// byte-identical to a registry with no `store`.\n\t#options(input: AgentJobInput, signal: AbortSignal | undefined): AgentOptions {\n\t\tconst budget = this.#budget(input.budget)\n\t\treturn {\n\t\t\ttools: this.#manager(input.tools),\n\t\t\t...(input.system === undefined ? {} : { system: input.system }),\n\t\t\t...(input.limit === undefined ? {} : { limit: input.limit }),\n\t\t\t...(input.timeout === undefined ? {} : { timeout: input.timeout }),\n\t\t\t...(budget === undefined ? {} : { budget }),\n\t\t\t...(input.authority === undefined ? {} : { authority: this.authority(input.authority) }),\n\t\t\t...(input.scheduler === undefined ? {} : { scheduler: this.scheduler(input.scheduler) }),\n\t\t\t...(this.#store === undefined\n\t\t\t\t? {}\n\t\t\t\t: { conversations: new ConversationManager({ store: this.#store }) }),\n\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t}\n\t}\n\n\t// A fresh tool registry loaded with the named tools (each resolved — an unknown name\n\t// throws). Always a new manager per build, so concurrent jobs never share one.\n\t#manager(names: readonly string[] | undefined): ToolManager {\n\t\tconst manager = new ToolManager()\n\t\tif (names !== undefined) for (const name of names) manager.add(this.tool(name))\n\t\treturn manager\n\t}\n\n\t// Rebuild a token budget from a job's serializable ceiling — `undefined` when the job\n\t// declared none (no bound), else a fresh `createTokenBudget({ max })`.\n\t#budget(max: number | undefined): BudgetInterface<TokenUsage> | undefined {\n\t\treturn max === undefined ? undefined : createTokenBudget({ max })\n\t}\n\n\t// Resolve a name against a pool, throwing a coded, loud error on a miss — an unknown name\n\t// in a rehydrated job is a programmer error and must not pass.\n\t#resolve<T>(pool: ReadonlyMap<string, T>, category: string, name: string): T {\n\t\tconst value = pool.get(name)\n\t\tif (value === undefined) throw new AgentError('REGISTRY', `unknown ${category}: ${name}`)\n\t\treturn value\n\t}\n}\n","import type {\n\tAuthorityContext,\n\tAuthorityDecision,\n\tAuthorityInterface,\n\tAuthorityOptions,\n\tAuthorityRule,\n} from './types.js'\nimport { DEFAULT_AUTHORITY_ZONE } from './constants.js'\n\n/**\n * Gates the agent loop's tool calls — the synchronous policy consulted before each call runs,\n * turning one {@link AuthorityContext} into an {@link AuthorityDecision} by walking the ordered\n * rules first-match-wins and falling back to a configurable default, which allows an unmatched\n * call unless its `fallback` denies.\n *\n * @remarks\n * - **Ordered, first-match-wins.** `evaluate` walks the configured rules in order and\n * returns the first whose `match(context)` is true as\n * `{ zone, allowed: rule.allowed ?? true, reason }` — a matched rule allows by\n * default and denies only when its `allowed` is explicitly `false`.\n * - **Fallback.** When no rule matches, `evaluate` returns the configured `fallback`.\n * It defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }` (allow-unmatched),\n * so a rules list of denials behaves as a denylist. To make the gate deny-by-default\n * (an allowlist — only matched rules that allow get through), pass an `allowed: false`\n * `fallback`.\n * - **Consulted before each tool call.** The agent loop calls `evaluate({ call })` for\n * every {@link import('@orkestrel/tool').ToolCall} the model emits; a denied call is fed\n * back to the model as a denial {@link import('@orkestrel/tool').ToolResult} (a `tool`\n * chunk + a tool message) instead of being executed — no tool run, no budget cost —\n * so the model sees the denial and can react.\n * - **Synchronous.** `evaluate` returns the verdict directly.\n * - **Event-free.** A purely functional gate — no Emitter, no events.\n *\n * @example\n * ```ts\n * // A denylist: deny the `delete` tool, allow everything else (default fallback).\n * const authority = new Authority({\n * \trules: [{ match: (c) => c.call.name === 'delete', zone: 'restricted', allowed: false }],\n * })\n * authority.evaluate({ call: { id: '1', name: 'delete', arguments: {} } }) // { zone: 'restricted', allowed: false }\n * authority.evaluate({ call: { id: '2', name: 'add', arguments: {} } }) // { zone: 'default', allowed: true }\n * ```\n */\nexport class Authority implements AuthorityInterface {\n\treadonly #rules: readonly AuthorityRule[]\n\treadonly #fallback: AuthorityDecision\n\n\tconstructor(options?: AuthorityOptions) {\n\t\tthis.#rules = options?.rules ?? []\n\t\tthis.#fallback = options?.fallback ?? { zone: DEFAULT_AUTHORITY_ZONE, allowed: true }\n\t}\n\n\tevaluate(context: AuthorityContext): AuthorityDecision {\n\t\tfor (const rule of this.#rules) {\n\t\t\tif (rule.match(context))\n\t\t\t\treturn {\n\t\t\t\t\tzone: rule.zone,\n\t\t\t\t\tallowed: rule.allowed ?? true,\n\t\t\t\t\t...(rule.reason === undefined ? {} : { reason: rule.reason }),\n\t\t\t\t}\n\t\t}\n\t\treturn this.#fallback\n\t}\n}\n","import type { ConversationSnapshot, Message, Section } from './types.js'\nimport { arrayOf, attempt, isArray, isRecord, isString } from '@orkestrel/contract'\nimport { isToolCall } from '@orkestrel/tool'\n\n/**\n * Checks whether a value satisfies the domain conversation-message contract.\n *\n * @remarks\n * Roles belong to MessageRole and image elements are strings. Tool arguments may\n * carry non-JSON values, as the domain type permits; the message wire contract is\n * narrower. Unreadable fields and hostile inputs return false.\n *\n * @param value - The unknown message candidate\n * @returns True if the domain message fields are valid; false otherwise\n * @example\n * ```ts\n * isMessage({ id: '1', role: 'user', content: 'hi' }) // true\n * isMessage({ id: '1', role: 'other', content: '' }) // false\n * isMessage({ id: '1', role: 'user', content: '', images: [1] }) // false\n * ```\n */\nexport function isMessage(value: unknown): value is Message {\n\tconst checked = attempt(() => {\n\t\tif (!isRecord(value)) return false\n\t\tconst { id, role, content, calls, images } = value\n\t\tif (!isString(id) || !isString(content)) return false\n\t\tif (role !== 'system' && role !== 'user' && role !== 'assistant' && role !== 'tool')\n\t\t\treturn false\n\t\tif (calls !== undefined && !arrayOf(isToolCall)(calls)) return false\n\t\treturn images === undefined || arrayOf(isString)(images)\n\t})\n\treturn checked.success && checked.value\n}\n\n/**\n * Checks whether an `unknown` is structurally a {@link Section} record — a `string` `id` and\n * `summary` beside a `messages` array of valid {@link Message}s, the per-section step of the\n * {@link isConversationSnapshot} read-boundary narrow. Total, never throwing, and never an\n * assertion.\n *\n * @remarks\n * A total guard (it never throws — adversarial input returns `false`). It checks the section's\n * shape: a record with a `string` `id`, a `string` `summary`, and a `messages` array every element\n * of which is a valid {@link Message} record ({@link isMessage}). Enough to safely impose\n * the {@link Section} type at a storage boundary without a cast.\n *\n * @param value - The value to test (one element of a snapshot's `sections` array)\n * @returns True if `value` has the structural shape of a {@link Section}; false otherwise\n *\n * @example\n * ```ts\n * isSection({ id: 's', summary: 'recap', messages: [{ id: '1', role: 'user', content: 'hi' }] }) // true\n * isSection({ id: 's', summary: 'recap', messages: 'nope' }) // false\n * isSection({ id: 's', messages: [] }) // false (missing summary)\n * ```\n */\nexport function isSection(value: unknown): value is Section {\n\tif (!isRecord(value)) return false\n\tif (!isString(value.id) || !isString(value.summary)) return false\n\treturn isArray(value.messages) && value.messages.every(isMessage)\n}\n\n/**\n * Narrows an `unknown` to a {@link ConversationSnapshot} — a `string` `id`, an optional `string`\n * `summary`, and valid `sections` and `messages` arrays; the total boundary guard for an\n * untrusted snapshot read (a storage row a\n * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}\n * reads back from its opaque JSON column, a snapshot loaded from disk), never throwing. The exact\n * analogue of {@link import('@orkestrel/workspace').isWorkspaceSnapshot}.\n *\n * @remarks\n * A total guard (it never throws — adversarial input returns `false`). It checks the snapshot's\n * shape: a `string` `id`, an optional `string` `summary` (present-or-absent — the rollup is\n * `undefined` until the first compaction), a `sections` array every element of which is a valid\n * {@link Section} ({@link isSection}), and a `messages` array every element of which is a\n * valid {@link Message} ({@link isMessage}) — enough to safely impose the\n * {@link ConversationSnapshot} type at a storage boundary without a cast. The structural twin of\n * {@link import('@orkestrel/workspace').isWorkspaceSnapshot}. A malformed blob (a non-record, a missing / non-string `id`, a\n * non-string `summary` when present, a non-array `sections` / `messages`, or any malformed\n * element) resolves `false`, so a\n * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}\n * read yields `undefined` rather than a broken conversation.\n *\n * @param value - The value to test (an opaque storage read)\n * @returns True if `value` has the structural shape of a {@link ConversationSnapshot}; false otherwise\n *\n * @example\n * ```ts\n * isConversationSnapshot({ id: 'c1', sections: [], messages: [] }) // true\n * isConversationSnapshot({ id: 'c1', summary: 'recap', sections: [], messages: [] }) // true\n * isConversationSnapshot({ id: 'c1', sections: 'nope', messages: [] }) // false\n * isConversationSnapshot({ sections: [], messages: [] }) // false (missing id)\n * ```\n */\nexport function isConversationSnapshot(value: unknown): value is ConversationSnapshot {\n\tif (!isRecord(value)) return false\n\tif (!isString(value.id)) return false\n\tif (value.summary !== undefined && !isString(value.summary)) return false\n\tif (!isArray(value.sections) || !value.sections.every(isSection)) return false\n\treturn isArray(value.messages) && value.messages.every(isMessage)\n}\n","import type {\n\tConversationSnapshot,\n\tConversationSnapshotRow,\n\tConversationStoreInterface,\n} from '../../types.js'\nimport type { TableInterface } from '@orkestrel/database'\nimport { isConversationSnapshot } from '../../validators.js'\n\n/**\n * Backs a {@link ConversationStoreInterface} with one table of the `databases` layer — a\n * conversation's durable state is a row holding the snapshot as one opaque JSON column, narrowed\n * back on `get` by {@link import('../../validators.js').isConversationSnapshot}, so persistence\n * reduces to keyed point-access (`get` / `set` / `delete`) over a {@link TableInterface}. The\n * driver-pluggable twin of the plain-`Map`\n * {@link import('./MemoryConversationStore.js').MemoryConversationStore}, and the exact twin of\n * {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}.\n *\n * @remarks\n * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,\n * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /\n * IndexedDB backend swaps in without touching the\n * {@link import('../ConversationManager.js').ConversationManager} or the\n * {@link import('../Conversation.js').Conversation} — the same seam as\n * {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}. The\n * driver defaults to memory ({@link import('../../factories.js').createDatabaseConversationStore}\n * passes `createMemoryDriver()`), so it also works in memory out of the box; you opt into the\n * durable plumbing by passing a JSON / SQLite / IndexedDB driver.\n *\n * The {@link ConversationSnapshot} is stored as one opaque JSON column — the table is a row of\n * `{ id; snapshot }` ({@link ConversationSnapshotRow}), the snapshot the whole JSON blob (a\n * `rawShape` column the factory builds) — exactly as `DatabaseWorkspaceStore` stores its snapshot.\n * The snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is\n * lossless and keeps the row type flat (`snapshot` reads back as `unknown`).\n *\n * - **`set(snapshot)` upserts under the snapshot's own `id`** (no separate id param) — it writes\n * the row `{ id: snapshot.id, snapshot }`.\n * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to\n * a {@link ConversationSnapshot} ({@link import('../../validators.js').isConversationSnapshot} — the\n * total guard for an untrusted storage read), or `undefined` if none is stored.\n * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * Unlike a session store there is no idle-TTL / eviction — a persisted conversation lives until an\n * explicit `delete`. The public surface is exactly `get` / `set` / `delete` — no extra members (the\n * method bijection with {@link ConversationStoreInterface}). Hydration stays a caller concern: a\n * {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds\n * the live conversation through the `snapshot` option (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createConversation, createDatabaseConversationStore } from '@orkestrel/agent'\n * import { createMemoryDriver } from '@orkestrel/database'\n *\n * const store = createDatabaseConversationStore(createMemoryDriver()) // a durable driver swaps in here\n * const conversation = createConversation()\n * conversation.add({ role: 'user', content: 'hello' })\n * await store.set(conversation.snapshot()) // persist the conversation (one JSON column)\n * const snapshot = await store.get(conversation.id)\n * await store.delete(conversation.id) // drop it\n * ```\n */\nexport class DatabaseConversationStore implements ConversationStoreInterface {\n\treadonly #table: TableInterface<ConversationSnapshotRow>\n\n\t/**\n\t * Wraps a table as a conversation store.\n\t *\n\t * @param table - The {@link TableInterface} holding the snapshots — its row is the\n\t * {@link ConversationSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)\n\t */\n\tconstructor(table: TableInterface<ConversationSnapshotRow>) {\n\t\tthis.#table = table\n\t}\n\n\t/** Resolves the persisted snapshot for `id`, narrowing the opaque JSON column back to a `ConversationSnapshot`. */\n\tasync get(id: string): Promise<ConversationSnapshot | undefined> {\n\t\tconst row = await this.#table.get(id)\n\t\tif (row === undefined) return undefined\n\t\t// The snapshot crosses back as an untrusted storage read (a structured clone / a JSON row),\n\t\t// so narrow the opaque JSON column with the total boundary guard rather than a cast;\n\t\t// a malformed blob resolves `undefined`, never a broken conversation.\n\t\treturn isConversationSnapshot(row.snapshot) ? row.snapshot : undefined\n\t}\n\n\t/** Inserts or replaces under the snapshot's own `id` (no separate id param) — the row is `{ id, snapshot }`. */\n\tasync set(snapshot: ConversationSnapshot): Promise<void> {\n\t\tawait this.#table.set({ id: snapshot.id, snapshot })\n\t}\n\n\t/** Drops a snapshot by id; an absent id is a no-op (no throw). */\n\tasync delete(id: string): Promise<void> {\n\t\tawait this.#table.remove(id)\n\t}\n}\n","import type { ConversationSnapshot, ConversationStoreInterface } from '../../types.js'\n\n/**\n * Implements the {@link ConversationStoreInterface} in memory — a process-lifetime `Map` of\n * {@link ConversationSnapshot}s keyed by conversation id, the default store\n * {@link import('../../factories.js').createMemoryConversationStore} builds and the default\n * backing for `open` / `save`. The exact twin of\n * {@link import('@orkestrel/workspace').MemoryWorkspaceStore}.\n *\n * @remarks\n * A plain `Map<string, ConversationSnapshot>` — the snapshot is already pure,\n * self-contained JSON, so no encoding is needed for the memory tier. Like the\n * {@link import('@orkestrel/workspace').MemoryWorkspaceStore} it twins,\n * there is no idle-TTL and no eviction: a persisted conversation lives until an explicit `delete`. A\n * durable backend (JSON / SQLite / IndexedDB) swaps in through the same interface without touching\n * the {@link import('../ConversationManager.js').ConversationManager} or the\n * {@link import('../Conversation.js').Conversation} — its driver-pluggable twin is\n * {@link import('./DatabaseConversationStore.js').DatabaseConversationStore} (the snapshot as one\n * opaque JSON column).\n *\n * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.\n * - **`set` inserts / replaces under the snapshot's own `id`** (no separate id param).\n * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * The public surface is exactly `get` / `set` / `delete` — no extra members (the method\n * bijection with {@link ConversationStoreInterface}). Hydration is a caller concern: a\n * {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds\n * the live conversation through the `snapshot` option (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createConversation, createMemoryConversationStore } from '@orkestrel/agent'\n *\n * const store = createMemoryConversationStore()\n * const conversation = createConversation()\n * conversation.add({ role: 'user', content: 'hello' })\n * await store.set(conversation.snapshot()) // persist the conversation\n * const snapshot = await store.get(conversation.id)\n * await store.delete(conversation.id) // drop it\n * ```\n */\nexport class MemoryConversationStore implements ConversationStoreInterface {\n\treadonly #snapshots = new Map<string, ConversationSnapshot>()\n\n\t/**\n\t * Resolves the persisted snapshot for `id`, or `undefined` if none is stored.\n\t *\n\t * @param id - The conversation id to resolve (a {@link ConversationSnapshot.id})\n\t * @returns The persisted snapshot, or `undefined` if absent\n\t */\n\tget(id: string): Promise<ConversationSnapshot | undefined> {\n\t\treturn Promise.resolve(this.#snapshots.get(id))\n\t}\n\n\t/**\n\t * Inserts or replaces a snapshot under its own `snapshot.id` (no separate id param —\n\t * mirroring {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`).\n\t *\n\t * @param snapshot - The snapshot to store (keyed by its `id`)\n\t * @returns A promise that resolves after the snapshot is stored\n\t */\n\tset(snapshot: ConversationSnapshot): Promise<void> {\n\t\t// Insert / replace under the snapshot's own id (no separate id param).\n\t\tthis.#snapshots.set(snapshot.id, snapshot)\n\t\treturn Promise.resolve()\n\t}\n\n\t/**\n\t * Drops a snapshot by id; an absent id is a no-op (no throw).\n\t *\n\t * @param id - The conversation id to drop\n\t * @returns A promise that resolves after the snapshot is dropped\n\t */\n\tdelete(id: string): Promise<void> {\n\t\t// Drop by id; `Map.delete` of an absent id is already a no-op (no throw).\n\t\tthis.#snapshots.delete(id)\n\t\treturn Promise.resolve()\n\t}\n}\n","import type { ToolDefinition } from '@orkestrel/tool'\nimport type {\n\tAgentProviderInput,\n\tAgentProviderInterface,\n\tContextFormat,\n\tMessage,\n\tProviderDelta,\n\tProviderIncrement,\n\tProviderOptions,\n\tProviderParserInterface,\n\tProviderRequest,\n\tProviderResult,\n\tProviderStreamOptions,\n\tThinkSplitterInterface,\n} from './types.js'\nimport { Timeout } from '@orkestrel/timeout'\nimport { DEFAULT_PROVIDER_TIMEOUT, MAX_ERROR_BODY_LENGTH } from './constants.js'\nimport { ProviderAbortError, ProviderError } from './errors.js'\nimport { createThinkSplitter } from './factories.js'\nimport { buildProviderResult, joinThinking, readChunks, readText } from './helpers.js'\n\n/**\n * Implements bounded HTTP streaming and result assembly behind concrete wire seams.\n *\n * @remarks\n * Every call owns its parser, splitter, deadline, and accumulation. Success bodies\n * have no size limit. A qwen3 implicit-open reclassification corrects the final\n * content while content deltas already yielded cannot be recalled. A subclass fills\n * `name`, `frame`, `body`, `read`, and `finish`; the constructor takes the `split`\n * and `strict` switches to control reasoning separation and settled-result requirements.\n *\n * @example Writing a provider for a new wire\n * ```ts\n * import type {\n * \tProviderIncrement,\n * \tProviderOptions,\n * \tProviderParserInterface,\n * \tProviderRequest,\n * } from '@orkestrel/agent'\n * import { AgentProvider } from '@orkestrel/agent'\n *\n * class TextFrame implements ProviderParserInterface<string> {\n * \tparse(chunk: string): readonly string[] {\n * \t\treturn [chunk]\n * \t}\n * \tclear(): void {} // Raw text retains no framing state.\n * }\n *\n * interface TextOptions extends ProviderOptions {\n * \treadonly url: string\n * }\n *\n * class TextProvider extends AgentProvider<string> {\n * \treadonly name = 'text'\n * \tconstructor(options: TextOptions) {\n * \t\tsuper({ ...options, path: '/generate' })\n * \t}\n * \tframe(): ProviderParserInterface<string> {\n * \t\treturn new TextFrame()\n * \t}\n * \tbody(request: ProviderRequest): object {\n * \t\treturn { messages: request.messages }\n * \t}\n * \tread(record: string): ProviderIncrement {\n * \t\treturn { content: record, thinking: '', tools: [] }\n * \t}\n * \tfinish(_parser: ProviderParserInterface<string>): readonly string[] {\n * \t\treturn [] // Raw text retains no records at end of input.\n * \t}\n * }\n * ```\n */\nexport abstract class AgentProvider<\n\tTRecord = Readonly<Record<string, unknown>>,\n> implements AgentProviderInterface<TRecord> {\n\treadonly #id: string\n\treadonly #url: string\n\treadonly #path: string\n\treadonly #timeout: number\n\treadonly #transport: typeof globalThis.fetch\n\treadonly #headers: ProviderOptions['headers']\n\treadonly #format: ContextFormat | undefined\n\treadonly #split: boolean\n\treadonly #strict: boolean\n\n\tconstructor(input: AgentProviderInput) {\n\t\tthis.#id = crypto.randomUUID()\n\t\tthis.#url = input.url\n\t\tthis.#path = input.path ?? ''\n\t\tthis.#timeout = input.timeout ?? DEFAULT_PROVIDER_TIMEOUT\n\t\tthis.#transport = input.fetch ?? globalThis.fetch.bind(globalThis)\n\t\tthis.#headers = input.headers\n\t\tthis.#format = input.format\n\t\tthis.#split = input.split ?? true\n\t\tthis.#strict = input.strict ?? false\n\t}\n\n\t/** Identifies the concrete backend. */\n\tabstract readonly name: string\n\n\t/** Exposes the instance's minted UUID. */\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\t/** Exposes the context framing exactly as supplied. */\n\tget format(): ContextFormat | undefined {\n\t\treturn this.#format\n\t}\n\n\t/** Creates fresh framing state for the call. */\n\tabstract frame(): ProviderParserInterface<TRecord>\n\t/** Projects a domain request onto the concrete protocol's wire body. */\n\tabstract body(request: ProviderRequest): object\n\t/** Decodes a framed record into a turn increment. */\n\tabstract read(record: TRecord): ProviderIncrement\n\t/** Returns any records retained at end of input. */\n\tabstract finish(parser: ProviderParserInterface<TRecord>): readonly TRecord[]\n\n\t/**\n\t * Generates a complete turn by draining the shared stream engine.\n\t *\n\t * @param messages - The conversation turns\n\t * @param signal - The caller's cancellation bound\n\t * @param tools - The advertised tool definitions\n\t * @param options - The per-call generation configuration\n\t * @returns The terminal stream result\n\t */\n\tasync generate(\n\t\tmessages: readonly Message[],\n\t\tsignal: AbortSignal,\n\t\ttools?: readonly ToolDefinition[],\n\t\toptions?: ProviderStreamOptions,\n\t): Promise<ProviderResult> {\n\t\tconst stream = this.stream(messages, signal, tools, options)\n\t\tlet step = await stream.next()\n\t\twhile (!step.done) step = await stream.next()\n\t\treturn step.value\n\t}\n\n\t/**\n\t * Streams decoded deltas and returns the authoritative or assembled turn result.\n\t *\n\t * @param messages - The conversation turns\n\t * @param signal - The caller's cancellation bound\n\t * @param tools - The advertised tool definitions\n\t * @param options - The per-call generation configuration\n\t * @returns Content and native thinking deltas followed by the settled result\n\t * @throws ProviderAbortError Thrown when the combined cancellation bound fires\n\t * @throws ProviderError Thrown for an HTTP or protocol failure\n\t */\n\tasync *stream(\n\t\tmessages: readonly Message[],\n\t\tsignal: AbortSignal,\n\t\ttools?: readonly ToolDefinition[],\n\t\toptions?: ProviderStreamOptions,\n\t): AsyncGenerator<ProviderDelta, ProviderResult> {\n\t\tif (signal.aborted) throw new ProviderAbortError({ content: '' })\n\t\tconst timeout = new Timeout({ ms: this.#timeout })\n\t\ttimeout.start()\n\t\tconst combined = AbortSignal.any([timeout.signal, signal])\n\t\tlet parser: ProviderParserInterface<TRecord> | undefined\n\t\tlet splitter: ThinkSplitterInterface | undefined\n\t\tlet state: ProviderIncrement = { content: '', thinking: '', tools: [] }\n\t\ttry {\n\t\t\tparser = this.frame()\n\t\t\tsplitter = this.#split ? createThinkSplitter() : undefined\n\t\t\tconst response = await this.#request(\n\t\t\t\t{\n\t\t\t\t\tmessages,\n\t\t\t\t\t...(tools === undefined ? {} : { tools }),\n\t\t\t\t\t...(options === undefined ? {} : { options }),\n\t\t\t\t},\n\t\t\t\tcombined,\n\t\t\t)\n\t\t\tif (response.body === null) {\n\t\t\t\tthrow new ProviderError('PROTOCOL', 'provider error: no response body')\n\t\t\t}\n\t\t\tfor await (const chunk of readChunks(response.body, combined)) {\n\t\t\t\tcombined.throwIfAborted()\n\t\t\t\tfor (const record of parser.parse(chunk)) {\n\t\t\t\t\tyield* this.#fold(record, state, splitter, combined, (increment) => {\n\t\t\t\t\t\tstate = increment\n\t\t\t\t\t})\n\t\t\t\t\tcombined.throwIfAborted()\n\t\t\t\t\tif (state.result !== undefined) return state.result\n\t\t\t\t}\n\t\t\t}\n\t\t\tcombined.throwIfAborted()\n\t\t\tfor (const record of this.finish(parser)) {\n\t\t\t\tyield* this.#fold(record, state, splitter, combined, (increment) => {\n\t\t\t\t\tstate = increment\n\t\t\t\t})\n\t\t\t\tcombined.throwIfAborted()\n\t\t\t\tif (state.result !== undefined) return state.result\n\t\t\t}\n\t\t\tconst tail = splitter?.flush() ?? ''\n\t\t\tif (tail.length > 0) yield { channel: 'content', text: tail }\n\t\t\tcombined.throwIfAborted()\n\t\t\tif (this.#strict)\n\t\t\t\tthrow new ProviderError('PROTOCOL', 'provider error: missing settled result')\n\t\t\treturn buildProviderResult(\n\t\t\t\tsplitter?.content ?? state.content,\n\t\t\t\tjoinThinking(splitter?.thinking, state.thinking),\n\t\t\t\tstate.tools,\n\t\t\t\tstate.usage,\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tif (combined.aborted) {\n\t\t\t\tsplitter?.flush()\n\t\t\t\tconst partial = buildProviderResult(\n\t\t\t\t\tsplitter?.content ?? state.content,\n\t\t\t\t\tjoinThinking(splitter?.thinking, state.thinking),\n\t\t\t\t\tstate.tools,\n\t\t\t\t\tstate.usage,\n\t\t\t\t)\n\t\t\t\t// A throw that raced the cancel is the call's real failure, so it rides as the cause.\n\t\t\t\tthrow new ProviderAbortError(\n\t\t\t\t\tpartial,\n\t\t\t\t\terror === combined.reason ? undefined : { cause: error },\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow error\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tparser?.clear()\n\t\t\t} finally {\n\t\t\t\ttimeout.clear()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fold every record before exposing deltas, so resumed cancellation retains its contribution.\n\t*#fold(\n\t\trecord: TRecord,\n\t\tprevious: ProviderIncrement,\n\t\tsplitter: ThinkSplitterInterface | undefined,\n\t\tsignal: AbortSignal,\n\t\tcommit: (increment: ProviderIncrement) => void,\n\t): Generator<ProviderDelta> {\n\t\tconst increment = this.read(record)\n\t\tif (increment.result !== undefined) {\n\t\t\tcommit(increment)\n\t\t\treturn\n\t\t}\n\t\tconst content = splitter?.split(increment.content) ?? increment.content\n\t\tconst usage = increment.usage ?? previous.usage\n\t\tconst state: ProviderIncrement = {\n\t\t\tcontent: previous.content + increment.content,\n\t\t\tthinking: previous.thinking + increment.thinking,\n\t\t\ttools: [...previous.tools, ...increment.tools],\n\t\t\t...(usage === undefined ? {} : { usage }),\n\t\t}\n\t\tcommit(state)\n\t\tif (content.length > 0) yield { channel: 'content', text: content }\n\t\tsignal.throwIfAborted()\n\t\tif (increment.thinking.length > 0) yield { channel: 'thinking', text: increment.thinking }\n\t}\n\n\t// Send one request and translate its HTTP failure into the shared provider taxonomy.\n\tasync #request(request: ProviderRequest, signal: AbortSignal): Promise<Response> {\n\t\tconst headers = await this.#requestHeaders(signal)\n\t\tsignal.throwIfAborted()\n\t\tconst response = await this.#transport(this.#url + this.#path, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify(this.body(request)),\n\t\t\tsignal,\n\t\t})\n\t\tif (!response.ok) {\n\t\t\tlet detail: string\n\t\t\ttry {\n\t\t\t\tdetail =\n\t\t\t\t\tresponse.body === null\n\t\t\t\t\t\t? ''\n\t\t\t\t\t\t: (await readText(response.body, MAX_ERROR_BODY_LENGTH, signal)).text\n\t\t\t} catch (cause) {\n\t\t\t\tthrow new ProviderError(\n\t\t\t\t\t'HTTP',\n\t\t\t\t\t`provider error: ${response.status} - (error body unavailable)`,\n\t\t\t\t\t{ status: response.status, cause },\n\t\t\t\t)\n\t\t\t}\n\t\t\tsignal.throwIfAborted()\n\t\t\tthrow new ProviderError(\n\t\t\t\t'HTTP',\n\t\t\t\t`provider error: ${response.status}${detail === '' ? '' : ` - ${detail}`}`,\n\t\t\t\t{ status: response.status },\n\t\t\t)\n\t\t}\n\t\treturn response\n\t}\n\n\t// Await the hook inside the call's cancellation bound and release its listener on exit.\n\tasync #requestHeaders(signal: AbortSignal): Promise<Headers> {\n\t\tconst headers = new Headers({ 'Content-Type': 'application/json' })\n\t\tif (this.#headers === undefined) return headers\n\t\tconst cleanup = new AbortController()\n\t\tconst aborted = Promise.withResolvers<never>()\n\t\tsignal.addEventListener('abort', () => aborted.reject(signal.reason), {\n\t\t\tonce: true,\n\t\t\tsignal: cleanup.signal,\n\t\t})\n\t\ttry {\n\t\t\tsignal.throwIfAborted()\n\t\t\tconst hook = this.#headers\n\t\t\tconst entries = await Promise.race([\n\t\t\t\tPromise.resolve().then(() => hook(signal)),\n\t\t\t\taborted.promise,\n\t\t\t])\n\t\t\tfor (const [key, value] of Object.entries(entries)) headers.set(key, value)\n\t\t\treturn headers\n\t\t} finally {\n\t\t\tcleanup.abort()\n\t\t}\n\t}\n}\n","import type {\n\tProviderIncrement,\n\tProviderParserInterface,\n\tProviderRequest,\n\tRelayProviderOptions,\n} from '../types.js'\nimport { cloneJSONValue } from '@orkestrel/contract'\nimport { AgentProvider } from '../AgentProvider.js'\nimport { providerRequestContract, relayFrameContract } from '../contracts.js'\nimport { ProviderAbortError, ProviderError } from '../errors.js'\n\n/**\n * Carries provider calls over an authenticated NDJSON relay endpoint.\n *\n * @remarks\n * Tool execution context stays local; calls carry only `id`, `name`, and `arguments`.\n * The wire body is an owned snapshot of\n * the projection read through property descriptors, so a serializer reachable only through a\n * `get` trap or a prototype is never consulted; an own function-valued property such as a\n * `toJSON` method is a value outside JSON and is refused before fetching, with the clone's\n * failure as the refusal's `cause`. A remote abort reconstructs a `ProviderAbortError` instance\n * without aborting the\n * local signal; the `Agent` runtime treats that instance as an error unless its own bound\n * signal is aborted.\n * Content is preserved verbatim, including literal thinking tags.\n * A refusal reaches the browser as a `ProviderError` instance with the `HTTP` code and status.\n * This is the browser end alone; {@link createRelay} mounts the server end, and\n * {@link createRelayProvider}'s example is the browser half of that pair.\n *\n * @example\n * ```ts\n * import type { ProviderResult } from '@orkestrel/agent'\n * import { RelayProvider } from '@orkestrel/agent'\n * // The browser application supplies this parser dependency.\n * import { createNDJSONParser } from '@orkestrel/ndjson'\n *\n * export function ask(bearer: string, signal: AbortSignal): Promise<ProviderResult> {\n * \tconst browser = new RelayProvider({\n * \t\turl: 'https://relay.example/relay',\n * \t\tparser: createNDJSONParser,\n * \t\theaders: () => ({ authorization: `Bearer ${bearer}` }),\n * \t})\n * \treturn browser.generate([{ id: 'ask', role: 'user', content: 'ping' }], signal)\n * }\n * ```\n */\nexport class RelayProvider extends AgentProvider {\n\treadonly #parser: () => ProviderParserInterface\n\n\tconstructor(options: RelayProviderOptions) {\n\t\tconst { url, timeout, fetch, headers, format } = options\n\t\tsuper({\n\t\t\turl,\n\t\t\tsplit: false,\n\t\t\tstrict: true,\n\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t...(fetch === undefined ? {} : { fetch }),\n\t\t\t...(headers === undefined ? {} : { headers }),\n\t\t\t...(format === undefined ? {} : { format }),\n\t\t})\n\t\tthis.#parser = options.parser\n\t}\n\n\t/** Identifies the relay backend. */\n\treadonly name = 'relay'\n\n\t/** Creates fresh framing state for each response. */\n\tframe(): ProviderParserInterface {\n\t\treturn this.#parser()\n\t}\n\n\t/**\n\t * Projects declared request fields and refuses values the JSON wire cannot carry.\n\t *\n\t * @remarks\n\t * The snapshot is taken from property descriptors, so a custom serializer a projected\n\t * value carries is ignored rather than consulted and cannot reach the wire.\n\t *\n\t * @param request - The domain conversation and call configuration\n\t * @returns The validated wire request\n\t * @throws {ProviderError} Thrown when the snapshot cannot be taken — a hostile read or a\n\t * value outside JSON — carrying that failure as its `cause`, and when the snapshot the\n\t * projection produced is not a valid wire request\n\t */\n\tbody(request: ProviderRequest): object {\n\t\tlet snapshot: unknown\n\t\ttry {\n\t\t\tconst projected = {\n\t\t\t\tmessages: request.messages.map((message) => ({\n\t\t\t\t\tid: message.id,\n\t\t\t\t\trole: message.role,\n\t\t\t\t\tcontent: message.content,\n\t\t\t\t\t...(message.calls === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tcalls: message.calls.map((call) => ({\n\t\t\t\t\t\t\t\t\tid: call.id,\n\t\t\t\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\t\t\t\targuments: call.arguments,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t...(message.images === undefined ? {} : { images: message.images }),\n\t\t\t\t})),\n\t\t\t\t...(request.tools === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\ttools: request.tools.map((tool) => ({\n\t\t\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\t\t\t...(tool.description === undefined ? {} : { description: tool.description }),\n\t\t\t\t\t\t\t\t...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t}),\n\t\t\t\t...(request.options === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t...(request.options.think === undefined ? {} : { think: request.options.think }),\n\t\t\t\t\t\t\t\t...(request.options.schema === undefined ? {} : { schema: request.options.schema }),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}\n\t\t\tsnapshot = cloneJSONValue(projected)\n\t\t} catch (cause) {\n\t\t\tthrow new ProviderError('PROTOCOL', 'relay request is not JSON', { cause })\n\t\t}\n\t\tif (!providerRequestContract.is(snapshot)) {\n\t\t\tthrow new ProviderError('PROTOCOL', 'relay request is not JSON')\n\t\t}\n\t\treturn snapshot\n\t}\n\n\t/**\n\t * Validates a relay frame and translates its channel into the shared stream engine.\n\t *\n\t * @param record - The framed wire record\n\t * @returns A delta contribution or authoritative result\n\t * @throws {ProviderAbortError} Thrown for a remote abort carrying its partial\n\t * @throws {ProviderError} Thrown for a malformed frame or remote provider failure\n\t */\n\tread(record: Readonly<Record<string, unknown>>): ProviderIncrement {\n\t\tif (!relayFrameContract.is(record)) {\n\t\t\tthrow new ProviderError('PROTOCOL', 'invalid relay frame')\n\t\t}\n\t\tswitch (record.channel) {\n\t\t\tcase 'content':\n\t\t\t\treturn { content: record.text, thinking: '', tools: [] }\n\t\t\tcase 'thinking':\n\t\t\t\treturn { content: '', thinking: record.text, tools: [] }\n\t\t\tcase 'result':\n\t\t\t\treturn { content: '', thinking: '', tools: [], result: record.result }\n\t\t\tcase 'abort':\n\t\t\t\tthrow new ProviderAbortError(record.partial)\n\t\t\tcase 'error':\n\t\t\t\tthrow new ProviderError('PROVIDER', record.message)\n\t\t}\n\t}\n\n\t/**\n\t * Recovers an unterminated final frame by completing its NDJSON line.\n\t *\n\t * @param parser - The call's retained framing state\n\t * @returns Records completed by the final newline\n\t */\n\tfinish(parser: ProviderParserInterface): ReadonlyArray<Readonly<Record<string, unknown>>> {\n\t\treturn parser.parse('\\n')\n\t}\n}\n","import type { ProviderDelta, ProviderResult, RelayFrame, RelayStreamOptions } from './types.js'\nimport { RELAY_CONTENT_TYPE, RELAY_PROVIDER_MESSAGE } from './constants.js'\nimport { relayFrameContract } from './contracts.js'\nimport { ProviderError, isProviderAbortError } from './errors.js'\n\n/**\n * Streams a provider call as validated NDJSON frames under response backpressure.\n *\n * @remarks\n * Cancellation aborts upstream before returning its iterator. Request listeners are\n * released on settlement. Unexpected provider failures carry a fixed public message.\n * An inbound abort leaves the response body neither closed nor errored — a server runtime\n * cancels that body when the client disconnects — so a consumer that aborts the inbound\n * signal itself must cancel the body rather than keep reading it.\n *\n * @example\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { RelayStream } from '@orkestrel/agent'\n *\n * export function respond(provider: ProviderInterface, signal: AbortSignal): Response {\n * \treturn new RelayStream({ provider, request: { messages: [] }, signal }).response\n * }\n * ```\n */\nexport class RelayStream {\n\treadonly #upstream = new AbortController()\n\treadonly #encoder = new TextEncoder()\n\treadonly #iterator: AsyncGenerator<ProviderDelta, ProviderResult>\n\treadonly #signal: AbortSignal\n\treadonly #listener: () => void\n\treadonly #response: Response\n\t#settled = false\n\n\tconstructor(options: RelayStreamOptions) {\n\t\tthis.#signal = options.signal\n\t\tthis.#listener = this.#cancel.bind(this)\n\t\tif (this.#signal.aborted) this.#abortProvider()\n\t\tthis.#iterator = options.provider.stream(\n\t\t\toptions.request.messages,\n\t\t\tthis.#upstream.signal,\n\t\t\toptions.request.tools,\n\t\t\toptions.request.options,\n\t\t)\n\t\tthis.#signal.addEventListener('abort', this.#listener, { once: true })\n\t\tthis.#response = new Response(\n\t\t\tnew ReadableStream<Uint8Array>({\n\t\t\t\tpull: this.#pull.bind(this),\n\t\t\t\tcancel: this.#cancel.bind(this),\n\t\t\t}),\n\t\t\t{ headers: { 'content-type': RELAY_CONTENT_TYPE, 'cache-control': 'no-store' } },\n\t\t)\n\t}\n\n\t/** Exposes the pull-driven response for the provider call. */\n\tget response(): Response {\n\t\treturn this.#response\n\t}\n\n\tasync #pull(controller: ReadableStreamDefaultController<Uint8Array>): Promise<void> {\n\t\tif (this.#settled) return\n\t\ttry {\n\t\t\tconst step = await this.#iterator.next()\n\t\t\tif (this.#settled) return\n\t\t\tthis.#write(controller, step.done ? { channel: 'result', result: step.value } : step.value)\n\t\t\tif (step.done) this.#finish(controller)\n\t\t} catch (error) {\n\t\t\tif (this.#settled) return\n\t\t\tconst frame: RelayFrame = isProviderAbortError(error)\n\t\t\t\t? { channel: 'abort', partial: error.partial }\n\t\t\t\t: { channel: 'error', message: RELAY_PROVIDER_MESSAGE }\n\t\t\tthis.#write(\n\t\t\t\tcontroller,\n\t\t\t\trelayFrameContract.is(frame)\n\t\t\t\t\t? frame\n\t\t\t\t\t: { channel: 'error', message: RELAY_PROVIDER_MESSAGE },\n\t\t\t)\n\t\t\tthis.#finish(controller)\n\t\t\tthis.#abortProvider()\n\t\t\tawait this.#return()\n\t\t}\n\t}\n\n\tasync #cancel(): Promise<void> {\n\t\tif (this.#settled) return\n\t\tthis.#settled = true\n\t\tthis.#abortProvider()\n\t\ttry {\n\t\t\tawait this.#return()\n\t\t} finally {\n\t\t\tthis.#release()\n\t\t}\n\t}\n\n\tasync #return(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.#iterator.return({ content: '' })\n\t\t} catch {\n\t\t\t// A settled response has no error channel for upstream cleanup failures.\n\t\t}\n\t}\n\n\t#write(controller: ReadableStreamDefaultController<Uint8Array>, frame: RelayFrame): void {\n\t\tif (!relayFrameContract.is(frame)) throw new ProviderError('PROTOCOL', 'invalid relay frame')\n\t\tcontroller.enqueue(this.#encoder.encode(`${JSON.stringify(frame)}\\n`))\n\t}\n\n\t#finish(controller: ReadableStreamDefaultController<Uint8Array>): void {\n\t\tthis.#settled = true\n\t\tthis.#release()\n\t\tcontroller.close()\n\t}\n\n\t#abortProvider(): void {\n\t\tthis.#upstream.abort(this.#signal.reason)\n\t}\n\n\t#release(): void {\n\t\tthis.#signal.removeEventListener('abort', this.#listener)\n\t}\n}\n","import type { ScopeFilter, ScopeInput, ScopeInterface } from '../types.js'\nimport { intersectKeys } from '../helpers.js'\n\n/**\n * Represents a named, immutable filter over a richer context's items — an optional allow-list per\n * category (`instructions` / `tools` / `files`), each keyed by that category's identity (an\n * instruction's `name`, a tool's `name`, a workspace file's `path`) and read as an allow-list:\n * `undefined` lets everything pass, `[]` lets nothing pass, and a non-empty list passes the listed\n * keys alone. `narrow` composes a tighter child by set intersection.\n *\n * @remarks\n * - **A category list is three-way.** `undefined` ⇒ no constraint on that category (all\n * pass); `[]` ⇒ none pass; a non-empty list ⇒ only the listed keys pass. The build\n * step / loop apply this through `filterAllowList`.\n * - **Immutable.** The `id` is minted at construction; every supplied list is copied in\n * (so a later mutation of the caller's array can't leak in), and the lists are\n * `readonly`. A `Scope` is never mutated after construction — `narrow` returns a new\n * one rather than altering this one.\n * - **`narrow` is set-intersection (immutable composition).** A child scope's visible set\n * per category is the intersection of this scope's list and the config's list — but\n * `undefined` means \"no constraint\", so it acts as the universal set: intersecting\n * `undefined` with a list yields the list, and `undefined` with `undefined` stays\n * `undefined`. Narrowing can only tighten, never widen — a key excluded by a parent\n * can never be re-admitted by a child.\n *\n * @example\n * ```ts\n * const scope = new Scope({ name: 'reader', tools: ['search', 'read'] })\n * // narrow intersects: tools ∩ ['read', 'write'] = ['read'] (write was never in the parent).\n * const tighter = scope.narrow({ tools: ['read', 'write'] })\n * tighter.tools // ['read']\n * // instructions had no parent constraint (undefined) → the child's list passes through.\n * tighter.narrow({ instructions: ['safety'] }).instructions // ['safety']\n * ```\n */\nexport class Scope implements ScopeInterface {\n\treadonly id: string = crypto.randomUUID()\n\treadonly name: string\n\treadonly instructions?: readonly string[]\n\treadonly tools?: readonly string[]\n\treadonly files?: readonly string[]\n\n\tconstructor(input: ScopeInput) {\n\t\tthis.name = input.name\n\t\t// Copy each supplied list in (a later mutation of the caller's array can't leak in);\n\t\t// an omitted list stays `undefined` — the \"no constraint\" sentinel.\n\t\tif (input.instructions !== undefined) this.instructions = [...input.instructions]\n\t\tif (input.tools !== undefined) this.tools = [...input.tools]\n\t\tif (input.files !== undefined) this.files = [...input.files]\n\t}\n\n\tnarrow(config: ScopeFilter): ScopeInterface {\n\t\t// A child = the per-category set-intersection of this scope and the config, keeping\n\t\t// this scope's name. Immutable: a brand-new Scope, this one untouched.\n\t\tconst instructions = intersectKeys(this.instructions, config.instructions)\n\t\tconst tools = intersectKeys(this.tools, config.tools)\n\t\tconst files = intersectKeys(this.files, config.files)\n\t\treturn new Scope({\n\t\t\tname: this.name,\n\t\t\t...(instructions === undefined ? {} : { instructions }),\n\t\t\t...(tools === undefined ? {} : { tools }),\n\t\t\t...(files === undefined ? {} : { files }),\n\t\t})\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tScopeInput,\n\tScopeInterface,\n\tScopeManagerEventMap,\n\tScopeManagerInterface,\n\tScopeManagerOptions,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Scope } from './Scope.js'\n\n/**\n * Registers the named filters a richer context reuses — immutable {@link Scope}s keyed by their\n * minted `id`, in insertion order, where `create` always mints and stores rather than overwriting,\n * and an observable `emitter` reports each change.\n *\n * @remarks\n * - **Registry.** Scopes live in an insertion-ordered `Map` keyed by their minted `id`;\n * `create` mints a {@link Scope} from a {@link ScopeInput} (an `id` plus the three\n * allow-lists), stores it, and returns it. `count` is the map size, `scope(id)` looks\n * one up, and `scopes()` lists them in insertion order. (Unlike the name-keyed\n * instruction registry, a scope's key is its minted `id`, so two scopes may share a\n * `name`; `create` therefore always adds — it never overwrites.)\n * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id\n * was removed; `clear` empties the registry.\n * - **Observable.** The owned {@link emitter} ({@link ScopeManagerEventMap}) carries\n * `create` (the created scope) / `remove` (the id) / `clear`. Every event is emitted\n * directly, strictly after the map mutation completes; the emitter isolates a listener\n * throw and routes it to its `error` handler (the `error` option), so a buggy observer can\n * never corrupt a mutation.\n *\n * @example\n * ```ts\n * const manager = new ScopeManager()\n * const reader = manager.create({ name: 'reader', tools: ['search', 'read'] })\n * manager.scope(reader.id) // the same scope\n * manager.count // 1\n * ```\n */\nexport class ScopeManager implements ScopeManagerInterface {\n\treadonly #scopes = new Map<string, ScopeInterface>()\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into a mutation.\n\treadonly #emitter: Emitter<ScopeManagerEventMap>\n\n\tconstructor(options?: ScopeManagerOptions) {\n\t\tthis.#emitter = new Emitter<ScopeManagerEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<ScopeManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#scopes.size\n\t}\n\n\tcreate(input: ScopeInput): ScopeInterface {\n\t\tconst scope = new Scope(input)\n\t\tthis.#scopes.set(scope.id, scope)\n\t\t// Observe the created scope — after the map set, so a swallowed listener throw can't\n\t\t// perturb the store the caller is about to use.\n\t\tthis.#emitter.emit('create', scope)\n\t\treturn scope\n\t}\n\n\tscope(id: string): ScopeInterface | undefined {\n\t\treturn this.#scopes.get(id)\n\t}\n\n\tscopes(): readonly ScopeInterface[] {\n\t\treturn [...this.#scopes.values()]\n\t}\n\n\tremove(id: string): boolean\n\tremove(ids: readonly string[]): boolean\n\tremove(ids: string | readonly string[]): boolean {\n\t\tif (isArray(ids)) {\n\t\t\t// True only when every supplied id was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one. Each present id still emits.\n\t\t\tlet removed = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (!this.#delete(id)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#delete(ids)\n\t}\n\n\tclear(): void {\n\t\tthis.#scopes.clear()\n\t\t// Observe the cleared registry — after the map emptied, so a swallowed listener\n\t\t// throw can never alter the clear (no payload — `clear` is a pure signal).\n\t\tthis.#emitter.emit('clear')\n\t}\n\n\t// Delete one scope, emitting `remove` only when one was actually removed (a delete of\n\t// an absent id returns `false` and emits nothing) — after the deletion.\n\t#delete(id: string): boolean {\n\t\tconst removed = this.#scopes.delete(id)\n\t\tif (removed) this.#emitter.emit('remove', id)\n\t\treturn removed\n\t}\n}\n","import type { ThinkSplitterInterface } from './types.js'\nimport { THINK_CLOSE, THINK_OPEN } from './constants.js'\n\n/**\n * Feeds raw content deltas through a tiny stream-stateful state machine that routes everything\n * inside a `<think>…</think>` span to `thinking` and returns everything outside it as clean\n * content, so a provider yields the answer alone and surfaces the reasoning as\n * {@link import('./types.js').ProviderResult.thinking}. A tag split across deltas is held until\n * disambiguated, `flush()` settles the stream end, and one splitter serves one stream.\n *\n * @remarks\n * - **Cross-chunk tags.** A tag may arrive split across wire deltas (`'<thi'` then\n * `'nk>'`): any suffix of the pending text that is a strict prefix of a tag being\n * scanned for is held back (neither surfaced nor routed) until the next delta — or\n * `flush()` — disambiguates it. A held tag prefix that never completes is real\n * content; a held close-tag prefix inside a span is thinking.\n * - **The implicit leading open (the qwen3-template shape).** Some chat templates\n * pre-seed `<think>` into the prompt scaffold, so the wire stream begins\n * mid-reasoning and only a bare `</think>` appears. Before any tag event, a bare\n * close therefore reclassifies everything surfaced so far (plus the pre-close\n * pending) as thinking — `content` is corrected retroactively (the already-returned\n * prefix cannot be recalled, so `content` is the authoritative accumulation). The\n * rule is one-shot: after any tag event a bare `</think>` is plain text.\n * - **Multiple spans** accumulate onto `thinking` in stream order. A nested-looking\n * `<think>` inside an open span is thinking text (no nesting is tracked — the\n * first `</think>` closes the span), matching how the models emit it.\n * - **Unclosed span at stream end.** `flush()` routes the open span's tail (including\n * any held partial close tag) to `thinking` — a cut-off model was still reasoning.\n * - **One splitter, one stream.** State is per-stream; create a fresh instance per\n * provider call ({@link import('./factories.js').createThinkSplitter}).\n *\n * @example\n * ```ts\n * const splitter = new ThinkSplitter()\n * splitter.split('<thi') // '' (held — ambiguous)\n * splitter.split('nk>plan</think>ok') // 'ok'\n * splitter.thinking // 'plan'\n * splitter.content // 'ok'\n * splitter.flush() // '' (nothing held)\n * ```\n */\nexport class ThinkSplitter implements ThinkSplitterInterface {\n\t// The undecided tail of the stream — text not yet routed to content or thinking\n\t// (at most one partial tag's worth between calls; transiently the whole delta).\n\t#pending = ''\n\t// Whether the scanner is inside an open `<think>` span.\n\t#inside = false\n\t// Whether a tag event has occurred (an explicit open, or the one-shot implicit-open\n\t// close) — before it, a bare `</think>` closes the implicit span a chat template\n\t// pre-seeded; after it, a bare close is plain text.\n\t#opened = false\n\t#content = ''\n\t#thinking = ''\n\n\tget content(): string {\n\t\treturn this.#content\n\t}\n\n\tget thinking(): string {\n\t\treturn this.#thinking\n\t}\n\n\tsplit(delta: string): string {\n\t\tconst out = this.#scan(delta)\n\t\tthis.#content += out\n\t\treturn out\n\t}\n\n\tflush(): string {\n\t\tconst pending = this.#pending\n\t\tthis.#pending = ''\n\t\tif (this.#inside) {\n\t\t\t// An unclosed span at stream end — the tail (held partial close tag included)\n\t\t\t// is thinking: the model was cut off mid-reasoning, never mid-answer.\n\t\t\tthis.#thinking += pending\n\t\t\tthis.#inside = false\n\t\t\treturn ''\n\t\t}\n\t\t// A held partial tag that never completed was real content after all.\n\t\tthis.#content += pending\n\t\treturn pending\n\t}\n\n\t// Drive the state machine over one delta, returning the clean content it surfaces —\n\t// the wrapper folds the return into `#content`, which the implicit-open branch may\n\t// have reset a moment earlier (the reclassification).\n\t#scan(delta: string): string {\n\t\tthis.#pending += delta\n\t\tlet content = ''\n\t\tfor (;;) {\n\t\t\tif (this.#inside) {\n\t\t\t\tconst close = this.#pending.indexOf(THINK_CLOSE)\n\t\t\t\tif (close === -1) {\n\t\t\t\t\t// No close yet — route all but a possible partial close-tag suffix to\n\t\t\t\t\t// thinking, holding that suffix for the next delta to disambiguate.\n\t\t\t\t\tthis.#thinking += this.#hold([THINK_CLOSE])\n\t\t\t\t\treturn content\n\t\t\t\t}\n\t\t\t\tthis.#thinking += this.#pending.slice(0, close)\n\t\t\t\tthis.#pending = this.#pending.slice(close + THINK_CLOSE.length)\n\t\t\t\tthis.#inside = false\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst open = this.#pending.indexOf(THINK_OPEN)\n\t\t\tif (!this.#opened) {\n\t\t\t\t// The implicit leading open: before any tag event, a bare close (arriving\n\t\t\t\t// ahead of any explicit open) means the stream began inside a pre-seeded\n\t\t\t\t// span — everything surfaced so far was reasoning. Reclassify it.\n\t\t\t\tconst close = this.#pending.indexOf(THINK_CLOSE)\n\t\t\t\tif (close !== -1 && (open === -1 || close < open)) {\n\t\t\t\t\tthis.#thinking += this.#content + content + this.#pending.slice(0, close)\n\t\t\t\t\tthis.#content = ''\n\t\t\t\t\tcontent = ''\n\t\t\t\t\tthis.#pending = this.#pending.slice(close + THINK_CLOSE.length)\n\t\t\t\t\tthis.#opened = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (open === -1) {\n\t\t\t\t// No open tag — surface all but a possible partial tag suffix as content\n\t\t\t\t// (before any tag event a split leading close must not leak either, so the\n\t\t\t\t// close tag's prefixes are held back too).\n\t\t\t\tconst tags = this.#opened ? [THINK_OPEN] : [THINK_OPEN, THINK_CLOSE]\n\t\t\t\tcontent += this.#hold(tags)\n\t\t\t\treturn content\n\t\t\t}\n\t\t\tthis.#opened = true\n\t\t\tcontent += this.#pending.slice(0, open)\n\t\t\tthis.#pending = this.#pending.slice(open + THINK_OPEN.length)\n\t\t\tthis.#inside = true\n\t\t}\n\t}\n\n\t// Settle the pending text against the given tags' possible partial suffixes: the\n\t// longest ambiguous suffix stays pending for the next delta; everything before it\n\t// is returned for routing.\n\t#hold(tags: readonly string[]): string {\n\t\tconst keep = Math.max(...tags.map((tag) => this.#overlap(tag)))\n\t\tconst cut = this.#pending.length - keep\n\t\tconst settled = this.#pending.slice(0, cut)\n\t\tthis.#pending = this.#pending.slice(cut)\n\t\treturn settled\n\t}\n\n\t// The length of the longest strict prefix of `tag` that suffixes the pending text —\n\t// how many trailing characters are an ambiguous partial tag and must be held back.\n\t#overlap(tag: string): number {\n\t\tconst max = Math.min(this.#pending.length, tag.length - 1)\n\t\tfor (let length = max; length > 0; length -= 1) {\n\t\t\tif (this.#pending.endsWith(tag.slice(0, length))) return length\n\t\t}\n\t\treturn 0\n\t}\n}\n","import type {\n\tAgentContextInterface,\n\tAgentContextOptions,\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentOptions,\n\tAgentQueueOptions,\n\tAgentRegistryInterface,\n\tAgentRegistryOptions,\n\tAgentResult,\n\tAgentRunnerOptions,\n\tAuthorityInterface,\n\tAuthorityOptions,\n\tChannelInterface,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tConversationManagerOptions,\n\tConversationOptions,\n\tConversationSnapshotRow,\n\tConversationStoreInterface,\n\tInstructionInput,\n\tInstructionInterface,\n\tInstructionManagerInterface,\n\tInstructionManagerOptions,\n\tProviderInterface,\n\tRelayHandler,\n\tRelayOptions,\n\tRelayProviderOptions,\n\tScopeInput,\n\tScopeInterface,\n\tScopeManagerInterface,\n\tScopeManagerOptions,\n\tThinkSplitterInterface,\n\tTextRead,\n} from './types.js'\nimport type { DriverInterface, TableInterface } from '@orkestrel/database'\nimport type { QueueInterface } from '@orkestrel/queue'\nimport type { RunnerInterface } from '@orkestrel/workflow'\nimport { parseJSONAs, rawShape, stringShape } from '@orkestrel/contract'\nimport { createDatabase, createMemoryDriver } from '@orkestrel/database'\nimport { createQueue } from '@orkestrel/queue'\nimport { createRunner } from '@orkestrel/workflow'\nimport { Agent } from './Agent.js'\nimport { AgentContext } from './AgentContext.js'\nimport { AgentRegistry } from './AgentRegistry.js'\nimport { Authority } from './Authority.js'\nimport { Channel } from './Channel.js'\nimport {\n\tDEFAULT_RELAY_LIMIT,\n\tINVALID_RELAY_STATUS,\n\tOVERSIZED_RELAY_STATUS,\n\tUNAUTHORIZED_RELAY_STATUS,\n\tUPSTREAM_RELAY_STATUS,\n} from './constants.js'\nimport { providerRequestContract } from './contracts.js'\nimport { Conversation } from './conversations/Conversation.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport { DatabaseConversationStore } from './conversations/stores/DatabaseConversationStore.js'\nimport { MemoryConversationStore } from './conversations/stores/MemoryConversationStore.js'\nimport { handleAgentQueueJob, handleAgentRunnerJob, readText } from './helpers.js'\nimport { Instruction } from './instructions/Instruction.js'\nimport { InstructionManager } from './instructions/InstructionManager.js'\nimport { RelayProvider } from './providers/RelayProvider.js'\nimport { RelayStream } from './RelayStream.js'\nimport { Scope } from './scopes/Scope.js'\nimport { ScopeManager } from './scopes/ScopeManager.js'\nimport { ThinkSplitter } from './ThinkSplitter.js'\n\n/**\n * Creates an authorized relay handler that validates a bounded JSON request before streaming.\n *\n * @remarks\n * Answers with the `401` status when authorization refuses or throws, the `400`\n * status when the body is missing, unreadable, or invalid, the `413` status when\n * the body fills its byte budget or the inbound read is aborted, and the `502`\n * status when the upstream provider call cannot be constructed. Refusals carry no body.\n *\n * @param options - The upstream provider, authorization decision, and optional byte budget\n * @returns A fetch-standard handler suitable for a router\n * @example Mounting the relay on your server\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createRelay } from '@orkestrel/agent'\n * import { createDispatcher } from '@orkestrel/router'\n * import { createServer } from '@orkestrel/server'\n *\n * declare const upstream: ProviderInterface // the server-side provider holding the credential\n * declare const bearer: string\n *\n * const handler = createRelay({\n * \tprovider: upstream,\n * \tauthorize: (request) => request.headers.get('authorization') === `Bearer ${bearer}`,\n * })\n * const dispatcher = createDispatcher({\n * \troutes: [{ method: 'POST', path: '/relay', handler }],\n * })\n *\n * export function serve(request: Request): Promise<Response> {\n * \treturn dispatcher.handle(request, undefined)\n * }\n *\n * const server = createServer({ dispatcher, state: () => undefined })\n * await server.start()\n * process.on('SIGTERM', () => server.stop()) // signal cancellation, drain, then close the listener\n * ```\n */\nexport function createRelay(options: RelayOptions): RelayHandler {\n\tconst { provider, authorize, limit } = options\n\treturn async (request) => {\n\t\ttry {\n\t\t\tif ((await authorize(request)) !== true) {\n\t\t\t\treturn new Response(undefined, { status: UNAUTHORIZED_RELAY_STATUS })\n\t\t\t}\n\t\t} catch {\n\t\t\treturn new Response(undefined, { status: UNAUTHORIZED_RELAY_STATUS })\n\t\t}\n\t\tif (request.body === null) return new Response(undefined, { status: INVALID_RELAY_STATUS })\n\t\tlet read: TextRead\n\t\ttry {\n\t\t\tread = await readText(request.body, limit ?? DEFAULT_RELAY_LIMIT, request.signal)\n\t\t} catch {\n\t\t\treturn new Response(undefined, {\n\t\t\t\tstatus: request.signal.aborted ? OVERSIZED_RELAY_STATUS : INVALID_RELAY_STATUS,\n\t\t\t})\n\t\t}\n\t\tif (!read.complete) return new Response(undefined, { status: OVERSIZED_RELAY_STATUS })\n\t\tconst parsed = parseJSONAs(read.text, providerRequestContract.is)\n\t\tif (parsed === undefined) return new Response(undefined, { status: INVALID_RELAY_STATUS })\n\t\ttry {\n\t\t\treturn new RelayStream({ provider, request: parsed, signal: request.signal }).response\n\t\t} catch {\n\t\t\treturn new Response(undefined, { status: UPSTREAM_RELAY_STATUS })\n\t\t}\n\t}\n}\n\n/**\n * Creates a provider that carries calls through a relay endpoint.\n *\n * @remarks\n * This is the browser end alone. {@link createRelay} mounts the server end, and its example\n * is the server half this one pairs with.\n *\n * @param options - The endpoint, parser factory, and HTTP call configuration\n * @returns The concrete relay provider\n * @example Reaching the relay from the browser\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createRelayProvider } from '@orkestrel/agent'\n * import { createAbort } from '@orkestrel/abort'\n * // The browser application supplies this parser dependency.\n * import { createNDJSONParser } from '@orkestrel/ndjson'\n *\n * declare const bearer: string\n * const abort = createAbort()\n * const messages = [{ id: '1', role: 'user', content: 'Say hello.' }] as const\n *\n * const browser: ProviderInterface = createRelayProvider({\n * \turl: 'https://app.example/relay',\n * \tparser: createNDJSONParser,\n * \theaders: () => ({ authorization: `Bearer ${bearer}` }),\n * })\n * const result = await browser.generate(messages, abort.signal) // a ProviderResult like a local provider's\n * ```\n */\nexport function createRelayProvider(options: RelayProviderOptions): RelayProvider {\n\treturn new RelayProvider(options)\n}\n\n/**\n * Creates a conversation — a {@link ConversationInterface} grouping messages above a flat\n * message store it owns directly, with compaction into summarized sections, a regenerated\n * rollup `summary`, on-demand `rehydrate`, and substring `search`, driven by a\n * provider-agnostic {@link ConversationSummaryHandler} seam.\n *\n * @remarks\n * Append turns through the conversation's own `add` (the live tail it owns); `view()` is the model input\n * (each section as a summary message, then the live tail). `compact()` folds the older live\n * messages into a summarized {@link Section} and regenerates the rollup — it requires\n * a `summarize` (omitted ⇒ `compact()` throws a `ConversationError`); `keep` retains a recent\n * tail (default `DEFAULT_CONVERSATION_KEEP` — fold all). `rehydrate(id)` / `search(query)` read\n * the retained originals. Observable (`emitter` — `compact` / `summary` / `rehydrate`), wired\n * through the reserved `on` option; the emitter isolates a listener throw and routes it to\n * its `error` handler (the `error` option), so it can never corrupt a compaction.\n *\n * @param options - Optional `id` / `on` hooks + the `summarize` seam + `keep` (see {@link ConversationOptions})\n * @returns A working {@link ConversationInterface}\n *\n * @example Conversations & compaction\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createConversation } from '@orkestrel/agent'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * // The summarizer seam — built from the provider by the runtime; core stays provider-agnostic.\n * // Append the instruction as the FINAL user turn: a chat model emits nothing when the prompt\n * // ends on an assistant turn, so a leading-system instruction is unreliable.\n * const conversation = createConversation({\n * \tsummarize: async (messages) =>\n * \t\t(\n * \t\t\tawait provider.generate(\n * \t\t\t\t[\n * \t\t\t\t\t...messages,\n * \t\t\t\t\t{ id: 's', role: 'user', content: 'Summarize the conversation so far concisely.' },\n * \t\t\t\t],\n * \t\t\t\tAbortSignal.timeout(30_000),\n * \t\t\t)\n * \t\t).content,\n * \tkeep: 2, // retain the two most recent turns verbatim on each compaction\n * })\n * conversation.add([\n * \t{ role: 'user', content: 'My name is Ada.' },\n * \t{ role: 'assistant', content: 'Nice to meet you, Ada.' },\n * \t{ role: 'user', content: 'What did I say my name was?' },\n * ])\n *\n * const section = await conversation.compact() // folds the older turns → a summarized section\n * conversation.view() // [<section summary message>, ...the retained recent tail] — the model input\n * conversation.summary // the regenerated rollup (a summary-of-summaries over all sections)\n * conversation.search('ada') // case-insensitive across sections' originals + the live tail\n * section && conversation.rehydrate(section.id) // the section's full original messages (a pure read)\n * ```\n */\nexport function createConversation(options?: ConversationOptions): ConversationInterface {\n\treturn new Conversation(options)\n}\n\n/**\n * Creates a conversation registry — a {@link ConversationManagerInterface} holding\n * {@link ConversationInterface}s keyed by their `id`, in insertion order, with an active pointer:\n * the id-keyed store over the conversation layer plus the `active` / `switch` seam the context\n * renders. `add` auto-activates the first conversation and flows the registry's default\n * `summarize` / `keep` into every conversation it creates.\n *\n * @remarks\n * Starts empty; `add(input?)` mints a {@link ConversationInterface} (its `id` from the input\n * or a random UUID), flowing the manager's default `summarize` / `keep` in unless the input\n * overrides them, and stores it (an already-present `id` overwrites — last write wins) — and\n * auto-activates the first one (a registry with conversations always has one `active`); a later\n * `add` leaves `active` unchanged. `switch(id)` re-points `active` (an unknown `id` returns\n * `undefined`, leaving `active` unchanged — lenient, never throws); `conversation(id)` /\n * `conversations()` look up; `remove` (one or a batch) reports `true` only when every supplied id\n * was removed and clears `active` if it was a removed one; `clear` empties it and clears `active`.\n * Event-free\n * (each conversation owns its own observable `emitter`). A conversation created with neither a\n * manager default nor a per-`add` `summarize` cannot `compact` (it throws a `ConversationError`).\n *\n * @param options - Optional default `summarize` / `keep` (see {@link ConversationManagerOptions})\n * @returns An empty {@link ConversationManagerInterface}\n *\n * @example\n * ```ts\n * import { createConversationManager } from '@orkestrel/agent'\n *\n * const conversations = createConversationManager({ summarize: async (m) => `recap of ${m.length}` })\n * const chat = conversations.add() // auto-activates — conversations.active === chat\n * chat.add({ role: 'user', content: 'Hello' })\n * ```\n */\nexport function createConversationManager(\n\toptions?: ConversationManagerOptions,\n): ConversationManagerInterface {\n\treturn new ConversationManager(options)\n}\n\n/**\n * Creates the in-memory conversation store — a {@link ConversationStoreInterface} backed by a\n * process-lifetime `Map` of {@link import('./types.js').ConversationSnapshot}s keyed by conversation\n * id, the default backing for the durable {@link ConversationManagerInterface.open} /\n * {@link ConversationManagerInterface.save} seam. The exact twin of\n * {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.\n *\n * @remarks\n * A plain `Map` (the snapshot is already pure JSON, so no encoding is needed for the memory tier),\n * the structural twin of {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.\n * `get` / `set` / `delete` are async (the\n * same shape a durable backend fits); unlike a session store there is no idle-TTL / eviction — a\n * persisted conversation lives until an explicit `delete`. Its driver-pluggable twin is\n * {@link createDatabaseConversationStore} (the snapshot as one opaque JSON column over a `databases`\n * table) — for a durable store pass it a JSON / SQLite / IndexedDB driver, and it swaps in without\n * touching the manager or the conversation. Hydration stays a manager concern: read a snapshot back\n * and rebuild the live conversation through the `snapshot` option (re-supplying the live\n * `summarize` / `keep`).\n *\n * @returns A memory-backed {@link ConversationStoreInterface}\n *\n * @example\n * ```ts\n * import { createConversationManager, createMemoryConversationStore } from '@orkestrel/agent'\n *\n * const store = createMemoryConversationStore()\n * const manager = createConversationManager({ store })\n * const conversation = manager.add()\n * conversation.add({ role: 'user', content: 'hello' })\n * await manager.save(conversation.id) // persist the conversation\n * ```\n */\nexport function createMemoryConversationStore(): ConversationStoreInterface {\n\treturn new MemoryConversationStore()\n}\n\n/**\n * Creates a {@link DatabaseConversationStore} over any {@link DriverInterface}, defaulting to\n * `createMemoryDriver()` — the durable, driver-pluggable backing for the conversation persistence\n * seam, holding each snapshot as one opaque JSON column and standing as the opt-in twin of\n * {@link createMemoryConversationStore}. The exact twin of\n * {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore}.\n *\n * @remarks\n * Builds a one-table database (`conversations`, keyed by `id`) over the supplied driver, the snapshot\n * held as one opaque JSON column — the column map is `{ id; snapshot }` where `snapshot` is a\n * `rawShape` (a JSON blob), exactly as\n * {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore} stores its snapshot. The\n * snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is lossless\n * and keeps the row type flat (the column reads back as `unknown`, narrowed on `get` by\n * {@link import('./validators.js').isConversationSnapshot}). The `driver` defaults to\n * {@link createMemoryDriver}, so the store also works in memory out of the box; pass a server\n * `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —\n * the durability is the driver's job, the store engine is shared. It swaps in behind\n * {@link ConversationStoreInterface} without touching the manager or the conversation.\n *\n * @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})\n * @returns A {@link ConversationStoreInterface} over the driver\n *\n * @example\n * ```ts\n * import { createConversationManager, createDatabaseConversationStore } from '@orkestrel/agent'\n * import { createMemoryDriver } from '@orkestrel/database'\n *\n * const store = createDatabaseConversationStore(createMemoryDriver()) // a durable driver swaps in here\n * const manager = createConversationManager({ store })\n * const conversation = manager.add()\n * conversation.add({ role: 'user', content: 'hello' })\n * await manager.save(conversation.id) // persist the conversation (one JSON column)\n * ```\n */\nexport function createDatabaseConversationStore(\n\tdriver: DriverInterface = createMemoryDriver(),\n): ConversationStoreInterface {\n\t// The snapshot is stored as one opaque JSON column (`rawShape`), so the row infers flat —\n\t// `{ id: string; snapshot: unknown }` = `ConversationSnapshotRow` — and the sections/messages\n\t// snapshot shape never forces a contract `Infer`.\n\tconst columns = { id: stringShape(), snapshot: rawShape({}) }\n\tconst database = createDatabase({ driver, tables: { conversations: columns } })\n\tconst table: TableInterface<ConversationSnapshotRow> = database.table('conversations')\n\treturn new DatabaseConversationStore(table)\n}\n\n/**\n * Creates an instruction — an immutable {@link InstructionInterface} (a named directive)\n * from its `name` / `content` and optional `priority`, the `id` minted at construction.\n *\n * @remarks\n * Only `name` / `content` are required; `priority` orders the instruction in an\n * {@link InstructionManagerInterface}'s rendered list (higher first) and defaults to `0`.\n * Stored immutable — never mutated after creation.\n *\n * @param input - `name` / `content` (required) and an optional `priority` (see\n * {@link InstructionInput})\n * @returns A working {@link InstructionInterface}\n *\n * @example\n * ```ts\n * import { createInstruction } from '@orkestrel/agent'\n *\n * const instruction = createInstruction({ name: 'tone', content: 'Be concise.', priority: 5 })\n * ```\n */\nexport function createInstruction(input: InstructionInput): InstructionInterface {\n\treturn new Instruction(input)\n}\n\n/**\n * Creates an instruction registry — an {@link InstructionManagerInterface} holding\n * immutable instructions keyed by `name`, listed by descending `priority`.\n *\n * @remarks\n * Starts empty; `add` (one or a batch) mints each `id` and overwrites a same-name\n * instruction (last write wins); `instructions()` lists them sorted by descending\n * `priority` (stable for ties); `open` / `render` are the build contract a richer\n * context renders an instructions block with; `remove` (one or a batch) reports `true` only\n * when every supplied name was removed; `clear` empties it. Carries an observable `emitter`\n * ({@link import('./types.js').InstructionManagerEventMap}) wired through the reserved `on`\n * option; the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option), so it can never corrupt a mutation. An optional `format`\n * override is the manager-options level of the `AgentContext` build cascade (consulted by\n * `open` / `render`, beating the provider default + built-in; a per-item\n * `InstructionInput.override` still beats it).\n *\n * @param options - Optional `on` hooks + a `format` override (see {@link InstructionManagerOptions})\n * @returns An empty {@link InstructionManagerInterface}\n *\n * @example\n * ```ts\n * import { createInstructionManager } from '@orkestrel/agent'\n *\n * const instructions = createInstructionManager()\n * instructions.add({ name: 'tone', content: 'Be concise.', priority: 5 })\n * ```\n */\nexport function createInstructionManager(\n\toptions?: InstructionManagerOptions,\n): InstructionManagerInterface {\n\treturn new InstructionManager(options)\n}\n\n/**\n * Creates a named scope — an immutable {@link ScopeInterface} from its `name` and its\n * per-category allow-lists, the `id` minted at construction.\n *\n * @remarks\n * Each list is three-way: `undefined` ⇒ no constraint on that category (all pass), `[]` ⇒\n * none pass, a non-empty list ⇒ only the listed keys pass. `narrow(config)` composes a\n * tighter child by set-intersection (an `undefined` side imposing no constraint). Stored\n * immutable — never mutated after creation (`narrow` returns a new scope).\n *\n * @param input - `name` (required) and the optional `instructions` / `tools` / `files`\n * allow-lists (see {@link ScopeInput})\n * @returns A working {@link ScopeInterface}\n *\n * @example\n * ```ts\n * import { createScope } from '@orkestrel/agent'\n *\n * const reader = createScope({ name: 'reader', tools: ['search', 'read'] })\n * reader.narrow({ tools: ['read', 'write'] }).tools // ['read'] — intersection tightens\n * ```\n */\nexport function createScope(input: ScopeInput): ScopeInterface {\n\treturn new Scope(input)\n}\n\n/**\n * Creates a scope registry — a {@link ScopeManagerInterface} holding immutable scopes keyed\n * by their minted `id`, in insertion order.\n *\n * @remarks\n * Starts empty; `create` mints each scope's `id` and stores it (keyed by `id`, so it\n * always adds — two scopes may share a `name`); `scopes()` lists them in insertion order;\n * `remove` (one or a batch) reports `true` only when every supplied id was removed; `clear`\n * empties it. Carries an observable `emitter`\n * ({@link import('./types.js').ScopeManagerEventMap}) wired through the reserved `on`\n * option; the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option), so it can never corrupt a mutation.\n *\n * @param options - Optional `on` hooks (see {@link ScopeManagerOptions})\n * @returns An empty {@link ScopeManagerInterface}\n *\n * @example\n * ```ts\n * import { createScopeManager } from '@orkestrel/agent'\n *\n * const scopes = createScopeManager()\n * const reader = scopes.create({ name: 'reader', tools: ['search'] })\n * ```\n */\nexport function createScopeManager(options?: ScopeManagerOptions): ScopeManagerInterface {\n\treturn new ScopeManager(options)\n}\n\n/**\n * Creates a richer turn context — an {@link AgentContextInterface} assembling a provider request\n * from the optional system prompt, the instruction registry, the workspace registry (the only\n * document channel), the conversation registry that is its `messages` source, the tool registry,\n * and the active scope, which `build()` folds into the next turn's input.\n *\n * @remarks\n * `system` is the optional system prompt; `tools` / `instructions` / `workspaces` are pre-built\n * managers to reuse (empty ones are created when omitted, so `context.workspaces` is always\n * present); `scope` is the initial active filter (`undefined` ⇒ no filtering, changeable afterwards\n * through `context.apply(...)`). The `messages` store is always fresh. `build()` folds the scoped\n * instructions — plus the active workspace's scope-filtered text files (fenced) — into one leading\n * `system` message and appends the scoped conversation (attaching the active workspace's\n * scope-filtered image files' `base64` payload to the last user message), built fresh each call; the active\n * workspace is the sole document/image context. Tools are advertised structurally (through\n * `tools.definitions()`, scope-filtered by the loop), never serialized into the prompt.\n *\n * @param options - Optional `system` / `tools` / `instructions` / `workspaces` / `scope`\n * (see {@link AgentContextOptions})\n * @returns A working {@link AgentContextInterface}\n *\n * @example\n * ```ts\n * import { createAgentContext } from '@orkestrel/agent'\n *\n * const context = createAgentContext({ system: 'You are concise.' })\n * context.instructions.add({ name: 'tone', content: 'Be terse.' })\n * context.messages.add({ role: 'user', content: 'Hi' })\n * context.build() // [{ role: 'system', content: 'You are concise.\\n\\n## Instructions\\n\\nBe terse.' }, { role: 'user', content: 'Hi' }]\n * ```\n */\nexport function createAgentContext(options?: AgentContextOptions): AgentContextInterface {\n\treturn new AgentContext(options)\n}\n\n/**\n * Creates an agent loop — an {@link AgentInterface} composing a\n * {@link ProviderInterface}, its {@link AgentContextInterface}, and a tool registry\n * into a bounded context → provider → tools → repeat turn, exposed as a one-shot\n * `generate` and a live `stream`.\n *\n * @remarks\n * One private loop drives the turn; `generate` drains the same stream `stream`\n * exposes, so they can never diverge. Each turn is bounded by one cancel folded from\n * `signal` + `timeout` + `budget` (through `AbortSignal.any`) — any trip (or `abort()`)\n * commits a partial result (the stream's `result` resolves on a cancel, rejects only\n * on a genuine provider / tool error). The `scheduler` paces between turns; tool\n * iteration is capped at `limit` (default `DEFAULT_AGENT_LIMIT`). Tools are advertised\n * structurally through `context.tools.definitions()`. Two observation surfaces: the\n * {@link AgentChunk} stream (pull — per-token content) and a typed `emitter` (push —\n * lifecycle + `usage` / `tool` / `deny` for fire-and-forget observers).\n *\n * @param provider - The {@link ProviderInterface} the loop drives each turn\n * @param options - Optional `system` / `tools` / `limit` / `timeout` / `budget` /\n * `scheduler` / `signal` (see {@link AgentOptions})\n * @returns A working {@link AgentInterface}\n *\n * @example\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createAgent } from '@orkestrel/agent'\n * import { createTokenBudget } from '@orkestrel/budget'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const agent = createAgent(provider, {\n * \tsystem: 'You are concise.',\n * \tbudget: createTokenBudget({ max: 50_000, scope: 'total' }),\n * })\n * agent.context.messages.add({ role: 'user', content: 'Say hi.' })\n *\n * const stream = agent.stream()\n * for await (const chunk of stream.events) {\n * \tif (chunk.category === 'token') process.stdout.write(chunk.content)\n * }\n * const result = await stream.result // { content, usage?, partial }\n * ```\n */\nexport function createAgent(provider: ProviderInterface, options?: AgentOptions): AgentInterface {\n\treturn new Agent(provider, options)\n}\n\n/**\n * Creates a fresh stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that\n * splits a thinking model's in-content `<think>…</think>` reasoning spans away from the answer,\n * delta by delta, so a provider yields clean content alone and surfaces the accumulated\n * reasoning as {@link import('./types.js').ProviderResult.thinking}. One splitter serves one\n * stream.\n *\n * @remarks\n * Feed each raw wire delta through `split(delta)` (it returns the clean content to\n * surface — possibly `''` mid-think) and settle the stream end with `flush()` (a held\n * partial open tag that never completed returns as final content; an unclosed think\n * span lands on `thinking`). Tags split across deltas are held back until\n * disambiguated, multiple spans accumulate in order, and a nested-looking `<think>`\n * inside an open span is thinking text. One splitter serves one stream — create\n * a fresh one per provider call.\n *\n * @returns A fresh {@link ThinkSplitterInterface} (state empty, outside any span)\n *\n * @example\n * ```ts\n * import { createThinkSplitter } from '@orkestrel/agent'\n *\n * const splitter = createThinkSplitter()\n * const clean = splitter.split('<think>plan the answer</think>Here it is.')\n * clean // 'Here it is.'\n * splitter.thinking // 'plan the answer'\n * ```\n */\nexport function createThinkSplitter(): ThinkSplitterInterface {\n\treturn new ThinkSplitter()\n}\n\n/**\n * Creates an empty unbounded async channel — a {@link ChannelInterface} a producer writes\n * values into (`push`) and ends (`close` / `fail`) regardless of consumption, while a\n * consumer reads them back live through `drain`.\n *\n * @remarks\n * Write and read are decoupled, so the producer never waits for a consumer: an agent's eager\n * pump writes each chunk into one, which is why a run's `result` settles whether or not the\n * live events are drained. A value pushed at an already-parked consumer is delivered, buffered\n * values are yielded before the end is reported, and the first failure wins.\n *\n * @typeParam T - The value type the channel carries\n * @returns A fresh, empty {@link ChannelInterface}\n *\n * @example\n * ```ts\n * import { createChannel } from '@orkestrel/agent'\n *\n * const channel = createChannel<number>()\n * channel.push(1)\n * channel.close()\n * for await (const value of channel.drain()) {\n * \tvalue // 1\n * }\n * ```\n */\nexport function createChannel<T>(): ChannelInterface<T> {\n\treturn new Channel<T>()\n}\n\n/**\n * Creates a policy gate — an {@link AuthorityInterface} the agent loop consults before\n * each tool call runs, evaluating the ordered rules first-match-wins and falling back\n * to the configured default when none match.\n *\n * @remarks\n * `rules` are evaluated in order — the first whose `match` is true decides (a matched\n * rule allows unless its `allowed` is explicitly `false`). When no rule matches, the\n * `fallback` decides; it defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }`\n * (allow-unmatched — a rules list of denials acts as a denylist). Pass an\n * `allowed: false` `fallback` to flip the gate to deny-by-default (an allowlist). Wire\n * the result into `createAgent` through `AgentOptions.authority`: a denied call is fed back\n * to the model as a denial `ToolResult` (not executed, no budget cost), so the model\n * can react. Synchronous — `evaluate` returns the verdict directly.\n *\n * @param options - Optional `rules` (ordered) and `fallback` (see {@link AuthorityOptions})\n * @returns A working {@link AuthorityInterface}\n *\n * @example\n * ```ts\n * import { createAgent, createAuthority } from '@orkestrel/agent'\n *\n * // Deny the `delete` tool, allow everything else.\n * const authority = createAuthority({\n * \trules: [{ match: (c) => c.call.name === 'delete', zone: 'restricted', allowed: false }],\n * })\n * const agent = createAgent(provider, { tools, authority })\n * ```\n */\nexport function createAuthority(options?: AuthorityOptions): AuthorityInterface {\n\treturn new Authority(options)\n}\n\n/**\n * Creates an agent registry — an {@link AgentRegistryInterface} holding the named pools of\n * live, non-serializable pieces (providers, tools, authorities, schedulers) that a\n * serializable {@link AgentJobInput}'s names resolve against, and `build`ing a seeded,\n * signal-wired {@link AgentInterface} from a job.\n *\n * @remarks\n * `providers` is required; `tools` / `authorities` / `schedulers` are optional pools.\n * The accessors (`provider` / `tool` / `authority` / `scheduler`) throw an\n * {@link import('./errors.js').AgentError} carrying `code: 'REGISTRY'` and the message\n * `unknown <category>: <name>` on an unregistered name — a misconfigured or crash-restored\n * job fails loudly rather than running with a missing dependency. `build(input, signal)`\n * resolves the names, rebuilds the token budget from its ceiling, seeds the agent's\n * context with the job's messages, and threads `signal` so a queue / runner abort\n * propagates. This is the bridge that makes durable, serializable agent jobs runnable.\n *\n * @param options - The named pools (see {@link AgentRegistryOptions})\n * @returns A working {@link AgentRegistryInterface}\n *\n * @example\n * ```ts\n * import { createAgentRegistry } from '@orkestrel/agent'\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createTool } from '@orkestrel/tool'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const registry = createAgentRegistry({\n * \tproviders: { main: provider },\n * \ttools: { add: createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }) },\n * })\n * const agent = registry.build({ provider: 'main', messages: [{ role: 'user', content: 'Hi.' }] })\n * ```\n */\nexport function createAgentRegistry(options: AgentRegistryOptions): AgentRegistryInterface {\n\treturn new AgentRegistry(options)\n}\n\n/**\n * Creates a durable, bounded-concurrency agent-job queue — a {@link QueueInterface} over\n * serializable {@link AgentJobInput}s that composes `createQueue`: each job is rehydrated\n * through the `registry` into a live {@link AgentInterface}, run to its {@link AgentResult},\n * and subjected to the partial-as-configurable-failure policy.\n *\n * @remarks\n * - **Composes the substrate (no new engine).** The handler is the only new logic;\n * bounded `concurrency`, `retries`, the per-attempt `timeout`, and durable persistence\n * through `store` (+ `restore()` after a crash) are all the backing Queue's. `enqueue`\n * returns a per-job promise.\n * - **Durable + serializable.** Because `AgentJobInput` is JSON-serializable, a `store`\n * (for example `createMemoryQueueStore` / `createDatabaseQueueStore`) persists outstanding\n * jobs; `restore()` re-enqueues them after a restart and the `registry` rehydrates the\n * live pieces from the names — so a job survives a crash.\n * - **Partial policy.** A partial result throws an\n * {@link import('./errors.js').AgentJobError} by default, so a job cancelled by its\n * attempt deadline / a queue abort retries while attempts remain; `partial: true`\n * resolves the partial as success instead.\n * - **Cancellation threads through.** The handler passes `context.signal` into\n * `registry.build`, so a queue `abort()` or a per-attempt timeout cancels the in-flight\n * agent (which commits a partial → throws → retries / fails per policy).\n *\n * @param options - The `registry`, the `partial` policy, and the substrate knobs\n * (`concurrency` / `retries` / `timeout` / `store`) (see {@link AgentQueueOptions})\n * @returns A {@link QueueInterface} of {@link AgentJobInput} → {@link AgentResult}\n *\n * @example\n * ```ts\n * import { createAgentQueue, createAgentRegistry } from '@orkestrel/agent'\n * import { createMemoryQueueStore } from '@orkestrel/queue'\n *\n * const registry = createAgentRegistry({ providers: { main: provider } })\n * const store = createMemoryQueueStore(agentJobShape) // survives a restart through restore()\n * const queue = createAgentQueue({ registry, concurrency: 2, retries: 1, store })\n * const result = await queue.enqueue({ provider: 'main', messages: [{ role: 'user', content: 'ok?' }] })\n * ```\n */\nexport function createAgentQueue(\n\toptions: AgentQueueOptions,\n): QueueInterface<AgentJobInput, AgentResult> {\n\tconst { registry, partial = false, concurrency, retries, timeout, store } = options\n\treturn createQueue<AgentJobInput, AgentResult>({\n\t\t...(concurrency === undefined ? {} : { concurrency }),\n\t\t...(retries === undefined ? {} : { retries }),\n\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t...(store === undefined ? {} : { store }),\n\t\thandler: handleAgentQueueJob.bind(undefined, registry, partial),\n\t})\n}\n\n/**\n * Creates an agent-job runner — a {@link RunnerInterface} over serializable\n * {@link AgentJobInput}s that composes `createRunner` (one-shot, ordered, fail-fast), each unit\n * rehydrated through the `registry` and subjected to the partial policy. The runner also carries\n * sub-agent fan-out: a parent job's handler can `controller.spawn(childJob)`.\n *\n * @remarks\n * - **Composes the substrate (no new engine).** Bounded `concurrency`, `retries`, the\n * per-attempt `timeout`, ordered results, and fail-fast are all the backing Runner's;\n * the handler adds only rehydration + the partial policy.\n * - **Sub-agent fan-out.** Each unit's handler receives a `ControllerInterface` whose\n * `spawn(childJob)` launches a child agent job through the same bounded queue (the\n * child's result joins the run after the declared units, in spawn order). On a bounded\n * runner, fan out and return — do not inline-`await` a spawn from within the handler (a\n * slot-holding handler awaiting its own spawn can deadlock; see `ControllerInterface`).\n * - **Partial policy + cancellation.** Same as `createAgentQueue`: a partial result\n * throws by default (the run's fail-fast engages), `partial: true` resolves it; the\n * handler threads `controller.signal` into `registry.build`, so a runner abort / a\n * per-attempt timeout cancels the agent.\n *\n * @param options - The `registry`, the `partial` policy, and the substrate knobs\n * (`concurrency` / `retries` / `timeout`) (see {@link AgentRunnerOptions})\n * @returns A {@link RunnerInterface} of {@link AgentJobInput} → {@link AgentResult}\n *\n * @example\n * ```ts\n * import { createAgentRunner, createAgentRegistry } from '@orkestrel/agent'\n *\n * const registry = createAgentRegistry({ providers: { main: provider } })\n * const runner = createAgentRunner({ registry, concurrency: 2 })\n * // Run two jobs; the first fans out a child sub-agent then returns.\n * const child = { provider: 'main', messages: [{ role: 'user', content: 'child' }] }\n * const parent = { provider: 'main', messages: [{ role: 'user', content: 'parent' }] }\n * const results = await runner.execute([parent, child]) // declared first, then any spawns\n * ```\n */\nexport function createAgentRunner(\n\toptions: AgentRunnerOptions,\n): RunnerInterface<AgentJobInput, AgentResult> {\n\tconst { registry, partial = false, concurrency, retries, timeout } = options\n\treturn createRunner<AgentJobInput, AgentResult>({\n\t\t...(concurrency === undefined ? {} : { concurrency }),\n\t\t...(retries === undefined ? {} : { retries }),\n\t\t...(timeout === undefined ? {} : { timeout }),\n\t\thandler: handleAgentRunnerJob.bind(undefined, registry, partial),\n\t})\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["isInstance","objectShape","stringShape","recordShape","jsonShape","literalShape","optionalShape","arrayShape","booleanShape","numberShape","unionShape","createContract","attempt","isObject","isString","isBoolean","isFiniteNumber","parseJSONValue","isBinary","Emitter","isArray","isArray","Emitter","isArray","WorkspaceManager","ToolManager","isText","Emitter","createTimeout","createAbort","errorToMessage","ToolManager","createTokenBudget","attempt","isRecord","isString","arrayOf","isToolCall","isArray","Timeout","cloneJSONValue","Emitter","isArray","parseJSONAs","createMemoryDriver","stringShape","rawShape","createDatabase","createQueue","createRunner"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/shapers.ts","../../../src/core/contracts.ts","../../../src/core/helpers.ts","../../../src/core/conversations/Conversation.ts","../../../src/core/conversations/ConversationManager.ts","../../../src/core/instructions/Instruction.ts","../../../src/core/instructions/InstructionManager.ts","../../../src/core/AgentContext.ts","../../../src/core/Channel.ts","../../../src/core/Agent.ts","../../../src/core/AgentRegistry.ts","../../../src/core/Authority.ts","../../../src/core/validators.ts","../../../src/core/conversations/stores/DatabaseConversationStore.ts","../../../src/core/conversations/stores/MemoryConversationStore.ts","../../../src/core/AgentProvider.ts","../../../src/core/providers/RelayProvider.ts","../../../src/core/RelayStream.ts","../../../src/core/scopes/Scope.ts","../../../src/core/scopes/ScopeManager.ts","../../../src/core/ThinkSplitter.ts","../../../src/core/factories.ts"],"sourcesContent":["/**\n * Caps an {@link AgentInterface} turn's tool iterations by default — `10` context → provider →\n * tools cycles before the loop stops, so a model that keeps requesting tools can never loop\n * forever. Overridable per agent through `AgentOptions.limit`.\n */\nexport const DEFAULT_AGENT_LIMIT = 10\n\n/**\n * Names the zone an {@link AuthorityInterface}'s default fallback {@link AuthorityDecision}\n * carries — `'default'`, the classification for a tool call that matched no rule. Paired with\n * the default `allowed: true` fallback, an unmatched call is allowed under this zone, so a\n * rules list of denials acts as a denylist; a caller wanting deny-by-default supplies an\n * `allowed: false` `fallback` of their own (see `AuthorityOptions`).\n */\nexport const DEFAULT_AUTHORITY_ZONE = 'default'\n\n/**\n * Sets the default number of recent live messages a {@link ConversationInterface}'s `compact()`\n * retains verbatim — `0`, so a manual `compact()` folds every current live message into one\n * summarized section and keeps no tail. A caller retains a recent tail by passing `keep` (on\n * {@link ConversationOptions}, {@link ConversationManagerOptions}, or per-fold through\n * {@link CompactOptions}), folding only the older `count - keep` messages and leaving the most\n * recent `keep` live for the next turn. Overridable everywhere `keep` is accepted.\n */\nexport const DEFAULT_CONVERSATION_KEEP = 0\n\n/**\n * Names the framing label a {@link ConversationInterface}'s `view()` prefixes onto each compacted\n * section's summary so a small model reads it as a condensed recap of earlier turns — the lean\n * `'[Summary of earlier messages] '` marker, never a literal assistant turn to echo or treat as\n * the live answer.\n *\n * @remarks\n * Deliberately a fixed, lean handful of tokens (a short bracketed marker) so the framing adds a\n * bounded `prefix × sections` overhead and never an open-ended blow-up — the\n * {@link ConversationInterface} no-bloat test guard pins exactly that. Kept here (beside\n * {@link DEFAULT_CONVERSATION_KEEP}) as the conversation layer's one tunable framing constant, so\n * the wording has a single source of truth as it is optimized against real small-model behavior\n * (the `view()` recap framing is distinct from `reference()`'s cross-conversation provenance\n * marker, which is rendered inline since it interpolates the per-call provenance `label`).\n */\nexport const CONVERSATION_RECAP_PREFIX = '[Summary of earlier messages] '\n\n/**\n * Names the opening tag a {@link import('./ThinkSplitter.js').ThinkSplitter} recognizes as the start of\n * an in-content reasoning span — `'<think>'`, the de-facto wire convention thinking models\n * (qwen3, DeepSeek-R1 family) emit their chain-of-thought under when a daemon renders it inline\n * instead of on a separate wire field. Paired with {@link THINK_CLOSE}.\n */\nexport const THINK_OPEN = '<think>'\n\n/**\n * Names the closing tag that ends a {@link THINK_OPEN} reasoning span — `'</think>'`. A span the\n * stream never closes (the model was cut off mid-reasoning) is treated as thinking to its end,\n * and {@link import('./types.js').ThinkSplitterInterface.flush} settles it.\n */\nexport const THINK_CLOSE = '</think>'\n\n/**\n * Names the section header {@link import('./AgentContext.js').AgentContext}'s `build()` renders the\n * active workspace's text files under — `'## Workspace'`, the leading line of the dedicated\n * workspace block in the system message and the carrier-split counterpart to the documents and\n * images section headers.\n *\n * @remarks\n * `build()` owns the workspace render (a `Workspace` / `WorkspaceManager` stays file-focused — no\n * `open` / `format` getters), so this header lives here as the agents module's one\n * workspace-section framing constant rather than on a manager. Each workspace text file renders\n * beneath it as a fenced `` File: <path>\\n```<language>\\n<text>\\n``` `` block — the same framing\n * the documents section uses — placed immediately after the documents section in the system block.\n */\nexport const WORKSPACE_SECTION_HEADER = '## Workspace'\n\n/**\n * Estimates the per-message role and framing overhead {@link import('./helpers.js').estimateMessages}\n * adds on top of a message's content estimate — `4` tokens for the fixed wire framing every\n * conversation turn carries (its role tag, its delimiters) that\n * {@link import('./helpers.js').estimateTokens}'s content-only heuristic does not otherwise\n * capture.\n */\nexport const MESSAGE_TOKEN_OVERHEAD = 4\n\n/**\n * Names the coarse, deliberately approximate per-image token cost\n * {@link import('./helpers.js').estimateMessages} charges for each attached image — `512`, because\n * a base64 payload's length is no reliable token proxy.\n *\n * @remarks\n * A base64 image payload's length is not a reliable token proxy (a vision model's actual image\n * token cost depends on resolution / tiling, not byte size), so this is a fixed, coarse\n * per-image estimate rather than a derivation from `image.length` — a planning heuristic, not an\n * exact count.\n */\nexport const IMAGE_TOKEN_ESTIMATE = 512\n\n/**\n * Holds the default provider deadline in milliseconds — `120_000`, the wall-clock bound a call\n * runs under when `AgentProviderInput.timeout` is omitted, folded with the caller's signal so\n * whichever trips first cancels the call.\n */\nexport const DEFAULT_PROVIDER_TIMEOUT = 120_000\n\n/**\n * Bounds the decoded error excerpt's input in bytes — `2048`, the leading bytes of a non-OK\n * response body handed to the decoder before the read cancels the remainder, so a `ProviderError`\n * message never carries a longer excerpt.\n */\nexport const MAX_ERROR_BODY_LENGTH = 2048\n\n/**\n * Holds the default relay request limit in bytes — `1_048_576`, the byte budget a relay applies\n * to an inbound body when `RelayOptions.limit` is omitted, refusing a body that reaches it.\n */\nexport const DEFAULT_RELAY_LIMIT = 1_048_576\n\n/**\n * Names the relay's newline-delimited JSON content type — `'application/x-ndjson; charset=utf-8'`,\n * the header a relay response carries beside `cache-control: no-store`.\n */\nexport const RELAY_CONTENT_TYPE = 'application/x-ndjson; charset=utf-8'\n\n/**\n * Names the public message for an unexpected upstream relay failure — `'relay provider failed'`,\n * the fixed text every `error` frame carries, so an upstream failure's own message never reaches\n * the browser.\n */\nexport const RELAY_PROVIDER_MESSAGE = 'relay provider failed'\n\n/**\n * Names the status a relay answers when the `authorize` callback returns anything but `true` or throws —\n * `401`, carried with no body and reaching the browser as a `ProviderError` with the `HTTP` code.\n */\nexport const UNAUTHORIZED_RELAY_STATUS = 401\n\n/**\n * Names the status a relay answers when the upstream provider call cannot be constructed — `502`,\n * carried with no body after `provider.stream` was entered and threw before returning its\n * iterator.\n */\nexport const UPSTREAM_RELAY_STATUS = 502\n\n/**\n * Names the status a relay answers for a body that is missing, unreadable, or rejected by\n * `providerRequestContract` — `400`, carried with no body and reaching the browser as a\n * `ProviderError` with the `HTTP` code.\n */\nexport const INVALID_RELAY_STATUS = 400\n\n/**\n * Names the status a relay answers for a request body at or above its byte budget — `413`,\n * carried with no body and answered for an aborted inbound read as well.\n */\nexport const OVERSIZED_RELAY_STATUS = 413\n","import type {\n\tAgentResult,\n\tProviderErrorCode,\n\tProviderErrorOptions,\n\tProviderResult,\n} from './types.js'\nimport { isInstance } from '@orkestrel/contract'\n\n// A real error type, not a sentinel. `stream` throws a\n// ProviderAbortError when its bound signal aborts mid-flight, carrying the partial\n// result it had assembled so far so the agent loop can recover the streamed content\n// on cancellation. The guard narrows a caught value with `instanceof`.\n\n/**\n * Reports a provider stream cancelled mid-flight by its bound signal — thrown by a\n * {@link ProviderInterface}'s `stream`, carrying the {@link ProviderResult} assembled from\n * whatever streamed before the cancel and the machine-readable `code` `'ABORT'`.\n *\n * @remarks\n * Lets a caller recover the partial content (and any tool calls / usage seen so far)\n * on cancellation: `catch` the throw, narrow with {@link isProviderAbortError}, and\n * read `partial`. `code` is the machine-readable condition (`'ABORT'` — the only one this\n * error reports), so a `catch` branches on it rather than on the message string. `cause`\n * holds the failure the cancel superseded when a throw raced the abort — the wire decoder's\n * {@link ProviderError}, say — and is undefined when the cancel was the only failure.\n */\nexport class ProviderAbortError extends Error {\n\t/** Names the machine-readable condition — `'ABORT'`: a stream cancelled mid-flight. */\n\treadonly code = 'ABORT' as const\n\treadonly partial: ProviderResult\n\n\tconstructor(partial: ProviderResult, options?: ErrorOptions) {\n\t\tsuper('provider stream aborted', options)\n\t\tthis.name = 'ProviderAbortError'\n\t\tthis.partial = partial\n\t}\n}\n\n/**\n * Narrows an unknown caught value to a {@link ProviderAbortError} through `instanceof`, so a\n * `catch` can recover its `partial` result.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns True if `value` is a {@link ProviderAbortError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tfor await (const delta of provider.stream(messages, signal)) render(delta)\n * } catch (error) {\n * \tif (isProviderAbortError(error)) keep(error.partial.content) // recover partial\n * }\n * ```\n */\nexport function isProviderAbortError(value: unknown): value is ProviderAbortError {\n\treturn isInstance(value, ProviderAbortError)\n}\n\n// A real error type, not a sentinel. An agent job treats a partial result\n// (a job committed early from an abort / budget / timeout) as a failure by default — the\n// queue / runner handler throws this so the Queue's retries + a Runner's fail-fast\n// engage. It carries the partial AgentResult so a caller (or a `retries: 0` enqueue that\n// rejects with it) can still inspect what accumulated. The guard narrows with\n// `instanceof`, mirroring ProviderAbortError / isProviderAbortError above.\n\n/**\n * Reports an {@link AgentInterface} run that ended {@link AgentResult.partial} under a\n * `partial` policy of `false` (the default) — thrown by an agent-job handler (a\n * `createAgentQueue` / `createAgentRunner` job), carrying the partial {@link AgentResult} so\n * the failure stays inspectable, and the machine-readable `code` `'PARTIAL'`.\n *\n * @remarks\n * A partial result means the agent was cancelled (an external `signal` abort, a queue /\n * runner abort threaded in, a `timeout` deadline, or an exhausted token `budget`) rather\n * than finishing naturally. For a durable job that is a failure by default: throwing this\n * lets the Queue's retries re-run the job and a Runner's fail-fast abort its siblings.\n * Set `partial: true` (see `AgentQueueOptions` / `AgentRunnerOptions`) to treat a\n * partial as success instead, in which case this is never thrown. Narrow a caught value\n * with {@link isAgentJobError} to read `partial`. `code` is the machine-readable condition\n * (`'PARTIAL'` — the only one this error reports), so a `catch` branches on it rather than on\n * the message string.\n */\nexport class AgentJobError extends Error {\n\t/** Names the machine-readable condition — `'PARTIAL'`: a job that ended partial under a disallowing policy. */\n\treadonly code = 'PARTIAL' as const\n\t/** Holds the partial {@link AgentResult} the cancelled job produced. */\n\treadonly partial: AgentResult\n\n\tconstructor(message: string, partial: AgentResult) {\n\t\tsuper(message)\n\t\tthis.name = 'AgentJobError'\n\t\tthis.partial = partial\n\t}\n}\n\n/**\n * Narrows an unknown caught value to an {@link AgentJobError} through `instanceof`, so a\n * `catch` can recover its `partial` result.\n *\n * @param value - The value to test (typically a `catch` binding or a rejected enqueue)\n * @returns True if `value` is an {@link AgentJobError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tawait queue.enqueue(job) // retries: 0 → a partial rejects with the error\n * } catch (error) {\n * \tif (isAgentJobError(error)) keep(error.partial.content) // recover the partial content\n * }\n * ```\n */\nexport function isAgentJobError(value: unknown): value is AgentJobError {\n\treturn isInstance(value, AgentJobError)\n}\n\n// A real error type, not a sentinel. A `ConversationInterface.compact()` is a\n// programmer error when no `ConversationSummaryHandler` was supplied — there is nothing to fold\n// the messages with — so it throws this, carrying a machine-readable `code` ('SUMMARIZER')\n// so a `catch` branches on `error.code` instead of parsing the message. The guard narrows a\n// caught value with `instanceof`, mirroring the other errors in this file.\n\n/**\n * Reports a conversation with no {@link ConversationSummaryHandler} to fold its messages with,\n * or with a `sections` cap below `1` — thrown by a {@link ConversationInterface}'s `compact()`\n * or its construction, carrying the machine-readable `code`\n * `'SUMMARIZER' | 'SECTIONS'`.\n *\n * @remarks\n * Compaction requires a summarizer (it digests the folded slice into a section summary and\n * regenerates the rollup); a conversation created without one can still store + `view()` its\n * live tail, but a `compact()` is a programmer error and throws this with `'SUMMARIZER'`.\n * A `sections` cap (on {@link import('./types.js').ConversationOptions} /\n * {@link import('./types.js').ConversationManagerOptions} /\n * {@link import('./types.js').CompactOptions}) must be `>= 1` — a sub-1 cap is a programmer\n * error and throws this with `'SECTIONS'`. Narrow a caught value with\n * {@link isConversationError} and branch on `error.code`.\n */\nexport class ConversationError extends Error {\n\t/** Names the machine-readable condition — `'SUMMARIZER'`: a `compact()` with no summarizer; `'SECTIONS'`: a sub-1 `sections` cap. */\n\treadonly code: 'SUMMARIZER' | 'SECTIONS'\n\n\tconstructor(code: 'SUMMARIZER' | 'SECTIONS', message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'ConversationError'\n\t\tthis.code = code\n\t}\n}\n\n/**\n * Narrows an unknown caught value to a {@link ConversationError} through `instanceof`, so a\n * `catch` can branch on its `code`.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns True if `value` is a {@link ConversationError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tawait conversation.compact()\n * } catch (error) {\n * \tif (isConversationError(error) && error.code === 'SUMMARIZER') addSummarizer()\n * }\n * ```\n */\nexport function isConversationError(value: unknown): value is ConversationError {\n\treturn isInstance(value, ConversationError)\n}\n\n// A real error type, not a sentinel. Concurrent runs on one Agent whose\n// construction carries a shared accounting instance (a `window` context budget, or a\n// construction-level `budget` with no per-run override) would corrupt that shared\n// accounting — so `stream()` throws this synchronously, before any state mutation or\n// emit, rather than letting the runs race. An `AgentRegistry` accessor throws it too, when a\n// rehydration name is absent from its pool. Carries a machine-readable `code` so a `catch`\n// branches on `error.code`, mirroring `ConversationError` above.\n\n/**\n * Reports a concurrent run that would corrupt shared per-agent accounting, or a rehydration\n * name absent from its registry pool — thrown synchronously by an {@link AgentInterface}'s\n * `stream()` (and so by `generate()`, which calls it) and by an\n * {@link AgentRegistryInterface}'s accessors, carrying the machine-readable `code`\n * `'CONCURRENCY' | 'REGISTRY'`. Synchronous means a fire-and-forget\n * `agent.generate().catch(…)` never catches it: `await` the call inside `try`/`catch`, or wrap\n * the call expression itself.\n *\n * @remarks\n * `'CONCURRENCY'` reports a run already in flight on the same agent, plus a construction-level\n * `window` (a shared context budget) or a construction-level `budget` with no per-run override\n * (a shared cost budget) — a second concurrent `stream()` would race its charges against the\n * same shared instance, corrupting the accounting. Use separate agents, or per-run `budget`\n * overrides with no `window`, for genuinely concurrent runs. `'REGISTRY'` reports a rehydration\n * name absent from its registry pool, on `provider` / `tool` / `authority` / `scheduler` /\n * `build`. Narrow a caught value with {@link isAgentError} and branch on `error.code`.\n */\nexport class AgentError extends Error {\n\t/** Names the machine-readable condition — `'CONCURRENCY'`: a concurrent run on a shared accounting agent; `'REGISTRY'`: a rehydration name absent from its registry pool. */\n\treadonly code: 'CONCURRENCY' | 'REGISTRY'\n\n\tconstructor(code: 'CONCURRENCY' | 'REGISTRY', message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'AgentError'\n\t\tthis.code = code\n\t}\n}\n\n/**\n * Narrows an unknown caught value to an {@link AgentError} through `instanceof`, so a `catch`\n * can branch on its `code`.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns True if `value` is an {@link AgentError}; false otherwise\n *\n * @example\n * ```ts\n * try {\n * \tagent.stream()\n * } catch (error) {\n * \tif (isAgentError(error) && error.code === 'CONCURRENCY') useSeparateAgents()\n * }\n * ```\n */\nexport function isAgentError(value: unknown): value is AgentError {\n\treturn isInstance(value, AgentError)\n}\n\n/**\n * Reports a coded provider failure with its HTTP status and underlying cause when available.\n *\n * @remarks\n * The provider base throws this error for a non-OK HTTP response, a missing response\n * body, or a missing settled result when strict assembly is enabled. Concrete wire\n * decoders also use it for malformed records and relayed provider failures.\n * `status` is present only for an `HTTP` failure; other codes leave it undefined.\n */\nexport class ProviderError extends Error {\n\t/** Names the machine-readable condition — `'HTTP'`: a non-OK response, including a relay refusing an oversized request with 413; `'PROTOCOL'`: a missing response body, a malformed wire record, or a strict stream with no settled result; `'PROVIDER'`: an upstream failure carried by a relay error record. */\n\treadonly code: ProviderErrorCode\n\t/** Holds the response status for an HTTP failure, or undefined for other codes. */\n\treadonly status: number | undefined\n\n\tconstructor(code: ProviderErrorCode, message: string, options?: ProviderErrorOptions) {\n\t\tsuper(message, options)\n\t\tthis.name = 'ProviderError'\n\t\tthis.code = code\n\t\tthis.status = options?.status\n\t}\n}\n\n/**\n * Narrows a caught value to the provider failure class through instanceof.\n *\n * @param value - The caught value\n * @returns True if the value is a provider failure; false otherwise\n * @example\n * ```ts\n * isProviderError(new ProviderError('HTTP', 'unavailable', { status: 503 })) // true\n * ```\n */\nexport function isProviderError(value: unknown): value is ProviderError {\n\treturn isInstance(value, ProviderError)\n}\n","import type { ContractShape } from '@orkestrel/contract'\nimport {\n\tarrayShape,\n\tbooleanShape,\n\tjsonShape,\n\tliteralShape,\n\tnumberShape,\n\tobjectShape,\n\toptionalShape,\n\trecordShape,\n\tstringShape,\n\tunionShape,\n} from '@orkestrel/contract'\n\n/**\n * Describes a tool call's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than the domain: non-JSON arguments are refused.\n * Calls carry only id, name, and arguments; execution context stays local.\n * The guard refuses every extra member; the contract parser drops extra members.\n */\nexport const toolCallShape = objectShape({\n\tid: stringShape(),\n\tname: stringShape(),\n\targuments: recordShape(jsonShape()),\n}) satisfies ContractShape\n\n/**\n * Describes a conversation message's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than Message: non-JSON call arguments are refused,\n * and execution context stays local. The guard refuses extra members; the parser drops them.\n */\nexport const messageShape = objectShape({\n\tid: stringShape(),\n\trole: literalShape(['system', 'user', 'assistant', 'tool']),\n\tcontent: stringShape(),\n\tcalls: optionalShape(arrayShape(toolCallShape)),\n\timages: optionalShape(arrayShape(stringShape())),\n}) satisfies ContractShape\n\n/**\n * Describes a provider request's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than ProviderRequest: non-JSON arguments, parameters,\n * or schema members are refused. Execution context stays local; the guard refuses\n * extra members, and the parser drops them.\n */\nexport const providerRequestShape = objectShape({\n\tmessages: arrayShape(messageShape),\n\ttools: optionalShape(\n\t\tarrayShape(\n\t\t\tobjectShape({\n\t\t\t\tname: stringShape(),\n\t\t\t\tdescription: optionalShape(stringShape()),\n\t\t\t\tparameters: optionalShape(recordShape(jsonShape())),\n\t\t\t}),\n\t\t),\n\t),\n\toptions: optionalShape(\n\t\tobjectShape({\n\t\t\tthink: optionalShape(booleanShape()),\n\t\t\tschema: optionalShape(recordShape(jsonShape())),\n\t\t}),\n\t),\n}) satisfies ContractShape\n\n/**\n * Describes a provider result's JSON wire projection.\n *\n * @remarks\n * The wire is strictly narrower than ProviderResult: non-JSON call arguments are\n * refused. Execution context stays local; the guard refuses extra members, and the parser drops them.\n */\nexport const providerResultShape = objectShape({\n\tcontent: stringShape(),\n\tthinking: optionalShape(stringShape()),\n\ttools: optionalShape(arrayShape(toolCallShape)),\n\tusage: optionalShape(\n\t\tobjectShape({\n\t\t\tprompt: numberShape(),\n\t\t\tcompletion: numberShape(),\n\t\t\ttotal: numberShape(),\n\t\t}),\n\t),\n}) satisfies ContractShape\n\n/**\n * Describes the channel-discriminated JSON relay wire projection.\n *\n * @remarks\n * The wire is strictly narrower than RelayFrame through its result and partial\n * fields: non-JSON arguments are refused. Execution context stays local; the guard\n * refuses extra members, and the parser drops them.\n */\nexport const relayFrameShape = unionShape(\n\tobjectShape({ channel: literalShape(['content', 'thinking']), text: stringShape() }),\n\tobjectShape({ channel: literalShape(['result']), result: providerResultShape }),\n\tobjectShape({ channel: literalShape(['abort']), partial: providerResultShape }),\n\tobjectShape({ channel: literalShape(['error']), message: stringShape() }),\n) satisfies ContractShape\n","import { createContract } from '@orkestrel/contract'\nimport {\n\tmessageShape,\n\tproviderRequestShape,\n\tproviderResultShape,\n\trelayFrameShape,\n} from './shapers.js'\n\n/** Validates and projects conversation messages at a JSON wire boundary. */\nexport const messageContract = createContract(messageShape)\n\n/** Validates and projects provider requests at a JSON wire boundary. */\nexport const providerRequestContract = createContract(providerRequestShape)\n\n/** Validates and projects provider results at a JSON wire boundary. */\nexport const providerResultContract = createContract(providerResultShape)\n\n/** Validates and projects channel-discriminated relay frames at a JSON wire boundary. */\nexport const relayFrameContract = createContract(relayFrameShape)\n","import type {\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentRegistryInterface,\n\tAgentResult,\n\tContextSectionFormat,\n\tContextSectionSourceInterface,\n\tMessage,\n\tProviderResult,\n\tRunOutcome,\n\tSection,\n\tTextRead,\n} from './types.js'\nimport type { TokenUsage } from '@orkestrel/budget'\nimport type { JSONValue } from '@orkestrel/contract'\nimport type { QueueContext } from '@orkestrel/queue'\nimport type { ToolCall, ToolResult } from '@orkestrel/tool'\nimport type { ControllerInterface } from '@orkestrel/workflow'\nimport type { FileInterface } from '@orkestrel/workspace'\nimport {\n\tattempt,\n\tisBoolean,\n\tisFiniteNumber,\n\tisObject,\n\tisString,\n\tparseJSONValue,\n} from '@orkestrel/contract'\nimport { isBinary } from '@orkestrel/workspace'\nimport {\n\tCONVERSATION_RECAP_PREFIX,\n\tIMAGE_TOKEN_ESTIMATE,\n\tMESSAGE_TOKEN_OVERHEAD,\n} from './constants.js'\nimport { AgentJobError } from './errors.js'\n\n/**\n * Projects an unknown value onto a fresh, exact `JSONValue` representation of an\n * {@link AgentResult} — capturing each structural field once through a total boundary,\n * accepting conforming accessors and inherited properties, preserving finite negative and\n * fractional usage counts, dropping extras, and resolving `undefined` for a malformed field, a\n * non-finite usage number, a throwing getter, or a hostile or revoked proxy.\n *\n * @remarks\n * This is a total hostile-boundary projection. Each structural field is captured once\n * through Contract's sanctioned exception boundary, so conforming accessors and inherited\n * properties are supported while a throwing getter or revoked proxy returns `undefined`.\n * Present usage counts must be finite numbers; negative and fractional values are preserved,\n * not normalized. Extra input properties are dropped while a fresh exact plain object is rebuilt\n * and deep-gated through\n * {@link import('@orkestrel/contract').parseJSONValue}.\n *\n * @param value - The unknown value to project\n * @returns A fresh JSON value containing only AgentResult fields, or `undefined` when invalid\n *\n * @example\n * ```ts\n * import { agentResultToJSON } from '@orkestrel/agent'\n *\n * agentResultToJSON({ content: 'done', usage: { prompt: 2, completion: 1, total: 3 }, partial: false })\n * // { content: 'done', usage: { prompt: 2, completion: 1, total: 3 }, partial: false }\n * ```\n */\nexport function agentResultToJSON(value: unknown): JSONValue | undefined {\n\tconst captured = attempt(() => {\n\t\tif (!isObject(value)) return undefined\n\n\t\tconst content = Reflect.get(value, 'content')\n\t\tconst thinking = Reflect.get(value, 'thinking')\n\t\tconst usage = Reflect.get(value, 'usage')\n\t\tconst partial = Reflect.get(value, 'partial')\n\t\tif (!isString(content) || !isBoolean(partial)) return undefined\n\t\tif (thinking !== undefined && !isString(thinking)) return undefined\n\n\t\tlet projectedUsage: TokenUsage | undefined\n\t\tif (usage !== undefined) {\n\t\t\tif (!isObject(usage)) return undefined\n\t\t\tconst prompt = Reflect.get(usage, 'prompt')\n\t\t\tconst completion = Reflect.get(usage, 'completion')\n\t\t\tconst total = Reflect.get(usage, 'total')\n\t\t\tif (!isFiniteNumber(prompt) || !isFiniteNumber(completion) || !isFiniteNumber(total)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tprojectedUsage = { prompt, completion, total }\n\t\t}\n\n\t\treturn {\n\t\t\tcontent,\n\t\t\t...(thinking === undefined ? {} : { thinking }),\n\t\t\t...(projectedUsage === undefined ? {} : { usage: projectedUsage }),\n\t\t\tpartial,\n\t\t}\n\t})\n\n\treturn captured.success ? parseJSONValue(captured.value) : undefined\n}\n\n/**\n * Filters a list of items by a {@link import('./types.js').ScopeInterface} allow-list of keys —\n * `undefined` passes everything, `[]` passes nothing, and a non-empty list passes the listed keys\n * alone, order preserved. The pure, total set-membership primitive the context's build step and\n * the agent loop's tool-advertise step apply a scope through.\n *\n * @remarks\n * Three-way by the allow-list's shape, so a `Scope` category cleanly expresses \"all /\n * none / only these\":\n * - `undefined` ⇒ no constraint — every item passes (returned unchanged).\n * - `[]` (empty) ⇒ none pass (no key is in an empty set).\n * - a non-empty list ⇒ only items whose `key(item)` is in the list pass.\n *\n * Order-preserving (it filters `items` in place order, never reorders) and total — never\n * throws. Keys are matched by a `Set` for O(1) membership, so a large list is cheap.\n *\n * @typeParam T - The item type being filtered\n * @param allow - The allow-list of keys (`undefined` ⇒ all, `[]` ⇒ none, else only-listed)\n * @param items - The items to filter (returned unchanged when `allow` is `undefined`)\n * @param key - Extracts the key an item is matched on (for example an instruction's `name`)\n * @returns The items that pass the allow-list, in their original order\n *\n * @example\n * ```ts\n * const items = [{ name: 'a' }, { name: 'b' }]\n * filterAllowList(undefined, items, (i) => i.name) // [{ name: 'a' }, { name: 'b' }] (all)\n * filterAllowList([], items, (i) => i.name) // [] (none)\n * filterAllowList(['b'], items, (i) => i.name) // [{ name: 'b' }] (only listed)\n * ```\n */\nexport function filterAllowList<T>(\n\tallow: readonly string[] | undefined,\n\titems: readonly T[],\n\tkey: (item: T) => string,\n): readonly T[] {\n\tif (allow === undefined) return items\n\tif (allow.length === 0) return []\n\tconst set = new Set(allow)\n\treturn items.filter((item) => set.has(key(item)))\n}\n\n/**\n * Estimates the context-token footprint of a string — the deterministic `ceil(length / 4)`\n * character heuristic {@link estimateMessages} sums over a conversation's messages (the default\n * context-budget estimator).\n *\n * @remarks\n * Approximates `ceil(length / 4)` (≈ four characters per token — the rough average for\n * English text), so the same input always yields the same estimate (no model round-trip).\n * Empty text is `0`. This is a planning heuristic for reasoning about how much a turn's\n * messages cost the next request, not an exact tokenizer count — it never calls a provider,\n * so the agent layer stays provider-agnostic and synchronous where it can be.\n *\n * @param text - The text to estimate (a section summary, a message's content)\n * @returns The estimated token count (`ceil(text.length / 4)`; `0` for empty text)\n *\n * @example\n * ```ts\n * estimateTokens('') // 0\n * estimateTokens('hello') // 2 (ceil(5 / 4))\n * estimateTokens('a'.repeat(40)) // 10\n * ```\n */\nexport function estimateTokens(text: string): number {\n\treturn Math.ceil(text.length / 4)\n}\n\n/**\n * Estimates the context-token footprint of a batch of messages — each message's content plus\n * {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD}, a tool-call JSON estimate, and\n * {@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} for each attached image. The default\n * `consumer` estimator for an agent's context budget (the\n * {@link import('./types.js').AgentOptions} `window`), total and never throwing, and a\n * deliberate provider-agnostic approximation rather than an exact tokenizer count.\n *\n * @remarks\n * Sums, per message, {@link estimateTokens} over its `content` (the `ceil(length / 4)` char\n * heuristic) plus {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (a fixed per-message\n * role/framing overhead) plus, when present, {@link estimateTokens} over its JSON-stringified\n * `calls` plus `images.length * `{@link import('./constants.js').IMAGE_TOKEN_ESTIMATE} (a coarse,\n * deliberately-approximate per-image cost — a base64 length is not a token proxy). Deterministic\n * and provider-free — the same messages always yield the same estimate, with an empty batch `0`.\n * It is the fully-swappable default an agent's auto-compaction context budget charges each\n * turn's new messages through; a caller wanting a sharper count supplies its own `consumer` to\n * `createBudget` instead. Total — never throws: a `calls` `JSON.stringify` that throws (a\n * circular `ToolCall.arguments`) is caught and replaced with a conservative fixed contribution of\n * {@link import('./constants.js').MESSAGE_TOKEN_OVERHEAD} (the same per-message overhead scale)\n * instead of estimating the (unreachable) serialized length.\n *\n * @param messages - The messages to estimate (a turn's appended assistant + tool messages)\n * @returns The summed estimated token count (`0` when empty)\n *\n * @example\n * ```ts\n * estimateMessages([]) // 0\n * estimateMessages([{ id: '1', role: 'user', content: 'hello' }]) // 6 (2 content + 4 overhead)\n * ```\n */\nexport function estimateMessages(messages: readonly Message[]): number {\n\treturn messages.reduce((sum, message) => {\n\t\tconst content = estimateTokens(message.content) + MESSAGE_TOKEN_OVERHEAD\n\t\tlet calls = 0\n\t\tif (message.calls?.length) {\n\t\t\t// `JSON.stringify` over `ToolCall.arguments` can throw (a circular reference) even\n\t\t\t// though this function promises never to throw — so the serialization is wrapped; a\n\t\t\t// throw falls back to a conservative fixed contribution (the same per-message overhead\n\t\t\t// scale) instead of an unreachable serialized-length estimate. The happy path (no\n\t\t\t// throw) is byte-identical to the bare estimate below.\n\t\t\ttry {\n\t\t\t\tcalls = estimateTokens(JSON.stringify(message.calls))\n\t\t\t} catch {\n\t\t\t\tcalls = MESSAGE_TOKEN_OVERHEAD\n\t\t\t}\n\t\t}\n\t\tconst images = (message.images?.length ?? 0) * IMAGE_TOKEN_ESTIMATE\n\t\treturn sum + content + calls + images\n\t}, 0)\n}\n\n/**\n * Runs one rehydrated agent and applies the partial-as-configurable-failure policy — a partial\n * run throws an {@link import('./errors.js').AgentJobError} unless the `partial` policy allows\n * it, and a natural finish resolves. The shared job-handler step `createAgentQueue` and\n * `createAgentRunner` both settle each job through, so the policy can never diverge between\n * them.\n *\n * @remarks\n * A turn that committed partial (a cancel — abort / budget / timeout) is by default a\n * failure, so it throws an {@link import('./errors.js').AgentJobError} carrying the partial\n * (the Queue's retries + a Runner's fail-fast then engage); the `partial` policy resolves\n * it as success instead. A natural finish always resolves with its result.\n *\n * @param agent - The rehydrated {@link AgentInterface} to run to its {@link AgentResult}\n * @param partial - The partial policy. If `true`, a partial result resolves as success; if\n * `false` (the default policy), a partial result throws an {@link AgentJobError}\n * @returns The agent's {@link AgentResult} (a natural finish, or a partial one under the\n * `partial` policy)\n * @throws {AgentJobError} Thrown when the run ended partial and the `partial` policy is `false`\n *\n * @example\n * ```ts\n * const result = await settleAgentJob(registry.build(input, signal), false)\n * ```\n */\nexport async function settleAgentJob(\n\tagent: AgentInterface,\n\tpartial: boolean,\n): Promise<AgentResult> {\n\tconst result = await agent.generate()\n\tif (result.partial && !partial) throw new AgentJobError('agent job ended partial', result)\n\treturn result\n}\n\n/**\n * Handles one queued agent job by rehydrating it through a registry with the queue\n * attempt's signal, then applying the shared partial-result policy.\n *\n * @param registry - The registry that rehydrates the serializable job\n * @param partial - The partial policy. If `true`, a partial result resolves; if `false`, it throws\n * @param input - The serializable agent job\n * @param context - The queue attempt whose signal bounds the agent\n * @returns The settled agent result\n */\nexport function handleAgentQueueJob(\n\tregistry: AgentRegistryInterface,\n\tpartial: boolean,\n\tinput: AgentJobInput,\n\tcontext: QueueContext,\n): Promise<AgentResult> {\n\treturn settleAgentJob(registry.build(input, context.signal), partial)\n}\n\n/**\n * Handles one runner agent job by fanning out its declared children, rehydrating the\n * parent through a registry with the controller signal, and applying the shared\n * partial-result policy.\n *\n * @remarks\n * Children are fired and tracked through the runner controller without awaiting them\n * inline, preserving bounded-runner progress.\n *\n * @param registry - The registry that rehydrates serializable jobs\n * @param partial - The partial policy. If `true`, a partial result resolves; if `false`, it throws\n * @param controller - The runner controller for this parent job\n * @returns The settled parent agent result\n */\nexport function handleAgentRunnerJob(\n\tregistry: AgentRegistryInterface,\n\tpartial: boolean,\n\tcontroller: ControllerInterface<AgentJobInput, AgentResult>,\n): Promise<AgentResult> {\n\tconst children = controller.input.children\n\tif (children !== undefined) for (const child of children) void controller.spawn(child)\n\treturn settleAgentJob(registry.build(controller.input, controller.signal), partial)\n}\n\n/**\n * Renders a path-addressed text body as a fenced reference block — a `File: <path>` label line\n * over a language-tagged fence, the framing an\n * {@link import('./AgentContext.js').AgentContext}'s active-workspace text-file render emits.\n *\n * @remarks\n * Produces `` File: <path>\\n```<language>\\n<content>\\n``` `` — the `File:` label line, then a\n * fenced code block tagged with `language`, the `content` verbatim inside. Pure string assembly,\n * total — never throws. The one fenced-file format string for the whole module — `AgentContext.build()`\n * frames an active workspace's text files with it (each carries its own `language` on its\n * {@link import('@orkestrel/workspace').FileContent} text arm).\n *\n * @param path - The file path shown on the `File:` label line\n * @param language - The fenced-code language tag (for example `'typescript'`)\n * @param content - The file body rendered verbatim inside the fence\n * @returns The fenced reference block\n *\n * @example\n * ```ts\n * import { renderFencedFile } from '@orkestrel/agent'\n *\n * renderFencedFile('src/main.ts', 'typescript', 'const x = 1')\n * // 'File: src/main.ts\\n```typescript\\nconst x = 1\\n```'\n * ```\n */\nexport function renderFencedFile(path: string, language: string, content: string): string {\n\treturn `File: ${path}\\n\\`\\`\\`${language}\\n${content}\\n\\`\\`\\``\n}\n\n/**\n * Sanitizes one reported token count into a safe non-negative integer — a non-finite or\n * non-positive value becomes `0`, and a positive fractional value floors down.\n *\n * @param value - The token count to sanitize\n * @returns The floored count, or `0` when the value is non-finite or non-positive\n */\nexport function sanitizeToken(value: number): number {\n\treturn isFiniteNumber(value) && value > 0 ? Math.floor(value) : 0\n}\n\n/**\n * Sanitizes a {@link TokenUsage} into safe, non-negative integers — the guard an agent's\n * abort-usage path applies to a provider's partial usage before it is charged against a\n * budget or folded into the run total.\n *\n * @remarks\n * Per field (`prompt` / `completion` / `total`): a non-finite value (`NaN`, `+Infinity`,\n * `-Infinity`) or a negative value floors to `0`; a fractional value floors to its\n * non-negative integer part. No upper cap is applied. Total — never throws.\n *\n * @param usage - The token usage to sanitize (for example a provider's abort-partial usage)\n * @returns A new {@link TokenUsage} with every field a safe non-negative integer\n *\n * @example\n * ```ts\n * sanitizeUsage({ prompt: -5, completion: NaN, total: 12.7 }) // { prompt: 0, completion: 0, total: 12 }\n * ```\n */\nexport function sanitizeUsage(usage: TokenUsage): TokenUsage {\n\treturn {\n\t\tprompt: sanitizeToken(usage.prompt),\n\t\tcompletion: sanitizeToken(usage.completion),\n\t\ttotal: sanitizeToken(usage.total),\n\t}\n}\n\n/**\n * Joins the reasoning a run's provider calls separated from the answer — the first call\n * seeds the accumulation, a later call appends blank-line separated so each turn's reasoning\n * stays readable.\n *\n * @remarks\n * Pure and total. `running` is `undefined` until a call surfaces reasoning, so the first join\n * returns `next` verbatim (no leading separator). The result is display/audit metadata that\n * never re-enters the conversation.\n *\n * @param running - The reasoning accumulated so far (`undefined` before the first)\n * @param next - This call's separated reasoning\n * @returns The joined reasoning\n *\n * @example\n * ```ts\n * joinThinking(undefined, 'first') // 'first'\n * joinThinking('', 'x') // 'x'\n * joinThinking('first', 'second') // 'first\\n\\nsecond'\n * ```\n */\nexport function joinThinking(running: string | undefined, next: string): string {\n\tif (running === undefined || running.length === 0) return next\n\treturn next.length === 0 ? running : `${running}\\n\\n${next}`\n}\n\n/**\n * Adds two {@link TokenUsage} values field by field — the running total an agent run keeps\n * across its provider calls.\n *\n * @remarks\n * Pure and total: the first call seeds the total (`running` `undefined` returns `next`\n * unchanged), later calls accumulate. No sanitization happens here — charge a provider's\n * reported usage through {@link sanitizeUsage} first.\n *\n * @param running - The total so far (`undefined` before the first usage-bearing call)\n * @param next - This call's reported usage\n * @returns The summed usage\n *\n * @example\n * ```ts\n * sumUsage(undefined, { prompt: 2, completion: 1, total: 3 }) // { prompt: 2, completion: 1, total: 3 }\n * sumUsage({ prompt: 2, completion: 1, total: 3 }, { prompt: 1, completion: 1, total: 2 })\n * // { prompt: 3, completion: 2, total: 5 }\n * ```\n */\nexport function sumUsage(running: TokenUsage | undefined, next: TokenUsage): TokenUsage {\n\tif (running === undefined) return next\n\treturn {\n\t\tprompt: running.prompt + next.prompt,\n\t\tcompletion: running.completion + next.completion,\n\t\ttotal: running.total + next.total,\n\t}\n}\n\n/**\n * Assembles the settled {@link AgentResult} from a run's {@link RunOutcome} — `thinking` and\n * `usage` are carried only when the run surfaced them, and the loop-internal `exhausted` flag is\n * left out.\n *\n * @remarks\n * Pure and total. An absent optional is omitted rather than stored as `undefined` (the\n * present-when-given convention the message store follows), so a settled result JSON\n * round-trips without an explicit `undefined` field. `exhausted` is loop bookkeeping and does\n * not reach the public result — the `exhaust` event carries it instead.\n *\n * @param outcome - The run's settled outcome\n * @returns The public {@link AgentResult}\n *\n * @example\n * ```ts\n * assembleResult({ content: 'hi', thinking: undefined, usage: undefined, partial: false, exhausted: false })\n * // { content: 'hi', partial: false }\n * ```\n */\nexport function assembleResult(outcome: RunOutcome): AgentResult {\n\tconst result: { content: string; thinking?: string; usage?: TokenUsage; partial: boolean } = {\n\t\tcontent: outcome.content,\n\t\tpartial: outcome.partial,\n\t}\n\tif (outcome.thinking !== undefined) result.thinking = outcome.thinking\n\tif (outcome.usage !== undefined) result.usage = outcome.usage\n\treturn result\n}\n\n/**\n * Synthesizes the denial {@link ToolResult} an authority-blocked call is fed back with — the\n * call's `id` / `name` keyed back, carrying a denial `error` instead of a value.\n *\n * @remarks\n * Pure and total. The rule's `reason` is rendered as `denied: <reason>` when one was given,\n * else the generic `denied by authority`. There is no `value`, so the agent loop feeds it back\n * exactly like a tool error and the model can react to it.\n *\n * @param call - The denied {@link ToolCall}\n * @param reason - The rule's explanation, or `undefined` for the generic denial\n * @returns The failure-arm {@link ToolResult}\n *\n * @example\n * ```ts\n * denyCall({ id: '1', name: 'drop', arguments: {} }, 'read-only mode')\n * // { success: false, id: '1', name: 'drop', error: 'denied: read-only mode' }\n * ```\n */\nexport function denyCall(call: ToolCall, reason: string | undefined): ToolResult {\n\treturn {\n\t\tsuccess: false,\n\t\tid: call.id,\n\t\tname: call.name,\n\t\terror: reason !== undefined ? `denied: ${reason}` : 'denied by authority',\n\t}\n}\n\n/**\n * Renders one context section — the resolved `open`, each item's rendering, and the resolved\n * `close` when one exists, blank-line joined; `undefined` when the section has no items.\n *\n * @remarks\n * Pure and total. A section with no items renders nothing (`undefined`), so an empty or fully\n * scoped-out manager stays silent — its `open` / `close` never appear without items. `close`\n * is the only optional slot: an unset one (there is no built-in close) drops the\n * trailing line.\n *\n * @typeParam T - The section item being rendered\n * @param open - The section's resolved leading text\n * @param items - The already scope-filtered items\n * @param render - Renders one item to its prompt text\n * @param close - The section's resolved trailing text, or `undefined` for none\n * @returns The rendered section, or `undefined` when there are no items\n *\n * @example\n * ```ts\n * renderSection('## Instructions', [{ content: 'Be terse.' }], (one) => one.content, undefined)\n * // '## Instructions\\n\\nBe terse.'\n * renderSection('<rules>', [], (one) => one.content, '</rules>') // undefined (no items)\n * ```\n */\nexport function renderSection<T>(\n\topen: string,\n\titems: readonly T[],\n\trender: (item: T) => string,\n\tclose: string | undefined,\n): string | undefined {\n\tif (items.length === 0) return undefined\n\tconst lines = [open, ...items.map(render)]\n\tif (close !== undefined) lines.push(close)\n\treturn lines.join('\\n\\n')\n}\n\n/**\n * Resolves one section's open text through the format cascade — manager-options override >\n * provider default > built-in header.\n *\n * @remarks\n * Pure and total. The leading text has no per-item level. A manager's `open` already\n * encapsulates `[options-override → built-in]`, so it is reached only when neither the\n * override's `open` nor the provider's `open` applies — and there it is the built-in header.\n *\n * @typeParam T - The section item the manager renders\n * @param manager - The section source (its `format` override + its built-in `open`)\n * @param provider - The provider-default framing for this section, or `undefined`\n * @returns The section's leading text\n *\n * @example\n * ```ts\n * resolveOpen(instructions, undefined) // '## Instructions' (the built-in header)\n * resolveOpen(instructions, { open: '<rules>' }) // '<rules>' (the provider default)\n * ```\n */\nexport function resolveOpen<T>(\n\tmanager: ContextSectionSourceInterface<T>,\n\tprovider: ContextSectionFormat<T> | undefined,\n): string {\n\treturn manager.format?.open ?? provider?.open ?? manager.open\n}\n\n/**\n * Resolves one section's close text through the format cascade — manager-options override >\n * provider default; `undefined` when neither sets one, because there is no built-in close.\n *\n * @remarks\n * Pure and total. There is no built-in close, so a section with neither level set returns\n * `undefined` and {@link renderSection} appends no closing line. Paired with\n * {@link resolveOpen}, one level can wrap the whole group.\n *\n * @typeParam T - The section item the manager renders\n * @param manager - The section source (its `format` override)\n * @param provider - The provider-default framing for this section, or `undefined`\n * @returns The section's trailing text, or `undefined` when no level sets one\n *\n * @example\n * ```ts\n * resolveClose(instructions, undefined) // undefined (no built-in close)\n * resolveClose(instructions, { close: '</rules>' }) // '</rules>'\n * ```\n */\nexport function resolveClose<T>(\n\tmanager: ContextSectionSourceInterface<T>,\n\tprovider: ContextSectionFormat<T> | undefined,\n): string | undefined {\n\treturn manager.format?.close ?? provider?.close\n}\n\n/**\n * Resolves one item's rendering through the format cascade — item override > manager-options\n * override > provider default > built-in rendering.\n *\n * @remarks\n * Pure and total. The item's own `override` is the most-specific level (a fully-rendered\n * string for that item alone). A manager's `render(item)` already encapsulates\n * `[options-override → built-in]`, so it is reached only when no higher level applies — and\n * there it is the built-in rendering.\n *\n * @typeParam T - The section item being rendered (it may carry its own `override`)\n * @param manager - The section source (its `format` override + its built-in `render`)\n * @param provider - The provider-default framing for this section, or `undefined`\n * @param item - The item to render\n * @returns The item's prompt text\n *\n * @example\n * ```ts\n * resolveItem(instructions, undefined, terse) // 'Be terse.' (the built-in rendering)\n * resolveItem(instructions, { render: (one) => `<rule>${one.content}</rule>` }, terse)\n * // '<rule>Be terse.</rule>'\n * ```\n */\nexport function resolveItem<T extends { readonly override?: string }>(\n\tmanager: ContextSectionSourceInterface<T>,\n\tprovider: ContextSectionFormat<T> | undefined,\n\titem: T,\n): string {\n\treturn (\n\t\titem.override ??\n\t\tmanager.format?.render?.(item) ??\n\t\tprovider?.render?.(item) ??\n\t\tmanager.render(item)\n\t)\n}\n\n/**\n * Copies a message with image data merged onto its `images` — the message's own images first,\n * then the attached data, carrying `calls` only when present and never mutating the original.\n *\n * @remarks\n * Pure and total: the original message is never mutated. `calls` is carried only when the\n * source message has one (kept omitted otherwise, mirroring the store's present-when-given\n * convention).\n *\n * @param message - The message to copy (left unchanged)\n * @param data - The base64 image data to attach\n * @returns A new message carrying the merged `images`\n *\n * @example\n * ```ts\n * attachImages({ id: '1', role: 'user', content: 'Describe' }, ['<payload>'])\n * // { id: '1', role: 'user', content: 'Describe', images: ['<payload>'] }\n * ```\n */\nexport function attachImages(message: Message, data: readonly string[]): Message {\n\tconst images = [...(message.images ?? []), ...data]\n\treturn message.calls === undefined\n\t\t? { id: message.id, role: message.role, content: message.content, images }\n\t\t: {\n\t\t\t\tid: message.id,\n\t\t\t\trole: message.role,\n\t\t\t\tcontent: message.content,\n\t\t\t\tcalls: message.calls,\n\t\t\t\timages,\n\t\t\t}\n}\n\n/**\n * Attaches image data to a conversation's last user message — the turn a vision provider reads\n * images off — as a new array with that one message replaced by its carrying copy, and unchanged\n * when there is no data or no user turn.\n *\n * @remarks\n * Pure and total: the conversation and its messages are never mutated, and the returned array\n * replaces exactly the one target message with the copy {@link attachImages} builds. Empty\n * data returns the conversation unchanged; a conversation with no user message returns it\n * unchanged too (there is nowhere to attach, and the images already rode the system block).\n *\n * @param conversation - The messages to attach into (left unchanged)\n * @param data - The base64 image data to attach\n * @returns The conversation with its last user message replaced by the carrying copy\n *\n * @example\n * ```ts\n * attachUserImages([{ id: '1', role: 'user', content: 'Describe' }], ['<payload>'])\n * // [{ id: '1', role: 'user', content: 'Describe', images: ['<payload>'] }]\n * ```\n */\nexport function attachUserImages(\n\tconversation: readonly Message[],\n\tdata: readonly string[],\n): readonly Message[] {\n\tif (data.length === 0) return conversation\n\tlet target = -1\n\tfor (let index = conversation.length - 1; index >= 0; index -= 1) {\n\t\tif (conversation[index]?.role === 'user') {\n\t\t\ttarget = index\n\t\t\tbreak\n\t\t}\n\t}\n\tif (target === -1) return conversation\n\treturn conversation.map((message, index) =>\n\t\tindex === target ? attachImages(message, data) : message,\n\t)\n}\n\n/**\n * Collects the `base64` payload of the image files in a workspace file list — the data an agent\n * context attaches to the last user message.\n *\n * @remarks\n * Pure and total. `isBinary` narrows the tagless content to its binary arm (a total guard,\n * never an assertion), then the MIME prefix gates it to an image, so a text file and a non-image\n * binary (a PDF) are both skipped. Order follows the file list.\n *\n * @param files - The (already scope-filtered) workspace files\n * @returns The `base64` payload of each image file, in file order\n *\n * @example\n * ```ts\n * collectImageData([createFile({ path: 'a.png', content: { base64: '<payload>', mime: 'image/png' } })])\n * // ['<payload>']\n * ```\n */\nexport function collectImageData(files: readonly FileInterface[]): readonly string[] {\n\tconst data: string[] = []\n\tfor (const file of files) {\n\t\tif (isBinary(file.content) && file.content.mime.startsWith('image/')) {\n\t\t\tdata.push(file.content.base64)\n\t\t}\n\t}\n\treturn data\n}\n\n/**\n * Builds the raw synthetic summary message for one compacted section — role `'assistant'`, the\n * section's stable `id`, and its `summary` verbatim as content.\n *\n * @remarks\n * Pure and total. This is the unframed form the rollup regeneration digests (a\n * summary-of-summaries over the section summaries); the recap label is a `view()`\n * presentation concern kept out of what the summarizer re-reads — see\n * {@link buildRecapMessage}.\n *\n * @param section - The compacted section to render\n * @returns The synthetic summary message\n *\n * @example\n * ```ts\n * buildSummaryMessage({ id: 's1', summary: 'recap', messages: [] })\n * // { id: 's1', role: 'assistant', content: 'recap' }\n * ```\n */\nexport function buildSummaryMessage(section: Section): Message {\n\treturn { id: section.id, role: 'assistant', content: section.summary }\n}\n\n/**\n * Builds the framed recap message for one compacted section — the same role and stable `id` as\n * {@link buildSummaryMessage}, with the content prefixed by {@link\n * import('./constants.js').CONVERSATION_RECAP_PREFIX}.\n *\n * @remarks\n * Pure and total. The prefix is what makes a small model read the message as a condensed\n * recap of earlier turns rather than a literal assistant turn to echo or answer from. It is a\n * fixed handful of tokens, so a conversation's `view()` stays lean however many sections it\n * carries.\n *\n * @param section - The compacted section to render\n * @returns The framed recap message\n *\n * @example\n * ```ts\n * buildRecapMessage({ id: 's1', summary: 'recap', messages: [] })\n * // { id: 's1', role: 'assistant', content: `${CONVERSATION_RECAP_PREFIX}recap` }\n * ```\n */\nexport function buildRecapMessage(section: Section): Message {\n\treturn {\n\t\tid: section.id,\n\t\trole: 'assistant',\n\t\tcontent: `${CONVERSATION_RECAP_PREFIX}${section.summary}`,\n\t}\n}\n\n/**\n * Intersects two scope category lists under the \"`undefined` is the universal set\" rule — a\n * fresh copy that can only tighten, and the primitive a scope narrows through.\n *\n * @remarks\n * Pure and total, and it can only tighten: `undefined` ∩ `undefined` is `undefined` (still no\n * constraint); `undefined` ∩ a list is a copy of that list (the `undefined` side imposes\n * nothing); a list ∩ a list keeps the child keys the parent also allows, so a parent-excluded\n * key can never be re-admitted. Every returned list is a fresh copy, so a later mutation of\n * either input cannot leak into the result.\n *\n * @param parent - The parent's allow-list (`undefined` ⇒ no constraint)\n * @param child - The narrowing allow-list (`undefined` ⇒ no constraint)\n * @returns The intersected allow-list, or `undefined` when neither side constrains\n *\n * @example\n * ```ts\n * intersectKeys(['read', 'write'], ['write', 'admin']) // ['write']\n * intersectKeys(undefined, ['read']) // ['read']\n * intersectKeys(undefined, undefined) // undefined\n * ```\n */\nexport function intersectKeys(\n\tparent: readonly string[] | undefined,\n\tchild: readonly string[] | undefined,\n): readonly string[] | undefined {\n\tif (parent === undefined) return child === undefined ? undefined : [...child]\n\tif (child === undefined) return [...parent]\n\tconst allowed = new Set(parent)\n\treturn child.filter((key) => allowed.has(key))\n}\n\n/**\n * Assembles a provider result with only populated optional fields.\n *\n * @param content - The authoritative answer\n * @param thinking - The joined reasoning\n * @param tools - The accumulated calls\n * @param usage - The reported token usage\n * @returns The assembled result\n * @example\n * ```ts\n * buildProviderResult('ok', '', [], undefined) // { content: 'ok' }\n * ```\n */\nexport function buildProviderResult(\n\tcontent: string,\n\tthinking: string,\n\ttools: readonly ToolCall[],\n\tusage: TokenUsage | undefined,\n): ProviderResult {\n\treturn {\n\t\tcontent,\n\t\t...(thinking.length === 0 ? {} : { thinking }),\n\t\t...(tools.length === 0 ? {} : { tools }),\n\t\t...(usage === undefined ? {} : { usage }),\n\t}\n}\n\n/**\n * Reads a UTF-8 prefix of a byte stream and cancels its remainder.\n *\n * @remarks\n * The `limit` parameter bounds bytes passed to the decoder, including a partial final\n * character. An omitted limit reads to completion. A source may deliver a chunk larger\n * than the remaining limit; its unused bytes are discarded without decoding.\n * The read can overshoot by one source chunk. An abort leaves completion false.\n *\n * @param body - The readable byte stream\n * @param limit - The maximum byte prefix, or undefined for the complete stream\n * @param signal - The optional cancellation bound; abort returns the decoded prefix\n * @returns The decoded prefix and whether EOF occurred within the byte budget\n * @example\n * ```ts\n * import { readText } from '@orkestrel/agent'\n *\n * const body = new Response('answer').body\n * if (body !== null) await readText(body, 3) // { text: 'ans', complete: false }\n * ```\n */\nexport async function readText(\n\tbody: ReadableStream<Uint8Array>,\n\tlimit?: number,\n\tsignal?: AbortSignal,\n): Promise<TextRead> {\n\tconst reader = body.getReader()\n\tconst decoder = new TextDecoder()\n\tconst cleanup = new AbortController()\n\tlet remaining = limit ?? Infinity\n\tlet text = ''\n\tlet complete = false\n\ttry {\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid reader.cancel(signal.reason).catch(() => {\n\t\t\t\t\t// Preserve the decoded prefix when source cancellation rejects.\n\t\t\t\t})\n\t\t\t},\n\t\t\t{ once: true, signal: cleanup.signal },\n\t\t)\n\t\tif (signal?.aborted) {\n\t\t\tawait reader.cancel(signal.reason).catch(() => {\n\t\t\t\t// An already-aborted read still returns its empty prefix.\n\t\t\t})\n\t\t}\n\t\twhile (remaining > 0) {\n\t\t\tif (signal?.aborted) break\n\t\t\tconst step = await reader.read()\n\t\t\tif (signal?.aborted) break\n\t\t\tif (step.done) {\n\t\t\t\tcomplete = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconst bytes = step.value.subarray(0, remaining)\n\t\t\ttext += decoder.decode(bytes, { stream: true })\n\t\t\tremaining -= bytes.byteLength\n\t\t}\n\t\treturn { text: text + decoder.decode(), complete }\n\t} finally {\n\t\tcleanup.abort()\n\t\ttry {\n\t\t\tawait reader.cancel()\n\t\t} catch {\n\t\t\t// Preserve the read outcome when cancellation fails.\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n}\n\n/**\n * Decodes UTF-8 chunks with a final flush and releases the stream on every exit.\n *\n * @param body - The readable byte stream\n * @param signal - The optional cancellation bound; abort ends iteration without further chunks\n * @returns Decoded text chunks, including a held decoder tail\n * @example\n * ```ts\n * const body = new Response('answer').body\n * if (body !== null) for await (const chunk of readChunks(body)) render(chunk)\n * ```\n */\nexport async function* readChunks(\n\tbody: ReadableStream<Uint8Array>,\n\tsignal?: AbortSignal,\n): AsyncGenerator<string> {\n\tconst reader = body.getReader()\n\tconst decoder = new TextDecoder()\n\tconst cleanup = new AbortController()\n\ttry {\n\t\tsignal?.addEventListener(\n\t\t\t'abort',\n\t\t\t() => {\n\t\t\t\tvoid reader.cancel(signal.reason).catch(() => {\n\t\t\t\t\t// Preserve the iteration outcome when source cancellation rejects.\n\t\t\t\t})\n\t\t\t},\n\t\t\t{ once: true, signal: cleanup.signal },\n\t\t)\n\t\tif (signal?.aborted) {\n\t\t\tawait reader.cancel(signal.reason).catch(() => {\n\t\t\t\t// An already-aborted iterator still ends without yielding.\n\t\t\t})\n\t\t\treturn\n\t\t}\n\t\tfor (;;) {\n\t\t\tconst step = await reader.read()\n\t\t\tif (signal?.aborted) return\n\t\t\tif (step.done) break\n\t\t\tconst chunk = decoder.decode(step.value, { stream: true })\n\t\t\tif (chunk.length > 0) yield chunk\n\t\t}\n\t\tconst tail = decoder.decode()\n\t\tif (tail.length > 0) yield tail\n\t} finally {\n\t\tcleanup.abort()\n\t\ttry {\n\t\t\tawait reader.cancel()\n\t\t} catch {\n\t\t\t// Preserve the primary outcome when the source refuses cancellation.\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tCompactOptions,\n\tConversationEventMap,\n\tConversationInterface,\n\tConversationOptions,\n\tConversationReferenceOptions,\n\tConversationSnapshot,\n\tConversationSummaryHandler,\n\tMessageInput,\n\tMessage,\n\tSection,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { DEFAULT_CONVERSATION_KEEP } from '../constants.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { ConversationError } from '../errors.js'\nimport { buildRecapMessage, buildSummaryMessage } from '../helpers.js'\n\n/**\n * Represents a conversation — a live uncompacted tail of messages it owns directly above a flat\n * message store, plus compacted, summarized {@link Section}s, a regenerated rollup `summary`, and\n * a `summarizable` flag, with on-demand `rehydrate` and substring `search`, driven by a\n * provider-agnostic {@link ConversationSummaryHandler} seam so `core` never imports a provider.\n * Observable through its own `emitter`.\n *\n * @remarks\n * - **Live tail + sections.** The conversation owns its live tail directly — `#messages` is an\n * insertion-ordered `Map` of immutable {@link Message}s keyed by their minted id\n * (the same store mechanics a flat manager had, folded in: `add` / `message` / `messages` /\n * `remove` / `clear` / `count`), exactly as a `Workspace` owns its files (no separate\n * per-value manager). `#sections` are the compacted history (oldest → newest), each a\n * summarized slice that retains its originals. `#summary` is the rollup (a\n * summary-of-summaries over all sections), regenerated on each compaction (`undefined`\n * until the first).\n * - **`view()`.** Each section folds to one synthetic summary message (role `'assistant'` — a\n * prior-context recap — keyed by the section's stable `id`), then the live messages\n * verbatim. The rollup `summary` is not injected (it is separately pull-able); `view()`\n * carries the per-section summaries, which are the compaction benefit.\n * - **`compact()`.** Folds the oldest `count - keep` live messages into a new section\n * (its `summary` from `#summarize`), removes them from the live tail by id, regenerates the\n * rollup (a second `#summarize` over all section summaries), and emits `summary` then\n * `compact`. Returns the section, or `undefined` when nothing folds (`count <= keep`).\n * Throws a {@link ConversationError} when no `#summarize` was supplied. A compaction calls\n * the summarizer for the section digest and again for the rollup.\n * - **`rehydrate(id)` / `search(query)`.** `rehydrate` returns a section's full original\n * messages (`[]` for an unknown id) and emits `rehydrate` — a pure read (the caller decides\n * whether to re-add them; `rehydrate` never reinserts). `search` is a case-insensitive\n * substring scan of `content` across all messages (every section's originals + the live tail).\n * - **Observable.** The owned {@link emitter} ({@link ConversationEventMap}) carries\n * `compact` / `summary` / `rehydrate`, emitted directly, strictly after the state change;\n * the emitter isolates a listener throw and routes it to its `error` handler (the `error`\n * option), so a buggy observer can never corrupt a compaction.\n *\n * @example\n * ```ts\n * const conversation = new Conversation({ summarize: async (m) => `recap of ${m.length}` })\n * conversation.add([\n * \t{ role: 'user', content: 'Hello' },\n * \t{ role: 'assistant', content: 'Hi there' },\n * ])\n * const section = await conversation.compact() // folds both into one summarized section\n * conversation.view() // [{ role: 'assistant', content: 'recap of 2' }] — the live tail is empty\n * conversation.summary // 'recap of 1' — the rollup over the one section\n * ```\n */\nexport class Conversation implements ConversationInterface {\n\treadonly #id: string\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into a compaction.\n\treadonly #emitter: Emitter<ConversationEventMap>\n\t// The provider-agnostic summarizer seam — `undefined` ⇒ `compact()` throws (a conversation\n\t// can still store + view a live tail; it cannot fold).\n\treadonly #summarize: ConversationSummaryHandler | undefined\n\t// How many recent live messages a `compact()` retains verbatim (older ones fold).\n\treadonly #keep: number\n\t// The optional cap on the compacted sections list — `undefined` ⇒ unlimited. Enforced\n\t// after pushing a fresh `compact()` fold: an overflow folds the oldest sections into one.\n\treadonly #cap: number | undefined\n\t// The compacted history, oldest → newest — each summarized slice retains its originals.\n\treadonly #sections: Section[] = []\n\t// The rollup (a summary-of-summaries over all sections), regenerated on each compaction.\n\t#summary: string | undefined\n\t// The live uncompacted tail the conversation owns directly — an insertion-ordered Map of\n\t// immutable messages keyed by their minted id (the flat store mechanics folded in).\n\treadonly #messages = new Map<string, Message>()\n\n\tconstructor(options?: ConversationOptions) {\n\t\t// An optional snapshot to hydrate from — its `id` is the conversation's identity (so it\n\t\t// wins over `options.id`), and its rollup `summary` / compacted `sections` / live tail are\n\t\t// restored, with the live `summarize` / `keep` / `on` supplied through `options` alongside it\n\t\t// (a summarizer is a function, not serialized — re-supplied as config). Restoring is silent\n\t\t// (no events — nothing was edited). `ConversationOptions.snapshot` is the one declared seam\n\t\t// every caller reaches it through — `createConversation(options)` hydrates through it, and\n\t\t// `ConversationManager.add` passes a stored snapshot in the same options object.\n\t\tconst snapshot = options?.snapshot\n\t\tthis.#id = snapshot?.id ?? options?.id ?? crypto.randomUUID()\n\t\tthis.#emitter = new Emitter<ConversationEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t\tthis.#summarize = options?.summarize\n\t\tthis.#keep = options?.keep ?? DEFAULT_CONVERSATION_KEEP\n\t\tif (options?.sections !== undefined && options.sections < 1) {\n\t\t\tthrow new ConversationError('SECTIONS', 'a sections cap must be >= 1')\n\t\t}\n\t\tthis.#cap = options?.sections\n\t\tif (snapshot !== undefined) {\n\t\t\tthis.#summary = snapshot.summary\n\t\t\tfor (const section of snapshot.sections) this.#sections.push(section)\n\t\t\tfor (const message of snapshot.messages) this.#messages.set(message.id, message)\n\t\t}\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget emitter(): EmitterInterface<ConversationEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget summary(): string | undefined {\n\t\treturn this.#summary\n\t}\n\n\tget sections(): readonly Section[] {\n\t\treturn [...this.#sections]\n\t}\n\n\tget summarizable(): boolean {\n\t\t// True exactly when a summarizer was supplied — the clean signal the agent loop's automatic\n\t\t// compaction gates on (a non-summarizable conversation is never auto-compacted, so the auto\n\t\t// path never throws the `SUMMARIZER` ConversationError). A manual `compact()` still throws.\n\t\treturn this.#summarize !== undefined\n\t}\n\n\tget count(): number {\n\t\treturn this.#messages.size\n\t}\n\n\tadd(input: MessageInput): Message\n\tadd(inputs: readonly MessageInput[]): readonly Message[]\n\tadd(input: MessageInput | readonly MessageInput[]): Message | readonly Message[] {\n\t\tif (isArray(input)) return input.map((one) => this.#create(one))\n\t\treturn this.#create(input)\n\t}\n\n\tmessage(id: string): Message | undefined {\n\t\treturn this.#messages.get(id)\n\t}\n\n\tmessages(): readonly Message[] {\n\t\treturn [...this.#messages.values()]\n\t}\n\n\tremove(id: string): boolean\n\tremove(ids: readonly string[]): boolean\n\tremove(ids: string | readonly string[]): boolean {\n\t\tif (isArray(ids)) {\n\t\t\t// True only when every supplied id was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one.\n\t\t\tlet removed = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (!this.#messages.delete(id)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#messages.delete(ids)\n\t}\n\n\tclear(): void {\n\t\tthis.#messages.clear()\n\t}\n\n\tview(): readonly Message[] {\n\t\t// Each section → one synthetic recap message (the compaction benefit), then the live\n\t\t// tail verbatim. The rollup `summary` is deliberately not injected here. The recap is\n\t\t// framed (a `[Summary of earlier messages]` label prefix) so a small model reads it as a\n\t\t// condensed recap of prior turns, not as a literal assistant turn it must echo / treat as\n\t\t// the latest answer — a lean label (a handful of tokens), proven no-bloat by a test guard.\n\t\treturn [\n\t\t\t...this.#sections.map((section) => buildRecapMessage(section)),\n\t\t\t...this.#messages.values(),\n\t\t]\n\t}\n\n\tasync compact(options?: CompactOptions): Promise<Section | undefined> {\n\t\tconst summarize = this.#summarize\n\t\tif (summarize === undefined) {\n\t\t\tthrow new ConversationError(\n\t\t\t\t'SUMMARIZER',\n\t\t\t\t'cannot compact a conversation without a summarizer',\n\t\t\t)\n\t\t}\n\t\tconst cap = options?.sections ?? this.#cap\n\t\tif (cap !== undefined && cap < 1) {\n\t\t\tthrow new ConversationError('SECTIONS', 'a sections cap must be >= 1')\n\t\t}\n\t\tconst keep = options?.keep ?? this.#keep\n\t\tconst live = [...this.#messages.values()]\n\t\t// Fold the oldest `count - keep` live messages; nothing to fold ⇒ a no-op.\n\t\tconst fold = keep <= 0 ? live.length : live.length - keep\n\t\tif (fold <= 0) return undefined\n\t\tconst slice = live.slice(0, fold)\n\t\t// 1. Digest the folded slice into the section summary (the first summarizer call).\n\t\tconst summary = await summarize(slice)\n\t\tconst section: Section = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\tsummary,\n\t\t\tmessages: slice,\n\t\t}\n\t\t// 2. Remove the folded messages from the live tail (by their ids) and push the section.\n\t\tfor (const message of slice) this.#messages.delete(message.id)\n\t\tthis.#sections.push(section)\n\t\t// 3. Enforce the bounded-`sections` cap: an overflow past `cap` folds the oldest\n\t\t// overflow sections into one merged section (a further summarizer call over the folded\n\t\t// section summaries), so `#sections.length === cap` afterward.\n\t\tif (cap !== undefined && this.#sections.length > cap) {\n\t\t\tconst overflow = this.#sections.length - cap + 1\n\t\t\tconst folded = this.#sections.slice(0, overflow)\n\t\t\ttry {\n\t\t\t\tconst merged: Section = {\n\t\t\t\t\tid: crypto.randomUUID(),\n\t\t\t\t\tsummary: await summarize(folded.map((one) => buildSummaryMessage(one))),\n\t\t\t\t\tmessages: folded.flatMap((one) => one.messages),\n\t\t\t\t}\n\t\t\t\tthis.#sections.splice(0, overflow, merged)\n\t\t\t\tthis.#emitter.emit('collapse', merged)\n\t\t\t} catch (error) {\n\t\t\t\t// The merge summarizer call threw — the sections stay transiently at `cap + 1`\n\t\t\t\t// (no splice, no loss), but the rollup still regenerates over the current\n\t\t\t\t// (unmerged) sections so it is never left stale, then the error propagates\n\t\t\t\t// (manual `compact()` always surfaces a summarizer failure to its caller; the\n\t\t\t\t// next successful `compact()` self-heals the over-cap count).\n\t\t\t\tthis.#summary = await summarize(this.#sections.map((one) => buildSummaryMessage(one)))\n\t\t\t\tthis.#emitter.emit('summary', this.#summary)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t}\n\t\t// 4. Regenerate the rollup — a summary-of-summaries over all (now-capped) sections\n\t\t// — then observe it, after the mutation, through the guarded path.\n\t\tthis.#summary = await summarize(this.#sections.map((one) => buildSummaryMessage(one)))\n\t\tthis.#emitter.emit('summary', this.#summary)\n\t\t// 5. Observe the new section last, so a swallowed listener throw can't perturb the fold.\n\t\tthis.#emitter.emit('compact', section)\n\t\treturn section\n\t}\n\n\trehydrate(id: string): readonly Message[] {\n\t\tconst section = this.#sections.find((one) => one.id === id)\n\t\t// A pure read — emit `rehydrate` after resolving (no mutation to perturb); `rehydrate`\n\t\t// never reinserts the originals (the caller decides). Unknown id ⇒ an empty list.\n\t\tthis.#emitter.emit('rehydrate', id)\n\t\treturn section === undefined ? [] : section.messages\n\t}\n\n\tsearch(query: string): readonly Message[] {\n\t\t// Case-insensitive substring over `content` across all messages — every section's\n\t\t// retained originals (oldest → newest) first, then the live tail.\n\t\tconst needle = query.toLowerCase()\n\t\tconst all = [\n\t\t\t...this.#sections.flatMap((section) => section.messages),\n\t\t\t...this.#messages.values(),\n\t\t]\n\t\treturn all.filter((message) => message.content.toLowerCase().includes(needle))\n\t}\n\n\treference(options?: ConversationReferenceOptions): string {\n\t\t// Render this conversation as a self-labeled, fenced provenance block to pull into another\n\t\t// conversation (as a `document`). A pure string — never a model call. The leading marker\n\t\t// names the source (`label`, default the `id`) and states it is not part of the live\n\t\t// conversation, so a small model reads the rollup + cherry-picked excerpts as foreign\n\t\t// material it attributes to that source, never as its own latest turns.\n\t\tconst label = options?.label ?? this.#id\n\t\tconst lines = [`[Reference — conversation \"${label}\" — NOT part of this conversation]`]\n\t\t// The rollup `summary` (a summary-of-summaries) — included when opted in (default true) and\n\t\t// one exists (`undefined` until the first compaction drops the line).\n\t\tif (options?.summary !== false && this.#summary !== undefined) {\n\t\t\tlines.push(`Summary: ${this.#summary}`)\n\t\t}\n\t\t// The cherry-picked excerpts (each `- role: content`) — the few relevant turns the caller\n\t\t// selected (through this conversation's own `search` / `rehydrate`), not the whole history.\n\t\tconst messages = options?.messages ?? []\n\t\tif (messages.length > 0) {\n\t\t\tlines.push('Relevant messages:')\n\t\t\tfor (const message of messages) lines.push(`- ${message.role}: ${message.content}`)\n\t\t}\n\t\treturn lines.join('\\n')\n\t}\n\n\tsnapshot(): ConversationSnapshot {\n\t\t// The container serializes itself: its id + the rollup summary + the compacted sections +\n\t\t// the live tail. The summarizer / keep are not serialized — they are live config re-supplied\n\t\t// on hydrate (a ConversationSummaryHandler is a function, not data). The sections + messages are\n\t\t// already plain immutable records, so the snapshot JSON-round-trips losslessly; mutates nothing.\n\t\treturn {\n\t\t\tid: this.#id,\n\t\t\t...(this.#summary === undefined ? {} : { summary: this.#summary }),\n\t\t\tsections: this.sections,\n\t\t\tmessages: this.messages(),\n\t\t}\n\t}\n\n\t// Mint an immutable live-tail message from one input — a fresh UUID id plus the input's\n\t// role / content, carrying `calls` / `images` only when the input supplied them (each\n\t// spread in conditionally, so an absent optional is never stored as `undefined`). Stored\n\t// by id and returned; never mutated after creation.\n\t#create(input: MessageInput): Message {\n\t\tconst message: Message = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\trole: input.role,\n\t\t\tcontent: input.content,\n\t\t\t...(input.calls === undefined ? {} : { calls: input.calls }),\n\t\t\t...(input.images === undefined ? {} : { images: input.images }),\n\t\t}\n\t\tthis.#messages.set(message.id, message)\n\t\treturn message\n\t}\n}\n","import type {\n\tConversationInput,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tConversationManagerOptions,\n\tConversationStoreInterface,\n\tConversationSummaryHandler,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { DEFAULT_CONVERSATION_KEEP } from '../constants.js'\nimport { Conversation } from './Conversation.js'\n\n/**\n * Registers {@link Conversation}s keyed by `id`, in insertion order, with an active pointer —\n * the id-keyed store over the conversation layer, the `active` / `switch` seam the\n * {@link import('../AgentContext.js').AgentContext} renders, and the durable `open` / `save`\n * store seam. Event-free (a registry, like\n * {@link import('@orkestrel/workspace').WorkspaceManager}); the observability lives on each\n * {@link Conversation}.\n *\n * @remarks\n * - **Registry.** Conversations live in an insertion-ordered `Map` keyed by `id`. `add(input?)`\n * mints a {@link Conversation} (its `id` from `input` or `crypto.randomUUID()`), flowing the\n * manager's default `#summarize` / `#keep` in unless the `input` overrides them, and stores\n * it (an already-present `id` overwrites — last write wins). `count` is the map size,\n * `conversation(id)` looks one up, `conversations()` lists them in insertion order.\n * - **Active pointer.** `active` is the active conversation (the agent's message source the\n * context renders), `undefined` until the first `add` (which auto-activates it — a registry\n * with conversations always has one active). A subsequent `add` leaves `active` unchanged.\n * `switch(id)` re-points `active` to the conversation with `id` and returns it; an unknown `id`\n * returns `undefined` and leaves `active` unchanged (the lenient lookup style — never throws,\n * no new error code).\n * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id was\n * removed; removing the active conversation sets `active` to `undefined`. `clear` empties the registry\n * and sets `active` to `undefined`.\n * - **Event-free.** A purely registry store — no Emitter, no events (each conversation owns\n * its own observable `emitter`).\n *\n * @example\n * ```ts\n * const manager = new ConversationManager({ summarize: async (m) => `recap of ${m.length}` })\n * const conversation = manager.add() // auto-activates — active === conversation\n * manager.add({ id: 'scratch' }) // leaves active unchanged\n * manager.switch('scratch') // re-points active to the 'scratch' conversation\n * manager.count // 2\n * ```\n */\nexport class ConversationManager implements ConversationManagerInterface {\n\treadonly #conversations = new Map<string, ConversationInterface>()\n\t// The active conversation's id — the message source the context renders; `undefined` until the\n\t// first `add` auto-activates one (kept as an id, never a stale reference, so a re-add / removal\n\t// of that id is reflected through the live map lookup in `active`).\n\t#active: string | undefined\n\t// The default summarizer flowed into every conversation `add` creates (a per-`add` override\n\t// wins); a conversation created with neither cannot `compact` (it throws a ConversationError).\n\treadonly #summarize: ConversationSummaryHandler | undefined\n\t// The default retained-tail size flowed into every conversation `add` creates (overridable).\n\treadonly #keep: number\n\t// The default `sections` cap flowed into every conversation `add` creates (overridable); `undefined` ⇒ unlimited.\n\treadonly #sections: number | undefined\n\t// The optional durable store backing `open` / `save`; `undefined` ⇒ registry-only (both lenient).\n\treadonly #store: ConversationStoreInterface | undefined\n\n\tconstructor(options?: ConversationManagerOptions) {\n\t\tthis.#summarize = options?.summarize\n\t\tthis.#keep = options?.keep ?? DEFAULT_CONVERSATION_KEEP\n\t\tthis.#sections = options?.sections\n\t\tthis.#store = options?.store\n\t}\n\n\tget count(): number {\n\t\treturn this.#conversations.size\n\t}\n\n\tget active(): ConversationInterface | undefined {\n\t\treturn this.#active === undefined ? undefined : this.#conversations.get(this.#active)\n\t}\n\n\tconversation(id: string): ConversationInterface | undefined {\n\t\treturn this.#conversations.get(id)\n\t}\n\n\tconversations(): readonly ConversationInterface[] {\n\t\treturn [...this.#conversations.values()]\n\t}\n\n\tadd(input?: ConversationInput): ConversationInterface {\n\t\t// The manager's defaults flow in unless the input overrides them — so a conversation\n\t\t// created through the manager inherits its summarizer / keep by default. An optional\n\t\t// `snapshot` hydrates the conversation through the declared `ConversationOptions.snapshot`\n\t\t// seam — its `id` / `summary` / `sections` / live tail restored, the live summarize / keep\n\t\t// re-supplied alongside it in the same options object.\n\t\tconst sections = input?.sections ?? this.#sections\n\t\tconst summarize = input?.summarize ?? this.#summarize\n\t\tconst conversation = new Conversation({\n\t\t\t...(input?.id === undefined ? {} : { id: input.id }),\n\t\t\t...(input?.on === undefined ? {} : { on: input.on }),\n\t\t\t...(summarize === undefined ? {} : { summarize }),\n\t\t\tkeep: input?.keep ?? this.#keep,\n\t\t\t...(sections === undefined ? {} : { sections }),\n\t\t\t...(input?.snapshot === undefined ? {} : { snapshot: input.snapshot }),\n\t\t})\n\t\tthis.#conversations.set(conversation.id, conversation)\n\t\t// First conversation auto-activates: a registry that holds conversations always has one active.\n\t\tif (this.#active === undefined) this.#active = conversation.id\n\t\treturn conversation\n\t}\n\n\tswitch(id: string): ConversationInterface | undefined {\n\t\t// Lenient (mirrors `conversation(id)`): an unknown id re-points nothing and returns undefined.\n\t\tconst conversation = this.#conversations.get(id)\n\t\tif (conversation === undefined) return undefined\n\t\tthis.#active = id\n\t\treturn conversation\n\t}\n\n\tasync open(id: string): Promise<ConversationInterface | undefined> {\n\t\t// Already registered ⇒ activate it (no store hit) — the registry is the live source.\n\t\tconst existing = this.#conversations.get(id)\n\t\tif (existing !== undefined) {\n\t\t\tthis.#active = id\n\t\t\treturn existing\n\t\t}\n\t\t// No store ⇒ a registry miss resolves nothing (lenient, like `switch`/`conversation`).\n\t\tif (this.#store === undefined) return undefined\n\t\t// Store hit ⇒ rehydrate through the `snapshot` option (it restores id / summary /\n\t\t// sections / live tail) by reusing `add`, which registers + auto-activates a fresh\n\t\t// Conversation (flowing the manager's default summarize / keep in); a miss ⇒ undefined.\n\t\tconst snapshot = await this.#store.get(id)\n\t\tif (snapshot === undefined) return undefined\n\t\tconst conversation = this.add({ snapshot })\n\t\t// Re-point `active` explicitly: `add` only auto-activates the first conversation, so an open\n\t\t// into a non-empty registry must still make the rehydrated one active.\n\t\tthis.#active = conversation.id\n\t\treturn conversation\n\t}\n\n\tasync save(id: string): Promise<boolean> {\n\t\t// Lenient: persist only when a store is set and the id is registered; otherwise a no-op.\n\t\tconst conversation = this.#conversations.get(id)\n\t\tif (this.#store === undefined || conversation === undefined) return false\n\t\tawait this.#store.set(conversation.snapshot())\n\t\treturn true\n\t}\n\n\t// The array overload comes first, so a list resolves to the batch form (an `id` is a string,\n\t// never an array, so the two never overlap — but the project declares the array overload\n\t// first by convention).\n\tremove(ids: readonly string[]): boolean\n\tremove(id: string): boolean\n\tremove(ids: string | readonly string[]): boolean {\n\t\tif (isArray(ids)) {\n\t\t\t// True only when every supplied id was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one. Each present id still clears `active`\n\t\t\t// when it was the active conversation.\n\t\t\tlet removed = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (!this.#drop(id)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#drop(ids)\n\t}\n\n\tclear(): void {\n\t\tthis.#conversations.clear()\n\t\t// An emptied registry has no active conversation.\n\t\tthis.#active = undefined\n\t}\n\n\t// Delete one conversation by id; when it was the active one, clear the active pointer (a removed\n\t// conversation can never stay active).\n\t#drop(id: string): boolean {\n\t\tconst removed = this.#conversations.delete(id)\n\t\tif (removed && this.#active === id) this.#active = undefined\n\t\treturn removed\n\t}\n}\n","import type { InstructionInput, InstructionInterface } from '../types.js'\n\n/**\n * Represents an immutable named directive — an {@link InstructionInterface} assembled once from\n * its input (`name` / `content`, an optional `priority` defaulting to `0`), the `id` minted at\n * construction.\n *\n * @remarks\n * A thin immutable value object (mirroring {@link import('@orkestrel/tool').Tool}): the\n * constructor mints a fresh `id` (`crypto.randomUUID()`), copies the input's `name` /\n * `content`, resolves `priority` to the input's value or `0`, and carries the input's\n * per-item `override` only when supplied (assigned when present, mirroring a\n * message's `images` / `calls` present-when-given convention — kept absent otherwise).\n * Never mutated after construction. An\n * {@link import('./InstructionManager.js').InstructionManager} keys it by `name` and\n * renders it (highest `priority` first) under its section header.\n *\n * @example\n * ```ts\n * const instruction = new Instruction({ name: 'tone', content: 'Be concise.', priority: 5 })\n * instruction.priority // 5\n * ```\n */\nexport class Instruction implements InstructionInterface {\n\treadonly id: string\n\treadonly name: string\n\treadonly content: string\n\treadonly priority: number\n\t// The per-item rendered override — the cascade's most-specific level. Assigned only when\n\t// the input supplied one, so it stays absent (not present-but-undefined) otherwise.\n\treadonly override?: string\n\n\tconstructor(input: InstructionInput) {\n\t\tthis.id = crypto.randomUUID()\n\t\tthis.name = input.name\n\t\tthis.content = input.content\n\t\tthis.priority = input.priority ?? 0\n\t\tif (input.override !== undefined) this.override = input.override\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tContextSectionFormat,\n\tInstructionInput,\n\tInstructionInterface,\n\tInstructionManagerEventMap,\n\tInstructionManagerInterface,\n\tInstructionManagerOptions,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Instruction } from './Instruction.js'\n\n/**\n * Registers the immutable {@link Instruction}s a richer context assembles a directives block\n * from — keyed by `name` so a re-`add` overwrites, last write wins, and listed by descending\n * `priority`, carrying the `open` / `render` build contract and an observable `emitter`.\n *\n * @remarks\n * - **Registry.** Instructions live in an insertion-ordered `Map` keyed by `name`;\n * `add` takes one {@link InstructionInput} or a batch, mints each instruction's\n * `id`, and a re-`add` of the same name overwrites it (last write wins). `count` is the\n * map size, `instruction(name)` looks one up, and `instructions()` lists them sorted by\n * descending `priority` (a stable sort, so equal priorities keep insertion order).\n * - **Build contract (with the manager-options override).** `open` is the section\n * header a context renders the instructions under; `render(instruction)` renders one\n * instruction (its `content`). Each encapsulates the cascade's `[options-override →\n * built-in]` half: when `InstructionManagerOptions.format` supplies an `open` /\n * `render`, `open` / `render` return it, else the built-in — so a richer context\n * reads one consistent pair and layers the provider default + per-item override on top\n * (see {@link import('../AgentContext.js').AgentContext}). The per-item\n * {@link InstructionInput.override} is round-tripped onto the stored instruction.\n * - **Removal.** `remove` drops one by name, or a batch — `true` only when every supplied\n * name was removed; `clear` empties the registry.\n * - **Observable.** The owned {@link emitter} ({@link InstructionManagerEventMap})\n * carries `add` (the created instruction) / `remove` (the name) / `clear` for\n * fire-and-forget observers. Every event is emitted directly, strictly after the map\n * mutation completes; the emitter isolates a listener throw and routes it to its `error`\n * handler (the `error` option), so a buggy observer can never corrupt a mutation.\n *\n * @example\n * ```ts\n * const manager = new InstructionManager()\n * manager.add([\n * \t{ name: 'tone', content: 'Be concise.', priority: 1 },\n * \t{ name: 'safety', content: 'Refuse unsafe requests.', priority: 10 },\n * ])\n * manager.instructions().map((one) => one.name) // ['safety', 'tone'] — highest priority first\n * ```\n */\nexport class InstructionManager implements InstructionManagerInterface {\n\treadonly #instructions = new Map<string, InstructionInterface>()\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into a mutation.\n\treadonly #emitter: Emitter<InstructionManagerEventMap>\n\t// The manager-options level of the build cascade — consulted first by `open` /\n\t// `render` (falling back to the built-in), so this manager encapsulates the\n\t// `[options-override → built-in]` half and a context layers the rest on top.\n\treadonly #format: ContextSectionFormat<InstructionInterface> | undefined\n\n\tconstructor(options?: InstructionManagerOptions) {\n\t\tthis.#emitter = new Emitter<InstructionManagerEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t\tthis.#format = options?.format\n\t}\n\n\tget emitter(): EmitterInterface<InstructionManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#instructions.size\n\t}\n\n\tget open(): string {\n\t\t// Manager-options override first, else the built-in header.\n\t\treturn this.#format?.open ?? '## Instructions'\n\t}\n\n\tget format(): ContextSectionFormat<InstructionInterface> | undefined {\n\t\t// The raw override — so a context's `build()` can interleave the provider default\n\t\t// beneath it (this getter / `open` / `render` encapsulate override→built-in).\n\t\treturn this.#format\n\t}\n\n\tadd(input: InstructionInput): InstructionInterface\n\tadd(inputs: readonly InstructionInput[]): readonly InstructionInterface[]\n\tadd(\n\t\tinput: InstructionInput | readonly InstructionInput[],\n\t): InstructionInterface | readonly InstructionInterface[] {\n\t\tif (isArray(input)) return input.map((one) => this.#create(one))\n\t\treturn this.#create(input)\n\t}\n\n\tinstruction(name: string): InstructionInterface | undefined {\n\t\treturn this.#instructions.get(name)\n\t}\n\n\tinstructions(): readonly InstructionInterface[] {\n\t\t// A stable descending-priority sort — Array.prototype.sort is stable, so equal\n\t\t// priorities keep their insertion order (the map's iteration order).\n\t\treturn [...this.#instructions.values()].sort((a, b) => b.priority - a.priority)\n\t}\n\n\trender(instruction: InstructionInterface): string {\n\t\t// Manager-options override first, else the built-in (its `content`).\n\t\treturn this.#format?.render?.(instruction) ?? instruction.content\n\t}\n\n\tremove(name: string): boolean\n\tremove(names: readonly string[]): boolean\n\tremove(names: string | readonly string[]): boolean {\n\t\tif (isArray(names)) {\n\t\t\t// True only when every supplied name was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one. Each present name still emits.\n\t\t\tlet removed = true\n\t\t\tfor (const name of names) {\n\t\t\t\tif (!this.#delete(name)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#delete(names)\n\t}\n\n\tclear(): void {\n\t\tthis.#instructions.clear()\n\t\t// Observe the cleared registry — after the map emptied, so a swallowed listener\n\t\t// throw can never alter the clear (no payload — `clear` is a pure signal).\n\t\tthis.#emitter.emit('clear')\n\t}\n\n\t// Mint an immutable instruction, store it by name (overwriting a same-name one), and\n\t// emit `add` after the map mutation — so a swallowed listener throw can't perturb it.\n\t#create(input: InstructionInput): InstructionInterface {\n\t\tconst instruction = new Instruction(input)\n\t\tthis.#instructions.set(instruction.name, instruction)\n\t\tthis.#emitter.emit('add', instruction)\n\t\treturn instruction\n\t}\n\n\t// Delete one instruction, emitting `remove` only when one was actually removed (a\n\t// delete of an absent name returns `false` and emits nothing) — after the deletion.\n\t#delete(name: string): boolean {\n\t\tconst removed = this.#instructions.delete(name)\n\t\tif (removed) this.#emitter.emit('remove', name)\n\t\treturn removed\n\t}\n}\n","import type {\n\tAgentContextInterface,\n\tAgentContextOptions,\n\tContextFormat,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tInstructionManagerInterface,\n\tMessage,\n\tMessageManagerInterface,\n\tScopeInterface,\n} from './types.js'\nimport type { ToolManagerInterface } from '@orkestrel/tool'\nimport type { WorkspaceManagerInterface } from '@orkestrel/workspace'\nimport { ToolManager } from '@orkestrel/tool'\nimport { isText, WorkspaceManager } from '@orkestrel/workspace'\nimport { WORKSPACE_SECTION_HEADER } from './constants.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport {\n\tattachUserImages,\n\tcollectImageData,\n\tfilterAllowList,\n\trenderFencedFile,\n\trenderSection,\n\tresolveClose,\n\tresolveItem,\n\tresolveOpen,\n} from './helpers.js'\nimport { InstructionManager } from './instructions/InstructionManager.js'\n\n/**\n * Assembles a provider request from the richer turn context — the optional system prompt, the\n * observable context managers (instructions / workspaces), the\n * {@link ConversationManagerInterface} message source whose active conversation is `messages`, the\n * {@link ToolManagerInterface} registry, and an active {@link ScopeInterface} changed through\n * {@link AgentContextInterface.apply}. `build()` folds the scoped managers and the active\n * workspace into one system block, then the conversation, and never reads `tools`.\n *\n * @remarks\n * - **Composition.** `system` is the optional system prompt; `instructions` / `tools` /\n * `workspaces` / `conversations` are the registries passed in `options` (bring your own), or\n * fresh empty ones when omitted (so `workspaces` is always present); `messages` is the active\n * conversation's live tail (always defined — see the following item). `scope` is the active filter —\n * `undefined` (the default) ⇒ no filtering; change it through `apply(scope)`. The structural\n * `workspaces` / `conversations` registries are fixed at construction; switch their active\n * members through their own `switch(id)` methods.\n * - **The message source — the conversation registry's active conversation.** `conversations` is a\n * {@link ConversationManagerInterface}; the context ensures it always has an active conversation\n * (at construction it `add`s a default when the manager has none), so the dynamic `messages`\n * getter — `this.#conversations.active` — is always defined. `messages` returns the active\n * conversation itself (it owns the live tail + the message verbs directly, satisfying\n * {@link MessageManagerInterface} structurally — the same reference, no duplication), and\n * `build()` folds that conversation's `view()` (its per-section summaries + live tail) as the\n * authoritative message inclusion — the scope does not filter the conversation (it owns inclusion\n * through compaction; scope filters only instructions / tools / workspace files). Because `messages`\n * is read dynamically, an agent switches the active\n * conversation between runs (`conversations.switch(id)`) to serve many threads (the real\n * multi-conversation pattern); switch between runs, not during a run, and use separate agents\n * for concurrent threads.\n * - **`build(format?)` — the scoped assembly + the format cascade.** It folds, in order,\n * the system prompt then the scope-filtered instructions → the active workspace's text files\n * (each as a block: the section's resolved `open` text, each item's resolved rendering, then\n * any resolved `close` text) into one leading `system` message (prepended only when at least\n * one part exists), then appends the active conversation's `view()` (the conversation owns\n * message inclusion through compaction — the scope does not filter the conversation). Each\n * `open` / item / `close`\n * resolves independently, most-specific-first — `build()`'s optional `format` (a provider's\n * per-section default) is the provider level: `open` = manager-options-override > provider >\n * built-in; per item = item-override > manager-options-override > provider > built-in; `close` =\n * manager-options-override > provider (no built-in ⇒ no closing line when unset) (see\n * {@link AgentContextInterface.build}). Passing no `format` (and with no overrides / no per-item\n * override) reproduces the built-in framing byte-for-byte (each section is its built-in header +\n * items, no closing line). The active workspace's scoped-in image files' `base64` payload is attached to\n * the last user message (a vision provider reads images off a user turn); when no user message\n * exists the attachment is skipped. Built fresh each call (recomputed, never cached), so it\n * always reflects the current managers / messages / scope / active workspace; it never mutates a\n * manager or the stored messages.\n * - **The active workspace, rendered by carrier — the sole document/image context.**\n * `workspaces.active` (when set) has its {@link import('@orkestrel/workspace').FileInterface}s scope-filtered by `scope.files`,\n * then split: text files fold into a dedicated `## Workspace` system section (fenced reference\n * blocks — placed right after the instructions section), and image files' `base64` payload attaches\n * to the last user message. Active-only — never the other registered workspaces; with no active\n * workspace nothing renders for workspaces. `build()` owns this render (a `Workspace` /\n * `WorkspaceManager` stays file-focused).\n * - **Tools are structural, not in the prompt.** The registry is advertised to the provider\n * through `tools.definitions()` (scope-filtered by the loop), never serialized into the\n * message array — so `build()`'s output carries no tool content, scoped or not.\n * - **Event-free context; observable managers.** The context itself owns no Emitter; the\n * context managers each carry their own (the push observation surface).\n *\n * @example\n * ```ts\n * const context = new AgentContext({ system: 'You are concise.' })\n * context.instructions.add({ name: 'tone', content: 'Be terse.' })\n * context.messages.add({ role: 'user', content: 'Hi' })\n * context.build() // [{ role: 'system', content: 'You are concise.\\n\\n## Instructions\\n\\nBe terse.' }, { role: 'user', content: 'Hi' }]\n * ```\n */\nexport class AgentContext implements AgentContextInterface {\n\treadonly #system: string | undefined\n\treadonly #instructions: InstructionManagerInterface\n\t// The workspace registry whose active workspace `build()` renders by carrier (text files →\n\t// the system block, image files → the last user message). Always present (a fresh empty\n\t// manager when none was supplied). The registry is structural; switch its active workspace\n\t// through `workspaces.switch(id)`. `build()` reads `active` / its `files()` fresh each call.\n\treadonly #workspaces: WorkspaceManagerInterface\n\t// The conversation registry whose active conversation is the message source: the dynamic\n\t// `messages` getter returns `#conversations.active` (always defined — the constructor ensures one)\n\t// and `build()` folds that conversation's `view()`. Always present. The registry is structural;\n\t// switch its active conversation through `conversations.switch(id)`.\n\treadonly #conversations: ConversationManagerInterface\n\treadonly #tools: ToolManagerInterface\n\t#scope: ScopeInterface | undefined\n\n\tconstructor(options?: AgentContextOptions) {\n\t\tthis.#system = options?.system\n\t\tthis.#instructions = options?.instructions ?? new InstructionManager()\n\t\t// Default to a fresh empty registry so `context.workspaces` is always present (mirroring\n\t\t// the always-present instruction manager); a supplied one is reused. The active workspace\n\t\t// is the sole document/image context.\n\t\tthis.#workspaces = options?.workspaces ?? new WorkspaceManager()\n\t\t// The conversation registry the message source flows from — a supplied one is reused, else a\n\t\t// fresh empty one. Ensure an active conversation so `context.messages` (the active conversation's\n\t\t// live tail) is always defined: when the manager has none active, `add()` a default (which\n\t\t// auto-activates it). NB: `messages` is not captured here — it is computed dynamically (the\n\t\t// getter reads `#conversations.active`), so it always tracks the current active conversation's\n\t\t// live tail, no duplication.\n\t\tthis.#conversations = options?.conversations ?? new ConversationManager()\n\t\tif (this.#conversations.active === undefined) this.#conversations.add()\n\t\tthis.#tools = options?.tools ?? new ToolManager()\n\t\tthis.#scope = options?.scope\n\t}\n\n\tget system(): string | undefined {\n\t\treturn this.#system\n\t}\n\n\tget instructions(): InstructionManagerInterface {\n\t\treturn this.#instructions\n\t}\n\n\tget workspaces(): WorkspaceManagerInterface {\n\t\treturn this.#workspaces\n\t}\n\n\t// Dynamic — the active conversation itself (it owns its live tail + the message verbs directly,\n\t// like a `Workspace` owns its files), always defined: the constructor ensures the registry has an\n\t// active conversation. Computed on every read (never captured), so `context.messages` always\n\t// points at the current active conversation (the same reference — no duplication) and follows a\n\t// `conversations.switch(id)`. The active `Conversation` satisfies the message-verb contract\n\t// directly, so this stays a `MessageManagerInterface`. The `?? this.#ensure()` fallback re-seats\n\t// a default if a caller's supplied manager was emptied (for example `clear()`), so the getter is\n\t// total — never undefined.\n\tget messages(): MessageManagerInterface {\n\t\treturn this.#conversations.active ?? this.#ensure()\n\t}\n\n\tget conversations(): ConversationManagerInterface {\n\t\treturn this.#conversations\n\t}\n\n\tget tools(): ToolManagerInterface {\n\t\treturn this.#tools\n\t}\n\n\tget scope(): ScopeInterface | undefined {\n\t\treturn this.#scope\n\t}\n\n\tapply(scope: ScopeInterface | undefined): void {\n\t\tthis.#scope = scope\n\t}\n\n\tbuild(format?: ContextFormat): readonly Message[] {\n\t\tconst scope = this.#scope\n\t\t// 1–2. Assemble the system block parts: the prompt, then each scoped manager's\n\t\t// section (its resolved `open` + each item's resolved rendering + any resolved\n\t\t// `close`) when it has any scoped-in items. Tools are not folded in — they reach the\n\t\t// provider structurally. Each slot resolves through the format cascade (`resolveOpen` /\n\t\t// `resolveItem` / `resolveClose`): open = manager-options-override > provider-default >\n\t\t// built-in; per item = item-override > manager-options-override > provider-default >\n\t\t// built-in; close = manager-options-override > provider-default (no built-in ⇒ no\n\t\t// closing line). With no `format` arg + no overrides + no per-item `override` it is\n\t\t// byte-for-byte the built-ins (each section's header + items, no closing line).\n\t\tconst parts: string[] = []\n\t\t// Configured by `=== undefined`, not falsiness — an explicitly supplied '' (or a\n\t\t// whitespace-only) system is opted in and prepended verbatim, exactly as the lean\n\t\t// context did (a refactor to a truthiness check would wrongly drop it).\n\t\tif (this.#system !== undefined) parts.push(this.#system)\n\t\tconst instructions = filterAllowList(\n\t\t\tscope?.instructions,\n\t\t\tthis.#instructions.instructions(),\n\t\t\t(one) => one.name,\n\t\t)\n\t\tconst instructed = renderSection(\n\t\t\tresolveOpen(this.#instructions, format?.instructions),\n\t\t\tinstructions,\n\t\t\t(one) => resolveItem(this.#instructions, format?.instructions, one),\n\t\t\tresolveClose(this.#instructions, format?.instructions),\n\t\t)\n\t\tif (instructed !== undefined) parts.push(instructed)\n\t\t// The active workspace's files, rendered by carrier — the sole document/image context.\n\t\t// Filter `active.files()` by `scope.files`, then split: text files fold into the\n\t\t// `## Workspace` system section (fenced reference blocks, the `renderFencedFile` framing — placed\n\t\t// right after the instructions section, grouping the in-prompt text content), image files'\n\t\t// `base64` payload attaches to the last user message (collected below, fed to\n\t\t// `attachUserImages`). `build()` owns this render — a `Workspace` / `WorkspaceManager` stays\n\t\t// file-focused (no `open` / `format` getters). No active workspace ⇒ nothing renders\n\t\t// (active-only).\n\t\tconst files = filterAllowList(\n\t\t\tscope?.files,\n\t\t\tthis.#workspaces.active?.files() ?? [],\n\t\t\t(one) => one.path,\n\t\t)\n\t\tconst workspaceTexts = files.filter((file) => isText(file.content))\n\t\t// The text files have no format-cascade level of their own (they are not a manager) — the\n\t\t// header is the fixed `WORKSPACE_SECTION_HEADER` and each item renders through `renderFencedFile`\n\t\t// off its own text arm (`{ text, language }`), narrowed by `isText` (a total guard, never an\n\t\t// assertion; the preceding pre-filter means the defensive arm is never reached). An empty set\n\t\t// contributes nothing (`renderSection` returns `undefined`).\n\t\tconst documented = renderSection(\n\t\t\tWORKSPACE_SECTION_HEADER,\n\t\t\tworkspaceTexts,\n\t\t\t(file) =>\n\t\t\t\tisText(file.content)\n\t\t\t\t\t? renderFencedFile(file.path, file.content.language, file.content.text)\n\t\t\t\t\t: renderFencedFile(file.path, 'text', ''),\n\t\t\tundefined,\n\t\t)\n\t\tif (documented !== undefined) parts.push(documented)\n\n\t\t// 4. The conversation. The active conversation's `view()` is authoritative (the per-section\n\t\t// summaries + the live tail) — the conversation owns message inclusion through compaction, so the\n\t\t// scope does not filter the conversation here (scope filters only the preceding instructions /\n\t\t// tools / workspace files). The active conversation is always present (the constructor ensures\n\t\t// one), with `#ensure()` as a total fallback if a caller emptied its supplied registry.\n\t\tconst active = this.#conversations.active ?? this.#ensure()\n\t\tconst conversation = active.view()\n\t\t// 5. Attach the active workspace's scoped-in image files' `base64` payload to the last user\n\t\t// message (a vision provider reads images off a user turn) — the active workspace is the\n\t\t// sole image source. Skipped when there is none. (Applies to the conversation's view too.)\n\t\tconst tail = attachUserImages(conversation, collectImageData(files))\n\n\t\t// 3. Prepend one assembled system message only when some part exists.\n\t\tif (parts.length === 0) return tail\n\t\tconst system: Message = {\n\t\t\tid: crypto.randomUUID(),\n\t\t\trole: 'system',\n\t\t\tcontent: parts.join('\\n\\n'),\n\t\t}\n\t\treturn [system, ...tail]\n\t}\n\n\t// The total fallback that keeps `messages` / `build()` defined even if a caller's supplied\n\t// conversation registry was emptied after construction (for example `conversations.clear()`): `add()` a\n\t// default (auto-activating it when the registry is empty) and return it. Returns the\n\t// `ConversationInterface` (which satisfies `MessageManagerInterface` structurally for the\n\t// `messages` getter and carries `view()` for `build()`). Normally never reached — the constructor\n\t// already seeds an active conversation.\n\t#ensure(): ConversationInterface {\n\t\tconst conversation = this.#conversations.add()\n\t\treturn this.#conversations.active ?? conversation\n\t}\n}\n","import type { ChannelInterface } from './types.js'\n\n/**\n * Buffers chunks in a minimal unbounded async channel — the eager pump writes them in (`push`)\n * and ends it (`close` / `fail`) regardless of consumption, while a consumer reads them back live\n * through the `drain` async-iterator. Decoupling write from read is what lets a producer make\n * progress without a consumer pulling, and it is why an agent's `result` settles whether or not\n * its `events` are drained.\n *\n * @remarks\n * The standard resolver-swap: a waiting `drain` parks on `#wake` (a void resolver);\n * `push` / `close` / `fail` enqueue/flag, then fire `#wake` so the parked reader wakes,\n * re-reads the buffer, and either yields the next chunk, returns (on `close`), or throws\n * (on `fail`). Event-free, no `!` / `as` / `any`.\n *\n * @example\n * ```ts\n * import { Channel } from '@orkestrel/agent'\n *\n * const channel = new Channel<number>()\n * channel.push(1)\n * channel.close()\n * for await (const value of channel.drain()) {\n * \tvalue // 1\n * }\n * ```\n */\nexport class Channel<T> implements ChannelInterface<T> {\n\treadonly #buffer: Array<{ value: T }> = []\n\t#wake: (() => void) | undefined\n\t#closed = false\n\t#failure: { error: unknown } | undefined\n\n\tpush(value: T): void {\n\t\tthis.#buffer.push({ value })\n\t\tthis.#signal()\n\t}\n\n\tclose(): void {\n\t\tthis.#closed = true\n\t\tthis.#signal()\n\t}\n\n\tfail(error: unknown): void {\n\t\t// First failure wins; a later close / fail can't override a recorded error.\n\t\tif (this.#failure === undefined) this.#failure = { error }\n\t\tthis.#closed = true\n\t\tthis.#signal()\n\t}\n\n\tasync *drain(): AsyncGenerator<T, void> {\n\t\tfor (;;) {\n\t\t\t// Yield everything buffered before checking for end, so a close / fail that\n\t\t\t// arrives alongside the last chunks still delivers those chunks first.\n\t\t\tfor (let cell = this.#buffer.shift(); cell !== undefined; cell = this.#buffer.shift())\n\t\t\t\tyield cell.value\n\t\t\tif (this.#failure !== undefined) throw this.#failure.error\n\t\t\tif (this.#closed) return\n\t\t\tawait this.#parked()\n\t\t}\n\t}\n\n\t// Resolve the parked reader (if any) and clear the slot — a fresh `#parked()` arms\n\t// the next wait. A `signal` with no parked reader is a no-op (the buffer / flags are\n\t// already set, so the next `drain` pass reads them without parking).\n\t#signal(): void {\n\t\tconst wake = this.#wake\n\t\tthis.#wake = undefined\n\t\twake?.()\n\t}\n\n\t#parked(): Promise<void> {\n\t\treturn new Promise<void>((resolve) => {\n\t\t\tthis.#wake = resolve\n\t\t})\n\t}\n}\n","import type {\n\tAgentChunk,\n\tAgentContextInterface,\n\tAgentEventMap,\n\tAgentInterface,\n\tAgentOptions,\n\tAgentResult,\n\tAgentRunOptions,\n\tAgentStatus,\n\tAgentStreamInterface,\n\tAuthorityDecision,\n\tAuthorityInterface,\n\tMessage,\n\tProviderInterface,\n\tProviderResult,\n\tRunOutcome,\n} from './types.js'\nimport type { AbortInterface } from '@orkestrel/abort'\nimport type { BudgetInterface, TokenUsage } from '@orkestrel/budget'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { ToolCall, ToolManagerInterface, ToolResult } from '@orkestrel/tool'\nimport type { SchedulerInterface } from '@orkestrel/workflow'\nimport type { TimeoutInterface } from '@orkestrel/timeout'\nimport { createAbort } from '@orkestrel/abort'\nimport { createTimeout } from '@orkestrel/timeout'\nimport { Emitter } from '@orkestrel/emitter'\nimport { errorToMessage } from '@orkestrel/workflow'\nimport { AgentContext } from './AgentContext.js'\nimport { Channel } from './Channel.js'\nimport { DEFAULT_AGENT_LIMIT } from './constants.js'\nimport { AgentError, isProviderAbortError } from './errors.js'\nimport {\n\tassembleResult,\n\tdenyCall,\n\testimateTokens,\n\tfilterAllowList,\n\tjoinThinking,\n\tsanitizeUsage,\n\tsumUsage,\n} from './helpers.js'\n\n/**\n * Composes a {@link ProviderInterface}, an {@link AgentContext}, and a\n * {@link ToolManagerInterface} into a bounded context → provider → tools → repeat turn, exposed\n * as both a one-shot `generate` and a live `stream` that share one private run — bounded by the\n * run `signal`, the `timeout`, and the `budget` folded through `AbortSignal.any`, paced by\n * `scheduler`, with tool iteration capped at `limit`.\n *\n * @remarks\n * - **One loop, two faces.** A single private async generator (`#run`) drives the\n * whole turn. `stream` kicks off an eager pump that iterates `#run` into a private\n * {@link Channel}, settling `result` from the run's outcome — so `result` settles\n * whether or not the live `events` are drained; `generate` awaits that same\n * settled `result` — so the two can never diverge.\n * - **The turn.** `#run` builds the provider input once (`context.build()` into a\n * working array) then loops up to `limit`: drive `provider.stream(...)` accumulating\n * + yielding each content delta as a `token` chunk; fold the turn's usage into the\n * running total + the `budget` and yield a `usage` chunk; if the model requested\n * tools, append the assistant turn, `execute` them, yield a `tool` chunk per call,\n * append each tool result message, and continue; otherwise append the final\n * assistant message and stop.\n * - **Bounded.** Each run arms one cancel through `createAbort({ signal: AbortSignal.any([\n * …]) })` folding the external `signal`, the `timeout` deadline, and the `budget`\n * signal; `abort()` fires it. Any trip stops the loop and commits a partial result\n * (the `result` promise resolves, never rejects, on a cancel) — only a genuine\n * provider / tool error rejects.\n * - **Paced + capped.** The `scheduler` (when given) `yield`s between turns; tool\n * iteration is capped at `limit`.\n * - **Two observation surfaces.** The pull {@link AgentChunk} stream carries per-token\n * deltas (+ usage/tool chunks); the push {@link emitter} ({@link AgentEventMap}) carries\n * lifecycle + usage/tool/deny moments for fire-and-forget observers. Every event is\n * emitted directly, after the relevant state transition / settle; the emitter isolates a\n * listener throw and routes it to its `error` handler (the `error` option), so a buggy\n * observer can never escape into / reorder / corrupt the settle-once loop — observation is\n * purely a side-channel.\n *\n * @example\n * ```ts\n * const agent = new Agent(provider, { system: 'You are concise.' })\n * agent.context.messages.add({ role: 'user', content: 'Say hi.' })\n * const result = await agent.generate()\n * ```\n */\nexport class Agent implements AgentInterface {\n\treadonly #id: string\n\treadonly #provider: ProviderInterface\n\treadonly #context: AgentContextInterface\n\treadonly #limit: number\n\treadonly #timeoutMs: number | undefined\n\treadonly #budget: BudgetInterface<TokenUsage> | undefined\n\treadonly #scheduler: SchedulerInterface | undefined\n\treadonly #signal: AbortSignal | undefined\n\treadonly #authority: AuthorityInterface | undefined\n\t// The context budget for automatic conversation compaction — its `consumer`\n\t// is a token estimator, its `max` the context window. `#trim` re-measures the absolute current\n\t// prompt against it (clear() + consume(messages)) before the first provider request and between\n\t// turns; `undefined` ⇒ disabled: `#trim` is a no-op and the loop is byte-for-byte the prior\n\t// behavior. Reset (`clear()`) at run entry so no stale `consumed` carries across runs / a\n\t// conversation switch. Not the hard cost `budget` ceiling — when the prompt reaches its `max`\n\t// this compacts + continues (non-fatal on a summarizer throw, futile-guarded), never aborts.\n\treadonly #window: BudgetInterface<readonly Message[]> | undefined\n\t// When true, a summarizer failure during automatic compaction rethrows (after the\n\t// `fault` event) instead of skipping compaction and continuing over-window.\n\treadonly #strict: boolean\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into the loop. No\n\t// `destroy()`: the Agent holds no other teardownable resources, and an `Emitter` owns\n\t// only listener `Set`s (no timers / handles), so it is reclaimed with the agent — there\n\t// is no leak to clear, and adding lifecycle the entity does not otherwise need is avoided.\n\treadonly #emitter: Emitter<AgentEventMap>\n\t// The label the last run settled on. `status` derives the live answer from `#runs`, so an\n\t// overlapping run can never report `done` while another is still in flight.\n\t#settled: AgentStatus = 'idle'\n\t// Every in-flight run's abort handle — a run adds its handle on `stream()` and the\n\t// pump removes it when it settles, so `abort()` fires every live run, not only the\n\t// most recent. Per-run, never a single shared slot a later `stream()` could clobber:\n\t// `generate`/`stream` are reusable and may overlap, and each run must cancel\n\t// independently (its own `stream.abort()` fires its own handle; `agent.abort()` fires\n\t// them all).\n\treadonly #runs = new Set<AbortInterface>()\n\n\tconstructor(provider: ProviderInterface, options?: AgentOptions) {\n\t\tthis.#id = crypto.randomUUID()\n\t\tthis.#provider = provider\n\t\tthis.#context = new AgentContext({\n\t\t\t...(options?.system === undefined ? {} : { system: options.system }),\n\t\t\t...(options?.tools === undefined ? {} : { tools: options.tools }),\n\t\t\t...(options?.instructions === undefined ? {} : { instructions: options.instructions }),\n\t\t\t...(options?.workspaces === undefined ? {} : { workspaces: options.workspaces }),\n\t\t\t...(options?.scope === undefined ? {} : { scope: options.scope }),\n\t\t\t...(options?.conversations === undefined ? {} : { conversations: options.conversations }),\n\t\t})\n\t\tthis.#limit = options?.limit ?? DEFAULT_AGENT_LIMIT\n\t\tthis.#timeoutMs = options?.timeout\n\t\tthis.#budget = options?.budget\n\t\tthis.#scheduler = options?.scheduler\n\t\tthis.#signal = options?.signal\n\t\tthis.#authority = options?.authority\n\t\tthis.#window = options?.window\n\t\tthis.#strict = options?.strict ?? false\n\t\tthis.#emitter = new Emitter<AgentEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget emitter(): EmitterInterface<AgentEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget status(): AgentStatus {\n\t\t// Derived, never stored: a live run outranks any settled label, so overlapping runs can\n\t\t// never report `done` while one is still in flight, and a settled `error` is not erased\n\t\t// by a later run's `done` until that later run itself settles.\n\t\treturn this.#runs.size > 0 ? 'running' : this.#settled\n\t}\n\n\tget context(): AgentContextInterface {\n\t\treturn this.#context\n\t}\n\n\tgenerate(options?: AgentRunOptions): Promise<AgentResult> {\n\t\t// Zero loop logic of its own — start the stream (whose eager pump settles `result`\n\t\t// independently of any consumer) and await that same settled result, so `generate`\n\t\t// and `stream` can never diverge. No manual drain needed: the pump runs regardless.\n\t\treturn this.stream(options).result\n\t}\n\n\tstream(options?: AgentRunOptions): AgentStreamInterface {\n\t\t// Concurrency guard: a run already in flight plus a shared construction-level\n\t\t// accounting instance (a `window` context budget, or a construction `budget` with no\n\t\t// per-run override) would race its charges against that shared instance — corrupting\n\t\t// the accounting. Thrown synchronously, before any state mutation or emit, so a\n\t\t// sequential/awaited caller is never affected and a concurrent run with no `window` and\n\t\t// a per-run `budget` override is still allowed.\n\t\tif (\n\t\t\tthis.#runs.size > 0 &&\n\t\t\t(this.#window !== undefined || (this.#budget !== undefined && options?.budget === undefined))\n\t\t) {\n\t\t\tthrow new AgentError(\n\t\t\t\t'CONCURRENCY',\n\t\t\t\t'concurrent runs on one agent with a shared construction window/budget corrupt accounting; use separate agents or per-run budgets',\n\t\t\t)\n\t\t}\n\t\t// Resolve effective per-run bounds — a per-run override wins, else the\n\t\t// construction default. `limit` and `budget` also thread into `#run` (the loop bound\n\t\t// + the mid-stream charging); `budget` here is the same instance folded into `#parents`,\n\t\t// so its trip both aborts the run and is the budget `#run` charges against.\n\t\tconst timeoutMs = options?.timeout ?? this.#timeoutMs\n\t\tconst timeout = timeoutMs === undefined ? undefined : createTimeout({ ms: timeoutMs })\n\t\ttimeout?.start()\n\t\tconst budget = options?.budget ?? this.#budget\n\t\t// A construction-level budget (`this.#budget`, not a per-run `options?.budget` override) is\n\t\t// a shared cumulative tally across every sequential run on this agent — concurrent streams\n\t\t// on one agent race their charges against the same instance. Use separate agents (or a\n\t\t// per-run `options.budget`) for concurrent streams that must not share a budget.\n\t\tbudget?.start()\n\t\tconst limit = options?.limit ?? this.#limit\n\t\t// Fold every present bound (external signal + a per-run signal + deadline + budget)\n\t\t// into one cancel the run races against; this run's own `abort()` fires this handle.\n\t\tconst signal = this.#parents(timeout, budget, options?.signal)\n\t\tconst abort = createAbort(signal === undefined ? {} : { signal })\n\t\tthis.#runs.add(abort)\n\t\t// Observe the run begin — after the run joins `#runs` (which is what `status` derives\n\t\t// `running` from), so a swallowed listener throw can't perturb the state the pump is\n\t\t// about to drive.\n\t\tthis.#emitter.emit('start', this.id)\n\t\tconst channel = new Channel<AgentChunk>()\n\t\tconst settled = Promise.withResolvers<AgentResult>()\n\t\t// Kick off the eager pump synchronously (not lazily on first `events` pull): it\n\t\t// drives `#run` into the channel and settles `settled` regardless of whether anyone\n\t\t// drains `events`. The per-run `think` / `schema` preferences ride through to\n\t\t// `provider.stream`; `limit` / `budget` ride through as the effective run bounds.\n\t\tvoid this.#pump(\n\t\t\tabort,\n\t\t\ttimeout,\n\t\t\tchannel,\n\t\t\tsettled,\n\t\t\toptions?.think,\n\t\t\toptions?.schema,\n\t\t\tlimit,\n\t\t\tbudget,\n\t\t)\n\t\t// An abandoned handle (neither `events` drained nor `result` awaited) must not surface an\n\t\t// unhandledRejection on a genuine error — guard the public result, where the rejection lives\n\t\t// (#pump's finally rejects `settled` without re-throwing, so the pump promise itself resolves).\n\t\t// A caller who awaits `result` still gets the rejection: `.catch` returns a derived promise, it\n\t\t// does not consume the original's rejection.\n\t\tsettled.promise.catch(() => {})\n\t\treturn {\n\t\t\tevents: this.#events(channel, abort),\n\t\t\tresult: settled.promise,\n\t\t\t// Fire this run's own handle (the closed-over `abort`), never a shared field a\n\t\t\t// later `stream()` could have replaced — so a handle's `abort()` always cancels\n\t\t\t// the run it belongs to, even when runs overlap.\n\t\t\tabort: abort.abort.bind(abort),\n\t\t}\n\t}\n\n\tabort(reason?: unknown): void {\n\t\t// Cancel every in-flight run — iterate a snapshot so a settle-driven `#runs.delete`\n\t\t// (a cancelled run unwinding) can't disturb the walk. Aborting is idempotent, so an\n\t\t// already-finished or already-cancelled handle is a harmless no-op.\n\t\tfor (const abort of [...this.#runs]) abort.abort(reason)\n\t}\n\n\t// The eager pump — the drive behind both faces. Kicked off synchronously in `stream`\n\t// (not lazily on an `events` pull), it drives `#run` and `push`es each chunk into the\n\t// channel as it arrives, then settles `result` from the outcome the generator returns: a\n\t// normal / cancelled finish `close`s the channel and resolves the assembled result (status\n\t// `done`); a genuine provider / tool error (the bound signal not aborted) `fail`s the\n\t// channel and rejects (status `error`). The generator is driven by hand rather than with\n\t// `for await`, which discards a generator's return value — the settled `RunOutcome` is that\n\t// return value, so the run owns its state and nothing is threaded through a caller-held box.\n\t// Because the pump runs regardless of whether anyone drains `events`, `result` always\n\t// settles — that is the fix for the no-drain hang. The deadline `clear()` lives in the\n\t// `finally` so it always fires (drained or not), and `result` settles exactly once through\n\t// the shared resolvers (the underlying promise obeys native settle-once — the first resolve\n\t// / reject wins).\n\tasync #pump(\n\t\tabort: AbortInterface,\n\t\ttimeout: TimeoutInterface | undefined,\n\t\tchannel: Channel<AgentChunk>,\n\t\tsettled: PromiseWithResolvers<AgentResult>,\n\t\tthink: boolean | undefined,\n\t\tschema: Readonly<Record<string, unknown>> | undefined,\n\t\tlimit: number,\n\t\tbudget: BudgetInterface<TokenUsage> | undefined,\n\t): Promise<void> {\n\t\tlet failure: { error: unknown } | undefined\n\t\t// The outcome of a run that produced nothing — replaced by whatever `#run` returns, and\n\t\t// read only on the success path (a genuine failure rejects from `failure` instead).\n\t\tlet outcome: RunOutcome = {\n\t\t\tcontent: '',\n\t\t\tthinking: undefined,\n\t\t\tusage: undefined,\n\t\t\tpartial: false,\n\t\t\texhausted: false,\n\t\t}\n\t\ttry {\n\t\t\tconst run = this.#run(abort, think, schema, limit, budget)\n\t\t\tlet next = await run.next()\n\t\t\twhile (next.done !== true) {\n\t\t\t\tchannel.push(next.value)\n\t\t\t\tnext = await run.next()\n\t\t\t}\n\t\t\toutcome = next.value\n\t\t} catch (error) {\n\t\t\tfailure = { error }\n\t\t} finally {\n\t\t\ttimeout?.clear()\n\t\t\t// This run is settling — drop its handle so a later `agent.abort()` no longer\n\t\t\t// fires it (and the set never leaks finished runs).\n\t\t\tthis.#runs.delete(abort)\n\t\t\tif (failure === undefined) {\n\t\t\t\tthis.#settled = 'done'\n\t\t\t\tchannel.close()\n\t\t\t\tconst result = assembleResult(outcome)\n\t\t\t\tsettled.resolve(result)\n\t\t\t\t// Observe the settle — after `settled.resolve(...)` (the result is already\n\t\t\t\t// settled; emit only observes it). A cancel still resolves a partial, so a\n\t\t\t\t// cancelled run emits `abort` (the cancel reason) then `finish` (the settled\n\t\t\t\t// partial) — observers see both \"it was cancelled\" and the partial outcome; a\n\t\t\t\t// natural / cap finish (`partial: false`) emits `finish` only. Limit exhaustion\n\t\t\t\t// (unresolved tool intent at the turn cap) is not a cancel — it emits `exhaust`\n\t\t\t\t// (the turn count) instead of `abort`, still followed by `finish`. Both emits are\n\t\t\t\t// post-settle, so an isolated listener throw can't reorder the latch.\n\t\t\t\tif (outcome.exhausted) this.#emitter.emit('exhaust', limit)\n\t\t\t\telse if (outcome.partial) this.#emitter.emit('abort', abort.signal.reason)\n\t\t\t\tthis.#emitter.emit('finish', result)\n\t\t\t} else {\n\t\t\t\tthis.#settled = 'error'\n\t\t\t\tchannel.fail(failure.error)\n\t\t\t\tsettled.reject(failure.error)\n\t\t\t\t// Observe the genuine (non-cancel) failure — after `settled.reject(...)`.\n\t\t\t\tthis.#emitter.emit('error', failure.error)\n\t\t\t}\n\t\t}\n\t}\n\n\t// The live event stream: drain the channel the pump writes into, yielding each\n\t// `AgentChunk` as it is pushed (and throwing if the pump `fail`ed the channel). Its\n\t// `return()` — fired when a consumer `break`s out early — fires the turn abort, so the\n\t// run stops promptly: the pump then completes the loop with `partial: true`, `clear`s\n\t// the deadline, and settles `result` to a non-misleading `{ partial: true }` (never the\n\t// old `{ content: '', partial: false }`), leaving `status` no longer `running`.\n\tasync *#events(\n\t\tchannel: Channel<AgentChunk>,\n\t\tabort: AbortInterface,\n\t): AsyncGenerator<AgentChunk, void> {\n\t\ttry {\n\t\t\tyield* channel.drain()\n\t\t} finally {\n\t\t\t// Early break (consumer stopped pulling): cancel the run so the pump unwinds and\n\t\t\t// settles partial. A natural end reaches here too with the signal already done, so\n\t\t\t// this abort is a harmless no-op then.\n\t\t\tabort.abort()\n\t\t}\n\t}\n\n\t// The core loop, shared by generate + stream. Builds the provider input once, then\n\t// iterates up to `limit`: stream the provider (yielding token chunks), fold usage,\n\t// dispatch any tool calls (yielding tool chunks) and continue, else finish. A cancel\n\t// (the bound abort) stops the loop and marks the outcome partial — it never throws;\n\t// only a genuine provider / tool error propagates. The run owns its state: every mutable\n\t// field lives in these locals for the length of one call (so concurrent runs share\n\t// nothing), and the settled `RunOutcome` is what the generator returns to `#pump`.\n\tasync *#run(\n\t\tabort: AbortInterface,\n\t\tthink: boolean | undefined,\n\t\tschema: Readonly<Record<string, unknown>> | undefined,\n\t\tlimit: number,\n\t\tbudget: BudgetInterface<TokenUsage> | undefined,\n\t): AsyncGenerator<AgentChunk, RunOutcome> {\n\t\t// Pass the provider's optional context-framing default into `build()` — the\n\t\t// provider level of the format cascade. An agnostic provider supplies no `format`,\n\t\t// so `build(undefined)` reproduces the managers' built-in framing exactly.\n\t\tconst messages: Message[] = [...this.#context.build(this.#provider.format)]\n\t\tconst tools = this.#context.tools\n\t\tlet content = ''\n\t\tlet thinking: string | undefined\n\t\tlet usage: TokenUsage | undefined\n\t\t// Limit-exhaustion tracking — `pending` is `true` while the most recent turn left\n\t\t// unresolved tool intent (the tool branch was taken and the loop is about to `continue`);\n\t\t// `broke` marks whether the loop exited through an explicit `break` (a cancel, or the natural\n\t\t// final-answer finish) rather than the `for` condition failing. Exhaustion is exactly\n\t\t// \"the condition failed (`!broke`) while tool intent was still pending\" — a `limit: 0` run\n\t\t// never enters the loop, so both stay `false` and the outcome is non-partial.\n\t\tlet pending = false\n\t\tlet broke = false\n\t\tlet partial = false\n\t\tlet exhausted = false\n\t\t// Per-run auto-compaction state — a local, so it starts fresh each run (never carried\n\t\t// across runs or a conversation switch). `futile` is the futile-compaction guard:\n\t\t// once a `compact()` returns `undefined` while still over the window, the prompt can't\n\t\t// shrink further, so auto-compaction stops for the rest of this run (no per-turn churn).\n\t\tlet futile = false\n\t\t// Auto-compaction is enabled only when both a `#window` budget is set and the active\n\t\t// conversation can summarize (`summarizable` — it has a summarizer). There is always an\n\t\t// active conversation, but the default one has no summarizer, so this gate preserves the shipped\n\t\t// behavior: a non-summarizable conversation is never auto-compacted (and the loop never throws\n\t\t// the `compact()` SUMMARIZER error from the auto path). Gating the whole auto-compaction path\n\t\t// (the run-entry `clear()` reset + the pre-first-turn `await this.#trim`) behind this flag keeps\n\t\t// the loop purely additive: with no window or a non-summarizable conversation, no extra `await`\n\t\t// is introduced before the first provider request, so the eager-pump / abort timing is\n\t\t// byte-for-byte the prior behavior (a synchronously-fired abort still lands exactly as before).\n\t\t// When enabled: reset `#window` at run entry so no stale `consumed` carries across runs / a\n\t\t// conversation switch, then run a pre-first-turn `#trim` so a resumed / long conversation whose\n\t\t// initial prompt already exceeds the window compacts at once (not only after a tool turn) —\n\t\t// skipped when already aborted (a pre-aborted run commits its empty partial without compaction).\n\t\tconst compacting =\n\t\t\tthis.#window !== undefined && this.#context.conversations.active?.summarizable === true\n\t\tif (compacting) {\n\t\t\tthis.#window?.clear()\n\t\t\t// Pre-first-turn: `latch: false` — an `undefined` fold here means the tail is too short\n\t\t\t// yet (this run's turns haven't accumulated), not permanently futile, so it must not disable\n\t\t\t// auto-compaction for the run; the growing tail can still fold on the between-turns checks.\n\t\t\tif (!abort.signal.aborted) futile = await this.#trim(messages, false)\n\t\t}\n\t\tfor (let turn = 0; turn < limit; turn += 1) {\n\t\t\t// Observe each iteration begin (the turn index). The emitter isolates a listener\n\t\t\t// throw, so it can't perturb the loop that immediately follows.\n\t\t\tthis.#emitter.emit('turn', turn)\n\t\t\t// Pace between expensive turns — never after the last (the loop body decides). A\n\t\t\t// scheduler honours the signal by rejecting a pending yield on abort (the standard\n\t\t\t// AbortSignal convention), so a cancel landing at the turn boundary surfaces here as\n\t\t\t// a throw, not as the `aborted` check that follows. Treat that exactly like a mid-stream\n\t\t\t// cancel: stop and commit a partial (resolve), never reject — a cancel is not an\n\t\t\t// error. A non-abort yield rejection (a genuine scheduler fault) still propagates.\n\t\t\tif (turn > 0) {\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#scheduler?.yield({ signal: abort.signal })\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (abort.signal.aborted) {\n\t\t\t\t\t\tpartial = true\n\t\t\t\t\t\tbroke = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tthrow error\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (abort.signal.aborted) {\n\t\t\t\tpartial = true\n\t\t\t\tbroke = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t\t// Advertise only the tools the active scope admits — a scoped-out tool is filtered\n\t\t\t// from the definitions handed to the provider, so the model never sees it and thus\n\t\t\t// can't call it (neither described nor callable). `undefined` scope ⇒ all pass.\n\t\t\tconst advertised = filterAllowList(\n\t\t\t\tthis.#context.scope?.tools,\n\t\t\t\ttools.definitions(),\n\t\t\t\t(definition) => definition.name,\n\t\t\t)\n\t\t\tconst definitions = advertised.length > 0 ? advertised : undefined\n\t\t\t// Bounded mid-stream budget enforcement — a per-turn local accumulator (`turnContent`,\n\t\t\t// distinct from the run-spanning `content`) so `charged` (the amount already consumed\n\t\t\t// against `budget` this turn) never mixes with prior turns' content. As each content delta\n\t\t\t// arrives, re-estimate the turn's token footprint so far and consume only the increment\n\t\t\t// over what was already charged — the running `budget.consume` therefore mirrors the live\n\t\t\t// stream instead of waiting for the turn's final usage report. Thinking deltas are not\n\t\t\t// metered here: `#provide` never routes a `'thinking'` delta through `onDelta` (only\n\t\t\t// `'content'` deltas are), so there is no live thinking text to estimate mid-stream — the\n\t\t\t// honest choice given the loop's existing delta wiring; thinking is metered, like content,\n\t\t\t// only through the post-turn usage reconcile that follows (which charges the full reported usage).\n\t\t\tlet charged = 0\n\t\t\tlet turnContent = ''\n\t\t\tlet result: ProviderResult\n\t\t\ttry {\n\t\t\t\tresult = yield* this.#provide(\n\t\t\t\t\tmessages,\n\t\t\t\t\tabort.signal,\n\t\t\t\t\tdefinitions,\n\t\t\t\t\tthink,\n\t\t\t\t\tschema,\n\t\t\t\t\t(delta) => {\n\t\t\t\t\t\tcontent += delta\n\t\t\t\t\t\tturnContent += delta\n\t\t\t\t\t\tconst est = estimateTokens(turnContent)\n\t\t\t\t\t\tif (est > charged) {\n\t\t\t\t\t\t\tbudget?.consume({ prompt: 0, completion: est - charged, total: est - charged })\n\t\t\t\t\t\t\tcharged = est\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t)\n\t\t\t} catch (error) {\n\t\t\t\t// A cancel mid-stream (the bound signal aborted): stop and mark partial. The\n\t\t\t\t// deltas streamed before the cancel were already accumulated into `content`\n\t\t\t\t// through `onDelta`, and a ProviderAbortError's `partial.content` is exactly those\n\t\t\t\t// same yielded deltas (the contract) — so `content` already holds the partial;\n\t\t\t\t// do not re-add it (that double-counts). The separated reasoning has no delta\n\t\t\t\t// channel, though — the abort partial is its only carrier, so harvest it. A\n\t\t\t\t// non-abort error (the signal is not aborted) propagates so the run rejects.\n\t\t\t\tif (abort.signal.aborted) {\n\t\t\t\t\tif (isProviderAbortError(error)) {\n\t\t\t\t\t\tif (error.partial.thinking !== undefined && error.partial.thinking.length > 0) {\n\t\t\t\t\t\t\tthinking = joinThinking(thinking, error.partial.thinking)\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// The abort's partial usage — when the provider observed it mid-stream — is\n\t\t\t\t\t\t// folded and reconciled exactly like the normal post-turn path that follows: the\n\t\t\t\t\t\t// full reported usage sums into `usage`, and only the residual over the\n\t\t\t\t\t\t// mid-stream `charged` estimate is consumed against `budget` (never\n\t\t\t\t\t\t// double-counted). A provider that can't observe usage mid-stream (its\n\t\t\t\t\t\t// final counts never arrive) reports none, and none is fabricated here.\n\t\t\t\t\t\tif (error.partial.usage !== undefined) {\n\t\t\t\t\t\t\t// Sanitize the provider's partial usage before charging/folding it: a\n\t\t\t\t\t\t\t// non-finite or negative field floors to `0`, a fractional field floors to its\n\t\t\t\t\t\t\t// integer part. The normal post-turn usage path is untouched.\n\t\t\t\t\t\t\tconst abortUsage = sanitizeUsage(error.partial.usage)\n\t\t\t\t\t\t\tbudget?.consume({\n\t\t\t\t\t\t\t\tprompt: abortUsage.prompt,\n\t\t\t\t\t\t\t\tcompletion: Math.max(0, abortUsage.completion - charged),\n\t\t\t\t\t\t\t\ttotal: Math.max(0, abortUsage.total - charged),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tusage = sumUsage(usage, abortUsage)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpartial = true\n\t\t\t\t\tbroke = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tif (result.thinking !== undefined && result.thinking.length > 0) {\n\t\t\t\tthinking = joinThinking(thinking, result.thinking)\n\t\t\t}\n\t\t\tif (result.usage !== undefined) {\n\t\t\t\t// Sanitize the provider's normal post-turn usage before charging/folding it,\n\t\t\t\t// exactly like the preceding abort path: a non-finite or negative field floors to `0`, a\n\t\t\t\t// fractional field floors to its integer part. Unsanitized, a buggy provider's\n\t\t\t\t// NaN/negative usage would poison `budget.consumed` and `sumUsage`, and never trip\n\t\t\t\t// exhaustion (`Math.max(0, NaN - charged)` is `NaN`).\n\t\t\t\tconst resultUsage = sanitizeUsage(result.usage)\n\t\t\t\t// Residual reconcile — the earlier mid-stream charges already consumed `charged` worth\n\t\t\t\t// of budget against this turn's completion; charge only what remains of the full\n\t\t\t\t// reported usage so the turn's total budget draw matches `resultUsage` exactly (never\n\t\t\t\t// double-counted). `prompt` was never charged mid-stream (no live prompt-delta channel\n\t\t\t\t// exists), so it is charged here in full. `sumUsage` / the emitted `usage` chunk below\n\t\t\t\t// still carry the full sanitized `resultUsage` — reconciliation affects only the\n\t\t\t\t// budget charge, never the reported usage.\n\t\t\t\tbudget?.consume({\n\t\t\t\t\tprompt: resultUsage.prompt,\n\t\t\t\t\tcompletion: Math.max(0, resultUsage.completion - charged),\n\t\t\t\t\ttotal: Math.max(0, resultUsage.total - charged),\n\t\t\t\t})\n\t\t\t\tusage = sumUsage(usage, resultUsage)\n\t\t\t\t// Observe this turn's usage — the result already exists; emit beside the yield.\n\t\t\t\tthis.#emitter.emit('usage', resultUsage)\n\t\t\t\tyield { category: 'usage', usage: resultUsage }\n\t\t\t}\n\t\t\tif (result.tools !== undefined && result.tools.length > 0) {\n\t\t\t\tconst authorization = this.#authorize(result.tools)\n\t\t\t\tif (abort.signal.aborted) {\n\t\t\t\t\tpartial = true\n\t\t\t\t\tbroke = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tconst assistant = this.#context.messages.add({\n\t\t\t\t\trole: 'assistant',\n\t\t\t\t\tcontent: result.content,\n\t\t\t\t\tcalls: result.tools,\n\t\t\t\t})\n\t\t\t\tmessages.push(assistant)\n\t\t\t\tconst results = await this.#dispatch(tools, result.tools, abort.signal, authorization)\n\t\t\t\tfor (let index = 0; index < result.tools.length; index += 1) {\n\t\t\t\t\tconst call = result.tools[index]\n\t\t\t\t\tconst outcomeResult = results[index]\n\t\t\t\t\tif (call === undefined || outcomeResult === undefined) continue\n\t\t\t\t\t// Observe the dispatched tool + its result — beside the existing `tool` yield\n\t\t\t\t\t// (the result already exists). Carries the same pair the chunk carries.\n\t\t\t\t\tthis.#emitter.emit('tool', call, outcomeResult)\n\t\t\t\t\tyield { category: 'tool', call, result: outcomeResult }\n\t\t\t\t\tconst toolMessage = this.#context.messages.add({\n\t\t\t\t\t\trole: 'tool',\n\t\t\t\t\t\tcontent: outcomeResult.success\n\t\t\t\t\t\t\t? JSON.stringify(outcomeResult.value)\n\t\t\t\t\t\t\t: outcomeResult.error,\n\t\t\t\t\t})\n\t\t\t\t\tmessages.push(toolMessage)\n\t\t\t\t}\n\t\t\t\t// Automatic compaction — between turns (this `continue` path: another\n\t\t\t\t// turn follows; never after the final assistant turn that ends the loop, where it\n\t\t\t\t// would be wasted). The same `#trim` the run also ran before the first provider request\n\t\t\t\t// (so a resumed / long conversation whose initial prompt already exceeds the window\n\t\t\t\t// compacts at once). Gated behind `compacting` (window + conversation both present), so\n\t\t\t\t// with auto-compaction off this introduces no extra `await` — the loop is byte-for-byte\n\t\t\t\t// the prior behavior. `latch: true` — by now the tail has accumulated this turn's\n\t\t\t\t// appends, so an `undefined` fold here is genuinely futile, and the run stops\n\t\t\t\t// calling `#trim` for the rest of its turns.\n\t\t\t\tif (compacting && !futile) futile = await this.#trim(messages, true)\n\t\t\t\tpending = true\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// No tools: this turn's content is the final answer — record it and finish.\n\t\t\tmessages.push(this.#context.messages.add({ role: 'assistant', content: result.content }))\n\t\t\tcontent = result.content\n\t\t\tpending = false\n\t\t\tbroke = true\n\t\t\tbreak\n\t\t}\n\t\t// The loop exhausted `limit` (the `for` condition failed, never a `break`) while the\n\t\t// most recent turn still held unresolved tool intent: commit the outcome partial. Flag it\n\t\t// `exhausted` only when the signal did not abort — a cancel that lands during the last turn's\n\t\t// post-provider work (tool authorize/execute, the residual budget reconcile, between-turns\n\t\t// compaction) also takes this `pending=true; continue` path and exits through the `for` condition\n\t\t// (never a `break`), so `broke` stays `false` even though it was a genuine cancel, not a limit\n\t\t// exhaustion. Checking `abort.signal.aborted` here classifies that case correctly: the pump\n\t\t// then emits `abort` (the cancel reason), never `exhaust`. A `limit: 0` run never enters the\n\t\t// loop (`pending` stays `false`), so it stays non-partial either way.\n\t\tif (!broke && pending) {\n\t\t\tpartial = true\n\t\t\texhausted = !abort.signal.aborted\n\t\t}\n\t\treturn { content, thinking, usage, partial, exhausted }\n\t}\n\n\t// Automatic compaction — the production-hardened context-budget check. Called\n\t// both before the first provider request (a resumed / long conversation compacts at once) and\n\t// between turns. Purely additive: with no `#window` budget or a non-summarizable active conversation\n\t// it is a no-op, so the loop is byte-for-byte the prior behavior — and a conversation that cannot\n\t// summarize (the default one has no summarizer) is never auto-compacted, so the auto path never\n\t// throws the `compact()` SUMMARIZER error. The trigger is the context `#window` budget —\n\t// its `consumer` a token estimator (for example `estimateMessages`), its `max` the context window — the\n\t// same consume-to-a-ceiling primitive as the cost `budget`, but the ceiling action is compaction, not\n\t// abort. It measures the absolute current prompt: `clear()` then `consume(messages)` makes\n\t// `#window.consumed` the estimated footprint of the exact next prompt (the working `messages` array\n\t// = the system block + the conversation's `view()` + this turn's appended messages — the real input\n\t// the next `provider.stream` will receive), and `exhausted` means that prompt has reached `max`.\n\t// Production hardening:\n\t// • Non-fatal summarizer failure — `conversation.compact()` is wrapped: a thrown summarizer error\n\t// does not crash the run; it is surfaced as a `fault` event (observable, never lost) and\n\t// compaction is skipped this turn, then the loop continues (the over-window prompt proceeds to\n\t// the provider). (A manual `conversation.compact()` still propagates — only the auto path here is\n\t// resilient.)\n\t// • Futile-compaction guard (the single-level limit) — when a between-turns `compact()` resolves\n\t// `undefined` (nothing left to fold) while the prompt is still over the window — that is, the live tail\n\t// is at/below `keep` and the over-window is structural (the uncompactable system block + the\n\t// section summaries) so compaction can't reduce further — set the per-run `futile` flag so\n\t// auto-compaction stops for the rest of this run (no per-turn churn). The over-window prompt then\n\t// proceeds to the provider, which surfaces a genuine context-length error if it truly can't fit\n\t// (the real limit). The loop does not churn futilely. The returned flag carries that latch back to\n\t// `#run`, which owns the per-run state and stops calling `#trim` after it is set. `latch`\n\t// gates it: the between-turns check passes `true`; the pre-first-turn check passes `false` —\n\t// there an `undefined` fold means \"nothing to fold yet\" (the live tail hasn't\n\t// accumulated this run's turns), not permanently futile, so it reports `false` and the run's\n\t// growing tail can still fold later. (A `compact()` that does fold a section is never futile\n\t// — the tail shrank; if the rebuilt prompt is still over window the next between-turns\n\t// `undefined` fold latches.)\n\t// No post-compact `clear()` is needed: the next check's `clear()` + `consume` re-measures the\n\t// now-shrunken prompt from scratch. The summarizer call is the conversation's configured\n\t// (best-effort) one, not separately bound to this run's abort signal.\n\tasync #trim(messages: Message[], latch: boolean): Promise<boolean> {\n\t\tconst conversation = this.#context.conversations.active\n\t\t// No window or a non-summarizable active conversation (the default one can't fold) ⇒ the\n\t\t// additive no-op. (Both call sites are gated by `compacting`, so here `conversation` is the\n\t\t// active, summarizable one; this guard keeps `#trim` total.)\n\t\tif (this.#window === undefined || conversation?.summarizable !== true) return false\n\t\tthis.#window.clear()\n\t\tthis.#window.consume(messages)\n\t\tif (!this.#window.exhausted) return false\n\t\tlet section: Awaited<ReturnType<typeof conversation.compact>>\n\t\ttry {\n\t\t\tsection = await conversation.compact()\n\t\t} catch (error) {\n\t\t\t// Surface the summarizer failure observably first (always). Lenient (default): skip\n\t\t\t// compaction this turn and continue over-window. Strict: rethrow after the event so\n\t\t\t// the caught error propagates through `#run` and the run settles `error` instead.\n\t\t\tthis.#emitter.emit('fault', error)\n\t\t\tif (this.#strict) throw error\n\t\t\treturn false\n\t\t}\n\t\t// Nothing folded. On a between-turns check (`latch`) the tail had its chance to grow yet\n\t\t// still won't fold ⇒ genuinely futile: report the latch so the run stops churning and the\n\t\t// over-window prompt reaches the provider. On the pre-first-turn check the tail is\n\t\t// too short yet ⇒ report no latch, leaving later turns free to fold as the tail grows.\n\t\tif (section === undefined) return latch\n\t\t// Rebuild the working array from the (now smaller) compacted view through the same projection the\n\t\t// loop opened with — so the run continues on the system block + compacted `view()`.\n\t\tmessages.splice(0, messages.length, ...this.#context.build(this.#provider.format))\n\t\treturn false\n\t}\n\n\t// Evaluate policy and emit denials before the run's final pre-dispatch abort guard:\n\t// policy callbacks and denial listeners can cancel the run synchronously.\n\t#authorize(calls: readonly ToolCall[]) {\n\t\tif (this.#authority === undefined) return undefined\n\t\tconst authority = this.#authority\n\t\tconst allowed: ToolCall[] = []\n\t\tconst denials = new Map<string, ToolResult>()\n\t\tfor (const call of calls) {\n\t\t\t// A security gate must fail closed: if a policy `evaluate` throws, the call is not\n\t\t\t// cleared, so it must not run. Synthesize a denial (carrying the error's message)\n\t\t\t// instead of letting the throw reject the whole run — the tool stays unexecuted and\n\t\t\t// the model still sees a denial it can react to, exactly like an explicit `deny`.\n\t\t\tlet decision: AuthorityDecision\n\t\t\ttry {\n\t\t\t\tdecision = authority.evaluate({ call })\n\t\t\t} catch (error) {\n\t\t\t\t// The declared `@orkestrel/workflow` normalizer, so a fail-closed denial carries a\n\t\t\t\t// non-empty explanation the model can read: an `Error` with an empty `message`\n\t\t\t\t// normalizes to real text, and a throw whose stringification itself fails is caught\n\t\t\t\t// rather than escaping the gate and rejecting the run.\n\t\t\t\tconst reason = errorToMessage(error)\n\t\t\t\tdenials.set(call.id, denyCall(call, reason))\n\t\t\t\t// Observe the fail-closed denial with the thrown reason.\n\t\t\t\tthis.#emitter.emit('deny', call, reason)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (decision.allowed) allowed.push(call)\n\t\t\telse {\n\t\t\t\tdenials.set(call.id, denyCall(call, decision.reason))\n\t\t\t\t// Observe the explicit denial (the call + the rule's reason).\n\t\t\t\tthis.#emitter.emit('deny', call, decision.reason)\n\t\t\t}\n\t\t}\n\t\treturn { allowed, denials }\n\t}\n\n\t// Carry cancellation into entered handlers, then merge executed results and denials\n\t// in call order. An all-denied turn costs no tool run.\n\tasync #dispatch(\n\t\ttools: ToolManagerInterface,\n\t\tcalls: readonly ToolCall[],\n\t\tsignal: AbortSignal,\n\t\tauthorization:\n\t\t\t| {\n\t\t\t\t\treadonly allowed: readonly ToolCall[]\n\t\t\t\t\treadonly denials: ReadonlyMap<string, ToolResult>\n\t\t\t }\n\t\t\t| undefined,\n\t): Promise<readonly ToolResult[]> {\n\t\tif (authorization === undefined) return tools.execute(calls, { signal })\n\t\tconst { allowed, denials } = authorization\n\t\tconst executed = allowed.length > 0 ? await tools.execute(allowed, { signal }) : []\n\t\tconst byId = new Map<string, ToolResult>(denials)\n\t\tfor (const result of executed) byId.set(result.id, result)\n\t\treturn calls.map((call) => byId.get(call.id) ?? denyCall(call, undefined))\n\t}\n\n\t// Drive one provider stream turn: read each {@link ProviderDelta}'s `channel` — a\n\t// `'content'` delta is the answer (fed back through `onDelta`, surfaced as a\n\t// `token` chunk); a `'thinking'` delta is live reasoning (surfaced as a `think` chunk,\n\t// never fed into `onDelta` — reasoning is not answer content) — returning the provider's\n\t// assembled result. The per-run `think` / `schema` preferences ride into `provider.stream`\n\t// as {@link ProviderStreamOptions}, composed together — keys are omitted when undefined, so\n\t// the provider receives no options object at all when both are absent (preserving the prior\n\t// think-only behavior exactly). Kept separate so the loop reads as one straight line.\n\tasync *#provide(\n\t\tmessages: readonly Message[],\n\t\tsignal: AbortSignal,\n\t\tdefinitions: ReturnType<ToolManagerInterface['definitions']> | undefined,\n\t\tthink: boolean | undefined,\n\t\tschema: Readonly<Record<string, unknown>> | undefined,\n\t\tonDelta: (delta: string) => void,\n\t): AsyncGenerator<AgentChunk, ProviderResult> {\n\t\tconst options: { think?: boolean; schema?: Readonly<Record<string, unknown>> } = {}\n\t\tif (think !== undefined) options.think = think\n\t\tif (schema !== undefined) options.schema = schema\n\t\tconst generator = this.#provider.stream(\n\t\t\tmessages,\n\t\t\tsignal,\n\t\t\tdefinitions,\n\t\t\tObject.keys(options).length > 0 ? options : undefined,\n\t\t)\n\t\tlet next = await generator.next()\n\t\twhile (!next.done) {\n\t\t\tconst delta = next.value\n\t\t\tif (delta.channel === 'content') {\n\t\t\t\tonDelta(delta.text)\n\t\t\t\tyield { category: 'token', content: delta.text }\n\t\t\t} else {\n\t\t\t\tyield { category: 'think', content: delta.text }\n\t\t\t}\n\t\t\tnext = await generator.next()\n\t\t}\n\t\treturn next.value\n\t}\n\n\t// The parent signal for a run's abort: the external signal, an optional per-run signal\n\t// (composed with, never replacing, the construction `signal`), the deadline, and the\n\t// effective budget (a per-run override, else the construction `budget`) folded through\n\t// `AbortSignal.any` — or a lone present one, or `undefined` when none.\n\t#parents(\n\t\ttimeout: TimeoutInterface | undefined,\n\t\tbudget: BudgetInterface<TokenUsage> | undefined,\n\t\tsignal: AbortSignal | undefined,\n\t): AbortSignal | undefined {\n\t\tconst signals: AbortSignal[] = []\n\t\tif (this.#signal !== undefined) signals.push(this.#signal)\n\t\tif (signal !== undefined) signals.push(signal)\n\t\tif (timeout !== undefined) signals.push(timeout.signal)\n\t\tif (budget !== undefined) signals.push(budget.signal)\n\t\tif (signals.length === 0) return undefined\n\t\tif (signals.length === 1) return signals[0]\n\t\treturn AbortSignal.any(signals)\n\t}\n}\n","import type {\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentOptions,\n\tAgentRegistryInterface,\n\tAgentRegistryOptions,\n\tAuthorityInterface,\n\tConversationStoreInterface,\n\tProviderInterface,\n} from './types.js'\nimport type { BudgetInterface, TokenUsage } from '@orkestrel/budget'\nimport type { ToolInterface } from '@orkestrel/tool'\nimport type { SchedulerInterface } from '@orkestrel/workflow'\nimport { createTokenBudget } from '@orkestrel/budget'\nimport { ToolManager } from '@orkestrel/tool'\nimport { Agent } from './Agent.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport { AgentError } from './errors.js'\n\n/**\n * Makes a durable, JSON-serializable {@link AgentJobInput} runnable — holds the named pools of\n * live, non-serializable pieces (providers, tools, authorities, schedulers), throws on a name\n * absent from its pool, and `build`s a seeded, signal-wired {@link Agent} from a job's names and\n * data.\n *\n * @remarks\n * - **Why it exists.** An `AgentJobInput` is serializable so it can survive a crash in a\n * Queue's store; the live objects it needs (a provider with sockets, tools / rules /\n * schedulers carrying functions) cannot serialize. The registry closes that gap:\n * construct it once with the live pools, then a queue / runner handler calls `build`\n * on each (possibly restored) job to get a ready agent.\n * - **Accessors throw on a miss.** `provider` / `tool` / `authority` / `scheduler` resolve a\n * name against their pool and throw an {@link AgentError} carrying `code: 'REGISTRY'` and\n * the message `unknown <category>: <name>` when it is absent — an unknown name in a\n * rehydrated job is a programmer / config error that must fail loudly at build time, never\n * silently resolve to `undefined` and run an agent missing a dependency.\n * - **`build` rehydrates.** Resolve the job's `provider`; assemble a fresh\n * {@link ToolManager} from the `tools` names; rebuild the token `budget` from its\n * ceiling (`createTokenBudget({ max })`); resolve the optional `authority` /\n * `scheduler` names; construct the {@link Agent} with `system` / `limit` / `timeout` /\n * the threaded `signal`; seed its context with the job's `messages`; return it. The\n * `signal` is the queue attempt's / runner unit's cancel, so a bounded abort propagates\n * into the agent (which commits a partial — the job's `partial` policy then\n * decides success vs. retry).\n * - **Event-free.** A pure resolver — no Emitter, no events.\n *\n * @example\n * ```ts\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const registry = new AgentRegistry({ providers: { main: provider } })\n * const agent = registry.build({ provider: 'main', messages: [{ role: 'user', content: 'Say ok.' }] })\n * const result = await agent.generate()\n * ```\n */\nexport class AgentRegistry implements AgentRegistryInterface {\n\treadonly #providers: ReadonlyMap<string, ProviderInterface>\n\treadonly #tools: ReadonlyMap<string, ToolInterface>\n\treadonly #authorities: ReadonlyMap<string, AuthorityInterface>\n\treadonly #schedulers: ReadonlyMap<string, SchedulerInterface>\n\treadonly #store: ConversationStoreInterface | undefined\n\n\tconstructor(options: AgentRegistryOptions) {\n\t\tthis.#providers = new Map(Object.entries(options.providers))\n\t\tthis.#tools = new Map(Object.entries(options.tools ?? {}))\n\t\tthis.#authorities = new Map(Object.entries(options.authorities ?? {}))\n\t\tthis.#schedulers = new Map(Object.entries(options.schedulers ?? {}))\n\t\tthis.#store = options.store\n\t}\n\n\tprovider(name: string): ProviderInterface {\n\t\treturn this.#resolve(this.#providers, 'provider', name)\n\t}\n\n\ttool(name: string): ToolInterface {\n\t\treturn this.#resolve(this.#tools, 'tool', name)\n\t}\n\n\tauthority(name: string): AuthorityInterface {\n\t\treturn this.#resolve(this.#authorities, 'authority', name)\n\t}\n\n\tscheduler(name: string): SchedulerInterface {\n\t\treturn this.#resolve(this.#schedulers, 'scheduler', name)\n\t}\n\n\tbuild(input: AgentJobInput, signal?: AbortSignal): AgentInterface {\n\t\tconst provider = this.provider(input.provider)\n\t\tconst agent = new Agent(provider, this.#options(input, signal))\n\t\t// Seed the conversation onto the rehydrated agent's context — the serializable\n\t\t// MessageInputs become stored messages (each id minted by the manager).\n\t\tfor (const message of input.messages) agent.context.messages.add(message)\n\t\treturn agent\n\t}\n\n\t// Assemble the AgentOptions for one job: a fresh ToolManager loaded from the named\n\t// tools, the rebuilt token budget, the resolved authority / scheduler, plus the data\n\t// fields and the threaded cancel. Optional fields are omitted (not set to `undefined`)\n\t// so the Agent's `?? default` fallbacks behave exactly as for a hand-built agent. When\n\t// the registry carries a conversation store, thread a fresh store-backed\n\t// ConversationManager for this build (a fresh conversation id per build ⇒ no\n\t// collisions in the shared store) — omitted when no store is set, so the shape stays\n\t// byte-identical to a registry with no `store`.\n\t#options(input: AgentJobInput, signal: AbortSignal | undefined): AgentOptions {\n\t\tconst budget = this.#budget(input.budget)\n\t\treturn {\n\t\t\ttools: this.#manager(input.tools),\n\t\t\t...(input.system === undefined ? {} : { system: input.system }),\n\t\t\t...(input.limit === undefined ? {} : { limit: input.limit }),\n\t\t\t...(input.timeout === undefined ? {} : { timeout: input.timeout }),\n\t\t\t...(budget === undefined ? {} : { budget }),\n\t\t\t...(input.authority === undefined ? {} : { authority: this.authority(input.authority) }),\n\t\t\t...(input.scheduler === undefined ? {} : { scheduler: this.scheduler(input.scheduler) }),\n\t\t\t...(this.#store === undefined\n\t\t\t\t? {}\n\t\t\t\t: { conversations: new ConversationManager({ store: this.#store }) }),\n\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t}\n\t}\n\n\t// A fresh tool registry loaded with the named tools (each resolved — an unknown name\n\t// throws). Always a new manager per build, so concurrent jobs never share one.\n\t#manager(names: readonly string[] | undefined): ToolManager {\n\t\tconst manager = new ToolManager()\n\t\tif (names !== undefined) for (const name of names) manager.add(this.tool(name))\n\t\treturn manager\n\t}\n\n\t// Rebuild a token budget from a job's serializable ceiling — `undefined` when the job\n\t// declared none (no bound), else a fresh `createTokenBudget({ max })`.\n\t#budget(max: number | undefined): BudgetInterface<TokenUsage> | undefined {\n\t\treturn max === undefined ? undefined : createTokenBudget({ max })\n\t}\n\n\t// Resolve a name against a pool, throwing a coded, loud error on a miss — an unknown name\n\t// in a rehydrated job is a programmer error and must not pass.\n\t#resolve<T>(pool: ReadonlyMap<string, T>, category: string, name: string): T {\n\t\tconst value = pool.get(name)\n\t\tif (value === undefined) throw new AgentError('REGISTRY', `unknown ${category}: ${name}`)\n\t\treturn value\n\t}\n}\n","import type {\n\tAuthorityContext,\n\tAuthorityDecision,\n\tAuthorityInterface,\n\tAuthorityOptions,\n\tAuthorityRule,\n} from './types.js'\nimport { DEFAULT_AUTHORITY_ZONE } from './constants.js'\n\n/**\n * Gates the agent loop's tool calls — the synchronous policy consulted before each call runs,\n * turning one {@link AuthorityContext} into an {@link AuthorityDecision} by walking the ordered\n * rules first-match-wins and falling back to a configurable default, which allows an unmatched\n * call unless its `fallback` denies.\n *\n * @remarks\n * - **Ordered, first-match-wins.** `evaluate` walks the configured rules in order and\n * returns the first whose `match(context)` is true as\n * `{ zone, allowed: rule.allowed ?? true, reason }` — a matched rule allows by\n * default and denies only when its `allowed` is explicitly `false`.\n * - **Fallback.** When no rule matches, `evaluate` returns the configured `fallback`.\n * It defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }` (allow-unmatched),\n * so a rules list of denials behaves as a denylist. To make the gate deny-by-default\n * (an allowlist — only matched rules that allow get through), pass an `allowed: false`\n * `fallback`.\n * - **Consulted before each tool call.** The agent loop calls `evaluate({ call })` for\n * every {@link import('@orkestrel/tool').ToolCall} the model emits; a denied call is fed\n * back to the model as a denial {@link import('@orkestrel/tool').ToolResult} (a `tool`\n * chunk + a tool message) instead of being executed — no tool run, no budget cost —\n * so the model sees the denial and can react.\n * - **Synchronous.** `evaluate` returns the verdict directly.\n * - **Event-free.** A purely functional gate — no Emitter, no events.\n *\n * @example\n * ```ts\n * // A denylist: deny the `delete` tool, allow everything else (default fallback).\n * const authority = new Authority({\n * \trules: [{ match: (c) => c.call.name === 'delete', zone: 'restricted', allowed: false }],\n * })\n * authority.evaluate({ call: { id: '1', name: 'delete', arguments: {} } }) // { zone: 'restricted', allowed: false }\n * authority.evaluate({ call: { id: '2', name: 'add', arguments: {} } }) // { zone: 'default', allowed: true }\n * ```\n */\nexport class Authority implements AuthorityInterface {\n\treadonly #rules: readonly AuthorityRule[]\n\treadonly #fallback: AuthorityDecision\n\n\tconstructor(options?: AuthorityOptions) {\n\t\tthis.#rules = options?.rules ?? []\n\t\tthis.#fallback = options?.fallback ?? { zone: DEFAULT_AUTHORITY_ZONE, allowed: true }\n\t}\n\n\tevaluate(context: AuthorityContext): AuthorityDecision {\n\t\tfor (const rule of this.#rules) {\n\t\t\tif (rule.match(context))\n\t\t\t\treturn {\n\t\t\t\t\tzone: rule.zone,\n\t\t\t\t\tallowed: rule.allowed ?? true,\n\t\t\t\t\t...(rule.reason === undefined ? {} : { reason: rule.reason }),\n\t\t\t\t}\n\t\t}\n\t\treturn this.#fallback\n\t}\n}\n","import type { ConversationSnapshot, Message, Section } from './types.js'\nimport { arrayOf, attempt, isArray, isRecord, isString } from '@orkestrel/contract'\nimport { isToolCall } from '@orkestrel/tool'\n\n/**\n * Checks whether a value satisfies the domain conversation-message contract.\n *\n * @remarks\n * Roles belong to MessageRole and image elements are strings. Tool arguments may\n * carry non-JSON values, as the domain type permits; the message wire contract is\n * narrower. Unreadable fields and hostile inputs return false.\n *\n * @param value - The unknown message candidate\n * @returns True if the domain message fields are valid; false otherwise\n * @example\n * ```ts\n * isMessage({ id: '1', role: 'user', content: 'hi' }) // true\n * isMessage({ id: '1', role: 'other', content: '' }) // false\n * isMessage({ id: '1', role: 'user', content: '', images: [1] }) // false\n * ```\n */\nexport function isMessage(value: unknown): value is Message {\n\tconst checked = attempt(() => {\n\t\tif (!isRecord(value)) return false\n\t\tconst { id, role, content, calls, images } = value\n\t\tif (!isString(id) || !isString(content)) return false\n\t\tif (role !== 'system' && role !== 'user' && role !== 'assistant' && role !== 'tool')\n\t\t\treturn false\n\t\tif (calls !== undefined && !arrayOf(isToolCall)(calls)) return false\n\t\treturn images === undefined || arrayOf(isString)(images)\n\t})\n\treturn checked.success && checked.value\n}\n\n/**\n * Checks whether an `unknown` is structurally a {@link Section} record — a `string` `id` and\n * `summary` beside a `messages` array of valid {@link Message}s, the per-section step of the\n * {@link isConversationSnapshot} read-boundary narrow. Total, never throwing, and never an\n * assertion.\n *\n * @remarks\n * A total guard (it never throws — adversarial input returns `false`). It checks the section's\n * shape: a record with a `string` `id`, a `string` `summary`, and a `messages` array every element\n * of which is a valid {@link Message} record ({@link isMessage}). Enough to safely impose\n * the {@link Section} type at a storage boundary without a cast.\n *\n * @param value - The value to test (one element of a snapshot's `sections` array)\n * @returns True if `value` has the structural shape of a {@link Section}; false otherwise\n *\n * @example\n * ```ts\n * isSection({ id: 's', summary: 'recap', messages: [{ id: '1', role: 'user', content: 'hi' }] }) // true\n * isSection({ id: 's', summary: 'recap', messages: 'nope' }) // false\n * isSection({ id: 's', messages: [] }) // false (missing summary)\n * ```\n */\nexport function isSection(value: unknown): value is Section {\n\tif (!isRecord(value)) return false\n\tif (!isString(value.id) || !isString(value.summary)) return false\n\treturn isArray(value.messages) && value.messages.every(isMessage)\n}\n\n/**\n * Narrows an `unknown` to a {@link ConversationSnapshot} — a `string` `id`, an optional `string`\n * `summary`, and valid `sections` and `messages` arrays; the total boundary guard for an\n * untrusted snapshot read (a storage row a\n * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}\n * reads back from its opaque JSON column, a snapshot loaded from disk), never throwing. The exact\n * analogue of {@link import('@orkestrel/workspace').isWorkspaceSnapshot}.\n *\n * @remarks\n * A total guard (it never throws — adversarial input returns `false`). It checks the snapshot's\n * shape: a `string` `id`, an optional `string` `summary` (present-or-absent — the rollup is\n * `undefined` until the first compaction), a `sections` array every element of which is a valid\n * {@link Section} ({@link isSection}), and a `messages` array every element of which is a\n * valid {@link Message} ({@link isMessage}) — enough to safely impose the\n * {@link ConversationSnapshot} type at a storage boundary without a cast. The structural twin of\n * {@link import('@orkestrel/workspace').isWorkspaceSnapshot}. A malformed blob (a non-record, a missing / non-string `id`, a\n * non-string `summary` when present, a non-array `sections` / `messages`, or any malformed\n * element) resolves `false`, so a\n * {@link import('./conversations/stores/DatabaseConversationStore.js').DatabaseConversationStore}\n * read yields `undefined` rather than a broken conversation.\n *\n * @param value - The value to test (an opaque storage read)\n * @returns True if `value` has the structural shape of a {@link ConversationSnapshot}; false otherwise\n *\n * @example\n * ```ts\n * isConversationSnapshot({ id: 'c1', sections: [], messages: [] }) // true\n * isConversationSnapshot({ id: 'c1', summary: 'recap', sections: [], messages: [] }) // true\n * isConversationSnapshot({ id: 'c1', sections: 'nope', messages: [] }) // false\n * isConversationSnapshot({ sections: [], messages: [] }) // false (missing id)\n * ```\n */\nexport function isConversationSnapshot(value: unknown): value is ConversationSnapshot {\n\tif (!isRecord(value)) return false\n\tif (!isString(value.id)) return false\n\tif (value.summary !== undefined && !isString(value.summary)) return false\n\tif (!isArray(value.sections) || !value.sections.every(isSection)) return false\n\treturn isArray(value.messages) && value.messages.every(isMessage)\n}\n","import type {\n\tConversationSnapshot,\n\tConversationSnapshotRow,\n\tConversationStoreInterface,\n} from '../../types.js'\nimport type { TableInterface } from '@orkestrel/database'\nimport { isConversationSnapshot } from '../../validators.js'\n\n/**\n * Backs a {@link ConversationStoreInterface} with one table of the `databases` layer — a\n * conversation's durable state is a row holding the snapshot as one opaque JSON column, narrowed\n * back on `get` by {@link import('../../validators.js').isConversationSnapshot}, so persistence\n * reduces to keyed point-access (`get` / `set` / `delete`) over a {@link TableInterface}. The\n * driver-pluggable twin of the plain-`Map`\n * {@link import('./MemoryConversationStore.js').MemoryConversationStore}, and the exact twin of\n * {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}.\n *\n * @remarks\n * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,\n * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /\n * IndexedDB backend swaps in without touching the\n * {@link import('../ConversationManager.js').ConversationManager} or the\n * {@link import('../Conversation.js').Conversation} — the same seam as\n * {@link import('@orkestrel/workspace').DatabaseWorkspaceStore}. The\n * driver defaults to memory ({@link import('../../factories.js').createDatabaseConversationStore}\n * passes `createMemoryDriver()`), so it also works in memory out of the box; you opt into the\n * durable plumbing by passing a JSON / SQLite / IndexedDB driver.\n *\n * The {@link ConversationSnapshot} is stored as one opaque JSON column — the table is a row of\n * `{ id; snapshot }` ({@link ConversationSnapshotRow}), the snapshot the whole JSON blob (a\n * `rawShape` column the factory builds) — exactly as `DatabaseWorkspaceStore` stores its snapshot.\n * The snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is\n * lossless and keeps the row type flat (`snapshot` reads back as `unknown`).\n *\n * - **`set(snapshot)` upserts under the snapshot's own `id`** (no separate id param) — it writes\n * the row `{ id: snapshot.id, snapshot }`.\n * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to\n * a {@link ConversationSnapshot} ({@link import('../../validators.js').isConversationSnapshot} — the\n * total guard for an untrusted storage read), or `undefined` if none is stored.\n * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * Unlike a session store there is no idle-TTL / eviction — a persisted conversation lives until an\n * explicit `delete`. The public surface is exactly `get` / `set` / `delete` — no extra members (the\n * method bijection with {@link ConversationStoreInterface}). Hydration stays a caller concern: a\n * {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds\n * the live conversation through the `snapshot` option (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createConversation, createDatabaseConversationStore } from '@orkestrel/agent'\n * import { createMemoryDriver } from '@orkestrel/database'\n *\n * const store = createDatabaseConversationStore(createMemoryDriver()) // a durable driver swaps in here\n * const conversation = createConversation()\n * conversation.add({ role: 'user', content: 'hello' })\n * await store.set(conversation.snapshot()) // persist the conversation (one JSON column)\n * const snapshot = await store.get(conversation.id)\n * await store.delete(conversation.id) // drop it\n * ```\n */\nexport class DatabaseConversationStore implements ConversationStoreInterface {\n\treadonly #table: TableInterface<ConversationSnapshotRow>\n\n\t/**\n\t * Wraps a table as a conversation store.\n\t *\n\t * @param table - The {@link TableInterface} holding the snapshots — its row is the\n\t * {@link ConversationSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)\n\t */\n\tconstructor(table: TableInterface<ConversationSnapshotRow>) {\n\t\tthis.#table = table\n\t}\n\n\t/** Resolves the persisted snapshot for `id`, narrowing the opaque JSON column back to a `ConversationSnapshot`. */\n\tasync get(id: string): Promise<ConversationSnapshot | undefined> {\n\t\tconst row = await this.#table.get(id)\n\t\tif (row === undefined) return undefined\n\t\t// The snapshot crosses back as an untrusted storage read (a structured clone / a JSON row),\n\t\t// so narrow the opaque JSON column with the total boundary guard rather than a cast;\n\t\t// a malformed blob resolves `undefined`, never a broken conversation.\n\t\treturn isConversationSnapshot(row.snapshot) ? row.snapshot : undefined\n\t}\n\n\t/** Inserts or replaces under the snapshot's own `id` (no separate id param) — the row is `{ id, snapshot }`. */\n\tasync set(snapshot: ConversationSnapshot): Promise<void> {\n\t\tawait this.#table.set({ id: snapshot.id, snapshot })\n\t}\n\n\t/** Drops a snapshot by id; an absent id is a no-op (no throw). */\n\tasync delete(id: string): Promise<void> {\n\t\tawait this.#table.remove(id)\n\t}\n}\n","import type { ConversationSnapshot, ConversationStoreInterface } from '../../types.js'\n\n/**\n * Implements the {@link ConversationStoreInterface} in memory — a process-lifetime `Map` of\n * {@link ConversationSnapshot}s keyed by conversation id, the default store\n * {@link import('../../factories.js').createMemoryConversationStore} builds and the default\n * backing for `open` / `save`. The exact twin of\n * {@link import('@orkestrel/workspace').MemoryWorkspaceStore}.\n *\n * @remarks\n * A plain `Map<string, ConversationSnapshot>` — the snapshot is already pure,\n * self-contained JSON, so no encoding is needed for the memory tier. Like the\n * {@link import('@orkestrel/workspace').MemoryWorkspaceStore} it twins,\n * there is no idle-TTL and no eviction: a persisted conversation lives until an explicit `delete`. A\n * durable backend (JSON / SQLite / IndexedDB) swaps in through the same interface without touching\n * the {@link import('../ConversationManager.js').ConversationManager} or the\n * {@link import('../Conversation.js').Conversation} — its driver-pluggable twin is\n * {@link import('./DatabaseConversationStore.js').DatabaseConversationStore} (the snapshot as one\n * opaque JSON column).\n *\n * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.\n * - **`set` inserts / replaces under the snapshot's own `id`** (no separate id param).\n * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * The public surface is exactly `get` / `set` / `delete` — no extra members (the method\n * bijection with {@link ConversationStoreInterface}). Hydration is a caller concern: a\n * {@link import('../ConversationManager.js').ConversationManager} reads a snapshot back and rebuilds\n * the live conversation through the `snapshot` option (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createConversation, createMemoryConversationStore } from '@orkestrel/agent'\n *\n * const store = createMemoryConversationStore()\n * const conversation = createConversation()\n * conversation.add({ role: 'user', content: 'hello' })\n * await store.set(conversation.snapshot()) // persist the conversation\n * const snapshot = await store.get(conversation.id)\n * await store.delete(conversation.id) // drop it\n * ```\n */\nexport class MemoryConversationStore implements ConversationStoreInterface {\n\treadonly #snapshots = new Map<string, ConversationSnapshot>()\n\n\t/**\n\t * Resolves the persisted snapshot for `id`, or `undefined` if none is stored.\n\t *\n\t * @param id - The conversation id to resolve (a {@link ConversationSnapshot.id})\n\t * @returns The persisted snapshot, or `undefined` if absent\n\t */\n\tget(id: string): Promise<ConversationSnapshot | undefined> {\n\t\treturn Promise.resolve(this.#snapshots.get(id))\n\t}\n\n\t/**\n\t * Inserts or replaces a snapshot under its own `snapshot.id` (no separate id param —\n\t * mirroring {@link import('@orkestrel/workspace').WorkspaceStoreInterface}'s `set`).\n\t *\n\t * @param snapshot - The snapshot to store (keyed by its `id`)\n\t * @returns A promise that resolves after the snapshot is stored\n\t */\n\tset(snapshot: ConversationSnapshot): Promise<void> {\n\t\t// Insert / replace under the snapshot's own id (no separate id param).\n\t\tthis.#snapshots.set(snapshot.id, snapshot)\n\t\treturn Promise.resolve()\n\t}\n\n\t/**\n\t * Drops a snapshot by id; an absent id is a no-op (no throw).\n\t *\n\t * @param id - The conversation id to drop\n\t * @returns A promise that resolves after the snapshot is dropped\n\t */\n\tdelete(id: string): Promise<void> {\n\t\t// Drop by id; `Map.delete` of an absent id is already a no-op (no throw).\n\t\tthis.#snapshots.delete(id)\n\t\treturn Promise.resolve()\n\t}\n}\n","import type { ToolDefinition } from '@orkestrel/tool'\nimport type {\n\tAgentProviderInput,\n\tAgentProviderInterface,\n\tContextFormat,\n\tMessage,\n\tProviderDelta,\n\tProviderIncrement,\n\tProviderOptions,\n\tProviderParserInterface,\n\tProviderRequest,\n\tProviderResult,\n\tProviderStreamOptions,\n\tThinkSplitterInterface,\n} from './types.js'\nimport { Timeout } from '@orkestrel/timeout'\nimport { DEFAULT_PROVIDER_TIMEOUT, MAX_ERROR_BODY_LENGTH } from './constants.js'\nimport { ProviderAbortError, ProviderError } from './errors.js'\nimport { createThinkSplitter } from './factories.js'\nimport { buildProviderResult, joinThinking, readChunks, readText } from './helpers.js'\n\n/**\n * Implements bounded HTTP streaming and result assembly behind concrete wire seams.\n *\n * @remarks\n * Every call owns its parser, splitter, deadline, and accumulation. Success bodies\n * have no size limit. A qwen3 implicit-open reclassification corrects the final\n * content while content deltas already yielded cannot be recalled. A subclass fills\n * `name`, `frame`, `body`, `read`, and `finish`; the constructor takes the `split`\n * and `strict` switches to control reasoning separation and settled-result requirements.\n *\n * @example Writing a provider for a new wire\n * ```ts\n * import type {\n * \tProviderIncrement,\n * \tProviderOptions,\n * \tProviderParserInterface,\n * \tProviderRequest,\n * } from '@orkestrel/agent'\n * import { AgentProvider } from '@orkestrel/agent'\n *\n * class TextFrame implements ProviderParserInterface<string> {\n * \tparse(chunk: string): readonly string[] {\n * \t\treturn [chunk]\n * \t}\n * \tclear(): void {} // Raw text retains no framing state.\n * }\n *\n * interface TextOptions extends ProviderOptions {\n * \treadonly url: string\n * }\n *\n * class TextProvider extends AgentProvider<string> {\n * \treadonly name = 'text'\n * \tconstructor(options: TextOptions) {\n * \t\tsuper({ ...options, path: '/generate' })\n * \t}\n * \tframe(): ProviderParserInterface<string> {\n * \t\treturn new TextFrame()\n * \t}\n * \tbody(request: ProviderRequest): object {\n * \t\treturn { messages: request.messages }\n * \t}\n * \tread(record: string): ProviderIncrement {\n * \t\treturn { content: record, thinking: '', tools: [] }\n * \t}\n * \tfinish(_parser: ProviderParserInterface<string>): readonly string[] {\n * \t\treturn [] // Raw text retains no records at end of input.\n * \t}\n * }\n * ```\n */\nexport abstract class AgentProvider<\n\tTRecord = Readonly<Record<string, unknown>>,\n> implements AgentProviderInterface<TRecord> {\n\treadonly #id: string\n\treadonly #url: string\n\treadonly #path: string\n\treadonly #timeout: number\n\treadonly #transport: typeof globalThis.fetch\n\treadonly #headers: ProviderOptions['headers']\n\treadonly #format: ContextFormat | undefined\n\treadonly #split: boolean\n\treadonly #strict: boolean\n\n\tconstructor(input: AgentProviderInput) {\n\t\tthis.#id = crypto.randomUUID()\n\t\tthis.#url = input.url\n\t\tthis.#path = input.path ?? ''\n\t\tthis.#timeout = input.timeout ?? DEFAULT_PROVIDER_TIMEOUT\n\t\tthis.#transport = input.fetch ?? globalThis.fetch.bind(globalThis)\n\t\tthis.#headers = input.headers\n\t\tthis.#format = input.format\n\t\tthis.#split = input.split ?? true\n\t\tthis.#strict = input.strict ?? false\n\t}\n\n\t/** Identifies the concrete backend. */\n\tabstract readonly name: string\n\n\t/** Exposes the instance's minted UUID. */\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\t/** Exposes the context framing exactly as supplied. */\n\tget format(): ContextFormat | undefined {\n\t\treturn this.#format\n\t}\n\n\t/** Creates fresh framing state for the call. */\n\tabstract frame(): ProviderParserInterface<TRecord>\n\t/** Projects a domain request onto the concrete protocol's wire body. */\n\tabstract body(request: ProviderRequest): object\n\t/** Decodes a framed record into a turn increment. */\n\tabstract read(record: TRecord): ProviderIncrement\n\t/** Returns any records retained at end of input. */\n\tabstract finish(parser: ProviderParserInterface<TRecord>): readonly TRecord[]\n\n\t/**\n\t * Generates a complete turn by draining the shared stream engine.\n\t *\n\t * @param messages - The conversation turns\n\t * @param signal - The caller's cancellation bound\n\t * @param tools - The advertised tool definitions\n\t * @param options - The per-call generation configuration\n\t * @returns The terminal stream result\n\t */\n\tasync generate(\n\t\tmessages: readonly Message[],\n\t\tsignal: AbortSignal,\n\t\ttools?: readonly ToolDefinition[],\n\t\toptions?: ProviderStreamOptions,\n\t): Promise<ProviderResult> {\n\t\tconst stream = this.stream(messages, signal, tools, options)\n\t\tlet step = await stream.next()\n\t\twhile (!step.done) step = await stream.next()\n\t\treturn step.value\n\t}\n\n\t/**\n\t * Streams decoded deltas and returns the authoritative or assembled turn result.\n\t *\n\t * @param messages - The conversation turns\n\t * @param signal - The caller's cancellation bound\n\t * @param tools - The advertised tool definitions\n\t * @param options - The per-call generation configuration\n\t * @returns Content and native thinking deltas followed by the settled result\n\t * @throws ProviderAbortError Thrown when the combined cancellation bound fires\n\t * @throws ProviderError Thrown for an HTTP or protocol failure\n\t */\n\tasync *stream(\n\t\tmessages: readonly Message[],\n\t\tsignal: AbortSignal,\n\t\ttools?: readonly ToolDefinition[],\n\t\toptions?: ProviderStreamOptions,\n\t): AsyncGenerator<ProviderDelta, ProviderResult> {\n\t\tif (signal.aborted) throw new ProviderAbortError({ content: '' })\n\t\tconst timeout = new Timeout({ ms: this.#timeout })\n\t\ttimeout.start()\n\t\tconst combined = AbortSignal.any([timeout.signal, signal])\n\t\tlet parser: ProviderParserInterface<TRecord> | undefined\n\t\tlet splitter: ThinkSplitterInterface | undefined\n\t\tlet state: ProviderIncrement = { content: '', thinking: '', tools: [] }\n\t\ttry {\n\t\t\tparser = this.frame()\n\t\t\tsplitter = this.#split ? createThinkSplitter() : undefined\n\t\t\tconst response = await this.#request(\n\t\t\t\t{\n\t\t\t\t\tmessages,\n\t\t\t\t\t...(tools === undefined ? {} : { tools }),\n\t\t\t\t\t...(options === undefined ? {} : { options }),\n\t\t\t\t},\n\t\t\t\tcombined,\n\t\t\t)\n\t\t\tif (response.body === null) {\n\t\t\t\tthrow new ProviderError('PROTOCOL', 'provider error: no response body')\n\t\t\t}\n\t\t\tfor await (const chunk of readChunks(response.body, combined)) {\n\t\t\t\tcombined.throwIfAborted()\n\t\t\t\tfor (const record of parser.parse(chunk)) {\n\t\t\t\t\tyield* this.#fold(record, state, splitter, combined, (increment) => {\n\t\t\t\t\t\tstate = increment\n\t\t\t\t\t})\n\t\t\t\t\tcombined.throwIfAborted()\n\t\t\t\t\tif (state.result !== undefined) return state.result\n\t\t\t\t}\n\t\t\t}\n\t\t\tcombined.throwIfAborted()\n\t\t\tfor (const record of this.finish(parser)) {\n\t\t\t\tyield* this.#fold(record, state, splitter, combined, (increment) => {\n\t\t\t\t\tstate = increment\n\t\t\t\t})\n\t\t\t\tcombined.throwIfAborted()\n\t\t\t\tif (state.result !== undefined) return state.result\n\t\t\t}\n\t\t\tconst tail = splitter?.flush() ?? ''\n\t\t\tif (tail.length > 0) yield { channel: 'content', text: tail }\n\t\t\tcombined.throwIfAborted()\n\t\t\tif (this.#strict)\n\t\t\t\tthrow new ProviderError('PROTOCOL', 'provider error: missing settled result')\n\t\t\treturn buildProviderResult(\n\t\t\t\tsplitter?.content ?? state.content,\n\t\t\t\tjoinThinking(splitter?.thinking, state.thinking),\n\t\t\t\tstate.tools,\n\t\t\t\tstate.usage,\n\t\t\t)\n\t\t} catch (error) {\n\t\t\tif (combined.aborted) {\n\t\t\t\tsplitter?.flush()\n\t\t\t\tconst partial = buildProviderResult(\n\t\t\t\t\tsplitter?.content ?? state.content,\n\t\t\t\t\tjoinThinking(splitter?.thinking, state.thinking),\n\t\t\t\t\tstate.tools,\n\t\t\t\t\tstate.usage,\n\t\t\t\t)\n\t\t\t\t// A throw that raced the cancel is the call's real failure, so it rides as the cause.\n\t\t\t\tthrow new ProviderAbortError(\n\t\t\t\t\tpartial,\n\t\t\t\t\terror === combined.reason ? undefined : { cause: error },\n\t\t\t\t)\n\t\t\t}\n\t\t\tthrow error\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tparser?.clear()\n\t\t\t} finally {\n\t\t\t\ttimeout.clear()\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fold every record before exposing deltas, so resumed cancellation retains its contribution.\n\t*#fold(\n\t\trecord: TRecord,\n\t\tprevious: ProviderIncrement,\n\t\tsplitter: ThinkSplitterInterface | undefined,\n\t\tsignal: AbortSignal,\n\t\tcommit: (increment: ProviderIncrement) => void,\n\t): Generator<ProviderDelta> {\n\t\tconst increment = this.read(record)\n\t\tif (increment.result !== undefined) {\n\t\t\tcommit(increment)\n\t\t\treturn\n\t\t}\n\t\tconst content = splitter?.split(increment.content) ?? increment.content\n\t\tconst usage = increment.usage ?? previous.usage\n\t\tconst state: ProviderIncrement = {\n\t\t\tcontent: previous.content + increment.content,\n\t\t\tthinking: previous.thinking + increment.thinking,\n\t\t\ttools: [...previous.tools, ...increment.tools],\n\t\t\t...(usage === undefined ? {} : { usage }),\n\t\t}\n\t\tcommit(state)\n\t\tif (content.length > 0) yield { channel: 'content', text: content }\n\t\tsignal.throwIfAborted()\n\t\tif (increment.thinking.length > 0) yield { channel: 'thinking', text: increment.thinking }\n\t}\n\n\t// Send one request and translate its HTTP failure into the shared provider taxonomy.\n\tasync #request(request: ProviderRequest, signal: AbortSignal): Promise<Response> {\n\t\tconst headers = await this.#requestHeaders(signal)\n\t\tsignal.throwIfAborted()\n\t\tconst response = await this.#transport(this.#url + this.#path, {\n\t\t\tmethod: 'POST',\n\t\t\theaders,\n\t\t\tbody: JSON.stringify(this.body(request)),\n\t\t\tsignal,\n\t\t})\n\t\tif (!response.ok) {\n\t\t\tlet detail: string\n\t\t\ttry {\n\t\t\t\tdetail =\n\t\t\t\t\tresponse.body === null\n\t\t\t\t\t\t? ''\n\t\t\t\t\t\t: (await readText(response.body, MAX_ERROR_BODY_LENGTH, signal)).text\n\t\t\t} catch (cause) {\n\t\t\t\tthrow new ProviderError(\n\t\t\t\t\t'HTTP',\n\t\t\t\t\t`provider error: ${response.status} - (error body unavailable)`,\n\t\t\t\t\t{ status: response.status, cause },\n\t\t\t\t)\n\t\t\t}\n\t\t\tsignal.throwIfAborted()\n\t\t\tthrow new ProviderError(\n\t\t\t\t'HTTP',\n\t\t\t\t`provider error: ${response.status}${detail === '' ? '' : ` - ${detail}`}`,\n\t\t\t\t{ status: response.status },\n\t\t\t)\n\t\t}\n\t\treturn response\n\t}\n\n\t// Await the hook inside the call's cancellation bound and release its listener on exit.\n\tasync #requestHeaders(signal: AbortSignal): Promise<Headers> {\n\t\tconst headers = new Headers({ 'Content-Type': 'application/json' })\n\t\tif (this.#headers === undefined) return headers\n\t\tconst cleanup = new AbortController()\n\t\tconst aborted = Promise.withResolvers<never>()\n\t\tsignal.addEventListener('abort', () => aborted.reject(signal.reason), {\n\t\t\tonce: true,\n\t\t\tsignal: cleanup.signal,\n\t\t})\n\t\ttry {\n\t\t\tsignal.throwIfAborted()\n\t\t\tconst hook = this.#headers\n\t\t\tconst entries = await Promise.race([\n\t\t\t\tPromise.resolve().then(() => hook(signal)),\n\t\t\t\taborted.promise,\n\t\t\t])\n\t\t\tfor (const [key, value] of Object.entries(entries)) headers.set(key, value)\n\t\t\treturn headers\n\t\t} finally {\n\t\t\tcleanup.abort()\n\t\t}\n\t}\n}\n","import type {\n\tProviderIncrement,\n\tProviderParserInterface,\n\tProviderRequest,\n\tRelayProviderOptions,\n} from '../types.js'\nimport { cloneJSONValue } from '@orkestrel/contract'\nimport { AgentProvider } from '../AgentProvider.js'\nimport { providerRequestContract, relayFrameContract } from '../contracts.js'\nimport { ProviderAbortError, ProviderError } from '../errors.js'\n\n/**\n * Carries provider calls over an authenticated NDJSON relay endpoint.\n *\n * @remarks\n * Tool execution context stays local; calls carry only `id`, `name`, and `arguments`.\n * The wire body is an owned snapshot of\n * the projection read through property descriptors, so a serializer reachable only through a\n * `get` trap or a prototype is never consulted; an own function-valued property such as a\n * `toJSON` method is a value outside JSON and is refused before fetching, with the clone's\n * failure as the refusal's `cause`. A remote abort reconstructs a `ProviderAbortError` instance\n * without aborting the\n * local signal; the `Agent` runtime treats that instance as an error unless its own bound\n * signal is aborted.\n * Content is preserved verbatim, including literal thinking tags.\n * A refusal reaches the browser as a `ProviderError` instance with the `HTTP` code and status.\n * This is the browser end alone; {@link createRelay} mounts the server end, and\n * {@link createRelayProvider}'s example is the browser half of that pair.\n *\n * @example\n * ```ts\n * import type { ProviderResult } from '@orkestrel/agent'\n * import { RelayProvider } from '@orkestrel/agent'\n * // The browser application supplies this parser dependency.\n * import { createNDJSONParser } from '@orkestrel/ndjson'\n *\n * export function ask(bearer: string, signal: AbortSignal): Promise<ProviderResult> {\n * \tconst browser = new RelayProvider({\n * \t\turl: 'https://relay.example/relay',\n * \t\tparser: createNDJSONParser,\n * \t\theaders: () => ({ authorization: `Bearer ${bearer}` }),\n * \t})\n * \treturn browser.generate([{ id: 'ask', role: 'user', content: 'ping' }], signal)\n * }\n * ```\n */\nexport class RelayProvider extends AgentProvider {\n\treadonly #parser: () => ProviderParserInterface\n\n\tconstructor(options: RelayProviderOptions) {\n\t\tconst { url, timeout, fetch, headers, format } = options\n\t\tsuper({\n\t\t\turl,\n\t\t\tsplit: false,\n\t\t\tstrict: true,\n\t\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t\t...(fetch === undefined ? {} : { fetch }),\n\t\t\t...(headers === undefined ? {} : { headers }),\n\t\t\t...(format === undefined ? {} : { format }),\n\t\t})\n\t\tthis.#parser = options.parser\n\t}\n\n\t/** Identifies the relay backend. */\n\treadonly name = 'relay'\n\n\t/** Creates fresh framing state for each response. */\n\tframe(): ProviderParserInterface {\n\t\treturn this.#parser()\n\t}\n\n\t/**\n\t * Projects declared request fields and refuses values the JSON wire cannot carry.\n\t *\n\t * @remarks\n\t * The snapshot is taken from property descriptors, so a custom serializer a projected\n\t * value carries is ignored rather than consulted and cannot reach the wire.\n\t *\n\t * @param request - The domain conversation and call configuration\n\t * @returns The validated wire request\n\t * @throws {ProviderError} Thrown when the snapshot cannot be taken — a hostile read or a\n\t * value outside JSON — carrying that failure as its `cause`, and when the snapshot the\n\t * projection produced is not a valid wire request\n\t */\n\tbody(request: ProviderRequest): object {\n\t\tlet snapshot: unknown\n\t\ttry {\n\t\t\tconst projected = {\n\t\t\t\tmessages: request.messages.map((message) => ({\n\t\t\t\t\tid: message.id,\n\t\t\t\t\trole: message.role,\n\t\t\t\t\tcontent: message.content,\n\t\t\t\t\t...(message.calls === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tcalls: message.calls.map((call) => ({\n\t\t\t\t\t\t\t\t\tid: call.id,\n\t\t\t\t\t\t\t\t\tname: call.name,\n\t\t\t\t\t\t\t\t\targuments: call.arguments,\n\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t...(message.images === undefined ? {} : { images: message.images }),\n\t\t\t\t})),\n\t\t\t\t...(request.tools === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\ttools: request.tools.map((tool) => ({\n\t\t\t\t\t\t\t\tname: tool.name,\n\t\t\t\t\t\t\t\t...(tool.description === undefined ? {} : { description: tool.description }),\n\t\t\t\t\t\t\t\t...(tool.parameters === undefined ? {} : { parameters: tool.parameters }),\n\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t}),\n\t\t\t\t...(request.options === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t...(request.options.think === undefined ? {} : { think: request.options.think }),\n\t\t\t\t\t\t\t\t...(request.options.schema === undefined ? {} : { schema: request.options.schema }),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t}\n\t\t\tsnapshot = cloneJSONValue(projected)\n\t\t} catch (cause) {\n\t\t\tthrow new ProviderError('PROTOCOL', 'relay request is not JSON', { cause })\n\t\t}\n\t\tif (!providerRequestContract.is(snapshot)) {\n\t\t\tthrow new ProviderError('PROTOCOL', 'relay request is not JSON')\n\t\t}\n\t\treturn snapshot\n\t}\n\n\t/**\n\t * Validates a relay frame and translates its channel into the shared stream engine.\n\t *\n\t * @param record - The framed wire record\n\t * @returns A delta contribution or authoritative result\n\t * @throws {ProviderAbortError} Thrown for a remote abort carrying its partial\n\t * @throws {ProviderError} Thrown for a malformed frame or remote provider failure\n\t */\n\tread(record: Readonly<Record<string, unknown>>): ProviderIncrement {\n\t\tif (!relayFrameContract.is(record)) {\n\t\t\tthrow new ProviderError('PROTOCOL', 'invalid relay frame')\n\t\t}\n\t\tswitch (record.channel) {\n\t\t\tcase 'content':\n\t\t\t\treturn { content: record.text, thinking: '', tools: [] }\n\t\t\tcase 'thinking':\n\t\t\t\treturn { content: '', thinking: record.text, tools: [] }\n\t\t\tcase 'result':\n\t\t\t\treturn { content: '', thinking: '', tools: [], result: record.result }\n\t\t\tcase 'abort':\n\t\t\t\tthrow new ProviderAbortError(record.partial)\n\t\t\tcase 'error':\n\t\t\t\tthrow new ProviderError('PROVIDER', record.message)\n\t\t}\n\t}\n\n\t/**\n\t * Recovers an unterminated final frame by completing its NDJSON line.\n\t *\n\t * @param parser - The call's retained framing state\n\t * @returns Records completed by the final newline\n\t */\n\tfinish(parser: ProviderParserInterface): ReadonlyArray<Readonly<Record<string, unknown>>> {\n\t\treturn parser.parse('\\n')\n\t}\n}\n","import type { ProviderDelta, ProviderResult, RelayFrame, RelayStreamOptions } from './types.js'\nimport { RELAY_CONTENT_TYPE, RELAY_PROVIDER_MESSAGE } from './constants.js'\nimport { relayFrameContract } from './contracts.js'\nimport { ProviderError, isProviderAbortError } from './errors.js'\n\n/**\n * Streams a provider call as validated NDJSON frames under response backpressure.\n *\n * @remarks\n * Cancellation aborts upstream before returning its iterator. Request listeners are\n * released on settlement. Unexpected provider failures carry a fixed public message.\n * An inbound abort leaves the response body neither closed nor errored — a server runtime\n * cancels that body when the client disconnects — so a consumer that aborts the inbound\n * signal itself must cancel the body rather than keep reading it.\n *\n * @example\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { RelayStream } from '@orkestrel/agent'\n *\n * export function respond(provider: ProviderInterface, signal: AbortSignal): Response {\n * \treturn new RelayStream({ provider, request: { messages: [] }, signal }).response\n * }\n * ```\n */\nexport class RelayStream {\n\treadonly #upstream = new AbortController()\n\treadonly #encoder = new TextEncoder()\n\treadonly #iterator: AsyncGenerator<ProviderDelta, ProviderResult>\n\treadonly #signal: AbortSignal\n\treadonly #listener: () => void\n\treadonly #response: Response\n\t#settled = false\n\n\tconstructor(options: RelayStreamOptions) {\n\t\tthis.#signal = options.signal\n\t\tthis.#listener = this.#cancel.bind(this)\n\t\tif (this.#signal.aborted) this.#abortProvider()\n\t\tthis.#iterator = options.provider.stream(\n\t\t\toptions.request.messages,\n\t\t\tthis.#upstream.signal,\n\t\t\toptions.request.tools,\n\t\t\toptions.request.options,\n\t\t)\n\t\tthis.#signal.addEventListener('abort', this.#listener, { once: true })\n\t\tthis.#response = new Response(\n\t\t\tnew ReadableStream<Uint8Array>({\n\t\t\t\tpull: this.#pull.bind(this),\n\t\t\t\tcancel: this.#cancel.bind(this),\n\t\t\t}),\n\t\t\t{ headers: { 'content-type': RELAY_CONTENT_TYPE, 'cache-control': 'no-store' } },\n\t\t)\n\t}\n\n\t/** Exposes the pull-driven response for the provider call. */\n\tget response(): Response {\n\t\treturn this.#response\n\t}\n\n\tasync #pull(controller: ReadableStreamDefaultController<Uint8Array>): Promise<void> {\n\t\tif (this.#settled) return\n\t\ttry {\n\t\t\tconst step = await this.#iterator.next()\n\t\t\tif (this.#settled) return\n\t\t\tthis.#write(controller, step.done ? { channel: 'result', result: step.value } : step.value)\n\t\t\tif (step.done) this.#finish(controller)\n\t\t} catch (error) {\n\t\t\tif (this.#settled) return\n\t\t\tconst frame: RelayFrame = isProviderAbortError(error)\n\t\t\t\t? { channel: 'abort', partial: error.partial }\n\t\t\t\t: { channel: 'error', message: RELAY_PROVIDER_MESSAGE }\n\t\t\tthis.#write(\n\t\t\t\tcontroller,\n\t\t\t\trelayFrameContract.is(frame)\n\t\t\t\t\t? frame\n\t\t\t\t\t: { channel: 'error', message: RELAY_PROVIDER_MESSAGE },\n\t\t\t)\n\t\t\tthis.#finish(controller)\n\t\t\tthis.#abortProvider()\n\t\t\tawait this.#return()\n\t\t}\n\t}\n\n\tasync #cancel(): Promise<void> {\n\t\tif (this.#settled) return\n\t\tthis.#settled = true\n\t\tthis.#abortProvider()\n\t\ttry {\n\t\t\tawait this.#return()\n\t\t} finally {\n\t\t\tthis.#release()\n\t\t}\n\t}\n\n\tasync #return(): Promise<void> {\n\t\ttry {\n\t\t\tawait this.#iterator.return({ content: '' })\n\t\t} catch {\n\t\t\t// A settled response has no error channel for upstream cleanup failures.\n\t\t}\n\t}\n\n\t#write(controller: ReadableStreamDefaultController<Uint8Array>, frame: RelayFrame): void {\n\t\tif (!relayFrameContract.is(frame)) throw new ProviderError('PROTOCOL', 'invalid relay frame')\n\t\tcontroller.enqueue(this.#encoder.encode(`${JSON.stringify(frame)}\\n`))\n\t}\n\n\t#finish(controller: ReadableStreamDefaultController<Uint8Array>): void {\n\t\tthis.#settled = true\n\t\tthis.#release()\n\t\tcontroller.close()\n\t}\n\n\t#abortProvider(): void {\n\t\tthis.#upstream.abort(this.#signal.reason)\n\t}\n\n\t#release(): void {\n\t\tthis.#signal.removeEventListener('abort', this.#listener)\n\t}\n}\n","import type { ScopeFilter, ScopeInput, ScopeInterface } from '../types.js'\nimport { intersectKeys } from '../helpers.js'\n\n/**\n * Represents a named, immutable filter over a richer context's items — an optional allow-list per\n * category (`instructions` / `tools` / `files`), each keyed by that category's identity (an\n * instruction's `name`, a tool's `name`, a workspace file's `path`) and read as an allow-list:\n * `undefined` lets everything pass, `[]` lets nothing pass, and a non-empty list passes the listed\n * keys alone. `narrow` composes a tighter child by set intersection.\n *\n * @remarks\n * - **A category list is three-way.** `undefined` ⇒ no constraint on that category (all\n * pass); `[]` ⇒ none pass; a non-empty list ⇒ only the listed keys pass. The build\n * step / loop apply this through `filterAllowList`.\n * - **Immutable.** The `id` is minted at construction; every supplied list is copied in\n * (so a later mutation of the caller's array can't leak in), and the lists are\n * `readonly`. A `Scope` is never mutated after construction — `narrow` returns a new\n * one rather than altering this one.\n * - **`narrow` is set-intersection (immutable composition).** A child scope's visible set\n * per category is the intersection of this scope's list and the config's list — but\n * `undefined` means \"no constraint\", so it acts as the universal set: intersecting\n * `undefined` with a list yields the list, and `undefined` with `undefined` stays\n * `undefined`. Narrowing can only tighten, never widen — a key excluded by a parent\n * can never be re-admitted by a child.\n *\n * @example\n * ```ts\n * const scope = new Scope({ name: 'reader', tools: ['search', 'read'] })\n * // narrow intersects: tools ∩ ['read', 'write'] = ['read'] (write was never in the parent).\n * const tighter = scope.narrow({ tools: ['read', 'write'] })\n * tighter.tools // ['read']\n * // instructions had no parent constraint (undefined) → the child's list passes through.\n * tighter.narrow({ instructions: ['safety'] }).instructions // ['safety']\n * ```\n */\nexport class Scope implements ScopeInterface {\n\treadonly id: string = crypto.randomUUID()\n\treadonly name: string\n\treadonly instructions?: readonly string[]\n\treadonly tools?: readonly string[]\n\treadonly files?: readonly string[]\n\n\tconstructor(input: ScopeInput) {\n\t\tthis.name = input.name\n\t\t// Copy each supplied list in (a later mutation of the caller's array can't leak in);\n\t\t// an omitted list stays `undefined` — the \"no constraint\" sentinel.\n\t\tif (input.instructions !== undefined) this.instructions = [...input.instructions]\n\t\tif (input.tools !== undefined) this.tools = [...input.tools]\n\t\tif (input.files !== undefined) this.files = [...input.files]\n\t}\n\n\tnarrow(config: ScopeFilter): ScopeInterface {\n\t\t// A child = the per-category set-intersection of this scope and the config, keeping\n\t\t// this scope's name. Immutable: a brand-new Scope, this one untouched.\n\t\tconst instructions = intersectKeys(this.instructions, config.instructions)\n\t\tconst tools = intersectKeys(this.tools, config.tools)\n\t\tconst files = intersectKeys(this.files, config.files)\n\t\treturn new Scope({\n\t\t\tname: this.name,\n\t\t\t...(instructions === undefined ? {} : { instructions }),\n\t\t\t...(tools === undefined ? {} : { tools }),\n\t\t\t...(files === undefined ? {} : { files }),\n\t\t})\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tScopeInput,\n\tScopeInterface,\n\tScopeManagerEventMap,\n\tScopeManagerInterface,\n\tScopeManagerOptions,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Scope } from './Scope.js'\n\n/**\n * Registers the named filters a richer context reuses — immutable {@link Scope}s keyed by their\n * minted `id`, in insertion order, where `create` always mints and stores rather than overwriting,\n * and an observable `emitter` reports each change.\n *\n * @remarks\n * - **Registry.** Scopes live in an insertion-ordered `Map` keyed by their minted `id`;\n * `create` mints a {@link Scope} from a {@link ScopeInput} (an `id` plus the three\n * allow-lists), stores it, and returns it. `count` is the map size, `scope(id)` looks\n * one up, and `scopes()` lists them in insertion order. (Unlike the name-keyed\n * instruction registry, a scope's key is its minted `id`, so two scopes may share a\n * `name`; `create` therefore always adds — it never overwrites.)\n * - **Removal.** `remove` drops one by id, or a batch — `true` only when every supplied id\n * was removed; `clear` empties the registry.\n * - **Observable.** The owned {@link emitter} ({@link ScopeManagerEventMap}) carries\n * `create` (the created scope) / `remove` (the id) / `clear`. Every event is emitted\n * directly, strictly after the map mutation completes; the emitter isolates a listener\n * throw and routes it to its `error` handler (the `error` option), so a buggy observer can\n * never corrupt a mutation.\n *\n * @example\n * ```ts\n * const manager = new ScopeManager()\n * const reader = manager.create({ name: 'reader', tools: ['search', 'read'] })\n * manager.scope(reader.id) // the same scope\n * manager.count // 1\n * ```\n */\nexport class ScopeManager implements ScopeManagerInterface {\n\treadonly #scopes = new Map<string, ScopeInterface>()\n\t// The push observation surface — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape into a mutation.\n\treadonly #emitter: Emitter<ScopeManagerEventMap>\n\n\tconstructor(options?: ScopeManagerOptions) {\n\t\tthis.#emitter = new Emitter<ScopeManagerEventMap>({\n\t\t\t...(options?.on === undefined ? {} : { on: options.on }),\n\t\t\t...(options?.error === undefined ? {} : { error: options.error }),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<ScopeManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#scopes.size\n\t}\n\n\tcreate(input: ScopeInput): ScopeInterface {\n\t\tconst scope = new Scope(input)\n\t\tthis.#scopes.set(scope.id, scope)\n\t\t// Observe the created scope — after the map set, so a swallowed listener throw can't\n\t\t// perturb the store the caller is about to use.\n\t\tthis.#emitter.emit('create', scope)\n\t\treturn scope\n\t}\n\n\tscope(id: string): ScopeInterface | undefined {\n\t\treturn this.#scopes.get(id)\n\t}\n\n\tscopes(): readonly ScopeInterface[] {\n\t\treturn [...this.#scopes.values()]\n\t}\n\n\tremove(id: string): boolean\n\tremove(ids: readonly string[]): boolean\n\tremove(ids: string | readonly string[]): boolean {\n\t\tif (isArray(ids)) {\n\t\t\t// True only when every supplied id was present and removed, so a caller can tell a\n\t\t\t// fully applied batch from a partly applied one. Each present id still emits.\n\t\t\tlet removed = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (!this.#delete(id)) removed = false\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#delete(ids)\n\t}\n\n\tclear(): void {\n\t\tthis.#scopes.clear()\n\t\t// Observe the cleared registry — after the map emptied, so a swallowed listener\n\t\t// throw can never alter the clear (no payload — `clear` is a pure signal).\n\t\tthis.#emitter.emit('clear')\n\t}\n\n\t// Delete one scope, emitting `remove` only when one was actually removed (a delete of\n\t// an absent id returns `false` and emits nothing) — after the deletion.\n\t#delete(id: string): boolean {\n\t\tconst removed = this.#scopes.delete(id)\n\t\tif (removed) this.#emitter.emit('remove', id)\n\t\treturn removed\n\t}\n}\n","import type { ThinkSplitterInterface } from './types.js'\nimport { THINK_CLOSE, THINK_OPEN } from './constants.js'\n\n/**\n * Feeds raw content deltas through a tiny stream-stateful state machine that routes everything\n * inside a `<think>…</think>` span to `thinking` and returns everything outside it as clean\n * content, so a provider yields the answer alone and surfaces the reasoning as\n * {@link import('./types.js').ProviderResult.thinking}. A tag split across deltas is held until\n * disambiguated, `flush()` settles the stream end, and one splitter serves one stream.\n *\n * @remarks\n * - **Cross-chunk tags.** A tag may arrive split across wire deltas (`'<thi'` then\n * `'nk>'`): any suffix of the pending text that is a strict prefix of a tag being\n * scanned for is held back (neither surfaced nor routed) until the next delta — or\n * `flush()` — disambiguates it. A held tag prefix that never completes is real\n * content; a held close-tag prefix inside a span is thinking.\n * - **The implicit leading open (the qwen3-template shape).** Some chat templates\n * pre-seed `<think>` into the prompt scaffold, so the wire stream begins\n * mid-reasoning and only a bare `</think>` appears. Before any tag event, a bare\n * close therefore reclassifies everything surfaced so far (plus the pre-close\n * pending) as thinking — `content` is corrected retroactively (the already-returned\n * prefix cannot be recalled, so `content` is the authoritative accumulation). The\n * rule is one-shot: after any tag event a bare `</think>` is plain text.\n * - **Multiple spans** accumulate onto `thinking` in stream order. A nested-looking\n * `<think>` inside an open span is thinking text (no nesting is tracked — the\n * first `</think>` closes the span), matching how the models emit it.\n * - **Unclosed span at stream end.** `flush()` routes the open span's tail (including\n * any held partial close tag) to `thinking` — a cut-off model was still reasoning.\n * - **One splitter, one stream.** State is per-stream; create a fresh instance per\n * provider call ({@link import('./factories.js').createThinkSplitter}).\n *\n * @example\n * ```ts\n * const splitter = new ThinkSplitter()\n * splitter.split('<thi') // '' (held — ambiguous)\n * splitter.split('nk>plan</think>ok') // 'ok'\n * splitter.thinking // 'plan'\n * splitter.content // 'ok'\n * splitter.flush() // '' (nothing held)\n * ```\n */\nexport class ThinkSplitter implements ThinkSplitterInterface {\n\t// The undecided tail of the stream — text not yet routed to content or thinking\n\t// (at most one partial tag's worth between calls; transiently the whole delta).\n\t#pending = ''\n\t// Whether the scanner is inside an open `<think>` span.\n\t#inside = false\n\t// Whether a tag event has occurred (an explicit open, or the one-shot implicit-open\n\t// close) — before it, a bare `</think>` closes the implicit span a chat template\n\t// pre-seeded; after it, a bare close is plain text.\n\t#opened = false\n\t#content = ''\n\t#thinking = ''\n\n\tget content(): string {\n\t\treturn this.#content\n\t}\n\n\tget thinking(): string {\n\t\treturn this.#thinking\n\t}\n\n\tsplit(delta: string): string {\n\t\tconst out = this.#scan(delta)\n\t\tthis.#content += out\n\t\treturn out\n\t}\n\n\tflush(): string {\n\t\tconst pending = this.#pending\n\t\tthis.#pending = ''\n\t\tif (this.#inside) {\n\t\t\t// An unclosed span at stream end — the tail (held partial close tag included)\n\t\t\t// is thinking: the model was cut off mid-reasoning, never mid-answer.\n\t\t\tthis.#thinking += pending\n\t\t\tthis.#inside = false\n\t\t\treturn ''\n\t\t}\n\t\t// A held partial tag that never completed was real content after all.\n\t\tthis.#content += pending\n\t\treturn pending\n\t}\n\n\t// Drive the state machine over one delta, returning the clean content it surfaces —\n\t// the wrapper folds the return into `#content`, which the implicit-open branch may\n\t// have reset a moment earlier (the reclassification).\n\t#scan(delta: string): string {\n\t\tthis.#pending += delta\n\t\tlet content = ''\n\t\tfor (;;) {\n\t\t\tif (this.#inside) {\n\t\t\t\tconst close = this.#pending.indexOf(THINK_CLOSE)\n\t\t\t\tif (close === -1) {\n\t\t\t\t\t// No close yet — route all but a possible partial close-tag suffix to\n\t\t\t\t\t// thinking, holding that suffix for the next delta to disambiguate.\n\t\t\t\t\tthis.#thinking += this.#hold([THINK_CLOSE])\n\t\t\t\t\treturn content\n\t\t\t\t}\n\t\t\t\tthis.#thinking += this.#pending.slice(0, close)\n\t\t\t\tthis.#pending = this.#pending.slice(close + THINK_CLOSE.length)\n\t\t\t\tthis.#inside = false\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst open = this.#pending.indexOf(THINK_OPEN)\n\t\t\tif (!this.#opened) {\n\t\t\t\t// The implicit leading open: before any tag event, a bare close (arriving\n\t\t\t\t// ahead of any explicit open) means the stream began inside a pre-seeded\n\t\t\t\t// span — everything surfaced so far was reasoning. Reclassify it.\n\t\t\t\tconst close = this.#pending.indexOf(THINK_CLOSE)\n\t\t\t\tif (close !== -1 && (open === -1 || close < open)) {\n\t\t\t\t\tthis.#thinking += this.#content + content + this.#pending.slice(0, close)\n\t\t\t\t\tthis.#content = ''\n\t\t\t\t\tcontent = ''\n\t\t\t\t\tthis.#pending = this.#pending.slice(close + THINK_CLOSE.length)\n\t\t\t\t\tthis.#opened = true\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (open === -1) {\n\t\t\t\t// No open tag — surface all but a possible partial tag suffix as content\n\t\t\t\t// (before any tag event a split leading close must not leak either, so the\n\t\t\t\t// close tag's prefixes are held back too).\n\t\t\t\tconst tags = this.#opened ? [THINK_OPEN] : [THINK_OPEN, THINK_CLOSE]\n\t\t\t\tcontent += this.#hold(tags)\n\t\t\t\treturn content\n\t\t\t}\n\t\t\tthis.#opened = true\n\t\t\tcontent += this.#pending.slice(0, open)\n\t\t\tthis.#pending = this.#pending.slice(open + THINK_OPEN.length)\n\t\t\tthis.#inside = true\n\t\t}\n\t}\n\n\t// Settle the pending text against the given tags' possible partial suffixes: the\n\t// longest ambiguous suffix stays pending for the next delta; everything before it\n\t// is returned for routing.\n\t#hold(tags: readonly string[]): string {\n\t\tconst keep = Math.max(...tags.map((tag) => this.#overlap(tag)))\n\t\tconst cut = this.#pending.length - keep\n\t\tconst settled = this.#pending.slice(0, cut)\n\t\tthis.#pending = this.#pending.slice(cut)\n\t\treturn settled\n\t}\n\n\t// The length of the longest strict prefix of `tag` that suffixes the pending text —\n\t// how many trailing characters are an ambiguous partial tag and must be held back.\n\t#overlap(tag: string): number {\n\t\tconst max = Math.min(this.#pending.length, tag.length - 1)\n\t\tfor (let length = max; length > 0; length -= 1) {\n\t\t\tif (this.#pending.endsWith(tag.slice(0, length))) return length\n\t\t}\n\t\treturn 0\n\t}\n}\n","import type {\n\tAgentContextInterface,\n\tAgentContextOptions,\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentOptions,\n\tAgentQueueOptions,\n\tAgentRegistryInterface,\n\tAgentRegistryOptions,\n\tAgentResult,\n\tAgentRunnerOptions,\n\tAuthorityInterface,\n\tAuthorityOptions,\n\tChannelInterface,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tConversationManagerOptions,\n\tConversationOptions,\n\tConversationSnapshotRow,\n\tConversationStoreInterface,\n\tInstructionInput,\n\tInstructionInterface,\n\tInstructionManagerInterface,\n\tInstructionManagerOptions,\n\tProviderInterface,\n\tRelayHandler,\n\tRelayOptions,\n\tRelayProviderOptions,\n\tScopeInput,\n\tScopeInterface,\n\tScopeManagerInterface,\n\tScopeManagerOptions,\n\tThinkSplitterInterface,\n\tTextRead,\n} from './types.js'\nimport type { DriverInterface, TableInterface } from '@orkestrel/database'\nimport type { QueueInterface } from '@orkestrel/queue'\nimport type { RunnerInterface } from '@orkestrel/workflow'\nimport { parseJSONAs, rawShape, stringShape } from '@orkestrel/contract'\nimport { createDatabase, createMemoryDriver } from '@orkestrel/database'\nimport { createQueue } from '@orkestrel/queue'\nimport { createRunner } from '@orkestrel/workflow'\nimport { Agent } from './Agent.js'\nimport { AgentContext } from './AgentContext.js'\nimport { AgentRegistry } from './AgentRegistry.js'\nimport { Authority } from './Authority.js'\nimport { Channel } from './Channel.js'\nimport {\n\tDEFAULT_RELAY_LIMIT,\n\tINVALID_RELAY_STATUS,\n\tOVERSIZED_RELAY_STATUS,\n\tUNAUTHORIZED_RELAY_STATUS,\n\tUPSTREAM_RELAY_STATUS,\n} from './constants.js'\nimport { providerRequestContract } from './contracts.js'\nimport { Conversation } from './conversations/Conversation.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport { DatabaseConversationStore } from './conversations/stores/DatabaseConversationStore.js'\nimport { MemoryConversationStore } from './conversations/stores/MemoryConversationStore.js'\nimport { handleAgentQueueJob, handleAgentRunnerJob, readText } from './helpers.js'\nimport { Instruction } from './instructions/Instruction.js'\nimport { InstructionManager } from './instructions/InstructionManager.js'\nimport { RelayProvider } from './providers/RelayProvider.js'\nimport { RelayStream } from './RelayStream.js'\nimport { Scope } from './scopes/Scope.js'\nimport { ScopeManager } from './scopes/ScopeManager.js'\nimport { ThinkSplitter } from './ThinkSplitter.js'\n\n/**\n * Creates an authorized relay handler that validates a bounded JSON request before streaming.\n *\n * @remarks\n * Answers with the `401` status when authorization refuses or throws, the `400`\n * status when the body is missing, unreadable, or invalid, the `413` status when\n * the body fills its byte budget or the inbound read is aborted, and the `502`\n * status when the upstream provider call cannot be constructed. Refusals carry no body.\n *\n * @param options - The upstream provider, authorization decision, and optional byte budget\n * @returns A fetch-standard handler suitable for a router\n * @example Mounting the relay on your server\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createRelay } from '@orkestrel/agent'\n * import { createDispatcher } from '@orkestrel/router'\n * import { createServer } from '@orkestrel/server'\n *\n * declare const upstream: ProviderInterface // the server-side provider holding the credential\n * declare const bearer: string\n *\n * const handler = createRelay({\n * \tprovider: upstream,\n * \tauthorize: (request) => request.headers.get('authorization') === `Bearer ${bearer}`,\n * })\n * const dispatcher = createDispatcher({\n * \troutes: [{ method: 'POST', path: '/relay', handler }],\n * })\n *\n * export function serve(request: Request): Promise<Response> {\n * \treturn dispatcher.handle(request, undefined)\n * }\n *\n * const server = createServer({ dispatcher, state: () => undefined })\n * await server.start()\n * process.on('SIGTERM', () => server.stop()) // signal cancellation, drain, then close the listener\n * ```\n */\nexport function createRelay(options: RelayOptions): RelayHandler {\n\tconst { provider, authorize, limit } = options\n\treturn async (request) => {\n\t\ttry {\n\t\t\tif ((await authorize(request)) !== true) {\n\t\t\t\treturn new Response(undefined, { status: UNAUTHORIZED_RELAY_STATUS })\n\t\t\t}\n\t\t} catch {\n\t\t\treturn new Response(undefined, { status: UNAUTHORIZED_RELAY_STATUS })\n\t\t}\n\t\tif (request.body === null) return new Response(undefined, { status: INVALID_RELAY_STATUS })\n\t\tlet read: TextRead\n\t\ttry {\n\t\t\tread = await readText(request.body, limit ?? DEFAULT_RELAY_LIMIT, request.signal)\n\t\t} catch {\n\t\t\treturn new Response(undefined, {\n\t\t\t\tstatus: request.signal.aborted ? OVERSIZED_RELAY_STATUS : INVALID_RELAY_STATUS,\n\t\t\t})\n\t\t}\n\t\tif (!read.complete) return new Response(undefined, { status: OVERSIZED_RELAY_STATUS })\n\t\tconst parsed = parseJSONAs(read.text, providerRequestContract.is)\n\t\tif (parsed === undefined) return new Response(undefined, { status: INVALID_RELAY_STATUS })\n\t\ttry {\n\t\t\treturn new RelayStream({ provider, request: parsed, signal: request.signal }).response\n\t\t} catch {\n\t\t\treturn new Response(undefined, { status: UPSTREAM_RELAY_STATUS })\n\t\t}\n\t}\n}\n\n/**\n * Creates a provider that carries calls through a relay endpoint.\n *\n * @remarks\n * This is the browser end alone. {@link createRelay} mounts the server end, and its example\n * is the server half this one pairs with.\n *\n * @param options - The endpoint, parser factory, and HTTP call configuration\n * @returns The concrete relay provider\n * @example Reaching the relay from the browser\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createRelayProvider } from '@orkestrel/agent'\n * import { createAbort } from '@orkestrel/abort'\n * // The browser application supplies this parser dependency.\n * import { createNDJSONParser } from '@orkestrel/ndjson'\n *\n * declare const bearer: string\n * const abort = createAbort()\n * const messages = [{ id: '1', role: 'user', content: 'Say hello.' }] as const\n *\n * const browser: ProviderInterface = createRelayProvider({\n * \turl: 'https://app.example/relay',\n * \tparser: createNDJSONParser,\n * \theaders: () => ({ authorization: `Bearer ${bearer}` }),\n * })\n * const result = await browser.generate(messages, abort.signal) // a ProviderResult like a local provider's\n * ```\n */\nexport function createRelayProvider(options: RelayProviderOptions): RelayProvider {\n\treturn new RelayProvider(options)\n}\n\n/**\n * Creates a conversation — a {@link ConversationInterface} grouping messages above a flat\n * message store it owns directly, with compaction into summarized sections, a regenerated\n * rollup `summary`, on-demand `rehydrate`, and substring `search`, driven by a\n * provider-agnostic {@link ConversationSummaryHandler} seam.\n *\n * @remarks\n * Append turns through the conversation's own `add` (the live tail it owns); `view()` is the model input\n * (each section as a summary message, then the live tail). `compact()` folds the older live\n * messages into a summarized {@link Section} and regenerates the rollup — it requires\n * a `summarize` (omitted ⇒ `compact()` throws a `ConversationError`); `keep` retains a recent\n * tail (default `DEFAULT_CONVERSATION_KEEP` — fold all). `rehydrate(id)` / `search(query)` read\n * the retained originals. Observable (`emitter` — `compact` / `summary` / `rehydrate`), wired\n * through the reserved `on` option; the emitter isolates a listener throw and routes it to\n * its `error` handler (the `error` option), so it can never corrupt a compaction.\n *\n * @param options - Optional `id` / `on` hooks + the `summarize` seam + `keep` (see {@link ConversationOptions})\n * @returns A working {@link ConversationInterface}\n *\n * @example Conversations & compaction\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createConversation } from '@orkestrel/agent'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * // The summarizer seam — built from the provider by the runtime; core stays provider-agnostic.\n * // Append the instruction as the FINAL user turn: a chat model emits nothing when the prompt\n * // ends on an assistant turn, so a leading-system instruction is unreliable.\n * const conversation = createConversation({\n * \tsummarize: async (messages) =>\n * \t\t(\n * \t\t\tawait provider.generate(\n * \t\t\t\t[\n * \t\t\t\t\t...messages,\n * \t\t\t\t\t{ id: 's', role: 'user', content: 'Summarize the conversation so far concisely.' },\n * \t\t\t\t],\n * \t\t\t\tAbortSignal.timeout(30_000),\n * \t\t\t)\n * \t\t).content,\n * \tkeep: 2, // retain the two most recent turns verbatim on each compaction\n * })\n * conversation.add([\n * \t{ role: 'user', content: 'My name is Ada.' },\n * \t{ role: 'assistant', content: 'Nice to meet you, Ada.' },\n * \t{ role: 'user', content: 'What did I say my name was?' },\n * ])\n *\n * const section = await conversation.compact() // folds the older turns → a summarized section\n * conversation.view() // [<section summary message>, ...the retained recent tail] — the model input\n * conversation.summary // the regenerated rollup (a summary-of-summaries over all sections)\n * conversation.search('ada') // case-insensitive across sections' originals + the live tail\n * section && conversation.rehydrate(section.id) // the section's full original messages (a pure read)\n * ```\n */\nexport function createConversation(options?: ConversationOptions): ConversationInterface {\n\treturn new Conversation(options)\n}\n\n/**\n * Creates a conversation registry — a {@link ConversationManagerInterface} holding\n * {@link ConversationInterface}s keyed by their `id`, in insertion order, with an active pointer:\n * the id-keyed store over the conversation layer plus the `active` / `switch` seam the context\n * renders. `add` auto-activates the first conversation and flows the registry's default\n * `summarize` / `keep` into every conversation it creates.\n *\n * @remarks\n * Starts empty; `add(input?)` mints a {@link ConversationInterface} (its `id` from the input\n * or a random UUID), flowing the manager's default `summarize` / `keep` in unless the input\n * overrides them, and stores it (an already-present `id` overwrites — last write wins) — and\n * auto-activates the first one (a registry with conversations always has one `active`); a later\n * `add` leaves `active` unchanged. `switch(id)` re-points `active` (an unknown `id` returns\n * `undefined`, leaving `active` unchanged — lenient, never throws); `conversation(id)` /\n * `conversations()` look up; `remove` (one or a batch) reports `true` only when every supplied id\n * was removed and clears `active` if it was a removed one; `clear` empties it and clears `active`.\n * Event-free\n * (each conversation owns its own observable `emitter`). A conversation created with neither a\n * manager default nor a per-`add` `summarize` cannot `compact` (it throws a `ConversationError`).\n *\n * @param options - Optional default `summarize` / `keep` (see {@link ConversationManagerOptions})\n * @returns An empty {@link ConversationManagerInterface}\n *\n * @example\n * ```ts\n * import { createConversationManager } from '@orkestrel/agent'\n *\n * const conversations = createConversationManager({ summarize: async (m) => `recap of ${m.length}` })\n * const chat = conversations.add() // auto-activates — conversations.active === chat\n * chat.add({ role: 'user', content: 'Hello' })\n * ```\n */\nexport function createConversationManager(\n\toptions?: ConversationManagerOptions,\n): ConversationManagerInterface {\n\treturn new ConversationManager(options)\n}\n\n/**\n * Creates the in-memory conversation store — a {@link ConversationStoreInterface} backed by a\n * process-lifetime `Map` of {@link import('./types.js').ConversationSnapshot}s keyed by conversation\n * id, the default backing for the durable {@link ConversationManagerInterface.open} /\n * {@link ConversationManagerInterface.save} seam. The exact twin of\n * {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.\n *\n * @remarks\n * A plain `Map` (the snapshot is already pure JSON, so no encoding is needed for the memory tier),\n * the structural twin of {@link import('@orkestrel/workspace').createMemoryWorkspaceStore}.\n * `get` / `set` / `delete` are async (the\n * same shape a durable backend fits); unlike a session store there is no idle-TTL / eviction — a\n * persisted conversation lives until an explicit `delete`. Its driver-pluggable twin is\n * {@link createDatabaseConversationStore} (the snapshot as one opaque JSON column over a `databases`\n * table) — for a durable store pass it a JSON / SQLite / IndexedDB driver, and it swaps in without\n * touching the manager or the conversation. Hydration stays a manager concern: read a snapshot back\n * and rebuild the live conversation through the `snapshot` option (re-supplying the live\n * `summarize` / `keep`).\n *\n * @returns A memory-backed {@link ConversationStoreInterface}\n *\n * @example\n * ```ts\n * import { createConversationManager, createMemoryConversationStore } from '@orkestrel/agent'\n *\n * const store = createMemoryConversationStore()\n * const manager = createConversationManager({ store })\n * const conversation = manager.add()\n * conversation.add({ role: 'user', content: 'hello' })\n * await manager.save(conversation.id) // persist the conversation\n * ```\n */\nexport function createMemoryConversationStore(): ConversationStoreInterface {\n\treturn new MemoryConversationStore()\n}\n\n/**\n * Creates a {@link DatabaseConversationStore} over any {@link DriverInterface}, defaulting to\n * `createMemoryDriver()` — the durable, driver-pluggable backing for the conversation persistence\n * seam, holding each snapshot as one opaque JSON column and standing as the opt-in twin of\n * {@link createMemoryConversationStore}. The exact twin of\n * {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore}.\n *\n * @remarks\n * Builds a one-table database (`conversations`, keyed by `id`) over the supplied driver, the snapshot\n * held as one opaque JSON column — the column map is `{ id; snapshot }` where `snapshot` is a\n * `rawShape` (a JSON blob), exactly as\n * {@link import('@orkestrel/workspace').createDatabaseWorkspaceStore} stores its snapshot. The\n * snapshot is already a complete, self-contained, pure-JSON payload, so storing it whole is lossless\n * and keeps the row type flat (the column reads back as `unknown`, narrowed on `get` by\n * {@link import('./validators.js').isConversationSnapshot}). The `driver` defaults to\n * {@link createMemoryDriver}, so the store also works in memory out of the box; pass a server\n * `createJSONDriver` / `createSQLiteDriver` (or a browser IndexedDB driver) for a persistent one —\n * the durability is the driver's job, the store engine is shared. It swaps in behind\n * {@link ConversationStoreInterface} without touching the manager or the conversation.\n *\n * @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})\n * @returns A {@link ConversationStoreInterface} over the driver\n *\n * @example\n * ```ts\n * import { createConversationManager, createDatabaseConversationStore } from '@orkestrel/agent'\n * import { createMemoryDriver } from '@orkestrel/database'\n *\n * const store = createDatabaseConversationStore(createMemoryDriver()) // a durable driver swaps in here\n * const manager = createConversationManager({ store })\n * const conversation = manager.add()\n * conversation.add({ role: 'user', content: 'hello' })\n * await manager.save(conversation.id) // persist the conversation (one JSON column)\n * ```\n */\nexport function createDatabaseConversationStore(\n\tdriver: DriverInterface = createMemoryDriver(),\n): ConversationStoreInterface {\n\t// The snapshot is stored as one opaque JSON column (`rawShape`), so the row infers flat —\n\t// `{ id: string; snapshot: unknown }` = `ConversationSnapshotRow` — and the sections/messages\n\t// snapshot shape never forces a contract `Infer`.\n\tconst columns = { id: stringShape(), snapshot: rawShape({}) }\n\tconst database = createDatabase({ driver, tables: { conversations: columns } })\n\tconst table: TableInterface<ConversationSnapshotRow> = database.table('conversations')\n\treturn new DatabaseConversationStore(table)\n}\n\n/**\n * Creates an instruction — an immutable {@link InstructionInterface} (a named directive)\n * from its `name` / `content` and optional `priority`, the `id` minted at construction.\n *\n * @remarks\n * Only `name` / `content` are required; `priority` orders the instruction in an\n * {@link InstructionManagerInterface}'s rendered list (higher first) and defaults to `0`.\n * Stored immutable — never mutated after creation.\n *\n * @param input - `name` / `content` (required) and an optional `priority` (see\n * {@link InstructionInput})\n * @returns A working {@link InstructionInterface}\n *\n * @example\n * ```ts\n * import { createInstruction } from '@orkestrel/agent'\n *\n * const instruction = createInstruction({ name: 'tone', content: 'Be concise.', priority: 5 })\n * ```\n */\nexport function createInstruction(input: InstructionInput): InstructionInterface {\n\treturn new Instruction(input)\n}\n\n/**\n * Creates an instruction registry — an {@link InstructionManagerInterface} holding\n * immutable instructions keyed by `name`, listed by descending `priority`.\n *\n * @remarks\n * Starts empty; `add` (one or a batch) mints each `id` and overwrites a same-name\n * instruction (last write wins); `instructions()` lists them sorted by descending\n * `priority` (stable for ties); `open` / `render` are the build contract a richer\n * context renders an instructions block with; `remove` (one or a batch) reports `true` only\n * when every supplied name was removed; `clear` empties it. Carries an observable `emitter`\n * ({@link import('./types.js').InstructionManagerEventMap}) wired through the reserved `on`\n * option; the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option), so it can never corrupt a mutation. An optional `format`\n * override is the manager-options level of the `AgentContext` build cascade (consulted by\n * `open` / `render`, beating the provider default + built-in; a per-item\n * `InstructionInput.override` still beats it).\n *\n * @param options - Optional `on` hooks + a `format` override (see {@link InstructionManagerOptions})\n * @returns An empty {@link InstructionManagerInterface}\n *\n * @example\n * ```ts\n * import { createInstructionManager } from '@orkestrel/agent'\n *\n * const instructions = createInstructionManager()\n * instructions.add({ name: 'tone', content: 'Be concise.', priority: 5 })\n * ```\n */\nexport function createInstructionManager(\n\toptions?: InstructionManagerOptions,\n): InstructionManagerInterface {\n\treturn new InstructionManager(options)\n}\n\n/**\n * Creates a named scope — an immutable {@link ScopeInterface} from its `name` and its\n * per-category allow-lists, the `id` minted at construction.\n *\n * @remarks\n * Each list is three-way: `undefined` ⇒ no constraint on that category (all pass), `[]` ⇒\n * none pass, a non-empty list ⇒ only the listed keys pass. `narrow(config)` composes a\n * tighter child by set-intersection (an `undefined` side imposing no constraint). Stored\n * immutable — never mutated after creation (`narrow` returns a new scope).\n *\n * @param input - `name` (required) and the optional `instructions` / `tools` / `files`\n * allow-lists (see {@link ScopeInput})\n * @returns A working {@link ScopeInterface}\n *\n * @example\n * ```ts\n * import { createScope } from '@orkestrel/agent'\n *\n * const reader = createScope({ name: 'reader', tools: ['search', 'read'] })\n * reader.narrow({ tools: ['read', 'write'] }).tools // ['read'] — intersection tightens\n * ```\n */\nexport function createScope(input: ScopeInput): ScopeInterface {\n\treturn new Scope(input)\n}\n\n/**\n * Creates a scope registry — a {@link ScopeManagerInterface} holding immutable scopes keyed\n * by their minted `id`, in insertion order.\n *\n * @remarks\n * Starts empty; `create` mints each scope's `id` and stores it (keyed by `id`, so it\n * always adds — two scopes may share a `name`); `scopes()` lists them in insertion order;\n * `remove` (one or a batch) reports `true` only when every supplied id was removed; `clear`\n * empties it. Carries an observable `emitter`\n * ({@link import('./types.js').ScopeManagerEventMap}) wired through the reserved `on`\n * option; the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option), so it can never corrupt a mutation.\n *\n * @param options - Optional `on` hooks (see {@link ScopeManagerOptions})\n * @returns An empty {@link ScopeManagerInterface}\n *\n * @example\n * ```ts\n * import { createScopeManager } from '@orkestrel/agent'\n *\n * const scopes = createScopeManager()\n * const reader = scopes.create({ name: 'reader', tools: ['search'] })\n * ```\n */\nexport function createScopeManager(options?: ScopeManagerOptions): ScopeManagerInterface {\n\treturn new ScopeManager(options)\n}\n\n/**\n * Creates a richer turn context — an {@link AgentContextInterface} assembling a provider request\n * from the optional system prompt, the instruction registry, the workspace registry (the only\n * document channel), the conversation registry that is its `messages` source, the tool registry,\n * and the active scope, which `build()` folds into the next turn's input.\n *\n * @remarks\n * `system` is the optional system prompt; `tools` / `instructions` / `workspaces` are pre-built\n * managers to reuse (empty ones are created when omitted, so `context.workspaces` is always\n * present); `scope` is the initial active filter (`undefined` ⇒ no filtering, changeable afterwards\n * through `context.apply(...)`). The `messages` store is always fresh. `build()` folds the scoped\n * instructions — plus the active workspace's scope-filtered text files (fenced) — into one leading\n * `system` message and appends the scoped conversation (attaching the active workspace's\n * scope-filtered image files' `base64` payload to the last user message), built fresh each call; the active\n * workspace is the sole document/image context. Tools are advertised structurally (through\n * `tools.definitions()`, scope-filtered by the loop), never serialized into the prompt.\n *\n * @param options - Optional `system` / `tools` / `instructions` / `workspaces` / `scope`\n * (see {@link AgentContextOptions})\n * @returns A working {@link AgentContextInterface}\n *\n * @example\n * ```ts\n * import { createAgentContext } from '@orkestrel/agent'\n *\n * const context = createAgentContext({ system: 'You are concise.' })\n * context.instructions.add({ name: 'tone', content: 'Be terse.' })\n * context.messages.add({ role: 'user', content: 'Hi' })\n * context.build() // [{ role: 'system', content: 'You are concise.\\n\\n## Instructions\\n\\nBe terse.' }, { role: 'user', content: 'Hi' }]\n * ```\n */\nexport function createAgentContext(options?: AgentContextOptions): AgentContextInterface {\n\treturn new AgentContext(options)\n}\n\n/**\n * Creates an agent loop — an {@link AgentInterface} composing a\n * {@link ProviderInterface}, its {@link AgentContextInterface}, and a tool registry\n * into a bounded context → provider → tools → repeat turn, exposed as a one-shot\n * `generate` and a live `stream`.\n *\n * @remarks\n * One private loop drives the turn; `generate` drains the same stream `stream`\n * exposes, so they can never diverge. Each turn is bounded by one cancel folded from\n * `signal` + `timeout` + `budget` (through `AbortSignal.any`) — any trip (or `abort()`)\n * commits a partial result (the stream's `result` resolves on a cancel, rejects only\n * on a genuine provider / tool error). The `scheduler` paces between turns; tool\n * iteration is capped at `limit` (default `DEFAULT_AGENT_LIMIT`). Tools are advertised\n * structurally through `context.tools.definitions()`. Two observation surfaces: the\n * {@link AgentChunk} stream (pull — per-token content) and a typed `emitter` (push —\n * lifecycle + `usage` / `tool` / `deny` for fire-and-forget observers).\n *\n * @param provider - The {@link ProviderInterface} the loop drives each turn\n * @param options - Optional `system` / `tools` / `limit` / `timeout` / `budget` /\n * `scheduler` / `signal` (see {@link AgentOptions})\n * @returns A working {@link AgentInterface}\n *\n * @example\n * ```ts\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createAgent } from '@orkestrel/agent'\n * import { createTokenBudget } from '@orkestrel/budget'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const agent = createAgent(provider, {\n * \tsystem: 'You are concise.',\n * \tbudget: createTokenBudget({ max: 50_000, scope: 'total' }),\n * })\n * agent.context.messages.add({ role: 'user', content: 'Say hi.' })\n *\n * const stream = agent.stream()\n * for await (const chunk of stream.events) {\n * \tif (chunk.category === 'token') process.stdout.write(chunk.content)\n * }\n * const result = await stream.result // { content, usage?, partial }\n * ```\n */\nexport function createAgent(provider: ProviderInterface, options?: AgentOptions): AgentInterface {\n\treturn new Agent(provider, options)\n}\n\n/**\n * Creates a fresh stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that\n * splits a thinking model's in-content `<think>…</think>` reasoning spans away from the answer,\n * delta by delta, so a provider yields clean content alone and surfaces the accumulated\n * reasoning as {@link import('./types.js').ProviderResult.thinking}. One splitter serves one\n * stream.\n *\n * @remarks\n * Feed each raw wire delta through `split(delta)` (it returns the clean content to\n * surface — possibly `''` mid-think) and settle the stream end with `flush()` (a held\n * partial open tag that never completed returns as final content; an unclosed think\n * span lands on `thinking`). Tags split across deltas are held back until\n * disambiguated, multiple spans accumulate in order, and a nested-looking `<think>`\n * inside an open span is thinking text. One splitter serves one stream — create\n * a fresh one per provider call.\n *\n * @returns A fresh {@link ThinkSplitterInterface} (state empty, outside any span)\n *\n * @example\n * ```ts\n * import { createThinkSplitter } from '@orkestrel/agent'\n *\n * const splitter = createThinkSplitter()\n * const clean = splitter.split('<think>plan the answer</think>Here it is.')\n * clean // 'Here it is.'\n * splitter.thinking // 'plan the answer'\n * ```\n */\nexport function createThinkSplitter(): ThinkSplitterInterface {\n\treturn new ThinkSplitter()\n}\n\n/**\n * Creates an empty unbounded async channel — a {@link ChannelInterface} a producer writes\n * values into (`push`) and ends (`close` / `fail`) regardless of consumption, while a\n * consumer reads them back live through `drain`.\n *\n * @remarks\n * Write and read are decoupled, so the producer never waits for a consumer: an agent's eager\n * pump writes each chunk into one, which is why a run's `result` settles whether or not the\n * live events are drained. A value pushed at an already-parked consumer is delivered, buffered\n * values are yielded before the end is reported, and the first failure wins.\n *\n * @typeParam T - The value type the channel carries\n * @returns A fresh, empty {@link ChannelInterface}\n *\n * @example\n * ```ts\n * import { createChannel } from '@orkestrel/agent'\n *\n * const channel = createChannel<number>()\n * channel.push(1)\n * channel.close()\n * for await (const value of channel.drain()) {\n * \tvalue // 1\n * }\n * ```\n */\nexport function createChannel<T>(): ChannelInterface<T> {\n\treturn new Channel<T>()\n}\n\n/**\n * Creates a policy gate — an {@link AuthorityInterface} the agent loop consults before\n * each tool call runs, evaluating the ordered rules first-match-wins and falling back\n * to the configured default when none match.\n *\n * @remarks\n * `rules` are evaluated in order — the first whose `match` is true decides (a matched\n * rule allows unless its `allowed` is explicitly `false`). When no rule matches, the\n * `fallback` decides; it defaults to `{ zone: DEFAULT_AUTHORITY_ZONE, allowed: true }`\n * (allow-unmatched — a rules list of denials acts as a denylist). Pass an\n * `allowed: false` `fallback` to flip the gate to deny-by-default (an allowlist). Wire\n * the result into `createAgent` through `AgentOptions.authority`: a denied call is fed back\n * to the model as a denial `ToolResult` (not executed, no budget cost), so the model\n * can react. Synchronous — `evaluate` returns the verdict directly.\n *\n * @param options - Optional `rules` (ordered) and `fallback` (see {@link AuthorityOptions})\n * @returns A working {@link AuthorityInterface}\n *\n * @example\n * ```ts\n * import { createAgent, createAuthority } from '@orkestrel/agent'\n *\n * // Deny the `delete` tool, allow everything else.\n * const authority = createAuthority({\n * \trules: [{ match: (c) => c.call.name === 'delete', zone: 'restricted', allowed: false }],\n * })\n * const agent = createAgent(provider, { tools, authority })\n * ```\n */\nexport function createAuthority(options?: AuthorityOptions): AuthorityInterface {\n\treturn new Authority(options)\n}\n\n/**\n * Creates an agent registry — an {@link AgentRegistryInterface} holding the named pools of\n * live, non-serializable pieces (providers, tools, authorities, schedulers) that a\n * serializable {@link AgentJobInput}'s names resolve against, and `build`ing a seeded,\n * signal-wired {@link AgentInterface} from a job.\n *\n * @remarks\n * `providers` is required; `tools` / `authorities` / `schedulers` are optional pools.\n * The accessors (`provider` / `tool` / `authority` / `scheduler`) throw an\n * {@link import('./errors.js').AgentError} carrying `code: 'REGISTRY'` and the message\n * `unknown <category>: <name>` on an unregistered name — a misconfigured or crash-restored\n * job fails loudly rather than running with a missing dependency. `build(input, signal)`\n * resolves the names, rebuilds the token budget from its ceiling, seeds the agent's\n * context with the job's messages, and threads `signal` so a queue / runner abort\n * propagates. This is the bridge that makes durable, serializable agent jobs runnable.\n *\n * @param options - The named pools (see {@link AgentRegistryOptions})\n * @returns A working {@link AgentRegistryInterface}\n *\n * @example\n * ```ts\n * import { createAgentRegistry } from '@orkestrel/agent'\n * import type { ProviderInterface } from '@orkestrel/agent'\n * import { createTool } from '@orkestrel/tool'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const registry = createAgentRegistry({\n * \tproviders: { main: provider },\n * \ttools: { add: createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }) },\n * })\n * const agent = registry.build({ provider: 'main', messages: [{ role: 'user', content: 'Hi.' }] })\n * ```\n */\nexport function createAgentRegistry(options: AgentRegistryOptions): AgentRegistryInterface {\n\treturn new AgentRegistry(options)\n}\n\n/**\n * Creates a durable, bounded-concurrency agent-job queue — a {@link QueueInterface} over\n * serializable {@link AgentJobInput}s that composes `createQueue`: each job is rehydrated\n * through the `registry` into a live {@link AgentInterface}, run to its {@link AgentResult},\n * and subjected to the partial-as-configurable-failure policy.\n *\n * @remarks\n * - **Composes the substrate (no new engine).** The handler is the only new logic;\n * bounded `concurrency`, `retries`, the per-attempt `timeout`, and durable persistence\n * through `store` (+ `restore()` after a crash) are all the backing Queue's. `enqueue`\n * returns a per-job promise.\n * - **Durable + serializable.** Because `AgentJobInput` is JSON-serializable, a `store`\n * (for example `createMemoryQueueStore` / `createDatabaseQueueStore`) persists outstanding\n * jobs; `restore()` re-enqueues them after a restart and the `registry` rehydrates the\n * live pieces from the names — so a job survives a crash.\n * - **Partial policy.** A partial result throws an\n * {@link import('./errors.js').AgentJobError} by default, so a job cancelled by its\n * attempt deadline / a queue abort retries while attempts remain; `partial: true`\n * resolves the partial as success instead.\n * - **Cancellation threads through.** The handler passes `context.signal` into\n * `registry.build`, so a queue `abort()` or a per-attempt timeout cancels the in-flight\n * agent (which commits a partial → throws → retries / fails per policy).\n *\n * @param options - The `registry`, the `partial` policy, and the substrate knobs\n * (`concurrency` / `retries` / `timeout` / `store`) (see {@link AgentQueueOptions})\n * @returns A {@link QueueInterface} of {@link AgentJobInput} → {@link AgentResult}\n *\n * @example\n * ```ts\n * import { createAgentQueue, createAgentRegistry } from '@orkestrel/agent'\n * import { createMemoryQueueStore } from '@orkestrel/queue'\n *\n * const registry = createAgentRegistry({ providers: { main: provider } })\n * const store = createMemoryQueueStore(agentJobShape) // survives a restart through restore()\n * const queue = createAgentQueue({ registry, concurrency: 2, retries: 1, store })\n * const result = await queue.enqueue({ provider: 'main', messages: [{ role: 'user', content: 'ok?' }] })\n * ```\n */\nexport function createAgentQueue(\n\toptions: AgentQueueOptions,\n): QueueInterface<AgentJobInput, AgentResult> {\n\tconst { registry, partial = false, concurrency, retries, timeout, store } = options\n\treturn createQueue<AgentJobInput, AgentResult>({\n\t\t...(concurrency === undefined ? {} : { concurrency }),\n\t\t...(retries === undefined ? {} : { retries }),\n\t\t...(timeout === undefined ? {} : { timeout }),\n\t\t...(store === undefined ? {} : { store }),\n\t\thandler: handleAgentQueueJob.bind(undefined, registry, partial),\n\t})\n}\n\n/**\n * Creates an agent-job runner — a {@link RunnerInterface} over serializable\n * {@link AgentJobInput}s that composes `createRunner` (one-shot, ordered, fail-fast), each unit\n * rehydrated through the `registry` and subjected to the partial policy. The runner also carries\n * sub-agent fan-out: a parent job's handler can `controller.spawn(childJob)`.\n *\n * @remarks\n * - **Composes the substrate (no new engine).** Bounded `concurrency`, `retries`, the\n * per-attempt `timeout`, ordered results, and fail-fast are all the backing Runner's;\n * the handler adds only rehydration + the partial policy.\n * - **Sub-agent fan-out.** Each unit's handler receives a `ControllerInterface` whose\n * `spawn(childJob)` launches a child agent job through the same bounded queue (the\n * child's result joins the run after the declared units, in spawn order). On a bounded\n * runner, fan out and return — do not inline-`await` a spawn from within the handler (a\n * slot-holding handler awaiting its own spawn can deadlock; see `ControllerInterface`).\n * - **Partial policy + cancellation.** Same as `createAgentQueue`: a partial result\n * throws by default (the run's fail-fast engages), `partial: true` resolves it; the\n * handler threads `controller.signal` into `registry.build`, so a runner abort / a\n * per-attempt timeout cancels the agent.\n *\n * @param options - The `registry`, the `partial` policy, and the substrate knobs\n * (`concurrency` / `retries` / `timeout`) (see {@link AgentRunnerOptions})\n * @returns A {@link RunnerInterface} of {@link AgentJobInput} → {@link AgentResult}\n *\n * @example\n * ```ts\n * import { createAgentRunner, createAgentRegistry } from '@orkestrel/agent'\n *\n * const registry = createAgentRegistry({ providers: { main: provider } })\n * const runner = createAgentRunner({ registry, concurrency: 2 })\n * // Run two jobs; the first fans out a child sub-agent then returns.\n * const child = { provider: 'main', messages: [{ role: 'user', content: 'child' }] }\n * const parent = { provider: 'main', messages: [{ role: 'user', content: 'parent' }] }\n * const results = await runner.execute([parent, child]) // declared first, then any spawns\n * ```\n */\nexport function createAgentRunner(\n\toptions: AgentRunnerOptions,\n): RunnerInterface<AgentJobInput, AgentResult> {\n\tconst { registry, partial = false, concurrency, retries, timeout } = options\n\treturn createRunner<AgentJobInput, AgentResult>({\n\t\t...(concurrency === undefined ? {} : { concurrency }),\n\t\t...(retries === undefined ? {} : { retries }),\n\t\t...(timeout === undefined ? {} : { timeout }),\n\t\thandler: handleAgentRunnerJob.bind(undefined, registry, partial),\n\t})\n}\n"],"mappings":"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"}