@arnilo/prism 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +42 -62
  3. package/dist/agent-run-lifecycle.js +4 -0
  4. package/dist/agent-run-state.d.ts +5 -2
  5. package/dist/agent-run-state.js +18 -8
  6. package/dist/agent-session/session/assemble.d.ts +6 -0
  7. package/dist/agent-session/session/assemble.js +391 -0
  8. package/dist/agent-session/session/persist.d.ts +28 -0
  9. package/dist/agent-session/session/persist.js +166 -0
  10. package/dist/agent-session/session/provider-round.d.ts +6 -0
  11. package/dist/agent-session/session/provider-round.js +231 -0
  12. package/dist/agent-session/session/tool-round.d.ts +31 -0
  13. package/dist/agent-session/session/tool-round.js +473 -0
  14. package/dist/agent-session/session/types.d.ts +115 -0
  15. package/dist/agent-session/session/types.js +5 -0
  16. package/dist/agent-session/session.d.ts +54 -41
  17. package/dist/agent-session/session.js +23 -1132
  18. package/dist/capture.d.ts +63 -0
  19. package/dist/capture.js +67 -0
  20. package/dist/cli-dev.d.ts +29 -0
  21. package/dist/cli-dev.js +52 -0
  22. package/dist/cli-init.d.ts +34 -3
  23. package/dist/cli-init.js +192 -24
  24. package/dist/cli-runner.d.ts +6 -2
  25. package/dist/cli-runner.js +57 -10
  26. package/dist/content.d.ts +3 -3
  27. package/dist/content.js +3 -1
  28. package/dist/contracts-core/agent.d.ts +8 -0
  29. package/dist/contracts-core/batch.d.ts +97 -0
  30. package/dist/contracts-core/batch.js +65 -0
  31. package/dist/contracts-core/content.d.ts +72 -1
  32. package/dist/contracts-core/embeddings.d.ts +30 -0
  33. package/dist/contracts-core/embeddings.js +17 -0
  34. package/dist/contracts-core/images.d.ts +60 -0
  35. package/dist/contracts-core/images.js +17 -0
  36. package/dist/contracts-core/moderation.d.ts +46 -0
  37. package/dist/contracts-core/moderation.js +34 -0
  38. package/dist/contracts-core/speech.d.ts +39 -0
  39. package/dist/contracts-core/speech.js +17 -0
  40. package/dist/contracts-core/transcription.d.ts +48 -0
  41. package/dist/contracts-core/transcription.js +17 -0
  42. package/dist/contracts-core/video.d.ts +61 -0
  43. package/dist/contracts-core/video.js +17 -0
  44. package/dist/contracts-core.d.ts +7 -0
  45. package/dist/contracts-core.js +7 -0
  46. package/dist/contracts-protocol.d.ts +18 -0
  47. package/dist/contracts-run-state.d.ts +1 -2
  48. package/dist/index.d.ts +7 -3
  49. package/dist/index.js +5 -3
  50. package/dist/input.d.ts +8 -0
  51. package/dist/input.js +4 -0
  52. package/dist/node/agent-definitions.d.ts +1 -8
  53. package/dist/node/agent-definitions.js +0 -34
  54. package/dist/node/settings.d.ts +0 -1
  55. package/dist/node/settings.js +0 -5
  56. package/dist/pinned-fetch.js +29 -3
  57. package/dist/provider-events.js +3 -4
  58. package/dist/providers/media.d.ts +1 -2
  59. package/dist/providers/media.js +1 -4
  60. package/dist/rpc.d.ts +1 -1
  61. package/dist/rpc.js +4 -4
  62. package/dist/testing/persistence-schema.d.ts +1 -1
  63. package/dist/testing/persistence-schema.js +32 -28
  64. package/dist/testing/provider-conformance.d.ts +114 -5
  65. package/dist/testing/provider-conformance.js +342 -0
  66. package/dist/testing/tool-conformance.d.ts +25 -0
  67. package/dist/testing/tool-conformance.js +128 -1
  68. package/dist/testing/tool-effect-store-conformance.d.ts +0 -1
  69. package/dist/testing/tool-effect-store-conformance.js +0 -3
  70. package/dist/thinking.d.ts +48 -9
  71. package/dist/thinking.js +134 -8
  72. package/dist/tool-search.d.ts +76 -0
  73. package/dist/tool-search.js +199 -0
  74. package/docs/0.1.0-readiness.md +3 -3
  75. package/docs/a2a.md +2 -2
  76. package/docs/acp-agent.md +1 -1
  77. package/docs/acp.md +3 -3
  78. package/docs/ag-ui-adoption.md +1 -1
  79. package/docs/ag-ui.md +1 -2
  80. package/docs/agent-definitions.md +1 -1
  81. package/docs/agent-events.md +5 -5
  82. package/docs/agent-identity.md +13 -2
  83. package/docs/audit-export.md +3 -3
  84. package/docs/batch-jobs.md +120 -0
  85. package/docs/browser-automation.md +5 -5
  86. package/docs/caveman.md +2 -2
  87. package/docs/cli-rpc.md +43 -9
  88. package/docs/coding-agent-tools.md +19 -19
  89. package/docs/coding-review-and-diagnostics.md +2 -2
  90. package/docs/coding-security.md +5 -5
  91. package/docs/coding-tools.md +82 -0
  92. package/docs/coding-workspaces.md +2 -2
  93. package/docs/compaction-and-retry.md +2 -2
  94. package/docs/compaction-llm.md +4 -4
  95. package/docs/compaction-observational-memory.md +3 -3
  96. package/docs/computer-use-linux.md +13 -2
  97. package/docs/context-and-skills.md +3 -1
  98. package/docs/conversations.md +4 -4
  99. package/docs/core.md +85 -0
  100. package/docs/credential-storage.md +12 -8
  101. package/docs/credentials-and-redaction.md +1 -1
  102. package/docs/data-classification.md +1 -1
  103. package/docs/database-persistence.md +7 -3
  104. package/docs/dev-inspector.md +103 -0
  105. package/docs/device-adapters.md +2 -2
  106. package/docs/diagrams.md +247 -0
  107. package/docs/document-reader.md +6 -6
  108. package/docs/documents.md +214 -0
  109. package/docs/embeddings.md +112 -0
  110. package/docs/enterprise-postgres-state.md +7 -7
  111. package/docs/evaluations.md +41 -7
  112. package/docs/extensions.md +3 -3
  113. package/docs/forge-integration.md +3 -3
  114. package/docs/graft.md +5 -5
  115. package/docs/guardrails.md +2 -2
  116. package/docs/host-security.md +16 -15
  117. package/docs/image-generation.md +129 -0
  118. package/docs/impeccable.md +7 -5
  119. package/docs/index.md +84 -46
  120. package/docs/indexed-code-search.md +2 -2
  121. package/docs/language-intelligence.md +4 -4
  122. package/docs/live-testing.md +126 -0
  123. package/docs/mcp-tools.md +44 -13
  124. package/docs/middleware-hooks.md +1 -1
  125. package/docs/migrate-to-0.4.md +312 -0
  126. package/docs/migrate-to-0.5.md +122 -0
  127. package/docs/migration.md +51 -1
  128. package/docs/model-registry.md +38 -0
  129. package/docs/model-routing.md +6 -6
  130. package/docs/moderation.md +117 -0
  131. package/docs/multi-agent-patterns.md +177 -0
  132. package/docs/multimodal-content.md +27 -3
  133. package/docs/obscura.md +12 -12
  134. package/docs/observability.md +32 -7
  135. package/docs/openapi-tools.md +14 -4
  136. package/docs/operations.md +11 -0
  137. package/docs/performance.md +30 -10
  138. package/docs/persistence-credentials-multimodality-primitives.md +7 -7
  139. package/docs/policy-and-audit.md +18 -8
  140. package/docs/ponytail.md +3 -3
  141. package/docs/postgres-persistence.md +5 -5
  142. package/docs/process-sessions.md +2 -2
  143. package/docs/prompt-registry.md +106 -0
  144. package/docs/provider-caching.md +36 -32
  145. package/docs/provider-conformance.md +24 -2
  146. package/docs/provider-packages.md +58 -22
  147. package/docs/provider-primitives.md +5 -5
  148. package/docs/provider-request-policies.md +1 -1
  149. package/docs/providers/ai-sdk.md +18 -6
  150. package/docs/providers/alibaba.md +10 -6
  151. package/docs/providers/anthropic.md +10 -6
  152. package/docs/providers/azure.md +20 -4
  153. package/docs/providers/bedrock.md +18 -3
  154. package/docs/providers/clinepass.md +7 -3
  155. package/docs/providers/commandcode.md +253 -0
  156. package/docs/providers/deepseek.md +7 -3
  157. package/docs/providers/google.md +8 -4
  158. package/docs/providers/hyper.md +284 -0
  159. package/docs/providers/kimi.md +7 -3
  160. package/docs/providers/neuralwatt.md +12 -8
  161. package/docs/providers/ollama.md +18 -3
  162. package/docs/providers/openai-compatible.md +5 -1
  163. package/docs/providers/openai.md +9 -5
  164. package/docs/providers/opencode-go.md +8 -4
  165. package/docs/providers/openrouter.md +8 -4
  166. package/docs/providers/vertex.md +21 -5
  167. package/docs/providers/xai.md +7 -3
  168. package/docs/providers/zai.md +7 -3
  169. package/docs/rag.md +31 -9
  170. package/docs/release-and-install.md +181 -76
  171. package/docs/resource-loading.md +1 -1
  172. package/docs/runs-and-usage.md +28 -3
  173. package/docs/server.md +94 -5
  174. package/docs/settings-auth-trust-security.md +7 -5
  175. package/docs/sheets.md +229 -0
  176. package/docs/speech.md +126 -0
  177. package/docs/sqlite-persistence.md +4 -4
  178. package/docs/supervisors.md +4 -3
  179. package/docs/thinking-and-reasoning.md +93 -60
  180. package/docs/tool-conformance.md +28 -3
  181. package/docs/tool-execution-primitives.md +8 -8
  182. package/docs/tools.md +32 -5
  183. package/docs/web-tools.md +3 -3
  184. package/docs/wiki.md +7 -7
  185. package/docs/work-artifacts-and-review.md +17 -6
  186. package/docs/work-connectors.md +4 -4
  187. package/docs/work-tools.md +5 -5
  188. package/docs/workflow-orchestration-primitives.md +35 -11
  189. package/docs/workflows.md +74 -13
  190. package/docs/working-and-semantic-memory.md +53 -5
  191. package/package.json +14 -31
  192. package/templates/README.md +23 -0
  193. package/templates/deep-research/README.md.tmpl +47 -0
  194. package/templates/deep-research/env.example.tmpl +12 -0
  195. package/templates/deep-research/gitignore.tmpl +7 -0
  196. package/templates/deep-research/manifest.json +12 -0
  197. package/templates/deep-research/package.json.tmpl +23 -0
  198. package/templates/deep-research/src/agent.ts.tmpl +81 -0
  199. package/templates/deep-research/src/index.ts.tmpl +53 -0
  200. package/templates/deep-research/src/tests/research.test.ts.tmpl +114 -0
  201. package/templates/deep-research/src/tools.ts.tmpl +86 -0
  202. package/templates/deep-research/src/types.ts.tmpl +45 -0
  203. package/templates/deep-research/src/workflow.ts.tmpl +156 -0
  204. package/templates/deep-research/tsconfig.json.tmpl +15 -0
  205. package/templates/init/manifest.json +5 -0
  206. package/templates/init/package.json.tmpl +2 -1
  207. package/templates/init/providers.json +40 -24
  208. package/docs/antigravity-agent.md +0 -207
@@ -0,0 +1,391 @@
1
+ /** Context-assembly + runInternal orchestrator (plan 059). */
2
+ import { AgentRunSuspended } from "../../agent-approval.js";
3
+ import { resolveLoop, resolveToolConcurrency } from "../../agent-loops.js";
4
+ import { validateRunStateOptions } from "../../agent-run-state.js";
5
+ import { activeTools } from "../../agent-tool-dispatch.js";
6
+ import { AgentLoopStateError, AgentRunError, AgentRunStateError } from "../../contracts.js";
7
+ import { assertGuardrailsAllowed, runGuardrails } from "../../guardrails.js";
8
+ import { identityTelemetryAttributes, ownershipFromIdentity, resolveRunIdentity } from "../../identity.js";
9
+ import { assembleProviderInput } from "../../input.js";
10
+ import { errorToErrorInfo, redactRunLedgerRecord } from "../../redaction.js";
11
+ import { RunLimitError, RunLimitTracker, resolveRunLimits } from "../../run-limits.js";
12
+ import { createSessionEntry } from "../../session-stores.js";
13
+ import { resolveSkillsDisclosure } from "../../skill-disclosure.js";
14
+ import { applyRestoredSkillBodies } from "../../skill-load.js";
15
+ import { assertStructuredOutputRequestSupported, resolveRunProviderOptions } from "../../structured-output.js";
16
+ import { composeSystemPrompt, mergeSystemPromptConfig } from "../../system-prompts.js";
17
+ import { resolveToolResultFold } from "../../tool-result-fold.js";
18
+ import { createSearchToolsTool, createToolSearchState, resolveToolsDisclosure } from "../../tool-search.js";
19
+ import { createToolRegistry } from "../../tools.js";
20
+ import { bridgeAbort, createUsageAccumulator, inputToMessages, isDurableLoop, isSteerSoftInterrupt, mergeGuardrails, throwIfAborted, } from "../helpers.js";
21
+ import { cleanupRun, persistDurable, persistSucceeded, suspendDurable } from "./persist.js";
22
+ import { generateWithRetry, recordProviderUsage } from "./provider-round.js";
23
+ import { bindChargeToolRound, bindDispatchToolCall, replayDurableNestedAndPending, runLoopUntilSettled, suspendGatedRound, } from "./tool-round.js";
24
+ const PROMPT_VERSION_MAX_NAME_BYTES = 256;
25
+ const PROMPT_VERSION_HASH_PATTERN = /^sha256:[0-9a-f]{64}$/;
26
+ function assertPromptVersionRef(ref) {
27
+ if (ref === undefined)
28
+ return undefined;
29
+ if (typeof ref !== "object" || ref === null)
30
+ throw new TypeError("RunOptions.promptVersion must be a PromptVersionRef object");
31
+ const { name, version, hash } = ref;
32
+ if (typeof name !== "string" || name.length === 0 || Buffer.byteLength(name, "utf8") > PROMPT_VERSION_MAX_NAME_BYTES) {
33
+ throw new TypeError(`RunOptions.promptVersion.name must be 1-${PROMPT_VERSION_MAX_NAME_BYTES} UTF-8 bytes`);
34
+ }
35
+ if (!Number.isInteger(version) || version < 1 || version > 0x7fffffff) {
36
+ throw new TypeError("RunOptions.promptVersion.version must be an integer in [1, 2147483647]");
37
+ }
38
+ if (typeof hash !== "string" || !PROMPT_VERSION_HASH_PATTERN.test(hash)) {
39
+ throw new TypeError('RunOptions.promptVersion.hash must be "sha256:" plus 64 lowercase hex characters');
40
+ }
41
+ return ref;
42
+ }
43
+ async function assembleRoundContext(params) {
44
+ const { session, input, options, runId, resumed, controller, model, startedAt, promptVersion, metadata, limits, runUsage } = params;
45
+ session.resolveRunProvider(options);
46
+ throwIfAborted(controller.signal);
47
+ session.emit({ type: "agent_started", sessionId: session.id, runId });
48
+ if (resumed)
49
+ session.emit({ type: "agent_resumed", sessionId: session.id, runId, version: resumed.version });
50
+ const startRecord = {
51
+ id: runId,
52
+ sessionId: session.id,
53
+ branchId: session.currentLeafId,
54
+ model,
55
+ provider: model.provider,
56
+ idempotencyKey: session.activeIdempotencyKey,
57
+ status: "running",
58
+ startedAt,
59
+ ...(promptVersion ? { promptVersion } : {}),
60
+ ...session.activeOwnership,
61
+ };
62
+ await session.activeLedger?.appendRun(redactRunLedgerRecord(startRecord, session.activeRedactor));
63
+ await session.rebuildHistory();
64
+ const { registry: baseRegistry, tools: activeToolList } = activeTools(session.agent.config.tools);
65
+ const toolsDisclosure = resolveToolsDisclosure(options.toolsDisclosure, session.agent.config.toolsDisclosure);
66
+ const toolSearch = toolsDisclosure === "search" && activeToolList.length > 0
67
+ ? {
68
+ state: createToolSearchState({
69
+ tools: activeToolList,
70
+ activated: session.activatedTools,
71
+ search: session.agent.config.toolsSearch,
72
+ }),
73
+ }
74
+ : undefined;
75
+ const searchTool = toolSearch ? createSearchToolsTool(toolSearch.state) : undefined;
76
+ const registry = searchTool ? createToolRegistry([...activeToolList, searchTool]) : baseRegistry;
77
+ const tools = searchTool ? [...activeToolList, searchTool] : activeToolList;
78
+ const activeSkills = session.resolveRunSkills(options, tools);
79
+ session.activeRunSkills = activeSkills;
80
+ if (options.model && JSON.stringify(options.model) !== JSON.stringify(session.agent.config.model)) {
81
+ await session.appendEntry(createSessionEntry({
82
+ sessionId: session.id,
83
+ parentId: session.currentLeafId,
84
+ runId,
85
+ kind: "model_change",
86
+ previousModel: session.agent.config.model,
87
+ model: options.model,
88
+ }));
89
+ }
90
+ const inputMessages = inputToMessages(input).map((message) => session.redact(message));
91
+ const inputGuardrails = await runGuardrails({
92
+ stage: "input",
93
+ guardrails: session.activeGuardrails,
94
+ value: inputMessages,
95
+ context: { sessionId: session.id, runId, metadata, signal: controller.signal },
96
+ redactor: session.activeRedactor,
97
+ emit: (event) => session.emit(event),
98
+ });
99
+ const approvedByResume = resumed !== undefined && inputGuardrails.terminal?.action === "interrupt" && session.activeDurable !== undefined;
100
+ if (inputGuardrails.terminal?.action === "interrupt" && session.activeDurable && !approvedByResume) {
101
+ const interruption = { kind: "input_guardrail", reason: inputGuardrails.terminal.reason ?? "Input requires approval" };
102
+ throw new AgentRunSuspended(await suspendDurable(session, { runId, model, limits, interruption, messages: inputMessages }), interruption);
103
+ }
104
+ if (inputGuardrails.terminal && !approvedByResume)
105
+ assertGuardrailsAllowed(inputGuardrails);
106
+ for (const message of inputMessages)
107
+ await session.appendMessage(message, runId);
108
+ await session.autoCompact(runId, options, controller.signal, inputMessages);
109
+ const maxToolRounds = resolveRunLimits(session.agent.config.limits, options.limits).maxToolRounds;
110
+ const systemInstructions = composeSystemPrompt(mergeSystemPromptConfig(session.agent.config.systemPrompt, options.systemPrompt), {
111
+ base: session.agent.config.instructions,
112
+ });
113
+ const contextProviders = [...(session.agent.config.context ?? []), ...activeSkills.flatMap((skill) => skill.context ?? [])];
114
+ const providerOptions = resolveRunProviderOptions(options, session.agent.config);
115
+ assertStructuredOutputRequestSupported(options.model ?? session.agent.config.model, providerOptions);
116
+ const validate = options.validate ?? session.agent.config.validator;
117
+ const instructionInjectors = options.instructionInjectors ?? session.agent.config.instructionInjectors ?? [];
118
+ const inputLayout = options.inputLayout ?? session.agent.config.inputLayout;
119
+ const loop = resolveLoop(options, session.agent.config);
120
+ session.activeLoop = loop;
121
+ const toolConcurrency = resolveToolConcurrency(options, session.agent.config);
122
+ session.activeLoopTurn = 1;
123
+ const ctx = {
124
+ session,
125
+ input,
126
+ options,
127
+ runId,
128
+ resumed,
129
+ controller,
130
+ model,
131
+ metadata,
132
+ limits,
133
+ registry,
134
+ tools,
135
+ activeSkills,
136
+ inputMessages,
137
+ maxToolRounds,
138
+ systemInstructions,
139
+ contextProviders,
140
+ providerOptions,
141
+ validate,
142
+ instructionInjectors,
143
+ inputLayout,
144
+ loop,
145
+ toolConcurrency,
146
+ toolsDisclosure,
147
+ assembledTurn: false,
148
+ artifactFinished: false,
149
+ artifactFailedInfo: undefined,
150
+ runUsage,
151
+ loopCtx: undefined,
152
+ };
153
+ const loopCtx = {
154
+ sessionId: session.id,
155
+ runId,
156
+ metadata,
157
+ signal: controller.signal,
158
+ history: session.history,
159
+ input,
160
+ inputMessages,
161
+ maxToolRounds,
162
+ toolConcurrency,
163
+ restoredLoopState: resumed?.state?.loopState?.snapshot,
164
+ assemble: async (nextInput, toolResults, turn) => {
165
+ limits.charge("maxTurns");
166
+ const request = await assembleProviderInput({
167
+ model: options.model ?? session.agent.config.model,
168
+ input: nextInput,
169
+ history: session.history,
170
+ summaries: (await session.snapshot()).summaries,
171
+ toolResults: toolResults ?? [],
172
+ turn,
173
+ instructionInjectors,
174
+ inputLayout,
175
+ systemInstructions,
176
+ inputBuilder: session.agent.config.inputBuilder,
177
+ promptBuilder: session.agent.config.promptBuilder,
178
+ contextProviders,
179
+ skills: session.restoredSkillBodies.length ? applyRestoredSkillBodies(activeSkills, session.restoredSkillBodies) : activeSkills,
180
+ skillsDisclosure: resolveSkillsDisclosure(options.skillsDisclosure, session.agent.config.skillsDisclosure),
181
+ toolsDisclosure,
182
+ toolsSearch: session.agent.config.toolsSearch,
183
+ activatedTools: session.activatedTools,
184
+ toolResultFold: resolveToolResultFold(options.toolResultFold, session.agent.config.toolResultFold),
185
+ loadedSkills: session.loadedSkills,
186
+ tools,
187
+ resourceLoader: session.agent.config.resourceLoader,
188
+ permission: session.agent.config.permission,
189
+ trust: session.agent.config.trust,
190
+ providerOptions,
191
+ redactor: session.activeRedactor,
192
+ middleware: session.agent.config.middleware,
193
+ sessionId: session.id,
194
+ runId,
195
+ metadata,
196
+ signal: controller.signal,
197
+ });
198
+ ctx.assembledTurn = true;
199
+ return request;
200
+ },
201
+ chargeToolRound: bindChargeToolRound(ctx),
202
+ generate: async (request) => {
203
+ await suspendGatedRound(ctx);
204
+ if (!ctx.assembledTurn)
205
+ limits.charge("maxTurns");
206
+ ctx.assembledTurn = false;
207
+ const policyResult = await session.applyProviderRequestPolicies(request, runId, options, metadata, controller.signal);
208
+ const middlewareRequest = (await session.agent.config.middleware?.run("provider_request", policyResult.request)) ?? policyResult.request;
209
+ try {
210
+ return await generateWithRetry(session, session.redactProviderRequest(middlewareRequest), runId, options, controller.signal, policyResult.secrets, session.activeLoopTurn, (turnUsage, turn, attempt) => recordProviderUsage(ctx, turnUsage, turn, attempt));
211
+ }
212
+ catch (error) {
213
+ if (isSteerSoftInterrupt(error)) {
214
+ return { content: [], calls: [], started: false, usage: undefined };
215
+ }
216
+ throw error;
217
+ }
218
+ },
219
+ isToolCallExclusive: (call) => registry.get(call.name)?.exclusive === true,
220
+ dispatchToolCall: bindDispatchToolCall(ctx),
221
+ appendMessage: (message) => session.appendMessage(message, runId),
222
+ hasPendingSteers: () => session.pendingSteers.length > 0,
223
+ applyPendingSteers: () => session.applyPendingSteers(runId, metadata, controller.signal),
224
+ emit: (event) => {
225
+ if (event.type === "turn_started")
226
+ session.activeLoopTurn = event.turn;
227
+ if (event.type === "artifact_finished")
228
+ ctx.artifactFinished = true;
229
+ if (event.type === "artifact_failed") {
230
+ const first = event.result.errors?.[0];
231
+ const reason = event.result.metadata?.reason;
232
+ ctx.artifactFailedInfo = {
233
+ message: first?.message ?? "artifact failed",
234
+ code: typeof reason === "string" || typeof reason === "number" ? reason : "artifact_failed",
235
+ };
236
+ }
237
+ session.emit(event);
238
+ },
239
+ };
240
+ ctx.loopCtx = loopCtx;
241
+ return ctx;
242
+ }
243
+ export async function executeRun(session, input, options, runId, resumed) {
244
+ const legacyMaxToolRounds = options.maxToolRounds;
245
+ if (legacyMaxToolRounds !== undefined) {
246
+ throw new TypeError("RunOptions.maxToolRounds was removed in 0.1.5; use RunOptions.limits.maxToolRounds instead");
247
+ }
248
+ const promptVersion = assertPromptVersionRef(options.promptVersion);
249
+ if (session.agent.config.secure &&
250
+ (options.redactor !== undefined ||
251
+ options.ownership !== undefined ||
252
+ options.validate !== undefined ||
253
+ options.effectStore !== undefined ||
254
+ options.runState !== undefined)) {
255
+ throw new AgentRunStateError("Secure agent defaults cannot be replaced per run");
256
+ }
257
+ const requestedLimits = options.limits;
258
+ const resolvedLimits = resolveRunLimits(session.agent.config.limits, requestedLimits);
259
+ const durableOptions = options.runState ?? session.agent.config.runState;
260
+ if (session.agent.config.runState && options.runState && session.agent.config.runState !== options.runState) {
261
+ throw new AgentRunStateError("RunOptions cannot replace agent durable run-state configuration");
262
+ }
263
+ if (durableOptions) {
264
+ validateRunStateOptions(durableOptions);
265
+ if (options.model || options.guardrails || options.loop || options.effectStore)
266
+ throw new AgentRunStateError("Durable runs require model, guardrails, loop, and effect store on AgentConfig for fingerprinting");
267
+ const configuredLoop = session.agent.config.loop;
268
+ if (configuredLoop && !isDurableLoop(configuredLoop)) {
269
+ throw new AgentLoopStateError("ERR_PRISM_LOOP_NOT_DURABLE", "Custom AgentLoopStrategy on a durable run requires snapshot and restore hooks");
270
+ }
271
+ }
272
+ if (session.activeRun) {
273
+ const error = new Error("Agent session already has an active run");
274
+ session.emit({ type: "error", sessionId: session.id, runId, error: errorToErrorInfo(error) });
275
+ throw error;
276
+ }
277
+ const controller = new AbortController();
278
+ const cleanupSignal = bridgeAbort(options.signal, controller);
279
+ session.activeRun = controller;
280
+ session.activeRunId = runId;
281
+ session.pendingSteers = [];
282
+ session.pendingSteerBytes = 0;
283
+ session.pendingSoftInterrupt = false;
284
+ session.activeRedactor = options.redactor ?? session.agent.config.redactor;
285
+ session.activeLedger = options.runLedger ?? session.agent.config.runLedger;
286
+ session.activeEffectStore = options.effectStore ?? session.agent.config.effectStore;
287
+ session.activeOwnership = options.ownership ?? session.agent.config.ownership;
288
+ session.activeIdentity = resolveRunIdentity(options.identity, session.agent.config.identity, session.activeOwnership);
289
+ if (session.activeIdentity && !session.activeOwnership)
290
+ session.activeOwnership = ownershipFromIdentity(session.activeIdentity);
291
+ session.activeIdempotencyKey = options.idempotencyKey ?? session.agent.config.idempotencyKey;
292
+ session.activeGuardrails = mergeGuardrails(session.agent.config.guardrails, options.guardrails);
293
+ session.activeDurable = resumed ?? (durableOptions ? { options: durableOptions, version: 0 } : undefined);
294
+ session.activeGatedRound = undefined;
295
+ if (resumed)
296
+ session.invalidateSnapshot();
297
+ const model = options.model ?? session.agent.config.model;
298
+ const startedAt = new Date().toISOString();
299
+ let runError;
300
+ let runStatus = "succeeded";
301
+ const runUsage = createUsageAccumulator();
302
+ let usage;
303
+ const metadata = {
304
+ ...session.agent.config.metadata,
305
+ ...session.metadata,
306
+ ...options.metadata,
307
+ ...(session.activeIdentity ? identityTelemetryAttributes(session.activeIdentity) : {}),
308
+ };
309
+ session.activeMetadata = metadata;
310
+ session.activePromptVersion = promptVersion;
311
+ const limits = new RunLimitTracker(resolvedLimits, {
312
+ onExceeded: (breach) => {
313
+ session.emit({ type: "run_limit_exceeded", sessionId: session.id, runId, breach });
314
+ controller.abort(new RunLimitError(breach));
315
+ },
316
+ snapshot: resumed?.state?.counters,
317
+ deadlineAt: resumed?.state?.deadlineAt,
318
+ });
319
+ session.activeLimits = limits;
320
+ session.activeLimitOutputBuffer = [session.agent.config.limits, requestedLimits].some((value) => value?.maxOutputTokens !== undefined || value?.maxTotalTokens !== undefined || value?.maxCost !== undefined);
321
+ try {
322
+ const ctx = await assembleRoundContext({
323
+ session,
324
+ input,
325
+ options,
326
+ runId,
327
+ resumed,
328
+ controller,
329
+ model,
330
+ startedAt,
331
+ promptVersion,
332
+ metadata,
333
+ limits,
334
+ runUsage,
335
+ });
336
+ await replayDurableNestedAndPending(ctx);
337
+ const resumedLoopState = resumed?.state?.loopState;
338
+ if (resumedLoopState) {
339
+ if (ctx.loop.name !== resumedLoopState.name || (ctx.loop.revision ?? "1") !== resumedLoopState.revision) {
340
+ throw new AgentLoopStateError("ERR_PRISM_LOOP_REVISION", `Loop ${resumedLoopState.name} revision ${resumedLoopState.revision} does not match the resumed durable run`);
341
+ }
342
+ ctx.loop.restore?.(resumedLoopState.snapshot);
343
+ }
344
+ const loopUsage = await runLoopUntilSettled(ctx);
345
+ if (ctx.loop.name === "generate-validate-revise" && !ctx.artifactFinished) {
346
+ throw Object.assign(new Error(ctx.artifactFailedInfo?.message ?? "artifact loop ended without a validated artifact"), {
347
+ name: "ArtifactFailed",
348
+ code: ctx.artifactFailedInfo?.code ?? "artifact_failed",
349
+ });
350
+ }
351
+ usage = runUsage.value() ?? loopUsage;
352
+ return await persistSucceeded(ctx, loopUsage);
353
+ }
354
+ catch (error) {
355
+ if (error instanceof AgentRunSuspended) {
356
+ runStatus = "suspended";
357
+ const version = error.state.version;
358
+ session.emit({ type: "agent_suspended", sessionId: session.id, runId, interruption: error.interruption, version });
359
+ return session.buildRunResult({ runId, status: "suspended", runState: error.state, interruption: error.interruption });
360
+ }
361
+ runError = errorToErrorInfo(error);
362
+ session.emit({ type: "error", sessionId: session.id, runId, error: runError });
363
+ const breach = error instanceof RunLimitError ? error.breach : limits.breach;
364
+ runStatus = breach ? "failed" : controller.signal.aborted ? "aborted" : "failed";
365
+ const runState = session.activeDurable?.state
366
+ ? await persistDurable(session, {
367
+ ...session.activeDurable.state,
368
+ status: runStatus,
369
+ interruption: undefined,
370
+ loopState: undefined,
371
+ pendingCalls: undefined,
372
+ nestedRuns: undefined,
373
+ stickyDecisions: undefined,
374
+ })
375
+ : undefined;
376
+ const result = session.buildRunResult({
377
+ runId,
378
+ status: runStatus,
379
+ usage: runUsage.value() ?? usage,
380
+ limit: breach,
381
+ error: runError,
382
+ abortReason: !breach && controller.signal.aborted ? String(controller.signal.reason) : undefined,
383
+ runState,
384
+ });
385
+ throw new AgentRunError(result, { cause: error });
386
+ }
387
+ finally {
388
+ await cleanupRun({ session, controller, cleanupSignal, runId, model, startedAt, runStatus, runError });
389
+ }
390
+ }
391
+ //# sourceMappingURL=assemble.js.map
@@ -0,0 +1,28 @@
1
+ /** Finalize/persist phase of runInternal (plan 059). */
2
+ import type { PendingToolCall, StoredAgentRunState } from "../../agent-run-state.js";
3
+ import type { AgentRunResult, AgentRunState, ErrorInfo, Message, ModelConfig, NestedRunRef, Usage } from "../../contracts.js";
4
+ import type { RunLimitTracker } from "../../run-limits.js";
5
+ import type { RoundContext, SessionHost } from "./types.js";
6
+ export declare function persistDurable(session: SessionHost, state: StoredAgentRunState): Promise<AgentRunState>;
7
+ export declare function suspendDurable(session: SessionHost, input: {
8
+ readonly runId: string;
9
+ readonly model: ModelConfig;
10
+ readonly limits: RunLimitTracker;
11
+ readonly interruption: import("../../contracts.js").AgentRunInterruption;
12
+ readonly messages?: readonly Message[];
13
+ readonly pending?: StoredAgentRunState["pending"];
14
+ readonly pendingCalls?: readonly PendingToolCall[];
15
+ /** Full replacement when provided; otherwise the recorded nested runs are preserved. */
16
+ readonly nestedRuns?: readonly NestedRunRef[];
17
+ }): Promise<AgentRunState>;
18
+ export declare function persistSucceeded(ctx: RoundContext, loopUsage: Usage | undefined): Promise<AgentRunResult>;
19
+ export declare function cleanupRun(input: {
20
+ session: SessionHost;
21
+ controller: AbortController;
22
+ cleanupSignal: () => void;
23
+ runId: string;
24
+ model: ModelConfig;
25
+ startedAt: string;
26
+ runStatus: AgentRunResult["status"];
27
+ runError: ErrorInfo | undefined;
28
+ }): Promise<void>;
@@ -0,0 +1,166 @@
1
+ /** Finalize/persist phase of runInternal (plan 059). */
2
+ import { boundedLoopSnapshot, initialAgentRunState, publicState, saveAgentRunState } from "../../agent-run-state.js";
3
+ import { AgentRunStateError } from "../../contracts.js";
4
+ import { redactRunLedgerRecord } from "../../redaction.js";
5
+ import { isFlushableRunLedger } from "../../run-ledger.js";
6
+ import { snapshotLoadedSkillBodies } from "../../skill-load.js";
7
+ import { randomId } from "../helpers.js";
8
+ export async function persistDurable(session, state) {
9
+ const durable = session.activeDurable;
10
+ if (!durable)
11
+ throw new AgentRunStateError("Durable run state is not configured");
12
+ const persisted = durable.options.persistSessionState
13
+ ? {
14
+ ...state,
15
+ sessionState: {
16
+ loadedSkillNames: session.loadedSkills.list(),
17
+ ...(session.activatedTools.list().length ? { activatedToolNames: session.activatedTools.list() } : {}),
18
+ ...(durable.options.includeSkillBodies
19
+ ? {
20
+ loadedSkillBodies: snapshotLoadedSkillBodies(session.activeRunSkills, session.loadedSkills, session.restoredSkillBodies.length
21
+ ? new Map(session.restoredSkillBodies.map((e) => [e.name, e.instructions]))
22
+ : undefined),
23
+ }
24
+ : {}),
25
+ },
26
+ }
27
+ : state;
28
+ const saved = await saveAgentRunState({
29
+ checkpoints: durable.options.checkpoints,
30
+ state: persisted,
31
+ expectedVersion: durable.version,
32
+ ownership: session.activeOwnership,
33
+ fencingToken: durable.options.fencingToken,
34
+ redactor: session.activeRedactor,
35
+ maxStateBytes: durable.options.maxStateBytes,
36
+ });
37
+ durable.state = saved.state;
38
+ durable.version = saved.record.version;
39
+ return publicState(saved.state);
40
+ }
41
+ export async function suspendDurable(session, input) {
42
+ const durable = session.activeDurable;
43
+ if (!durable)
44
+ throw new AgentRunStateError("Durable interruption is not configured");
45
+ const loop = session.activeLoop;
46
+ const loopState = loop?.snapshot ? boundedLoopSnapshot(loop.name, loop.revision ?? "1", loop.snapshot()) : undefined;
47
+ const state = durable.state ??
48
+ initialAgentRunState({
49
+ agent: session.agent,
50
+ options: durable.options,
51
+ runId: input.runId,
52
+ sessionId: session.id,
53
+ leafId: session.currentLeafId,
54
+ model: input.model,
55
+ counters: input.limits.snapshot(),
56
+ deadlineAt: input.limits.deadlineAt,
57
+ status: "suspended",
58
+ interruption: input.interruption,
59
+ messages: input.messages,
60
+ pending: input.pending,
61
+ pendingCalls: input.pendingCalls,
62
+ interruptBeforeTool: durable.options.interruptBeforeTool,
63
+ });
64
+ return persistDurable(session, {
65
+ ...state,
66
+ leafId: session.currentLeafId,
67
+ status: "suspended",
68
+ interruption: input.interruption,
69
+ ...(input.messages ? { input: input.messages } : {}),
70
+ ...(input.pending ? { pending: input.pending } : {}),
71
+ ...(input.pendingCalls ? { pendingCalls: input.pendingCalls } : {}),
72
+ nestedRuns: input.nestedRuns ?? state.nestedRuns,
73
+ ...(loopState ? { loopState } : {}),
74
+ counters: input.limits.snapshot(),
75
+ });
76
+ }
77
+ export async function persistSucceeded(ctx, loopUsage) {
78
+ const { session, runId, runUsage } = ctx;
79
+ const usage = runUsage.value() ?? loopUsage;
80
+ if (usage && session.activeLedger) {
81
+ const usageRecord = {
82
+ id: randomId("usage"),
83
+ sessionId: session.id,
84
+ runId,
85
+ scope: "run_total",
86
+ usage,
87
+ recordedAt: new Date().toISOString(),
88
+ ...session.activeOwnership,
89
+ };
90
+ await session.activeLedger.appendUsage(redactRunLedgerRecord(usageRecord, session.activeRedactor));
91
+ }
92
+ await session.drainLedger();
93
+ const runState = session.activeDurable?.state
94
+ ? await persistDurable(session, {
95
+ ...session.activeDurable.state,
96
+ status: "succeeded",
97
+ pending: undefined,
98
+ pendingCalls: undefined,
99
+ nestedRuns: undefined,
100
+ stickyDecisions: undefined,
101
+ interruption: undefined,
102
+ loopState: undefined,
103
+ })
104
+ : undefined;
105
+ session.emit({
106
+ type: "agent_finished",
107
+ sessionId: session.id,
108
+ runId,
109
+ usage,
110
+ ...(ctx.loopCtx.finishReason ? { finishReason: ctx.loopCtx.finishReason } : {}),
111
+ });
112
+ return session.buildRunResult({ runId, status: "succeeded", usage, runState });
113
+ }
114
+ export async function cleanupRun(input) {
115
+ const { session, controller, cleanupSignal, runId, model, startedAt, runStatus, runError } = input;
116
+ if (session.activeRun === controller)
117
+ session.activeRun = undefined;
118
+ session.activeRunId = undefined;
119
+ session.activeLoop = undefined;
120
+ session.activeGatedRound = undefined;
121
+ session.activeProviderTurnAbort = undefined;
122
+ session.pendingSoftInterrupt = false;
123
+ session.pendingSteers = [];
124
+ session.pendingSteerBytes = 0;
125
+ try {
126
+ await session.drainLedger();
127
+ if (session.activeLedger) {
128
+ const finishRecord = {
129
+ id: runId,
130
+ sessionId: session.id,
131
+ branchId: session.currentLeafId,
132
+ model,
133
+ provider: model.provider,
134
+ idempotencyKey: session.activeIdempotencyKey,
135
+ status: runStatus,
136
+ startedAt,
137
+ finishedAt: new Date().toISOString(),
138
+ abortReason: controller.signal.aborted ? String(controller.signal.reason) : undefined,
139
+ error: runError,
140
+ ...(session.activePromptVersion ? { promptVersion: session.activePromptVersion } : {}),
141
+ ...session.activeOwnership,
142
+ };
143
+ await session.activeLedger.appendRun(redactRunLedgerRecord(finishRecord, session.activeRedactor));
144
+ if (isFlushableRunLedger(session.activeLedger) && session.activeLedger.durability === "flush_on_terminal")
145
+ await session.activeLedger.flush();
146
+ }
147
+ }
148
+ finally {
149
+ session.activeLedger = undefined;
150
+ session.activeEffectStore = undefined;
151
+ session.activeOwnership = undefined;
152
+ session.activeIdentity = undefined;
153
+ session.activeIdempotencyKey = undefined;
154
+ session.activeGuardrails = undefined;
155
+ session.activeMetadata = undefined;
156
+ session.activePromptVersion = undefined;
157
+ session.activeLimits?.dispose();
158
+ session.activeLimits = undefined;
159
+ session.activeLimitOutputBuffer = false;
160
+ session.activeRedactor = undefined;
161
+ session.activeProvider = undefined;
162
+ cleanupSignal();
163
+ session.closeSubscribers();
164
+ }
165
+ }
166
+ //# sourceMappingURL=persist.js.map
@@ -0,0 +1,6 @@
1
+ /** Provider-round phase of runInternal (plan 059). */
2
+ import type { ProviderRequest, ProviderTurnResult, RunOptions, Usage } from "../../contracts.js";
3
+ import type { RoundContext, SessionHost } from "./types.js";
4
+ export declare function recordProviderUsage(ctx: RoundContext, turnUsage: Usage | undefined, turn: number, attempt: number): Promise<void>;
5
+ export declare function generateWithRetry(session: SessionHost, request: ProviderRequest, runId: string, options: RunOptions, signal: AbortSignal, requestSecrets?: readonly (string | undefined)[], turn?: number, recordUsage?: (usage: Usage | undefined, turn: number, attempt: number) => Promise<void>): Promise<ProviderTurnResult>;
6
+ export declare function generateProviderTurn(session: SessionHost, request: ProviderRequest, runId: string, signal: AbortSignal, secrets?: readonly (string | undefined)[], turn?: number, attempt?: number, recordUsage?: (usage: Usage | undefined, turn: number, attempt: number) => Promise<void>): Promise<ProviderTurnResult>;