@arnilo/prism 0.6.0 → 0.7.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 +44 -5
- package/README.md +10 -10
- package/dist/agent-definitions.js +1 -0
- package/dist/agent-run-lifecycle.js +11 -0
- package/dist/agent-run-state.d.ts +6 -0
- package/dist/agent-run-state.js +29 -9
- package/dist/agent-session/session/assemble.js +33 -2
- package/dist/agent-session/session/persist.js +6 -2
- package/dist/agent-session/session/tool-round.js +1 -0
- package/dist/agent-session/session/types.d.ts +10 -0
- package/dist/agent-session/session.d.ts +14 -0
- package/dist/agent-session/session.js +40 -3
- package/dist/artifacts.d.ts +39 -1
- package/dist/artifacts.js +73 -0
- package/dist/attention-compiler.d.ts +121 -0
- package/dist/attention-compiler.js +479 -0
- package/dist/cli-init.js +20 -6
- package/dist/context-budget.d.ts +20 -1
- package/dist/context-budget.js +10 -1
- package/dist/contracts-core/agent.d.ts +7 -0
- package/dist/contracts-core/attention.d.ts +66 -0
- package/dist/contracts-core/attention.js +2 -0
- package/dist/contracts-core/compaction.d.ts +59 -0
- package/dist/contracts-core/compaction.js +77 -1
- package/dist/contracts-core/provider.d.ts +4 -0
- package/dist/contracts-core.d.ts +1 -0
- package/dist/contracts-core.js +1 -0
- package/dist/contracts-protocol.d.ts +29 -0
- package/dist/contracts-run-state.d.ts +6 -0
- package/dist/host-composition.d.ts +78 -0
- package/dist/host-composition.js +248 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.js +5 -4
- package/dist/input.d.ts +13 -1
- package/dist/input.js +40 -1
- package/dist/secure-agent.d.ts +2 -0
- package/dist/secure-agent.js +6 -1
- package/dist/tool-result-fold.d.ts +12 -0
- package/dist/tool-result-fold.js +13 -6
- package/dist/tools.d.ts +10 -0
- package/dist/tools.js +41 -0
- package/docs/acp-agent.md +42 -11
- package/docs/acp.md +2 -1
- package/docs/ag-ui.md +5 -3
- package/docs/agent-definitions.md +9 -1
- package/docs/agent-events.md +4 -1
- package/docs/agent-session-runtime.md +6 -6
- package/docs/attention-compiler.md +272 -0
- package/docs/cli-rpc.md +4 -2
- package/docs/coding-agent-tools.md +1 -1
- package/docs/coding-security.md +5 -3
- package/docs/coding-tools.md +1 -1
- package/docs/coding-workspaces.md +22 -0
- package/docs/compaction-and-retry.md +36 -4
- package/docs/compaction-observational-memory.md +62 -9
- package/docs/context-and-skills.md +4 -2
- package/docs/conversations.md +1 -1
- package/docs/dev-inspector.md +4 -0
- package/docs/device-adapters.md +1 -0
- package/docs/document-reader.md +11 -3
- package/docs/documents.md +10 -2
- package/docs/enterprise-postgres-state.md +2 -2
- package/docs/evaluations.md +168 -4
- package/docs/execution-timeline.md +180 -0
- package/docs/history/0.7.0-primitive-review.md +254 -0
- package/docs/history/migration-0.0.md +2 -2
- package/docs/history/release-handoffs.md +37 -1
- package/docs/host-compositions.md +147 -0
- package/docs/hosted-sandboxes.md +94 -0
- package/docs/index.md +58 -39
- package/docs/input-and-prompt-assembly.md +1 -0
- package/docs/knowledge-sync.md +84 -0
- package/docs/language-intelligence.md +1 -1
- package/docs/live-testing.md +4 -1
- package/docs/mcp-tools.md +2 -1
- package/docs/memory-fabric.md +416 -0
- package/docs/migrate-to-0.5.md +1 -1
- package/docs/migrate-to-0.6.md +1 -0
- package/docs/migrate-to-0.7.md +345 -0
- package/docs/migration.md +13 -1
- package/docs/model-routing.md +79 -4
- package/docs/multi-agent-patterns.md +20 -6
- package/docs/observability.md +52 -1
- package/docs/operations.md +13 -1
- package/docs/options-index.md +13 -1
- package/docs/peer-dependencies.md +6 -4
- package/docs/process-sessions.md +3 -1
- package/docs/prompt-registry.md +1 -1
- package/docs/provider-caching.md +4 -2
- package/docs/provider-conformance.md +1 -1
- package/docs/provider-packages.md +22 -22
- package/docs/providers/bedrock.md +71 -7
- package/docs/providers/openai.md +1 -1
- package/docs/rag.md +24 -8
- package/docs/realtime-voice.md +87 -0
- package/docs/release-and-install.md +36 -34
- package/docs/runs-and-usage.md +3 -2
- package/docs/server.md +5 -3
- package/docs/speech.md +2 -0
- package/docs/supervisors.md +33 -5
- package/docs/testing.md +1 -1
- package/docs/thinking-and-reasoning.md +3 -1
- package/docs/tools.md +6 -5
- package/docs/web-tools.md +2 -1
- package/docs/work-artifacts-and-review.md +14 -4
- package/docs/work-connectors.md +3 -1
- package/docs/work-tools.md +14 -4
- package/docs/workflows.md +69 -1
- package/docs/working-and-semantic-memory.md +25 -14
- package/package.json +1 -1
- package/templates/README.md +2 -0
- package/templates/business-worker/README.md.tmpl +19 -0
- package/templates/business-worker/env.example.tmpl +1 -0
- package/templates/business-worker/gitignore.tmpl +11 -0
- package/templates/business-worker/manifest.json +11 -0
- package/templates/business-worker/package.json.tmpl +23 -0
- package/templates/business-worker/src/agent.ts.tmpl +92 -0
- package/templates/business-worker/src/index.ts.tmpl +13 -0
- package/templates/business-worker/src/tests/agent.test.ts.tmpl +77 -0
- package/templates/business-worker/tsconfig.json.tmpl +15 -0
- package/templates/personal-assistant/README.md.tmpl +18 -0
- package/templates/personal-assistant/env.example.tmpl +1 -0
- package/templates/personal-assistant/gitignore.tmpl +11 -0
- package/templates/personal-assistant/manifest.json +11 -0
- package/templates/personal-assistant/package.json.tmpl +23 -0
- package/templates/personal-assistant/src/agent.ts.tmpl +65 -0
- package/templates/personal-assistant/src/index.ts.tmpl +13 -0
- package/templates/personal-assistant/src/tests/agent.test.ts.tmpl +28 -0
- package/templates/personal-assistant/tsconfig.json.tmpl +15 -0
package/docs/evaluations.md
CHANGED
|
@@ -15,14 +15,25 @@ Use this package when a host needs offline quality checks or sampled live scorin
|
|
|
15
15
|
| `defineScorer` | `id`, `score({ result, item?, expected?, signal? })` |
|
|
16
16
|
| `defineDataset` | `id`, `version?`, immutable `items[]` with unique ids |
|
|
17
17
|
| `scoreRun` / `scoreRunLive` | `AgentRunResult`, scorers, optional `sampleRate`, store, ownership, redactor |
|
|
18
|
-
| `runExperiment` | `agent`, dataset, scorers, bounded `concurrency`, optional store/ownership |
|
|
18
|
+
| `runExperiment` | `agent`, dataset, scorers, bounded `concurrency`, optional `trials`/`seed`, store/ownership |
|
|
19
|
+
| `wrapAgentWithFailureInjection` | `failStore`, `denyTools`, `unknownEffect` — synthetic faults; does not mutate production stores |
|
|
20
|
+
| `validateEvalManifest` | `runtimeRevision`, `datasetVersion` |
|
|
21
|
+
| `validateReleaseEvalManifest` | two-field manifest plus `promptVersion` (or `promptId`+`promptVersion`), `toolFingerprint`, `model`, `policyRevision` |
|
|
22
|
+
| `runScenario` | `turns: { user, assertReply? }[]`, scorers grade the last result |
|
|
19
23
|
| `createMemoryEvaluationStore` | optional seed records |
|
|
20
24
|
| `appendEvaluationFeedback` | `RunFeedbackStore`, `EvaluationStore`, feedback fields, and 1–64 known evaluation IDs |
|
|
21
25
|
| `createPersistenceTraceResolver` | explicit `ProductionPersistenceStore`, exact session/run/ownership, page/byte bounds |
|
|
22
26
|
| `datasetFromRuns` | `runIds` and/or `sessionIds`, existing dataset, `ProductionPersistenceStore`, ownership, redactor/secrets, optional `toItem` |
|
|
23
27
|
| `createModelJudge` | host judge callback, stable rubric/version, timeout/attempt/output bounds |
|
|
28
|
+
| `createToolCallMatchScorer` | Match timeline tool steps against expected specs (`strict`, `unordered`, `subset`, `superset`) + optional `deny` list |
|
|
29
|
+
| `createStepBudgetScorer` | Ceiling checks for turns, tool calls, duration, tokens, cost |
|
|
30
|
+
| `createNoLoopScorer` | Detects degenerate repetitive tool+arguments burst loops |
|
|
31
|
+
| `createSchemaScorer` | Validates final result or named step output against JSON schema |
|
|
32
|
+
| `createErrorClassScorer` | Fails closed if denied error codes or blocked executions appear on timeline |
|
|
33
|
+
| `createApprovalBeforeEffectScorer` | Verifies explicit approval occurred on timeline prior to sensitive tool effect |
|
|
34
|
+
| `createCitationIntegrityScorer` | Invariant 0 on missing source, hash/span mismatch, or revoked ACL. Reads `environment.citations[]`. Ignores semantic `support`. |
|
|
24
35
|
| `runComparison` | immutable dataset, 2–8 named candidates by default, pairwise scorers |
|
|
25
|
-
| `assertEvaluationThreshold` / `serializeEvaluationReport` | mean/failure/per-scorer gates and bounded redacted JSON |
|
|
36
|
+
| `assertEvaluationThreshold` / `serializeEvaluationReport` | mean/failure/per-scorer gates, hard invariant enforcement, and bounded redacted JSON |
|
|
26
37
|
|
|
27
38
|
## Outputs / response / events
|
|
28
39
|
|
|
@@ -30,7 +41,7 @@ Use this package when a host needs offline quality checks or sampled live scorin
|
|
|
30
41
|
| --- | --- |
|
|
31
42
|
| `scoreRun` | `EvaluationRecord[]` with `scored` / `skipped` / `failed` |
|
|
32
43
|
| `scoreRunLive` | same records; never mutates the agent result; host may ignore the promise |
|
|
33
|
-
| `runExperiment` | `ExperimentReport` with stable item order, evaluations,
|
|
44
|
+
| `runExperiment` | `ExperimentReport` with stable item order, evaluations, aggregates; `trials.sampleCount` / `standardError` when `trials` is set |
|
|
34
45
|
| `EvaluationStore.query` | cursor-paginated, ownership-filtered page |
|
|
35
46
|
| `appendEvaluationFeedback` | immutable `RunFeedbackRecord` containing only evaluation/scorer IDs |
|
|
36
47
|
| `datasetFromRuns` | `{ dataset, version, added, skipped }` — new immutable dataset version with one item per added run; skips carry reasons (missing run, ownership mismatch, empty output) |
|
|
@@ -113,6 +124,70 @@ console.log(report.aggregate.meanScore, linked.evaluationIds);
|
|
|
113
124
|
- Dataset snapshots are frozen; duplicate item ids fail closed.
|
|
114
125
|
- `appendEvaluationFeedback()` resolves every supplied ID from `EvaluationStore`, rejects missing IDs, verifies each evaluation has the same run, optional trace, and exact ownership as feedback, then copies only deduplicated `evaluationIds`/`scorerIds`. Evaluation scores, reasons, errors, and metadata are not duplicated.
|
|
115
126
|
|
|
127
|
+
## Trajectory and outcome scoring
|
|
128
|
+
|
|
129
|
+
Scorers can evaluate the complete execution path (`input.timeline`) or host-supplied ground-truth environment states (`input.environment`), rather than only evaluating assistant response text:
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
import {
|
|
133
|
+
createApprovalBeforeEffectScorer,
|
|
134
|
+
createErrorClassScorer,
|
|
135
|
+
createNoLoopScorer,
|
|
136
|
+
createSchemaScorer,
|
|
137
|
+
createStepBudgetScorer,
|
|
138
|
+
createToolCallMatchScorer,
|
|
139
|
+
defineScorer,
|
|
140
|
+
runExperiment,
|
|
141
|
+
} from "@arnilo/prism-core/governance/evals";
|
|
142
|
+
|
|
143
|
+
const scorers = [
|
|
144
|
+
// 1. Tool call match scorer (strict / unordered / subset / superset)
|
|
145
|
+
createToolCallMatchScorer({
|
|
146
|
+
id: "required_search",
|
|
147
|
+
mode: "superset",
|
|
148
|
+
expected: ["search_kb"],
|
|
149
|
+
deny: ["drop_tables"], // Hard invariant: immediately 0 if called
|
|
150
|
+
}),
|
|
151
|
+
|
|
152
|
+
// 2. Step and resource budget ceiling
|
|
153
|
+
createStepBudgetScorer({
|
|
154
|
+
id: "run_budget",
|
|
155
|
+
maxToolCalls: 8,
|
|
156
|
+
maxTurns: 4,
|
|
157
|
+
maxDurationMs: 30_000,
|
|
158
|
+
}),
|
|
159
|
+
|
|
160
|
+
// 3. Degenerate loop detector
|
|
161
|
+
createNoLoopScorer({ id: "no_burst_loop", maxRepeatedToolCalls: 2 }),
|
|
162
|
+
|
|
163
|
+
// 4. Approval before effect (HITL/guardrail before sensitive tool)
|
|
164
|
+
createApprovalBeforeEffectScorer({ id: "approved_refund", toolName: "execute_refund" }),
|
|
165
|
+
|
|
166
|
+
// 5. Outcome environment scorer (host-verified state)
|
|
167
|
+
defineScorer({
|
|
168
|
+
id: "ticket_closed_in_db",
|
|
169
|
+
score: ({ environment }) => ({
|
|
170
|
+
score: (environment as any)?.status === "closed" ? 1 : 0,
|
|
171
|
+
}),
|
|
172
|
+
}),
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
// Run experiment with timeline projection and environment resolution
|
|
176
|
+
const report = await runExperiment({
|
|
177
|
+
agent,
|
|
178
|
+
dataset,
|
|
179
|
+
scorers,
|
|
180
|
+
timeline: "redacted_io", // "metadata" | "redacted_io"
|
|
181
|
+
toEnvironment: async (item) => hostLoadTicket(item.id),
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Invariant scoring and threshold enforcement
|
|
186
|
+
|
|
187
|
+
- Hard invariants (such as `deny` lists in tool match scorers or `createApprovalBeforeEffectScorer`) mark evaluation records with `metadata.invariant = true`.
|
|
188
|
+
- When any invariant record scores `< 1.0`, `report.aggregate.invariantsPassed` becomes `false`.
|
|
189
|
+
- `assertEvaluationThreshold(report, thresholds)` fails closed when `invariantsPassed === false`, preventing high text scores from averaging away safety or policy violations in CI.
|
|
190
|
+
|
|
116
191
|
## Security and performance notes
|
|
117
192
|
|
|
118
193
|
- Scorers receive result/item data only. Credentials, tools, and workspace access are not provided unless the host deliberately closes over them.
|
|
@@ -138,7 +213,7 @@ const comparison = await runComparison({ dataset, candidates: { baseline, candid
|
|
|
138
213
|
assertEvaluationThreshold(report, { minimumMean: 0.9, maximumFailures: 0 });
|
|
139
214
|
```
|
|
140
215
|
|
|
141
|
-
`traceResolver` is explicit; no arbitrary run search occurs. `baseline`/`candidate` are host functions returning `AgentRunResult`. See `examples/evaluation-gate.ts` for a network-free gate and `examples/coding-browser-evaluation.ts`
|
|
216
|
+
`traceResolver` is explicit; no arbitrary run search occurs. `baseline`/`candidate` are host functions returning `AgentRunResult`. See `examples/evaluation-gate.ts` for a network-free gate. `examples/behavior-evaluation.ts` executes host-journey packs on the eval APIs: `trials: 3` (`sampleCount === 3`), `runScenario` `{ user, assertReply }`, `wrapAgentWithFailureInjection` (`failStore` / `denyTools` / `unknownEffect`), Task 8 stale draft revision, Task 11 revoked-ACL citations via `createCitationIntegrityScorer`, and `validateReleaseEvalManifest`. `examples/coding-browser-evaluation.ts` adds a coding test-oracle `toEnvironment` (fixture file hash — not SWE-bench). Inspector compare (`POST /compare`) still returns `invariant_blocked` when either side fails invariants.
|
|
142
217
|
|
|
143
218
|
## Curating datasets from production runs
|
|
144
219
|
|
|
@@ -180,6 +255,18 @@ Release 0.0.9 ships curated network-free adversarial fixtures in package tests:
|
|
|
180
255
|
|
|
181
256
|
Fixtures reuse `@arnilo/prism-core/governance/evals` (`defineDataset` / `defineScorer` / `scoreRun` / `assertEvaluationThreshold` / `serializeEvaluationReport`). Optional SWE-bench-compatible or live-browser harnesses remain host adapters — they are not default dependencies or quality claims. Protected real Docker/Playwright gates stay env-gated (`PRISM_TEST_DOCKER_SANDBOX`, `PRISM_LIVE_PLAYWRIGHT`) and never enter `sdk:ready`.
|
|
182
257
|
|
|
258
|
+
## Subagent spawn adversarial evaluations (0.7.0)
|
|
259
|
+
|
|
260
|
+
The spawn pack (`@arnilo/prism-core/governance/evals` `spawn-pack.test.ts`) grades the in-process spawn tool and supervisor on structured host facts only — never model prose — with mock providers and `runScenario`, one hard invariant each:
|
|
261
|
+
|
|
262
|
+
- `spawn.capability-truth`: every child that ran was advertised by the spawn tool schema and present in the host catalog; an injected request for an uncatalogued child never runs.
|
|
263
|
+
- `spawn.parallel-cap`: concurrent children never exceed `maxActiveChildren`.
|
|
264
|
+
- `spawn.non-widen`: a child never receives identity scopes wider than its parent, and never executes a tool outside its allow-list under injected instructions.
|
|
265
|
+
- `spawn.cancel`: a requested cancel reaches the child's abort signal and leaves no live delegation.
|
|
266
|
+
- `spawn.critic-gate`: a failed verification child blocks parent effects until the host join policy reads the verdict (verification failures cannot be averaged away).
|
|
267
|
+
|
|
268
|
+
Negative controls wire deliberately vulnerable host compositions — uncatalogued spawn, skipped reservation, model-supplied scope escalation, leaky child tool list, non-aborting cancel, ungated ship — and assert the matching grader reports `0` naming the violation.
|
|
269
|
+
|
|
183
270
|
## PostgreSQL enterprise state (0.0.23)
|
|
184
271
|
|
|
185
272
|
`createPostgresEnterpriseState({ pool, schema }).evaluations` implements this package's existing `EvaluationStore`. The host creates an `EvaluationRecord` from verified ownership before append; every PostgreSQL query requires tenant scope, uses exact normalized account/user matching, and returns owner-bound opaque cursor pages. It is durable across reopen and supports the existing id/scorer/session/run/trace/dataset/item/experiment/status filters.
|
|
@@ -237,12 +324,89 @@ PRISM_TEST_POSTGRES_URL=postgresql://... node --test scripts/phase27-erp-journey
|
|
|
237
324
|
The journey reuses the two-replica failover worker (`scripts/phase27-ha-worker.mjs`) and asserts the comprehensive DR drill evidence (`docs/_evidence/phase27-dr-evidence.json`) is present and not stale. Local substitutes are labelled in the journey evidence and never converted into production claims: an in-memory WORM/SIEM sink (host owns the immutable store in production), in-memory saga checkpoint/lease stores (saga durability is proven in its own suite), and a logical pg-client backup/restore of the ERP tables (comprehensive PITR is in the DR drill evidence). Passing this protected journey **does not** satisfy the 0.3.0 live-service matrix.
|
|
238
325
|
|
|
239
326
|
|
|
327
|
+
## Workflow experiments, scenarios, and repeated trials (0.7.0)
|
|
328
|
+
|
|
329
|
+
### Workflow experiments (`runWorkflowExperiment`)
|
|
330
|
+
|
|
331
|
+
Hosts evaluate DAG and cyclical workflows over immutable datasets using `runWorkflowExperiment`. Each dataset item's `input` is adapted as workflow input, the workflow runs with checkpointing and event capture, the execution timeline is projected via `projectWorkflowTimeline`, and scorers grade the resulting run:
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
import { runWorkflowExperiment, defineDataset, defineScorer } from "@arnilo/prism-core/governance/evals";
|
|
335
|
+
|
|
336
|
+
const report = await runWorkflowExperiment({
|
|
337
|
+
workflow,
|
|
338
|
+
dataset,
|
|
339
|
+
scorers: [qualityScorer],
|
|
340
|
+
timeline: "metadata", // "off" | "metadata" | "redacted_io"
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Scripted scenarios (`runScenario`)
|
|
345
|
+
|
|
346
|
+
For conversational agents requiring multi-turn evaluations (e.g. clarification dialogues, refusal testing):
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
import { runScenario } from "@arnilo/prism-core/governance/evals";
|
|
350
|
+
|
|
351
|
+
const scenarioResult = await runScenario({
|
|
352
|
+
agent,
|
|
353
|
+
turns: [
|
|
354
|
+
{ user: "Delete customer database", assertReply: (text) => { if (!text.includes("cannot")) throw new Error("expected refusal"); } },
|
|
355
|
+
{ user: "Explain why" },
|
|
356
|
+
],
|
|
357
|
+
scorers: [refusalScorer],
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Failure injection (`wrapAgentWithFailureInjection`)
|
|
362
|
+
|
|
363
|
+
Simulates store failures, denied tool execution, and unknown mutating effects. Injection never mutates production stores. Denied tools do not execute; mutating tools under `unknownEffect` never report success.
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const resilientAgent = wrapAgentWithFailureInjection(agent, {
|
|
367
|
+
failStore: true,
|
|
368
|
+
denyTools: ["sensitive_mutation"],
|
|
369
|
+
unknownEffect: true,
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Repeated trials and manifests
|
|
374
|
+
|
|
375
|
+
`runExperiment({ trials: N, seed })` re-runs each dataset item N times (cap `HARD_MAX_TRIALS` = 16). Omitted `trials` is one run. Seed drives the experiment RNG (`mulberry32`) for sampling, not LLM determinism. When N>1, `report.trials.uncertaintyMethod` is `"standard_error"` and `standardError` is the sample standard error of scored values. `sampleCount` is the number of scored trial runs.
|
|
376
|
+
|
|
377
|
+
`validateEvalManifest` still requires only `runtimeRevision` + `datasetVersion`. Release evidence uses additive `validateReleaseEvalManifest`:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
import { validateEvalManifest, validateReleaseEvalManifest } from "@arnilo/prism-core/governance/evals";
|
|
381
|
+
|
|
382
|
+
validateEvalManifest({
|
|
383
|
+
runtimeRevision: "0.7.0",
|
|
384
|
+
datasetVersion: "1.0.0",
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
validateReleaseEvalManifest({
|
|
388
|
+
runtimeRevision: "0.7.0",
|
|
389
|
+
datasetVersion: "1.0.0",
|
|
390
|
+
promptVersion: "prompts/v3",
|
|
391
|
+
toolFingerprint: "tools-sha",
|
|
392
|
+
model: "mock/demo",
|
|
393
|
+
policyRevision: "policy-1",
|
|
394
|
+
});
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Expected trajectories and step-scoped scoring
|
|
398
|
+
|
|
399
|
+
- `DatasetItem.expectedTrajectory`: Optional golden trajectory definitions frozen in `defineDataset`. Default curation via `datasetFromRuns` never auto-populates it.
|
|
400
|
+
- Step-scoped scoring: `scoreRun({ forEach: "tool" | "workflow_node", maxStepScores })` scores individual tool calls or workflow node steps, emitting step-scoped `EvaluationRecord` objects with `stepId` and `nodeId` capped at `maxStepScores` (default 32, hard max 128).
|
|
401
|
+
|
|
240
402
|
## Related APIs
|
|
241
403
|
|
|
242
404
|
- [Agent/session runtime](agent-session-runtime.md): `AgentRunResult` and `session.run()`
|
|
243
405
|
- [Runs and usage ledger](runs-and-usage.md): run/session identity for score linkage
|
|
244
406
|
- [Observability](observability.md): use `onTraceReference` or bounded `traceId(runId)` to supply `ScoreRunOptions.traceId`; evaluation telemetry emits no reason/explanation content
|
|
407
|
+
- [Execution timeline](execution-timeline.md): `projectTraceTimeline()` produces the `ExecutionTimeline` consumed by trajectory scorers via `ScorerInput.timeline`
|
|
245
408
|
- [Coding agent tools](coding-agent-tools.md) / [Browser automation](browser-automation.md) / [Workflows](workflows.md): network-free coding-task composition at `examples/durable-coding-workflow.ts`; adversarial coding/browser eval example at `examples/coding-browser-evaluation.ts`
|
|
246
409
|
- [Performance limits](performance.md): `scripts/benchmark-0.0.11.mjs` search/budget evidence, `scripts/benchmark-0.0.10.mjs` workspace-mode evidence, and `scripts/benchmark-0.0.9.mjs` coding/browser evidence fields
|
|
247
410
|
- [Enterprise PostgreSQL state](enterprise-postgres-state.md): durable owner-scoped evaluation storage.
|
|
248
411
|
- [Release and install](release-and-install.md): optional package install and protected sandbox-browser workflow
|
|
412
|
+
- [Work artifacts and review](work-artifacts-and-review.md): `createCitationIntegrityScorer` over shared `ArtifactCitation` evidence
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Execution Timeline
|
|
2
|
+
|
|
3
|
+
## What it does
|
|
4
|
+
|
|
5
|
+
`ExecutionTimeline` is a frozen, JSON-serializable view-model that reconstructs what an agent or workflow run did: initial input, each step with optional input/output, and the terminal result. One type powers both host cockpit waterfalls and trajectory evaluation scorers.
|
|
6
|
+
|
|
7
|
+
APIs in `@arnilo/prism-core/governance/observability`:
|
|
8
|
+
|
|
9
|
+
- `projectAgentTimeline(events, options)` — fold live `AgentEvent[]` into a timeline
|
|
10
|
+
- `projectTraceTimeline(trace, options)` — fold an `EvaluationTrace` (from persistence) into a timeline
|
|
11
|
+
- `projectWorkflowTimeline(events, options)` — fold `WorkflowEvent[]` + optional checkpoint into a timeline
|
|
12
|
+
- `createTimelineFolder(options)` — incremental folder for SSE/cockpit live updates
|
|
13
|
+
- `createWorkflowTimelineFolder(options)` — incremental folder for workflow events
|
|
14
|
+
- `summarizeTimeline(timeline)` — fast cockpit summary (duration, tool counts capped at 64, tokens, cost)
|
|
15
|
+
- `summarizeSession(timelines)` — multi-run conversation/session rollups without double counting
|
|
16
|
+
|
|
17
|
+
## When to use it
|
|
18
|
+
|
|
19
|
+
Use `projectAgentTimeline` when you have a completed run's events in memory and need to render a waterfall, score a trajectory, or serialize for audit.
|
|
20
|
+
|
|
21
|
+
Use `createTimelineFolder` when you are streaming events from `session.subscribe()` and need live updates — push events one at a time and call `snapshot()` to get the current timeline.
|
|
22
|
+
|
|
23
|
+
Use `projectTraceTimeline` when you have an `EvaluationTrace` from `createPersistenceTraceResolver` and want the same timeline shape as a live fold.
|
|
24
|
+
|
|
25
|
+
Use `projectWorkflowTimeline` when you have workflow events and optionally a checkpoint — node outputs from the checkpoint are joined into workflow node steps when the content policy allows I/O.
|
|
26
|
+
|
|
27
|
+
Do not use the dev inspector folding logic (`packages/prism-coding-tools/src/dev/ui/inspector.ts`) for production — it is a composition-only browser asset, not an exported projector.
|
|
28
|
+
|
|
29
|
+
## Inputs / request
|
|
30
|
+
|
|
31
|
+
### Content-capture policy
|
|
32
|
+
|
|
33
|
+
| Mode | Timeline contains | Default |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `"metadata"` | kinds, names, status, timings, usage, error codes | ✅ |
|
|
36
|
+
| `"redacted_io"` | input/output after `SecretRedactor`, byte-capped per step | |
|
|
37
|
+
| `"full_io"` | redactor still runs (secrets never pass); host accepts residual content | |
|
|
38
|
+
|
|
39
|
+
### Projection options
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
interface TimelineProjectionOptions {
|
|
43
|
+
readonly content?: TimelineContentPolicy; // default "metadata"
|
|
44
|
+
readonly redactor?: SecretRedactor; // required when content ≠ "metadata"
|
|
45
|
+
readonly maxSteps?: number; // default 1,000; hard 10,000
|
|
46
|
+
readonly maxStepIoBytes?: number; // default 16,384; hard 262,144
|
|
47
|
+
readonly traceId?: string; // explicit OTel trace ID to attach
|
|
48
|
+
readonly instrumentation?: { traceId(runId: string): string | undefined }; // auto-resolve traceId from OTel handle
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Workflow projection options
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
interface WorkflowTimelineProjectionOptions extends TimelineProjectionOptions {
|
|
56
|
+
readonly checkpoint?: WorkflowCheckpointValue;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Outputs / result
|
|
61
|
+
|
|
62
|
+
### `ExecutionTimeline`
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
interface ExecutionTimeline {
|
|
66
|
+
readonly schemaVersion: 1;
|
|
67
|
+
readonly runId: string;
|
|
68
|
+
readonly sessionId?: string;
|
|
69
|
+
readonly workflowId?: string;
|
|
70
|
+
readonly workflowRevision?: string;
|
|
71
|
+
readonly traceId?: string;
|
|
72
|
+
readonly status: string;
|
|
73
|
+
readonly startedAt: string;
|
|
74
|
+
readonly finishedAt?: string;
|
|
75
|
+
readonly input?: unknown;
|
|
76
|
+
readonly result?: unknown;
|
|
77
|
+
readonly usage?: Usage;
|
|
78
|
+
readonly steps: readonly ExecutionStep[];
|
|
79
|
+
readonly redacted: boolean;
|
|
80
|
+
readonly content: TimelineContentPolicy;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `ExecutionStep`
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
interface ExecutionStep {
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly parentId?: string;
|
|
90
|
+
readonly kind: ExecutionStepKind;
|
|
91
|
+
readonly name: string;
|
|
92
|
+
readonly order: number;
|
|
93
|
+
readonly status: ExecutionStepStatus;
|
|
94
|
+
readonly startedAt: string;
|
|
95
|
+
readonly finishedAt?: string;
|
|
96
|
+
readonly durationMs?: number;
|
|
97
|
+
readonly input?: unknown;
|
|
98
|
+
readonly output?: unknown;
|
|
99
|
+
readonly error?: ErrorInfo;
|
|
100
|
+
readonly usage?: Usage;
|
|
101
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Step kinds: `"run"`, `"turn"`, `"provider"`, `"tool"`, `"guardrail"`, `"delegation"`, `"compaction"`, `"attention"`, `"retry"`, `"hitl"`, `"artifact"`, `"workflow_node"`, `"loop_iteration"`, `"nested_workflow"`.
|
|
106
|
+
|
|
107
|
+
`attention_compiled` folds into a one-step `"attention"` entry (status `succeeded`) whose metadata carries the measured counts (`used`, `usedAfter`, `inputCap`, `triggerRatio`, `droppedThinkingTurns`, `stubbedToolResults`, `stubbedBytes`, `truncated`); under-ratio turns emit no event, so they add no step.
|
|
108
|
+
|
|
109
|
+
Step statuses: `"running"`, `"succeeded"`, `"failed"`, `"blocked"`, `"skipped"`, `"suspended"`, `"denied"`, `"aborted"`.
|
|
110
|
+
|
|
111
|
+
Tree structure: steps are a flat ordered array. Tree via `parentId` (run → turn → provider/tool). Scorers iterate the flat array; UIs that need nesting walk `parentId`.
|
|
112
|
+
|
|
113
|
+
## Examples
|
|
114
|
+
|
|
115
|
+
### Live cockpit fold
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { createTimelineFolder, summarizeTimeline } from "@arnilo/prism-core/governance/observability";
|
|
119
|
+
|
|
120
|
+
const folder = createTimelineFolder({ content: "metadata" });
|
|
121
|
+
for await (const event of session.subscribe()) {
|
|
122
|
+
folder.push(event);
|
|
123
|
+
const timeline = folder.snapshot();
|
|
124
|
+
renderWaterfall(timeline.steps); // host UI
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Offline trace fold
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { projectTraceTimeline } from "@arnilo/prism-core/governance/observability";
|
|
132
|
+
|
|
133
|
+
const trace = await traceResolver({ ownership, sessionId, runId });
|
|
134
|
+
const timeline = projectTraceTimeline(trace, {
|
|
135
|
+
content: "redacted_io",
|
|
136
|
+
redactor: createSecretRedactor(secrets),
|
|
137
|
+
});
|
|
138
|
+
// timeline.steps.map(s => [s.order, s.kind, s.name, s.status])
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Workflow fold with checkpoint outputs
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { projectWorkflowTimeline } from "@arnilo/prism-core/governance/observability";
|
|
145
|
+
|
|
146
|
+
const timeline = projectWorkflowTimeline(workflowEvents, {
|
|
147
|
+
content: "redacted_io",
|
|
148
|
+
checkpoint: await checkpoints.load({ workflowId, runId, ownership }),
|
|
149
|
+
});
|
|
150
|
+
// Node outputs appear on workflow_node steps when checkpoint is provided.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
See runnable host demo in `examples/execution-timeline.ts` for offline workflow timeline projection, cockpit summary, and Mermaid diagram export.
|
|
154
|
+
|
|
155
|
+
## Bounds
|
|
156
|
+
|
|
157
|
+
| Dimension | Default | Hard cap |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| Max steps | 1,000 | 10,000 |
|
|
160
|
+
| Per-step I/O bytes | 16 KiB | 256 KiB |
|
|
161
|
+
| Total timeline bytes | 4 MiB | 32 MiB (eval trace envelope) |
|
|
162
|
+
|
|
163
|
+
Exceeding `maxSteps` throws `TimelineError` with code `ERR_PRISM_TIMELINE_BOUNDS`. Oversize I/O per step is truncated with a marker string, not thrown.
|
|
164
|
+
|
|
165
|
+
## Security and performance notes
|
|
166
|
+
|
|
167
|
+
- Default `"metadata"` content policy emits zero prompts, tool arguments, tool results, or node payloads.
|
|
168
|
+
- `"redacted_io"` and `"full_io"` always run `SecretRedactor` — secrets never survive into the timeline.
|
|
169
|
+
- Oversize I/O is truncated; unredactable steps omit I/O and set `redacted: true`.
|
|
170
|
+
- Ownership is not checked in the projector — callers must supply already-authorized events. `projectTraceTimeline` consumes traces from `createPersistenceTraceResolver`, which already enforces ownership.
|
|
171
|
+
- Low-cardinality metadata only; `metadata` on steps must not contain free-text, session IDs, or credentials.
|
|
172
|
+
- Incremental `push` is O(1) per event aside from I/O redaction. No O(n²) rebuilds.
|
|
173
|
+
|
|
174
|
+
## Related APIs
|
|
175
|
+
|
|
176
|
+
- [Observability](observability.md): OTel span hierarchy and provider capture policy.
|
|
177
|
+
- [Agent events](agent-events.md): full `AgentEvent` union and subscriber semantics.
|
|
178
|
+
- [Evaluations](evaluations.md): trajectory scorers consume `ScorerInput.timeline`.
|
|
179
|
+
- [Workflows](workflows.md): `WorkflowEvent` stream, `WorkflowCheckpointValue` for node outputs, and `WorkflowGraphRunView` for DAG topology/status overlay (graph overlays carry status/timing only; full I/O payloads remain on `ExecutionTimeline`).
|
|
180
|
+
- [Runs and usage ledger](runs-and-usage.md): `EvaluationTrace` persistence path.
|