@orkestrel/agent 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["#id","#emitter","#summarize","#keep","#sections","#messages","#summary","#create","#recapMessage","#summaryMessage","#conversations","#summarize","#keep","#store","#active","#drop","#instructions","#emitter","#format","#create","#delete","#tools","#definition","#run","#id","#files","#emitter","#pattern","#write","#splice","#prepend","#append","#move","#remove","#text","#workspaces","#on","#error","#store","#active","#drop","#system","#instructions","#tools","#workspaces","#conversations","#scope","#ensure","#section","#header","#render","#footer","#fenced","#attach","#workspaceImages","#withImages","#buffer","#signal","#closed","#failure","#parked","#wake","#provider","#context","#limit","#timeoutMs","#budget","#scheduler","#signal","#authority","#window","#emitter","#runs","#status","#parents","#pump","#events","#run","#result","#trim","#provide","#thought","#sum","#authorize","#reason","#denial","#providers","#tools","#authorities","#schedulers","#resolve","#options","#manager","#budget","#rules","#fallback","#table","#snapshots","#intersect","#scopes","#emitter","#delete","#content","#thinking","#scan","#pending","#inside","#hold","#opened","#overlap","#execute","#table","#snapshots"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/shapers.ts","../../../src/core/conversations/Conversation.ts","../../../src/core/conversations/ConversationManager.ts","../../../src/core/helpers.ts","../../../src/core/instructions/Instruction.ts","../../../src/core/instructions/InstructionManager.ts","../../../src/core/tools/ToolManager.ts","../../../src/core/workspaces/Workspace.ts","../../../src/core/workspaces/WorkspaceManager.ts","../../../src/core/AgentContext.ts","../../../src/core/Channel.ts","../../../src/core/Agent.ts","../../../src/core/AgentRegistry.ts","../../../src/core/Authority.ts","../../../src/core/conversations/stores/DatabaseConversationStore.ts","../../../src/core/conversations/stores/MemoryConversationStore.ts","../../../src/core/scopes/Scope.ts","../../../src/core/scopes/ScopeManager.ts","../../../src/core/ThinkSplitter.ts","../../../src/core/tools/Tool.ts","../../../src/core/workspaces/stores/DatabaseWorkspaceStore.ts","../../../src/core/workspaces/stores/MemoryWorkspaceStore.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { WorkspaceOperation } from './types.js'\n\n/**\n * The default cap on an {@link AgentInterface} turn's tool iterations — the maximum\n * number of context → provider → tools cycles before the loop stops, so a model that\n * keeps requesting tools can never loop forever. Overridable per agent via\n * `AgentOptions.limit`.\n */\nexport const DEFAULT_AGENT_LIMIT = 10\n\n/**\n * The zone an {@link AuthorityInterface}'s default fallback {@link AuthorityDecision}\n * carries — the classification for a tool call that matched no rule. Paired with the\n * 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\n * an `allowed: false` `fallback` of their own (see `AuthorityOptions`).\n */\nexport const DEFAULT_AUTHORITY_ZONE = 'default'\n\n/**\n * The default number of recent live messages a {@link ConversationInterface}'s `compact()`\n * RETAINS verbatim — `0`, so a manual `compact()` folds ALL of the current live messages\n * into one summarized section (no tail kept). A caller retains a recent tail by passing\n * `keep` (on {@link ConversationOptions}, {@link ConversationManagerOptions}, or per-fold\n * via {@link CompactOptions}), folding only the older `count - keep` messages and leaving\n * the most recent `keep` live for the next turn. Overridable everywhere `keep` is accepted.\n */\nexport const DEFAULT_CONVERSATION_KEEP = 0\n\n/**\n * 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 — not a\n * literal assistant turn to echo or treat as 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 * The opening tag a {@link import('./ThinkSplitter.js').ThinkSplitter} recognizes as the start of\n * an in-content reasoning span — the de-facto wire convention thinking models (qwen3, DeepSeek-R1\n * family) emit their chain-of-thought under when a daemon renders it inline instead of on a\n * separate wire field. Paired with {@link THINK_CLOSE}.\n */\nexport const THINK_OPEN = '<think>'\n\n/**\n * The closing tag that ends a {@link THINK_OPEN} reasoning span. A span the stream never closes\n * (the model was cut off mid-reasoning) is treated as thinking to its end —\n * {@link import('./types.js').ThinkSplitterInterface.flush} settles it.\n */\nexport const THINK_CLOSE = '</think>'\n\n/**\n * The section header {@link import('./AgentContext.js').AgentContext}'s `build()` renders the\n * ACTIVE workspace's TEXT files under — the leading line of the dedicated workspace block in the\n * system message, the carrier-split counterpart to the documents / images section headers.\n *\n * @remarks\n * `build()` OWNS the workspace render (a `Workspace` / `WorkspaceManager` stays file-focused — no\n * `description` / `framing` 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 just after the documents section in the system block.\n */\nexport const WORKSPACE_SECTION_HEADER = '## Workspace'\n\n/**\n * The extension→language table {@link import('./helpers.js').inferLanguage} reads to\n * map a file path's extension to a fenced-code language tag. Covers the common source /\n * markup / data extensions; an unlisted extension falls back to `'text'`.\n */\nexport const EXTENSION_TO_LANGUAGE: Readonly<Record<string, string>> = Object.freeze({\n\tts: 'typescript',\n\ttsx: 'typescript',\n\tjs: 'javascript',\n\tjsx: 'javascript',\n\tmjs: 'javascript',\n\tcjs: 'javascript',\n\tjson: 'json',\n\tmd: 'markdown',\n\thtml: 'html',\n\thtm: 'html',\n\tcss: 'css',\n\tscss: 'scss',\n\tsass: 'sass',\n\tless: 'less',\n\tvue: 'vue',\n\tsvelte: 'svelte',\n\tpy: 'python',\n\trb: 'ruby',\n\trs: 'rust',\n\tgo: 'go',\n\tjava: 'java',\n\tkt: 'kotlin',\n\tswift: 'swift',\n\tc: 'c',\n\tcpp: 'cpp',\n\th: 'c',\n\thpp: 'cpp',\n\tcs: 'csharp',\n\tphp: 'php',\n\tsql: 'sql',\n\tsh: 'bash',\n\tbash: 'bash',\n\tzsh: 'bash',\n\tps1: 'powershell',\n\tyaml: 'yaml',\n\tyml: 'yaml',\n\ttoml: 'toml',\n\txml: 'xml',\n\tsvg: 'xml',\n\ttxt: 'text',\n})\n\n// Workspace-tool constants — the model-facing surface `createWorkspaceTool` (factories.ts)\n// advertises. UPPER_SNAKE, `Object.freeze`d, every member exported (AGENTS §5). The\n// description teaches a small model the `operation`-discriminated union (mirroring\n// `WORKFLOW_TOOL_DESCRIPTION`'s teaching style): it names the discriminant, enumerates the\n// 13 ops with their FLAT fields (the 11 edit / read ops over the ACTIVE workspace plus the\n// `workspaces` / `switch` registry ops), and embeds a verbatim worked example pinned by a test.\n\n/**\n * The name {@link import('./factories.js').createWorkspaceTool} advertises by default — the key a\n * model calls and the {@link import('./types.js').ToolManagerInterface} registers under.\n */\nexport const WORKSPACE_TOOL_NAME = 'workspace'\n\n/**\n * A valid {@link WorkspaceOperation} object — the canonical example embedded VERBATIM in\n * {@link WORKSPACE_TOOL_DESCRIPTION} and pinned by a parity test (it must satisfy the compiled\n * contract's `is`), so the doc example can never drift from a real, contract-valid operation.\n *\n * @remarks\n * A `'write'` op (the most common authoring action): create or overwrite `notes.txt` with\n * `hello`. Frozen so it cannot be mutated in place.\n */\nexport const WORKSPACE_TOOL_EXAMPLE: WorkspaceOperation = Object.freeze({\n\toperation: 'write',\n\tpath: 'notes.txt',\n\tcontent: 'hello',\n})\n\n/**\n * The DESCRIPTION {@link import('./factories.js').createWorkspaceTool} advertises — a multi-line\n * guide that teaches a small model how to drive a workspace through the single `operation`-keyed\n * tool.\n *\n * @remarks\n * Mirrors the analogous `WORKFLOW_TOOL_DESCRIPTION` in `@orkestrel/workflow`'s teaching style:\n * names the `operation` discriminant field, enumerates all 13 operations with their FLAT fields,\n * gives a worked example for the common ones (read / write / search / replace / splice), and embeds\n * {@link WORKSPACE_TOOL_EXAMPLE} verbatim (pinned by a parity test). The range edit is the FLAT\n * `'splice'` op — four positive-integer caret components, NOT a nested range — the ergonomic lever\n * a 2B model can fill. The edit / read ops target the ACTIVE workspace (one is auto-created on the\n * first edit when none is active); the `workspaces` / `switch` ops let the model move between\n * workspaces.\n */\nexport const WORKSPACE_TOOL_DESCRIPTION = [\n\t'Read and edit files in a workspace. Every call is ONE operation, chosen by the \"operation\" field.',\n\t'All file operations act on the ACTIVE workspace; use \"workspaces\" then \"switch\" to move between workspaces.',\n\t'',\n\t'Operations (each takes the fields listed):',\n\t'- read { \"operation\": \"read\", \"path\": \"<file>\" } — return the file\\'s text.',\n\t'- list { \"operation\": \"list\" } — list every file in the active workspace (path, state, size, lines, kind).',\n\t'- has { \"operation\": \"has\", \"path\": \"<file>\" } — whether the file exists.',\n\t'- search { \"operation\": \"search\", \"query\": \"<text>\", \"regex\"?: bool, \"exact\"?: bool, \"limit\"?: int } — find lines matching the query across all files.',\n\t'- replace { \"operation\": \"replace\", \"query\": \"<text>\", \"replacement\": \"<text>\", \"regex\"?: bool, \"exact\"?: bool, \"limit\"?: int } — replace matches across all files.',\n\t'- write { \"operation\": \"write\", \"path\": \"<file>\", \"content\": \"<text>\" } — create or overwrite the whole file.',\n\t'- splice { \"operation\": \"splice\", \"path\": \"<file>\", \"content\": \"<text>\", \"fromLine\": int, \"fromColumn\": int, \"toLine\": int, \"toColumn\": int } — replace a 1-based range (from inclusive, to exclusive) with content.',\n\t'- prepend { \"operation\": \"prepend\", \"path\": \"<file>\", \"content\": \"<text>\" } — add content to the start of the file.',\n\t'- append { \"operation\": \"append\", \"path\": \"<file>\", \"content\": \"<text>\" } — add content to the end of the file.',\n\t'- move { \"operation\": \"move\", \"from\": \"<file>\", \"to\": \"<file>\" } — rename / move a file.',\n\t'- remove { \"operation\": \"remove\", \"path\": \"<file>\" } — delete a file.',\n\t'- workspaces { \"operation\": \"workspaces\" } — list the workspaces you can switch between (each id, file count, active).',\n\t'- switch { \"operation\": \"switch\", \"id\": \"<id>\" } — make the workspace with that id active (ids come from \"workspaces\").',\n\t'',\n\t'Notes: lines and columns are 1-based (column 1 is the first character). \"regex\" defaults to false (a literal substring), \"exact\" defaults to true (case-sensitive). \"search\"/\"replace\"/\"splice\" act only on text files. Editing with no active workspace auto-creates one.',\n\t'',\n\t'Example — write a file:',\n\tJSON.stringify(WORKSPACE_TOOL_EXAMPLE),\n].join('\\n')\n","import type { AgentResult, ProviderResult, WorkspaceErrorCode } from './types.js'\n\n// AGENTS §12: 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 * Thrown by a {@link ProviderInterface}'s `stream` when its bound signal aborts\n * mid-flight — carries the {@link ProviderResult} assembled from whatever streamed\n * before the cancel.\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`.\n */\nexport class ProviderAbortError extends Error {\n\treadonly partial: ProviderResult\n\n\tconstructor(partial: ProviderResult) {\n\t\tsuper('provider stream aborted')\n\t\tthis.name = 'ProviderAbortError'\n\t\tthis.partial = partial\n\t}\n}\n\n/**\n * Narrow an unknown caught value to a {@link ProviderAbortError}.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns `true` when `value` is a {@link ProviderAbortError}\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 value instanceof ProviderAbortError\n}\n\n// AGENTS §12: 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 * Thrown by an agent-job handler (a `createAgentQueue` / `createAgentRunner` job) when\n * its {@link AgentInterface} run ended {@link AgentResult.partial} and the job's\n * `allowPartial` policy is `false` (the default) — carries the partial\n * {@link AgentResult} so the failure stays inspectable.\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 `allowPartial: 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`.\n */\nexport class AgentJobError extends Error {\n\t/** 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 * Narrow an unknown caught value to an {@link AgentJobError}.\n *\n * @param value - The value to test (typically a `catch` binding or a rejected enqueue)\n * @returns `true` when `value` is an {@link AgentJobError}\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 value instanceof AgentJobError\n}\n\n// AGENTS §12: a real error type, not a sentinel. A `ConversationInterface.compact()` is a\n// PROGRAMMER error when no `ConversationSummarizer` 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 * Thrown by a {@link ConversationInterface}'s `compact()` when the conversation has no\n * {@link ConversationSummarizer} to fold its messages with — carries a machine-readable\n * `code`.\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 (§12) and throws this. `code` is\n * `'SUMMARIZER'` (the only condition so far). Narrow a caught value with\n * {@link isConversationError} and branch on `error.code`.\n */\nexport class ConversationError extends Error {\n\t/** The machine-readable condition — `'SUMMARIZER'`: a `compact()` with no summarizer. */\n\treadonly code: 'SUMMARIZER'\n\n\tconstructor(code: 'SUMMARIZER', message: string) {\n\t\tsuper(message)\n\t\tthis.name = 'ConversationError'\n\t\tthis.code = code\n\t}\n}\n\n/**\n * Narrow an unknown caught value to a {@link ConversationError}.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns `true` when `value` is a {@link ConversationError}\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 value instanceof ConversationError\n}\n\n// AGENTS §12: a text-only edit aimed at an image file, an invalid search/replace pattern,\n// or a structurally invalid edit range `throw`s a `WorkspaceError` carrying a\n// machine-readable `code`, so a `catch` branches on `error.code` instead of parsing the\n// message. The optional `context` bag names the offending path / range. Optional lookups\n// (`file`, a plain `read` of an absent or image path) return `undefined` — they never throw.\n\n/**\n * An error thrown by the in-memory {@link import('./workspaces/Workspace.js').Workspace} edit\n * surface.\n *\n * @remarks\n * Carries a {@link WorkspaceErrorCode} and an optional `context` bag naming the offending\n * path / range. Thrown for a text-only operation aimed at an image file (`MODALITY` — a\n * ranged read / write, `prepend`, or `append`), an invalid `search` / `replace` regular\n * expression (`PATTERN`), and a structurally invalid ranged-write {@link import('./types.js').Range}\n * (`RANGE` — inverted, or a sub-1 line / column).\n */\nexport class WorkspaceError extends Error {\n\treadonly code: WorkspaceErrorCode\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(\n\t\tcode: WorkspaceErrorCode,\n\t\tmessage: string,\n\t\tcontext?: Readonly<Record<string, unknown>>,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'WorkspaceError'\n\t\tthis.code = code\n\t\tthis.context = context\n\t}\n}\n\n/**\n * Narrow an unknown caught value to a {@link WorkspaceError}.\n *\n * @param value - The value to test (typically a `catch` binding)\n * @returns `true` when `value` is a {@link WorkspaceError}\n *\n * @example\n * ```ts\n * try {\n * \tworkspace.prepend('icon.png', '// header')\n * } catch (error) {\n * \tif (isWorkspaceError(error) && error.code === 'MODALITY') skipBinary()\n * }\n * ```\n */\nexport function isWorkspaceError(value: unknown): value is WorkspaceError {\n\treturn value instanceof WorkspaceError\n}\n","import {\n\tbooleanShape,\n\tintegerShape,\n\tliteralShape,\n\tobjectShape,\n\toptionalShape,\n\tstringShape,\n\tunionShape,\n} from '@orkestrel/contract'\n\n// Workspace-tool contract shape — the shape VALUE `createWorkspaceTool` (factories.ts) compiles\n// into the four lockstep outputs (JSON Schema + guard + parser + first-match parser). It MUST\n// agree with the hand-written `WorkspaceOperation` discriminated union (types.ts), which is the\n// source of truth (AGENTS §14): a valid `WorkspaceOperation` is accepted by the compiled `is` /\n// `parse`. The union compiles to an `anyOf` schema + `unionOf` guard + first-match parser\n// automatically — one `objectShape` per operation arm, each leading with the `operation`\n// discriminant.\n//\n// Every field carries a `description` so the advertised JSON Schema spells out what each op does\n// and what each field means (compilers.ts `compileSchema` emits a shape's `description` verbatim)\n// — the FLAT-steps ergonomic lever a 2B model authors a complete operation from. The range edit is\n// the FLAT `'splice'` op (four positive-integer caret components), never a nested range — the four\n// ints are reassembled into a `Range` by `rangeOf` in the handler. The description-carrying\n// `operation` discriminant rides on the shared `literalShape` (@orkestrel/contract) — the same\n// helper the workflow tool's `via` discriminant uses (consolidated there per AGENTS §5).\n\n/**\n * The shape of a {@link import('./types.js').WorkspaceOperation} — a descriptive tagged union over\n * the 13 workspace edit / read / navigation operations, discriminated by the `operation` literal\n * (never a bare `kind`; AGENTS §4.8). Each variant leads with its `operation` discriminant then its\n * FLAT fields, every field via `stringShape` / `optionalShape` / `integerShape({ min: 1 })` /\n * `booleanShape`, each carrying a strong field-level `description`.\n *\n * @remarks\n * The union compiles to an `anyOf` JSON Schema + a `unionOf` guard + a first-match parser\n * automatically ({@link import('./factories.js').createWorkspaceTool} types the result to the\n * hand-written `WorkspaceOperation`). `limit` and the four `'splice'` caret components are POSITIVE\n * integers (`integerShape({ min: 1 })`); `regex` / `exact` are `optionalShape(booleanShape(...))`.\n * The two REGISTRY arms — `workspaces` (list the workspaces the model can move between) and `switch`\n * (re-point the active one by `id`) — let a model DISCOVER then CHOOSE which workspace the edit /\n * read arms target. The descriptions are the small-model ergonomic lever — they ride into the\n * advertised schema so a model authoring an operation gets per-field guidance.\n */\nexport const workspaceToolShape = unionShape(\n\tobjectShape({\n\t\toperation: literalShape(['read'], { description: \"Read a whole text file's text by path.\" }),\n\t\tpath: stringShape({ description: 'The path of the file to read.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['list'], { description: 'List every file in the workspace.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['has'], { description: 'Check whether a file exists at the path.' }),\n\t\tpath: stringShape({ description: 'The path to check for.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['search'], {\n\t\t\tdescription: 'Search every text file for a query, returning each hit.',\n\t\t}),\n\t\tquery: stringShape({ description: 'The text (or regular-expression source) to search for.' }),\n\t\tregex: optionalShape(\n\t\t\tbooleanShape({\n\t\t\t\tdescription:\n\t\t\t\t\t'Treat the query as a regular expression. Defaults to false (a literal substring).',\n\t\t\t}),\n\t\t),\n\t\texact: optionalShape(\n\t\t\tbooleanShape({\n\t\t\t\tdescription: 'Match case-sensitively. Defaults to true (set false for case-insensitive).',\n\t\t\t}),\n\t\t),\n\t\tlimit: optionalShape(\n\t\t\tintegerShape({\n\t\t\t\tmin: 1,\n\t\t\t\tdescription: 'Stop after this many matches across all files. Omitted means unlimited.',\n\t\t\t}),\n\t\t),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['replace'], {\n\t\t\tdescription: 'Replace a query with a replacement across every text file.',\n\t\t}),\n\t\tquery: stringShape({ description: 'The text (or regular-expression source) to replace.' }),\n\t\treplacement: stringShape({ description: 'The text to substitute for each match.' }),\n\t\tregex: optionalShape(\n\t\t\tbooleanShape({\n\t\t\t\tdescription:\n\t\t\t\t\t'Treat the query as a regular expression. Defaults to false (a literal substring).',\n\t\t\t}),\n\t\t),\n\t\texact: optionalShape(\n\t\t\tbooleanShape({\n\t\t\t\tdescription: 'Match case-sensitively. Defaults to true (set false for case-insensitive).',\n\t\t\t}),\n\t\t),\n\t\tlimit: optionalShape(\n\t\t\tintegerShape({\n\t\t\t\tmin: 1,\n\t\t\t\tdescription: 'Stop after this many replacements across all files. Omitted means unlimited.',\n\t\t\t}),\n\t\t),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['write'], {\n\t\t\tdescription: 'Create or overwrite a whole file with content.',\n\t\t}),\n\t\tpath: stringShape({ description: 'The path of the file to write.' }),\n\t\tcontent: stringShape({ description: 'The full new contents of the file.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['splice'], {\n\t\t\tdescription:\n\t\t\t\t'Replace a 1-based range of an existing text file (from inclusive, to exclusive) with content.',\n\t\t}),\n\t\tpath: stringShape({ description: 'The path of the text file to edit.' }),\n\t\tcontent: stringShape({ description: 'The text to splice in place of the range.' }),\n\t\tfromLine: integerShape({\n\t\t\tmin: 1,\n\t\t\tdescription: 'The 1-based start line of the range (inclusive).',\n\t\t}),\n\t\tfromColumn: integerShape({\n\t\t\tmin: 1,\n\t\t\tdescription:\n\t\t\t\t'The 1-based start column of the range (inclusive; column 1 is the first character).',\n\t\t}),\n\t\ttoLine: integerShape({ min: 1, description: 'The 1-based end line of the range (exclusive).' }),\n\t\ttoColumn: integerShape({\n\t\t\tmin: 1,\n\t\t\tdescription: 'The 1-based end column of the range (exclusive).',\n\t\t}),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['prepend'], {\n\t\t\tdescription: 'Add content to the start of a file (creating it when absent).',\n\t\t}),\n\t\tpath: stringShape({ description: 'The path of the file to prepend to.' }),\n\t\tcontent: stringShape({ description: 'The text to add at the start of the file.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['append'], {\n\t\t\tdescription: 'Add content to the end of a file (creating it when absent).',\n\t\t}),\n\t\tpath: stringShape({ description: 'The path of the file to append to.' }),\n\t\tcontent: stringShape({ description: 'The text to add at the end of the file.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['move'], {\n\t\t\tdescription: 'Rename or move a file (overwriting an occupied target).',\n\t\t}),\n\t\tfrom: stringShape({ description: 'The current path of the file.' }),\n\t\tto: stringShape({ description: 'The new path for the file.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['remove'], { description: 'Delete a file from the workspace.' }),\n\t\tpath: stringShape({ description: 'The path of the file to remove.' }),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['workspaces'], {\n\t\t\tdescription:\n\t\t\t\t'List the workspaces you can move between (each id, file count, and whether it is active), so you can pick an id to switch to.',\n\t\t}),\n\t}),\n\tobjectShape({\n\t\toperation: literalShape(['switch'], {\n\t\t\tdescription:\n\t\t\t\t'Switch the active workspace to the one with this id (get ids from the \"workspaces\" operation). Edit and read operations then target it.',\n\t\t}),\n\t\tid: stringShape({\n\t\t\tdescription: 'The id of the workspace to make active (from the \"workspaces\" listing).',\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\tConversationSummarizer,\n\tMessageInput,\n\tMessageInterface,\n\tSectionInterface,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { CONVERSATION_RECAP_PREFIX, DEFAULT_CONVERSATION_KEEP } from '../constants.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { ConversationError } from '../errors.js'\n\n/**\n * A conversation grouping messages ABOVE a flat message store — a live uncompacted tail it\n * OWNS DIRECTLY plus compacted, summarized {@link SectionInterface}s and a regenerated rollup\n * `summary`, with on-demand `rehydrate` and substring `search`, driven by a provider-agnostic\n * {@link ConversationSummarizer} seam (so `core` never imports a provider).\n *\n * @remarks\n * - **Live tail + sections.** The conversation OWNS its live tail DIRECTLY — `#messages` is an\n * insertion-ordered `Map` of immutable {@link MessageInterface}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. Two summarizer calls\n * per compaction.\n * - **`rehydrate(id)` / `search(query)`.** `rehydrate` returns a section's full original\n * messages (`[]` for an unknown id) and emits `rehydrate` — a pure read (v1 never\n * auto-reinserts). `search` is a case-insensitive substring scan of `content` across ALL\n * messages (every section's originals + the live tail).\n * - **Observable (§13).** 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 (§13) — 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 just cannot fold).\n\treadonly #summarize: ConversationSummarizer | undefined\n\t// How many recent live messages a `compact()` retains verbatim (older ones fold).\n\treadonly #keep: number\n\t// The compacted history, oldest → newest — each summarized slice RETAINS its originals.\n\treadonly #sections: SectionInterface[] = []\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, MessageInterface>()\n\n\tconstructor(options?: ConversationOptions, seed?: ConversationSnapshot) {\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). The hydration analogue\n\t\t// of a `Workspace`'s `seed`; restoring is SILENT (no events — nothing was edited).\n\t\tthis.#id = seed?.id ?? options?.id ?? crypto.randomUUID()\n\t\tthis.#emitter = new Emitter<ConversationEventMap>({ on: options?.on, error: options?.error })\n\t\tthis.#summarize = options?.summarize\n\t\tthis.#keep = options?.keep ?? DEFAULT_CONVERSATION_KEEP\n\t\tif (seed) {\n\t\t\tthis.#summary = seed.summary\n\t\t\tfor (const section of seed.sections) this.#sections.push(section)\n\t\t\tfor (const message of seed.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 SectionInterface[] {\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): MessageInterface\n\tadd(inputs: readonly MessageInput[]): readonly MessageInterface[]\n\tadd(\n\t\tinput: MessageInput | readonly MessageInput[],\n\t): MessageInterface | readonly MessageInterface[] {\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): MessageInterface | undefined {\n\t\treturn this.#messages.get(id)\n\t}\n\n\tmessages(): readonly MessageInterface[] {\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\tlet removed = false\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (this.#messages.delete(id)) removed = true\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 MessageInterface[] {\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) => this.#recapMessage(section)),\n\t\t\t...this.#messages.values(),\n\t\t]\n\t}\n\n\tasync compact(options?: CompactOptions): Promise<SectionInterface | 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 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: SectionInterface = {\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. Regenerate the rollup — a summary-of-summaries over ALL sections (the SECOND\n\t\t// summarizer call) — then observe it, AFTER the mutation, through the guarded path.\n\t\tthis.#summary = await summarize(this.#sections.map((one) => this.#summaryMessage(one)))\n\t\tthis.#emitter.emit('summary', this.#summary)\n\t\t// 4. 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 MessageInterface[] {\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), and v1 never\n\t\t// auto-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 MessageInterface[] {\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`). 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 simply 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 (via 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 ConversationSummarizer 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// One section rendered as a RAW synthetic summary message — role `'assistant'`, keyed by the\n\t// section's stable `id`, carrying its `summary` VERBATIM as content. Used by the rollup\n\t// regeneration (a summary-of-summaries over the unframed section summaries — the recap LABEL\n\t// is a `view()`-only presentation concern, kept OUT of the digest the summarizer re-reads).\n\t#summaryMessage(section: SectionInterface): MessageInterface {\n\t\treturn { id: section.id, role: 'assistant', content: section.summary }\n\t}\n\n\t// One section rendered as a FRAMED RECAP message for `view()` (the model input) — same role +\n\t// stable `id` as `#summaryMessage`, but its content is prefixed with `RECAP_PREFIX` so a small\n\t// model reads it as a CONDENSED RECAP of earlier turns rather than a literal assistant turn to\n\t// echo or treat as the live answer. The prefix is a fixed handful of tokens (no per-section\n\t// growth beyond the constant), keeping `view()` lean — asserted by the no-bloat test guard.\n\t#recapMessage(section: SectionInterface): MessageInterface {\n\t\treturn {\n\t\t\tid: section.id,\n\t\t\trole: 'assistant',\n\t\t\tcontent: `${CONVERSATION_RECAP_PREFIX}${section.summary}`,\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): MessageInterface {\n\t\tconst message: MessageInterface = {\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\tConversationSummarizer,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { DEFAULT_CONVERSATION_KEEP } from '../constants.js'\nimport { Conversation } from './Conversation.js'\n\n/**\n * The registry of {@link Conversation}s keyed by `id`, in insertion order, WITH an active pointer\n * — the §9 store over the conversation layer PLUS the `active` / `switch` seam the\n * {@link import('../AgentContext.js').AgentContext} renders. Event-free (a registry, like\n * {@link import('../workspaces/WorkspaceManager.js').WorkspaceManager}); the observability lives\n * on each {@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 (§9.2) — `true` when any was removed;\n * 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: ConversationSummarizer | undefined\n\t// The default retained-tail size flowed into every conversation `add` creates (overridable).\n\treadonly #keep: number\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.#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 constructor `seed` (the second arg) —\n\t\t// its `id` / `summary` / `sections` / live tail restored, the live summarize / keep above\n\t\t// re-supplied alongside it (mirroring how WorkspaceManager threads `seed`).\n\t\tconst conversation = new Conversation(\n\t\t\t{\n\t\t\t\t...(input?.id === undefined ? {} : { id: input.id }),\n\t\t\t\t...(input?.on === undefined ? {} : { on: input.on }),\n\t\t\t\tsummarize: input?.summarize ?? this.#summarize,\n\t\t\t\tkeep: input?.keep ?? this.#keep,\n\t\t\t},\n\t\t\tinput?.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 ⇒ just 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 constructor `seed` (the snapshot 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// §9.2: the array overload 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\tlet removed = false\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (this.#drop(id)) removed = true\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 {\n\tAgentInterface,\n\tAgentResult,\n\tBinaryMIME,\n\tConversationSnapshot,\n\tFileContent,\n\tFileInterface,\n\tMessageInterface,\n\tPosition,\n\tRange,\n\tSectionInterface,\n\tToolCall,\n\tToolCallResult,\n\tToolResult,\n\tWorkspaceSnapshot,\n} from './types.js'\nimport { isArray, isNumber, isRecord, isString } from '@orkestrel/contract'\nimport { EXTENSION_TO_LANGUAGE } from './constants.js'\nimport { AgentJobError } from './errors.js'\n\n// The pure derivation helper a file uses to fill an inferred language field from its path\n// (§4.3 multi-word `infer*` name). Total — an unknown or extension-less input falls back to\n// a sensible default rather than throwing.\n\n/**\n * Infer a fenced-code language tag from a file path's extension — what a workspace text file\n * (or the {@link fencedFile} renderer) renders its content block as.\n *\n * @remarks\n * Reads the extension after the last `.` (case-insensitive) and maps it through a\n * fixed extension→language table. An unknown extension, or a path with no extension,\n * falls back to `'text'` (a safe, language-agnostic fence). Total — never throws.\n *\n * @param path - The document's file path (e.g. `'src/main.ts'`)\n * @returns The inferred language tag (e.g. `'typescript'`), or `'text'` when unknown\n *\n * @example\n * ```ts\n * inferLanguage('src/main.ts') // 'typescript'\n * inferLanguage('README.md') // 'markdown'\n * inferLanguage('LICENSE') // 'text'\n * ```\n */\nexport function inferLanguage(path: string): string {\n\tconst dot = path.lastIndexOf('.')\n\tif (dot === -1) return 'text'\n\tconst extension = path.slice(dot + 1).toLowerCase()\n\treturn EXTENSION_TO_LANGUAGE[extension] ?? 'text'\n}\n\n/**\n * Filter a list of items by a {@link import('./types.js').ScopeInterface} allow-list of\n * keys — the pure, total set-membership primitive the context's build step and the agent\n * 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 (e.g. 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 * Estimate the context-token footprint of a string — the deterministic char-based heuristic\n * {@link estimateMessages} sums over a conversation's messages (the default context-budget\n * 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 * Estimate the context-token footprint of a batch of messages — the default `consume`\n * estimator for an agent's context `BudgetInterface` (a budgets surface's tracking contract)\n * (the {@link import('./types.js').AgentOptions} `window`).\n *\n * @remarks\n * Sums {@link estimateTokens} over each message's `content` (the `ceil(length / 4)` char\n * heuristic), so it is deterministic and provider-free — the same messages always yield the\n * same estimate, with an empty batch `0`. It is the fully-swappable default an agent's\n * auto-compaction context budget charges each turn's new messages through; a caller wanting a\n * sharper count supplies its own `consume` to `createBudget` instead. Total — never throws.\n *\n * @param messages - The messages to estimate (a turn's appended assistant + tool messages)\n * @returns The summed estimated token count (`Σ estimateTokens(m.content)`; `0` when empty)\n *\n * @example\n * ```ts\n * estimateMessages([]) // 0\n * estimateMessages([{ id: '1', role: 'user', content: 'hello' }]) // 2\n * ```\n */\nexport function estimateMessages(messages: readonly MessageInterface[]): number {\n\treturn messages.reduce((sum, message) => sum + estimateTokens(message.content), 0)\n}\n\n/**\n * Run one rehydrated agent and apply the partial-as-configurable-failure policy — the\n * shared job-handler step BOTH `createAgentQueue` and `createAgentRunner` settle each job\n * through, so the policy can never diverge between 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); with `allowPartial` it RESOLVES\n * the partial 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 allowPartial - When `true`, a partial result resolves as success; when `false`\n * (the default policy), a partial result throws an {@link AgentJobError}\n * @returns The agent's {@link AgentResult} (a natural finish, or a partial when `allowPartial`)\n * @throws {AgentJobError} When the run ended `partial` and `allowPartial` 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\tallowPartial: boolean,\n): Promise<AgentResult> {\n\tconst result = await agent.generate()\n\tif (result.partial && !allowPartial) throw new AgentJobError('agent job ended partial', result)\n\treturn result\n}\n\n// Workspaces — the FileContent narrowing surface (the `isText` / `isBinary` / `isImage` guards that\n// tell a TAGLESS text-vs-binary content union apart STRUCTURALLY; §14: narrow an untyped arm via a\n// guard, never an `as`; there is no `modality` discriminant). `isText` tests `'text' in content`,\n// `isBinary` tests `'data' in content`, and `isImage` is a binary whose `mime` starts with `image/`\n// (so an image is just a binary with an image MIME). Every former modality check goes through these.\n//\n// Plus the pure, environment-agnostic derivation helpers a File computes its `size` / `lines` from\n// when built, plus the 1-based range helpers the Workspace edit surface slices / splices text with\n// (§4.3 multi-word `{verb}{Noun}` names). All ZERO-Node (no `node:*`, no `Buffer`/`Blob`/`atob`/DOM):\n// text byte length comes from the standard Web/Node `TextEncoder`, the decoded binary byte length is\n// computed ARITHMETICALLY from the base64 string, and the range helpers are pure string math. All\n// total — they never throw.\n//\n// Plus `fencedFile` — the one fenced-reference-block renderer `AgentContext.build()` frames an active\n// workspace's text files with (the SOLE document/image context now that the legacy managers are gone).\n\n/**\n * Whether a {@link FileContent} is the TEXT arm — the narrowing guard for the text-vs-binary\n * union (AGENTS §14: narrow an untyped arm via a guard, never an `as`).\n *\n * @remarks\n * Tests `'text' in content` structurally — there is no `modality` discriminant. A `true`\n * narrows `content` to `{ text: string; language: string }`, unlocking `.text` / `.language`.\n * Total — never throws.\n *\n * @param content - The file content to test\n * @returns `true` when `content` is the text arm (carries `text` + `language`)\n *\n * @example\n * ```ts\n * if (isText(file.content)) file.content.text // the literal text + .language\n * ```\n */\nexport function isText(\n\tcontent: FileContent,\n): content is { readonly text: string; readonly language: string } {\n\treturn 'text' in content\n}\n\n/**\n * Whether a {@link FileContent} is the BINARY arm — the narrowing guard for the text-vs-binary\n * union (AGENTS §14: narrow an untyped arm via a guard, never an `as`).\n *\n * @remarks\n * Tests `'data' in content` structurally — there is no `modality` discriminant. A `true`\n * narrows `content` to `{ data: string; mime: BinaryMIME }`, unlocking `.data` / `.mime`. An\n * image is a binary whose `mime` starts with `image/` ({@link isImage}). Total — never throws.\n *\n * @param content - The file content to test\n * @returns `true` when `content` is the binary arm (carries base64 `data` + `mime`)\n *\n * @example\n * ```ts\n * if (isBinary(file.content)) file.content.data // the base64 payload + .mime\n * ```\n */\nexport function isBinary(\n\tcontent: FileContent,\n): content is { readonly data: string; readonly mime: BinaryMIME } {\n\treturn 'data' in content\n}\n\n/**\n * Whether a {@link FileContent} is an IMAGE — a {@link isBinary} arm whose `mime` is an\n * `image/*` type (an image is just a binary with an image MIME).\n *\n * @remarks\n * Narrows to the binary arm first, then checks the `image/` MIME prefix — so a future\n * non-image binary (a PDF, `'application/pdf'`) is binary but NOT an image. Total — never\n * throws.\n *\n * @param content - The file content to test\n * @returns `true` when `content` is a binary arm with an `image/*` MIME\n *\n * @example\n * ```ts\n * isImage({ data: '<base64>', mime: 'image/png' }) // true\n * isImage({ text: 'hi', language: 'text' }) // false\n * ```\n */\nexport function isImage(content: FileContent): boolean {\n\treturn isBinary(content) && content.mime.startsWith('image/')\n}\n\n/**\n * Whether an `unknown` is structurally a {@link FileInterface} record — the per-file step of the\n * {@link isWorkspaceSnapshot} read-boundary narrow (AGENTS §14: narrow an untrusted storage read\n * via a guard, never an `as`).\n *\n * @remarks\n * A total guard (it NEVER throws — adversarial input returns `false`). It checks the file's SHAPE:\n * a record with a `string` `path`, a `string` `state`, `number` `size` / `lines`, and a `content`\n * that is EITHER the TEXT arm (`{ text: string; language: string }`) OR the BINARY arm\n * (`{ data: string; mime: string }`) — the tagless {@link FileContent} union, told apart\n * structurally exactly as {@link isText} / {@link isBinary} do (no `modality` discriminant). Enough\n * to safely impose the {@link FileInterface} type at a storage boundary WITHOUT a cast; the `mime`\n * is left as a broad `string` here (an open {@link BinaryMIME}, so any storage-read MIME string is\n * accepted defensively rather than rejected against the current literal set).\n *\n * @param value - The value to test (one element of a snapshot's opaque `files` array)\n * @returns `true` when `value` has the structural shape of a {@link FileInterface}\n *\n * @example\n * ```ts\n * isFile({ path: 'a.ts', content: { text: 'x', language: 'typescript' }, state: 'created', size: 1, lines: 1 }) // true\n * isFile({ path: 'a.png', content: { data: 'AAAA', mime: 'image/png' }, state: 'created', size: 3, lines: 0 }) // true\n * isFile({ path: 'a.ts' }) // false (missing content / state / size / lines)\n * ```\n */\nexport function isFile(value: unknown): value is FileInterface {\n\tif (!isRecord(value)) return false\n\tif (!isString(value.path) || !isString(value.state)) return false\n\tif (!isNumber(value.size) || !isNumber(value.lines)) return false\n\tif (!isRecord(value.content)) return false\n\tconst text = isString(value.content.text) && isString(value.content.language)\n\tconst binary = isString(value.content.data) && isString(value.content.mime)\n\treturn text || binary\n}\n\n/**\n * Narrow an `unknown` to a {@link WorkspaceSnapshot} — the AGENTS §14 boundary guard for an\n * UNTRUSTED snapshot read (a storage row a\n * {@link import('./workspaces/stores/DatabaseWorkspaceStore.js').DatabaseWorkspaceStore} reads back\n * from its opaque JSON column, a snapshot loaded from disk).\n *\n * @remarks\n * A total guard (it NEVER throws — adversarial input returns `false`). It checks the snapshot's\n * SHAPE: a `string` `id` and a `files` array EVERY element of which is a valid {@link FileInterface}\n * record ({@link isFile}) — enough to safely impose the {@link WorkspaceSnapshot} type at a storage\n * boundary WITHOUT a cast. The structural twin of\n * the analogous `isWorkflowSnapshot` in `@orkestrel/workflow`. A malformed blob (a non-record, a\n * missing / non-string `id`, a non-array `files`, or any malformed file element) resolves `false`,\n * so a {@link import('./workspaces/stores/DatabaseWorkspaceStore.js').DatabaseWorkspaceStore} read\n * yields `undefined` rather than a broken workspace.\n *\n * @param value - The value to test (an opaque storage read)\n * @returns `true` when `value` has the structural shape of a {@link WorkspaceSnapshot}\n *\n * @example\n * ```ts\n * isWorkspaceSnapshot({ id: 'w1', files: [] }) // true\n * isWorkspaceSnapshot({ id: 'w1', files: 'nope' }) // false\n * isWorkspaceSnapshot({ files: [] }) // false (missing id)\n * ```\n */\nexport function isWorkspaceSnapshot(value: unknown): value is WorkspaceSnapshot {\n\treturn isRecord(value) && isString(value.id) && isArray(value.files) && value.files.every(isFile)\n}\n\n/**\n * Whether an `unknown` is structurally a {@link ToolCall} record — the per-call step of the\n * {@link isMessage} read-boundary narrow (AGENTS §14: narrow an untrusted storage read via a\n * guard, never an `as`).\n *\n * @remarks\n * A total guard (it NEVER throws — adversarial input returns `false`). It checks the call's\n * SHAPE: a record with a `string` `id`, a `string` `name`, and a record `arguments` — the real\n * {@link ToolCall} shape a restored assistant turn replays to a provider. This is the ASI06\n * fail-CLOSED element check: a tampered persisted call (`null`, a bare string, a non-record\n * `arguments`) fails the guard, so {@link isMessage} — and through it\n * {@link isConversationSnapshot} — rejects the whole snapshot and a poisoned store row reads\n * back as ABSENT instead of replaying a malformed call into a chat template.\n *\n * @param value - The value to test (one element of an assistant message's `calls`)\n * @returns `true` when `value` has the structural shape of a {@link ToolCall}\n *\n * @example\n * ```ts\n * isToolCall({ id: 'c1', name: 'search', arguments: { q: 'acme' } }) // true\n * isToolCall({ id: 'c1', name: 'search' }) // false (missing arguments)\n * isToolCall({ id: 'c1', name: 123, arguments: {} }) // false (non-string name)\n * ```\n */\nexport function isToolCall(value: unknown): value is ToolCall {\n\tif (!isRecord(value)) return false\n\treturn isString(value.id) && isString(value.name) && isRecord(value.arguments)\n}\n\n/**\n * Project a {@link ToolResult} into the MCP `CallToolResult` shape — a top-level `error`\n * maps to a single `isError: true` text block (the failure reason), otherwise the `value`\n * is JSON-stringified into a single text block with no `isError`.\n *\n * @param result - The {@link ToolResult} to project (as returned by {@link import('./tools/ToolManager.js').ToolManager.execute})\n * @returns The equivalent {@link ToolCallResult}\n *\n * @example\n * ```ts\n * buildToolResult({ id: 'c1', name: 'search', error: 'max depth' })\n * // { content: [{ type: 'text', text: 'max depth' }], isError: true }\n * buildToolResult({ id: 'c1', name: 'search', value: { count: 1 } })\n * // { content: [{ type: 'text', text: '{\"count\":1}' }] }\n * ```\n */\nexport function buildToolResult(result: ToolResult): ToolCallResult {\n\tif (result.error !== undefined) {\n\t\treturn { content: [{ type: 'text', text: result.error }], isError: true }\n\t}\n\treturn { content: [{ type: 'text', text: JSON.stringify(result.value) }] }\n}\n\n/**\n * Whether an `unknown` is structurally a {@link MessageInterface} record — the per-message step of\n * the {@link isConversationSnapshot} read-boundary narrow (AGENTS §14: narrow an untrusted storage\n * read via a guard, never an `as`). The conversation analogue of {@link isFile}.\n *\n * @remarks\n * A total guard (it NEVER throws — adversarial input returns `false`). It checks the message's\n * SHAPE: a record with a `string` `id`, a `string` `role`, a `string` `content`, and — WHEN present\n * — a `calls` array EVERY element of which is a valid {@link ToolCall} ({@link isToolCall} — the\n * ASI06 fail-closed deepening: a tampered `calls` element rejects the message, so the snapshot\n * reads back as absent rather than replaying a malformed call) and an `images` that is an array\n * (an absent optional passes). The `role` is left as a broad `string` here (an open\n * {@link import('./types.js').MessageRole}, so any storage-read role string is accepted\n * defensively rather than rejected against the current literal set) — exactly as {@link isFile}\n * accepts a broad `state` / `mime`. Enough to safely impose the {@link MessageInterface} type at\n * a storage boundary WITHOUT a cast.\n *\n * @param value - The value to test (one element of a snapshot's `messages` / a section's `messages`)\n * @returns `true` when `value` has the structural shape of a {@link MessageInterface}\n *\n * @example\n * ```ts\n * isMessage({ id: '1', role: 'user', content: 'hi' }) // true\n * isMessage({ id: '1', role: 'assistant', content: '', calls: [] }) // true\n * isMessage({ id: '1', role: 'user' }) // false (missing content)\n * isMessage({ id: '1', role: 'assistant', content: '', calls: [null] }) // false (malformed call)\n * ```\n */\nexport function isMessage(value: unknown): value is MessageInterface {\n\tif (!isRecord(value)) return false\n\tif (!isString(value.id) || !isString(value.role) || !isString(value.content)) return false\n\tif (value.calls !== undefined && !(isArray(value.calls) && value.calls.every(isToolCall))) {\n\t\treturn false\n\t}\n\treturn value.images === undefined || isArray(value.images)\n}\n\n/**\n * Whether an `unknown` is structurally a {@link SectionInterface} record — the per-section step of\n * the {@link isConversationSnapshot} read-boundary narrow (AGENTS §14: narrow an untrusted storage\n * read via a guard, never an `as`).\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 MessageInterface} record ({@link isMessage}). Enough to safely impose\n * the {@link SectionInterface} 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` when `value` has the structural shape of a {@link SectionInterface}\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 SectionInterface {\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 * Narrow an `unknown` to a {@link ConversationSnapshot} — the AGENTS §14 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). The EXACT analogue of\n * {@link 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 SectionInterface} ({@link isSection}), and a `messages` array EVERY element of which is a\n * valid {@link MessageInterface} ({@link isMessage}) — enough to safely impose the\n * {@link ConversationSnapshot} type at a storage boundary WITHOUT a cast. The structural twin of\n * {@link 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` when `value` has the structural shape of a {@link ConversationSnapshot}\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\n/**\n * Compute the byte size of a {@link FileContent} — the `size` a {@link FileInterface} derives\n * once when built.\n *\n * @remarks\n * Dispatches on {@link isText}: a text arm is its UTF-8 byte length (via `new\n * TextEncoder().encode(text).length` — the standard Web/Node API, so a multi-byte\n * character like `'é'` or `'😀'` counts as its real encoded bytes, NOT its character\n * count); a binary arm is the decoded payload byte length of its base64 `data` (via\n * {@link decodedSize}, computed arithmetically — no `atob` / `Buffer`). Total — never throws.\n *\n * @param content - The file content to size\n * @returns The byte size (UTF-8 bytes for text; decoded payload bytes for binary)\n *\n * @example\n * ```ts\n * computeSize({ text: 'café', language: 'text' }) // 5 (é is two bytes)\n * computeSize({ data: 'AAAA', mime: 'image/png' }) // 3\n * ```\n */\nexport function computeSize(content: FileContent): number {\n\tif (isText(content)) return new TextEncoder().encode(content.text).length\n\treturn decodedSize(content.data)\n}\n\n/**\n * Count the lines of a {@link FileContent} — the `lines` a {@link FileInterface} derives once\n * when built.\n *\n * @remarks\n * A text arm's line count is `0` for the empty string, otherwise one more than the\n * number of newline (`\\n`) separators it contains — so `'a'` is one line, `'a\\nb'` is two,\n * and a trailing newline `'a\\n'` counts the empty final line as two. A binary arm has no\n * lines and returns `0`. Total — never throws.\n *\n * @param content - The file content to count lines for\n * @returns The line count (text line count; `0` for a binary arm or empty text)\n *\n * @example\n * ```ts\n * countLines({ text: '', language: 'text' }) // 0\n * countLines({ text: 'a\\nb\\nc', language: 'text' }) // 3\n * countLines({ data: 'AAAA', mime: 'image/png' }) // 0\n * ```\n */\nexport function countLines(content: FileContent): number {\n\tif (!isText(content)) return 0\n\tif (content.text.length === 0) return 0\n\tlet count = 1\n\tfor (const character of content.text) if (character === '\\n') count += 1\n\treturn count\n}\n\n/**\n * Compute the decoded byte length of a base64 string ARITHMETICALLY — the image-payload\n * sizing primitive {@link computeSize} uses, with no `atob` / `Buffer` decode.\n *\n * @remarks\n * A base64 string encodes each group of 3 input bytes as 4 characters, so a well-formed\n * string's length is a multiple of 4 and its decoded length is `(length / 4) * 3` MINUS\n * the trailing `=` padding (one `=` ⇒ the last group held 2 bytes, two `==` ⇒ 1 byte).\n * The padding is counted from the trailing `=` characters, so both the `=` and `==` cases\n * are handled. The empty string decodes to `0`. Total — never throws (a malformed,\n * non-multiple-of-4 length still yields a defined non-negative estimate via `floor`).\n *\n * @param base64 - The base64-encoded string (e.g. an image's `data`)\n * @returns The decoded payload's byte length\n *\n * @example\n * ```ts\n * decodedSize('') // 0\n * decodedSize('AAAA') // 3 (no padding)\n * decodedSize('AAA=') // 2 (one '=')\n * decodedSize('AA==') // 1 (two '=')\n * ```\n */\nexport function decodedSize(base64: string): number {\n\tif (base64.length === 0) return 0\n\tlet padding = 0\n\tif (base64.endsWith('==')) padding = 2\n\telse if (base64.endsWith('=')) padding = 1\n\treturn Math.floor(base64.length / 4) * 3 - padding\n}\n\n/**\n * Whether a {@link Range} is STRUCTURALLY valid — the predicate a ranged `write` checks\n * before applying (a `false` here is the `RANGE` throw).\n *\n * @remarks\n * Structural validity is independent of any content: every component must be `>= 1`\n * (1-based lines and columns), and `start` must not come after `end` (an inverted range\n * is invalid). A range that is structurally valid but reaches PAST the end of a specific\n * text is still valid — it is {@link clampRange}d to the bounds when applied, not rejected.\n * Total — never throws.\n *\n * @param range - The range to validate\n * @returns `true` when every component is `>= 1` and `start` is at or before `end`\n *\n * @example\n * ```ts\n * isValidRange({ start: { line: 1, column: 1 }, end: { line: 2, column: 1 } }) // true\n * isValidRange({ start: { line: 2, column: 1 }, end: { line: 1, column: 1 } }) // false (inverted)\n * isValidRange({ start: { line: 0, column: 1 }, end: { line: 1, column: 1 } }) // false (sub-1 line)\n * ```\n */\nexport function isValidRange(range: Range): boolean {\n\tif (range.start.line < 1 || range.start.column < 1) return false\n\tif (range.end.line < 1 || range.end.column < 1) return false\n\tif (range.start.line > range.end.line) return false\n\treturn !(range.start.line === range.end.line && range.start.column > range.end.column)\n}\n\n/**\n * Clamp a 1-based {@link Position} to the bounds of `text` — every component pinned into a\n * caret that actually exists in the content.\n *\n * @remarks\n * `line` is pinned to `[1, lineCount]` and `column` to `[1, lineLength + 1]` of the\n * resolved line (column `lineLength + 1` is the caret just past the line's last\n * character). So a position beyond the end of the text resolves to the end rather than\n * overflowing. Total — never throws.\n *\n * @param text - The text the position addresses\n * @param position - The 1-based position to clamp\n * @returns The clamped {@link Position}\n *\n * @example\n * ```ts\n * clampPosition('ab\\ncd', { line: 9, column: 9 }) // { line: 2, column: 3 } (end of 'cd')\n * ```\n */\nexport function clampPosition(text: string, position: Position): Position {\n\tconst lines = text.split('\\n')\n\tconst line = Math.max(1, Math.min(position.line, lines.length))\n\tconst lineText = lines[line - 1] ?? ''\n\tconst column = Math.max(1, Math.min(position.column, lineText.length + 1))\n\treturn { line, column }\n}\n\n/**\n * Clamp both ends of a {@link Range} to the bounds of `text` — the actual span a ranged\n * read / write applies (and the `range` a {@link import('./types.js').ReadResult} reports).\n *\n * @remarks\n * Clamps `start` and `end` independently via {@link clampPosition}, so a range reaching\n * past the end of the content is trimmed to the content's end. Total — never throws.\n *\n * @param text - The text the range addresses\n * @param range - The 1-based range to clamp\n * @returns The clamped {@link Range}\n *\n * @example\n * ```ts\n * clampRange('ab\\ncd', { start: { line: 1, column: 1 }, end: { line: 9, column: 9 } })\n * // { start: { line: 1, column: 1 }, end: { line: 2, column: 3 } }\n * ```\n */\nexport function clampRange(text: string, range: Range): Range {\n\treturn { start: clampPosition(text, range.start), end: clampPosition(text, range.end) }\n}\n\n/**\n * Convert a 1-based {@link Position} to a 0-based string offset into `text` — the indexing\n * primitive {@link sliceRange} / {@link spliceRange} use, clamped to `text.length`.\n *\n * @remarks\n * Sums each preceding line's length plus its `\\n` separator, then adds the `column - 1`\n * within the target line, capped at `text.length`. Total — never throws (an out-of-bounds\n * position yields a defined in-range offset).\n *\n * @param text - The text to index into\n * @param position - The 1-based position to resolve\n * @returns The 0-based offset (in `[0, text.length]`)\n *\n * @example\n * ```ts\n * offsetAt('ab\\ncd', { line: 2, column: 1 }) // 3 (just after 'ab\\n')\n * ```\n */\nexport function offsetAt(text: string, position: Position): number {\n\tconst lines = text.split('\\n')\n\tlet offset = 0\n\tfor (let index = 0; index < position.line - 1 && index < lines.length; index += 1) {\n\t\toffset += (lines[index]?.length ?? 0) + 1\n\t}\n\toffset += position.column - 1\n\treturn Math.min(offset, text.length)\n}\n\n/**\n * Slice the substring of `text` spanned by a {@link Range} (start INCLUSIVE, end\n * EXCLUSIVE), clamping the range to the text's bounds first — the read half of the ranged\n * edit surface.\n *\n * @remarks\n * Clamps via {@link clampRange}, resolves each end to an offset via {@link offsetAt}, and\n * returns `text.slice(startOffset, endOffset)`. Total — never throws.\n *\n * @param text - The text to slice\n * @param range - The 1-based range to extract\n * @returns The spanned substring (empty when the clamped span is empty)\n *\n * @example\n * ```ts\n * sliceRange('hello\\nworld', { start: { line: 1, column: 1 }, end: { line: 1, column: 6 } }) // 'hello'\n * ```\n */\nexport function sliceRange(text: string, range: Range): string {\n\tconst clamped = clampRange(text, range)\n\treturn text.slice(offsetAt(text, clamped.start), offsetAt(text, clamped.end))\n}\n\n/**\n * Replace the span of `text` covered by a {@link Range} with `replacement` (start\n * INCLUSIVE, end EXCLUSIVE), clamping the range to the text's bounds first — the write\n * half of the ranged edit surface.\n *\n * @remarks\n * Clamps via {@link clampRange}, then stitches `before + replacement + after` around the\n * resolved offsets. An empty span (`start === end`) becomes a pure insertion. Total —\n * never throws.\n *\n * @param text - The original text\n * @param range - The 1-based range to overwrite\n * @param replacement - The text to splice in place of the spanned range\n * @returns The text with the spanned range replaced by `replacement`\n *\n * @example\n * ```ts\n * spliceRange('hello', { start: { line: 1, column: 1 }, end: { line: 1, column: 6 } }, 'bye') // 'bye'\n * ```\n */\nexport function spliceRange(text: string, range: Range, replacement: string): string {\n\tconst clamped = clampRange(text, range)\n\tconst start = offsetAt(text, clamped.start)\n\tconst end = offsetAt(text, clamped.end)\n\treturn text.slice(0, start) + replacement + text.slice(end)\n}\n\n/**\n * Assemble a 1-based nested {@link Range} from the four FLAT caret integers of the workspace tool's\n * `'splice'` operation — the bridge from the small-model FLAT surface\n * ({@link import('./types.js').WorkspaceOperation}) back to the nested {@link Range} the\n * {@link import('./workspaces/Workspace.js').Workspace} edit surface speaks.\n *\n * @remarks\n * Pairs `(fromLine, fromColumn)` into `start` and `(toLine, toColumn)` into `end` verbatim — a pure\n * structural lift, no validation (a structurally invalid range is rejected downstream by the ranged\n * `write` it feeds, via {@link isValidRange}). Total — never throws. Zero-Node.\n *\n * @param fromLine - The 1-based start line\n * @param fromColumn - The 1-based start column\n * @param toLine - The 1-based end line\n * @param toColumn - The 1-based end column\n * @returns The `{ start, end }` {@link Range}\n *\n * @example\n * ```ts\n * rangeOf(1, 11, 1, 12) // { start: { line: 1, column: 11 }, end: { line: 1, column: 12 } }\n * ```\n */\nexport function rangeOf(\n\tfromLine: number,\n\tfromColumn: number,\n\ttoLine: number,\n\ttoColumn: number,\n): Range {\n\treturn { start: { line: fromLine, column: fromColumn }, end: { line: toLine, column: toColumn } }\n}\n\n/**\n * Render a path-addressed text body as a fenced reference block — the framing an\n * {@link import('./AgentContext.js').AgentContext}'s ACTIVE-workspace text-file render emits (the\n * active workspace is the SOLE document/image context).\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 FileContent} text arm).\n *\n * @param path - The file path shown on the `File:` label line\n * @param language - The fenced-code language tag (e.g. `'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 { fencedFile } from '@src/core'\n *\n * fencedFile('src/main.ts', 'typescript', 'const x = 1')\n * // 'File: src/main.ts\\n```typescript\\nconst x = 1\\n```'\n * ```\n */\nexport function fencedFile(path: string, language: string, content: string): string {\n\treturn `File: ${path}\\n\\`\\`\\`${language}\\n${content}\\n\\`\\`\\``\n}\n\n/**\n * Escape a string's regex-special characters so it matches LITERALLY inside a `RegExp` — the\n * primitive a {@link import('./workspaces/Workspace.js').Workspace} search builds a literal-text\n * search pattern through (as opposed to a caller-supplied regex pattern).\n *\n * @remarks\n * Prefixes every character in the class `. * + ? ^ $ { } ( ) | [ ] \\` with a backslash, so the\n * escaped string, when compiled into a `RegExp`, matches only its own literal characters — no\n * character acts as a quantifier, anchor, group, or class. Pure string assembly, total — never\n * throws.\n *\n * @param value - The text to escape for literal use inside a `RegExp` pattern\n * @returns `value` with every regex-special character backslash-escaped\n *\n * @example\n * ```ts\n * escapeRegExp('a.b*c') // 'a\\\\.b\\\\*c'\n * new RegExp(escapeRegExp('a.b*c')).test('a.b*c') // true\n * ```\n */\nexport function escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n","import type { InstructionInput, InstructionInterface } from '../types.js'\n\n/**\n * An immutable named directive — a {@link InstructionInterface} assembled once from its\n * input (`name` / `content`, an optional `priority` defaulting to `0`), the `id` minted\n * at construction.\n *\n * @remarks\n * A thin immutable value object (mirroring {@link import('../tools/Tool.js').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 `format` override ONLY when supplied (assigned just 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 format 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 format?: 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.format !== undefined) this.format = input.format\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 * The instruction registry a richer context assembles a directives block from —\n * immutable {@link Instruction}s keyed by `name`, listed by descending `priority`.\n *\n * @remarks\n * - **Registry.** Instructions live in an insertion-ordered `Map` keyed by `name`;\n * `add` takes one {@link InstructionInput} or a batch (§9.2), 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).** `description` is the section\n * header a context renders the instructions under; `format(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`, `description` / `format` 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.format} is round-tripped onto the stored instruction.\n * - **Removal.** `remove` drops one by name, or a batch (§9.2) — `true` when any was\n * removed; `clear` empties the registry.\n * - **Observable (§13).** 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 (§13) — 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 `description` /\n\t// `format` (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\ton: options?.on,\n\t\t\terror: 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 description(): 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 framing(): 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 / `description` / `format` 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\tformat(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\tlet removed = false\n\t\t\tfor (const name of names) {\n\t\t\t\tif (this.#delete(name)) removed = true\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\tToolCall,\n\tToolDefinition,\n\tToolInterface,\n\tToolManagerInterface,\n\tToolResult,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\n\n/**\n * The tool registry the agent loop dispatches model tool-calls through — resolves\n * names, lists {@link ToolDefinition}s for the provider, and executes calls with\n * per-call error isolation.\n *\n * @remarks\n * - **Registry.** Tools live in an insertion-ordered `Map` keyed by `tool.name`;\n * `add` takes one or a batch (§9.2) and a re-`add` of the same name OVERWRITES it\n * (last write wins). `count` is the map size, `tool(name)` looks one up, `tools()`\n * lists them in insertion order, and `definitions()` maps each to a plain\n * {@link ToolDefinition} (`name` / `description?` / `parameters?`, the `execute`\n * handler stripped) — exactly what a provider advertises to the model.\n * - **Per-call error isolation (the load-bearing part).** `execute` resolves a\n * {@link ToolCall}'s tool by name and ALWAYS resolves a {@link ToolResult}: an\n * unknown name → `{ id, name, error: 'tool not found: <name>' }`; a successful run →\n * `{ id, name, value }`; a handler throw is CAUGHT into `{ id, name, error }` (an\n * `Error`'s message, else the stringified throw). A tool throw never escapes — it\n * becomes a result the model can react to.\n * - **Batch never fails as a whole.** `execute(calls)` runs every call via\n * `Promise.all(calls.map(...))` and resolves the results correlated by `id` in the\n * input order — a mix of success, throw, and not-found all resolve; one bad call\n * does not reject the batch.\n * - **Event-free.** A purely functional registry — no Emitter, no events.\n *\n * @example\n * ```ts\n * const manager = new ToolManager()\n * manager.add(new Tool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))\n * const result = await manager.execute({ id: '1', name: 'add', arguments: { x: 1, y: 2 } })\n * result.value // 3\n * ```\n */\nexport class ToolManager implements ToolManagerInterface {\n\treadonly #tools = new Map<string, ToolInterface>()\n\n\tget count(): number {\n\t\treturn this.#tools.size\n\t}\n\n\tadd(tool: ToolInterface): void\n\tadd(tools: readonly ToolInterface[]): void\n\tadd(tools: ToolInterface | readonly ToolInterface[]): void {\n\t\tif (isArray(tools)) {\n\t\t\tfor (const tool of tools) this.#tools.set(tool.name, tool)\n\t\t\treturn\n\t\t}\n\t\tthis.#tools.set(tools.name, tools)\n\t}\n\n\ttool(name: string): ToolInterface | undefined {\n\t\treturn this.#tools.get(name)\n\t}\n\n\ttools(): readonly ToolInterface[] {\n\t\treturn [...this.#tools.values()]\n\t}\n\n\tdefinitions(): readonly ToolDefinition[] {\n\t\treturn [...this.#tools.values()].map((tool) => this.#definition(tool))\n\t}\n\n\texecute(call: ToolCall): Promise<ToolResult>\n\texecute(calls: readonly ToolCall[]): Promise<readonly ToolResult[]>\n\texecute(call: ToolCall | readonly ToolCall[]): Promise<ToolResult | readonly ToolResult[]> {\n\t\t// The batch form runs every call concurrently and resolves results correlated by\n\t\t// id in order — one bad call (throw / not-found) never fails the whole batch.\n\t\tif (isArray(call)) return Promise.all(call.map((one) => this.#run(one)))\n\t\treturn this.#run(call)\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\tlet removed = false\n\t\t\tfor (const name of names) {\n\t\t\t\tif (this.#tools.delete(name)) removed = true\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#tools.delete(names)\n\t}\n\n\tclear(): void {\n\t\tthis.#tools.clear()\n\t}\n\n\t// Run one call with per-call error isolation: an unknown name → a not-found error\n\t// result; a handler throw → an error result (never re-thrown). The tool throw is\n\t// turned into a ToolResult the model can react to.\n\tasync #run(call: ToolCall): Promise<ToolResult> {\n\t\tconst tool = this.#tools.get(call.name)\n\t\tif (tool === undefined)\n\t\t\treturn { id: call.id, name: call.name, error: `tool not found: ${call.name}` }\n\t\ttry {\n\t\t\tconst value = await tool.execute(call.arguments)\n\t\t\treturn { id: call.id, name: call.name, value }\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tid: call.id,\n\t\t\t\tname: call.name,\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t}\n\t\t}\n\t}\n\n\t// Strip a tool to the plain ToolDefinition a provider advertises — the schema the\n\t// model sees (name / description? / parameters?), without the execute handler.\n\t#definition(tool: ToolInterface): ToolDefinition {\n\t\tconst definition: {\n\t\t\tname: string\n\t\t\tdescription?: string\n\t\t\tparameters?: Readonly<Record<string, unknown>>\n\t\t} = {\n\t\t\tname: tool.name,\n\t\t}\n\t\tif (tool.description !== undefined) definition.description = tool.description\n\t\tif (tool.parameters !== undefined) definition.parameters = tool.parameters\n\t\treturn definition\n\t}\n}\n","import type { EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tFileInterface,\n\tRange,\n\tReadResult,\n\tReplaceOptions,\n\tReplaceResult,\n\tSearchMatch,\n\tSearchOptions,\n\tWorkspaceEventMap,\n\tWorkspaceInterface,\n\tWorkspaceOptions,\n\tWorkspaceSnapshot,\n} from '../types.js'\nimport { isArray, isRecord } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { escapeRegExp } from '../helpers.js'\nimport { WorkspaceError } from '../errors.js'\nimport { createFile } from '../factories.js'\nimport {\n\tclampRange,\n\tinferLanguage,\n\tisText,\n\tisValidRange,\n\tsliceRange,\n\tspliceRange,\n} from '../helpers.js'\n\n/**\n * A mutable, `path`-keyed working set of immutable {@link FileInterface}s — the\n * in-memory editing surface over the file primitive.\n *\n * @remarks\n * - **Registry.** Files live in an insertion-ordered `Map` keyed by `path`; `count` is the\n * map size, `file(path)` looks one up, and `files()` lists them in insertion order.\n * - **Write replaces the File (§11 immutability).** Every edit MINTS a replacement\n * {@link FileInterface} (via {@link import('../factories.js').createFile}) rather than\n * mutating in place, transitioning `state` to `'created'` for a brand-new path or\n * `'modified'` for an existing one. A whole-file string write preserves an existing text\n * file's `language`, else infers it from the `path` (`inferLanguage`); writing a string\n * onto an existing BINARY path replaces it with a text file (a deliberate retype). A\n * ranged `write` splices a `Range` of an existing text file.\n * - **Modality rules.** Text-only ops on a binary file are rejected: a ranged `read` /\n * `write`, `prepend`, and `append` throw `MODALITY`; a plain `read(path)` of a binary\n * file returns `undefined`; `search` / `replace` skip binary files (0 matches).\n * - **In-memory removal.** `remove(path)` / `remove(paths)` drop files outright (no\n * tombstone — the `'loaded'` / `'deleted'` states are reserved for a future FileStore);\n * `remove()` and `clear()` both empty the registry and emit the single `clear` signal.\n * The disk/sync lifecycle (`load` / `revert` / `accept` / `purge` / `dirty`) is NOT part\n * of this surface.\n * - **Observable (§13).** The owned {@link emitter} ({@link WorkspaceEventMap}) carries\n * `write` (the resulting file) / `remove` (the path) / `move` (`{ from, to }`) / `clear`.\n * Every event is emitted directly, strictly AFTER the map mutation completes; the\n * emitter isolates a listener throw and routes it to its `error` handler, so a buggy\n * observer can never corrupt a mutation.\n *\n * @example\n * ```ts\n * const workspace = new Workspace()\n * workspace.write('src/main.ts', 'const x = 1')\n * workspace.file('src/main.ts')?.state // 'created'\n * workspace.append('src/main.ts', '\\nconst y = 2')\n * workspace.file('src/main.ts')?.state // 'modified'\n * workspace.read('src/main.ts') // 'const x = 1\\nconst y = 2'\n * ```\n */\nexport class Workspace implements WorkspaceInterface {\n\t// The workspace's identity — its key in a WorkspaceManager; minted when not supplied\n\t// (exactly as Conversation mints its own #id).\n\treadonly #id: string\n\t// The path-keyed registry — insertion-ordered, holding immutable Files replaced (not\n\t// mutated) on every edit.\n\treadonly #files = new Map<string, FileInterface>()\n\t// The PUSH observation surface (§13) — owned, never inherited. The emitter isolates a\n\t// listener throw (routing it to the `error` handler), so it can never escape a mutation.\n\treadonly #emitter: Emitter<WorkspaceEventMap>\n\n\tconstructor(options?: WorkspaceOptions, seed?: Iterable<readonly [string, FileInterface]>) {\n\t\tthis.#id = options?.id ?? crypto.randomUUID()\n\t\tthis.#emitter = new Emitter<WorkspaceEventMap>({ on: options?.on, error: options?.error })\n\t\t// An optional pre-seeded set of files (path → File) — the hydration seam a future\n\t\t// FileStore reads a snapshot into, and the only way to seat a non-text (binary) file\n\t\t// (the edit surface itself only ever mints text Files). Seeding is silent — it places\n\t\t// files without emitting, since nothing was edited.\n\t\tif (seed) for (const [path, file] of seed) this.#files.set(path, file)\n\t}\n\n\tget id(): string {\n\t\treturn this.#id\n\t}\n\n\tget emitter(): EmitterInterface<WorkspaceEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#files.size\n\t}\n\n\tfile(path: string): FileInterface | undefined {\n\t\treturn this.#files.get(path)\n\t}\n\n\tfiles(): readonly FileInterface[] {\n\t\treturn [...this.#files.values()]\n\t}\n\n\tread(path: string): string | undefined\n\tread(path: string, range: Range): ReadResult | undefined\n\tread(paths: readonly string[]): Readonly<Record<string, string>>\n\tread(\n\t\tpath: string | readonly string[],\n\t\trange?: Range,\n\t): string | ReadResult | undefined | Readonly<Record<string, string>> {\n\t\tif (isArray(path)) {\n\t\t\tconst result: Record<string, string> = {}\n\t\t\tfor (const one of path) {\n\t\t\t\tconst file = this.#files.get(one)\n\t\t\t\tif (file && isText(file.content)) result[one] = file.content.text\n\t\t\t}\n\t\t\treturn result\n\t\t}\n\t\tconst file = this.#files.get(path)\n\t\tif (!file) return undefined\n\t\tif (!range) return isText(file.content) ? file.content.text : undefined\n\t\t// A ranged read of a binary file is a text-only op aimed at a non-text arm.\n\t\tif (!isText(file.content)) {\n\t\t\tthrow new WorkspaceError('MODALITY', `Cannot read a range of a binary file: ${path}`, {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t\t// `range` reports the clamped span actually applied (so a past-the-end request\n\t\t// surfaces the trimmed range, never the original out-of-bounds one).\n\t\treturn {\n\t\t\tcontent: sliceRange(file.content.text, range),\n\t\t\trange: clampRange(file.content.text, range),\n\t\t}\n\t}\n\n\thas(path: string): boolean\n\thas(paths: readonly string[]): boolean\n\thas(path: string | readonly string[]): boolean {\n\t\tif (isArray(path)) return path.some((one) => this.#files.has(one))\n\t\treturn this.#files.has(path)\n\t}\n\n\tsearch(query: string, options?: SearchOptions): readonly SearchMatch[] {\n\t\tconst pattern = this.#pattern(query, options)\n\t\tconst limit = options?.limit\n\t\tconst matches: SearchMatch[] = []\n\t\tfor (const file of this.#files.values()) {\n\t\t\tif (limit !== undefined && matches.length >= limit) break\n\t\t\t// Binary files have no lines to scan — they contribute zero matches.\n\t\t\tif (!isText(file.content)) continue\n\t\t\tconst lines = file.content.text.split('\\n')\n\t\t\tfor (let index = 0; index < lines.length; index += 1) {\n\t\t\t\tif (limit !== undefined && matches.length >= limit) break\n\t\t\t\tconst lineText = lines[index] ?? ''\n\t\t\t\tpattern.lastIndex = 0\n\t\t\t\tlet hit = pattern.exec(lineText)\n\t\t\t\twhile (hit !== null) {\n\t\t\t\t\tif (limit !== undefined && matches.length >= limit) break\n\t\t\t\t\tmatches.push({\n\t\t\t\t\t\tpath: file.path,\n\t\t\t\t\t\tline: index + 1,\n\t\t\t\t\t\tcolumn: hit.index + 1,\n\t\t\t\t\t\tlength: hit[0].length,\n\t\t\t\t\t\tcontent: lineText,\n\t\t\t\t\t})\n\t\t\t\t\t// A zero-width match would loop forever at the same index — step past it.\n\t\t\t\t\tif (hit[0].length === 0) pattern.lastIndex += 1\n\t\t\t\t\thit = pattern.exec(lineText)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn matches\n\t}\n\n\treplace(query: string, replacement: string, options?: ReplaceOptions): ReplaceResult {\n\t\tconst pattern = this.#pattern(query, options)\n\t\tconst limit = options?.limit\n\t\tlet replaced = 0\n\t\tlet files = 0\n\t\tfor (const [path, file] of this.#files) {\n\t\t\tif (limit !== undefined && replaced >= limit) break\n\t\t\tif (!isText(file.content)) continue\n\t\t\tconst remaining = limit === undefined ? undefined : limit - replaced\n\t\t\tlet count = 0\n\t\t\tpattern.lastIndex = 0\n\t\t\tconst next = file.content.text.replace(pattern, (match) => {\n\t\t\t\tif (remaining !== undefined && count >= remaining) return match\n\t\t\t\tcount += 1\n\t\t\t\treturn replacement\n\t\t\t})\n\t\t\tif (count > 0) {\n\t\t\t\treplaced += count\n\t\t\t\tfiles += 1\n\t\t\t\t// Route through the write mechanic so the state transition + `write` event fire.\n\t\t\t\tthis.write(path, next)\n\t\t\t}\n\t\t}\n\t\treturn { query, replaced, files }\n\t}\n\n\twrite(path: string, content: string): void\n\twrite(path: string, content: string, range: Range): void\n\twrite(files: Readonly<Record<string, string>>): void\n\twrite(path: string | Readonly<Record<string, string>>, content?: string, range?: Range): void {\n\t\tif (isRecord(path)) {\n\t\t\tfor (const [one, text] of Object.entries(path)) this.#write(one, text)\n\t\t\treturn\n\t\t}\n\t\tconst text = content ?? ''\n\t\tif (!range) {\n\t\t\tthis.#write(path, text)\n\t\t\treturn\n\t\t}\n\t\tthis.#splice(path, text, range)\n\t}\n\n\tprepend(path: string, content: string): void\n\tprepend(files: Readonly<Record<string, string>>): void\n\tprepend(path: string | Readonly<Record<string, string>>, content?: string): void {\n\t\tif (isRecord(path)) {\n\t\t\tfor (const [one, text] of Object.entries(path)) this.#prepend(one, text)\n\t\t\treturn\n\t\t}\n\t\tthis.#prepend(path, content ?? '')\n\t}\n\n\tappend(path: string, content: string): void\n\tappend(files: Readonly<Record<string, string>>): void\n\tappend(path: string | Readonly<Record<string, string>>, content?: string): void {\n\t\tif (isRecord(path)) {\n\t\t\tfor (const [one, text] of Object.entries(path)) this.#append(one, text)\n\t\t\treturn\n\t\t}\n\t\tthis.#append(path, content ?? '')\n\t}\n\n\tmove(from: string, to: string): boolean\n\tmove(mapping: Readonly<Record<string, string>>): boolean\n\tmove(from: string | Readonly<Record<string, string>>, to?: string): boolean {\n\t\tif (isRecord(from)) {\n\t\t\tlet moved = false\n\t\t\tfor (const [one, target] of Object.entries(from)) {\n\t\t\t\tif (this.#move(one, target)) moved = true\n\t\t\t}\n\t\t\treturn moved\n\t\t}\n\t\treturn this.#move(from, to ?? '')\n\t}\n\n\tremove(): void\n\tremove(path: string): boolean\n\tremove(paths: readonly string[]): boolean\n\tremove(path?: string | readonly string[]): boolean | void {\n\t\tif (path === undefined) {\n\t\t\t// `remove()` empties the registry — the single canonical \"emptied\" signal.\n\t\t\tthis.#files.clear()\n\t\t\tthis.#emitter.emit('clear')\n\t\t\treturn\n\t\t}\n\t\tif (isArray(path)) {\n\t\t\tlet removed = false\n\t\t\tfor (const one of path) {\n\t\t\t\tif (this.#remove(one)) removed = true\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#remove(path)\n\t}\n\n\tclear(): void {\n\t\tthis.#files.clear()\n\t\t// Observe the cleared registry — AFTER the map emptied (no payload — a pure signal).\n\t\tthis.#emitter.emit('clear')\n\t}\n\n\tsnapshot(): WorkspaceSnapshot {\n\t\t// The container serializes ITSELF: its id + a flat list of its (already-frozen, plain) Files.\n\t\t// A File carries its own `path`, so the flat list reconstructs the path-keyed map on hydrate\n\t\t// (the WorkspaceManager seeds a fresh Workspace from `snapshot.files`); pure JSON, mutates nothing.\n\t\treturn { id: this.#id, files: this.files() }\n\t}\n\n\t// Mint a whole-file replacement, store it by path, and emit `write` AFTER the mutation.\n\t// The state transitions to 'modified' over an existing path, else 'created'; a text\n\t// file's language is preserved, else inferred from the path. A string write onto a\n\t// binary path retypes it to text (a deliberate replacement).\n\t#write(path: string, content: string): void {\n\t\tconst existing = this.#files.get(path)\n\t\tconst language =\n\t\t\texisting && isText(existing.content) ? existing.content.language : inferLanguage(path)\n\t\tconst file = createFile({\n\t\t\tpath,\n\t\t\tcontent: { text: content, language },\n\t\t\tstate: existing ? 'modified' : 'created',\n\t\t})\n\t\tthis.#files.set(path, file)\n\t\tthis.#emitter.emit('write', file)\n\t}\n\n\t// Splice a Range of an existing text file. The path MUST exist and be text (else\n\t// MODALITY); the range must be structurally valid (else RANGE). Mints a 'modified'\n\t// replacement and emits `write` AFTER the mutation.\n\t#splice(path: string, content: string, range: Range): void {\n\t\tconst existing = this.#files.get(path)\n\t\tif (!existing || !isText(existing.content)) {\n\t\t\tthrow new WorkspaceError('MODALITY', `Cannot splice a range of a non-text file: ${path}`, {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t\tif (!isValidRange(range)) {\n\t\t\tthrow new WorkspaceError('RANGE', `Invalid range for file: ${path}`, { path, range })\n\t\t}\n\t\tconst file = createFile({\n\t\t\tpath,\n\t\t\tcontent: {\n\t\t\t\ttext: spliceRange(existing.content.text, range, content),\n\t\t\t\tlanguage: existing.content.language,\n\t\t\t},\n\t\t\tstate: 'modified',\n\t\t})\n\t\tthis.#files.set(path, file)\n\t\tthis.#emitter.emit('write', file)\n\t}\n\n\t// Prepend text, creating the file on an absent path (missing treated as empty). A\n\t// prepend onto a binary file is a text-only op (MODALITY). Routes through `#write` so\n\t// the state transition + single `write` event fire once.\n\t#prepend(path: string, content: string): void {\n\t\tthis.#write(path, content + this.#text(path, 'prepend'))\n\t}\n\n\t// Append text, creating the file on an absent path. A append onto a binary file is a\n\t// text-only op (MODALITY). Routes through `#write` (one state transition + event).\n\t#append(path: string, content: string): void {\n\t\tthis.#write(path, this.#text(path, 'append') + content)\n\t}\n\n\t// The existing text of a path for a text-edit (prepend / append) — '' when absent\n\t// (create-on-absent), throwing MODALITY when the path holds a binary file.\n\t#text(path: string, operation: string): string {\n\t\tconst existing = this.#files.get(path)\n\t\tif (!existing) return ''\n\t\tif (!isText(existing.content)) {\n\t\t\tthrow new WorkspaceError('MODALITY', `Cannot ${operation} text to a binary file: ${path}`, {\n\t\t\t\tpath,\n\t\t\t})\n\t\t}\n\t\treturn existing.content.text\n\t}\n\n\t// Re-key one file: absent `from` → false. Else mint a re-keyed 'modified' replacement\n\t// (the path is identity), delete `from`, set `to` (OVERWRITING an occupied target —\n\t// last write wins), and emit `move` AFTER the mutation.\n\t#move(from: string, to: string): boolean {\n\t\tconst file = this.#files.get(from)\n\t\tif (!file) return false\n\t\tconst moved = createFile({ path: to, content: file.content, state: 'modified' })\n\t\tthis.#files.delete(from)\n\t\tthis.#files.set(to, moved)\n\t\tthis.#emitter.emit('move', { from, to })\n\t\treturn true\n\t}\n\n\t// Delete one file, emitting `remove` only when one was actually dropped — AFTER the\n\t// deletion (an in-memory drop, no tombstone).\n\t#remove(path: string): boolean {\n\t\tconst removed = this.#files.delete(path)\n\t\tif (removed) this.#emitter.emit('remove', path)\n\t\treturn removed\n\t}\n\n\t// Build the search / replace RegExp from the query + options: a literal substring\n\t// (escaped) unless `regex`, case-insensitive unless `exact`, always global so every\n\t// occurrence on a line is found. An invalid user pattern is the PATTERN throw.\n\t#pattern(query: string, options?: SearchOptions | ReplaceOptions): RegExp {\n\t\tconst source = options?.regex === true ? query : escapeRegExp(query)\n\t\tconst flags = options?.exact === false ? 'gi' : 'g'\n\t\ttry {\n\t\t\treturn new RegExp(source, flags)\n\t\t} catch {\n\t\t\tthrow new WorkspaceError('PATTERN', `Invalid search pattern: ${query}`, { query })\n\t\t}\n\t}\n}\n","import type { EmitterErrorHandler, EmitterHooks } from '@orkestrel/emitter'\nimport type {\n\tWorkspaceEventMap,\n\tWorkspaceInput,\n\tWorkspaceInterface,\n\tWorkspaceManagerInterface,\n\tWorkspaceManagerOptions,\n\tWorkspaceStoreInterface,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { Workspace } from './Workspace.js'\n\n/**\n * The registry of {@link Workspace}s keyed by `id`, in insertion order, WITH an active pointer\n * — the §9 store over the workspace layer PLUS the `active` / `switch` seam the context renders.\n * Event-free (a registry, like {@link ConversationManager}); the observability lives on each\n * {@link Workspace}.\n *\n * @remarks\n * - **Registry.** Workspaces live in an insertion-ordered `Map` keyed by `id`. `add(input?)`\n * mints a {@link Workspace} (its `id` from `input` or `crypto.randomUUID()`), flowing the\n * manager's default `on` / `error` in unless the `input` OVERRIDES them, and stores it (an\n * already-present `id` OVERWRITES — last write wins). `count` is the map size, `workspace(id)`\n * looks one up, `workspaces()` lists them in insertion order.\n * - **Active pointer.** `active` is the active workspace (what the context renders), `undefined`\n * until the FIRST `add` (which auto-activates it — a registry with workspaces always has one\n * active). A subsequent `add` leaves `active` unchanged. `switch(id)` re-points `active` to the\n * workspace with `id` and returns it; an unknown `id` returns `undefined` and leaves `active`\n * unchanged (the lenient lookup style — never throws, no new error code).\n * - **Removal.** `remove` drops one by id, or a batch (§9.2) — `true` when any was removed;\n * removing the ACTIVE workspace sets `active` to `undefined`. `clear` empties the registry and\n * sets `active` to `undefined`.\n * - **Durable open / save (the optional `store`).** With a {@link WorkspaceStoreInterface} supplied\n * (the `store` option), `open(id)` HYDRATES a workspace on a registry miss — it `store.get(id)`s\n * the snapshot and rebuilds a fresh {@link Workspace} through the constructor `seed`\n * (`snapshot.files` → path → File), then activates it — and `save(id)` PERSISTS a registered\n * workspace's `snapshot()`. Both are LENIENT without a store (open resolves only registered ids,\n * save is a no-op `false`), consistent with the lenient `switch`.\n * - **Event-free.** A purely registry store — no Emitter, no events (each workspace owns its own\n * observable `emitter`).\n *\n * @example\n * ```ts\n * const manager = new WorkspaceManager()\n * const first = manager.add() // auto-activates — active === first\n * manager.add({ id: 'scratch' }) // leaves active unchanged\n * manager.switch('scratch') // re-points active to the 'scratch' workspace\n * manager.count // 2\n * ```\n */\nexport class WorkspaceManager implements WorkspaceManagerInterface {\n\treadonly #workspaces = new Map<string, WorkspaceInterface>()\n\t// The active workspace's id — what the context renders; `undefined` until the first `add`\n\t// auto-activates one (kept as an id, never a stale reference, so a re-add / removal of that id\n\t// is reflected through the live map lookup in `active`).\n\t#active: string | undefined\n\t// The default event listeners flowed into every workspace `add` creates (a per-`add` override\n\t// wins).\n\treadonly #on: EmitterHooks<WorkspaceEventMap> | undefined\n\t// The default listener-error handler flowed into every workspace `add` creates (overridable).\n\treadonly #error: EmitterErrorHandler | undefined\n\t// The optional durable store backing `open` / `save`; `undefined` ⇒ registry-only (both lenient).\n\treadonly #store: WorkspaceStoreInterface | undefined\n\n\tconstructor(options?: WorkspaceManagerOptions) {\n\t\tthis.#on = options?.on\n\t\tthis.#error = options?.error\n\t\tthis.#store = options?.store\n\t}\n\n\tget count(): number {\n\t\treturn this.#workspaces.size\n\t}\n\n\tget active(): WorkspaceInterface | undefined {\n\t\treturn this.#active === undefined ? undefined : this.#workspaces.get(this.#active)\n\t}\n\n\tworkspace(id: string): WorkspaceInterface | undefined {\n\t\treturn this.#workspaces.get(id)\n\t}\n\n\tworkspaces(): readonly WorkspaceInterface[] {\n\t\treturn [...this.#workspaces.values()]\n\t}\n\n\tadd(input?: WorkspaceInput): WorkspaceInterface {\n\t\t// The manager's defaults flow in unless the input overrides them — so a workspace created\n\t\t// through the manager inherits its `on` / `error` by default.\n\t\tconst workspace = new Workspace(\n\t\t\t{\n\t\t\t\t...(input?.id === undefined ? {} : { id: input.id }),\n\t\t\t\ton: input?.on ?? this.#on,\n\t\t\t\terror: input?.error ?? this.#error,\n\t\t\t},\n\t\t\tinput?.seed,\n\t\t)\n\t\tthis.#workspaces.set(workspace.id, workspace)\n\t\t// First workspace auto-activates: a registry that holds workspaces always has one active.\n\t\tif (this.#active === undefined) this.#active = workspace.id\n\t\treturn workspace\n\t}\n\n\tswitch(id: string): WorkspaceInterface | undefined {\n\t\t// Lenient (mirrors `workspace(id)`): an unknown id re-points nothing and returns undefined.\n\t\tconst workspace = this.#workspaces.get(id)\n\t\tif (workspace === undefined) return undefined\n\t\tthis.#active = id\n\t\treturn workspace\n\t}\n\n\tasync open(id: string): Promise<WorkspaceInterface | undefined> {\n\t\t// Already registered ⇒ just activate it (no store hit) — the registry is the live source.\n\t\tconst existing = this.#workspaces.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`/`workspace`).\n\t\tif (this.#store === undefined) return undefined\n\t\t// Store hit ⇒ rehydrate through the constructor `seed` (snapshot.files → path → File) by\n\t\t// reusing `add`, which registers + auto-activates a fresh Workspace; a miss ⇒ undefined.\n\t\tconst snapshot = await this.#store.get(id)\n\t\tif (snapshot === undefined) return undefined\n\t\tconst workspace = this.add({ id, seed: snapshot.files.map((file) => [file.path, file]) })\n\t\t// Re-point `active` explicitly: `add` only auto-activates the FIRST workspace, so an open into\n\t\t// a non-empty registry must still make the rehydrated one active.\n\t\tthis.#active = workspace.id\n\t\treturn workspace\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 workspace = this.#workspaces.get(id)\n\t\tif (this.#store === undefined || workspace === undefined) return false\n\t\tawait this.#store.set(workspace.snapshot())\n\t\treturn true\n\t}\n\n\t// §9.2: the array overload 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\tlet removed = false\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (this.#drop(id)) removed = true\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.#workspaces.clear()\n\t\t// An emptied registry has no active workspace.\n\t\tthis.#active = undefined\n\t}\n\n\t// Delete one workspace by id; when it was the ACTIVE one, clear the active pointer (a removed\n\t// workspace can never stay active).\n\t#drop(id: string): boolean {\n\t\tconst removed = this.#workspaces.delete(id)\n\t\tif (removed && this.#active === id) this.#active = undefined\n\t\treturn removed\n\t}\n}\n","import type {\n\tAgentContextInterface,\n\tAgentContextOptions,\n\tContextFormatInterface,\n\tContextSectionFormat,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tFileInterface,\n\tInstructionManagerInterface,\n\tMessageInterface,\n\tMessageManagerInterface,\n\tScopeInterface,\n\tToolManagerInterface,\n\tWorkspaceManagerInterface,\n} from './types.js'\nimport { WORKSPACE_SECTION_HEADER } from './constants.js'\nimport { ConversationManager } from './conversations/ConversationManager.js'\nimport { fencedFile, filterAllowList, isBinary, isImage, isText } from './helpers.js'\nimport { InstructionManager } from './instructions/InstructionManager.js'\nimport { ToolManager } from './tools/ToolManager.js'\nimport { WorkspaceManager } from './workspaces/WorkspaceManager.js'\n\n/**\n * The richer turn context the agent loop assembles a provider request from — the optional\n * system prompt, the observable context managers (instructions / workspaces), the\n * {@link ConversationManagerInterface} message source (whose active conversation IS `messages`),\n * the {@link ToolManagerInterface} registry, and a mutable active {@link ScopeInterface}.\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 below). `scope` is the active filter —\n * `undefined` (the default) ⇒ no filtering; settable afterwards. `workspaces` / `conversations`\n * are likewise SETTABLE (swap the whole registry between runs).\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 * via 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 via 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 * format) 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' `data` 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 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 `data` 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 * via `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 §13 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), and SETTABLE (the `workspaces` setter) — swap the whole\n\t// registry between runs; `build()` reads `active` / its `files()` fresh each call. Mutable\n\t// (not `readonly`) because the setter reassigns it, mirroring `#conversations` / `#scope`.\n\t#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 + SETTABLE (the `conversations`\n\t// setter) — swap the whole registry between runs; switch the active conversation through\n\t// `conversations.switch(id)`. Mutable (not `readonly`) because the setter reassigns it, mirroring\n\t// `#workspaces` / `#scope`.\n\t#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// SWAP the whole workspace registry (mirroring the settable `conversation` / `scope`): assigning\n\t// redirects `build()`'s active-workspace render at the new registry's `active` (read fresh each\n\t// call, so a later `switch` / `add` on it reflects through). The active workspace is the SOLE\n\t// document/image context.\n\tset workspaces(value: WorkspaceManagerInterface) {\n\t\tthis.#workspaces = value\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 (and the `conversations`\n\t// setter) ENSURE the registry has an active conversation. Computed on every read (never captured),\n\t// so `context.messages` ALWAYS points at the CURRENT active conversation (the SAME reference — no\n\t// duplication) and FOLLOWS a `conversations.switch(id)` or a `conversations` swap. The active\n\t// `Conversation` satisfies the message-verb contract directly, so this stays a\n\t// `MessageManagerInterface`. The `?? this.#ensure()` fallback re-seats a default if a caller's\n\t// supplied manager was somehow emptied (e.g. `clear()`), so the getter is 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\t// SWAP the whole conversation registry (mirroring the settable `workspaces` / `scope`): assigning\n\t// redirects the dynamic `messages` getter + `build()` at the NEW registry's ACTIVE conversation\n\t// (switch the active one through `value.switch(id)`). ENSURE the new registry has an active\n\t// conversation so `messages` stays defined. This is the multi-conversation mechanism — one agent\n\t// serving many threads. Swap / switch BETWEEN runs, NOT during a run (the loop reads\n\t// `context.conversations` / `context.messages` fresh each run); for CONCURRENT threads use separate\n\t// agents — the framework ships the mechanism, the app owns concurrency policy.\n\tset conversations(value: ConversationManagerInterface) {\n\t\tthis.#conversations = value\n\t\tif (this.#conversations.active === undefined) this.#conversations.add()\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\tset scope(value: ScopeInterface | undefined) {\n\t\tthis.#scope = value\n\t}\n\n\tbuild(format?: ContextFormatInterface): readonly MessageInterface[] {\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 (`#header` /\n\t\t// `#render` / `#footer`): 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 format 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\tthis.#section(\n\t\t\tparts,\n\t\t\tthis.#header(this.#instructions, format?.instructions),\n\t\t\tinstructions,\n\t\t\t(one) => this.#render(this.#instructions, format?.instructions, one),\n\t\t\tthis.#footer(this.#instructions, format?.instructions),\n\t\t)\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 `fencedFile` framing — placed\n\t\t// right after the instructions section, grouping the in-prompt text content), IMAGE files'\n\t\t// base64 `data` attaches to the last user message (collected below, fed to `#attach`).\n\t\t// `build()` OWNS this render — a `Workspace` / `WorkspaceManager` stays file-focused (no\n\t\t// `description` / `framing` getters). No active workspace ⇒ nothing renders (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 via `fencedFile`\n\t\t// off its own text arm (`{ text, language }`). An empty set contributes nothing (`#section`).\n\t\tthis.#section(\n\t\t\tparts,\n\t\t\tWORKSPACE_SECTION_HEADER,\n\t\t\tworkspaceTexts,\n\t\t\t(file) => this.#fenced(file),\n\t\t\tundefined,\n\t\t)\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 via compaction, so the\n\t\t// scope does NOT filter the conversation here (scope filters only instructions / tools /\n\t\t// workspace files, above). The active conversation is ALWAYS present (the constructor / setter\n\t\t// ensure 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 `data` 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 = this.#attach(conversation, this.#workspaceImages(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: MessageInterface = {\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// Append a section to the system parts — the resolved `open` (the leading text),\n\t// then each (already scope-filtered) item's resolved rendering, then the resolved\n\t// `close` (the trailing text) WHEN one resolved, all blank-line joined. A section with\n\t// no items contributes nothing (so an empty / fully scoped-out manager is silent — the\n\t// `open` / `close` never appear without items). `close` is the only optional slot:\n\t// `open` is always the resolved header string, and an unset `close` (no built-in) drops\n\t// the trailing line, keeping the no-arg default byte-for-byte the prior output.\n\t#section<T>(\n\t\tparts: string[],\n\t\topen: string,\n\t\titems: readonly T[],\n\t\tformat: (item: T) => string,\n\t\tclose: string | undefined,\n\t): void {\n\t\tif (items.length === 0) return\n\t\tconst lines = [open, ...items.map(format)]\n\t\tif (close !== undefined) lines.push(close)\n\t\tparts.push(lines.join('\\n\\n'))\n\t}\n\n\t// Resolve ONE section's OPEN (its leading text — the header or a group's opening tag)\n\t// per the cascade — manager-options override > provider default > built-in. The\n\t// manager's `framing` is the raw options override; its `description` already\n\t// encapsulates `[options-override → built-in]`, so the trailing `?? manager.description`\n\t// is reached ONLY when neither the override's `open` nor the provider's `open` applies —\n\t// and there it equals the built-in header (the leading text has no per-item level). With\n\t// no provider `format` and no override it is the built-in.\n\t#header<T>(\n\t\tmanager: {\n\t\t\treadonly description: string\n\t\t\treadonly framing: ContextSectionFormat<T> | undefined\n\t\t},\n\t\tprovider: ContextSectionFormat<T> | undefined,\n\t): string {\n\t\treturn manager.framing?.open ?? provider?.open ?? manager.description\n\t}\n\n\t// Resolve ONE section's CLOSE (its trailing text — a group's closing tag) per the\n\t// cascade — manager-options override > provider default. There is NO built-in close, so\n\t// when neither level sets one this returns `undefined` and `#section` appends no closing\n\t// line (the no-arg default stays byte-for-byte the prior built-in output). Paired with\n\t// `#header`'s `open`, a level can WRAP the group (`open: '<docs>'` … `close: '</docs>'`).\n\t#footer<T>(\n\t\tmanager: { readonly framing: ContextSectionFormat<T> | undefined },\n\t\tprovider: ContextSectionFormat<T> | undefined,\n\t): string | undefined {\n\t\treturn manager.framing?.close ?? provider?.close\n\t}\n\n\t// Resolve ONE item's RENDERING per the cascade — item override > manager-options override\n\t// > provider default > built-in. `item.format` is the most-specific per-item override;\n\t// the manager's `framing` is the raw options override; its `format(item)` already\n\t// encapsulates `[options-override → built-in]`, so the trailing `?? manager.format(item)`\n\t// is reached ONLY when no higher level applies — and there it equals the built-in\n\t// rendering. With no item format, no provider `format`, and no override it is the built-in.\n\t#render<T extends { readonly format?: string }>(\n\t\tmanager: {\n\t\t\treadonly framing: ContextSectionFormat<T> | undefined\n\t\t\tformat(item: T): string\n\t\t},\n\t\tprovider: ContextSectionFormat<T> | undefined,\n\t\titem: T,\n\t): string {\n\t\treturn (\n\t\t\titem.format ??\n\t\t\tmanager.framing?.render?.(item) ??\n\t\t\tprovider?.render?.(item) ??\n\t\t\tmanager.format(item)\n\t\t)\n\t}\n\n\t// Attach image data to the last user message — returns a NEW array with that one\n\t// message replaced by a copy carrying the merged `images` (its own first, then the\n\t// attached data), never mutating the stored message. No data ⇒ the conversation is\n\t// returned unchanged; no user message ⇒ the attachment is skipped (the conversation is\n\t// returned unchanged — the image text markers already rode the system block).\n\t#attach(\n\t\tconversation: readonly MessageInterface[],\n\t\tdata: readonly string[],\n\t): readonly MessageInterface[] {\n\t\tif (data.length === 0) return conversation\n\t\tlet target = -1\n\t\tfor (let index = conversation.length - 1; index >= 0; index -= 1) {\n\t\t\tif (conversation[index]?.role === 'user') {\n\t\t\t\ttarget = index\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (target === -1) return conversation\n\t\treturn conversation.map((message, index) =>\n\t\t\tindex === target ? this.#withImages(message, data) : message,\n\t\t)\n\t}\n\n\t// A copy of a message carrying the merged image data on `images` (its existing images\n\t// first, then the attached data) — `calls` is carried only when present (kept omitted\n\t// otherwise, mirroring the store's present-when-given convention), never mutating the\n\t// original.\n\t#withImages(message: MessageInterface, data: readonly string[]): MessageInterface {\n\t\tconst images = [...(message.images ?? []), ...data]\n\t\treturn message.calls === undefined\n\t\t\t? { id: message.id, role: message.role, content: message.content, images }\n\t\t\t: {\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\tcalls: message.calls,\n\t\t\t\t\timages,\n\t\t\t\t}\n\t}\n\n\t// Render one ACTIVE-workspace TEXT file as a fenced reference block — the `fencedFile` framing,\n\t// off the file's OWN text arm (`{ text, language }`), narrowed via `isText` (§14: narrow, never\n\t// assert). A non-text file (never passed here — the caller pre-filters by `isText`) renders its\n\t// `path` with no body, a defensive total fallback.\n\t#fenced(file: FileInterface): string {\n\t\tif (isText(file.content)) return fencedFile(file.path, file.content.language, file.content.text)\n\t\treturn fencedFile(file.path, 'text', '')\n\t}\n\n\t// The base64 `data` of the ACTIVE-workspace IMAGE files (already scope-filtered) — collected for\n\t// the last-user-message attach (the active workspace is the SOLE image source). `isBinary` NARROWS\n\t// the tagless content to the binary arm (`{ data, mime }`, §14: narrow, never assert) and `isImage`\n\t// gates it to an `image/*` MIME; a text / non-image file is skipped. A future non-image binary (a\n\t// PDF) is excluded here.\n\t#workspaceImages(files: readonly FileInterface[]): readonly string[] {\n\t\tconst data: string[] = []\n\t\tfor (const file of files) {\n\t\t\tif (isBinary(file.content) && isImage(file.content)) data.push(file.content.data)\n\t\t}\n\t\treturn data\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 (e.g. `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// + the `conversations` setter already seed 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","/**\n * A minimal unbounded async channel — the eager pump WRITES chunks into it (`push`)\n * and ends it (`close` / `fail`) regardless of consumption; a consumer READS them back\n * live via the `drain` async-iterator. Decoupling write from read is what lets a\n * producer make progress without a consumer pulling.\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 */\nexport class Channel<T> {\n\treadonly #buffer: 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\twhile (this.#buffer.length > 0) {\n\t\t\t\tconst next = this.#buffer.shift()\n\t\t\t\tif (next !== undefined) yield next\n\t\t\t}\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\tCompactionState,\n\tMessageInterface,\n\tProviderInterface,\n\tProviderResult,\n\tRunOutcome,\n\tToolCall,\n\tToolManagerInterface,\n\tToolResult,\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 { DeferredInterface, SchedulerInterface } from '@orkestrel/workflow'\nimport type { TimeoutInterface } from '@orkestrel/timeout'\nimport { createAbort } from '@orkestrel/abort'\nimport { createTimeout } from '@orkestrel/timeout'\nimport { createDeferred } from '@orkestrel/workflow'\nimport { Emitter } from '@orkestrel/emitter'\nimport { AgentContext } from './AgentContext.js'\nimport { Channel } from './Channel.js'\nimport { DEFAULT_AGENT_LIMIT } from './constants.js'\nimport { isProviderAbortError } from './errors.js'\nimport { filterAllowList } from './helpers.js'\n\n/**\n * The agent loop — composes a {@link ProviderInterface}, an {@link AgentContext}, and\n * a {@link ToolManagerInterface} into a bounded context → provider → tools → repeat\n * turn, exposed as both a one-shot `generate` and a live `stream`.\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` simply 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 via `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 #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 (§ auto-compact) — its `consume`\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 MessageInterface[]> | undefined\n\t// The PUSH observation surface (§13) — 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\treadonly id: string = crypto.randomUUID()\n\t#status: 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 just 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.#provider = provider\n\t\tthis.#context = new AgentContext({\n\t\t\tsystem: options?.system,\n\t\t\ttools: options?.tools,\n\t\t\tconversations: 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.#emitter = new Emitter<AgentEventMap>({ on: options?.on, error: options?.error })\n\t}\n\n\tget emitter(): EmitterInterface<AgentEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget status(): AgentStatus {\n\t\treturn this.#status\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\tconst timeout =\n\t\t\tthis.#timeoutMs === undefined ? undefined : createTimeout({ ms: this.#timeoutMs })\n\t\ttimeout?.start()\n\t\tthis.#budget?.start()\n\t\t// Fold every present bound (external signal + deadline + budget) into one cancel\n\t\t// the run races against; this run's own `abort()` fires this handle.\n\t\tconst abort = createAbort({ signal: this.#parents(timeout) })\n\t\tthis.#runs.add(abort)\n\t\tthis.#status = 'running'\n\t\t// Observe the run begin — AFTER the `running` transition, so a swallowed listener\n\t\t// throw can't perturb the state the pump is about to drive.\n\t\tthis.#emitter.emit('start', this.id)\n\t\tconst outcome: RunOutcome = {\n\t\t\tcontent: '',\n\t\t\tthinking: undefined,\n\t\t\tusage: undefined,\n\t\t\tpartial: false,\n\t\t}\n\t\tconst channel = new Channel<AgentChunk>()\n\t\tconst settled: DeferredInterface<AgentResult> = createDeferred<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` preference rides through to `provider.stream`.\n\t\tvoid this.#pump(abort, outcome, timeout, channel, settled, options?.think)\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: (reason) => {\n\t\t\t\tabort.abort(reason)\n\t\t\t},\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 iterates `#run` and `push`es each chunk into the\n\t// channel as it arrives, then settles `result` from the outcome: a normal / cancelled\n\t// finish `close`s the channel and RESOLVES the assembled result (status `done`); a\n\t// genuine provider / tool error (the bound signal NOT aborted) `fail`s the channel and\n\t// REJECTS (status `error`). Because the pump runs regardless of whether anyone drains\n\t// `events`, `result` ALWAYS settles — that is the fix for the no-drain hang. The\n\t// deadline `clear()` lives in the `finally` so it ALWAYS fires (drained or not), and\n\t// `result` settles EXACTLY ONCE via the shared `DeferredInterface` handle (its\n\t// underlying promise obeys native settle-once — the first resolve / reject wins).\n\tasync #pump(\n\t\tabort: AbortInterface,\n\t\toutcome: RunOutcome,\n\t\ttimeout: TimeoutInterface | undefined,\n\t\tchannel: Channel<AgentChunk>,\n\t\tsettled: DeferredInterface<AgentResult>,\n\t\tthink: boolean | undefined,\n\t): Promise<void> {\n\t\tlet failure: { error: unknown } | undefined\n\t\ttry {\n\t\t\tfor await (const chunk of this.#run(abort, outcome, think)) channel.push(chunk)\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.#status = 'done'\n\t\t\t\tchannel.close()\n\t\t\t\tconst result = this.#result(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. 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.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.#status = '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.\n\tasync *#run(\n\t\tabort: AbortInterface,\n\t\toutcome: RunOutcome,\n\t\tthink: boolean | undefined,\n\t): AsyncGenerator<AgentChunk, void> {\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: MessageInterface[] = [...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// PER-RUN auto-compaction state — created FRESH each run (never carried across runs or a\n\t\t// conversation switch). `futile` is the single-level guard (clause 26): once a `compact()`\n\t\t// returns `undefined` while still over the window, the prompt can't shrink further, so\n\t\t// auto-compaction STOPS for the rest of THIS run (no per-turn churn).\n\t\tconst compaction: CompactionState = { 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 now 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: `latchFutile: 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) await this.#trim(messages, compaction, false)\n\t\t}\n\t\tfor (let turn = 0; turn < this.#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 below. 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\toutcome.partial = 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\toutcome.partial = 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\tlet result: ProviderResult\n\t\t\ttry {\n\t\t\t\tresult = yield* this.#provide(messages, abort.signal, definitions, think, (delta) => {\n\t\t\t\t\tcontent += delta\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// via `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) && error.partial.thinking !== undefined) {\n\t\t\t\t\t\tthinking = this.#thought(thinking, error.partial.thinking)\n\t\t\t\t\t}\n\t\t\t\t\toutcome.partial = 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 = this.#thought(thinking, result.thinking)\n\t\t\t}\n\t\t\tif (result.usage !== undefined) {\n\t\t\t\tthis.#budget?.consume(result.usage)\n\t\t\t\tusage = this.#sum(usage, result.usage)\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', result.usage)\n\t\t\t\tyield { type: 'usage', usage: result.usage }\n\t\t\t}\n\t\t\tif (result.tools !== undefined && result.tools.length > 0) {\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.#authorize(tools, result.tools)\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 { type: '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: JSON.stringify(outcomeResult.value ?? 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 (§ auto-compact) — 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. `latchFutile: true` — by now the tail has accumulated this turn's\n\t\t\t\t// appends, so an `undefined` fold here is genuinely futile (clause 26).\n\t\t\t\tif (compacting) await this.#trim(messages, compaction, 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\tbreak\n\t\t}\n\t\toutcome.content = content\n\t\toutcome.thinking = thinking\n\t\toutcome.usage = usage\n\t}\n\n\t// AUTOMATIC compaction — the production-hardened context-budget check (§ auto-compact). 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 `consume` a token estimator (e.g. `estimateMessages`), its `max` the context window — the\n\t// SAME consume-to-a-ceiling primitive as the cost `budget`, but the ceiling action is COMPACT, 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 `compactError` 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 v1 single-level limit) — when a BETWEEN-TURNS `compact()` resolves\n\t// `undefined` (nothing left to fold) while the prompt is still over the window — i.e. 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). We do NOT loop futilely. `latchFutile` gates this: the BETWEEN-TURNS check\n\t// passes `true`; the PRE-FIRST-TURN check passes `false` — there an `undefined` fold just means\n\t// \"nothing to fold YET\" (the live tail hasn't accumulated this run's turns), NOT permanently\n\t// futile, so it skips without latching and the run's growing tail can still fold later. (A\n\t// `compact()` that DOES fold a section is never futile — the tail shrank; if the rebuilt prompt is\n\t// still over window the NEXT between-turns `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 (a future tier can thread it).\n\tasync #trim(\n\t\tmessages: MessageInterface[],\n\t\tcompaction: CompactionState,\n\t\tlatchFutile: boolean,\n\t): Promise<void> {\n\t\tconst conversation = this.#context.conversations.active\n\t\t// No window, a non-summarizable active conversation (the default one can't fold), or\n\t\t// already-futile this run ⇒ the additive no-op. (Both call sites are gated by `compacting`, so\n\t\t// here `conversation` is the active, summarizable one; this guard keeps `#trim` total.)\n\t\tif (this.#window === undefined || conversation?.summarizable !== true || compaction.futile) {\n\t\t\treturn\n\t\t}\n\t\tthis.#window.clear()\n\t\tthis.#window.consume(messages)\n\t\tif (!this.#window.exhausted) return\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// NON-FATAL: surface the summarizer failure observably, skip compaction this turn, continue.\n\t\t\tthis.#emitter.emit('compactError', error)\n\t\t\treturn\n\t\t}\n\t\tif (section === undefined) {\n\t\t\t// Nothing folded. On a BETWEEN-TURNS check (latchFutile) the tail had its chance to grow yet\n\t\t\t// still won't fold ⇒ genuinely FUTILE: latch so the run stops churning and the over-window\n\t\t\t// prompt reaches the provider. On the PRE-FIRST-TURN check (no latch) the tail is simply too\n\t\t\t// short YET ⇒ skip without latching, leaving later turns free to fold as the tail grows.\n\t\t\tif (latchFutile) compaction.futile = true\n\t\t\treturn\n\t\t}\n\t\t// REBUILD the working array from the (now smaller) compacted view via 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}\n\n\t// The tool-dispatch gate. With no authority this is byte-identical to the Ch5 path —\n\t// `tools.execute(calls)` straight through. With one set, each call is `evaluate`d:\n\t// ALLOWED calls run as a batch (skipped entirely when none are allowed, so a denial\n\t// costs no tool run / no budget); DENIED calls become a synthesized denial ToolResult\n\t// (never executed). The two are then MERGED back into the ORIGINAL `calls` order\n\t// (correlated by `id` via a Map), so the loop's per-call `tool` chunks + tool messages\n\t// stay in call order — a denied call still yields a `tool` chunk + a tool message\n\t// (carrying the denial error), so the model sees it and can react.\n\tasync #authorize(\n\t\ttools: ToolManagerInterface,\n\t\tcalls: readonly ToolCall[],\n\t): Promise<readonly ToolResult[]> {\n\t\tif (this.#authority === undefined) return tools.execute(calls)\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\tconst reason = this.#reason(error)\n\t\t\t\tdenials.set(call.id, this.#denial(call, reason))\n\t\t\t\t// Observe the fail-closed denial (the call + the thrown reason) — the denial is\n\t\t\t\t// already synthesized; the guarded emit can't perturb the dispatch that follows.\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, this.#denial(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\tconst executed = allowed.length > 0 ? await tools.execute(allowed) : []\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) ?? this.#denial(call, undefined))\n\t}\n\n\t// A denied call's synthesized ToolResult — the call's `id` / `name` keyed back (like\n\t// any ToolResult) carrying a denial `error` (the rule's `reason` when given, else a\n\t// generic message). No `value`, so the loop feeds it back exactly like a tool error.\n\t#denial(call: ToolCall, reason: string | undefined): ToolResult {\n\t\treturn {\n\t\t\tid: call.id,\n\t\t\tname: call.name,\n\t\t\terror: reason !== undefined ? `denied: ${reason}` : 'denied by authority',\n\t\t}\n\t}\n\n\t// The denial reason for a policy `evaluate` that THREW — an `Error`'s message, else the\n\t// stringified throw (the same extraction `ToolManager` uses for a thrown tool handler),\n\t// so a fail-closed denial carries a useful explanation the model can read.\n\t#reason(error: unknown): string {\n\t\treturn error instanceof Error ? error.message : String(error)\n\t}\n\n\t// Drive one provider stream turn: discriminate each {@link ProviderDelta} the provider\n\t// yields — a `'content'` delta is the answer (fed back via `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` preference rides into `provider.stream` as\n\t// {@link ProviderStreamOptions}. Kept separate so the loop reads as one straight line.\n\tasync *#provide(\n\t\tmessages: readonly MessageInterface[],\n\t\tsignal: AbortSignal,\n\t\tdefinitions: ReturnType<ToolManagerInterface['definitions']> | undefined,\n\t\tthink: boolean | undefined,\n\t\tonDelta: (delta: string) => void,\n\t): AsyncGenerator<AgentChunk, ProviderResult> {\n\t\tconst generator = this.#provider.stream(\n\t\t\tmessages,\n\t\t\tsignal,\n\t\t\tdefinitions,\n\t\t\tthink === undefined ? undefined : { think },\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.type === 'content') {\n\t\t\t\tonDelta(delta.text)\n\t\t\t\tyield { type: 'token', content: delta.text }\n\t\t\t} else {\n\t\t\t\tyield { type: '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, the deadline, and the\n\t// budget folded via AbortSignal.any — or a lone present one, or undefined when none.\n\t#parents(timeout: TimeoutInterface | undefined): AbortSignal | undefined {\n\t\tconst signals: AbortSignal[] = []\n\t\tif (this.#signal !== undefined) signals.push(this.#signal)\n\t\tif (timeout !== undefined) signals.push(timeout.signal)\n\t\tif (this.#budget !== undefined) signals.push(this.#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\t// Join the separated reasoning across a run's provider calls — the first call seeds\n\t// it; later calls append blank-line separated (each turn's reasoning stays readable).\n\t#thought(running: string | undefined, next: string): string {\n\t\treturn running === undefined ? next : `${running}\\n\\n${next}`\n\t}\n\n\t// Add two token usages field-by-field — the running total across a turn's provider\n\t// calls (the first call seeds it; later calls accumulate).\n\t#sum(running: TokenUsage | undefined, next: TokenUsage): TokenUsage {\n\t\tif (running === undefined) return next\n\t\treturn {\n\t\t\tprompt: running.prompt + next.prompt,\n\t\t\tcompletion: running.completion + next.completion,\n\t\t\ttotal: running.total + next.total,\n\t\t}\n\t}\n\n\t// Assemble the settled AgentResult from the run's outcome — `thinking` / `usage`\n\t// present only when a provider call surfaced / reported one.\n\t#result(outcome: RunOutcome): AgentResult {\n\t\tconst result: { content: string; thinking?: string; usage?: TokenUsage; partial: boolean } = {\n\t\t\tcontent: outcome.content,\n\t\t\tpartial: outcome.partial,\n\t\t}\n\t\tif (outcome.thinking !== undefined) result.thinking = outcome.thinking\n\t\tif (outcome.usage !== undefined) result.usage = outcome.usage\n\t\treturn result\n\t}\n}\n","import type {\n\tAgentInterface,\n\tAgentJobInput,\n\tAgentOptions,\n\tAgentRegistryInterface,\n\tAgentRegistryOptions,\n\tAuthorityInterface,\n\tProviderInterface,\n\tToolInterface,\n} from './types.js'\nimport type { BudgetInterface, TokenUsage } from '@orkestrel/budget'\nimport type { SchedulerInterface } from '@orkestrel/workflow'\nimport { createTokenBudget } from '@orkestrel/budget'\nimport { Agent } from './Agent.js'\nimport { ToolManager } from './tools/ToolManager.js'\n\n/**\n * The bridge that makes a durable, JSON-serializable {@link AgentJobInput} runnable —\n * it holds the named pools of live, non-serializable pieces (providers, tools,\n * authorities, schedulers) and rehydrates a seeded, signal-wired {@link Agent} from a\n * job's names + 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 (§9.1 + §12).** `provider` / `tool` / `authority` /\n * `scheduler` resolve a name against their pool and THROW `unknown <category>: <name>`\n * when it is absent — an unknown name in a rehydrated job is a programmer / config\n * error that must fail LOUDLY at build time, never silently resolve to `undefined` and\n * 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 `allowPartial` 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\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}\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.\n\t#options(input: AgentJobInput, signal: AbortSignal | undefined): AgentOptions {\n\t\treturn {\n\t\t\tsystem: input.system,\n\t\t\ttools: this.#manager(input.tools),\n\t\t\tlimit: input.limit,\n\t\t\ttimeout: input.timeout,\n\t\t\tbudget: this.#budget(input.budget),\n\t\t\tauthority: input.authority === undefined ? undefined : this.authority(input.authority),\n\t\t\tscheduler: input.scheduler === undefined ? undefined : this.scheduler(input.scheduler),\n\t\t\tsignal,\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 clear, loud error on a miss (§9.1 accessor\n\t// + §12 programmer-error throw) — an unknown name in a rehydrated job 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 Error(`unknown ${category}: ${name}`)\n\t\treturn value\n\t}\n}\n","import type {\n\tAuthorityContextInterface,\n\tAuthorityDecision,\n\tAuthorityInterface,\n\tAuthorityOptions,\n\tAuthorityRule,\n} from './types.js'\nimport { DEFAULT_AUTHORITY_ZONE } from './constants.js'\n\n/**\n * The synchronous policy gate the agent loop consults before each tool call runs —\n * it turns one {@link AuthorityContextInterface} into an {@link AuthorityDecision}.\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('./types.js').ToolCall} the model emits; a denied call is fed\n * back to the model as a denial {@link import('./types.js').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 now.** The async human-approval handshake (request / grant / deny) is\n * deferred to a later chunk; `evaluate` returns a 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: AuthorityContextInterface): AuthorityDecision {\n\t\tfor (const rule of this.#rules) {\n\t\t\tif (rule.match(context))\n\t\t\t\treturn { zone: rule.zone, allowed: rule.allowed ?? true, reason: rule.reason }\n\t\t}\n\t\treturn this.#fallback\n\t}\n}\n","import type {\n\tConversationSnapshot,\n\tConversationSnapshotRow,\n\tConversationStoreInterface,\n} from '../../types.js'\nimport type { TableInterface } from '@orkestrel/database'\nimport { isConversationSnapshot } from '../../helpers.js'\n\n/**\n * A {@link ConversationStoreInterface} backed by one table of the `databases` layer — a\n * conversation's durable state IS a row, so persistence reduces to keyed point-access (`get` / `set`\n * / `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`\n * {@link import('./MemoryConversationStore.js').MemoryConversationStore}. The EXACT twin of\n * {@link import('../../workspaces/stores/DatabaseWorkspaceStore.js').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('../../workspaces/stores/DatabaseWorkspaceStore.js').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('../../helpers.js').isConversationSnapshot} — the\n * AGENTS §14 boundary narrow 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 * §22 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 constructor `seed` (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createConversation, createDatabaseConversationStore, createMemoryDriver } from '@src/core'\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 * Wrap 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/** Resolve 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 boundary guard rather than a cast (AGENTS §14);\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/** Insert or replace 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/** Drop 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 * The in-memory {@link ConversationStoreInterface} — a process-lifetime `Map` of\n * {@link ConversationSnapshot}s keyed by conversation id, the DEFAULT store\n * {@link import('../../factories.js').createMemoryConversationStore} builds. The EXACT twin of\n * {@link import('../../workspaces/stores/MemoryWorkspaceStore.js').MemoryWorkspaceStore}.\n *\n * @remarks\n * A plain `Map<string, ConversationSnapshot>` (AGENTS §21 — the snapshot is already pure,\n * self-contained JSON, so no encoding is needed for the memory tier). Like the\n * {@link import('../../workspaces/stores/MemoryWorkspaceStore.js').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 §22 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 constructor `seed` (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createConversation, createMemoryConversationStore } from '@src/core'\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\tget(id: string): Promise<ConversationSnapshot | undefined> {\n\t\treturn Promise.resolve(this.#snapshots.get(id))\n\t}\n\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\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 { ScopeConfiguration, ScopeInput, ScopeInterface } from '../types.js'\n\n/**\n * A named, immutable filter over a richer context's items — three optional allow-lists,\n * one per category (`instructions` / `tools` / `files`), each keyed by that category's\n * identity (an instruction's `name`, a tool's `name`, a workspace file's `path`).\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 via `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[] | undefined\n\treadonly tools: readonly string[] | undefined\n\treadonly files: readonly string[] | undefined\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\tthis.instructions = input.instructions === undefined ? undefined : [...input.instructions]\n\t\tthis.tools = input.tools === undefined ? undefined : [...input.tools]\n\t\tthis.files = input.files === undefined ? undefined : [...input.files]\n\t}\n\n\tnarrow(config: ScopeConfiguration): 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\treturn new Scope({\n\t\t\tname: this.name,\n\t\t\tinstructions: Scope.#intersect(this.instructions, config.instructions),\n\t\t\ttools: Scope.#intersect(this.tools, config.tools),\n\t\t\tfiles: Scope.#intersect(this.files, config.files),\n\t\t})\n\t}\n\n\t// Intersect two category lists under the \"undefined = universal set (no constraint)\"\n\t// rule: undefined ∩ undefined = undefined; undefined ∩ list = a copy of the list (the\n\t// undefined side imposes nothing); list ∩ list = the child keys that are also in the\n\t// parent (so narrowing can only TIGHTEN — a parent-excluded key never returns).\n\tstatic #intersect(\n\t\tparent: readonly string[] | undefined,\n\t\tchild: readonly string[] | undefined,\n\t): readonly string[] | undefined {\n\t\tif (parent === undefined) return child === undefined ? undefined : [...child]\n\t\tif (child === undefined) return [...parent]\n\t\tconst allowed = new Set(parent)\n\t\treturn child.filter((key) => allowed.has(key))\n\t}\n}\n","import type { EmitterErrorHandler, EmitterHooks, EmitterInterface } from '@orkestrel/emitter'\nimport type {\n\tScopeInput,\n\tScopeInterface,\n\tScopeManagerEventMap,\n\tScopeManagerInterface,\n} from '../types.js'\nimport { isArray } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { Scope } from './Scope.js'\n\n/**\n * The scope registry a richer context reuses named filters from — immutable {@link Scope}s\n * keyed by their minted `id`, in insertion order.\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 (§9.2) — `true` when any was\n * removed; `clear` empties the registry.\n * - **Observable (§13).** 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 (§13) — 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(on?: EmitterHooks<ScopeManagerEventMap>, error?: EmitterErrorHandler) {\n\t\tthis.#emitter = new Emitter<ScopeManagerEventMap>({ on, error })\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\tlet removed = false\n\t\t\tfor (const id of ids) {\n\t\t\t\tif (this.#delete(id)) removed = true\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 * The stream-stateful `<think>` separator — feeds raw content deltas through a tiny\n * state machine that routes everything inside a `<think>…</think>` span to `thinking`\n * and returns everything outside it as clean content, so a provider yields ONLY the\n * answer and surfaces the reasoning as {@link import('./types.js').ProviderResult.thinking}.\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 just 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 just reset (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 { ToolInterface, ToolOptions } from '../types.js'\n\n/**\n * A registered tool — its {@link import('../types.js').ToolDefinition} schema (the\n * `name` / `description` / `parameters` the model sees) bound to the `execute`\n * handler that runs a call.\n *\n * @remarks\n * A thin value object: the constructor stores the schema fields and the handler, and\n * `execute` delegates to the handler verbatim. `parameters` is kept by reference (the\n * open JSON-Schema the provider forwards as-is) — not cloned. The handler's `args` is\n * the model-supplied `unknown` arguments record, narrowed inside the handler (§14);\n * isolating a throw is the {@link ToolManager}'s job, not this class's. Event-free —\n * no Emitter, no events.\n *\n * @example\n * ```ts\n * const tool = new Tool({\n * \tname: 'add',\n * \tdescription: 'Add two numbers',\n * \tparameters: { type: 'object', properties: { a: { type: 'number' }, b: { type: 'number' } } },\n * \texecute: (args) => Number(args.a) + Number(args.b),\n * })\n * ```\n */\nexport class Tool implements ToolInterface {\n\treadonly name: string\n\treadonly description?: string\n\treadonly parameters?: Readonly<Record<string, unknown>>\n\treadonly #execute: (args: Readonly<Record<string, unknown>>) => Promise<unknown> | unknown\n\n\tconstructor(options: ToolOptions) {\n\t\tthis.name = options.name\n\t\tthis.description = options.description\n\t\tthis.parameters = options.parameters\n\t\tthis.#execute = options.execute\n\t}\n\n\texecute(args: Readonly<Record<string, unknown>>): Promise<unknown> | unknown {\n\t\treturn this.#execute(args)\n\t}\n}\n","import type {\n\tWorkspaceSnapshot,\n\tWorkspaceSnapshotRow,\n\tWorkspaceStoreInterface,\n} from '../../types.js'\nimport type { TableInterface } from '@orkestrel/database'\nimport { isWorkspaceSnapshot } from '../../helpers.js'\n\n/**\n * A {@link WorkspaceStoreInterface} backed by one table of the `databases` layer — a workspace's\n * durable state IS a row, so persistence reduces to keyed point-access (`get` / `set` / `delete`)\n * over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`\n * {@link import('./MemoryWorkspaceStore.js').MemoryWorkspaceStore}.\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('../WorkspaceManager.js').WorkspaceManager} or the\n * {@link import('../Workspace.js').Workspace} — the same seam as\n * the analogous `DatabaseWorkflowStore` in `@orkestrel/workflow`. The\n * driver defaults to memory ({@link import('../../factories.js').createDatabaseWorkspaceStore}\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 WorkspaceSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of\n * `{ id; snapshot }` ({@link WorkspaceSnapshotRow}), the snapshot the whole JSON blob (a `rawShape`\n * column the factory builds) — exactly as `DatabaseWorkflowStore` stores its snapshot. The snapshot\n * is already a COMPLETE, self-contained, pure-JSON payload, so storing it whole is lossless AND\n * 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 WorkspaceSnapshot} ({@link import('../../helpers.js').isWorkspaceSnapshot} — the AGENTS\n * §14 boundary narrow 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 workspace lives until an\n * explicit `delete`. The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the\n * §22 method bijection with {@link WorkspaceStoreInterface}). Hydration stays a caller concern: a\n * {@link import('../WorkspaceManager.js').WorkspaceManager} reads a snapshot back and rebuilds the\n * live workspace through the constructor `seed` (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createDatabaseWorkspaceStore, createMemoryDriver, createWorkspace } from '@src/core'\n *\n * const store = createDatabaseWorkspaceStore(createMemoryDriver()) // a durable driver swaps in here\n * const workspace = createWorkspace()\n * workspace.write('notes.txt', 'hello')\n * await store.set(workspace.snapshot()) // persist the workspace (one JSON column)\n * const snapshot = await store.get(workspace.id)\n * await store.delete(workspace.id) // drop it\n * ```\n */\nexport class DatabaseWorkspaceStore implements WorkspaceStoreInterface {\n\treadonly #table: TableInterface<WorkspaceSnapshotRow>\n\n\t/**\n\t * Wrap a table as a workspace store.\n\t *\n\t * @param table - The {@link TableInterface} holding the snapshots — its row is the\n\t * {@link WorkspaceSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)\n\t */\n\tconstructor(table: TableInterface<WorkspaceSnapshotRow>) {\n\t\tthis.#table = table\n\t}\n\n\t/** Resolve the persisted snapshot for `id`, narrowing the opaque JSON column back to a `WorkspaceSnapshot`. */\n\tasync get(id: string): Promise<WorkspaceSnapshot | 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 boundary guard rather than a cast (AGENTS §14);\n\t\t// a malformed blob resolves `undefined`, never a broken workspace.\n\t\treturn isWorkspaceSnapshot(row.snapshot) ? row.snapshot : undefined\n\t}\n\n\t/** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */\n\tasync set(snapshot: WorkspaceSnapshot): Promise<void> {\n\t\tawait this.#table.set({ id: snapshot.id, snapshot })\n\t}\n\n\t/** Drop 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 { WorkspaceSnapshot, WorkspaceStoreInterface } from '../../types.js'\n\n/**\n * The in-memory {@link WorkspaceStoreInterface} — a process-lifetime `Map` of\n * {@link WorkspaceSnapshot}s keyed by workspace id, the DEFAULT store\n * {@link import('../../factories.js').createMemoryWorkspaceStore} builds.\n *\n * @remarks\n * A plain `Map<string, WorkspaceSnapshot>` (AGENTS §21 — the snapshot is already pure,\n * self-contained JSON, so no encoding is needed for the memory tier). Like the\n * the analogous `MemoryWorkflowStore` in `@orkestrel/workflow` it twins,\n * there is NO idle-TTL and NO eviction: a persisted workspace lives until an explicit `delete`. A\n * durable backend (JSON / SQLite / IndexedDB) swaps in through the SAME interface without touching\n * the {@link import('../WorkspaceManager.js').WorkspaceManager} or the\n * {@link import('../Workspace.js').Workspace} — its driver-pluggable twin is\n * {@link import('./DatabaseWorkspaceStore.js').DatabaseWorkspaceStore} (the snapshot as one opaque\n * 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 §22 method\n * bijection with {@link WorkspaceStoreInterface}). Hydration is a caller concern: a\n * {@link import('../WorkspaceManager.js').WorkspaceManager} reads a snapshot back and rebuilds the\n * live workspace through the constructor `seed` (its `open` / `save`).\n *\n * @example\n * ```ts\n * import { createMemoryWorkspaceStore, createWorkspace } from '@src/core'\n *\n * const store = createMemoryWorkspaceStore()\n * const workspace = createWorkspace()\n * workspace.write('notes.txt', 'hello')\n * await store.set(workspace.snapshot()) // persist the workspace\n * const snapshot = await store.get(workspace.id)\n * await store.delete(workspace.id) // drop it\n * ```\n */\nexport class MemoryWorkspaceStore implements WorkspaceStoreInterface {\n\treadonly #snapshots = new Map<string, WorkspaceSnapshot>()\n\n\tget(id: string): Promise<WorkspaceSnapshot | undefined> {\n\t\treturn Promise.resolve(this.#snapshots.get(id))\n\t}\n\n\tset(snapshot: WorkspaceSnapshot): 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\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 {\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\tBinaryMIME,\n\tConversationInterface,\n\tConversationManagerInterface,\n\tConversationManagerOptions,\n\tConversationOptions,\n\tConversationSnapshotRow,\n\tConversationStoreInterface,\n\tFileContent,\n\tFileInput,\n\tFileInterface,\n\tInstructionInput,\n\tInstructionInterface,\n\tInstructionManagerInterface,\n\tInstructionManagerOptions,\n\tProviderInterface,\n\tScopeInput,\n\tScopeInterface,\n\tScopeManagerInterface,\n\tScopeManagerOptions,\n\tThinkSplitterInterface,\n\tToolInterface,\n\tToolManagerInterface,\n\tToolOptions,\n\tWorkspaceInterface,\n\tWorkspaceManagerInterface,\n\tWorkspaceManagerOptions,\n\tWorkspaceOperation,\n\tWorkspaceOptions,\n\tWorkspaceSnapshotRow,\n\tWorkspaceStoreInterface,\n\tWorkspaceToolOptions,\n} from './types.js'\nimport type { ContractInterface } from '@orkestrel/contract'\nimport type { DriverInterface, TableInterface } from '@orkestrel/database'\nimport type { QueueInterface } from '@orkestrel/queue'\nimport type { RunnerInterface } from '@orkestrel/workflow'\nimport { createContract, rawShape, schemaToParameters, 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 { 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 { settleAgentJob } from './helpers.js'\nimport { Instruction } from './instructions/Instruction.js'\nimport { InstructionManager } from './instructions/InstructionManager.js'\nimport { Scope } from './scopes/Scope.js'\nimport { ScopeManager } from './scopes/ScopeManager.js'\nimport { ThinkSplitter } from './ThinkSplitter.js'\nimport { Tool } from './tools/Tool.js'\nimport { ToolManager } from './tools/ToolManager.js'\nimport { WORKSPACE_TOOL_DESCRIPTION, WORKSPACE_TOOL_NAME } from './constants.js'\nimport { WorkspaceError } from './errors.js'\nimport { computeSize, countLines, isText, rangeOf } from './helpers.js'\nimport { workspaceToolShape } from './shapers.js'\nimport { Workspace } from './workspaces/Workspace.js'\nimport { WorkspaceManager } from './workspaces/WorkspaceManager.js'\nimport { DatabaseWorkspaceStore } from './workspaces/stores/DatabaseWorkspaceStore.js'\nimport { MemoryWorkspaceStore } from './workspaces/stores/MemoryWorkspaceStore.js'\n\n/**\n * Create a tool — a {@link ToolInterface} binding a {@link ToolDefinition} schema\n * (the `name` / `description` / `parameters` the model sees) to the `execute` handler\n * that runs a call.\n *\n * @remarks\n * Only `name` is required (it keys the tool in a {@link ToolManagerInterface} and is\n * what the model calls); `description` / `parameters` are the optional JSON-Schema the\n * provider advertises (forwarded verbatim). The handler's `args` is the model-supplied\n * `unknown` arguments record — narrow it inside (§14); a `createToolManager` registry\n * isolates a throw into a `ToolResult.error`.\n *\n * @param options - `name` (required), optional `description` / `parameters`, and the\n * `execute` handler (see {@link ToolOptions})\n * @returns A working {@link ToolInterface}\n *\n * @example\n * ```ts\n * import { createTool } from '@src/core'\n *\n * const add = createTool({\n * \tname: 'add',\n * \tdescription: 'Add two numbers',\n * \texecute: (args) => Number(args.a) + Number(args.b),\n * })\n * ```\n */\nexport function createTool(options: ToolOptions): ToolInterface {\n\treturn new Tool(options)\n}\n\n/**\n * Create a tool registry — a {@link ToolManagerInterface} that resolves tool names,\n * lists {@link ToolDefinition}s for the provider, and executes calls with per-call\n * error isolation.\n *\n * @remarks\n * Starts empty; `add` registers one tool or a batch (§9.2), `definitions()` yields the\n * schemas to hand a provider, and `execute` runs a {@link ToolCall} (or a batch),\n * ALWAYS resolving a {@link ToolResult} — a handler throw becomes an `error` result and\n * an unknown name a not-found `error`, so a tool throw never escapes and a batch never\n * fails as a whole.\n *\n * @returns An empty {@link ToolManagerInterface}\n *\n * @example\n * ```ts\n * import { createTool, createToolManager } from '@src/core'\n *\n * const tools = createToolManager()\n * tools.add(createTool({ name: 'add', execute: (a) => Number(a.x) + Number(a.y) }))\n * const result = await tools.execute({ id: '1', name: 'add', arguments: { x: 1, y: 2 } })\n * ```\n */\nexport function createToolManager(): ToolManagerInterface {\n\treturn new ToolManager()\n}\n\n/**\n * Create 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 ConversationSummarizer} 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 SectionInterface} 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 * via the reserved `on` option (§8); the emitter isolates a listener throw and routes it to\n * its `error` handler (the `error` option, §13), 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\n * ```ts\n * import type { ProviderInterface } from '@src/core'\n * import { createConversation } from '@src/core'\n *\n * declare const provider: ProviderInterface // any concrete implementation supplied by the host app\n * const conversation = createConversation({\n * \t// Append the instruction as the FINAL user turn — a chat model emits nothing when the\n * \t// prompt ends on an assistant turn, so a leading-system instruction is unreliable.\n * \tsummarize: async (messages) =>\n * \t\t(await provider.generate([...messages, { id: 's', role: 'user', content: 'Summarize the conversation so far concisely.' }], AbortSignal.timeout(30_000))).content,\n * })\n * conversation.add({ role: 'user', content: 'Hello' })\n * await conversation.compact() // folds the live tail into a summarized section\n * ```\n */\nexport function createConversation(options?: ConversationOptions): ConversationInterface {\n\treturn new Conversation(options)\n}\n\n/**\n * Create a conversation registry — a {@link ConversationManagerInterface} holding\n * {@link ConversationInterface}s keyed by their `id` (in insertion order) WITH an active pointer:\n * the §9 store over the conversation layer plus the `active` / `switch` seam the context renders.\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, §9.2) reports whether any was removed AND\n * clears `active` if it was the removed one; `clear` empties it and clears `active`. 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 '@src/core'\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 * Create 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 {@link 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 createMemoryWorkspaceStore}. `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 constructor `seed` (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 '@src/core'\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 * Create a {@link DatabaseConversationStore} over any {@link DriverInterface} — the durable,\n * driver-pluggable backing for the conversation persistence seam, the opt-in twin of\n * {@link createMemoryConversationStore}. The EXACT twin of {@link 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 {@link 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('./helpers.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, createMemoryDriver } from '@src/core'\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 * Create 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 '@src/core'\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 * Create 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, §9.2) MINTS each `id` and OVERWRITES a same-name\n * instruction (last write wins); `instructions()` lists them sorted by descending\n * `priority` (stable for ties); `format` / `description` are the build contract a richer\n * context renders an instructions block with; `remove` (one or a batch) reports whether\n * any was removed; `clear` empties it. Carries an observable `emitter`\n * ({@link import('./types.js').InstructionManagerEventMap}) wired via the reserved `on`\n * option (§8); the emitter isolates a listener throw and routes it to its `error` handler\n * (the `error` option, §13), 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 * `description` / `format`, beating the provider default + built-in; a per-item\n * `InstructionInput.format` 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 '@src/core'\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 * Create a named scope — an immutable {@link ScopeInterface} from its `name` and the four\n * optional 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` / `messages` /\n * `files` allow-lists (see {@link ScopeInput})\n * @returns A working {@link ScopeInterface}\n *\n * @example\n * ```ts\n * import { createScope } from '@src/core'\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 * Create 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, §9.2) reports whether any was removed; `clear` empties it.\n * Carries an observable `emitter` ({@link import('./types.js').ScopeManagerEventMap}) wired\n * via the reserved `on` option (§8); the emitter isolates a listener throw and routes it to\n * its `error` handler (the `error` option, §13), 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 '@src/core'\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?.on, options?.error)\n}\n\n/**\n * Create a richer turn context — an {@link AgentContextInterface} assembling a provider\n * request from the optional system prompt, the instruction registry, the workspace registry,\n * the conversation store, the tool registry, and the active scope.\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, mutable afterwards\n * via `context.scope`). 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' `data` to the last user message), built fresh each call; the active\n * workspace is the SOLE document/image context. Tools are advertised STRUCTURALLY (via\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 '@src/core'\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 * Create 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` (via `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 via `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 '@src/core'\n * import { createAgent, createTokenBudget } from '@src/core'\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.type === '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 * Create a stream-stateful `<think>` separator — a {@link ThinkSplitterInterface} that\n * splits a thinking model's in-content `<think>…</think>` reasoning spans away from\n * the answer, delta by delta, so a provider yields ONLY clean content and surfaces the\n * accumulated reasoning as {@link import('./types.js').ProviderResult.thinking}.\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 just 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 '@src/core'\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 * Create 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` via `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 now — the async human-approval handshake is deferred.\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 '@src/core'\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 * Create 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 `unknown <category>:\n * <name>` on an unregistered name (§9.1 + §12) — a misconfigured or crash-restored job\n * 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 type { ProviderInterface } from '@src/core'\n * import { createAgentRegistry, createTool } from '@src/core'\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 * Create 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 * via `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 * (e.g. `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; `allowPartial: true`\n * resolves the partial as success instead.\n * - **Cancellation threads through.** The handler passes `execution.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 `allowPartial` 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, createMemoryQueueStore } from '@src/core'\n *\n * const registry = createAgentRegistry({ providers: { main: provider } })\n * const store = createMemoryQueueStore(agentJobShape) // survives a restart via 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, allowPartial = false, concurrency, retries, timeout, store } = options\n\treturn createQueue<AgentJobInput, AgentResult>({\n\t\tconcurrency,\n\t\tretries,\n\t\ttimeout,\n\t\tstore,\n\t\thandler: (input, execution) =>\n\t\t\tsettleAgentJob(registry.build(input, execution.signal), allowPartial),\n\t})\n}\n\n/**\n * Create an agent-job runner — a {@link RunnerInterface} over serializable\n * {@link AgentJobInput}s that COMPOSES `createRunner` (one-shot, ordered, fail-fast), each\n * unit rehydrated through the `registry` and subjected to the partial policy. The runner\n * enables **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), `allowPartial: 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 `allowPartial` 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 '@src/core'\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, allowPartial = false, concurrency, retries, timeout } = options\n\treturn createRunner<AgentJobInput, AgentResult>({\n\t\tconcurrency,\n\t\tretries,\n\t\ttimeout,\n\t\thandler: (controller) => {\n\t\t\t// Fan out this job's declared sub-agents FIRST (fire-and-track): spawn each child\n\t\t\t// through the same bounded queue and DON'T await it here — the runner awaits the\n\t\t\t// whole spawn closure via its count gate, and inline-awaiting a spawn from a\n\t\t\t// slot-holding handler on a bounded runner can deadlock (see ControllerInterface).\n\t\t\tconst children = controller.input.children\n\t\t\tif (children !== undefined) for (const child of children) void controller.spawn(child)\n\t\t\t// Then run THIS (parent) job's agent and apply the partial policy.\n\t\t\treturn settleAgentJob(registry.build(controller.input, controller.signal), allowPartial)\n\t\t},\n\t})\n}\n\n/**\n * Create a file — an immutable {@link FileInterface} from its `path` + {@link FileContent}\n * and optional {@link import('./types.js').FileState}, with `size` / `lines` DERIVED from the\n * content.\n *\n * @remarks\n * Returns a PLAIN `Object.freeze`d record (NOT a class instance) — the `path` IS its identity\n * (there is no `id`). Only `path` / `content` are required; `state` defaults to `'created'`\n * when omitted. `size` (via {@link computeSize}) and `lines` (via {@link countLines}) are\n * computed from the content here (so they never drift from it). Frozen + plain, so it\n * `structuredClone`s losslessly and is never mutated after creation.\n *\n * @param input - `path` / `content` (required) and an optional `state` (see {@link FileInput})\n * @returns A frozen {@link FileInterface} record\n *\n * @example\n * ```ts\n * import { createFile, createTextContent } from '@src/core'\n *\n * const file = createFile({ path: 'src/main.ts', content: createTextContent('const x = 1', 'typescript') })\n * file.lines // 1\n * ```\n */\nexport function createFile(input: FileInput): FileInterface {\n\treturn Object.freeze({\n\t\tpath: input.path,\n\t\tcontent: input.content,\n\t\tstate: input.state ?? 'created',\n\t\tsize: computeSize(input.content),\n\t\tlines: countLines(input.content),\n\t})\n}\n\n/**\n * Build the TEXT {@link FileContent} arm — the §4.2.3 split constructor for text (a separate\n * function per arm, not one constructor dispatching on a discriminator parameter).\n *\n * @param text - The literal text body\n * @param language - The fenced-code language the text renders as (e.g. `'typescript'`)\n * @returns A `{ text; language }` content arm\n *\n * @example\n * ```ts\n * import { createTextContent } from '@src/core'\n *\n * createTextContent('const x = 1', 'typescript') // { text: 'const x = 1', language: 'typescript' }\n * ```\n */\nexport function createTextContent(text: string, language: string): FileContent {\n\treturn { text, language }\n}\n\n/**\n * Build the BINARY {@link FileContent} arm — the §4.2.3 split constructor for binary (a\n * separate function per arm, not one constructor dispatching on a discriminator parameter).\n * An image is just a binary with an image {@link BinaryMIME}.\n *\n * @param data - The base64-encoded binary payload\n * @param mime - The {@link BinaryMIME} that labels the payload\n * @returns A `{ data; mime }` content arm\n *\n * @example\n * ```ts\n * import { createBinaryContent } from '@src/core'\n *\n * createBinaryContent('<base64>', 'image/png') // { data: '<base64>', mime: 'image/png' }\n * ```\n */\nexport function createBinaryContent(data: string, mime: BinaryMIME): FileContent {\n\treturn { data, mime }\n}\n\n/**\n * Create a workspace — a mutable, `path`-keyed working set of immutable\n * {@link FileInterface}s with the in-memory edit surface (read / write / search / replace /\n * move / remove), observable through its `EmitterInterface` (from `@orkestrel/emitter`).\n *\n * @param options - Optional initial {@link import('./types.js').WorkspaceEventMap} listeners (`on`) and the emitter's `error` handler (see {@link WorkspaceOptions})\n * @returns A working {@link WorkspaceInterface}\n *\n * @example\n * ```ts\n * import { createWorkspace } from '@src/core'\n *\n * const workspace = createWorkspace({ on: { write: (file) => console.log(file.path) } })\n * workspace.write('src/main.ts', 'const x = 1')\n * workspace.file('src/main.ts')?.state // 'created'\n * ```\n */\nexport function createWorkspace(options?: WorkspaceOptions): WorkspaceInterface {\n\treturn new Workspace(options)\n}\n\n/**\n * Create the in-memory workspace store — a {@link WorkspaceStoreInterface} backed by a\n * process-lifetime `Map` of {@link import('./types.js').WorkspaceSnapshot}s keyed by workspace id,\n * the DEFAULT backing for the durable {@link WorkspaceManagerInterface.open} /\n * {@link WorkspaceManagerInterface.save} seam.\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 the analogous `createMemoryWorkflowStore` in `@orkestrel/workflow`.\n * `get` / `set` / `delete` are async (the same shape a durable backend fits); UNLIKE a session\n * store there is NO idle-TTL / eviction — a persisted workspace lives until an explicit `delete`.\n * Its driver-pluggable twin is {@link createDatabaseWorkspaceStore} (the snapshot as one opaque\n * JSON column over a `databases` table) — for a DURABLE store pass it a JSON / SQLite / IndexedDB\n * driver, and it swaps in WITHOUT touching the manager or the workspace. Hydration stays a manager\n * concern: read a snapshot back and rebuild the live workspace through the constructor `seed`.\n *\n * @returns A memory-backed {@link WorkspaceStoreInterface}\n *\n * @example\n * ```ts\n * import { createMemoryWorkspaceStore, createWorkspaceManager } from '@src/core'\n *\n * const store = createMemoryWorkspaceStore()\n * const manager = createWorkspaceManager({ store })\n * const workspace = manager.add()\n * workspace.write('notes.txt', 'hello')\n * await manager.save(workspace.id) // persist the workspace\n * ```\n */\nexport function createMemoryWorkspaceStore(): WorkspaceStoreInterface {\n\treturn new MemoryWorkspaceStore()\n}\n\n/**\n * Create a {@link DatabaseWorkspaceStore} over any {@link DriverInterface} — the durable,\n * driver-pluggable backing for the workspace persistence seam, the opt-in twin of\n * {@link createMemoryWorkspaceStore}.\n *\n * @remarks\n * Builds a one-table database (`workspaces`, 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 * the analogous `createDatabaseWorkflowStore` in `@orkestrel/workflow` 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('./helpers.js').isWorkspaceSnapshot}). 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 WorkspaceStoreInterface} WITHOUT touching the manager or the workspace.\n *\n * @param driver - The storage backend the snapshots persist to (defaults to {@link createMemoryDriver})\n * @returns A {@link WorkspaceStoreInterface} over the driver\n *\n * @example\n * ```ts\n * import { createDatabaseWorkspaceStore, createMemoryDriver, createWorkspaceManager } from '@src/core'\n *\n * const store = createDatabaseWorkspaceStore(createMemoryDriver()) // a durable driver swaps in here\n * const manager = createWorkspaceManager({ store })\n * const workspace = manager.add()\n * workspace.write('notes.txt', 'hello')\n * await manager.save(workspace.id) // persist the workspace (one JSON column)\n * ```\n */\nexport function createDatabaseWorkspaceStore(\n\tdriver: DriverInterface = createMemoryDriver(),\n): WorkspaceStoreInterface {\n\t// The snapshot is stored as ONE OPAQUE JSON column (`rawShape`), so the row infers FLAT —\n\t// `{ id: string; snapshot: unknown }` = `WorkspaceSnapshotRow` — and the File-list snapshot\n\t// shape never forces a contract `Infer`.\n\tconst columns = { id: stringShape(), snapshot: rawShape({}) }\n\tconst database = createDatabase({ driver, tables: { workspaces: columns } })\n\tconst table: TableInterface<WorkspaceSnapshotRow> = database.table('workspaces')\n\treturn new DatabaseWorkspaceStore(table)\n}\n\n/**\n * Create a workspace registry — a {@link WorkspaceManagerInterface} holding\n * {@link WorkspaceInterface}s keyed by their `id` (in insertion order) WITH an active pointer:\n * the §9 store over the workspace layer plus the `active` / `switch` seam the context renders.\n *\n * @remarks\n * Starts empty; `add(input?)` mints a {@link WorkspaceInterface} (its `id` from the input or a\n * random UUID), flowing the manager's default `on` / `error` in unless the input overrides them,\n * and stores it (an already-present `id` overwrites — last write wins) — and AUTO-ACTIVATES the\n * FIRST one (a registry with workspaces always has one `active`); a later `add` leaves `active`\n * unchanged. `switch(id)` re-points `active` (an unknown `id` returns `undefined`, leaving\n * `active` unchanged — lenient, never throws); `workspace(id)` / `workspaces()` look up;\n * `remove` (one or a batch, §9.2) reports whether any was removed AND clears `active` if it was\n * the removed one; `clear` empties it and clears `active`. Event-free (each workspace owns its\n * own observable `emitter`).\n *\n * With the optional `store` ({@link WorkspaceStoreInterface}, e.g. `createMemoryWorkspaceStore` /\n * `createDatabaseWorkspaceStore`), `open(id)` HYDRATES a workspace on a registry miss (rebuilding it\n * through the constructor `seed` from the snapshot's `files`, then activating it) and `save(id)`\n * PERSISTS a registered workspace's `snapshot()`. Both are LENIENT without a store (open resolves\n * only registered ids, save is a no-op `false`).\n *\n * @param options - Optional default `on` / `error` for created workspaces + the durable `store`\n * (see {@link WorkspaceManagerOptions})\n * @returns An empty {@link WorkspaceManagerInterface}\n *\n * @example\n * ```ts\n * import { createWorkspaceManager } from '@src/core'\n *\n * const workspaces = createWorkspaceManager()\n * const scratch = workspaces.add() // auto-activates — workspaces.active === scratch\n * scratch.write('notes.txt', 'hello')\n * ```\n */\nexport function createWorkspaceManager(\n\toptions?: WorkspaceManagerOptions,\n): WorkspaceManagerInterface {\n\treturn new WorkspaceManager(options)\n}\n\n/**\n * Wrap a {@link WorkspaceManagerInterface} as an LLM-callable {@link ToolInterface} — it ADVERTISES\n * the `operation`-discriminated 13-op union ({@link import('./shapers.js').workspaceToolShape}) as\n * its `parameters`, and its handler PARSES the model-supplied args against that contract and\n * DISPATCHES the matched operation against the manager's ACTIVE workspace (the registry ops drive\n * the manager itself), returning the plain result (throwing a typed {@link WorkspaceError} on\n * failure).\n *\n * @remarks\n * MANAGER-DRIVEN: every edit / read op (read / list / has / search / replace / write / splice /\n * prepend / append / move / remove) targets `manager.active`, so the model edits whichever workspace\n * is active and a host can re-point it ({@link WorkspaceManagerInterface.switch}) between turns —\n * wire the agent's registry in via `createWorkspaceTool(agent.context.workspaces)`. Two REGISTRY ops\n * make the model self-sufficient: `workspaces` LISTS the registered workspaces (each\n * `{ id, files, active }`) so it can discover an id, and `switch` re-points the active workspace by\n * id (lenient — an unknown id is a no-op reporting `switched: false`, never a throw).\n *\n * NO-ACTIVE RULE (the ergonomic seam): a WRITING op (write / splice / prepend / append / move /\n * remove / replace) run when `manager.active` is `undefined` AUTO-CREATES + activates a default\n * workspace (`manager.add()`) so the model can just start writing; a pure-READ op (read / list / has\n * / search) against no active workspace returns the EMPTY result (`undefined` / `[]` / `false`),\n * never creating one and never throwing.\n *\n * A plain {@link ToolManagerInterface}-compatible tool (so `createMCPServer` / `createMCPRoutes`\n * expose it over MCP for free — nothing MCP is wired here), built as a factory + dispatch closure\n * exactly like the analogous `createWorkflowTool` in `@orkestrel/workflow` (NOT a class). The\n * contract is compiled ONCE and its JSON Schema is narrowed to the open\n * `Readonly<Record<string, unknown>>` a tool advertises via the shared\n * {@link schemaToParameters} contracts helper, never an assertion\n * (§14) — a compiled contract schema is always a record, so it passes; the `undefined` fallback only\n * satisfies the type's optionality.\n *\n * The handler conforms to the universal tool-handler contract (AGENTS §14): it `contract.parse`s the\n * args, THROWS a `TOOL` {@link WorkspaceError} when no operation arm matched (a malformed / unknown\n * operation), else `switch`es on `op.operation` and RETURNS the plain result — letting a\n * `WorkspaceError` raised by the live workspace (`MODALITY` / `PATTERN` / `RANGE`) PROPAGATE\n * unCAUGHT. The {@link import('./tools/ToolManager.js').ToolManager} performs the ONE\n * canonical wrap (`{ id, name, value }` on a return; `{ id, name, error }` on a throw, ISOLATED so\n * nothing escapes the run), so the outcome appears EXACTLY ONCE over BOTH the agent loop and MCP (a\n * throw → MCP `isError: true`). There is no `{ ok, output, duration }` envelope. The range edit is\n * the FLAT `'splice'` op: its four flat caret integers are reassembled into a {@link import('./types.js').Range}\n * by {@link rangeOf} and fed to the workspace's ranged `write`.\n *\n * @param manager - The workspace registry the tool reads + edits (its ACTIVE workspace; closed over by the handler)\n * @param options - Optional advertised `name` / `description` overrides (see {@link WorkspaceToolOptions})\n * @returns A {@link ToolInterface} (named {@link import('./constants.js').WORKSPACE_TOOL_NAME} by\n * default) whose `parameters` advertise the `operation`-discriminated union schema\n *\n * @example\n * ```ts\n * import { createWorkspaceManager, createWorkspaceTool, createToolManager } from '@src/core'\n *\n * const manager = createWorkspaceManager()\n * const tool = createWorkspaceTool(manager) // edits the manager's ACTIVE workspace\n * const tools = createToolManager()\n * tools.add(tool) // a model can now read + edit the active workspace by calling `workspace`\n * ```\n */\nexport function createWorkspaceTool(\n\tmanager: WorkspaceManagerInterface,\n\toptions?: WorkspaceToolOptions,\n): ToolInterface {\n\tconst contract: ContractInterface<WorkspaceOperation> = createContract(workspaceToolShape)\n\t// The advertised schema, narrowed to the open tool-parameters record (§14, never `as`) via the\n\t// shared `schemaToParameters` contracts helper.\n\tconst parameters = schemaToParameters(contract.schema)\n\treturn createTool({\n\t\tname: options?.name ?? WORKSPACE_TOOL_NAME,\n\t\tdescription: options?.description ?? WORKSPACE_TOOL_DESCRIPTION,\n\t\tparameters,\n\t\t// The universal tool-handler contract (§14): PARSE the args against the operation contract;\n\t\t// an un-parseable / unknown operation ⇒ THROW a `TOOL` WorkspaceError. Else DISPATCH the\n\t\t// matched op — the registry ops (`workspaces` / `switch`) drive the manager, every edit / read\n\t\t// op the manager's ACTIVE workspace. A WorkspaceError the workspace itself raises (MODALITY /\n\t\t// PATTERN / RANGE) PROPAGATES — the ToolManager isolates every throw into the canonical\n\t\t// ToolResult's top-level `error`, so nothing escapes the run.\n\t\texecute: (args) => {\n\t\t\tconst op = contract.parse(args)\n\t\t\tif (op === undefined) {\n\t\t\t\tthrow new WorkspaceError('TOOL', `unknown or malformed operation`, { args })\n\t\t\t}\n\t\t\t// Registry ops act on the MANAGER, not a workspace — handle them first.\n\t\t\tif (op.operation === 'workspaces') {\n\t\t\t\tconst activeId = manager.active?.id\n\t\t\t\treturn manager.workspaces().map((workspace) => ({\n\t\t\t\t\tid: workspace.id,\n\t\t\t\t\tfiles: workspace.count,\n\t\t\t\t\tactive: workspace.id === activeId,\n\t\t\t\t}))\n\t\t\t}\n\t\t\tif (op.operation === 'switch') {\n\t\t\t\tconst switched = manager.switch(op.id)\n\t\t\t\t// Lenient: an unknown id leaves `active` unchanged and reports `switched: false`.\n\t\t\t\treturn switched === undefined\n\t\t\t\t\t? { id: op.id, switched: false }\n\t\t\t\t\t: { id: switched.id, switched: true, files: switched.count }\n\t\t\t}\n\t\t\t// Edit / read ops target the ACTIVE workspace. A WRITING op ensures a target — auto-creating\n\t\t\t// + activating a default workspace when none is active (the no-active ergonomic seam) — while\n\t\t\t// a pure-READ op returns the empty result against no active workspace rather than creating one.\n\t\t\tconst active = manager.active\n\t\t\tswitch (op.operation) {\n\t\t\t\tcase 'read':\n\t\t\t\t\treturn active?.read(op.path)\n\t\t\t\tcase 'list':\n\t\t\t\t\treturn (active?.files() ?? []).map((file) => ({\n\t\t\t\t\t\tpath: file.path,\n\t\t\t\t\t\tstate: file.state,\n\t\t\t\t\t\tsize: file.size,\n\t\t\t\t\t\tlines: file.lines,\n\t\t\t\t\t\tkind: isText(file.content) ? 'text' : 'binary',\n\t\t\t\t\t}))\n\t\t\t\tcase 'has':\n\t\t\t\t\treturn active?.has(op.path) ?? false\n\t\t\t\tcase 'search':\n\t\t\t\t\treturn (\n\t\t\t\t\t\tactive?.search(op.query, { regex: op.regex, exact: op.exact, limit: op.limit }) ?? []\n\t\t\t\t\t)\n\t\t\t\tcase 'replace': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\treturn workspace.replace(op.query, op.replacement, {\n\t\t\t\t\t\tregex: op.regex,\n\t\t\t\t\t\texact: op.exact,\n\t\t\t\t\t\tlimit: op.limit,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t\tcase 'write': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\tworkspace.write(op.path, op.content)\n\t\t\t\t\treturn { path: op.path, state: workspace.file(op.path)?.state }\n\t\t\t\t}\n\t\t\t\tcase 'splice': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\tworkspace.write(\n\t\t\t\t\t\top.path,\n\t\t\t\t\t\top.content,\n\t\t\t\t\t\trangeOf(op.fromLine, op.fromColumn, op.toLine, op.toColumn),\n\t\t\t\t\t)\n\t\t\t\t\treturn { path: op.path, state: workspace.file(op.path)?.state }\n\t\t\t\t}\n\t\t\t\tcase 'prepend': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\tworkspace.prepend(op.path, op.content)\n\t\t\t\t\treturn { path: op.path, state: workspace.file(op.path)?.state }\n\t\t\t\t}\n\t\t\t\tcase 'append': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\tworkspace.append(op.path, op.content)\n\t\t\t\t\treturn { path: op.path, state: workspace.file(op.path)?.state }\n\t\t\t\t}\n\t\t\t\tcase 'move': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\treturn { from: op.from, to: op.to, moved: workspace.move(op.from, op.to) }\n\t\t\t\t}\n\t\t\t\tcase 'remove': {\n\t\t\t\t\tconst workspace = active ?? manager.add()\n\t\t\t\t\treturn { path: op.path, removed: workspace.remove(op.path) }\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t})\n}\n"],"mappings":"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"}