@noetaris/harness 0.3.2 → 0.4.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 +6 -3
- package/dist/index.d.ts +253 -125
- package/dist/index.js +437 -78
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -124,17 +124,20 @@ h.provide('model', runtime()) // per-run — supplied at agent.run
|
|
|
124
124
|
|
|
125
125
|
### Session Store
|
|
126
126
|
|
|
127
|
-
`h.store()` adds persistence. The reserved `session` key is used by the framework to save and restore state across runs
|
|
127
|
+
`h.store()` adds persistence. The reserved `session` key is used by the framework to save and restore state across runs.
|
|
128
128
|
|
|
129
129
|
```ts
|
|
130
130
|
import { InMemorySessionStore } from '@noetaris/harness-store'
|
|
131
131
|
|
|
132
132
|
h.store({
|
|
133
|
-
session:
|
|
134
|
-
knowledge: new MyKnowledgeGraph(), // available as ctx.store.knowledge
|
|
133
|
+
session: new InMemorySessionStore(), // framework-managed lifecycle
|
|
135
134
|
})
|
|
136
135
|
```
|
|
137
136
|
|
|
137
|
+
> **Note:** Only the `session` key is processed today. Surfacing additional
|
|
138
|
+
> store keys to steps as `ctx.store.<name>` is planned but not yet wired up —
|
|
139
|
+
> non-session keys passed to `h.store()` are currently ignored.
|
|
140
|
+
|
|
138
141
|
The framework injects `ctx.sessionId` automatically on every run — no declaration in `Ctx` needed.
|
|
139
142
|
|
|
140
143
|
### Interrupts
|
package/dist/index.d.ts
CHANGED
|
@@ -100,6 +100,172 @@ declare function isRequiredMarker(value: unknown): value is RequiredMarker;
|
|
|
100
100
|
*/
|
|
101
101
|
declare function isRuntimeMarker(value: unknown): value is RuntimeMarker;
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Identifies the agent and session for run-level observer callbacks.
|
|
105
|
+
*/
|
|
106
|
+
interface RunContext {
|
|
107
|
+
readonly agentId: string;
|
|
108
|
+
readonly sessionId: string;
|
|
109
|
+
/**
|
|
110
|
+
* The UUID for this specific run invocation. Always present in RunContext
|
|
111
|
+
* passed to observer methods.
|
|
112
|
+
*/
|
|
113
|
+
readonly runId: string;
|
|
114
|
+
/**
|
|
115
|
+
* Optional parent run UUID for cross-process trace correlation. Present
|
|
116
|
+
* when parentRunId was passed to agent.run() resources. Absent for top-level
|
|
117
|
+
* runs or when not provided by the caller.
|
|
118
|
+
*/
|
|
119
|
+
readonly parentRunId?: string;
|
|
120
|
+
/**
|
|
121
|
+
* The physical instance ID of the agent process, if configured via
|
|
122
|
+
* `createAgent()` options. Absent when `instanceId` was not provided.
|
|
123
|
+
*/
|
|
124
|
+
readonly instanceId?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Branch-name path (outermost to innermost), present only when this context describes a
|
|
127
|
+
* fork branch's own nested run rather than the top-level run. A branch is implemented as
|
|
128
|
+
* its own recursive runLoop call, so it fires onRunStart/onRunEnd on the same observer as
|
|
129
|
+
* the top-level run, under the same runId — this field is what makes those distinguishable
|
|
130
|
+
* from the real top-level pair. Absent for the top-level run.
|
|
131
|
+
*/
|
|
132
|
+
readonly branchPath?: readonly string[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Identifies the agent, session, and current step for step-level observer callbacks.
|
|
136
|
+
*/
|
|
137
|
+
interface StepContext {
|
|
138
|
+
readonly agentId: string;
|
|
139
|
+
readonly sessionId: string;
|
|
140
|
+
readonly stepName: string;
|
|
141
|
+
/**
|
|
142
|
+
* Branch-name path (outermost to innermost), present only when this step runs inside a
|
|
143
|
+
* fork branch. Absent for a step at the top level of the loop (including the fork node
|
|
144
|
+
* itself, which is one atomic step from the outer run's point of view).
|
|
145
|
+
*/
|
|
146
|
+
readonly branchPath?: readonly string[];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Observability hook interface. All methods are optional — implement only
|
|
150
|
+
* the hooks you need.
|
|
151
|
+
*
|
|
152
|
+
* Pass an `Observer` implementation in `agent.run()` resources under the key
|
|
153
|
+
* `'observer'`, or bind it to an {@link ObserverAware} slot before running.
|
|
154
|
+
*
|
|
155
|
+
* LLM adapters emit `'llm.response'` events via `onEvent` carrying an
|
|
156
|
+
* `LLMUsageEvent` payload for token tracking.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const obs: Observer = {
|
|
161
|
+
* onRunStart: (ctx) => console.log('run started', ctx.sessionId),
|
|
162
|
+
* onEvent: (ctx, type, payload) => metrics.record(type, payload),
|
|
163
|
+
* }
|
|
164
|
+
* agent.run({}, { llm, observer: obs })
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
interface Observer {
|
|
168
|
+
/** Called once when a run begins, before the first step executes. */
|
|
169
|
+
onRunStart?: (ctx: RunContext) => void;
|
|
170
|
+
/** Called once when a run settles (completed or stopped). */
|
|
171
|
+
onRunEnd?: (ctx: RunContext, event: {
|
|
172
|
+
signal: string;
|
|
173
|
+
durationMs: number;
|
|
174
|
+
}) => void;
|
|
175
|
+
/** Called immediately before each step's `run` function is invoked. */
|
|
176
|
+
onStepStart?: (ctx: StepContext) => void;
|
|
177
|
+
/** Called after a step completes successfully. */
|
|
178
|
+
onStepEnd?: (ctx: StepContext, event: {
|
|
179
|
+
durationMs: number;
|
|
180
|
+
}) => void;
|
|
181
|
+
/** Called when a step's `run` function throws. */
|
|
182
|
+
onStepError?: (ctx: StepContext, event: {
|
|
183
|
+
error: unknown;
|
|
184
|
+
durationMs: number;
|
|
185
|
+
}) => void;
|
|
186
|
+
/** Called when a step issues a `ctx.interrupt()`. */
|
|
187
|
+
onInterrupt?: (ctx: StepContext, event: {
|
|
188
|
+
prompt: unknown;
|
|
189
|
+
interruptId: string;
|
|
190
|
+
}) => void;
|
|
191
|
+
/**
|
|
192
|
+
* Called for arbitrary named events emitted by step code via `ctx.emit()` or
|
|
193
|
+
* by LLM adapters (e.g. `'llm.response'`).
|
|
194
|
+
*/
|
|
195
|
+
onEvent?: (ctx: StepContext, type: string, payload: unknown) => void;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Implemented by resources (e.g. LLM adapters) that accept an {@link Observer}
|
|
199
|
+
* at run time. The harness calls `bindObserver` on every slot value that
|
|
200
|
+
* implements this interface before the first step runs.
|
|
201
|
+
*
|
|
202
|
+
* Optionally, the harness calls `setStepContext` at the start of each step for
|
|
203
|
+
* every slot that exposes it. Adapters use this to attribute per-step telemetry
|
|
204
|
+
* (e.g. `observer.onEvent`) to the correct step without manual calls from step code.
|
|
205
|
+
*/
|
|
206
|
+
interface ObserverAware {
|
|
207
|
+
/**
|
|
208
|
+
* Receive the run's observer. The harness calls this once per `agent.run()`
|
|
209
|
+
* invocation before execution begins.
|
|
210
|
+
*/
|
|
211
|
+
bindObserver(observer: Observer): void;
|
|
212
|
+
/**
|
|
213
|
+
* Receive the current step context. The harness calls this at the start of
|
|
214
|
+
* each step for every slot that exposes this method, before calling `step.run`.
|
|
215
|
+
*
|
|
216
|
+
* Adapters that emit `observer.onEvent` in their `invoke()` method store the
|
|
217
|
+
* provided `StepContext` and use it as the first argument to `onEvent`, so
|
|
218
|
+
* events are attributed to the correct step automatically.
|
|
219
|
+
*
|
|
220
|
+
* **Known limitation (fork/join branches):** the store-in-a-field pattern above is safe only
|
|
221
|
+
* because exactly one step runs at a time in a non-forked run. When a fork's branches run
|
|
222
|
+
* concurrently, they typically share one `ObserverAware` slot instance (`h.provide('llm', ...)`
|
|
223
|
+
* provides it once), so concurrent branches race on that stored field and `onEvent` calls may
|
|
224
|
+
* be attributed to the wrong branch/step. This is a known v1 limitation of the built-in LLM
|
|
225
|
+
* adapters (`@noetaris/harness-anthropic`/`-openai`/`-google`/`-ollama`), not fixed for this
|
|
226
|
+
* release — a correct fix means passing `StepContext` through the call instead of storing it.
|
|
227
|
+
* Treat per-step LLM telemetry as unreliable for concurrently-running branches until then.
|
|
228
|
+
*/
|
|
229
|
+
setStepContext?(ctx: StepContext): void;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Combine multiple {@link Observer} instances into one. Each hook on the
|
|
233
|
+
* composite forwards to all constituent observers in order.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* const observer = composeObservers(otelObserver, metricsObserver)
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
240
|
+
declare function composeObservers(...observers: Observer[]): Observer;
|
|
241
|
+
|
|
242
|
+
type Cursor = string | ForkCursor;
|
|
243
|
+
/**
|
|
244
|
+
* Persisted/returned shape of a paused fork. Always lists every branch of the fork, in
|
|
245
|
+
* declaration order (never completion order — see decision #8). A branch never appears
|
|
246
|
+
* with an 'errored' status: an uncaught branch error always escalates to whole-fork
|
|
247
|
+
* failure (decision #9) rather than sitting here as a persisted per-branch state.
|
|
248
|
+
*/
|
|
249
|
+
interface ForkCursor {
|
|
250
|
+
readonly kind: 'fork';
|
|
251
|
+
readonly fork: string;
|
|
252
|
+
readonly branches: readonly BranchCursor[];
|
|
253
|
+
}
|
|
254
|
+
type BranchCursor = {
|
|
255
|
+
readonly name: string;
|
|
256
|
+
readonly status: 'done';
|
|
257
|
+
readonly state: Record<string, unknown>;
|
|
258
|
+
readonly touchedKeys: readonly string[];
|
|
259
|
+
} | {
|
|
260
|
+
readonly name: string;
|
|
261
|
+
readonly status: 'paused';
|
|
262
|
+
readonly state: Record<string, unknown>;
|
|
263
|
+
readonly cursor: Cursor;
|
|
264
|
+
readonly touchedKeys: readonly string[];
|
|
265
|
+
};
|
|
266
|
+
/** Structural type guard distinguishing a ForkCursor from a plain step-name cursor. */
|
|
267
|
+
declare function isForkCursor(cursor: Cursor): cursor is ForkCursor;
|
|
268
|
+
|
|
103
269
|
/**
|
|
104
270
|
* Options passed to {@link SessionStore.claim}.
|
|
105
271
|
*
|
|
@@ -236,7 +402,11 @@ interface SessionStore {
|
|
|
236
402
|
* every run settles (either `'paused'` on an interrupt or `'completed'`).
|
|
237
403
|
*
|
|
238
404
|
* - `phase: 'paused'` — the run paused on an interrupt; `step` is the step that
|
|
239
|
-
* issued the interrupt and `signal` is `'$interrupt'`.
|
|
405
|
+
* issued the interrupt and `signal` is `'$interrupt'`. `step` is a plain step name,
|
|
406
|
+
* or (when the run paused inside a fork) a composite `ForkCursor` carrying every
|
|
407
|
+
* branch's own state/cursor — see `Cursor` in `loop-executor.ts` and
|
|
408
|
+
* HANDOVER-fork-join.md §4/Phase 5. A plain-string `step` from before fork/join
|
|
409
|
+
* existed is still a valid `Cursor`, so old rows load and resume unchanged.
|
|
240
410
|
* - `phase: 'completed'` — the loop exited normally; `signal` holds the exit
|
|
241
411
|
* signal (or is absent when the loop ended without emitting a signal).
|
|
242
412
|
*/
|
|
@@ -251,7 +421,7 @@ interface StoredRun {
|
|
|
251
421
|
readonly initialState: Record<string, unknown>;
|
|
252
422
|
readonly finalState: Record<string, unknown>;
|
|
253
423
|
readonly signal?: string;
|
|
254
|
-
readonly step?:
|
|
424
|
+
readonly step?: Cursor;
|
|
255
425
|
/**
|
|
256
426
|
* Operational metadata written by the framework.
|
|
257
427
|
*
|
|
@@ -268,7 +438,8 @@ interface StoredRun {
|
|
|
268
438
|
* - `'in-flight'` — a run is currently executing (in-process guard only; not
|
|
269
439
|
* detectable cross-process from the store alone).
|
|
270
440
|
* - `'paused'` — the last run settled on an interrupt; `step` identifies the
|
|
271
|
-
* step that issued the interrupt.
|
|
441
|
+
* step that issued the interrupt. When the run paused inside a fork, `step` is
|
|
442
|
+
* the fork's own name (not the richer per-branch detail — see `pendingInterrupts`).
|
|
272
443
|
* - `'completed'` — the last run exited the loop; `signal` is the exit signal.
|
|
273
444
|
*/
|
|
274
445
|
type SessionPhase = {
|
|
@@ -280,10 +451,28 @@ type SessionPhase = {
|
|
|
280
451
|
readonly phase: 'paused';
|
|
281
452
|
readonly signal?: string;
|
|
282
453
|
readonly step: string;
|
|
454
|
+
/**
|
|
455
|
+
* Every interrupt currently awaiting a response, one per paused branch when the run
|
|
456
|
+
* paused inside a fork (a single-element array for a plain, non-forked pause). Lets a
|
|
457
|
+
* caller discover and resolve each one — via `Agent.resume(response, sessionId, id)` —
|
|
458
|
+
* independently; the session stays `'paused'` until every entry is resolved.
|
|
459
|
+
*/
|
|
460
|
+
readonly pendingInterrupts: readonly PendingInterrupt[];
|
|
283
461
|
} | {
|
|
284
462
|
readonly phase: 'completed';
|
|
285
463
|
readonly signal?: string;
|
|
286
464
|
};
|
|
465
|
+
/** One outstanding `ctx.interrupt()` call awaiting a response. See {@link SessionPhase}. */
|
|
466
|
+
interface PendingInterrupt {
|
|
467
|
+
readonly interruptId: string;
|
|
468
|
+
readonly prompt: unknown;
|
|
469
|
+
/**
|
|
470
|
+
* The step that raised this interrupt. For a forked pause this is a `/`-joined
|
|
471
|
+
* breadcrumb (`"<fork>/<branch>/<step>"`, recursing further for nested forks) —
|
|
472
|
+
* same style as the validator's own fork/branch violation paths.
|
|
473
|
+
*/
|
|
474
|
+
readonly step: string;
|
|
475
|
+
}
|
|
287
476
|
|
|
288
477
|
/**
|
|
289
478
|
* Options for background renewal mode.
|
|
@@ -408,20 +597,47 @@ interface StepDef {
|
|
|
408
597
|
readonly next: string | undefined;
|
|
409
598
|
readonly errorAware: boolean;
|
|
410
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* A single `.branch(name, fn)` declaration inside a fork.
|
|
602
|
+
* definition is the branch's own, independently-captured LoopDefinition — built by running
|
|
603
|
+
* the branch's builder lambda against a fresh createLoopBuilder() instance. Inside a branch,
|
|
604
|
+
* `.end()` means "this branch is done," not "the run is done" (see LoopBuilder.branch).
|
|
605
|
+
*/
|
|
606
|
+
interface BranchDef {
|
|
607
|
+
readonly name: string;
|
|
608
|
+
readonly definition: LoopDefinition;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Compiled fork node stored in LoopDefinition.steps alongside StepDef nodes.
|
|
612
|
+
* A fork has no run/route of its own — it never emits a signal, so .on() is not supported on it.
|
|
613
|
+
* next: explicit .next(name) target for the step that runs once every branch has settled
|
|
614
|
+
* (the "join"), or undefined to fall through to the next declared top-level node.
|
|
615
|
+
* Discriminated from StepDef structurally (see isForkDef) rather than via a tag field, so
|
|
616
|
+
* existing StepDef-only code and hand-built StepDef literals are unaffected.
|
|
617
|
+
*/
|
|
618
|
+
interface ForkDef {
|
|
619
|
+
readonly name: string;
|
|
620
|
+
readonly branches: readonly BranchDef[];
|
|
621
|
+
readonly next: string | undefined;
|
|
622
|
+
}
|
|
623
|
+
/** A top-level node in a LoopDefinition: either an ordinary step or a fork. */
|
|
624
|
+
type LoopNode = StepDef | ForkDef;
|
|
625
|
+
/** Structural type guard distinguishing ForkDef from StepDef within a LoopNode. */
|
|
626
|
+
declare function isForkDef(node: LoopNode): node is ForkDef;
|
|
411
627
|
/**
|
|
412
628
|
* Complete loop topology captured from the builder lambda.
|
|
413
629
|
* Immutable snapshot — produced once, consumed by LoopValidator and (later) F6.
|
|
414
630
|
*
|
|
415
631
|
* startCalled: true if l.start() was invoked at least once.
|
|
416
|
-
* entryStep: name of the first .step() declared after .start() was called; undefined if
|
|
417
|
-
* was never called or no
|
|
418
|
-
* steps: all declared steps in declaration order.
|
|
632
|
+
* entryStep: name of the first .step()/.fork() declared after .start() was called; undefined if
|
|
633
|
+
* .start() was never called or no node was declared after it.
|
|
634
|
+
* steps: all declared top-level nodes (steps and forks) in declaration order.
|
|
419
635
|
* onError: the fallback step name from l.onError(), or undefined if not set.
|
|
420
636
|
*/
|
|
421
637
|
interface LoopDefinition {
|
|
422
638
|
readonly startCalled: boolean;
|
|
423
639
|
readonly entryStep: string | undefined;
|
|
424
|
-
readonly steps: readonly
|
|
640
|
+
readonly steps: readonly LoopNode[];
|
|
425
641
|
readonly onError: string | undefined;
|
|
426
642
|
}
|
|
427
643
|
/**
|
|
@@ -439,13 +655,41 @@ interface OnChain<S, Ctx> {
|
|
|
439
655
|
* All methods mutate internal state and return `this` for chaining.
|
|
440
656
|
*/
|
|
441
657
|
interface LoopBuilder<S, Ctx> {
|
|
442
|
-
/** Mark the loop as having a declared entry. The first .step() called after .start() is the entry. */
|
|
658
|
+
/** Mark the loop as having a declared entry. The first .step()/.fork() called after .start() is the entry. */
|
|
443
659
|
start(): LoopBuilder<S, Ctx>;
|
|
444
660
|
/** Declare a step. At least one of run or route must be set (validated later by LoopValidator). */
|
|
445
661
|
step(name: string, options: StepOptions<S, Ctx>): LoopBuilder<S, Ctx>;
|
|
662
|
+
/**
|
|
663
|
+
* Declare a fork: a named node that splits execution into 2+ concurrent branches, declared
|
|
664
|
+
* with .branch() immediately after. The step immediately following the fork automatically
|
|
665
|
+
* waits for every branch to settle (the "join") — no separate join primitive exists.
|
|
666
|
+
*
|
|
667
|
+
* Known limitation: the built-in LLM adapters (`@noetaris/harness-anthropic`/`-openai`/
|
|
668
|
+
* `-google`/`-ollama`) attribute per-step telemetry via a stored-field pattern that is not
|
|
669
|
+
* safe when one adapter instance is shared across concurrently-running branches (the normal
|
|
670
|
+
* setup). See `ObserverAware.setStepContext`'s doc comment (`agent/observer.ts`) for details
|
|
671
|
+
* — not fixed for this release.
|
|
672
|
+
*/
|
|
673
|
+
fork(name: string): LoopBuilder<S, Ctx>;
|
|
674
|
+
/**
|
|
675
|
+
* Declare one branch of the fork most recently opened with .fork(). Must be called immediately
|
|
676
|
+
* after .fork() or another .branch() on the same fork — throws otherwise.
|
|
677
|
+
* builderFn receives a fresh LoopBuilder scoped to this branch, using the same .step()/.on()/
|
|
678
|
+
* .next() vocabulary as the top level; inside it, .end() means "this branch is done," not
|
|
679
|
+
* "the run is done."
|
|
680
|
+
*/
|
|
681
|
+
branch(name: string, builderFn: (b: LoopBuilder<S, Ctx>) => void): LoopBuilder<S, Ctx>;
|
|
682
|
+
/**
|
|
683
|
+
* Declare the step that runs once every branch of the preceding fork has settled.
|
|
684
|
+
* Pure alias of .step(name, options) — not enforced by the validator, just a naming
|
|
685
|
+
* convenience so the DSL reads as fork/branch/join.
|
|
686
|
+
*/
|
|
687
|
+
join(name: string, options: StepOptions<S, Ctx>): LoopBuilder<S, Ctx>;
|
|
446
688
|
/**
|
|
447
689
|
* Begin a signal transition declaration. Must be called immediately after .step() or after
|
|
448
690
|
* a previous .on().to() or .on().end() chain (attaches to the most recently declared step).
|
|
691
|
+
* Throws if the most recently declared node is a fork — a fork has no run/route to emit
|
|
692
|
+
* a signal from.
|
|
449
693
|
*/
|
|
450
694
|
on(signal: string): OnChain<S, Ctx>;
|
|
451
695
|
/**
|
|
@@ -723,120 +967,4 @@ declare class LeaseExpiredError extends Error {
|
|
|
723
967
|
constructor(sessionId: string);
|
|
724
968
|
}
|
|
725
969
|
|
|
726
|
-
|
|
727
|
-
* Identifies the agent and session for run-level observer callbacks.
|
|
728
|
-
*/
|
|
729
|
-
interface RunContext {
|
|
730
|
-
readonly agentId: string;
|
|
731
|
-
readonly sessionId: string;
|
|
732
|
-
/**
|
|
733
|
-
* The UUID for this specific run invocation. Always present in RunContext
|
|
734
|
-
* passed to observer methods.
|
|
735
|
-
*/
|
|
736
|
-
readonly runId: string;
|
|
737
|
-
/**
|
|
738
|
-
* Optional parent run UUID for cross-process trace correlation. Present
|
|
739
|
-
* when parentRunId was passed to agent.run() resources. Absent for top-level
|
|
740
|
-
* runs or when not provided by the caller.
|
|
741
|
-
*/
|
|
742
|
-
readonly parentRunId?: string;
|
|
743
|
-
/**
|
|
744
|
-
* The physical instance ID of the agent process, if configured via
|
|
745
|
-
* `createAgent()` options. Absent when `instanceId` was not provided.
|
|
746
|
-
*/
|
|
747
|
-
readonly instanceId?: string;
|
|
748
|
-
}
|
|
749
|
-
/**
|
|
750
|
-
* Identifies the agent, session, and current step for step-level observer callbacks.
|
|
751
|
-
*/
|
|
752
|
-
interface StepContext {
|
|
753
|
-
readonly agentId: string;
|
|
754
|
-
readonly sessionId: string;
|
|
755
|
-
readonly stepName: string;
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* Observability hook interface. All methods are optional — implement only
|
|
759
|
-
* the hooks you need.
|
|
760
|
-
*
|
|
761
|
-
* Pass an `Observer` implementation in `agent.run()` resources under the key
|
|
762
|
-
* `'observer'`, or bind it to an {@link ObserverAware} slot before running.
|
|
763
|
-
*
|
|
764
|
-
* LLM adapters emit `'llm.response'` events via `onEvent` carrying an
|
|
765
|
-
* `LLMUsageEvent` payload for token tracking.
|
|
766
|
-
*
|
|
767
|
-
* @example
|
|
768
|
-
* ```ts
|
|
769
|
-
* const obs: Observer = {
|
|
770
|
-
* onRunStart: (ctx) => console.log('run started', ctx.sessionId),
|
|
771
|
-
* onEvent: (ctx, type, payload) => metrics.record(type, payload),
|
|
772
|
-
* }
|
|
773
|
-
* agent.run({}, { llm, observer: obs })
|
|
774
|
-
* ```
|
|
775
|
-
*/
|
|
776
|
-
interface Observer {
|
|
777
|
-
/** Called once when a run begins, before the first step executes. */
|
|
778
|
-
onRunStart?: (ctx: RunContext) => void;
|
|
779
|
-
/** Called once when a run settles (completed or stopped). */
|
|
780
|
-
onRunEnd?: (ctx: RunContext, event: {
|
|
781
|
-
signal: string;
|
|
782
|
-
durationMs: number;
|
|
783
|
-
}) => void;
|
|
784
|
-
/** Called immediately before each step's `run` function is invoked. */
|
|
785
|
-
onStepStart?: (ctx: StepContext) => void;
|
|
786
|
-
/** Called after a step completes successfully. */
|
|
787
|
-
onStepEnd?: (ctx: StepContext, event: {
|
|
788
|
-
durationMs: number;
|
|
789
|
-
}) => void;
|
|
790
|
-
/** Called when a step's `run` function throws. */
|
|
791
|
-
onStepError?: (ctx: StepContext, event: {
|
|
792
|
-
error: unknown;
|
|
793
|
-
durationMs: number;
|
|
794
|
-
}) => void;
|
|
795
|
-
/** Called when a step issues a `ctx.interrupt()`. */
|
|
796
|
-
onInterrupt?: (ctx: StepContext, event: {
|
|
797
|
-
prompt: unknown;
|
|
798
|
-
interruptId: string;
|
|
799
|
-
}) => void;
|
|
800
|
-
/**
|
|
801
|
-
* Called for arbitrary named events emitted by step code via `ctx.emit()` or
|
|
802
|
-
* by LLM adapters (e.g. `'llm.response'`).
|
|
803
|
-
*/
|
|
804
|
-
onEvent?: (ctx: StepContext, type: string, payload: unknown) => void;
|
|
805
|
-
}
|
|
806
|
-
/**
|
|
807
|
-
* Implemented by resources (e.g. LLM adapters) that accept an {@link Observer}
|
|
808
|
-
* at run time. The harness calls `bindObserver` on every slot value that
|
|
809
|
-
* implements this interface before the first step runs.
|
|
810
|
-
*
|
|
811
|
-
* Optionally, the harness calls `setStepContext` at the start of each step for
|
|
812
|
-
* every slot that exposes it. Adapters use this to attribute per-step telemetry
|
|
813
|
-
* (e.g. `observer.onEvent`) to the correct step without manual calls from step code.
|
|
814
|
-
*/
|
|
815
|
-
interface ObserverAware {
|
|
816
|
-
/**
|
|
817
|
-
* Receive the run's observer. The harness calls this once per `agent.run()`
|
|
818
|
-
* invocation before execution begins.
|
|
819
|
-
*/
|
|
820
|
-
bindObserver(observer: Observer): void;
|
|
821
|
-
/**
|
|
822
|
-
* Receive the current step context. The harness calls this at the start of
|
|
823
|
-
* each step for every slot that exposes this method, before calling `step.run`.
|
|
824
|
-
*
|
|
825
|
-
* Adapters that emit `observer.onEvent` in their `invoke()` method store the
|
|
826
|
-
* provided `StepContext` and use it as the first argument to `onEvent`, so
|
|
827
|
-
* events are attributed to the correct step automatically.
|
|
828
|
-
*/
|
|
829
|
-
setStepContext?(ctx: StepContext): void;
|
|
830
|
-
}
|
|
831
|
-
/**
|
|
832
|
-
* Combine multiple {@link Observer} instances into one. Each hook on the
|
|
833
|
-
* composite forwards to all constituent observers in order.
|
|
834
|
-
*
|
|
835
|
-
* @example
|
|
836
|
-
* ```ts
|
|
837
|
-
* const observer = composeObservers(otelObserver, metricsObserver)
|
|
838
|
-
* ```
|
|
839
|
-
*/
|
|
840
|
-
declare function composeObservers(...observers: Observer[]): Observer;
|
|
841
|
-
|
|
842
|
-
export { type Agent, type ClaimOptions, type DeepWithMarkers, type FieldDefinition, type FrameworkState, type Harness, type Lease, LeaseExpiredError, type LoopDefinition, LoopNotDefinedError, NoInterruptError, type Observer, type ObserverAware, REQUIRED_TAG, RUNTIME_TAG, type RequiredMarker, type RouteFn, type RunContext, type RunFn, type RuntimeMarker, SessionBusyError, SessionInFlightError, SessionPendingInterruptError, type SessionStore, type SignalTransition, type StateFromSchema, type StepContext, type StepDef, type StepState, StoreLoadError, type StoredRun, type StoredRunMetadata, type TransitionTarget, composeObservers, createAgent, createHarness, field, isRequiredMarker, isRuntimeMarker, required, runtime };
|
|
970
|
+
export { type Agent, type BranchCursor, type BranchDef, type ClaimOptions, type Cursor, type DeepWithMarkers, type FieldDefinition, type ForkCursor, type ForkDef, type FrameworkState, type Harness, type Lease, LeaseExpiredError, type LoopDefinition, type LoopNode, LoopNotDefinedError, NoInterruptError, type Observer, type ObserverAware, REQUIRED_TAG, RUNTIME_TAG, type RequiredMarker, type RouteFn, type RunContext, type RunFn, type RuntimeMarker, SessionBusyError, SessionInFlightError, SessionPendingInterruptError, type SessionStore, type SignalTransition, type StateFromSchema, type StepContext, type StepDef, type StepState, StoreLoadError, type StoredRun, type StoredRunMetadata, type TransitionTarget, composeObservers, createAgent, createHarness, field, isForkCursor, isForkDef, isRequiredMarker, isRuntimeMarker, required, runtime };
|