@directive-run/knowledge 1.13.0 → 1.15.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/README.md +50 -15
- package/ai/ai-adapters.md +2 -0
- package/ai/ai-agents-streaming.md +182 -149
- package/ai/ai-budget-resilience.md +299 -132
- package/ai/ai-communication.md +215 -197
- package/ai/ai-debug-observability.md +253 -173
- package/ai/ai-guardrails-memory.md +185 -153
- package/ai/ai-mcp-rag.md +199 -199
- package/ai/ai-multi-agent.md +247 -153
- package/ai/ai-orchestrator.md +344 -114
- package/ai/ai-security.md +282 -180
- package/ai/ai-tasks.md +3 -1
- package/ai/ai-testing-evals.md +357 -256
- package/core/anti-patterns.md +9 -2
- package/core/constraints.md +6 -2
- package/core/core-patterns.md +2 -0
- package/core/error-boundaries.md +2 -0
- package/core/history.md +2 -0
- package/core/multi-module.md +8 -3
- package/core/naming.md +15 -6
- package/core/plugins.md +2 -0
- package/core/react-adapter.md +250 -174
- package/core/resolvers.md +2 -0
- package/core/schema-types.md +2 -0
- package/core/system-api.md +2 -0
- package/core/testing.md +251 -143
- package/examples/checkers.ts +15 -16
- package/examples/contact-form.ts +2 -2
- package/examples/counter-react.ts +1 -1
- package/examples/counter-svelte.ts +1 -1
- package/examples/counter-vue.ts +1 -1
- package/examples/counter.ts +1 -1
- package/examples/data-triggers.ts +4 -4
- package/examples/feature-flags.ts +2 -2
- package/examples/form-wizard.ts +2 -2
- package/examples/newsletter.ts +2 -2
- package/examples/server.ts +2 -2
- package/examples/shopping-cart.ts +1 -1
- package/examples/topic-guard.ts +1 -1
- package/package.json +3 -3
- package/sitemap.md +26 -3
- package/examples/debounce-constraints.ts +0 -95
- package/examples/multi-module.ts +0 -58
|
@@ -1,243 +1,323 @@
|
|
|
1
|
-
# AI
|
|
1
|
+
# AI debug + observability
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Covers `@directive-run/ai/devtools` and `@directive-run/core/plugins` — `createDebugTimeline`, breakpoints, `createOtelPlugin`, `createOTLPExporter`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Debug timeline with typed event recording, breakpoints, checkpoints, an OTel plugin for span emission, and an OTLP exporter for sending metrics/traces to any OTel-compatible backend.
|
|
6
|
+
|
|
7
|
+
## Decision tree
|
|
6
8
|
|
|
7
9
|
```
|
|
8
10
|
What do you need?
|
|
9
|
-
├── Event stream of all AI activity
|
|
10
|
-
├── Pause execution at specific points → breakpoints
|
|
11
|
-
├── Save/restore orchestrator state → checkpoint() / restore
|
|
12
|
-
├──
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
├── Composition patterns → race_start, race_winner, race_cancelled,
|
|
21
|
-
│ debate_round, reflection_iteration
|
|
22
|
-
├── Handoffs → handoff_start, handoff_complete, reroute
|
|
23
|
-
├── Tasks → task_start, task_complete, task_error, task_progress, goal_step
|
|
24
|
-
├── Checkpoints → checkpoint_save, checkpoint_restore
|
|
25
|
-
└── Breakpoints → breakpoint_hit, breakpoint_resumed
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Debug Timeline
|
|
29
|
-
|
|
30
|
-
Subscribe to a real-time event stream of all orchestrator activity:
|
|
11
|
+
├── Event stream of all AI activity → createDebugTimeline()
|
|
12
|
+
├── Pause execution at specific points → breakpoints (top-level option on orchestrator)
|
|
13
|
+
├── Save / restore orchestrator state → orchestrator.checkpoint() / restore()
|
|
14
|
+
├── Span emission to OTel → createOtelPlugin({ serviceName })
|
|
15
|
+
├── Ship metrics + traces to backend → createOTLPExporter({ endpoint })
|
|
16
|
+
└── DevTools panel + websocket export → createDevtoolsServer + createDevtoolsExport
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## `createDebugTimeline(options?)`
|
|
20
|
+
|
|
21
|
+
Returns a `DebugTimeline` with typed event recording, multi-axis querying, snapshot-aware forking, and JSON import/export. Import from `@directive-run/ai/devtools` — the main `@directive-run/ai` barrel re-exports it with `@deprecated` notices for v2.
|
|
31
22
|
|
|
32
23
|
```typescript
|
|
33
|
-
import { createDebugTimeline } from "@directive-run/ai";
|
|
24
|
+
import { createDebugTimeline, type DebugTimelineListener } from "@directive-run/ai/devtools";
|
|
34
25
|
|
|
35
26
|
const timeline = createDebugTimeline({
|
|
36
|
-
maxEvents: 2000,
|
|
27
|
+
maxEvents: 2000, // default 2000 — ring buffer, oldest evicted first
|
|
28
|
+
getSnapshotId: () => system.history?.currentId ?? null, // for snapshot-aware querying
|
|
29
|
+
goToSnapshot: (id) => system.history?.goTo(id), // for forkFrom
|
|
37
30
|
});
|
|
38
31
|
|
|
39
|
-
// Subscribe
|
|
40
|
-
const unsubscribe = timeline.subscribe((event) => {
|
|
32
|
+
// Subscribe — listener takes a single DebugEvent. There is NO options arg / filter shape.
|
|
33
|
+
const unsubscribe: () => void = timeline.subscribe((event) => {
|
|
41
34
|
console.log(`[${event.timestamp}] ${event.type}`, event);
|
|
42
35
|
});
|
|
43
36
|
|
|
44
|
-
// Filter
|
|
45
|
-
const
|
|
46
|
-
(event)
|
|
47
|
-
console.log(`
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
);
|
|
37
|
+
// Filter at the listener — the API has no built-in filter option
|
|
38
|
+
const unsubAgents = timeline.subscribe((event) => {
|
|
39
|
+
if (event.type.startsWith("agent_")) {
|
|
40
|
+
console.log(`agent: ${event.type}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
51
43
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
const recentAgentStarts = timeline.query({
|
|
44
|
+
// Record an event manually
|
|
45
|
+
timeline.record({
|
|
55
46
|
type: "agent_start",
|
|
56
|
-
|
|
47
|
+
timestamp: Date.now(),
|
|
48
|
+
agentId: "researcher",
|
|
49
|
+
snapshotId: null,
|
|
50
|
+
inputLength: 42,
|
|
57
51
|
});
|
|
52
|
+
|
|
53
|
+
// Length
|
|
54
|
+
console.log(timeline.length);
|
|
58
55
|
```
|
|
59
56
|
|
|
60
|
-
|
|
57
|
+
### Querying past events
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
The query surface is method-based — there is no `timeline.query({ type, since })`. Use the typed helpers:
|
|
63
60
|
|
|
64
61
|
```typescript
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// Constraints and resolvers
|
|
77
|
-
type ConstraintEvents =
|
|
78
|
-
| { type: "constraint_evaluate"; constraintId: string; result: boolean }
|
|
79
|
-
| { type: "resolver_start"; resolverType: string; requirementKey: string }
|
|
80
|
-
| { type: "resolver_complete"; resolverType: string; duration: number };
|
|
81
|
-
|
|
82
|
-
// Approval workflow
|
|
83
|
-
type ApprovalEvents =
|
|
84
|
-
| { type: "approval_request"; agentName: string; prompt: string }
|
|
85
|
-
| { type: "approval_response"; agentName: string; approved: boolean; reason?: string };
|
|
86
|
-
|
|
87
|
-
// Multi-agent patterns
|
|
88
|
-
type PatternEvents =
|
|
89
|
-
| { type: "pattern_start"; patternName: string; agents: string[] }
|
|
90
|
-
| { type: "pattern_complete"; patternName: string; duration: number }
|
|
91
|
-
| { type: "dag_node_update"; nodeId: string; status: "pending" | "running" | "complete" | "error" };
|
|
92
|
-
|
|
93
|
-
// Composition patterns
|
|
94
|
-
type CompositionEvents =
|
|
95
|
-
| { type: "race_start"; agents: string[] }
|
|
96
|
-
| { type: "race_winner"; agentName: string; duration: number }
|
|
97
|
-
| { type: "race_cancelled"; agentName: string; reason: string }
|
|
98
|
-
| { type: "debate_round"; round: number; agentName: string; position: string }
|
|
99
|
-
| { type: "reflection_iteration"; iteration: number; agentName: string };
|
|
100
|
-
|
|
101
|
-
// Handoffs and routing
|
|
102
|
-
type HandoffEvents =
|
|
103
|
-
| { type: "handoff_start"; from: string; to: string }
|
|
104
|
-
| { type: "handoff_complete"; from: string; to: string; duration: number }
|
|
105
|
-
| { type: "reroute"; from: string; to: string; reason: string };
|
|
106
|
-
|
|
107
|
-
// Checkpoints and breakpoints
|
|
108
|
-
type CheckpointEvents =
|
|
109
|
-
| { type: "checkpoint_save"; checkpointId: string }
|
|
110
|
-
| { type: "checkpoint_restore"; checkpointId: string }
|
|
111
|
-
| { type: "breakpoint_hit"; breakpointId: string; agentName: string }
|
|
112
|
-
| { type: "breakpoint_resumed"; breakpointId: string };
|
|
113
|
-
|
|
114
|
-
// Tasks
|
|
115
|
-
type TaskEvents =
|
|
116
|
-
| { type: "task_start"; taskId: string; label?: string }
|
|
117
|
-
| { type: "task_complete"; taskId: string; duration: number }
|
|
118
|
-
| { type: "task_error"; taskId: string; error: Error }
|
|
119
|
-
| { type: "task_progress"; taskId: string; percent: number; message?: string }
|
|
120
|
-
| { type: "goal_step"; iteration: number; goalMet: boolean };
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
## Attaching Timeline to Orchestrator
|
|
62
|
+
const all = timeline.getEvents(); // DebugEvent[]
|
|
63
|
+
const agentErrors = timeline.getEventsByType("agent_error"); // typed-narrowed
|
|
64
|
+
const recentSpan = timeline.getEventsInRange(Date.now() - 60_000, Date.now());
|
|
65
|
+
const researcher = timeline.getEventsForAgent("researcher");
|
|
66
|
+
const atSnapshot = timeline.getEventsAtSnapshot(7);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`getEventsByType<T>(type)` narrows the union — `agentErrors` above is typed as `Extract<DebugEvent, { type: "agent_error" }>[]`, so `err.error.message` autocompletes.
|
|
70
|
+
|
|
71
|
+
### Persistence + fork
|
|
124
72
|
|
|
125
73
|
```typescript
|
|
126
|
-
|
|
74
|
+
const json = timeline.export(); // string — full JSON dump
|
|
75
|
+
timeline.clear();
|
|
76
|
+
timeline.import(json); // re-hydrate
|
|
77
|
+
|
|
78
|
+
timeline.forkFrom(snapshotId); // truncate post-snapshot events + call goToSnapshot
|
|
79
|
+
```
|
|
127
80
|
|
|
128
|
-
|
|
81
|
+
## Attaching the timeline to an orchestrator
|
|
82
|
+
|
|
83
|
+
`OrchestratorDebugConfig` has exactly one option: `verboseTimeline?: boolean`. There is NO `timeline:` / `breakpoints:` / `exporter:` field inside `debug:` — `breakpoints` and `onBreakpoint` are top-level options on the orchestrator, and the timeline is *read off* the orchestrator via `orchestrator.timeline` after construction.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { createAgentOrchestrator } from "@directive-run/ai";
|
|
129
87
|
|
|
130
88
|
const orchestrator = createAgentOrchestrator({
|
|
131
89
|
runner,
|
|
132
|
-
debug: {
|
|
133
|
-
|
|
134
|
-
|
|
90
|
+
debug: { verboseTimeline: true }, // or just `debug: true`
|
|
91
|
+
// Top-level — NOT inside debug
|
|
92
|
+
breakpoints: [
|
|
93
|
+
{ id: "before-write", before: "agent_start" },
|
|
94
|
+
],
|
|
95
|
+
onBreakpoint: (req) => {
|
|
96
|
+
console.log("breakpoint hit", req.id);
|
|
97
|
+
orchestrator.resumeBreakpoint(req.id);
|
|
135
98
|
},
|
|
136
99
|
});
|
|
100
|
+
|
|
101
|
+
// Timeline is exposed on the orchestrator (null when debug: false)
|
|
102
|
+
const timeline = orchestrator.timeline;
|
|
103
|
+
timeline?.subscribe((event) => console.log(event));
|
|
137
104
|
```
|
|
138
105
|
|
|
139
106
|
## Breakpoints
|
|
140
107
|
|
|
141
|
-
|
|
108
|
+
Configure breakpoints as a top-level option on the orchestrator. Each entry pauses execution before/after a specific event type; `onBreakpoint` fires with a `BreakpointRequest` you resume via `orchestrator.resumeBreakpoint(id)` (with optional input modifications) or cancel via `orchestrator.cancelBreakpoint(id, reason?)`.
|
|
142
109
|
|
|
143
110
|
```typescript
|
|
111
|
+
import type { BreakpointConfig, BreakpointModifications } from "@directive-run/ai";
|
|
112
|
+
|
|
144
113
|
const orchestrator = createMultiAgentOrchestrator({
|
|
145
114
|
agents: { researcher, writer, editor },
|
|
146
115
|
runner,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
id: "on-error",
|
|
166
|
-
when: (event) => {
|
|
167
|
-
return event.type === "agent_error";
|
|
168
|
-
},
|
|
169
|
-
onHit: async (event, resume) => {
|
|
170
|
-
console.error("Agent error:", event.error);
|
|
171
|
-
// Decide whether to continue or abort
|
|
172
|
-
resume();
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
],
|
|
116
|
+
breakpoints: [
|
|
117
|
+
{ id: "before-write", before: "agent_start", filter: (e) => e.agentName === "writer" },
|
|
118
|
+
{ id: "on-error", after: "agent_error" },
|
|
119
|
+
],
|
|
120
|
+
onBreakpoint: async (req) => {
|
|
121
|
+
if (req.id === "on-error") {
|
|
122
|
+
// Log + cancel
|
|
123
|
+
console.error("breakpoint on error:", req.event);
|
|
124
|
+
orchestrator.cancelBreakpoint(req.id, "aborting on error");
|
|
125
|
+
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
await waitForUserClick();
|
|
130
|
+
orchestrator.resumeBreakpoint(req.id);
|
|
176
131
|
},
|
|
132
|
+
breakpointTimeoutMs: 5 * 60 * 1000,
|
|
177
133
|
});
|
|
178
134
|
```
|
|
179
135
|
|
|
136
|
+
There is NO `breakpoint.when(event)` / `breakpoint.onHit(event, resume)` shape — those don't exist. Filter on a typed `before:` / `after:` event-type key plus an optional `filter:` predicate; resume/cancel via the orchestrator's methods.
|
|
137
|
+
|
|
180
138
|
## Checkpoints
|
|
181
139
|
|
|
182
|
-
|
|
140
|
+
See `ai-orchestrator.md` and `ai-multi-agent.md` for the full checkpoint surface. Quick form:
|
|
183
141
|
|
|
184
142
|
```typescript
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
const serialized = JSON.stringify(checkpoint);
|
|
143
|
+
const cp = await orchestrator.checkpoint({ label: "before-risky-op" }); // async!
|
|
144
|
+
const serialized = JSON.stringify(cp);
|
|
188
145
|
|
|
189
|
-
//
|
|
190
|
-
|
|
146
|
+
// Restore on an EXISTING instance — there is no `checkpoint` constructor option
|
|
147
|
+
const fresh = createAgentOrchestrator({ runner /* same config */ });
|
|
148
|
+
fresh.restore(JSON.parse(serialized));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## OpenTelemetry plugin
|
|
152
|
+
|
|
153
|
+
`createOtelPlugin({ serviceName, … })` returns a Directive plugin you pass to `createSystem({ plugins: [otel] })` (or to the orchestrator via its `plugins:` option). It emits spans for agent runs, resolver execution, guardrails, and pattern boundaries — mapped to GenAI semantic conventions.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { createOtelPlugin, OtelStatusCode } from "@directive-run/ai";
|
|
191
157
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
158
|
+
const otel = createOtelPlugin({
|
|
159
|
+
serviceName: "my-ai-app",
|
|
160
|
+
serviceVersion: "1.0.0",
|
|
161
|
+
// Optional: a custom OtelTracer. Defaults to an in-memory tracer suitable for the OTLP exporter.
|
|
162
|
+
tracer: customTracer,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const orchestrator = createAgentOrchestrator({
|
|
196
166
|
runner,
|
|
197
|
-
|
|
167
|
+
plugins: [otel],
|
|
198
168
|
});
|
|
199
|
-
restored.start();
|
|
200
169
|
```
|
|
201
170
|
|
|
202
|
-
##
|
|
171
|
+
## OTLP exporter
|
|
203
172
|
|
|
204
|
-
|
|
173
|
+
`createOTLPExporter({ endpoint, … })` returns `{ exportMetrics, exportTraces }` — paired with an observability config that streams collected data to any OTel-compatible backend (Jaeger, Tempo, Grafana Cloud, Honeycomb, etc.).
|
|
205
174
|
|
|
206
175
|
```typescript
|
|
207
176
|
import { createOTLPExporter } from "@directive-run/ai";
|
|
177
|
+
// (re-exported from @directive-run/core/plugins)
|
|
208
178
|
|
|
209
179
|
const exporter = createOTLPExporter({
|
|
210
|
-
endpoint: "http://localhost:4318
|
|
180
|
+
endpoint: "http://localhost:4318",
|
|
211
181
|
serviceName: "my-ai-app",
|
|
212
|
-
|
|
213
|
-
|
|
182
|
+
serviceVersion: "1.0.0",
|
|
183
|
+
headers: { Authorization: `Bearer ${process.env.OTEL_TOKEN}` },
|
|
184
|
+
timeoutMs: 10_000,
|
|
185
|
+
onError: (err, kind) => console.error(`[otlp] ${kind} export failed:`, err),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Wire into the observability plugin (see core observability docs)
|
|
189
|
+
const obs = createObservabilityPlugin({
|
|
190
|
+
metrics: { exporter: { export: exporter.exportMetrics } },
|
|
191
|
+
tracing: { exporter: { export: exporter.exportTraces } },
|
|
214
192
|
});
|
|
215
193
|
|
|
216
194
|
const orchestrator = createAgentOrchestrator({
|
|
217
195
|
runner,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
196
|
+
plugins: [obs, otel],
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
The exporter maps Directive events to GenAI semantic conventions. The exact mapping (gen_ai.chat, gen_ai.tool, gen_ai.guardrail, gen_ai.orchestration) lives in `@directive-run/core/plugins/otlp-exporter.ts` and tracks the OpenTelemetry GenAI spec.
|
|
201
|
+
|
|
202
|
+
## DevTools server (live websocket export)
|
|
203
|
+
|
|
204
|
+
For browser-based devtools panels, pair `createDebugTimeline` with `createDevtoolsServer` (also from `@directive-run/ai/devtools`) — same data the in-process listener gets, streamed over a WebSocket.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
import { createDebugTimeline, createDevtoolsServer } from "@directive-run/ai/devtools";
|
|
208
|
+
|
|
209
|
+
const timeline = createDebugTimeline({ maxEvents: 5000 });
|
|
210
|
+
const server = createDevtoolsServer({ timeline, port: 9229 });
|
|
211
|
+
|
|
212
|
+
server.start();
|
|
213
|
+
// Connect a devtools UI to ws://localhost:9229
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Anti-patterns
|
|
217
|
+
|
|
218
|
+
### `timeline.subscribe(listener, { filter })`
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// WRONG — subscribe takes only a listener
|
|
222
|
+
timeline.subscribe((e) => console.log(e), { filter: (e) => e.type === "agent_error" })
|
|
223
|
+
|
|
224
|
+
// CORRECT — filter inside the listener
|
|
225
|
+
timeline.subscribe((e) => {
|
|
226
|
+
if (e.type === "agent_error") console.log(e);
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### `timeline.query({ type, since })`
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// WRONG — there is no .query() method
|
|
234
|
+
timeline.query({ type: "agent_error", since: Date.now() - 60_000 })
|
|
235
|
+
|
|
236
|
+
// CORRECT — typed getters
|
|
237
|
+
timeline.getEventsByType("agent_error")
|
|
238
|
+
.filter((e) => e.timestamp >= Date.now() - 60_000);
|
|
239
|
+
|
|
240
|
+
// Or use range directly
|
|
241
|
+
timeline.getEventsInRange(Date.now() - 60_000, Date.now());
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Nesting timeline / breakpoints inside `debug:`
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
// WRONG — only verboseTimeline lives inside debug; breakpoints + timeline are top-level
|
|
248
|
+
createAgentOrchestrator({
|
|
249
|
+
runner,
|
|
250
|
+
debug: { timeline, verbose: true, breakpoints: [...] },
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
// CORRECT
|
|
254
|
+
createAgentOrchestrator({
|
|
255
|
+
runner,
|
|
256
|
+
debug: { verboseTimeline: true }, // OR just `debug: true`
|
|
257
|
+
breakpoints: [...], // top-level
|
|
258
|
+
onBreakpoint: (req) => orchestrator.resumeBreakpoint(req.id),
|
|
222
259
|
});
|
|
260
|
+
// timeline is read off `orchestrator.timeline` after construction
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### `breakpoint.when(event)` / `breakpoint.onHit(event, resume)`
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// WRONG — these shapes don't exist
|
|
267
|
+
breakpoints: [
|
|
268
|
+
{ id: "x", when: (e) => e.type === "agent_start", onHit: (e, resume) => resume() },
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
// CORRECT — declarative before:/after: + typed filter, then orchestrator.resumeBreakpoint()
|
|
272
|
+
breakpoints: [
|
|
273
|
+
{ id: "x", before: "agent_start", filter: (e) => e.agentName === "writer" },
|
|
274
|
+
],
|
|
275
|
+
onBreakpoint: (req) => orchestrator.resumeBreakpoint(req.id),
|
|
223
276
|
```
|
|
224
277
|
|
|
225
|
-
|
|
278
|
+
### Restoring a checkpoint via the constructor
|
|
226
279
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
280
|
+
```typescript
|
|
281
|
+
// WRONG — there is no `checkpoint:` constructor option
|
|
282
|
+
createMultiAgentOrchestrator({ agents, patterns, runner, checkpoint: saved })
|
|
283
|
+
|
|
284
|
+
// CORRECT — orch.restore() on an existing instance
|
|
285
|
+
const orch = createMultiAgentOrchestrator({ agents, patterns, runner });
|
|
286
|
+
orch.restore(saved);
|
|
287
|
+
orch.start();
|
|
288
|
+
```
|
|
233
289
|
|
|
234
|
-
|
|
290
|
+
### Assuming `agent_complete.output` is `string`
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// WRONG — output is unknown, not string
|
|
294
|
+
timeline.subscribe((e) => {
|
|
295
|
+
if (e.type === "agent_complete") console.log(e.output.length); // type error
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// CORRECT — narrow before reading
|
|
299
|
+
timeline.subscribe((e) => {
|
|
300
|
+
if (e.type === "agent_complete" && typeof e.output === "string") {
|
|
301
|
+
console.log(e.output.length);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
```
|
|
235
305
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
|
239
|
-
|
|
240
|
-
| `
|
|
241
|
-
| `
|
|
242
|
-
| `
|
|
243
|
-
|
|
|
306
|
+
## Quick reference
|
|
307
|
+
|
|
308
|
+
| API | Purpose |
|
|
309
|
+
|---|---|
|
|
310
|
+
| `createDebugTimeline(options?)` | Typed event recorder + queryable history |
|
|
311
|
+
| `timeline.subscribe(listener)` | Live event stream (no filter option) |
|
|
312
|
+
| `timeline.getEventsByType<T>(type)` | Typed-narrowed query |
|
|
313
|
+
| `timeline.getEventsInRange(start, end)` | Time-bounded query |
|
|
314
|
+
| `timeline.getEventsForAgent(agentId)` | Per-agent stream |
|
|
315
|
+
| `timeline.getEventsAtSnapshot(id)` | Snapshot-aware stream |
|
|
316
|
+
| `timeline.forkFrom(id)` | Truncate post-snapshot + reroute |
|
|
317
|
+
| `timeline.export()` / `import(json)` | JSON round-trip |
|
|
318
|
+
| `orchestrator.timeline` | Read the timeline back off the orchestrator (`null` when `debug: false`) |
|
|
319
|
+
| `breakpoints: [...]` + `onBreakpoint` | Top-level orchestrator options for pause points |
|
|
320
|
+
| `orchestrator.resumeBreakpoint(id, mods?)` / `cancelBreakpoint(id, reason?)` | Resolve a paused breakpoint |
|
|
321
|
+
| `createOtelPlugin(config)` | Plugin that emits spans for orchestrator activity |
|
|
322
|
+
| `createOTLPExporter(config)` | Returns `{ exportMetrics, exportTraces }` for OTel backends |
|
|
323
|
+
| `createDevtoolsServer({ timeline, port })` | WebSocket-bridged timeline for browser devtools |
|