@warlock.js/ai 4.14.0 → 4.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +182 -141
- package/cjs/index.cjs +640 -139
- package/cjs/index.cjs.map +1 -1
- package/esm/contracts/index.d.mts +3 -3
- package/esm/contracts/memory/index.d.mts +1 -1
- package/esm/contracts/memory/memory-config.type.d.mts +29 -3
- package/esm/contracts/memory/memory-config.type.d.mts.map +1 -1
- package/esm/contracts/memory/memory-item.type.d.mts +15 -1
- package/esm/contracts/memory/memory-item.type.d.mts.map +1 -1
- package/esm/contracts/memory/memory.contract.d.mts +15 -2
- package/esm/contracts/memory/memory.contract.d.mts.map +1 -1
- package/esm/contracts/memory/recall-options.type.d.mts +12 -0
- package/esm/contracts/memory/recall-options.type.d.mts.map +1 -1
- package/esm/contracts/orchestrator/index.d.mts +1 -1
- package/esm/contracts/orchestrator/orchestrator-config.type.d.mts +38 -1
- package/esm/contracts/orchestrator/orchestrator-config.type.d.mts.map +1 -1
- package/esm/contracts/orchestrator/orchestrator.contract.d.mts +67 -3
- package/esm/contracts/orchestrator/orchestrator.contract.d.mts.map +1 -1
- package/esm/contracts/supervisor/supervisor-config.type.d.mts +23 -0
- package/esm/contracts/supervisor/supervisor-config.type.d.mts.map +1 -1
- package/esm/contracts/team/team-config.type.d.mts +9 -6
- package/esm/contracts/team/team-config.type.d.mts.map +1 -1
- package/esm/contracts/tool.contract.d.mts +35 -3
- package/esm/contracts/tool.contract.d.mts.map +1 -1
- package/esm/index.d.mts +8 -7
- package/esm/index.mjs +3 -2
- package/esm/memory/episodic-memory.mjs +14 -6
- package/esm/memory/episodic-memory.mjs.map +1 -1
- package/esm/memory/index.d.mts +1 -1
- package/esm/memory/memory.d.mts +13 -1
- package/esm/memory/memory.d.mts.map +1 -1
- package/esm/memory/memory.mjs +41 -7
- package/esm/memory/memory.mjs.map +1 -1
- package/esm/memory/procedural-memory.mjs +20 -7
- package/esm/memory/procedural-memory.mjs.map +1 -1
- package/esm/memory/semantic-memory.mjs +27 -10
- package/esm/memory/semantic-memory.mjs.map +1 -1
- package/esm/memory/working-memory.mjs +70 -13
- package/esm/memory/working-memory.mjs.map +1 -1
- package/esm/middleware/builtins/semantic-cache.d.mts +46 -1
- package/esm/middleware/builtins/semantic-cache.d.mts.map +1 -1
- package/esm/middleware/builtins/semantic-cache.mjs +60 -15
- package/esm/middleware/builtins/semantic-cache.mjs.map +1 -1
- package/esm/middleware/index.d.mts +1 -1
- package/esm/mock/index.d.mts +1 -1
- package/esm/mock/mock-config.type.d.mts +33 -4
- package/esm/mock/mock-config.type.d.mts.map +1 -1
- package/esm/mock/mock-model.d.mts +2 -1
- package/esm/mock/mock-model.d.mts.map +1 -1
- package/esm/mock/mock-model.mjs +5 -4
- package/esm/mock/mock-model.mjs.map +1 -1
- package/esm/mock/mock-sdk.d.mts +11 -3
- package/esm/mock/mock-sdk.d.mts.map +1 -1
- package/esm/mock/mock-sdk.mjs.map +1 -1
- package/esm/orchestrator/as-tool.d.mts +35 -9
- package/esm/orchestrator/as-tool.d.mts.map +1 -1
- package/esm/orchestrator/as-tool.mjs +67 -19
- package/esm/orchestrator/as-tool.mjs.map +1 -1
- package/esm/orchestrator/execution.d.mts.map +1 -1
- package/esm/orchestrator/execution.mjs +2 -2
- package/esm/orchestrator/execution.mjs.map +1 -1
- package/esm/orchestrator/index.d.mts +1 -1
- package/esm/orchestrator/index.mjs +1 -1
- package/esm/orchestrator/memory.d.mts +41 -5
- package/esm/orchestrator/memory.d.mts.map +1 -1
- package/esm/orchestrator/memory.mjs +53 -5
- package/esm/orchestrator/memory.mjs.map +1 -1
- package/esm/planner/plan-schema.d.mts +15 -4
- package/esm/planner/plan-schema.d.mts.map +1 -1
- package/esm/planner/plan-schema.mjs +27 -16
- package/esm/planner/plan-schema.mjs.map +1 -1
- package/esm/security/index.mjs +1 -0
- package/esm/security/outbound-policy.d.mts +9 -0
- package/esm/security/outbound-policy.d.mts.map +1 -1
- package/esm/security/outbound-policy.mjs +79 -5
- package/esm/security/outbound-policy.mjs.map +1 -1
- package/esm/security/outbound-policy.type.d.mts +8 -0
- package/esm/security/outbound-policy.type.d.mts.map +1 -1
- package/esm/security/safe-merge.d.mts +52 -0
- package/esm/security/safe-merge.d.mts.map +1 -0
- package/esm/security/safe-merge.mjs +68 -0
- package/esm/security/safe-merge.mjs.map +1 -0
- package/esm/supervisor/decide.mjs +52 -5
- package/esm/supervisor/decide.mjs.map +1 -1
- package/esm/supervisor/execution.d.mts +22 -12
- package/esm/supervisor/execution.d.mts.map +1 -1
- package/esm/supervisor/execution.mjs +47 -24
- package/esm/supervisor/execution.mjs.map +1 -1
- package/esm/supervisor/supervisor.mjs +4 -0
- package/esm/supervisor/supervisor.mjs.map +1 -1
- package/llms-full.txt +185 -14
- package/llms.txt +5 -4
- package/package.json +24 -4
- package/skills/README.md +6 -2
- package/skills/attach-ai-middleware/SKILL.md +17 -1
- package/skills/generate-images/SKILL.md +11 -4
- package/skills/rag-loaders-and-stores/SKILL.md +3 -0
- package/skills/run-ai-agent/SKILL.md +3 -0
- package/skills/run-orchestrator/SKILL.md +6 -1
- package/skills/run-planner/SKILL.md +7 -3
- package/skills/run-supervisor/SKILL.md +11 -1
- package/skills/secure-outbound-requests/SKILL.md +85 -0
- package/skills/use-ai-memory/SKILL.md +36 -3
- package/skills/use-runtime-skills/SKILL.md +2 -1
|
@@ -76,7 +76,8 @@ declare class MockModel implements ModelContract {
|
|
|
76
76
|
complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse>;
|
|
77
77
|
/**
|
|
78
78
|
* Record the call, optionally delay, then emit the scripted response as a
|
|
79
|
-
* sequence of stream chunks:
|
|
79
|
+
* sequence of stream chunks: the scripted `deltas` when the entry
|
|
80
|
+
* supplies them, otherwise content split word-by-word, as `delta`
|
|
80
81
|
* chunks, each scripted tool call as a `tool-call` chunk, and finally a
|
|
81
82
|
* `done` chunk with finish reason + usage. Throws eagerly if the scripted
|
|
82
83
|
* entry carries an `error`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-model.d.mts","names":[],"sources":["../../../../../../../ai/src/mock/mock-model.ts"],"mappings":";;;;;KAUK,YAAA;EACH,QAAA,EAAU,OAAA;EACV,OAAA,GAAU,gBAAgB;AAAA;;;;;;;;AAAA;AA+B5B;;;;;;;;;;;;;;;;;;;;cAAa,SAAA,YAAqB,aAAA;EAAA,SAQd,IAAA;EAAA,iBACC,SAAA;EAAA,SARH,QAAA;EAAA,SACA,YAAA,GAAe,iBAAA;EAAA,QAEvB,aAAA;EAAA,QACA,KAAA;cAGU,IAAA,UACC,SAAA,EAAW,iBAAA,IAC5B,YAAA,GAAe,iBAAA;EADa;;;;;EAAA,IAWnB,WAAA,IAAe,YAAA;EAQf;;;;EAAA,IAAA,SAAA;EA8CW;;;;;;EAAA,QApCd,YAAA;
|
|
1
|
+
{"version":3,"file":"mock-model.d.mts","names":[],"sources":["../../../../../../../ai/src/mock/mock-model.ts"],"mappings":";;;;;KAUK,YAAA;EACH,QAAA,EAAU,OAAA;EACV,OAAA,GAAU,gBAAgB;AAAA;;;;;;;;AAAA;AA+B5B;;;;;;;;;;;;;;;;;;;;cAAa,SAAA,YAAqB,aAAA;EAAA,SAQd,IAAA;EAAA,iBACC,SAAA;EAAA,SARH,QAAA;EAAA,SACA,YAAA,GAAe,iBAAA;EAAA,QAEvB,aAAA;EAAA,QACA,KAAA;cAGU,IAAA,UACC,SAAA,EAAW,iBAAA,IAC5B,YAAA,GAAe,iBAAA;EADa;;;;;EAAA,IAWnB,WAAA,IAAe,YAAA;EAQf;;;;EAAA,IAAA,SAAA;EA8CW;;;;;;EAAA,QApCd,YAAA;EA6DN;;;;;EAAA,QAhDM,aAAA;EA8FI;AAAA;;;;;EAvEC,QAAA,CAAS,QAAA,EAAU,OAAA,IAAW,OAAA,GAAU,gBAAA,GAAmB,OAAA,CAAQ,aAAA;;;;;;;;;EAwBlE,MAAA,CACZ,QAAA,EAAU,OAAA,IACV,OAAA,GAAU,gBAAA,GACT,aAAA,CAAc,gBAAA;;;;;;EA4CV,KAAA;AAAA"}
|
package/esm/mock/mock-model.mjs
CHANGED
|
@@ -103,7 +103,8 @@ var MockModel = class {
|
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
105
|
* Record the call, optionally delay, then emit the scripted response as a
|
|
106
|
-
* sequence of stream chunks:
|
|
106
|
+
* sequence of stream chunks: the scripted `deltas` when the entry
|
|
107
|
+
* supplies them, otherwise content split word-by-word, as `delta`
|
|
107
108
|
* chunks, each scripted tool call as a `tool-call` chunk, and finally a
|
|
108
109
|
* `done` chunk with finish reason + usage. Throws eagerly if the scripted
|
|
109
110
|
* entry carries an `error`.
|
|
@@ -116,10 +117,10 @@ var MockModel = class {
|
|
|
116
117
|
const mock = this.nextResponse();
|
|
117
118
|
if (mock.delay) await new Promise((resolve) => setTimeout(resolve, mock.delay));
|
|
118
119
|
if (mock.error) throw mock.error;
|
|
119
|
-
const
|
|
120
|
-
for (const
|
|
120
|
+
const chunks = mock.deltas ?? mock.content.split(" ").map((word) => word + " ");
|
|
121
|
+
for (const chunk of chunks) yield {
|
|
121
122
|
type: "delta",
|
|
122
|
-
content:
|
|
123
|
+
content: chunk
|
|
123
124
|
};
|
|
124
125
|
if (mock.toolCalls) for (const toolCall of mock.toolCalls) yield {
|
|
125
126
|
type: "tool-call",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-model.mjs","names":[],"sources":["../../../../../../../ai/src/mock/mock-model.ts"],"sourcesContent":["import type { Message } from \"../contracts/conversation-message.type\";\nimport type {\n ModelCallOptions,\n ModelCapabilities,\n ModelContract,\n ModelResponse,\n ModelStreamChunk,\n} from \"../contracts/model.contract\";\nimport type { MockModelResponse } from \"./mock-config.type\";\n\ntype RecordedCall = {\n messages: Message[];\n options?: ModelCallOptions;\n};\n\n/**\n * Deterministic in-memory `ModelContract` implementation for tests.\n *\n * **Role.** Stands in for a real provider model so agent/workflow/supervisor\n * tests can assert behavior without hitting the network, spending tokens, or\n * depending on non-deterministic LLM output.\n *\n * **Responsibility.**\n * - Owns: a scripted queue of `MockModelResponse` entries, a call-history\n * log for assertions, and the index pointer that advances through the\n * queue on each `complete()` / `stream()` call.\n * - Does NOT own: any real inference, tokenization, or network I/O — when\n * the queue is exhausted, the final entry is reused so tests never crash\n * on accidental over-consumption.\n *\n * Every AI-related test in this repo uses `MockSDK` / `MockModel` — real\n * provider APIs are never hit from the test suite (see §6 of code-style.md).\n *\n * @example\n * const model = new MockModel(\"mock-gpt\", [\n * { content: \"Hello!\", finishReason: \"stop\" },\n * { content: \"Second turn.\", finishReason: \"stop\" },\n * ]);\n *\n * const first = await model.complete([{ role: \"user\", content: \"hi\" }]);\n * expect(first.content).toBe(\"Hello!\");\n * expect(model.callCount).toBe(1);\n */\nexport class MockModel implements ModelContract {\n public readonly provider = \"mock\";\n public readonly capabilities?: ModelCapabilities;\n\n private responseIndex = 0;\n private calls: RecordedCall[] = [];\n\n public constructor(\n public readonly name: string,\n private readonly responses: MockModelResponse[],\n capabilities?: ModelCapabilities,\n ) {\n this.capabilities = capabilities;\n }\n\n /**\n * Full history of calls made to this model. Each entry is the exact\n * `{ messages, options }` pair that was passed — useful for asserting\n * that an agent built the right prompt or forwarded the right tool list.\n */\n public get callHistory(): RecordedCall[] {\n return this.calls;\n }\n\n /**\n * Number of times `complete()` or `stream()` has been invoked. Convenient\n * shorthand for `callHistory.length` in assertions.\n */\n public get callCount(): number {\n return this.calls.length;\n }\n\n /**\n * Advance the scripted response queue by one and return the entry at the\n * current pointer. If the queue is exhausted, the final scripted entry is\n * returned repeatedly so over-consumption in tests produces predictable\n * output instead of `undefined`.\n */\n private nextResponse(): MockModelResponse {\n const response = this.responses[Math.min(this.responseIndex, this.responses.length - 1)];\n\n this.responseIndex++;\n\n return response ?? { content: \"Mock response\", finishReason: \"stop\" };\n }\n\n /**\n * Convert a scripted `MockModelResponse` into a full `ModelResponse` with\n * synthesized usage numbers when the script didn't supply them. Input\n * usage is a fixed estimate; output usage is derived from content length.\n */\n private buildResponse(mock: MockModelResponse): ModelResponse {\n const estimatedInput = 10;\n const estimatedOutput = Math.ceil(mock.content.length / 4);\n\n return {\n content: mock.content,\n finishReason: mock.finishReason ?? \"stop\",\n usage: {\n input: mock.usage?.input ?? estimatedInput,\n output: mock.usage?.output ?? estimatedOutput,\n total: (mock.usage?.input ?? estimatedInput) + (mock.usage?.output ?? estimatedOutput),\n ...(mock.usage?.cachedTokens !== undefined ? { cachedTokens: mock.usage.cachedTokens } : {}),\n },\n toolCalls: mock.toolCalls,\n };\n }\n\n /**\n * Record the call, optionally delay (to simulate latency), and either\n * throw the scripted error or return the scripted response. Mirrors the\n * real provider's `complete()` contract so agents cannot tell the\n * difference at runtime.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.calls.push({ messages, options });\n\n const mock = this.nextResponse();\n\n if (mock.delay) {\n await new Promise((resolve) => setTimeout(resolve, mock.delay));\n }\n\n if (mock.error) {\n throw mock.error;\n }\n\n return this.buildResponse(mock);\n }\n\n /**\n * Record the call, optionally delay, then emit the scripted response as a\n * sequence of stream chunks: content split word-by-word as `delta`\n * chunks, each scripted tool call as a `tool-call` chunk, and finally a\n * `done` chunk with finish reason + usage. Throws eagerly if the scripted\n * entry carries an `error`.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.calls.push({ messages, options });\n\n const mock = this.nextResponse();\n\n if (mock.delay) {\n await new Promise((resolve) => setTimeout(resolve, mock.delay));\n }\n\n if (mock.error) {\n throw mock.error;\n }\n\n const
|
|
1
|
+
{"version":3,"file":"mock-model.mjs","names":[],"sources":["../../../../../../../ai/src/mock/mock-model.ts"],"sourcesContent":["import type { Message } from \"../contracts/conversation-message.type\";\nimport type {\n ModelCallOptions,\n ModelCapabilities,\n ModelContract,\n ModelResponse,\n ModelStreamChunk,\n} from \"../contracts/model.contract\";\nimport type { MockModelResponse } from \"./mock-config.type\";\n\ntype RecordedCall = {\n messages: Message[];\n options?: ModelCallOptions;\n};\n\n/**\n * Deterministic in-memory `ModelContract` implementation for tests.\n *\n * **Role.** Stands in for a real provider model so agent/workflow/supervisor\n * tests can assert behavior without hitting the network, spending tokens, or\n * depending on non-deterministic LLM output.\n *\n * **Responsibility.**\n * - Owns: a scripted queue of `MockModelResponse` entries, a call-history\n * log for assertions, and the index pointer that advances through the\n * queue on each `complete()` / `stream()` call.\n * - Does NOT own: any real inference, tokenization, or network I/O — when\n * the queue is exhausted, the final entry is reused so tests never crash\n * on accidental over-consumption.\n *\n * Every AI-related test in this repo uses `MockSDK` / `MockModel` — real\n * provider APIs are never hit from the test suite (see §6 of code-style.md).\n *\n * @example\n * const model = new MockModel(\"mock-gpt\", [\n * { content: \"Hello!\", finishReason: \"stop\" },\n * { content: \"Second turn.\", finishReason: \"stop\" },\n * ]);\n *\n * const first = await model.complete([{ role: \"user\", content: \"hi\" }]);\n * expect(first.content).toBe(\"Hello!\");\n * expect(model.callCount).toBe(1);\n */\nexport class MockModel implements ModelContract {\n public readonly provider = \"mock\";\n public readonly capabilities?: ModelCapabilities;\n\n private responseIndex = 0;\n private calls: RecordedCall[] = [];\n\n public constructor(\n public readonly name: string,\n private readonly responses: MockModelResponse[],\n capabilities?: ModelCapabilities,\n ) {\n this.capabilities = capabilities;\n }\n\n /**\n * Full history of calls made to this model. Each entry is the exact\n * `{ messages, options }` pair that was passed — useful for asserting\n * that an agent built the right prompt or forwarded the right tool list.\n */\n public get callHistory(): RecordedCall[] {\n return this.calls;\n }\n\n /**\n * Number of times `complete()` or `stream()` has been invoked. Convenient\n * shorthand for `callHistory.length` in assertions.\n */\n public get callCount(): number {\n return this.calls.length;\n }\n\n /**\n * Advance the scripted response queue by one and return the entry at the\n * current pointer. If the queue is exhausted, the final scripted entry is\n * returned repeatedly so over-consumption in tests produces predictable\n * output instead of `undefined`.\n */\n private nextResponse(): MockModelResponse {\n const response = this.responses[Math.min(this.responseIndex, this.responses.length - 1)];\n\n this.responseIndex++;\n\n return response ?? { content: \"Mock response\", finishReason: \"stop\" };\n }\n\n /**\n * Convert a scripted `MockModelResponse` into a full `ModelResponse` with\n * synthesized usage numbers when the script didn't supply them. Input\n * usage is a fixed estimate; output usage is derived from content length.\n */\n private buildResponse(mock: MockModelResponse): ModelResponse {\n const estimatedInput = 10;\n const estimatedOutput = Math.ceil(mock.content.length / 4);\n\n return {\n content: mock.content,\n finishReason: mock.finishReason ?? \"stop\",\n usage: {\n input: mock.usage?.input ?? estimatedInput,\n output: mock.usage?.output ?? estimatedOutput,\n total: (mock.usage?.input ?? estimatedInput) + (mock.usage?.output ?? estimatedOutput),\n ...(mock.usage?.cachedTokens !== undefined ? { cachedTokens: mock.usage.cachedTokens } : {}),\n },\n toolCalls: mock.toolCalls,\n };\n }\n\n /**\n * Record the call, optionally delay (to simulate latency), and either\n * throw the scripted error or return the scripted response. Mirrors the\n * real provider's `complete()` contract so agents cannot tell the\n * difference at runtime.\n */\n public async complete(messages: Message[], options?: ModelCallOptions): Promise<ModelResponse> {\n this.calls.push({ messages, options });\n\n const mock = this.nextResponse();\n\n if (mock.delay) {\n await new Promise((resolve) => setTimeout(resolve, mock.delay));\n }\n\n if (mock.error) {\n throw mock.error;\n }\n\n return this.buildResponse(mock);\n }\n\n /**\n * Record the call, optionally delay, then emit the scripted response as a\n * sequence of stream chunks: the scripted `deltas` when the entry\n * supplies them, otherwise content split word-by-word, as `delta`\n * chunks, each scripted tool call as a `tool-call` chunk, and finally a\n * `done` chunk with finish reason + usage. Throws eagerly if the scripted\n * entry carries an `error`.\n */\n public async *stream(\n messages: Message[],\n options?: ModelCallOptions,\n ): AsyncIterable<ModelStreamChunk> {\n this.calls.push({ messages, options });\n\n const mock = this.nextResponse();\n\n if (mock.delay) {\n await new Promise((resolve) => setTimeout(resolve, mock.delay));\n }\n\n if (mock.error) {\n throw mock.error;\n }\n\n const chunks = mock.deltas ?? mock.content.split(\" \").map((word) => word + \" \");\n\n for (const chunk of chunks) {\n yield { type: \"delta\", content: chunk };\n }\n\n if (mock.toolCalls) {\n for (const toolCall of mock.toolCalls) {\n yield {\n type: \"tool-call\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.input,\n };\n }\n }\n\n const response = this.buildResponse(mock);\n\n yield {\n type: \"done\",\n finishReason: response.finishReason,\n usage: response.usage,\n };\n }\n\n /**\n * Reset call history and response pointer back to their initial state.\n * Intended for test-suite `beforeEach` hooks so a single `MockModel`\n * instance can be reused across cases without cross-test leakage.\n */\n public reset(): void {\n this.calls = [];\n this.responseIndex = 0;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,IAAa,YAAb,MAAgD;CAO9C,AAAO,YACL,AAAgB,MAChB,AAAiB,WACjB,cACA;EAHgB;EACC;kBARQ;uBAGH;eACQ,CAAC;EAO/B,KAAK,eAAe;CACtB;;;;;;CAOA,IAAW,cAA8B;EACvC,OAAO,KAAK;CACd;;;;;CAMA,IAAW,YAAoB;EAC7B,OAAO,KAAK,MAAM;CACpB;;;;;;;CAQA,AAAQ,eAAkC;EACxC,MAAM,WAAW,KAAK,UAAU,KAAK,IAAI,KAAK,eAAe,KAAK,UAAU,SAAS,CAAC;EAEtF,KAAK;EAEL,OAAO,YAAY;GAAE,SAAS;GAAiB,cAAc;EAAO;CACtE;;;;;;CAOA,AAAQ,cAAc,MAAwC;EAC5D,MAAM,iBAAiB;EACvB,MAAM,kBAAkB,KAAK,KAAK,KAAK,QAAQ,SAAS,CAAC;EAEzD,OAAO;GACL,SAAS,KAAK;GACd,cAAc,KAAK,gBAAgB;GACnC,OAAO;IACL,OAAO,KAAK,OAAO,SAAS;IAC5B,QAAQ,KAAK,OAAO,UAAU;IAC9B,QAAQ,KAAK,OAAO,SAAS,mBAAmB,KAAK,OAAO,UAAU;IACtE,GAAI,KAAK,OAAO,iBAAiB,SAAY,EAAE,cAAc,KAAK,MAAM,aAAa,IAAI,CAAC;GAC5F;GACA,WAAW,KAAK;EAClB;CACF;;;;;;;CAQA,MAAa,SAAS,UAAqB,SAAoD;EAC7F,KAAK,MAAM,KAAK;GAAE;GAAU;EAAQ,CAAC;EAErC,MAAM,OAAO,KAAK,aAAa;EAE/B,IAAI,KAAK,OACP,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,KAAK,KAAK,CAAC;EAGhE,IAAI,KAAK,OACP,MAAM,KAAK;EAGb,OAAO,KAAK,cAAc,IAAI;CAChC;;;;;;;;;CAUA,OAAc,OACZ,UACA,SACiC;EACjC,KAAK,MAAM,KAAK;GAAE;GAAU;EAAQ,CAAC;EAErC,MAAM,OAAO,KAAK,aAAa;EAE/B,IAAI,KAAK,OACP,MAAM,IAAI,SAAS,YAAY,WAAW,SAAS,KAAK,KAAK,CAAC;EAGhE,IAAI,KAAK,OACP,MAAM,KAAK;EAGb,MAAM,SAAS,KAAK,UAAU,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC,KAAK,SAAS,OAAO,GAAG;EAE9E,KAAK,MAAM,SAAS,QAClB,MAAM;GAAE,MAAM;GAAS,SAAS;EAAM;EAGxC,IAAI,KAAK,WACP,KAAK,MAAM,YAAY,KAAK,WAC1B,MAAM;GACJ,MAAM;GACN,IAAI,SAAS;GACb,MAAM,SAAS;GACf,OAAO,SAAS;EAClB;EAIJ,MAAM,WAAW,KAAK,cAAc,IAAI;EAExC,MAAM;GACJ,MAAM;GACN,cAAc,SAAS;GACvB,OAAO,SAAS;EAClB;CACF;;;;;;CAOA,AAAO,QAAc;EACnB,KAAK,QAAQ,CAAC;EACd,KAAK,gBAAgB;CACvB;AACF"}
|
package/esm/mock/mock-sdk.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDKAdapterContract } from "../contracts/sdk-adapter.contract.mjs";
|
|
1
|
+
import { ModelConfig, SDKAdapterContract } from "../contracts/sdk-adapter.contract.mjs";
|
|
2
2
|
import { MockImageModel } from "./mock-image-model.mjs";
|
|
3
3
|
import { MockSpeechModel } from "./mock-speech-model.mjs";
|
|
4
4
|
import { MockTranscriptionModel } from "./mock-transcription-model.mjs";
|
|
@@ -20,8 +20,16 @@ import { MockModel } from "./mock-model.mjs";
|
|
|
20
20
|
* const result = await model.complete([{ role: "user", content: "Hi" }]);
|
|
21
21
|
* console.log(result.content); // "Hello from mock!"
|
|
22
22
|
*/
|
|
23
|
-
declare function MockSDK(config?: MockSDKConfig): SDKAdapterContract & {
|
|
24
|
-
/**
|
|
23
|
+
declare function MockSDK(config?: MockSDKConfig): Omit<SDKAdapterContract, "model"> & {
|
|
24
|
+
/**
|
|
25
|
+
* Narrower than `SDKAdapterContract.model()` on purpose — the
|
|
26
|
+
* instance really is a `MockModel`, so tests can reach `.calls` /
|
|
27
|
+
* `.reset()` straight off the returned model instead of digging it
|
|
28
|
+
* back out of `models`. Still satisfies the adapter contract:
|
|
29
|
+
* `MockModel` implements `ModelContract`.
|
|
30
|
+
*/
|
|
31
|
+
model(modelConfig: ModelConfig): MockModel; /** All model instances created by this SDK — for inspecting calls in tests */
|
|
32
|
+
models: MockModel[]; /** All image-model instances created by this SDK — for inspecting calls in tests */
|
|
25
33
|
imageModels: MockImageModel[]; /** All speech-model instances created by this SDK — for inspecting calls in tests */
|
|
26
34
|
speechModels: MockSpeechModel[]; /** All transcription-model instances created by this SDK — for inspecting calls in tests */
|
|
27
35
|
transcriptionModels: MockTranscriptionModel[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-sdk.d.mts","names":[],"sources":["../../../../../../../ai/src/mock/mock-sdk.ts"],"mappings":";;;;;;;;;;AA4BA;;;;;;;;;;;;iBAAgB,OAAA,CAAQ,MAAA,GAAQ,aAAA,GAAqB,kBAAA;EAAA,
|
|
1
|
+
{"version":3,"file":"mock-sdk.d.mts","names":[],"sources":["../../../../../../../ai/src/mock/mock-sdk.ts"],"mappings":";;;;;;;;;;AA4BA;;;;;;;;;;;;iBAAgB,OAAA,CAAQ,MAAA,GAAQ,aAAA,GAAqB,IAAA,CAAK,kBAAA;EAgBb;;;;;;;EAR3C,KAAA,CAAM,WAAA,EAAa,WAAA,GAAc,SAAA,EAAA;EAEjC,MAAA,EAAQ,SAAA,IAAA;EAER,WAAA,EAAa,cAAA,IAAA;EAEb,YAAA,EAAc,eAAA,IAAA;EAEd,mBAAA,EAAqB,sBAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-sdk.mjs","names":[],"sources":["../../../../../../../ai/src/mock/mock-sdk.ts"],"sourcesContent":["import type { ImageModelConfig } from \"../contracts/image-model.contract\";\nimport type {\n ModelConfig,\n SDKAdapterContract,\n} from \"../contracts/sdk-adapter.contract\";\nimport type { SpeechModelConfig } from \"../contracts/speech-model.contract\";\nimport type { TranscriptionModelConfig } from \"../contracts/transcription-model.contract\";\nimport { approximateTokenCount } from \"../utils/token-count\";\nimport type { MockSDKConfig } from \"./mock-config.type\";\nimport { MockImageModel } from \"./mock-image-model\";\nimport { MockModel } from \"./mock-model\";\nimport { MockSpeechModel } from \"./mock-speech-model\";\nimport { MockTranscriptionModel } from \"./mock-transcription-model\";\n\n/**\n * Creates a mock SDK adapter for testing — no HTTP calls, fully configurable.\n *\n * @example\n * const mock = MockSDK({\n * responses: [\n * { content: \"Hello from mock!\" },\n * { content: \"Second response\" },\n * ],\n * });\n * const model = mock.model({ name: \"gpt-4o\" });\n * const result = await model.complete([{ role: \"user\", content: \"Hi\" }]);\n * console.log(result.content); // \"Hello from mock!\"\n */\nexport function MockSDK(config: MockSDKConfig = {}): SDKAdapterContract & {\n /** All model instances created by this SDK — for inspecting calls in tests */\n models: MockModel[];\n /** All image-model instances created by this SDK — for inspecting calls in tests */\n imageModels: MockImageModel[];\n /** All speech-model instances created by this SDK — for inspecting calls in tests */\n speechModels: MockSpeechModel[];\n /** All transcription-model instances created by this SDK — for inspecting calls in tests */\n transcriptionModels: MockTranscriptionModel[];\n} {\n const models: MockModel[] = [];\n const imageModels: MockImageModel[] = [];\n const speechModels: MockSpeechModel[] = [];\n const transcriptionModels: MockTranscriptionModel[] = [];\n const responses = config.responses ?? [{ content: \"Mock response\" }];\n const imageResponses = config.imageResponses ?? [{}];\n const speechResponses = config.speechResponses ?? [{}];\n const transcriptionResponses = config.transcriptionResponses ?? [{}];\n\n return {\n models,\n imageModels,\n speechModels,\n transcriptionModels,\n model(modelConfig: ModelConfig) {\n const model = new MockModel(\n modelConfig.name ?? config.defaultModelName ?? \"mock-model\",\n responses,\n config.capabilities,\n );\n models.push(model);\n return model;\n },\n image(imageConfig: ImageModelConfig) {\n const model = new MockImageModel(\n imageConfig.name ?? config.defaultModelName ?? \"mock-image-model\",\n imageResponses,\n imageConfig.pricing ?? config.imagePricing,\n );\n imageModels.push(model);\n return model;\n },\n speech(speechConfig: SpeechModelConfig) {\n const model = new MockSpeechModel(\n speechConfig.name ?? config.defaultModelName ?? \"mock-speech-model\",\n speechResponses,\n speechConfig.pricing ?? config.speechPricing,\n );\n speechModels.push(model);\n return model;\n },\n transcribe(transcribeConfig: TranscriptionModelConfig) {\n const model = new MockTranscriptionModel(\n transcribeConfig.name ?? config.defaultModelName ?? \"mock-transcription-model\",\n transcriptionResponses,\n transcribeConfig.pricing ?? config.transcriptionPricing,\n );\n transcriptionModels.push(model);\n return model;\n },\n async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,QAAQ,SAAwB,CAAC,
|
|
1
|
+
{"version":3,"file":"mock-sdk.mjs","names":[],"sources":["../../../../../../../ai/src/mock/mock-sdk.ts"],"sourcesContent":["import type { ImageModelConfig } from \"../contracts/image-model.contract\";\nimport type {\n ModelConfig,\n SDKAdapterContract,\n} from \"../contracts/sdk-adapter.contract\";\nimport type { SpeechModelConfig } from \"../contracts/speech-model.contract\";\nimport type { TranscriptionModelConfig } from \"../contracts/transcription-model.contract\";\nimport { approximateTokenCount } from \"../utils/token-count\";\nimport type { MockSDKConfig } from \"./mock-config.type\";\nimport { MockImageModel } from \"./mock-image-model\";\nimport { MockModel } from \"./mock-model\";\nimport { MockSpeechModel } from \"./mock-speech-model\";\nimport { MockTranscriptionModel } from \"./mock-transcription-model\";\n\n/**\n * Creates a mock SDK adapter for testing — no HTTP calls, fully configurable.\n *\n * @example\n * const mock = MockSDK({\n * responses: [\n * { content: \"Hello from mock!\" },\n * { content: \"Second response\" },\n * ],\n * });\n * const model = mock.model({ name: \"gpt-4o\" });\n * const result = await model.complete([{ role: \"user\", content: \"Hi\" }]);\n * console.log(result.content); // \"Hello from mock!\"\n */\nexport function MockSDK(config: MockSDKConfig = {}): Omit<SDKAdapterContract, \"model\"> & {\n /**\n * Narrower than `SDKAdapterContract.model()` on purpose — the\n * instance really is a `MockModel`, so tests can reach `.calls` /\n * `.reset()` straight off the returned model instead of digging it\n * back out of `models`. Still satisfies the adapter contract:\n * `MockModel` implements `ModelContract`.\n */\n model(modelConfig: ModelConfig): MockModel;\n /** All model instances created by this SDK — for inspecting calls in tests */\n models: MockModel[];\n /** All image-model instances created by this SDK — for inspecting calls in tests */\n imageModels: MockImageModel[];\n /** All speech-model instances created by this SDK — for inspecting calls in tests */\n speechModels: MockSpeechModel[];\n /** All transcription-model instances created by this SDK — for inspecting calls in tests */\n transcriptionModels: MockTranscriptionModel[];\n} {\n const models: MockModel[] = [];\n const imageModels: MockImageModel[] = [];\n const speechModels: MockSpeechModel[] = [];\n const transcriptionModels: MockTranscriptionModel[] = [];\n const responses = config.responses ?? [{ content: \"Mock response\" }];\n const imageResponses = config.imageResponses ?? [{}];\n const speechResponses = config.speechResponses ?? [{}];\n const transcriptionResponses = config.transcriptionResponses ?? [{}];\n\n return {\n models,\n imageModels,\n speechModels,\n transcriptionModels,\n model(modelConfig: ModelConfig) {\n const model = new MockModel(\n modelConfig.name ?? config.defaultModelName ?? \"mock-model\",\n responses,\n config.capabilities,\n );\n models.push(model);\n return model;\n },\n image(imageConfig: ImageModelConfig) {\n const model = new MockImageModel(\n imageConfig.name ?? config.defaultModelName ?? \"mock-image-model\",\n imageResponses,\n imageConfig.pricing ?? config.imagePricing,\n );\n imageModels.push(model);\n return model;\n },\n speech(speechConfig: SpeechModelConfig) {\n const model = new MockSpeechModel(\n speechConfig.name ?? config.defaultModelName ?? \"mock-speech-model\",\n speechResponses,\n speechConfig.pricing ?? config.speechPricing,\n );\n speechModels.push(model);\n return model;\n },\n transcribe(transcribeConfig: TranscriptionModelConfig) {\n const model = new MockTranscriptionModel(\n transcribeConfig.name ?? config.defaultModelName ?? \"mock-transcription-model\",\n transcriptionResponses,\n transcribeConfig.pricing ?? config.transcriptionPricing,\n );\n transcriptionModels.push(model);\n return model;\n },\n async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,QAAQ,SAAwB,CAAC,GAiB/C;CACA,MAAM,SAAsB,CAAC;CAC7B,MAAM,cAAgC,CAAC;CACvC,MAAM,eAAkC,CAAC;CACzC,MAAM,sBAAgD,CAAC;CACvD,MAAM,YAAY,OAAO,aAAa,CAAC,EAAE,SAAS,gBAAgB,CAAC;CACnE,MAAM,iBAAiB,OAAO,kBAAkB,CAAC,CAAC,CAAC;CACnD,MAAM,kBAAkB,OAAO,mBAAmB,CAAC,CAAC,CAAC;CACrD,MAAM,yBAAyB,OAAO,0BAA0B,CAAC,CAAC,CAAC;CAEnE,OAAO;EACL;EACA;EACA;EACA;EACA,MAAM,aAA0B;GAC9B,MAAM,QAAQ,IAAI,UAChB,YAAY,QAAQ,OAAO,oBAAoB,cAC/C,WACA,OAAO,YACT;GACA,OAAO,KAAK,KAAK;GACjB,OAAO;EACT;EACA,MAAM,aAA+B;GACnC,MAAM,QAAQ,IAAI,eAChB,YAAY,QAAQ,OAAO,oBAAoB,oBAC/C,gBACA,YAAY,WAAW,OAAO,YAChC;GACA,YAAY,KAAK,KAAK;GACtB,OAAO;EACT;EACA,OAAO,cAAiC;GACtC,MAAM,QAAQ,IAAI,gBAChB,aAAa,QAAQ,OAAO,oBAAoB,qBAChD,iBACA,aAAa,WAAW,OAAO,aACjC;GACA,aAAa,KAAK,KAAK;GACvB,OAAO;EACT;EACA,WAAW,kBAA4C;GACrD,MAAM,QAAQ,IAAI,uBAChB,iBAAiB,QAAQ,OAAO,oBAAoB,4BACpD,wBACA,iBAAiB,WAAW,OAAO,oBACrC;GACA,oBAAoB,KAAK,KAAK;GAC9B,OAAO;EACT;EACA,MAAM,MAAM,MAAc,QAAkC;GAC1D,OAAO,sBAAsB,IAAI;EACnC;CACF;AACF"}
|
|
@@ -8,20 +8,34 @@ import { OrchestratorAsToolOptions, OrchestratorContract } from "../contracts/or
|
|
|
8
8
|
* Mirrors `supervisor.asTool()` — same `compositeAsTool` composition and
|
|
9
9
|
* error normalization — and adds `sessionScope`.
|
|
10
10
|
*
|
|
11
|
-
* The boundary is OPAQUE (§13, §18.6): the parent's `
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* The boundary is OPAQUE (§13, §18.6): the parent's `context` / events do
|
|
12
|
+
* NOT auto-forward. Per-call data the wrapped orchestrator needs rides on
|
|
13
|
+
* the tool's `inputSchema` payload — with ONE deliberate exception, the
|
|
14
|
+
* session binding below, because the payload is written by an LLM.
|
|
14
15
|
*
|
|
15
16
|
* Session continuity:
|
|
16
17
|
* - `"fresh"` (default) — each invocation gets a brand-new `sessionId`
|
|
17
18
|
* (a generated id) and empty history; the session lives only for this
|
|
18
19
|
* tool call. The whole validated payload is forwarded as the
|
|
19
20
|
* orchestrator's `execute(input)` argument.
|
|
20
|
-
* - `"shared"` — the
|
|
21
|
-
* `
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* - `"shared"` — the orchestrator joins an EXISTING session named by the
|
|
22
|
+
* developer through `options.session`: either a literal id fixed at
|
|
23
|
+
* construction, or a resolver that reads the invocation's
|
|
24
|
+
* {@link ToolContext} (`ctx.artifacts`, the out-of-band bag the model
|
|
25
|
+
* cannot write to). The whole validated payload is forwarded as
|
|
26
|
+
* `execute(input)`. A `"shared"` tool built without `session` throws at
|
|
27
|
+
* construction.
|
|
28
|
+
*
|
|
29
|
+
* **Why the session id is not a schema field (4.15.0 security fix).**
|
|
30
|
+
* Before this release, `"shared"` scope read `sessionId` straight out of
|
|
31
|
+
* the model-generated tool arguments. A `sessionId` is bearer-equivalent
|
|
32
|
+
* — naming one grants read/write on that session's persisted state — so
|
|
33
|
+
* any prompt injection reaching the outer agent ("continue session
|
|
34
|
+
* `<victim-id>`") made the nested orchestrator load a stranger's
|
|
35
|
+
* conversation, mutate it, and echo its content back into the attacker's
|
|
36
|
+
* transcript. The binding now lives on channels the model has no access
|
|
37
|
+
* to. The old behavior survives only behind the loudly-named
|
|
38
|
+
* `unsafeAllowModelSessionId` opt-in.
|
|
25
39
|
*
|
|
26
40
|
* On `result.error`, the typed orchestrator error is thrown so the tool
|
|
27
41
|
* wrapper produces a `ToolExecutionError` with `cause` preserved — the
|
|
@@ -29,12 +43,24 @@ import { OrchestratorAsToolOptions, OrchestratorContract } from "../contracts/or
|
|
|
29
43
|
*
|
|
30
44
|
* @example
|
|
31
45
|
* const support = ai.orchestrator({ name: "refund-support", intents });
|
|
46
|
+
*
|
|
47
|
+
* // Fresh session per call — no continuity, nothing to hijack.
|
|
32
48
|
* const supportTool = support.asTool({
|
|
33
49
|
* name: "handle_refund",
|
|
34
50
|
* description: "Handle a refund conversation end-to-end.",
|
|
35
51
|
* inputSchema: v.object({ message: v.string() }),
|
|
36
52
|
* });
|
|
37
|
-
*
|
|
53
|
+
*
|
|
54
|
+
* // Continuous session — bound from the authenticated request, never
|
|
55
|
+
* // from the model's arguments.
|
|
56
|
+
* const continuousTool = support.asTool({
|
|
57
|
+
* name: "handle_refund",
|
|
58
|
+
* inputSchema: v.object({ message: v.string() }),
|
|
59
|
+
* sessionScope: "shared",
|
|
60
|
+
* session: (ctx) => ({
|
|
61
|
+
* sessionId: String(ctx?.artifacts?.refundSessionId ?? ""),
|
|
62
|
+
* }),
|
|
63
|
+
* });
|
|
38
64
|
*/
|
|
39
65
|
declare function asTool<TOutput, TState, TToolInput>(orchestrator: OrchestratorContract<TOutput, TState>, options: OrchestratorAsToolOptions<TToolInput>): ToolContract<TToolInput, TOutput>;
|
|
40
66
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"as-tool.d.mts","names":[],"sources":["../../../../../../../ai/src/orchestrator/as-tool.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"as-tool.d.mts","names":[],"sources":["../../../../../../../ai/src/orchestrator/as-tool.ts"],"mappings":";;;;;;AA2FA;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAHnB,MAAA,8BACd,YAAA,EAAc,oBAAA,CAAqB,OAAA,EAAS,MAAA,GAC5C,OAAA,EAAS,yBAAA,CAA0B,UAAA,IAClC,YAAA,CAAa,UAAA,EAAY,OAAA"}
|
|
@@ -10,20 +10,34 @@ import { compositeAsTool } from "../tool/tool.mjs";
|
|
|
10
10
|
* Mirrors `supervisor.asTool()` — same `compositeAsTool` composition and
|
|
11
11
|
* error normalization — and adds `sessionScope`.
|
|
12
12
|
*
|
|
13
|
-
* The boundary is OPAQUE (§13, §18.6): the parent's `
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* The boundary is OPAQUE (§13, §18.6): the parent's `context` / events do
|
|
14
|
+
* NOT auto-forward. Per-call data the wrapped orchestrator needs rides on
|
|
15
|
+
* the tool's `inputSchema` payload — with ONE deliberate exception, the
|
|
16
|
+
* session binding below, because the payload is written by an LLM.
|
|
16
17
|
*
|
|
17
18
|
* Session continuity:
|
|
18
19
|
* - `"fresh"` (default) — each invocation gets a brand-new `sessionId`
|
|
19
20
|
* (a generated id) and empty history; the session lives only for this
|
|
20
21
|
* tool call. The whole validated payload is forwarded as the
|
|
21
22
|
* orchestrator's `execute(input)` argument.
|
|
22
|
-
* - `"shared"` — the
|
|
23
|
-
* `
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* - `"shared"` — the orchestrator joins an EXISTING session named by the
|
|
24
|
+
* developer through `options.session`: either a literal id fixed at
|
|
25
|
+
* construction, or a resolver that reads the invocation's
|
|
26
|
+
* {@link ToolContext} (`ctx.artifacts`, the out-of-band bag the model
|
|
27
|
+
* cannot write to). The whole validated payload is forwarded as
|
|
28
|
+
* `execute(input)`. A `"shared"` tool built without `session` throws at
|
|
29
|
+
* construction.
|
|
30
|
+
*
|
|
31
|
+
* **Why the session id is not a schema field (4.15.0 security fix).**
|
|
32
|
+
* Before this release, `"shared"` scope read `sessionId` straight out of
|
|
33
|
+
* the model-generated tool arguments. A `sessionId` is bearer-equivalent
|
|
34
|
+
* — naming one grants read/write on that session's persisted state — so
|
|
35
|
+
* any prompt injection reaching the outer agent ("continue session
|
|
36
|
+
* `<victim-id>`") made the nested orchestrator load a stranger's
|
|
37
|
+
* conversation, mutate it, and echo its content back into the attacker's
|
|
38
|
+
* transcript. The binding now lives on channels the model has no access
|
|
39
|
+
* to. The old behavior survives only behind the loudly-named
|
|
40
|
+
* `unsafeAllowModelSessionId` opt-in.
|
|
27
41
|
*
|
|
28
42
|
* On `result.error`, the typed orchestrator error is thrown so the tool
|
|
29
43
|
* wrapper produces a `ToolExecutionError` with `cause` preserved — the
|
|
@@ -31,22 +45,36 @@ import { compositeAsTool } from "../tool/tool.mjs";
|
|
|
31
45
|
*
|
|
32
46
|
* @example
|
|
33
47
|
* const support = ai.orchestrator({ name: "refund-support", intents });
|
|
48
|
+
*
|
|
49
|
+
* // Fresh session per call — no continuity, nothing to hijack.
|
|
34
50
|
* const supportTool = support.asTool({
|
|
35
51
|
* name: "handle_refund",
|
|
36
52
|
* description: "Handle a refund conversation end-to-end.",
|
|
37
53
|
* inputSchema: v.object({ message: v.string() }),
|
|
38
54
|
* });
|
|
39
|
-
*
|
|
55
|
+
*
|
|
56
|
+
* // Continuous session — bound from the authenticated request, never
|
|
57
|
+
* // from the model's arguments.
|
|
58
|
+
* const continuousTool = support.asTool({
|
|
59
|
+
* name: "handle_refund",
|
|
60
|
+
* inputSchema: v.object({ message: v.string() }),
|
|
61
|
+
* sessionScope: "shared",
|
|
62
|
+
* session: (ctx) => ({
|
|
63
|
+
* sessionId: String(ctx?.artifacts?.refundSessionId ?? ""),
|
|
64
|
+
* }),
|
|
65
|
+
* });
|
|
40
66
|
*/
|
|
41
67
|
function asTool(orchestrator, options) {
|
|
42
68
|
if (!orchestrator.name || typeof orchestrator.name !== "string") throw new SupervisorFailedError("orchestrator.asTool(): orchestrator must have a `name` to be wrapped as a tool");
|
|
43
69
|
const sessionScope = options.sessionScope ?? "fresh";
|
|
70
|
+
const allowModelSessionId = options.unsafeAllowModelSessionId === true;
|
|
71
|
+
if (sessionScope === "shared" && !options.session && !allowModelSessionId) throw new SupervisorFailedError("orchestrator.asTool(): sessionScope \"shared\" requires a `session` binding — a session id fixed at construction, or a `(ctx) => sessionId` resolver reading the tool context. A model-supplied `sessionId` in the tool payload is bearer-equivalent access to that session; pass `unsafeAllowModelSessionId: true` only if the outer agent's context is trusted and you verify session ownership yourself");
|
|
44
72
|
return compositeAsTool({
|
|
45
73
|
name: options.name ?? orchestrator.name,
|
|
46
74
|
description: options.description ?? `Invoke orchestrator "${orchestrator.name}" as a tool.`,
|
|
47
75
|
input: options.inputSchema,
|
|
48
|
-
execute: async (input) => {
|
|
49
|
-
const { sessionId, history, executeInput } = resolveSession(sessionScope, input);
|
|
76
|
+
execute: async (input, ctx) => {
|
|
77
|
+
const { sessionId, history, executeInput } = await resolveSession(sessionScope, input, ctx, options.session, allowModelSessionId);
|
|
50
78
|
const result = await orchestrator.execute(executeInput, {
|
|
51
79
|
sessionId,
|
|
52
80
|
history
|
|
@@ -62,21 +90,41 @@ function asTool(orchestrator, options) {
|
|
|
62
90
|
}
|
|
63
91
|
/**
|
|
64
92
|
* Resolve the per-call `sessionId`, `history`, and the `execute(input)`
|
|
65
|
-
* argument
|
|
93
|
+
* argument, according to `sessionScope`.
|
|
94
|
+
*
|
|
95
|
+
* For `"shared"` scope the session comes from the developer's `session`
|
|
96
|
+
* binding (construction-time literal or `ToolContext` resolver) — the
|
|
97
|
+
* validated payload is never consulted for it unless the caller opted
|
|
98
|
+
* into `unsafeAllowModelSessionId`. Either way `sessionId` / `history`
|
|
99
|
+
* are stripped from the payload before it is forwarded as
|
|
100
|
+
* `execute(input)`, so a model-authored field of that name can't reach
|
|
101
|
+
* the orchestrator's input under a misleading name.
|
|
66
102
|
*/
|
|
67
|
-
function resolveSession(sessionScope, input) {
|
|
103
|
+
async function resolveSession(sessionScope, input, ctx, session, allowModelSessionId) {
|
|
68
104
|
if (sessionScope === "fresh") return {
|
|
69
105
|
sessionId: generateRunId("session"),
|
|
70
106
|
history: [],
|
|
71
107
|
executeInput: coerceInput(input)
|
|
72
108
|
};
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
109
|
+
const { sessionId: payloadSessionId, history: payloadHistory, ...rest } = typeof input === "object" && input !== null ? input : {};
|
|
110
|
+
const executeInput = coerceInput(rest);
|
|
111
|
+
if (session !== void 0) {
|
|
112
|
+
const bound = typeof session === "function" ? await session(ctx) : session;
|
|
113
|
+
const sessionId = typeof bound === "string" ? bound : bound?.sessionId;
|
|
114
|
+
const history = typeof bound === "string" ? void 0 : bound?.history;
|
|
115
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) throw new SupervisorFailedError("orchestrator.asTool(): the `session` binding for sessionScope \"shared\" resolved to no session id — return a non-empty string (or `{ sessionId }`) from it, or throw to reject the call. The model's payload is never used as a fallback");
|
|
116
|
+
return {
|
|
117
|
+
sessionId,
|
|
118
|
+
history: Array.isArray(history) ? history : [],
|
|
119
|
+
executeInput
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (!allowModelSessionId) throw new SupervisorFailedError("orchestrator.asTool(): sessionScope \"shared\" requires a `session` binding");
|
|
123
|
+
if (typeof payloadSessionId !== "string" || payloadSessionId.length === 0) throw new SupervisorFailedError("orchestrator.asTool(): sessionScope \"shared\" requires a `sessionId` string in the tool input payload");
|
|
76
124
|
return {
|
|
77
|
-
sessionId,
|
|
78
|
-
history: Array.isArray(
|
|
79
|
-
executeInput
|
|
125
|
+
sessionId: payloadSessionId,
|
|
126
|
+
history: Array.isArray(payloadHistory) ? payloadHistory : [],
|
|
127
|
+
executeInput
|
|
80
128
|
};
|
|
81
129
|
}
|
|
82
130
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"as-tool.mjs","names":[],"sources":["../../../../../../../ai/src/orchestrator/as-tool.ts"],"sourcesContent":["import type { Message } from \"../contracts/conversation-message.type\";\nimport type {\n OrchestratorAsToolOptions,\n OrchestratorContract,\n} from \"../contracts/orchestrator/orchestrator.contract\";\nimport type { SupervisorInput } from \"../contracts/supervisor/supervisor-input.type\";\nimport { SupervisorFailedError } from \"../errors\";\nimport { compositeAsTool, type ToolContract } from \"../tool/tool\";\nimport { generateRunId } from \"../utils/generate-run-id\";\n\n/**\n * Shape the orchestrator looks for inside the validated tool input when\n * `sessionScope: \"shared\"` — the parent must thread the session id (and\n * optionally the prior history) through the tool's `inputSchema`\n * payload, since the boundary is opaque (§13). Everything else on the\n * payload becomes the orchestrator's `execute(input)` argument.\n */\ntype SharedScopePayload = {\n sessionId?: unknown;\n history?: unknown;\n [key: string]: unknown;\n};\n\n/**\n * Wrap an {@link OrchestratorContract} as a {@link ToolContract} so an\n * outer agent can invoke it from its tool-call loop (design §13).\n * Mirrors `supervisor.asTool()` — same `compositeAsTool` composition and\n * error normalization — and adds `sessionScope`.\n *\n * The boundary is OPAQUE (§13, §18.6): the parent's `signal` / `context`\n * / events do NOT auto-forward. Anything the wrapped orchestrator needs\n * per call must ride on the tool's `inputSchema` payload.\n *\n * Session continuity:\n * - `\"fresh\"` (default) — each invocation gets a brand-new `sessionId`\n * (a generated id) and empty history; the session lives only for this\n * tool call. The whole validated payload is forwarded as the\n * orchestrator's `execute(input)` argument.\n * - `\"shared\"` — the parent supplies `sessionId` (and optionally\n * `history`) inside the validated payload; the orchestrator\n * participates in that session. The remaining payload fields are\n * forwarded as `execute(input)`. A missing/blank `sessionId` throws\n * {@link SupervisorFailedError}.\n *\n * On `result.error`, the typed orchestrator error is thrown so the tool\n * wrapper produces a `ToolExecutionError` with `cause` preserved — the\n * outer agent sees one uniform error class.\n *\n * @example\n * const support = ai.orchestrator({ name: \"refund-support\", intents });\n * const supportTool = support.asTool({\n * name: \"handle_refund\",\n * description: \"Handle a refund conversation end-to-end.\",\n * inputSchema: v.object({ message: v.string() }),\n * });\n * const concierge = ai.agent({ model, tools: [supportTool] });\n */\nexport function asTool<TOutput, TState, TToolInput>(\n orchestrator: OrchestratorContract<TOutput, TState>,\n options: OrchestratorAsToolOptions<TToolInput>,\n): ToolContract<TToolInput, TOutput> {\n if (!orchestrator.name || typeof orchestrator.name !== \"string\") {\n throw new SupervisorFailedError(\n \"orchestrator.asTool(): orchestrator must have a `name` to be wrapped as a tool\",\n );\n }\n\n const sessionScope = options.sessionScope ?? \"fresh\";\n\n return compositeAsTool<TToolInput, TOutput>({\n name: options.name ?? orchestrator.name,\n description:\n options.description ??\n `Invoke orchestrator \"${orchestrator.name}\" as a tool.`,\n input: options.inputSchema,\n execute: async (input) => {\n const { sessionId, history, executeInput } = resolveSession(\n sessionScope,\n input,\n );\n\n const result = await orchestrator.execute(executeInput, {\n sessionId,\n history,\n });\n\n if (result.error) {\n // Surface the typed orchestrator error — the outer ToolContract\n // wraps it as a ToolExecutionError with `cause` preserved.\n throw result.error;\n }\n\n return {\n data: result.data as TOutput,\n usage: result.usage,\n report: result.report,\n };\n },\n });\n}\n\n/**\n * Resolve the per-call `sessionId`, `history`, and the `execute(input)`\n * argument from the validated tool payload, according to `sessionScope`.\n */\nfunction resolveSession(\n sessionScope: \"fresh\" | \"shared\",\n input: unknown,\n): { sessionId: string; history: Message[]; executeInput: SupervisorInput } {\n if (sessionScope === \"fresh\") {\n return {\n sessionId: generateRunId(\"session\"),\n history: [],\n executeInput: coerceInput(input),\n };\n }\n\n const payload = (\n typeof input === \"object\" && input !== null ? input : {}\n ) as SharedScopePayload;\n\n if (typeof payload.sessionId !== \"string\" || payload.sessionId.length === 0) {\n throw new SupervisorFailedError(\n 'orchestrator.asTool(): sessionScope \"shared\" requires a `sessionId` string in the tool input payload',\n );\n }\n\n const { sessionId, history, ...rest } = payload;\n\n return {\n sessionId,\n history: Array.isArray(history) ? (history as Message[]) : [],\n executeInput: coerceInput(rest),\n };\n}\n\n/**\n * Coerce a tool-input value into the `SupervisorInput` shape the\n * orchestrator's `execute()` accepts (`string | Record<string,\n * unknown>`). Strings and plain objects pass through; everything else\n * is JSON-stringified so the orchestrator receives a predictable input\n * regardless of how the outer agent shaped its call.\n */\nfunction coerceInput(value: unknown): SupervisorInput {\n if (typeof value === \"string\") {\n return value;\n }\n\n if (typeof value === \"object\" && value !== null) {\n return value as Record<string, unknown>;\n }\n\n if (value === undefined || value === null) {\n return \"\";\n }\n\n return String(value);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,SAAgB,OACd,cACA,SACmC;CACnC,IAAI,CAAC,aAAa,QAAQ,OAAO,aAAa,SAAS,UACrD,MAAM,IAAI,sBACR,gFACF;CAGF,MAAM,eAAe,QAAQ,gBAAgB;CAE7C,OAAO,gBAAqC;EAC1C,MAAM,QAAQ,QAAQ,aAAa;EACnC,aACE,QAAQ,eACR,wBAAwB,aAAa,KAAK;EAC5C,OAAO,QAAQ;EACf,SAAS,OAAO,UAAU;GACxB,MAAM,EAAE,WAAW,SAAS,iBAAiB,eAC3C,cACA,KACF;GAEA,MAAM,SAAS,MAAM,aAAa,QAAQ,cAAc;IACtD;IACA;GACF,CAAC;GAED,IAAI,OAAO,OAGT,MAAM,OAAO;GAGf,OAAO;IACL,MAAM,OAAO;IACb,OAAO,OAAO;IACd,QAAQ,OAAO;GACjB;EACF;CACF,CAAC;AACH;;;;;AAMA,SAAS,eACP,cACA,OAC0E;CAC1E,IAAI,iBAAiB,SACnB,OAAO;EACL,WAAW,cAAc,SAAS;EAClC,SAAS,CAAC;EACV,cAAc,YAAY,KAAK;CACjC;CAGF,MAAM,UACJ,OAAO,UAAU,YAAY,UAAU,OAAO,QAAQ,CAAC;CAGzD,IAAI,OAAO,QAAQ,cAAc,YAAY,QAAQ,UAAU,WAAW,GACxE,MAAM,IAAI,sBACR,wGACF;CAGF,MAAM,EAAE,WAAW,SAAS,GAAG,SAAS;CAExC,OAAO;EACL;EACA,SAAS,MAAM,QAAQ,OAAO,IAAK,UAAwB,CAAC;EAC5D,cAAc,YAAY,IAAI;CAChC;AACF;;;;;;;;AASA,SAAS,YAAY,OAAiC;CACpD,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAGT,IAAI,UAAU,UAAa,UAAU,MACnC,OAAO;CAGT,OAAO,OAAO,KAAK;AACrB"}
|
|
1
|
+
{"version":3,"file":"as-tool.mjs","names":[],"sources":["../../../../../../../ai/src/orchestrator/as-tool.ts"],"sourcesContent":["import type { Message } from \"../contracts/conversation-message.type\";\nimport type {\n OrchestratorAsToolOptions,\n OrchestratorContract,\n OrchestratorToolSession,\n} from \"../contracts/orchestrator/orchestrator.contract\";\nimport type { SupervisorInput } from \"../contracts/supervisor/supervisor-input.type\";\nimport type { ToolContext } from \"../contracts/tool.contract\";\nimport { SupervisorFailedError } from \"../errors\";\nimport { compositeAsTool, type ToolContract } from \"../tool/tool\";\nimport { generateRunId } from \"../utils/generate-run-id\";\n\n/**\n * Shape read out of the validated tool input ONLY under the\n * `unsafeAllowModelSessionId` opt-in — the legacy, model-chosen session\n * path. Everything else on the payload becomes the orchestrator's\n * `execute(input)` argument.\n */\ntype SharedScopePayload = {\n sessionId?: unknown;\n history?: unknown;\n [key: string]: unknown;\n};\n\n/** Resolved per-call session binding for one tool invocation. */\ntype ResolvedToolSession = {\n sessionId: string;\n history: Message[];\n executeInput: SupervisorInput;\n};\n\n/**\n * Wrap an {@link OrchestratorContract} as a {@link ToolContract} so an\n * outer agent can invoke it from its tool-call loop (design §13).\n * Mirrors `supervisor.asTool()` — same `compositeAsTool` composition and\n * error normalization — and adds `sessionScope`.\n *\n * The boundary is OPAQUE (§13, §18.6): the parent's `context` / events do\n * NOT auto-forward. Per-call data the wrapped orchestrator needs rides on\n * the tool's `inputSchema` payload — with ONE deliberate exception, the\n * session binding below, because the payload is written by an LLM.\n *\n * Session continuity:\n * - `\"fresh\"` (default) — each invocation gets a brand-new `sessionId`\n * (a generated id) and empty history; the session lives only for this\n * tool call. The whole validated payload is forwarded as the\n * orchestrator's `execute(input)` argument.\n * - `\"shared\"` — the orchestrator joins an EXISTING session named by the\n * developer through `options.session`: either a literal id fixed at\n * construction, or a resolver that reads the invocation's\n * {@link ToolContext} (`ctx.artifacts`, the out-of-band bag the model\n * cannot write to). The whole validated payload is forwarded as\n * `execute(input)`. A `\"shared\"` tool built without `session` throws at\n * construction.\n *\n * **Why the session id is not a schema field (4.15.0 security fix).**\n * Before this release, `\"shared\"` scope read `sessionId` straight out of\n * the model-generated tool arguments. A `sessionId` is bearer-equivalent\n * — naming one grants read/write on that session's persisted state — so\n * any prompt injection reaching the outer agent (\"continue session\n * `<victim-id>`\") made the nested orchestrator load a stranger's\n * conversation, mutate it, and echo its content back into the attacker's\n * transcript. The binding now lives on channels the model has no access\n * to. The old behavior survives only behind the loudly-named\n * `unsafeAllowModelSessionId` opt-in.\n *\n * On `result.error`, the typed orchestrator error is thrown so the tool\n * wrapper produces a `ToolExecutionError` with `cause` preserved — the\n * outer agent sees one uniform error class.\n *\n * @example\n * const support = ai.orchestrator({ name: \"refund-support\", intents });\n *\n * // Fresh session per call — no continuity, nothing to hijack.\n * const supportTool = support.asTool({\n * name: \"handle_refund\",\n * description: \"Handle a refund conversation end-to-end.\",\n * inputSchema: v.object({ message: v.string() }),\n * });\n *\n * // Continuous session — bound from the authenticated request, never\n * // from the model's arguments.\n * const continuousTool = support.asTool({\n * name: \"handle_refund\",\n * inputSchema: v.object({ message: v.string() }),\n * sessionScope: \"shared\",\n * session: (ctx) => ({\n * sessionId: String(ctx?.artifacts?.refundSessionId ?? \"\"),\n * }),\n * });\n */\nexport function asTool<TOutput, TState, TToolInput>(\n orchestrator: OrchestratorContract<TOutput, TState>,\n options: OrchestratorAsToolOptions<TToolInput>,\n): ToolContract<TToolInput, TOutput> {\n if (!orchestrator.name || typeof orchestrator.name !== \"string\") {\n throw new SupervisorFailedError(\n \"orchestrator.asTool(): orchestrator must have a `name` to be wrapped as a tool\",\n );\n }\n\n const sessionScope = options.sessionScope ?? \"fresh\";\n const allowModelSessionId = options.unsafeAllowModelSessionId === true;\n\n // Fail closed at construction, not at the first hostile tool call: a\n // \"shared\" tool with no developer-supplied binding would have to fall\n // back to the model's payload, which is exactly the hijack path.\n if (sessionScope === \"shared\" && !options.session && !allowModelSessionId) {\n throw new SupervisorFailedError(\n 'orchestrator.asTool(): sessionScope \"shared\" requires a `session` binding — ' +\n \"a session id fixed at construction, or a `(ctx) => sessionId` resolver reading the \" +\n \"tool context. A model-supplied `sessionId` in the tool payload is bearer-equivalent \" +\n \"access to that session; pass `unsafeAllowModelSessionId: true` only if the outer \" +\n \"agent's context is trusted and you verify session ownership yourself\",\n );\n }\n\n return compositeAsTool<TToolInput, TOutput>({\n name: options.name ?? orchestrator.name,\n description:\n options.description ??\n `Invoke orchestrator \"${orchestrator.name}\" as a tool.`,\n input: options.inputSchema,\n execute: async (input, ctx) => {\n const { sessionId, history, executeInput } = await resolveSession(\n sessionScope,\n input,\n ctx,\n options.session,\n allowModelSessionId,\n );\n\n const result = await orchestrator.execute(executeInput, {\n sessionId,\n history,\n });\n\n if (result.error) {\n // Surface the typed orchestrator error — the outer ToolContract\n // wraps it as a ToolExecutionError with `cause` preserved.\n throw result.error;\n }\n\n return {\n data: result.data as TOutput,\n usage: result.usage,\n report: result.report,\n };\n },\n });\n}\n\n/**\n * Resolve the per-call `sessionId`, `history`, and the `execute(input)`\n * argument, according to `sessionScope`.\n *\n * For `\"shared\"` scope the session comes from the developer's `session`\n * binding (construction-time literal or `ToolContext` resolver) — the\n * validated payload is never consulted for it unless the caller opted\n * into `unsafeAllowModelSessionId`. Either way `sessionId` / `history`\n * are stripped from the payload before it is forwarded as\n * `execute(input)`, so a model-authored field of that name can't reach\n * the orchestrator's input under a misleading name.\n */\nasync function resolveSession(\n sessionScope: \"fresh\" | \"shared\",\n input: unknown,\n ctx: ToolContext | undefined,\n session: OrchestratorToolSession | undefined,\n allowModelSessionId: boolean,\n): Promise<ResolvedToolSession> {\n if (sessionScope === \"fresh\") {\n return {\n sessionId: generateRunId(\"session\"),\n history: [],\n executeInput: coerceInput(input),\n };\n }\n\n const payload = (\n typeof input === \"object\" && input !== null ? input : {}\n ) as SharedScopePayload;\n\n const { sessionId: payloadSessionId, history: payloadHistory, ...rest } = payload;\n const executeInput = coerceInput(rest);\n\n if (session !== undefined) {\n const bound = typeof session === \"function\" ? await session(ctx) : session;\n\n const sessionId = typeof bound === \"string\" ? bound : bound?.sessionId;\n const history = typeof bound === \"string\" ? undefined : bound?.history;\n\n if (typeof sessionId !== \"string\" || sessionId.length === 0) {\n throw new SupervisorFailedError(\n 'orchestrator.asTool(): the `session` binding for sessionScope \"shared\" resolved to no ' +\n \"session id — return a non-empty string (or `{ sessionId }`) from it, or throw to \" +\n \"reject the call. The model's payload is never used as a fallback\",\n );\n }\n\n return {\n sessionId,\n history: Array.isArray(history) ? history : [],\n executeInput,\n };\n }\n\n // Legacy, explicitly opted-in path: the session id is whatever the\n // calling model wrote. Anything that can influence that model chooses\n // the session — see `unsafeAllowModelSessionId`.\n if (!allowModelSessionId) {\n throw new SupervisorFailedError(\n 'orchestrator.asTool(): sessionScope \"shared\" requires a `session` binding',\n );\n }\n\n if (typeof payloadSessionId !== \"string\" || payloadSessionId.length === 0) {\n throw new SupervisorFailedError(\n 'orchestrator.asTool(): sessionScope \"shared\" requires a `sessionId` string in the tool input payload',\n );\n }\n\n return {\n sessionId: payloadSessionId,\n history: Array.isArray(payloadHistory) ? (payloadHistory as Message[]) : [],\n executeInput,\n };\n}\n\n/**\n * Coerce a tool-input value into the `SupervisorInput` shape the\n * orchestrator's `execute()` accepts (`string | Record<string,\n * unknown>`). Strings and plain objects pass through; everything else\n * is JSON-stringified so the orchestrator receives a predictable input\n * regardless of how the outer agent shaped its call.\n */\nfunction coerceInput(value: unknown): SupervisorInput {\n if (typeof value === \"string\") {\n return value;\n }\n\n if (typeof value === \"object\" && value !== null) {\n return value as Record<string, unknown>;\n }\n\n if (value === undefined || value === null) {\n return \"\";\n }\n\n return String(value);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2FA,SAAgB,OACd,cACA,SACmC;CACnC,IAAI,CAAC,aAAa,QAAQ,OAAO,aAAa,SAAS,UACrD,MAAM,IAAI,sBACR,gFACF;CAGF,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,sBAAsB,QAAQ,8BAA8B;CAKlE,IAAI,iBAAiB,YAAY,CAAC,QAAQ,WAAW,CAAC,qBACpD,MAAM,IAAI,sBACR,4YAKF;CAGF,OAAO,gBAAqC;EAC1C,MAAM,QAAQ,QAAQ,aAAa;EACnC,aACE,QAAQ,eACR,wBAAwB,aAAa,KAAK;EAC5C,OAAO,QAAQ;EACf,SAAS,OAAO,OAAO,QAAQ;GAC7B,MAAM,EAAE,WAAW,SAAS,iBAAiB,MAAM,eACjD,cACA,OACA,KACA,QAAQ,SACR,mBACF;GAEA,MAAM,SAAS,MAAM,aAAa,QAAQ,cAAc;IACtD;IACA;GACF,CAAC;GAED,IAAI,OAAO,OAGT,MAAM,OAAO;GAGf,OAAO;IACL,MAAM,OAAO;IACb,OAAO,OAAO;IACd,QAAQ,OAAO;GACjB;EACF;CACF,CAAC;AACH;;;;;;;;;;;;;AAcA,eAAe,eACb,cACA,OACA,KACA,SACA,qBAC8B;CAC9B,IAAI,iBAAiB,SACnB,OAAO;EACL,WAAW,cAAc,SAAS;EAClC,SAAS,CAAC;EACV,cAAc,YAAY,KAAK;CACjC;CAOF,MAAM,EAAE,WAAW,kBAAkB,SAAS,gBAAgB,GAAG,SAH/D,OAAO,UAAU,YAAY,UAAU,OAAO,QAAQ,CAAC;CAIzD,MAAM,eAAe,YAAY,IAAI;CAErC,IAAI,YAAY,QAAW;EACzB,MAAM,QAAQ,OAAO,YAAY,aAAa,MAAM,QAAQ,GAAG,IAAI;EAEnE,MAAM,YAAY,OAAO,UAAU,WAAW,QAAQ,OAAO;EAC7D,MAAM,UAAU,OAAO,UAAU,WAAW,SAAY,OAAO;EAE/D,IAAI,OAAO,cAAc,YAAY,UAAU,WAAW,GACxD,MAAM,IAAI,sBACR,2OAGF;EAGF,OAAO;GACL;GACA,SAAS,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC;GAC7C;EACF;CACF;CAKA,IAAI,CAAC,qBACH,MAAM,IAAI,sBACR,6EACF;CAGF,IAAI,OAAO,qBAAqB,YAAY,iBAAiB,WAAW,GACtE,MAAM,IAAI,sBACR,wGACF;CAGF,OAAO;EACL,WAAW;EACX,SAAS,MAAM,QAAQ,cAAc,IAAK,iBAA+B,CAAC;EAC1E;CACF;AACF;;;;;;;;AASA,SAAS,YAAY,OAAiC;CACpD,IAAI,OAAO,UAAU,UACnB,OAAO;CAGT,IAAI,OAAO,UAAU,YAAY,UAAU,MACzC,OAAO;CAGT,IAAI,UAAU,UAAa,UAAU,MACnC,OAAO;CAGT,OAAO,OAAO,KAAK;AACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.d.mts","names":[],"sources":["../../../../../../../ai/src/orchestrator/execution.ts"],"mappings":";;;;;;;;;;;;;;AAqEA;;;;;;;;;;;KAAY,2BAAA;EACV,MAAA,EAAQ,kBAAA,CAAmB,OAAA,EAAS,MAAA,GAOY;EALhD,OAAA,GAAU,GAAA,SAAY,mBAAA;EACtB,SAAA;EACA,OAAA,EAAS,mBAAA;EACT,KAAA,GAAQ,eAAA;EACR,OAAA,GAAU,0BAAA,CAA2B,MAAA;EACrC,gBAAA,GAAmB,4BAAA,CAA6B,kBAAA,CAAmB,OAAA;EACnE,eAAA;EACA,aAAA,GAAgB,yBAAA;AAAA;;;;;;;;;;;;;;;;;;;;cAsBL,qBAAA;EAAA,iBACM,MAAA;EAAA,iBACA,GAAA;EAAA,iBACA,gBAAA;cAIE,MAAA,EAAQ,2BAAA,CAA4B,OAAA,EAAS,MAAA;EAAT;;;;;;EAyB1C,GAAA,IAAO,OAAA,CAAQ,kBAAA,CAAmB,OAAA;EAiChB;;;;EAAlB,MAAA,IAAU,OAAA,CAAQ,kBAAA,CAAmB,OAAA;EAiBxC;;;;;EAFG,OAAA,CACX,IAAA,EAAM,oBAAA,sBACL,OAAA,CAAQ,oBAAA;AAAA;;;;;;;;;;;;iBAuPS,OAAA,kBACpB,GAAA,EAAK,yBAAA,CAA0B,OAAA,EAAS,MAAA,GACxC,KAAA,EAAO,eAAA,EACP,OAAA,EAAS,0BAAA,CAA2B,MAAA,IACnC,OAAA,CAAQ,kBAAA,CAAmB,OAAA;;;;;;;;AA3PG;AAuPjC;;
|
|
1
|
+
{"version":3,"file":"execution.d.mts","names":[],"sources":["../../../../../../../ai/src/orchestrator/execution.ts"],"mappings":";;;;;;;;;;;;;;AAqEA;;;;;;;;;;;KAAY,2BAAA;EACV,MAAA,EAAQ,kBAAA,CAAmB,OAAA,EAAS,MAAA,GAOY;EALhD,OAAA,GAAU,GAAA,SAAY,mBAAA;EACtB,SAAA;EACA,OAAA,EAAS,mBAAA;EACT,KAAA,GAAQ,eAAA;EACR,OAAA,GAAU,0BAAA,CAA2B,MAAA;EACrC,gBAAA,GAAmB,4BAAA,CAA6B,kBAAA,CAAmB,OAAA;EACnE,eAAA;EACA,aAAA,GAAgB,yBAAA;AAAA;;;;;;;;;;;;;;;;;;;;cAsBL,qBAAA;EAAA,iBACM,MAAA;EAAA,iBACA,GAAA;EAAA,iBACA,gBAAA;cAIE,MAAA,EAAQ,2BAAA,CAA4B,OAAA,EAAS,MAAA;EAAT;;;;;;EAyB1C,GAAA,IAAO,OAAA,CAAQ,kBAAA,CAAmB,OAAA;EAiChB;;;;EAAlB,MAAA,IAAU,OAAA,CAAQ,kBAAA,CAAmB,OAAA;EAiBxC;;;;;EAFG,OAAA,CACX,IAAA,EAAM,oBAAA,sBACL,OAAA,CAAQ,oBAAA;AAAA;;;;;;;;;;;;iBAuPS,OAAA,kBACpB,GAAA,EAAK,yBAAA,CAA0B,OAAA,EAAS,MAAA,GACxC,KAAA,EAAO,eAAA,EACP,OAAA,EAAS,0BAAA,CAA2B,MAAA,IACnC,OAAA,CAAQ,kBAAA,CAAmB,OAAA;;;;;;;;AA3PG;AAuPjC;;iBAiNsB,SAAA,kBACpB,GAAA,EAAK,yBAAA,CAA0B,OAAA,EAAS,MAAA,GACxC,SAAA,UACA,OAAA,GAAU,yBAAA,GACT,OAAA,CAAQ,kBAAA,CAAmB,OAAA;;;;;;;;;;;iBAiDR,UAAA,kBACpB,GAAA,EAAK,yBAAA,CAA0B,OAAA,EAAS,MAAA,GACxC,KAAA,EAAO,eAAA,EACP,OAAA,EAAS,0BAAA,CAA2B,MAAA,IACnC,OAAA,CAAQ,kBAAA,CAAmB,OAAA"}
|
|
@@ -280,7 +280,7 @@ async function runTurn(ctx, input, options) {
|
|
|
280
280
|
const seedState = applyStatePatch(loaded.state, options.state);
|
|
281
281
|
let turnContext = options.context;
|
|
282
282
|
if (ctx.memory) {
|
|
283
|
-
const recalled = await recallForTurn(ctx.memory, input);
|
|
283
|
+
const recalled = await recallForTurn(ctx.memory, input, sessionId);
|
|
284
284
|
turnContext = injectMemories(turnContext, ctx.memory, recalled);
|
|
285
285
|
}
|
|
286
286
|
const { result, state, turnSnapshot } = await dispatchTurn({
|
|
@@ -320,7 +320,7 @@ async function runTurn(ctx, input, options) {
|
|
|
320
320
|
lastRoute: summarizeRoute(turnSnapshot.decision.raw),
|
|
321
321
|
summarizedThrough: loaded.record?.summarized_through ?? null
|
|
322
322
|
});
|
|
323
|
-
if (ctx.memory) await rememberTurnOutcome(ctx.memory, input, outcomeTextFromTurn(result.data, turnSnapshot));
|
|
323
|
+
if (ctx.memory) await rememberTurnOutcome(ctx.memory, input, outcomeTextFromTurn(result.data, turnSnapshot), sessionId);
|
|
324
324
|
let compaction;
|
|
325
325
|
if (shouldCompact(ctx, loaded.turnIndex)) {
|
|
326
326
|
const outcome = await runCompaction(ctx, sessionId, options.history);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execution.mjs","names":[],"sources":["../../../../../../../ai/src/orchestrator/execution.ts"],"sourcesContent":["import type { Message } from \"../contracts/conversation-message.type\";\nimport type { OrchestratorCommands } from \"../contracts/orchestrator/orchestrator-commands.type\";\nimport type { OrchestratorConfig } from \"../contracts/orchestrator/orchestrator-config.type\";\nimport type {\n OrchestratorEvent,\n OrchestratorEventHandlers,\n OrchestratorEventMap,\n OrchestratorEventName,\n} from \"../contracts/orchestrator/orchestrator-event.type\";\nimport type {\n OrchestratorExecuteOptions,\n OrchestratorResumeOptions,\n} from \"../contracts/orchestrator/orchestrator-execute-options.type\";\nimport type {\n CompactionResult,\n OrchestratorReport,\n OrchestratorReportStatus,\n OrchestratorResult,\n TurnSnapshot,\n} from \"../contracts/result/orchestrator-result.type\";\nimport { REPORT_SCHEMA_VERSION } from \"../contracts/result/base-report.type\";\nimport type { BaseReport } from \"../contracts/result/base-report.type\";\nimport type { Usage } from \"../contracts/result/usage.type\";\nimport type { SupervisorInput } from \"../contracts/supervisor/supervisor-input.type\";\nimport type { EventIdentity } from \"../contracts/events/event-identity.type\";\nimport {\n resolveDefaultCheckpointStore,\n resolveDefaultSnapshotStore,\n} from \"../config\";\nimport type { AIError } from \"../errors/ai-error\";\nimport { OrchestratorConfigError, OrchestratorDriftError } from \"../errors\";\nimport { notifyObservers } from \"../observe/resolve-observers\";\nimport type { ResolvedIntentEntry } from \"../supervisor/entries\";\nimport { generateRunId } from \"../utils/generate-run-id\";\nimport { persistCheckpoint, summarizeRoute } from \"./checkpoint\";\nimport { runCompaction, runManualCompaction, shouldCompact } from \"./compaction\";\nimport { deriveRunId, dispatchTurn } from \"./dispatch\";\nimport type { OrchestratorEmitter } from \"./emitter\";\nimport type { OrchestratorEmitterLike } from \"./emitter-port.type\";\nimport type { OrchestratorEngineContext } from \"./engine-context.type\";\nimport { acquireLock } from \"./lock\";\nimport { loadSession } from \"./load\";\nimport {\n injectMemories,\n outcomeTextFromTurn,\n recallForTurn,\n rememberTurnOutcome,\n resolveOrchestratorMemory,\n} from \"./memory\";\nimport type { OrchestratorStreamController } from \"./orchestrator-stream\";\nimport { resolveResume } from \"./resume\";\nimport { windowHistory } from \"./window\";\n\n/** Empty rolled-up usage for turns that never dispatched (drift/seed). */\nconst ZERO_USAGE: Usage = { input: 0, output: 0, total: 0 };\n\n/**\n * Constructor params the C1 factory passes when building an\n * {@link OrchestratorExecution} per call. The factory owns author-time\n * validation, intent-entry resolution, and signature computation; it\n * hands the engine the validated `config`, the resolved `entries`, the\n * computed `signature`, and the shared three-tier `emitter`. The\n * per-call inputs vary by entry point:\n *\n * - `execute` / `stream` — `input` + `options` (and `streamController`\n * for `stream`).\n * - `resume` — `resumeSessionId` + `resumeOptions`.\n * - `command(\"compact\")` — neither; `compact(args)` carries its own.\n */\nexport type OrchestratorExecutionParams<TOutput, TState> = {\n config: OrchestratorConfig<TOutput, TState>;\n /** Resolved intent entries (validated by C1; the engine delegates dispatch to the supervisor). */\n entries?: Map<string, ResolvedIntentEntry>;\n signature: string;\n emitter: OrchestratorEmitter;\n input?: SupervisorInput;\n options?: OrchestratorExecuteOptions<TState>;\n streamController?: OrchestratorStreamController<OrchestratorResult<TOutput>>;\n resumeSessionId?: string;\n resumeOptions?: OrchestratorResumeOptions;\n};\n\n/**\n * Per-call lifecycle engine — the single object the C1 factory\n * constructs and drives. Owns the 7-phase lifecycle (orchestrator.md §3:\n * load → drift → lock → window → dispatch → persist → compaction),\n * resolving the durable stores (own config field → `ai.config` default)\n * and adapting C1's three-tier {@link OrchestratorEmitter} to the\n * {@link OrchestratorEmitterLike} port the phase modules call.\n *\n * The factory creates a fresh instance per `execute` / `stream` /\n * `resume` / `command` call (single-call lifecycle invariant — §18.8);\n * the heavy lifting lives in the standalone phase functions\n * ({@link runTurn} / {@link runResume}) which this class delegates to.\n *\n * @example\n * const execution = new OrchestratorExecution({\n * config, entries, signature, emitter, input, options,\n * });\n * const result = await execution.run();\n */\nexport class OrchestratorExecution<TOutput, TState> {\n private readonly params: OrchestratorExecutionParams<TOutput, TState>;\n private readonly ctx: OrchestratorEngineContext<TOutput, TState>;\n private readonly streamController?: OrchestratorStreamController<\n OrchestratorResult<TOutput>\n >;\n\n public constructor(params: OrchestratorExecutionParams<TOutput, TState>) {\n this.params = params;\n this.streamController = params.streamController;\n this.ctx = {\n config: params.config,\n signature: params.signature,\n checkpointStore: resolveCheckpointStore(params.config),\n snapshotStore: resolveSnapshotStore(params.config),\n emitter: adaptEmitter(\n params.emitter,\n generateRunId(\"orchestrator\"),\n this.streamController as\n | OrchestratorStreamController<unknown>\n | undefined,\n ),\n memory: resolveOrchestratorMemory(params.config.memory),\n };\n }\n\n /**\n * `execute()` / `stream()` entry — run one turn through the 7-phase\n * lifecycle. When a `streamController` was supplied, the adapter mirrors\n * every emitted event into the stream and the controller is settled\n * (`end` / `fail`) once the result resolves.\n */\n public async run(): Promise<OrchestratorResult<TOutput>> {\n if (this.params.input === undefined || !this.params.options) {\n throw new OrchestratorConfigError(\n `ai.orchestrator(\"${this.params.config.name}\"): internal — run() invoked without input/options`,\n );\n }\n\n try {\n const result = await runTurn(\n this.ctx,\n this.params.input,\n this.params.options,\n );\n\n // Route the orchestrator's report to observers (per-flow `observe` +\n // the global observe-all gate) — parity with agent/workflow/supervisor,\n // so a durable session root no longer needs a manual observe.collect().\n await notifyObservers(this.ctx.config.observe, result.report);\n\n this.streamController?.end(result);\n\n return result;\n } catch (error) {\n this.streamController?.fail(error as Error);\n\n throw error;\n }\n }\n\n /**\n * `resume()` entry — drain an interrupted `iterate: true` turn (§9).\n * Returns `null` when nothing is in flight.\n */\n public async resume(): Promise<OrchestratorResult<TOutput> | null> {\n if (!this.params.resumeSessionId) {\n throw new OrchestratorConfigError(\n `ai.orchestrator(\"${this.params.config.name}\"): internal — resume() invoked without a sessionId`,\n );\n }\n\n return runResume(this.ctx, this.params.resumeSessionId, this.params.resumeOptions);\n }\n\n /**\n * `command(\"compact\")` entry — run a manual compaction on demand (§11 /\n * §12.1). Reuses the post-turn compaction code path against the\n * caller-supplied history and returns the raw {@link CompactionResult}.\n */\n public async compact(\n args: OrchestratorCommands[\"compact\"][\"args\"],\n ): Promise<OrchestratorCommands[\"compact\"][\"result\"]> {\n return runManualCompaction(\n this.ctx as OrchestratorEngineContext<unknown, TState>,\n args.history,\n );\n }\n}\n\n/**\n * Resolve the durable checkpoint store: the config's own field, falling\n * back to `ai.config({ defaultCheckpointStore })`. Throws\n * {@link OrchestratorConfigError} when neither resolves — persistence is\n * always on (§8.1), so a turn can never run without a checkpoint store.\n */\nfunction resolveCheckpointStore<TOutput, TState>(\n config: OrchestratorConfig<TOutput, TState>,\n) {\n const store = config.checkpointStore ?? resolveDefaultCheckpointStore();\n\n if (!store) {\n throw new OrchestratorConfigError(\n `ai.orchestrator(\"${config.name}\"): a \\`checkpointStore\\` is required ` +\n `(set one on the config or via \\`ai.config({ defaultCheckpointStore })\\`)`,\n );\n }\n\n return store;\n}\n\n/**\n * Resolve the internal-supervisor snapshot store for `iterate: true`\n * turns: the config's own field, falling back to\n * `ai.config({ defaultSnapshotStore })`. Returns `undefined` for\n * `iterate: false` orchestrators (no mid-turn resume — nothing to\n * snapshot). The factory already guarantees presence when\n * `iterate: true`, so the engine never asserts here.\n */\nfunction resolveSnapshotStore<TOutput, TState>(\n config: OrchestratorConfig<TOutput, TState>,\n) {\n if (config.iterate !== true) {\n return undefined;\n }\n\n return config.snapshotStore ?? resolveDefaultSnapshotStore();\n}\n\n/**\n * Adapt C1's three-tier {@link OrchestratorEmitter} (whose `emit` takes\n * `event, payload, identity, perCallHandlers?`) to the\n * {@link OrchestratorEmitterLike} port the phase modules call (a 2-arg\n * `emit(event, payload)` plus `bindPerCall`).\n *\n * The adapter injects the run identity centrally and, when a stream\n * controller is present, mirrors every fully-stamped event into the\n * stream pipe (§14.1 — the orchestrator's own events surface on the\n * stream alongside the bubbled child events). `bindPerCall` registers\n * the per-call `options.on` bag for the turn's duration and returns a\n * disposer that clears it.\n */\nfunction adaptEmitter(\n emitter: OrchestratorEmitter,\n runId: string,\n streamController: OrchestratorStreamController<unknown> | undefined,\n): OrchestratorEmitterLike {\n // `rootRunId === runId` for a standalone run; nested propagation lands\n // in a follow-up (see `EventIdentity`).\n const fullIdentity: EventIdentity = { runId, rootRunId: runId };\n\n let perCall: OrchestratorEventHandlers | undefined;\n\n return {\n emit<K extends OrchestratorEventName>(\n event: K,\n payload: OrchestratorEventMap[K],\n ): void {\n const fullPayload = emitter.emit(event, payload, fullIdentity, perCall);\n\n // The discriminated-union correlation between `type` and the\n // matching payload variant can't be expressed structurally — the\n // cast mirrors the supervisor stream's established pattern.\n streamController?.push({ type: event, ...fullPayload } as OrchestratorEvent);\n },\n bindPerCall(handlers: OrchestratorEventHandlers | undefined): () => void {\n perCall = handlers;\n\n return () => {\n perCall = undefined;\n };\n },\n };\n}\n\n/**\n * Phase 2 — drift check (orchestrator.md §3 / §4 Phase 2). Compares the\n * loaded checkpoint's `signature` against the current definition's.\n * Mismatch throws `OrchestratorDriftError` synchronously unless\n * `force` is set. Emits `orchestrator.drift.checked` either way. A new\n * session (no loaded signature) never drifts.\n */\nfunction assertNoDrift(\n ctx: OrchestratorEngineContext,\n sessionId: string,\n loadedSignature: string | undefined,\n force: boolean | undefined,\n): void {\n const drifted =\n loadedSignature !== undefined && loadedSignature !== ctx.signature;\n\n ctx.emitter.emit(\"orchestrator.drift.checked\", {\n sessionId,\n signature: ctx.signature,\n drifted,\n });\n\n if (drifted && !force) {\n throw new OrchestratorDriftError(\n `orchestrator \"${ctx.config.name}\": signature drift on session \"${sessionId}\" — ` +\n `the definition changed since this session was last persisted. ` +\n `Pass { force: true } only after reviewing the change, or discard / migrate the session.`,\n {\n savedSignature: loadedSignature as string,\n currentSignature: ctx.signature,\n sessionId,\n },\n );\n }\n}\n\n/**\n * Shallow-merge the per-call `state` patch (§5 — partial state\n * override) over the loaded session-state seed. The merged value\n * becomes the supervisor's seed for this turn.\n */\nfunction applyStatePatch<TState>(\n seed: TState,\n patch: Partial<TState> | undefined,\n): TState {\n if (!patch) {\n return seed;\n }\n\n return { ...seed, ...patch } as TState;\n}\n\n/**\n * Assemble the orchestrator-scope {@link OrchestratorReport} from the\n * dispatched turn's child report and the turn snapshot. Wraps the\n * child supervisor/agent report tree as `children[0]` (§15.6 —\n * `children[]` carries only the CURRENT turn's dispatched primitive\n * reports) while the per-turn forensic record lives on `turns[]`.\n */\nfunction buildReport(\n ctx: OrchestratorEngineContext,\n sessionId: string,\n turnIndex: number,\n status: OrchestratorReportStatus,\n turnSnapshot: TurnSnapshot | undefined,\n childReport: BaseReport | undefined,\n error?: AIError,\n): OrchestratorReport {\n const now = new Date().toISOString();\n const usage = turnSnapshot?.usage ?? childReport?.usage ?? ZERO_USAGE;\n\n return {\n runId: deriveRunId(sessionId, ctx.config.version, turnIndex),\n rootRunId: deriveRunId(sessionId, ctx.config.version, turnIndex),\n name: ctx.config.name,\n version: ctx.config.version,\n sessionId,\n type: \"orchestrator\",\n status,\n // Stamp the terminal error so the observe path surfaces it on the\n // orchestrator span (an observer never sees the result envelope).\n // Absent on a clean turn.\n ...(error ? { error } : {}),\n startedAt: turnSnapshot?.startedAt ?? now,\n endedAt: turnSnapshot?.endedAt ?? now,\n duration: turnSnapshot?.duration ?? 0,\n usage,\n children: childReport ? [childReport] : [],\n reportSchemaVersion: REPORT_SCHEMA_VERSION,\n turnIndex,\n signature: ctx.signature,\n turns: turnSnapshot ? [turnSnapshot] : [],\n };\n}\n\n/**\n * Map the dispatched supervisor result's report status onto the\n * orchestrator's status surface (§15.6). A clean completion that is\n * still mid-conversation reports `\"awaiting-input\"` (the session\n * continues) rather than `\"completed\"`; failures and cancellations\n * pass through.\n */\nfunction deriveStatus(childStatus: BaseReport[\"status\"]): OrchestratorReportStatus {\n if (childStatus === \"completed\") {\n return \"awaiting-input\";\n }\n\n return childStatus;\n}\n\n/**\n * Emit the terminal turn event matching the report status (§14.1).\n */\nfunction emitTerminal(\n ctx: OrchestratorEngineContext,\n sessionId: string,\n turnIndex: number,\n status: OrchestratorReportStatus,\n): void {\n if (status === \"cancelled\") {\n ctx.emitter.emit(\"orchestrator.turn.cancelled\", { sessionId, turnIndex });\n\n return;\n }\n\n if (status === \"failed\" || status === \"max-iterations\") {\n ctx.emitter.emit(\"orchestrator.turn.failed\", { sessionId, turnIndex });\n\n return;\n }\n\n if (status === \"awaiting-input\") {\n ctx.emitter.emit(\"orchestrator.turn.awaiting-input\", {\n sessionId,\n turnIndex,\n });\n\n return;\n }\n\n ctx.emitter.emit(\"orchestrator.turn.completed\", { sessionId, turnIndex });\n}\n\n/**\n * Run one turn end-to-end through the 7-phase lifecycle (orchestrator\n * .md §3). The single entry the C1 factory's `execute()` delegates to.\n *\n * Phase order is the diagram's contract: load → drift → lock → window\n * → dispatch → persist → compaction. Drift / config misuse throw;\n * every other failure surfaces on `result.error` (the contract: the\n * orchestrator never throws on runtime failure). Cancellation and\n * failure do NOT persist a fresh checkpoint (§17 — state reverts to the\n * pre-turn checkpoint).\n */\nexport async function runTurn<TOutput, TState>(\n ctx: OrchestratorEngineContext<TOutput, TState>,\n input: SupervisorInput,\n options: OrchestratorExecuteOptions<TState>,\n): Promise<OrchestratorResult<TOutput>> {\n const sessionId = options.sessionId;\n const disposePerCall = ctx.emitter.bindPerCall(options.on);\n\n try {\n // Phase 1 — load session.\n const loaded = await loadSession(ctx, sessionId);\n\n ctx.emitter.emit(\"orchestrator.turn.starting\", {\n sessionId,\n turnIndex: loaded.turnIndex,\n });\n\n ctx.emitter.emit(\"orchestrator.session.loaded\", {\n sessionId,\n turnIndex: loaded.turnIndex,\n found: loaded.found,\n });\n\n // Phase 2 — drift check.\n assertNoDrift(\n ctx as OrchestratorEngineContext,\n sessionId,\n loaded.record?.signature,\n options.force,\n );\n\n // Phase 3 — lock check (cooperative, fail-open).\n await acquireLock(ctx, sessionId, loaded.record);\n\n // Phase 4 — window history.\n const windowed = windowHistory(\n ctx as OrchestratorEngineContext,\n sessionId,\n options.history,\n );\n\n // Phase 5 — dispatch. When memory is configured, recall the\n // turn-relevant memories and inject them into the request-scoped\n // context bag so every route / router / evaluate / dispatch callback\n // surfaces them at `ctx.context[injectKey]` before routing runs.\n const seedState = applyStatePatch(loaded.state, options.state);\n\n let turnContext = options.context;\n\n if (ctx.memory) {\n const recalled = await recallForTurn(ctx.memory, input);\n turnContext = injectMemories(turnContext, ctx.memory, recalled);\n }\n\n const { result, state, turnSnapshot } = await dispatchTurn<TOutput, TState>({\n ctx,\n sessionId,\n input,\n seedState,\n turnIndex: loaded.turnIndex,\n history: windowed.agents,\n context: turnContext,\n signal: options.signal,\n });\n\n ctx.emitter.emit(\"orchestrator.turn.routed\", {\n sessionId,\n turnIndex: loaded.turnIndex,\n source: turnSnapshot.decision.source,\n raw: turnSnapshot.decision.raw,\n });\n\n const status = result.error\n ? deriveStatus(result.report.status)\n : \"awaiting-input\";\n\n // Cancelled / failed turns revert: no fresh checkpoint, no compaction.\n if (result.error) {\n const report = buildReport(\n ctx as OrchestratorEngineContext,\n sessionId,\n loaded.turnIndex,\n status,\n turnSnapshot,\n result.report,\n result.error,\n );\n\n emitTerminal(ctx as OrchestratorEngineContext, sessionId, loaded.turnIndex, status);\n\n return {\n data: result.data,\n error: result.error,\n usage: result.usage,\n report,\n sessionId,\n turnIndex: loaded.turnIndex,\n };\n }\n\n // Phase 6 — persist checkpoint.\n await persistCheckpoint({\n ctx,\n sessionId,\n turnIndex: loaded.turnIndex,\n state,\n lastRoute: summarizeRoute(turnSnapshot.decision.raw as never),\n summarizedThrough: loaded.record?.summarized_through ?? null,\n });\n\n // Memory write-back (memory core M2). The turn settled cleanly (the\n // `result.error` branch above already returned for cancelled /\n // failed turns, which revert and never remember — §17), so remember\n // the input + its outcome for later recall.\n if (ctx.memory) {\n await rememberTurnOutcome(\n ctx.memory,\n input,\n outcomeTextFromTurn(result.data, turnSnapshot),\n );\n }\n\n // Phase 7 — post-turn compaction (only when triggered).\n let compaction: CompactionResult | undefined;\n\n if (shouldCompact(ctx as OrchestratorEngineContext, loaded.turnIndex)) {\n const outcome = await runCompaction(\n ctx as OrchestratorEngineContext<unknown, TState>,\n sessionId,\n options.history,\n );\n\n if (outcome) {\n compaction = outcome.compaction;\n\n if (outcome.applied) {\n await advanceSummarizedThrough(\n ctx as OrchestratorEngineContext<unknown, TState>,\n sessionId,\n outcome.compaction.replacesToIndex,\n );\n }\n }\n }\n\n const report = buildReport(\n ctx as OrchestratorEngineContext,\n sessionId,\n loaded.turnIndex,\n \"awaiting-input\",\n turnSnapshot,\n result.report,\n );\n\n emitTerminal(ctx as OrchestratorEngineContext, sessionId, loaded.turnIndex, \"awaiting-input\");\n\n return {\n data: result.data,\n error: undefined,\n usage: result.usage,\n report,\n sessionId,\n turnIndex: loaded.turnIndex,\n compaction,\n };\n } finally {\n disposePerCall();\n }\n}\n\n/**\n * After a framework-applied compaction (`onCompact` succeeded), advance\n * the persisted `summarized_through` to the compaction's\n * `replacesToIndex` (§12.2 step 4). Re-saves the latest row with the\n * updated marker (append-only stores keep the prior row).\n */\nasync function advanceSummarizedThrough<TState>(\n ctx: OrchestratorEngineContext<unknown, TState>,\n sessionId: string,\n replacesToIndex: number,\n): Promise<void> {\n const latest = await ctx.checkpointStore.load(ctx.config.name, sessionId);\n\n if (!latest) {\n return;\n }\n\n await ctx.checkpointStore.save({\n ...latest,\n summarized_through: replacesToIndex,\n saved_at: new Date().toISOString(),\n });\n}\n\n/**\n * §9 resume protocol entry the C1 factory's `resume()` delegates to.\n * Returns `null` when no in-flight `iterate: true` turn is detected;\n * otherwise drains the interrupted supervisor run, persists a fresh\n * checkpoint for the resumed turn, and returns the completed result.\n *\n * Runs the same Phase 2 drift check as `runTurn` (§9.4). The heavy\n * lifting lives in `resume.ts`; this wrapper threads the engine\n * context.\n */\nexport async function runResume<TOutput, TState>(\n ctx: OrchestratorEngineContext<TOutput, TState>,\n sessionId: string,\n options?: OrchestratorResumeOptions,\n): Promise<OrchestratorResult<TOutput> | null> {\n const disposePerCall = ctx.emitter.bindPerCall(options?.on);\n\n try {\n return await resolveResume(ctx, sessionId, options, {\n assertNoDrift: (loadedSignature) =>\n assertNoDrift(\n ctx as OrchestratorEngineContext,\n sessionId,\n loadedSignature,\n options?.force,\n ),\n buildReport: (turnIndex, status, turnSnapshot, childReport) =>\n buildReport(\n ctx as OrchestratorEngineContext,\n sessionId,\n turnIndex,\n status,\n turnSnapshot,\n childReport,\n ),\n deriveStatus,\n emitTerminal: (turnIndex, status) =>\n emitTerminal(ctx as OrchestratorEngineContext, sessionId, turnIndex, status),\n persist: (turnIndex, state, lastRoute, summarizedThrough) =>\n persistCheckpoint({\n ctx,\n sessionId,\n turnIndex,\n state,\n lastRoute,\n summarizedThrough,\n }),\n });\n } finally {\n disposePerCall();\n }\n}\n\n/**\n * The `stream()` entry. The orchestrator's streaming surface bubbles\n * child agent/supervisor events under their own namespace (§14.2); the\n * C1 stream controller owns the `StreamContract` wiring. This engine\n * entry runs the same lifecycle as `runTurn` — the C1 factory passes a\n * per-call `on` bag wired to the stream controller, so the engine needs\n * no streaming-specific branch. Exposed as a distinct name for the\n * factory to call, returning the same `OrchestratorResult` the stream's\n * `.result` resolves to.\n */\nexport async function streamTurn<TOutput, TState>(\n ctx: OrchestratorEngineContext<TOutput, TState>,\n input: SupervisorInput,\n options: OrchestratorExecuteOptions<TState>,\n): Promise<OrchestratorResult<TOutput>> {\n return runTurn(ctx, input, options);\n}\n\nexport type { OrchestratorEngineContext } from \"./engine-context.type\";\nexport type { Message };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"execution.mjs","names":[],"sources":["../../../../../../../ai/src/orchestrator/execution.ts"],"sourcesContent":["import type { Message } from \"../contracts/conversation-message.type\";\nimport type { OrchestratorCommands } from \"../contracts/orchestrator/orchestrator-commands.type\";\nimport type { OrchestratorConfig } from \"../contracts/orchestrator/orchestrator-config.type\";\nimport type {\n OrchestratorEvent,\n OrchestratorEventHandlers,\n OrchestratorEventMap,\n OrchestratorEventName,\n} from \"../contracts/orchestrator/orchestrator-event.type\";\nimport type {\n OrchestratorExecuteOptions,\n OrchestratorResumeOptions,\n} from \"../contracts/orchestrator/orchestrator-execute-options.type\";\nimport type {\n CompactionResult,\n OrchestratorReport,\n OrchestratorReportStatus,\n OrchestratorResult,\n TurnSnapshot,\n} from \"../contracts/result/orchestrator-result.type\";\nimport { REPORT_SCHEMA_VERSION } from \"../contracts/result/base-report.type\";\nimport type { BaseReport } from \"../contracts/result/base-report.type\";\nimport type { Usage } from \"../contracts/result/usage.type\";\nimport type { SupervisorInput } from \"../contracts/supervisor/supervisor-input.type\";\nimport type { EventIdentity } from \"../contracts/events/event-identity.type\";\nimport {\n resolveDefaultCheckpointStore,\n resolveDefaultSnapshotStore,\n} from \"../config\";\nimport type { AIError } from \"../errors/ai-error\";\nimport { OrchestratorConfigError, OrchestratorDriftError } from \"../errors\";\nimport { notifyObservers } from \"../observe/resolve-observers\";\nimport type { ResolvedIntentEntry } from \"../supervisor/entries\";\nimport { generateRunId } from \"../utils/generate-run-id\";\nimport { persistCheckpoint, summarizeRoute } from \"./checkpoint\";\nimport { runCompaction, runManualCompaction, shouldCompact } from \"./compaction\";\nimport { deriveRunId, dispatchTurn } from \"./dispatch\";\nimport type { OrchestratorEmitter } from \"./emitter\";\nimport type { OrchestratorEmitterLike } from \"./emitter-port.type\";\nimport type { OrchestratorEngineContext } from \"./engine-context.type\";\nimport { acquireLock } from \"./lock\";\nimport { loadSession } from \"./load\";\nimport {\n injectMemories,\n outcomeTextFromTurn,\n recallForTurn,\n rememberTurnOutcome,\n resolveOrchestratorMemory,\n} from \"./memory\";\nimport type { OrchestratorStreamController } from \"./orchestrator-stream\";\nimport { resolveResume } from \"./resume\";\nimport { windowHistory } from \"./window\";\n\n/** Empty rolled-up usage for turns that never dispatched (drift/seed). */\nconst ZERO_USAGE: Usage = { input: 0, output: 0, total: 0 };\n\n/**\n * Constructor params the C1 factory passes when building an\n * {@link OrchestratorExecution} per call. The factory owns author-time\n * validation, intent-entry resolution, and signature computation; it\n * hands the engine the validated `config`, the resolved `entries`, the\n * computed `signature`, and the shared three-tier `emitter`. The\n * per-call inputs vary by entry point:\n *\n * - `execute` / `stream` — `input` + `options` (and `streamController`\n * for `stream`).\n * - `resume` — `resumeSessionId` + `resumeOptions`.\n * - `command(\"compact\")` — neither; `compact(args)` carries its own.\n */\nexport type OrchestratorExecutionParams<TOutput, TState> = {\n config: OrchestratorConfig<TOutput, TState>;\n /** Resolved intent entries (validated by C1; the engine delegates dispatch to the supervisor). */\n entries?: Map<string, ResolvedIntentEntry>;\n signature: string;\n emitter: OrchestratorEmitter;\n input?: SupervisorInput;\n options?: OrchestratorExecuteOptions<TState>;\n streamController?: OrchestratorStreamController<OrchestratorResult<TOutput>>;\n resumeSessionId?: string;\n resumeOptions?: OrchestratorResumeOptions;\n};\n\n/**\n * Per-call lifecycle engine — the single object the C1 factory\n * constructs and drives. Owns the 7-phase lifecycle (orchestrator.md §3:\n * load → drift → lock → window → dispatch → persist → compaction),\n * resolving the durable stores (own config field → `ai.config` default)\n * and adapting C1's three-tier {@link OrchestratorEmitter} to the\n * {@link OrchestratorEmitterLike} port the phase modules call.\n *\n * The factory creates a fresh instance per `execute` / `stream` /\n * `resume` / `command` call (single-call lifecycle invariant — §18.8);\n * the heavy lifting lives in the standalone phase functions\n * ({@link runTurn} / {@link runResume}) which this class delegates to.\n *\n * @example\n * const execution = new OrchestratorExecution({\n * config, entries, signature, emitter, input, options,\n * });\n * const result = await execution.run();\n */\nexport class OrchestratorExecution<TOutput, TState> {\n private readonly params: OrchestratorExecutionParams<TOutput, TState>;\n private readonly ctx: OrchestratorEngineContext<TOutput, TState>;\n private readonly streamController?: OrchestratorStreamController<\n OrchestratorResult<TOutput>\n >;\n\n public constructor(params: OrchestratorExecutionParams<TOutput, TState>) {\n this.params = params;\n this.streamController = params.streamController;\n this.ctx = {\n config: params.config,\n signature: params.signature,\n checkpointStore: resolveCheckpointStore(params.config),\n snapshotStore: resolveSnapshotStore(params.config),\n emitter: adaptEmitter(\n params.emitter,\n generateRunId(\"orchestrator\"),\n this.streamController as\n | OrchestratorStreamController<unknown>\n | undefined,\n ),\n memory: resolveOrchestratorMemory(params.config.memory),\n };\n }\n\n /**\n * `execute()` / `stream()` entry — run one turn through the 7-phase\n * lifecycle. When a `streamController` was supplied, the adapter mirrors\n * every emitted event into the stream and the controller is settled\n * (`end` / `fail`) once the result resolves.\n */\n public async run(): Promise<OrchestratorResult<TOutput>> {\n if (this.params.input === undefined || !this.params.options) {\n throw new OrchestratorConfigError(\n `ai.orchestrator(\"${this.params.config.name}\"): internal — run() invoked without input/options`,\n );\n }\n\n try {\n const result = await runTurn(\n this.ctx,\n this.params.input,\n this.params.options,\n );\n\n // Route the orchestrator's report to observers (per-flow `observe` +\n // the global observe-all gate) — parity with agent/workflow/supervisor,\n // so a durable session root no longer needs a manual observe.collect().\n await notifyObservers(this.ctx.config.observe, result.report);\n\n this.streamController?.end(result);\n\n return result;\n } catch (error) {\n this.streamController?.fail(error as Error);\n\n throw error;\n }\n }\n\n /**\n * `resume()` entry — drain an interrupted `iterate: true` turn (§9).\n * Returns `null` when nothing is in flight.\n */\n public async resume(): Promise<OrchestratorResult<TOutput> | null> {\n if (!this.params.resumeSessionId) {\n throw new OrchestratorConfigError(\n `ai.orchestrator(\"${this.params.config.name}\"): internal — resume() invoked without a sessionId`,\n );\n }\n\n return runResume(this.ctx, this.params.resumeSessionId, this.params.resumeOptions);\n }\n\n /**\n * `command(\"compact\")` entry — run a manual compaction on demand (§11 /\n * §12.1). Reuses the post-turn compaction code path against the\n * caller-supplied history and returns the raw {@link CompactionResult}.\n */\n public async compact(\n args: OrchestratorCommands[\"compact\"][\"args\"],\n ): Promise<OrchestratorCommands[\"compact\"][\"result\"]> {\n return runManualCompaction(\n this.ctx as OrchestratorEngineContext<unknown, TState>,\n args.history,\n );\n }\n}\n\n/**\n * Resolve the durable checkpoint store: the config's own field, falling\n * back to `ai.config({ defaultCheckpointStore })`. Throws\n * {@link OrchestratorConfigError} when neither resolves — persistence is\n * always on (§8.1), so a turn can never run without a checkpoint store.\n */\nfunction resolveCheckpointStore<TOutput, TState>(\n config: OrchestratorConfig<TOutput, TState>,\n) {\n const store = config.checkpointStore ?? resolveDefaultCheckpointStore();\n\n if (!store) {\n throw new OrchestratorConfigError(\n `ai.orchestrator(\"${config.name}\"): a \\`checkpointStore\\` is required ` +\n `(set one on the config or via \\`ai.config({ defaultCheckpointStore })\\`)`,\n );\n }\n\n return store;\n}\n\n/**\n * Resolve the internal-supervisor snapshot store for `iterate: true`\n * turns: the config's own field, falling back to\n * `ai.config({ defaultSnapshotStore })`. Returns `undefined` for\n * `iterate: false` orchestrators (no mid-turn resume — nothing to\n * snapshot). The factory already guarantees presence when\n * `iterate: true`, so the engine never asserts here.\n */\nfunction resolveSnapshotStore<TOutput, TState>(\n config: OrchestratorConfig<TOutput, TState>,\n) {\n if (config.iterate !== true) {\n return undefined;\n }\n\n return config.snapshotStore ?? resolveDefaultSnapshotStore();\n}\n\n/**\n * Adapt C1's three-tier {@link OrchestratorEmitter} (whose `emit` takes\n * `event, payload, identity, perCallHandlers?`) to the\n * {@link OrchestratorEmitterLike} port the phase modules call (a 2-arg\n * `emit(event, payload)` plus `bindPerCall`).\n *\n * The adapter injects the run identity centrally and, when a stream\n * controller is present, mirrors every fully-stamped event into the\n * stream pipe (§14.1 — the orchestrator's own events surface on the\n * stream alongside the bubbled child events). `bindPerCall` registers\n * the per-call `options.on` bag for the turn's duration and returns a\n * disposer that clears it.\n */\nfunction adaptEmitter(\n emitter: OrchestratorEmitter,\n runId: string,\n streamController: OrchestratorStreamController<unknown> | undefined,\n): OrchestratorEmitterLike {\n // `rootRunId === runId` for a standalone run; nested propagation lands\n // in a follow-up (see `EventIdentity`).\n const fullIdentity: EventIdentity = { runId, rootRunId: runId };\n\n let perCall: OrchestratorEventHandlers | undefined;\n\n return {\n emit<K extends OrchestratorEventName>(\n event: K,\n payload: OrchestratorEventMap[K],\n ): void {\n const fullPayload = emitter.emit(event, payload, fullIdentity, perCall);\n\n // The discriminated-union correlation between `type` and the\n // matching payload variant can't be expressed structurally — the\n // cast mirrors the supervisor stream's established pattern.\n streamController?.push({ type: event, ...fullPayload } as OrchestratorEvent);\n },\n bindPerCall(handlers: OrchestratorEventHandlers | undefined): () => void {\n perCall = handlers;\n\n return () => {\n perCall = undefined;\n };\n },\n };\n}\n\n/**\n * Phase 2 — drift check (orchestrator.md §3 / §4 Phase 2). Compares the\n * loaded checkpoint's `signature` against the current definition's.\n * Mismatch throws `OrchestratorDriftError` synchronously unless\n * `force` is set. Emits `orchestrator.drift.checked` either way. A new\n * session (no loaded signature) never drifts.\n */\nfunction assertNoDrift(\n ctx: OrchestratorEngineContext,\n sessionId: string,\n loadedSignature: string | undefined,\n force: boolean | undefined,\n): void {\n const drifted =\n loadedSignature !== undefined && loadedSignature !== ctx.signature;\n\n ctx.emitter.emit(\"orchestrator.drift.checked\", {\n sessionId,\n signature: ctx.signature,\n drifted,\n });\n\n if (drifted && !force) {\n throw new OrchestratorDriftError(\n `orchestrator \"${ctx.config.name}\": signature drift on session \"${sessionId}\" — ` +\n `the definition changed since this session was last persisted. ` +\n `Pass { force: true } only after reviewing the change, or discard / migrate the session.`,\n {\n savedSignature: loadedSignature as string,\n currentSignature: ctx.signature,\n sessionId,\n },\n );\n }\n}\n\n/**\n * Shallow-merge the per-call `state` patch (§5 — partial state\n * override) over the loaded session-state seed. The merged value\n * becomes the supervisor's seed for this turn.\n */\nfunction applyStatePatch<TState>(\n seed: TState,\n patch: Partial<TState> | undefined,\n): TState {\n if (!patch) {\n return seed;\n }\n\n return { ...seed, ...patch } as TState;\n}\n\n/**\n * Assemble the orchestrator-scope {@link OrchestratorReport} from the\n * dispatched turn's child report and the turn snapshot. Wraps the\n * child supervisor/agent report tree as `children[0]` (§15.6 —\n * `children[]` carries only the CURRENT turn's dispatched primitive\n * reports) while the per-turn forensic record lives on `turns[]`.\n */\nfunction buildReport(\n ctx: OrchestratorEngineContext,\n sessionId: string,\n turnIndex: number,\n status: OrchestratorReportStatus,\n turnSnapshot: TurnSnapshot | undefined,\n childReport: BaseReport | undefined,\n error?: AIError,\n): OrchestratorReport {\n const now = new Date().toISOString();\n const usage = turnSnapshot?.usage ?? childReport?.usage ?? ZERO_USAGE;\n\n return {\n runId: deriveRunId(sessionId, ctx.config.version, turnIndex),\n rootRunId: deriveRunId(sessionId, ctx.config.version, turnIndex),\n name: ctx.config.name,\n version: ctx.config.version,\n sessionId,\n type: \"orchestrator\",\n status,\n // Stamp the terminal error so the observe path surfaces it on the\n // orchestrator span (an observer never sees the result envelope).\n // Absent on a clean turn.\n ...(error ? { error } : {}),\n startedAt: turnSnapshot?.startedAt ?? now,\n endedAt: turnSnapshot?.endedAt ?? now,\n duration: turnSnapshot?.duration ?? 0,\n usage,\n children: childReport ? [childReport] : [],\n reportSchemaVersion: REPORT_SCHEMA_VERSION,\n turnIndex,\n signature: ctx.signature,\n turns: turnSnapshot ? [turnSnapshot] : [],\n };\n}\n\n/**\n * Map the dispatched supervisor result's report status onto the\n * orchestrator's status surface (§15.6). A clean completion that is\n * still mid-conversation reports `\"awaiting-input\"` (the session\n * continues) rather than `\"completed\"`; failures and cancellations\n * pass through.\n */\nfunction deriveStatus(childStatus: BaseReport[\"status\"]): OrchestratorReportStatus {\n if (childStatus === \"completed\") {\n return \"awaiting-input\";\n }\n\n return childStatus;\n}\n\n/**\n * Emit the terminal turn event matching the report status (§14.1).\n */\nfunction emitTerminal(\n ctx: OrchestratorEngineContext,\n sessionId: string,\n turnIndex: number,\n status: OrchestratorReportStatus,\n): void {\n if (status === \"cancelled\") {\n ctx.emitter.emit(\"orchestrator.turn.cancelled\", { sessionId, turnIndex });\n\n return;\n }\n\n if (status === \"failed\" || status === \"max-iterations\") {\n ctx.emitter.emit(\"orchestrator.turn.failed\", { sessionId, turnIndex });\n\n return;\n }\n\n if (status === \"awaiting-input\") {\n ctx.emitter.emit(\"orchestrator.turn.awaiting-input\", {\n sessionId,\n turnIndex,\n });\n\n return;\n }\n\n ctx.emitter.emit(\"orchestrator.turn.completed\", { sessionId, turnIndex });\n}\n\n/**\n * Run one turn end-to-end through the 7-phase lifecycle (orchestrator\n * .md §3). The single entry the C1 factory's `execute()` delegates to.\n *\n * Phase order is the diagram's contract: load → drift → lock → window\n * → dispatch → persist → compaction. Drift / config misuse throw;\n * every other failure surfaces on `result.error` (the contract: the\n * orchestrator never throws on runtime failure). Cancellation and\n * failure do NOT persist a fresh checkpoint (§17 — state reverts to the\n * pre-turn checkpoint).\n */\nexport async function runTurn<TOutput, TState>(\n ctx: OrchestratorEngineContext<TOutput, TState>,\n input: SupervisorInput,\n options: OrchestratorExecuteOptions<TState>,\n): Promise<OrchestratorResult<TOutput>> {\n const sessionId = options.sessionId;\n const disposePerCall = ctx.emitter.bindPerCall(options.on);\n\n try {\n // Phase 1 — load session.\n const loaded = await loadSession(ctx, sessionId);\n\n ctx.emitter.emit(\"orchestrator.turn.starting\", {\n sessionId,\n turnIndex: loaded.turnIndex,\n });\n\n ctx.emitter.emit(\"orchestrator.session.loaded\", {\n sessionId,\n turnIndex: loaded.turnIndex,\n found: loaded.found,\n });\n\n // Phase 2 — drift check.\n assertNoDrift(\n ctx as OrchestratorEngineContext,\n sessionId,\n loaded.record?.signature,\n options.force,\n );\n\n // Phase 3 — lock check (cooperative, fail-open).\n await acquireLock(ctx, sessionId, loaded.record);\n\n // Phase 4 — window history.\n const windowed = windowHistory(\n ctx as OrchestratorEngineContext,\n sessionId,\n options.history,\n );\n\n // Phase 5 — dispatch. When memory is configured, recall the\n // turn-relevant memories and inject them into the request-scoped\n // context bag so every route / router / evaluate / dispatch callback\n // surfaces them at `ctx.context[injectKey]` before routing runs.\n const seedState = applyStatePatch(loaded.state, options.state);\n\n let turnContext = options.context;\n\n // Recall is scoped to THIS session (`memory.scope`, default\n // `\"session\"`): the store is shared by every session of this\n // orchestrator instance, so the scope — not the store — is what keeps\n // another session's remembered turns out of this turn's context.\n if (ctx.memory) {\n const recalled = await recallForTurn(ctx.memory, input, sessionId);\n turnContext = injectMemories(turnContext, ctx.memory, recalled);\n }\n\n const { result, state, turnSnapshot } = await dispatchTurn<TOutput, TState>({\n ctx,\n sessionId,\n input,\n seedState,\n turnIndex: loaded.turnIndex,\n history: windowed.agents,\n context: turnContext,\n signal: options.signal,\n });\n\n ctx.emitter.emit(\"orchestrator.turn.routed\", {\n sessionId,\n turnIndex: loaded.turnIndex,\n source: turnSnapshot.decision.source,\n raw: turnSnapshot.decision.raw,\n });\n\n const status = result.error\n ? deriveStatus(result.report.status)\n : \"awaiting-input\";\n\n // Cancelled / failed turns revert: no fresh checkpoint, no compaction.\n if (result.error) {\n const report = buildReport(\n ctx as OrchestratorEngineContext,\n sessionId,\n loaded.turnIndex,\n status,\n turnSnapshot,\n result.report,\n result.error,\n );\n\n emitTerminal(ctx as OrchestratorEngineContext, sessionId, loaded.turnIndex, status);\n\n return {\n data: result.data,\n error: result.error,\n usage: result.usage,\n report,\n sessionId,\n turnIndex: loaded.turnIndex,\n };\n }\n\n // Phase 6 — persist checkpoint.\n await persistCheckpoint({\n ctx,\n sessionId,\n turnIndex: loaded.turnIndex,\n state,\n lastRoute: summarizeRoute(turnSnapshot.decision.raw as never),\n summarizedThrough: loaded.record?.summarized_through ?? null,\n });\n\n // Memory write-back (memory core M2). The turn settled cleanly (the\n // `result.error` branch above already returned for cancelled /\n // failed turns, which revert and never remember — §17), so remember\n // the input + its outcome for later recall.\n if (ctx.memory) {\n await rememberTurnOutcome(\n ctx.memory,\n input,\n outcomeTextFromTurn(result.data, turnSnapshot),\n sessionId,\n );\n }\n\n // Phase 7 — post-turn compaction (only when triggered).\n let compaction: CompactionResult | undefined;\n\n if (shouldCompact(ctx as OrchestratorEngineContext, loaded.turnIndex)) {\n const outcome = await runCompaction(\n ctx as OrchestratorEngineContext<unknown, TState>,\n sessionId,\n options.history,\n );\n\n if (outcome) {\n compaction = outcome.compaction;\n\n if (outcome.applied) {\n await advanceSummarizedThrough(\n ctx as OrchestratorEngineContext<unknown, TState>,\n sessionId,\n outcome.compaction.replacesToIndex,\n );\n }\n }\n }\n\n const report = buildReport(\n ctx as OrchestratorEngineContext,\n sessionId,\n loaded.turnIndex,\n \"awaiting-input\",\n turnSnapshot,\n result.report,\n );\n\n emitTerminal(ctx as OrchestratorEngineContext, sessionId, loaded.turnIndex, \"awaiting-input\");\n\n return {\n data: result.data,\n error: undefined,\n usage: result.usage,\n report,\n sessionId,\n turnIndex: loaded.turnIndex,\n compaction,\n };\n } finally {\n disposePerCall();\n }\n}\n\n/**\n * After a framework-applied compaction (`onCompact` succeeded), advance\n * the persisted `summarized_through` to the compaction's\n * `replacesToIndex` (§12.2 step 4). Re-saves the latest row with the\n * updated marker (append-only stores keep the prior row).\n */\nasync function advanceSummarizedThrough<TState>(\n ctx: OrchestratorEngineContext<unknown, TState>,\n sessionId: string,\n replacesToIndex: number,\n): Promise<void> {\n const latest = await ctx.checkpointStore.load(ctx.config.name, sessionId);\n\n if (!latest) {\n return;\n }\n\n await ctx.checkpointStore.save({\n ...latest,\n summarized_through: replacesToIndex,\n saved_at: new Date().toISOString(),\n });\n}\n\n/**\n * §9 resume protocol entry the C1 factory's `resume()` delegates to.\n * Returns `null` when no in-flight `iterate: true` turn is detected;\n * otherwise drains the interrupted supervisor run, persists a fresh\n * checkpoint for the resumed turn, and returns the completed result.\n *\n * Runs the same Phase 2 drift check as `runTurn` (§9.4). The heavy\n * lifting lives in `resume.ts`; this wrapper threads the engine\n * context.\n */\nexport async function runResume<TOutput, TState>(\n ctx: OrchestratorEngineContext<TOutput, TState>,\n sessionId: string,\n options?: OrchestratorResumeOptions,\n): Promise<OrchestratorResult<TOutput> | null> {\n const disposePerCall = ctx.emitter.bindPerCall(options?.on);\n\n try {\n return await resolveResume(ctx, sessionId, options, {\n assertNoDrift: (loadedSignature) =>\n assertNoDrift(\n ctx as OrchestratorEngineContext,\n sessionId,\n loadedSignature,\n options?.force,\n ),\n buildReport: (turnIndex, status, turnSnapshot, childReport) =>\n buildReport(\n ctx as OrchestratorEngineContext,\n sessionId,\n turnIndex,\n status,\n turnSnapshot,\n childReport,\n ),\n deriveStatus,\n emitTerminal: (turnIndex, status) =>\n emitTerminal(ctx as OrchestratorEngineContext, sessionId, turnIndex, status),\n persist: (turnIndex, state, lastRoute, summarizedThrough) =>\n persistCheckpoint({\n ctx,\n sessionId,\n turnIndex,\n state,\n lastRoute,\n summarizedThrough,\n }),\n });\n } finally {\n disposePerCall();\n }\n}\n\n/**\n * The `stream()` entry. The orchestrator's streaming surface bubbles\n * child agent/supervisor events under their own namespace (§14.2); the\n * C1 stream controller owns the `StreamContract` wiring. This engine\n * entry runs the same lifecycle as `runTurn` — the C1 factory passes a\n * per-call `on` bag wired to the stream controller, so the engine needs\n * no streaming-specific branch. Exposed as a distinct name for the\n * factory to call, returning the same `OrchestratorResult` the stream's\n * `.result` resolves to.\n */\nexport async function streamTurn<TOutput, TState>(\n ctx: OrchestratorEngineContext<TOutput, TState>,\n input: SupervisorInput,\n options: OrchestratorExecuteOptions<TState>,\n): Promise<OrchestratorResult<TOutput>> {\n return runTurn(ctx, input, options);\n}\n\nexport type { OrchestratorEngineContext } from \"./engine-context.type\";\nexport type { Message };\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { asTool } from "./as-tool.mjs";
|
|
2
2
|
import { OrchestratorCommandHandlers, createCommandDispatcher } from "./commands.mjs";
|
|
3
3
|
import { OrchestratorEmitter } from "./emitter.mjs";
|
|
4
|
-
import { ResolvedOrchestratorMemory, injectMemories, memoryQueryFromInput, outcomeTextFromTurn, recallForTurn, rememberTurnOutcome, resolveOrchestratorMemory } from "./memory.mjs";
|
|
4
|
+
import { ResolvedOrchestratorMemory, injectMemories, memoryQueryFromInput, memoryScopeFor, outcomeTextFromTurn, recallForTurn, rememberTurnOutcome, resolveOrchestratorMemory, sessionMemoryScope } from "./memory.mjs";
|
|
5
5
|
import { OrchestratorStreamController, createOrchestratorStream } from "./orchestrator-stream.mjs";
|
|
6
6
|
import { OrchestratorExecution, OrchestratorExecutionParams, runResume, runTurn, streamTurn } from "./execution.mjs";
|
|
7
7
|
import { orchestrator } from "./orchestrator.mjs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { asTool } from "./as-tool.mjs";
|
|
2
2
|
import { createCommandDispatcher } from "./commands.mjs";
|
|
3
3
|
import { OrchestratorEmitter } from "./emitter.mjs";
|
|
4
|
-
import { injectMemories, memoryQueryFromInput, outcomeTextFromTurn, recallForTurn, rememberTurnOutcome, resolveOrchestratorMemory } from "./memory.mjs";
|
|
4
|
+
import { injectMemories, memoryQueryFromInput, memoryScopeFor, outcomeTextFromTurn, recallForTurn, rememberTurnOutcome, resolveOrchestratorMemory, sessionMemoryScope } from "./memory.mjs";
|
|
5
5
|
import { OrchestratorExecution, runResume, runTurn, streamTurn } from "./execution.mjs";
|
|
6
6
|
import { createOrchestratorStream } from "./orchestrator-stream.mjs";
|
|
7
7
|
import { inProcessSessionLock, noopSessionLock } from "./session-lock.mjs";
|