@arnilo/prism 0.0.4 → 0.0.5
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 +18 -0
- package/README.md +34 -10
- package/dist/agents.js +146 -19
- package/dist/cli-init.d.ts +41 -0
- package/dist/cli-init.js +390 -0
- package/dist/cli-runner.d.ts +7 -1
- package/dist/cli-runner.js +13 -1
- package/dist/content.d.ts +19 -0
- package/dist/content.js +197 -69
- package/dist/contracts.d.ts +94 -9
- package/dist/contracts.js +8 -0
- package/dist/feedback.d.ts +48 -0
- package/dist/feedback.js +230 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/providers/media.d.ts +3 -1
- package/dist/providers/media.js +11 -1
- package/dist/testing/feedback.d.ts +6 -0
- package/dist/testing/feedback.js +37 -0
- package/dist/testing/persistence-schema.d.ts +3 -3
- package/dist/testing/persistence-schema.js +32 -2
- package/dist/testing/run-ledger-conformance.js +7 -1
- package/docs/a2a.md +73 -0
- package/docs/agent-events.md +4 -6
- package/docs/agent-loops.md +1 -1
- package/docs/agent-session-runtime.md +14 -16
- package/docs/cli-rpc.md +35 -7
- package/docs/coding-agent-tools.md +2 -2
- package/docs/coding-security.md +7 -3
- package/docs/compaction-observational-memory.md +2 -0
- package/docs/context-and-skills.md +1 -0
- package/docs/credentials-and-redaction.md +2 -2
- package/docs/database-persistence.md +9 -6
- package/docs/evaluations.md +122 -0
- package/docs/extensions.md +2 -2
- package/docs/host-security.md +20 -3
- package/docs/index.md +29 -17
- package/docs/mcp-tools.md +49 -4
- package/docs/migration.md +33 -3
- package/docs/multimodal-content.md +14 -6
- package/docs/observability.md +14 -6
- package/docs/performance.md +209 -0
- package/docs/postgres-persistence.md +6 -4
- package/docs/provider-conformance.md +1 -0
- package/docs/provider-packages.md +2 -0
- package/docs/providers/ai-sdk.md +113 -0
- package/docs/public-contracts.md +6 -5
- package/docs/rag.md +113 -0
- package/docs/release-and-install.md +100 -77
- package/docs/review-coverage-2026-07-15.md +193 -0
- package/docs/runs-and-usage.md +41 -4
- package/docs/server.md +139 -0
- package/docs/settings-auth-trust-security.md +5 -5
- package/docs/sqlite-persistence.md +4 -3
- package/docs/supervisors.md +71 -0
- package/docs/workflow-orchestration-primitives.md +19 -3
- package/docs/workflows.md +97 -23
- package/docs/working-and-semantic-memory.md +169 -0
- package/package.json +12 -2
- package/templates/init/README.md.tmpl +28 -0
- package/templates/init/env.example.tmpl +1 -0
- package/templates/init/gitignore.tmpl +11 -0
- package/templates/init/optional/evals-example.ts.tmpl +17 -0
- package/templates/init/optional/workflows-example.ts.tmpl +27 -0
- package/templates/init/package.json.tmpl +22 -0
- package/templates/init/providers.json +76 -0
- package/templates/init/src/agent.ts.tmpl +10 -0
- package/templates/init/src/index.ts.tmpl +12 -0
- package/templates/init/src/tests/agent.test.ts.tmpl +24 -0
- package/templates/init/tsconfig.json.tmpl +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.0.5] - 2026-07-16
|
|
11
|
+
|
|
12
|
+
- `@arnilo/prism-providers` now installs all seven first-party adapters including AI SDK interoperability; `@arnilo/prism-all` now installs every first-party package while activating none automatically.
|
|
13
|
+
|
|
14
|
+
- Added optional `@arnilo/prism-supervisor` with bounded explicit child delegation, derived memory scope IDs, narrowing-only permissions, A2A 1.0 cards/ES256 signatures, authorized JSON-RPC/SSE serving, and an exact-origin remote client.
|
|
15
|
+
|
|
16
|
+
- Added bounded immutable run/trace feedback with exact ownership, evaluation linkage, memory/SQLite/PostgreSQL stores, schema migration 003, and safe OpenTelemetry projection.
|
|
17
|
+
|
|
18
|
+
- Phase 11 extends workflows with explicit durable schedules/background execution, nested composition, bounded validated state, immutable-lineage replay, and optional command/Web bindings over existing checkpoint/lease primitives.
|
|
19
|
+
|
|
20
|
+
- Optional `@arnilo/prism-server` package with authorized bounded Web-standard direct/SSE agent and durable workflow routes; `@arnilo/prism-mcp` now supports explicit authorized Prism tool/command server exposure and bounded Web-standard Streamable HTTP handling.
|
|
21
|
+
- Optional `@arnilo/prism-rag` package: bounded deterministic text/Markdown chunking, Phase 7 vector indexing/retrieval, stable citations, metadata filters, redaction, and explicit ContextProvider injection.
|
|
22
|
+
- Workflows now support durable human `suspend()`/approve/deny, expected-version exact-once resume, validated/redacted resume payloads, and opt-in tool approval with execution-policy recheck.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Optional `@arnilo/prism-memory` package: schema/template-backed working memory, semantic recall, package-owned `Embedder`/`VectorStore` contracts, in-memory adapters, context provider, opt-in processor, shared conformance, and PostgreSQL/pgvector production path.
|
|
27
|
+
|
|
10
28
|
## [0.0.4] - 2026-07-14
|
|
11
29
|
|
|
12
30
|
### Added
|
package/README.md
CHANGED
|
@@ -26,13 +26,14 @@ packages. Prism defines contracts, not apps.
|
|
|
26
26
|
- **Input/prompt/context**: default input and prompt builders, system-prompt
|
|
27
27
|
layering, and provider-input assembly — every stage replaceable.
|
|
28
28
|
- **Sessions and memory**: in-memory and JSONL session stores, branching/fork/
|
|
29
|
-
clone, default and LLM compaction strategies, retry policy,
|
|
30
|
-
observational-memory recall/status/view
|
|
29
|
+
clone, default and LLM compaction strategies, retry policy,
|
|
30
|
+
observational-memory recall/status/view, optional working/semantic memory
|
|
31
|
+
(`@arnilo/prism-memory`), and bounded text/Markdown RAG (`@arnilo/prism-rag`).
|
|
31
32
|
- **Extensions and manifests**: extension kernel + event bus, contribution
|
|
32
33
|
registries, middleware hooks, and data-only package manifests.
|
|
33
34
|
- **Config, settings, security**: layered config merge, settings providers,
|
|
34
35
|
credential resolvers, trust/permission policies, and secret redaction.
|
|
35
|
-
- **CLI/RPC**: `prism --mode print|json|rpc`
|
|
36
|
+
- **CLI/RPC/server**: `prism --mode print|json|rpc`, `prism init`, optional framework-free authorized Web agent/workflow routes, and explicit MCP server exposure.
|
|
36
37
|
|
|
37
38
|
## Install
|
|
38
39
|
|
|
@@ -50,6 +51,8 @@ npm install @arnilo/prism-base # core + compaction
|
|
|
50
51
|
npm install @arnilo/prism-code @arnilo/prism-provider-openai # coding-agent profile
|
|
51
52
|
npm install @arnilo/prism-sdk @arnilo/prism-provider-openai # application profile
|
|
52
53
|
npm install @arnilo/prism-all # every first-party package
|
|
54
|
+
npm install @arnilo/prism-server @arnilo/prism-workflows # optional Web API boundary
|
|
55
|
+
npm install @arnilo/prism-supervisor # optional local delegation + A2A 1.0
|
|
53
56
|
```
|
|
54
57
|
|
|
55
58
|
See [docs/release-and-install.md](docs/release-and-install.md) for install
|
|
@@ -57,6 +60,17 @@ specifiers, tarball contents, and the offline test budget.
|
|
|
57
60
|
|
|
58
61
|
## Quick start
|
|
59
62
|
|
|
63
|
+
Scaffold a tiny project (offline mock test included):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx --package @arnilo/prism prism init my-agent
|
|
67
|
+
# or, with a real provider package selected:
|
|
68
|
+
npx --package @arnilo/prism prism init my-agent --provider openai
|
|
69
|
+
cd my-agent && npm install && npm test
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Or embed Prism directly:
|
|
73
|
+
|
|
60
74
|
```ts
|
|
61
75
|
import { createAgent, createAgentSession, createMockProvider } from "@arnilo/prism";
|
|
62
76
|
|
|
@@ -68,9 +82,18 @@ const agent = createAgent({
|
|
|
68
82
|
|
|
69
83
|
const session = createAgentSession({ agent });
|
|
70
84
|
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
// Direct result: run/prompt return AgentRunResult (text, usage, status, ids).
|
|
86
|
+
const result = await session.run("Hi");
|
|
87
|
+
console.log(result.text, result.usage?.totalTokens);
|
|
88
|
+
|
|
89
|
+
// Integrated streaming: subscribe-before-run for one owned run.
|
|
90
|
+
for await (const event of session.stream("Hi again")) {
|
|
91
|
+
// AgentEvent: agent_started, message_delta, turn_finished, ...
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Long-lived subscribe() still works when you need a subscriber across runs.
|
|
95
|
+
// `subscribe()` only emits while a run is in progress, so the loop and `run()`
|
|
96
|
+
// must run together; awaiting the loop before calling `run()` would deadlock.
|
|
74
97
|
(async () => {
|
|
75
98
|
const consumer = (async () => {
|
|
76
99
|
for await (const event of session.subscribe()) {
|
|
@@ -132,12 +155,13 @@ printf '{"id":"1","command":"prompt","params":{"input":"Hi"}}\n' \
|
|
|
132
155
|
| `@arnilo/prism-coding-security` | coding approval, containment, and sandbox adapters |
|
|
133
156
|
| `@arnilo/prism-tool-validator-json-schema` | bounded JSON Schema tool validation |
|
|
134
157
|
| `@arnilo/prism-mcp` | MCP client/tool bridge |
|
|
135
|
-
| `@arnilo/prism-workflows` | bounded DAG workflows and
|
|
158
|
+
| `@arnilo/prism-workflows` | bounded DAG workflows, durable suspend/resume, schedules/background runs, composition/state/replay, and multi-process coordination |
|
|
159
|
+
| `@arnilo/prism-supervisor` | bounded local child delegation and A2A 1.0 interoperability |
|
|
136
160
|
| `@arnilo/prism-observability-opentelemetry` | optional OpenTelemetry adapter |
|
|
137
161
|
| `@arnilo/prism-credentials-node` | encrypted-file and keychain credentials |
|
|
138
|
-
| `@arnilo/prism-session-store-sqlite` | SQLite persistence/checkpoints/leases |
|
|
139
|
-
| `@arnilo/prism-session-store-postgres` | PostgreSQL persistence/checkpoints/leases |
|
|
140
|
-
| `@arnilo/prism-providers` | family: all
|
|
162
|
+
| `@arnilo/prism-session-store-sqlite` | SQLite persistence/checkpoints/leases/owned run feedback |
|
|
163
|
+
| `@arnilo/prism-session-store-postgres` | PostgreSQL persistence/checkpoints/leases/owned run feedback |
|
|
164
|
+
| `@arnilo/prism-providers` | family: all 7 provider adapters, including AI SDK interoperability |
|
|
141
165
|
| `@arnilo/prism-compaction` | family: both compaction strategies |
|
|
142
166
|
| `@arnilo/prism-base` | profile: core + compaction + JSON Schema validation |
|
|
143
167
|
| `@arnilo/prism-code` | profile: base + coding tools/security + MCP |
|
package/dist/agents.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AgentRunError } from "./contracts.js";
|
|
1
2
|
import { resolveLoop, resolveToolConcurrency } from "./agent-loops.js";
|
|
2
3
|
import { createProviderTurnMetadata, readProviderHttpStatus } from "./observability.js";
|
|
3
4
|
import { createDefaultCompactionStrategy, isCompactionEntryData } from "./compaction.js";
|
|
@@ -71,6 +72,8 @@ class RuntimeAgentSession {
|
|
|
71
72
|
const model = options.model ?? this.agent.config.model;
|
|
72
73
|
const startedAt = new Date().toISOString();
|
|
73
74
|
let runError;
|
|
75
|
+
const runUsage = createUsageAccumulator();
|
|
76
|
+
let usage;
|
|
74
77
|
try {
|
|
75
78
|
this.resolveRunProvider(options);
|
|
76
79
|
throwIfAborted(controller.signal);
|
|
@@ -114,6 +117,23 @@ class RuntimeAgentSession {
|
|
|
114
117
|
const loop = resolveLoop(options, this.agent.config);
|
|
115
118
|
const toolConcurrency = resolveToolConcurrency(options, this.agent.config);
|
|
116
119
|
this.activeLoopTurn = 1;
|
|
120
|
+
const recordProviderUsage = async (turnUsage, turn, attempt) => {
|
|
121
|
+
runUsage.add(turnUsage);
|
|
122
|
+
if (!this.activeLedger)
|
|
123
|
+
return;
|
|
124
|
+
const usageRecord = {
|
|
125
|
+
id: randomId("usage"),
|
|
126
|
+
sessionId: this.id,
|
|
127
|
+
runId,
|
|
128
|
+
scope: "provider_turn",
|
|
129
|
+
turn,
|
|
130
|
+
attempt,
|
|
131
|
+
usage: turnUsage,
|
|
132
|
+
recordedAt: new Date().toISOString(),
|
|
133
|
+
...this.activeOwnership,
|
|
134
|
+
};
|
|
135
|
+
await this.activeLedger.appendUsage(redactRunLedgerRecord(usageRecord, this.activeRedactor));
|
|
136
|
+
};
|
|
117
137
|
// ponytail: LoopContext binds existing private helpers; loop orchestrates only.
|
|
118
138
|
const ctx = {
|
|
119
139
|
sessionId: this.id,
|
|
@@ -152,7 +172,7 @@ class RuntimeAgentSession {
|
|
|
152
172
|
generate: async (request) => {
|
|
153
173
|
const policyResult = await this.applyProviderRequestPolicies(request, runId, options, metadata, controller.signal);
|
|
154
174
|
const middlewareRequest = await this.agent.config.middleware?.run("provider_request", policyResult.request) ?? policyResult.request;
|
|
155
|
-
return this.generateWithRetry(this.redactProviderRequest(middlewareRequest), runId, options, controller.signal, policyResult.secrets, this.activeLoopTurn);
|
|
175
|
+
return this.generateWithRetry(this.redactProviderRequest(middlewareRequest), runId, options, controller.signal, policyResult.secrets, this.activeLoopTurn, recordProviderUsage);
|
|
156
176
|
},
|
|
157
177
|
isToolCallExclusive: (call) => registry.get(call.name)?.exclusive === true,
|
|
158
178
|
dispatchToolCall: (call) => dispatchToolCall({
|
|
@@ -175,12 +195,14 @@ class RuntimeAgentSession {
|
|
|
175
195
|
this.emit(event);
|
|
176
196
|
},
|
|
177
197
|
};
|
|
178
|
-
const
|
|
198
|
+
const loopUsage = await loop.run(ctx);
|
|
199
|
+
usage = runUsage.value() ?? loopUsage;
|
|
179
200
|
if (usage && this.activeLedger) {
|
|
180
201
|
const usageRecord = {
|
|
181
202
|
id: randomId("usage"),
|
|
182
203
|
sessionId: this.id,
|
|
183
204
|
runId,
|
|
205
|
+
scope: "run_total",
|
|
184
206
|
usage,
|
|
185
207
|
recordedAt: new Date().toISOString(),
|
|
186
208
|
...this.activeOwnership,
|
|
@@ -189,11 +211,23 @@ class RuntimeAgentSession {
|
|
|
189
211
|
}
|
|
190
212
|
await this.drainLedger();
|
|
191
213
|
this.emit({ type: "agent_finished", sessionId: this.id, runId, usage });
|
|
214
|
+
return this.buildRunResult({
|
|
215
|
+
runId,
|
|
216
|
+
status: "succeeded",
|
|
217
|
+
usage,
|
|
218
|
+
});
|
|
192
219
|
}
|
|
193
220
|
catch (error) {
|
|
194
221
|
runError = errorToErrorInfo(error);
|
|
195
222
|
this.emit({ type: "error", sessionId: this.id, runId, error: runError });
|
|
196
|
-
|
|
223
|
+
const result = this.buildRunResult({
|
|
224
|
+
runId,
|
|
225
|
+
status: controller.signal.aborted ? "aborted" : "failed",
|
|
226
|
+
usage: runUsage.value() ?? usage,
|
|
227
|
+
error: runError,
|
|
228
|
+
abortReason: controller.signal.aborted ? String(controller.signal.reason) : undefined,
|
|
229
|
+
});
|
|
230
|
+
throw new AgentRunError(result, { cause: error });
|
|
197
231
|
}
|
|
198
232
|
finally {
|
|
199
233
|
if (this.activeRun === controller)
|
|
@@ -233,6 +267,48 @@ class RuntimeAgentSession {
|
|
|
233
267
|
prompt(input, options) {
|
|
234
268
|
return this.run(input, options);
|
|
235
269
|
}
|
|
270
|
+
async *stream(input, options = {}) {
|
|
271
|
+
const { maxQueuedEvents, overflow, ...runOptions } = options;
|
|
272
|
+
const subscription = this.subscribe({ maxQueuedEvents, overflow });
|
|
273
|
+
let runOwnedId;
|
|
274
|
+
let settled = false;
|
|
275
|
+
const runPromise = this.run(input, runOptions).finally(() => {
|
|
276
|
+
settled = true;
|
|
277
|
+
});
|
|
278
|
+
try {
|
|
279
|
+
for await (const event of subscription) {
|
|
280
|
+
if ("runId" in event && typeof event.runId === "string") {
|
|
281
|
+
if (runOwnedId === undefined && event.type === "agent_started")
|
|
282
|
+
runOwnedId = event.runId;
|
|
283
|
+
if (runOwnedId !== undefined && event.runId !== runOwnedId)
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
yield event;
|
|
287
|
+
}
|
|
288
|
+
await runPromise;
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
if (!settled) {
|
|
292
|
+
this.abort(new Error("stream consumer closed"));
|
|
293
|
+
await runPromise.catch(() => undefined);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
buildRunResult(input) {
|
|
298
|
+
const final = finalAssistantMessage(this.history);
|
|
299
|
+
return {
|
|
300
|
+
sessionId: this.id,
|
|
301
|
+
runId: input.runId,
|
|
302
|
+
status: input.status,
|
|
303
|
+
leafId: this.currentLeafId,
|
|
304
|
+
text: final.text,
|
|
305
|
+
content: final.content,
|
|
306
|
+
message: final.message,
|
|
307
|
+
usage: input.usage,
|
|
308
|
+
error: input.error,
|
|
309
|
+
abortReason: input.abortReason,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
236
312
|
async compact(options = {}) {
|
|
237
313
|
if (this.activeRun)
|
|
238
314
|
throw new Error("Agent session already has an active run");
|
|
@@ -340,13 +416,13 @@ class RuntimeAgentSession {
|
|
|
340
416
|
if (failure)
|
|
341
417
|
throw failure;
|
|
342
418
|
}
|
|
343
|
-
async generateWithRetry(request, runId, options, signal, requestSecrets = [], turn = 1) {
|
|
419
|
+
async generateWithRetry(request, runId, options, signal, requestSecrets = [], turn = 1, recordUsage) {
|
|
344
420
|
const retry = mergeRetry(this.agent.config.retry, options.retry);
|
|
345
421
|
const secrets = [...requestSecrets, ...(retry?.secrets ?? [])];
|
|
346
422
|
const policy = retry?.policy ?? (retry ? createDefaultRetryPolicy(retry) : undefined);
|
|
347
423
|
for (let attempt = 1;; attempt += 1) {
|
|
348
424
|
try {
|
|
349
|
-
return await this.generateProviderTurn(request, runId, signal, secrets, turn, attempt);
|
|
425
|
+
return await this.generateProviderTurn(request, runId, signal, secrets, turn, attempt, recordUsage);
|
|
350
426
|
}
|
|
351
427
|
catch (error) {
|
|
352
428
|
const failure = error instanceof ProviderTurnFailure ? error : undefined;
|
|
@@ -365,7 +441,7 @@ class RuntimeAgentSession {
|
|
|
365
441
|
}
|
|
366
442
|
}
|
|
367
443
|
}
|
|
368
|
-
async generateProviderTurn(request, runId, signal, secrets = [], turn = 1, attempt = 1) {
|
|
444
|
+
async generateProviderTurn(request, runId, signal, secrets = [], turn = 1, attempt = 1, recordUsage) {
|
|
369
445
|
const startedAt = performance.now();
|
|
370
446
|
const providerId = this.activeProvider?.id ?? request.model.provider;
|
|
371
447
|
const buildMetadata = (extra = {}) => createProviderTurnMetadata(request, providerId, { attempt, ...extra });
|
|
@@ -382,25 +458,20 @@ class RuntimeAgentSession {
|
|
|
382
458
|
let messageId;
|
|
383
459
|
let started = false;
|
|
384
460
|
let usage;
|
|
461
|
+
let usageRecorded = false;
|
|
462
|
+
const recordTurnUsage = async () => {
|
|
463
|
+
if (!usage || usageRecorded)
|
|
464
|
+
return;
|
|
465
|
+
usageRecorded = true;
|
|
466
|
+
await recordUsage?.(usage, turn, attempt);
|
|
467
|
+
};
|
|
385
468
|
try {
|
|
386
469
|
for await (const event of this.activeProvider.generate(request)) {
|
|
387
470
|
throwIfAborted(signal);
|
|
388
471
|
if (event.type === "error")
|
|
389
472
|
throw new ProviderTurnFailure(event.error, started);
|
|
390
|
-
if (event.type === "usage")
|
|
473
|
+
if (event.type === "usage")
|
|
391
474
|
usage = event.usage;
|
|
392
|
-
if (this.activeLedger) {
|
|
393
|
-
const usageRecord = {
|
|
394
|
-
id: randomId("usage"),
|
|
395
|
-
sessionId: this.id,
|
|
396
|
-
runId,
|
|
397
|
-
usage: event.usage,
|
|
398
|
-
recordedAt: new Date().toISOString(),
|
|
399
|
-
...this.activeOwnership,
|
|
400
|
-
};
|
|
401
|
-
await this.activeLedger.appendUsage(redactRunLedgerRecord(usageRecord, this.activeRedactor));
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
475
|
if (event.type === "done") {
|
|
405
476
|
usage = event.usage ?? usage;
|
|
406
477
|
break;
|
|
@@ -433,6 +504,7 @@ class RuntimeAgentSession {
|
|
|
433
504
|
calls.push(call);
|
|
434
505
|
this.emit({ type: "message_delta", sessionId: this.id, runId, content: call });
|
|
435
506
|
}
|
|
507
|
+
await recordTurnUsage();
|
|
436
508
|
const latencyMs = Math.round(performance.now() - startedAt);
|
|
437
509
|
this.emit({
|
|
438
510
|
type: "provider_turn_finished",
|
|
@@ -447,12 +519,14 @@ class RuntimeAgentSession {
|
|
|
447
519
|
catch (error) {
|
|
448
520
|
const latencyMs = Math.round(performance.now() - startedAt);
|
|
449
521
|
const info = error instanceof ProviderTurnFailure ? redactSecrets(error.info, secrets) : errorToErrorInfo(error, secrets);
|
|
522
|
+
await recordTurnUsage();
|
|
450
523
|
this.emit({
|
|
451
524
|
type: "provider_turn_finished",
|
|
452
525
|
sessionId: this.id,
|
|
453
526
|
runId,
|
|
454
527
|
turn,
|
|
455
528
|
metadata: buildMetadata({ latencyMs, httpStatus: readProviderHttpStatus(info) }),
|
|
529
|
+
usage,
|
|
456
530
|
error: info,
|
|
457
531
|
});
|
|
458
532
|
if (error instanceof ProviderTurnFailure)
|
|
@@ -608,6 +682,19 @@ function inputToMessages(input) {
|
|
|
608
682
|
return [input];
|
|
609
683
|
return [...input];
|
|
610
684
|
}
|
|
685
|
+
function finalAssistantMessage(history) {
|
|
686
|
+
for (let index = history.length - 1; index >= 0; index -= 1) {
|
|
687
|
+
const message = history[index];
|
|
688
|
+
if (message.role !== "assistant")
|
|
689
|
+
continue;
|
|
690
|
+
const text = message.content
|
|
691
|
+
.filter((block) => block.type === "text")
|
|
692
|
+
.map((block) => block.text)
|
|
693
|
+
.join("");
|
|
694
|
+
return { message, content: message.content, text };
|
|
695
|
+
}
|
|
696
|
+
return { content: [], text: "" };
|
|
697
|
+
}
|
|
611
698
|
function activeTools(tools) {
|
|
612
699
|
if (!tools)
|
|
613
700
|
return { registry: createToolRegistry(), tools: [] };
|
|
@@ -673,6 +760,46 @@ function throwIfAbortedSignal(signal) {
|
|
|
673
760
|
if (signal?.aborted)
|
|
674
761
|
throw signal.reason instanceof Error ? signal.reason : new Error("Agent run aborted");
|
|
675
762
|
}
|
|
763
|
+
function createUsageAccumulator() {
|
|
764
|
+
const sums = new Map();
|
|
765
|
+
let costCurrency;
|
|
766
|
+
let costCompatible = true;
|
|
767
|
+
return {
|
|
768
|
+
add(usage) {
|
|
769
|
+
for (const key of ["inputTokens", "outputTokens", "cacheReadTokens", "cacheWriteTokens"]) {
|
|
770
|
+
const value = usage[key];
|
|
771
|
+
if (value !== undefined)
|
|
772
|
+
sums.set(key, (sums.get(key) ?? 0) + value);
|
|
773
|
+
}
|
|
774
|
+
const total = usage.totalTokens
|
|
775
|
+
?? (usage.inputTokens !== undefined || usage.outputTokens !== undefined
|
|
776
|
+
? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)
|
|
777
|
+
: undefined);
|
|
778
|
+
if (total !== undefined)
|
|
779
|
+
sums.set("totalTokens", (sums.get("totalTokens") ?? 0) + total);
|
|
780
|
+
if (usage.cost !== undefined && costCompatible) {
|
|
781
|
+
if (!sums.has("cost"))
|
|
782
|
+
costCurrency = usage.currency;
|
|
783
|
+
else if (usage.currency !== costCurrency)
|
|
784
|
+
costCompatible = false;
|
|
785
|
+
if (costCompatible)
|
|
786
|
+
sums.set("cost", (sums.get("cost") ?? 0) + usage.cost);
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
|
+
value() {
|
|
790
|
+
if (sums.size === 0)
|
|
791
|
+
return undefined;
|
|
792
|
+
const usage = {};
|
|
793
|
+
for (const [key, value] of sums) {
|
|
794
|
+
if (key !== "cost" || costCompatible)
|
|
795
|
+
usage[key] = value;
|
|
796
|
+
}
|
|
797
|
+
if (costCompatible && sums.has("cost") && costCurrency !== undefined)
|
|
798
|
+
usage.currency = costCurrency;
|
|
799
|
+
return Object.keys(usage).length > 0 ? usage : undefined;
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
}
|
|
676
803
|
function randomId(prefix) {
|
|
677
804
|
return `${prefix}_${globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2)}`;
|
|
678
805
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Writable } from "node:stream";
|
|
2
|
+
export declare class InitUsageError extends Error {
|
|
3
|
+
}
|
|
4
|
+
export type InitProvider = string;
|
|
5
|
+
export interface InitOptions {
|
|
6
|
+
readonly directory: string;
|
|
7
|
+
readonly provider: InitProvider;
|
|
8
|
+
readonly withWorkflows: boolean;
|
|
9
|
+
readonly withEvals: boolean;
|
|
10
|
+
readonly force: boolean;
|
|
11
|
+
readonly help: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface InitRuntime {
|
|
14
|
+
readonly stdout: Writable;
|
|
15
|
+
readonly stderr: Writable;
|
|
16
|
+
/** Override template root (tests). Defaults to package `templates/init`. */
|
|
17
|
+
readonly templatesRoot?: string;
|
|
18
|
+
/** Override package version stamped into generated package.json. */
|
|
19
|
+
readonly packageVersion?: string;
|
|
20
|
+
/** Working directory used to resolve relative destinations. Defaults to process.cwd(). */
|
|
21
|
+
readonly cwd?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface InitResult {
|
|
24
|
+
readonly targetDir: string;
|
|
25
|
+
readonly writtenFiles: readonly string[];
|
|
26
|
+
readonly provider: InitProvider;
|
|
27
|
+
readonly withWorkflows: boolean;
|
|
28
|
+
readonly withEvals: boolean;
|
|
29
|
+
readonly totalBytes: number;
|
|
30
|
+
}
|
|
31
|
+
/** Provider ids supported by `prism init --provider`. Loaded from templates data. */
|
|
32
|
+
export declare function listInitProviders(templatesRoot?: string): readonly string[];
|
|
33
|
+
/** @deprecated Prefer listInitProviders(); retained for tests that import the name. */
|
|
34
|
+
export declare const INIT_PROVIDERS: readonly string[];
|
|
35
|
+
export declare function getInitUsage(templatesRoot?: string): string;
|
|
36
|
+
export declare const initUsage: string;
|
|
37
|
+
export declare function parseInitArgs(argv: readonly string[], templatesRoot?: string): InitOptions;
|
|
38
|
+
export declare function runInitCommand(argv: readonly string[], runtime: InitRuntime): Promise<number>;
|
|
39
|
+
export declare function createInitProject(options: InitOptions, runtime?: InitRuntime): Promise<InitResult>;
|
|
40
|
+
export declare function defaultTemplatesRoot(): string;
|
|
41
|
+
export declare function isInitProvider(value: string, templatesRoot?: string): value is InitProvider;
|