@infinityi/engine-lib 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +488 -0
  3. package/dist/agent/agent-registry.d.ts +46 -0
  4. package/dist/agent/as-tool.d.ts +64 -0
  5. package/dist/agent/define.d.ts +35 -0
  6. package/dist/agent/handoff.d.ts +39 -0
  7. package/dist/agent/index.d.ts +20 -0
  8. package/dist/agent/index.js +38 -0
  9. package/dist/agent/registry.d.ts +27 -0
  10. package/dist/agent/types.d.ts +109 -0
  11. package/dist/context/index.d.ts +11 -0
  12. package/dist/context/index.js +21 -0
  13. package/dist/context/providers.d.ts +25 -0
  14. package/dist/context/types.d.ts +63 -0
  15. package/dist/context/window.d.ts +41 -0
  16. package/dist/errors.d.ts +93 -0
  17. package/dist/errors.js +24 -0
  18. package/dist/events/hub.d.ts +15 -0
  19. package/dist/events/index.d.ts +26 -0
  20. package/dist/events/index.js +24 -0
  21. package/dist/events/subscribers.d.ts +57 -0
  22. package/dist/events/telemetry.d.ts +61 -0
  23. package/dist/events/types.d.ts +39 -0
  24. package/dist/execution/index.d.ts +11 -0
  25. package/dist/execution/index.js +22 -0
  26. package/dist/execution/run.d.ts +35 -0
  27. package/dist/execution/types.d.ts +203 -0
  28. package/dist/execution/usage.d.ts +14 -0
  29. package/dist/index-02s1fjxr.js +226 -0
  30. package/dist/index-19pwq79t.js +0 -0
  31. package/dist/index-1p6mb2vz.js +32 -0
  32. package/dist/index-64tt9696.js +1796 -0
  33. package/dist/index-7690reng.js +96 -0
  34. package/dist/index-bqg01r42.js +354 -0
  35. package/dist/index-d4xz3abn.js +0 -0
  36. package/dist/index-dexgmwg6.js +148 -0
  37. package/dist/index-fkr3rcq9.js +97 -0
  38. package/dist/index-jg19te9v.js +0 -0
  39. package/dist/index-jp2b31xs.js +101 -0
  40. package/dist/index-jxgj4z08.js +68 -0
  41. package/dist/index-kte2h4k2.js +0 -0
  42. package/dist/index-pwr8179t.js +492 -0
  43. package/dist/index-rentvdpp.js +27 -0
  44. package/dist/index-vnby35rm.js +84 -0
  45. package/dist/index-w34cbktd.js +14 -0
  46. package/dist/index-xsv43c5j.js +39 -0
  47. package/dist/index-yrqrxwjt.js +148 -0
  48. package/dist/index-zfgr4xx3.js +90 -0
  49. package/dist/index.d.ts +45 -0
  50. package/dist/index.js +117 -0
  51. package/dist/lifecycle/component.d.ts +74 -0
  52. package/dist/lifecycle/index.d.ts +12 -0
  53. package/dist/lifecycle/index.js +72 -0
  54. package/dist/messages/factory.d.ts +24 -0
  55. package/dist/messages/index.d.ts +8 -0
  56. package/dist/messages/index.js +17 -0
  57. package/dist/messages/types.d.ts +52 -0
  58. package/dist/providers/adapter.d.ts +42 -0
  59. package/dist/providers/anthropic/index.d.ts +31 -0
  60. package/dist/providers/anthropic/map.d.ts +12 -0
  61. package/dist/providers/anthropic/stream.d.ts +9 -0
  62. package/dist/providers/google/index.d.ts +29 -0
  63. package/dist/providers/google/map.d.ts +13 -0
  64. package/dist/providers/google/stream.d.ts +11 -0
  65. package/dist/providers/http.d.ts +61 -0
  66. package/dist/providers/index.d.ts +32 -0
  67. package/dist/providers/index.js +35 -0
  68. package/dist/providers/openai/index.d.ts +34 -0
  69. package/dist/providers/openai/map.d.ts +10 -0
  70. package/dist/providers/openai/stream.d.ts +9 -0
  71. package/dist/providers/openai-compatible/index.d.ts +37 -0
  72. package/dist/providers/openai-compatible/map.d.ts +13 -0
  73. package/dist/providers/openai-compatible/stream.d.ts +11 -0
  74. package/dist/providers/shared.d.ts +34 -0
  75. package/dist/providers/sse.d.ts +19 -0
  76. package/dist/providers/stream.d.ts +69 -0
  77. package/dist/providers/types.d.ts +137 -0
  78. package/dist/runtime/index.d.ts +11 -0
  79. package/dist/runtime/index.js +11 -0
  80. package/dist/runtime/secret.d.ts +12 -0
  81. package/dist/runtime/types.d.ts +27 -0
  82. package/dist/schema/builder.d.ts +70 -0
  83. package/dist/schema/index.d.ts +13 -0
  84. package/dist/schema/index.js +15 -0
  85. package/dist/schema/json-schema.d.ts +19 -0
  86. package/dist/schema/types.d.ts +70 -0
  87. package/dist/schema/validate.d.ts +19 -0
  88. package/dist/session/index.d.ts +11 -0
  89. package/dist/session/index.js +8 -0
  90. package/dist/session/session.d.ts +31 -0
  91. package/dist/session/store.d.ts +20 -0
  92. package/dist/session/types.d.ts +55 -0
  93. package/dist/testing/conformance.d.ts +106 -0
  94. package/dist/testing/conformance.js +132 -0
  95. package/dist/testing/index.d.ts +84 -0
  96. package/dist/testing/index.js +31 -0
  97. package/dist/tools/define.d.ts +42 -0
  98. package/dist/tools/index.d.ts +11 -0
  99. package/dist/tools/index.js +15 -0
  100. package/dist/tools/result.d.ts +36 -0
  101. package/dist/tools/types.d.ts +85 -0
  102. package/docs/README.md +36 -0
  103. package/examples/README.md +24 -0
  104. package/examples/incident-analysis.ts +100 -0
  105. package/examples/lifecycle.ts +53 -0
  106. package/examples/multi-agent.ts +93 -0
  107. package/examples/terminal-coder.ts +80 -0
  108. package/package.json +114 -0
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The `forge/telemetry` bridge for agent runs.
3
+ *
4
+ * Wraps the run loop in spans and metrics expressed entirely in terms of
5
+ * forge's `Telemetry` handle — engine-lib never invents its own observability
6
+ * surface. The stable application path is passing `telemetry` to `runAgent`.
7
+ * `createRunTelemetry`, span constants, and telemetry handle types are exported
8
+ * from `@infinityi/engine-lib/events` for advanced integrations and tests. Everything here
9
+ * is a no-op when no telemetry handle (or no tracer/meter) is supplied, so the
10
+ * library stays usable with zero wiring.
11
+ *
12
+ * Spans:
13
+ * - {@link SPAN_RUN} `agent.run` — one per {@link runAgent} call.
14
+ * - {@link SPAN_PROVIDER} `agent.provider.call` — one per provider turn.
15
+ * - {@link SPAN_TOOL} `agent.tool.execute` — one per tool execution.
16
+ *
17
+ * In buffered mode the run span is opened with `tracer.withSpan`, so it is the
18
+ * active context for the whole loop and the provider/tool spans (and the
19
+ * provider's own `tracedFetch` HTTP span) nest underneath it. In streaming mode
20
+ * the run span is opened with `tracer.startSpan` and ended on completion;
21
+ * child spans are still emitted but not nested under it.
22
+ *
23
+ * Metric names emitted by this bridge: `agent.run.duration` /
24
+ * `agent.tool.duration` (histograms, ms), `agent.tokens` (counter, tagged
25
+ * `token.type`), and `agent.runs` (counter, tagged outcome).
26
+ *
27
+ * @module
28
+ */
29
+ import type { Usage } from "../providers/types";
30
+ import type { TelemetryHandle } from "../runtime/types";
31
+ /** Span name for the whole run. */
32
+ export declare const SPAN_RUN = "agent.run";
33
+ /** Span name for a single provider turn. */
34
+ export declare const SPAN_PROVIDER = "agent.provider.call";
35
+ /** Span name for a single tool execution. */
36
+ export declare const SPAN_TOOL = "agent.tool.execute";
37
+ /** Attribute bag accepted by spans and metrics (forge's common subset). */
38
+ export type Attrs = Record<string, string | number | boolean>;
39
+ /** A started span the loop ends manually; a no-op when telemetry is absent. */
40
+ export interface SpanHandle {
41
+ setAttributes(attrs: Attrs): void;
42
+ ok(): void;
43
+ fail(message: string): void;
44
+ end(): void;
45
+ }
46
+ /** The telemetry surface the run loop drives. All methods are no-op safe. */
47
+ export interface RunTelemetry {
48
+ /** Run `fn` inside `name` as the active context (nests children). */
49
+ withSpan<T>(name: string, attrs: Attrs, fn: (span: SpanHandle) => Promise<T>): Promise<T>;
50
+ /** Start `name`, parented to the current active span; caller ends it. */
51
+ startSpan(name: string, attrs: Attrs): SpanHandle;
52
+ /** Record run-level duration, outcome, and token usage. */
53
+ recordRun(attrs: Attrs, durationMs: number, usage: Usage): void;
54
+ /** Record one tool execution's duration. */
55
+ recordTool(attrs: Attrs, durationMs: number): void;
56
+ }
57
+ /**
58
+ * Build the {@link RunTelemetry} bridge from a forge telemetry handle.
59
+ * Returns a fully no-op implementation when no tracer/meter is available.
60
+ */
61
+ export declare function createRunTelemetry(telemetry?: TelemetryHandle): RunTelemetry;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Event-system contracts (Phase 6).
3
+ *
4
+ * A run already emits a {@link RunEvent} stream (Phase 4). Phase 6 adds the
5
+ * ability to attach **multiple independent subscribers** — UI streaming, an
6
+ * audit log, a metrics sink, a `forge/messaging` bridge — to a single run
7
+ * without coupling them to the runtime internals or to each other.
8
+ *
9
+ * A {@link RunSubscriber} is just a function of a {@link RunEvent}. Subscribers
10
+ * are dispatched by an {@link EventHub} (see {@link createEventHub}) in
11
+ * declaration order, awaited, and isolated: a subscriber that throws or rejects
12
+ * is reported but never aborts the run nor starves the other subscribers.
13
+ * `runAgent` registers `onEvent` first, then entries from `subscribers`.
14
+ *
15
+ * @module
16
+ */
17
+ import type { RunEvent } from "../execution/types";
18
+ /**
19
+ * An external observer of a run. May be sync or async; the hub awaits it so a
20
+ * slow subscriber applies back-pressure to the run (offload heavy work yourself
21
+ * if you don't want that).
22
+ */
23
+ export type RunSubscriber = (event: RunEvent) => void | Promise<void>;
24
+ /** Fans one {@link RunEvent} out to every registered {@link RunSubscriber}. */
25
+ export interface EventHub {
26
+ /** Deliver `event` to all subscribers, in order, awaiting each. */
27
+ emit(event: RunEvent): Promise<void>;
28
+ }
29
+ /** Options for {@link createEventHub}. */
30
+ export interface EventHubOptions {
31
+ /** Subscribers, dispatched in array order. `undefined` entries are ignored. */
32
+ readonly subscribers?: ReadonlyArray<RunSubscriber | undefined>;
33
+ /**
34
+ * Invoked when a subscriber throws/rejects (the run continues regardless).
35
+ * If this callback throws, that failure is swallowed so isolation is
36
+ * preserved.
37
+ */
38
+ readonly onSubscriberError?: (error: unknown, event: RunEvent, index: number) => void;
39
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `@infinityi/engine-lib/execution` — the agent run loop.
3
+ *
4
+ * {@link runAgent} executes an {@link AgentDefinition} against its provider
5
+ * using provider-native tool calling, in buffered or streaming mode.
6
+ *
7
+ * @module
8
+ */
9
+ export { DEFAULT_MAX_HANDOFFS, DEFAULT_MAX_STEPS, runAgent } from "./run";
10
+ export { addUsage, emptyUsage } from "./usage";
11
+ export type { AnyRunOptions, BufferedRunOptions, RunBridge, RunEvent, RunHandle, RunInput, RunOptions, RunResult, StreamingRunOptions, } from "./types";
@@ -0,0 +1,22 @@
1
+ import"../index-kte2h4k2.js";
2
+ import {
3
+ DEFAULT_MAX_HANDOFFS,
4
+ DEFAULT_MAX_STEPS,
5
+ addUsage,
6
+ emptyUsage,
7
+ runAgent
8
+ } from "../index-pwr8179t.js";
9
+ import"../index-yrqrxwjt.js";
10
+ import"../index-fkr3rcq9.js";
11
+ import"../index-02s1fjxr.js";
12
+ import"../index-zfgr4xx3.js";
13
+ import"../index-7690reng.js";
14
+ import"../index-rentvdpp.js";
15
+ import"../index-1p6mb2vz.js";
16
+ export {
17
+ runAgent,
18
+ emptyUsage,
19
+ addUsage,
20
+ DEFAULT_MAX_STEPS,
21
+ DEFAULT_MAX_HANDOFFS
22
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `runAgent` — the provider-native agent execution loop.
3
+ *
4
+ * Each step sends the conversation + the agent's tool schemas to the provider,
5
+ * appends the assistant turn, and — if the model requested tools — validates
6
+ * each call's arguments against its Phase-1 schema, dispatches the tools **in
7
+ * parallel** with per-call error isolation, appends the results, and loops.
8
+ * The loop ends when the model answers without tool calls, the step budget is
9
+ * exhausted (`MaxStepsExceededError`), or the run is cancelled
10
+ * (`CancelledError`).
11
+ *
12
+ * Buffered and streaming modes share one core async generator
13
+ * ({@link executeAgent}); the buffered path drives it to completion, the
14
+ * streaming path exposes it as a {@link RunHandle}.
15
+ *
16
+ * @module
17
+ */
18
+ import type { AgentDefinition } from "../agent/types";
19
+ import type { AnyRunOptions, BufferedRunOptions, RunHandle, RunResult, StreamingRunOptions } from "./types";
20
+ /** Default cap on provider turns when {@link RunOptions.maxSteps} is omitted. */
21
+ export declare const DEFAULT_MAX_STEPS = 16;
22
+ /** Default cap on agent handoffs when {@link RunOptions.maxHandoffs} is omitted. */
23
+ export declare const DEFAULT_MAX_HANDOFFS = 8;
24
+ /**
25
+ * Run an agent to completion using the provider-native tool-calling loop.
26
+ *
27
+ * Buffered mode (default, or `stream: false`) resolves with a {@link RunResult}.
28
+ * Streaming mode (`stream: true`) returns a {@link RunHandle} you can
29
+ * `for await` over for {@link RunEvent}s, with `handle.completed` resolving to
30
+ * the final result. When `stream` is a non-literal boolean, the return type is
31
+ * `Promise<RunResult> | RunHandle`.
32
+ */
33
+ export declare function runAgent(agent: AgentDefinition, opts?: BufferedRunOptions): Promise<RunResult>;
34
+ export declare function runAgent(agent: AgentDefinition, opts: StreamingRunOptions): RunHandle;
35
+ export declare function runAgent(agent: AgentDefinition, opts: AnyRunOptions): Promise<RunResult> | RunHandle;
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Types for the agent execution flow.
3
+ *
4
+ * {@link runAgent} drives the provider-native tool-calling loop. It runs in two
5
+ * shapes that share one core: *buffered* (returns a {@link RunResult}) and
6
+ * *streaming* (returns a {@link RunHandle} — an async-iterable of
7
+ * {@link RunEvent}s plus a `completed` promise). Both modes also feed
8
+ * {@link RunOptions.onEvent} and {@link RunOptions.subscribers}.
9
+ *
10
+ * `RunEvent["type"]` values are part of the public contract. Consumers should
11
+ * handle unknown future variants defensively if they want minor-version
12
+ * compatibility with newly added events.
13
+ *
14
+ * @module
15
+ */
16
+ import type { AgentError } from "../errors";
17
+ import type { Message } from "../messages/types";
18
+ import type { FinishReason, Usage } from "../providers/types";
19
+ import type { Logger, TelemetryHandle } from "../runtime/types";
20
+ import type { GenerationSettings } from "../agent/types";
21
+ import type { AgentRegistry } from "../agent/agent-registry";
22
+ import type { ContextProvider, ContextWindowOptions } from "../context/types";
23
+ import type { Session } from "../session/types";
24
+ import type { ToolResult } from "../tools/types";
25
+ import type { RunSubscriber } from "../events/types";
26
+ /** New input for a run: raw text (→ a user message), a single message, or several. */
27
+ export type RunInput = string | Message | Message[];
28
+ /**
29
+ * A single event emitted over the course of a run.
30
+ *
31
+ * Ordering guarantees:
32
+ *
33
+ * - Every run starts with `run.start`.
34
+ * - Provider assistant turns are emitted as `message` events.
35
+ * - Streaming text is emitted as `token` before the assistant `message` that
36
+ * contains the accumulated text.
37
+ * - Tool calls emit `tool.call`, then `tool.result`, then the corresponding
38
+ * tool-result `message`.
39
+ * - Successful runs end with `run.finish`; failed runs emit `error` and then
40
+ * reject/throw the same `AgentError`.
41
+ * - `agent.child` wraps events forwarded from sub-agent tools, and
42
+ * `agent.handoff` marks a control transfer between agents.
43
+ */
44
+ export type RunEvent = {
45
+ readonly type: "run.start";
46
+ readonly agent: string;
47
+ } | {
48
+ readonly type: "message";
49
+ readonly message: Message;
50
+ } | {
51
+ readonly type: "token";
52
+ readonly delta: string;
53
+ } | {
54
+ readonly type: "tool.call";
55
+ readonly id: string;
56
+ readonly name: string;
57
+ readonly arguments: unknown;
58
+ } | {
59
+ readonly type: "tool.result";
60
+ readonly id: string;
61
+ readonly name: string;
62
+ readonly result: ToolResult;
63
+ } | {
64
+ readonly type: "run.finish";
65
+ readonly result: RunResult;
66
+ } | {
67
+ readonly type: "error";
68
+ readonly error: AgentError;
69
+ }
70
+ /**
71
+ * An event from a nested child run (e.g. a sub-agent invoked through
72
+ * {@link RunBridge}). `agent` is the child's name and `depth` is its nesting
73
+ * level relative to this run (1 for a direct child). Parent subscribers that
74
+ * don't care about nesting can ignore this variant; those that do can recurse
75
+ * into `event`.
76
+ */
77
+ | {
78
+ readonly type: "agent.child";
79
+ readonly agent: string;
80
+ readonly depth: number;
81
+ readonly event: RunEvent;
82
+ }
83
+ /**
84
+ * The active agent handed the run off to another agent (Phase 7). `from` and
85
+ * `to` are agent names. Emitted at the switch point; the message history is
86
+ * preserved across the handoff.
87
+ */
88
+ | {
89
+ readonly type: "agent.handoff";
90
+ readonly from: string;
91
+ readonly to: string;
92
+ };
93
+ /**
94
+ * A handle the run loop hands to a tool so it can participate in its parent run:
95
+ * forward nested {@link RunEvent}s onto the parent's event stream and fold
96
+ * nested token {@link Usage} into the parent run's aggregate. Used by
97
+ * sub-agent-as-tool (`asTool`) to propagate a child run's events and usage
98
+ * upward. Tools that ignore it behave exactly as before.
99
+ */
100
+ export interface RunBridge {
101
+ /** Forward a nested event onto the parent run's event stream. */
102
+ emit(event: RunEvent): void;
103
+ /** Add token usage from nested work into the parent run's running total. */
104
+ reportUsage(usage: Usage): void;
105
+ }
106
+ /** Options for a single {@link runAgent} call. */
107
+ export interface RunOptions {
108
+ /** New input for this run. */
109
+ readonly input?: RunInput;
110
+ /** Prior conversation prepended before `input`. Ignored when `session` is set (history comes from the session). */
111
+ readonly messages?: Message[];
112
+ /** Durable conversation: history is read before the run and new messages appended after it. */
113
+ readonly session?: Session;
114
+ /** Context providers injected into the system layer at run time (after instructions, before history). */
115
+ readonly context?: readonly ContextProvider[];
116
+ /** Token budgeting for the messages sent to the provider (does not affect persisted/returned history). */
117
+ readonly contextWindow?: ContextWindowOptions;
118
+ /** Per-run generation overrides, merged over the agent's `generation` defaults. */
119
+ readonly generation?: GenerationSettings;
120
+ /** Cap on provider turns (model→tools→model cycles). Defaults to {@link DEFAULT_MAX_STEPS}. */
121
+ readonly maxSteps?: number;
122
+ /** Stream tokens + tool lifecycle. Omitted/`false` → buffered `Promise<RunResult>`. */
123
+ readonly stream?: boolean;
124
+ /** Event sink invoked for every {@link RunEvent}, in both buffered and streaming modes. */
125
+ readonly onEvent?: (event: RunEvent) => void;
126
+ /**
127
+ * Additional independent event subscribers (UI streaming, audit log, metrics,
128
+ * a `forge/messaging` bridge). Dispatched after {@link RunOptions.onEvent}, in
129
+ * order, awaited per event. A subscriber that throws/rejects is isolated — it
130
+ * neither aborts the run nor starves the others.
131
+ */
132
+ readonly subscribers?: readonly RunSubscriber[];
133
+ /** Forge telemetry handle, threaded to provider calls / tools / hooks. */
134
+ readonly telemetry?: TelemetryHandle;
135
+ /** Structured logger (defaults to `telemetry.log`). */
136
+ readonly logger?: Logger;
137
+ /** Cancellation signal; halts the loop and in-flight provider/tool calls. */
138
+ readonly signal?: AbortSignal;
139
+ /**
140
+ * Cap on agent handoffs in a single run, to bound triage↔specialist
141
+ * ping-pong (Phase 7). Defaults to {@link DEFAULT_MAX_HANDOFFS}. Exceeding it
142
+ * throws {@link MaxHandoffsExceededError}.
143
+ */
144
+ readonly maxHandoffs?: number;
145
+ /**
146
+ * Registry used to resolve string-named {@link AgentDefinition.handoffs}
147
+ * targets (Phase 7). Not needed when every handoff target is given directly
148
+ * as an {@link AgentDefinition}.
149
+ */
150
+ readonly registry?: AgentRegistry;
151
+ }
152
+ /** Options for buffered mode. This is the default when `stream` is omitted. */
153
+ export type BufferedRunOptions = Omit<RunOptions, "stream"> & {
154
+ readonly stream?: false | undefined;
155
+ };
156
+ /** Options for streaming mode. */
157
+ export type StreamingRunOptions = Omit<RunOptions, "stream"> & {
158
+ readonly stream: true;
159
+ };
160
+ /**
161
+ * Options for callers that decide streaming dynamically. Passing this shape to
162
+ * `runAgent` returns `Promise<RunResult> | RunHandle`.
163
+ */
164
+ export type AnyRunOptions = Omit<RunOptions, "stream"> & {
165
+ readonly stream?: boolean;
166
+ };
167
+ /** The buffered result of a completed run. */
168
+ export interface RunResult {
169
+ /** Concatenated text of the final assistant message. */
170
+ readonly output: string;
171
+ /** The final assistant message. */
172
+ readonly finalMessage: Message;
173
+ /** Full history: prior messages + input + every assistant turn + tool results. */
174
+ readonly messages: Message[];
175
+ /** Why the loop ended. */
176
+ readonly finishReason: FinishReason;
177
+ /** Number of provider turns taken. */
178
+ readonly steps: number;
179
+ /** Token usage aggregated across all turns (zeros when unreported). */
180
+ readonly usage: Usage;
181
+ /**
182
+ * Name of the agent that produced the final answer (Phase 7). Equals the
183
+ * agent passed to {@link runAgent} unless the run handed off to another.
184
+ */
185
+ readonly agent: string;
186
+ /**
187
+ * Ordered trail of agent names the run handed off to (Phase 7). Empty when no
188
+ * handoff occurred; the final entry equals {@link RunResult.agent}.
189
+ */
190
+ readonly handoffs: readonly string[];
191
+ }
192
+ /**
193
+ * A streaming run: an async-iterable of {@link RunEvent}s, plus `completed`
194
+ * which resolves with the final {@link RunResult} once the stream is fully
195
+ * consumed (the same result is also delivered as the `run.finish` event).
196
+ *
197
+ * If iteration throws, `completed` rejects with the same error. If the consumer
198
+ * abandons iteration before a terminal event, `completed` rejects with
199
+ * `CancelledError`.
200
+ */
201
+ export type RunHandle = AsyncIterable<RunEvent> & {
202
+ readonly completed: Promise<RunResult>;
203
+ };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Usage aggregation across the turns of a run.
3
+ *
4
+ * Provider {@link Usage} is reported per turn (and may be absent); the run loop
5
+ * folds each turn's usage into a running total so {@link RunResult.usage}
6
+ * reflects the whole run.
7
+ *
8
+ * @module
9
+ */
10
+ import type { Usage } from "../providers/types";
11
+ /** A zeroed {@link Usage} accumulator. */
12
+ export declare function emptyUsage(): Usage;
13
+ /** Field-wise sum of two {@link Usage} values; optional fields appear only when present. */
14
+ export declare function addUsage(a: Usage, b?: Usage): Usage;
@@ -0,0 +1,226 @@
1
+ import {
2
+ SchemaValidationError
3
+ } from "./index-7690reng.js";
4
+
5
+ // src/schema/validate.ts
6
+ function issue(path, message) {
7
+ return { path: [...path], message };
8
+ }
9
+ function isPlainObject(value) {
10
+ return typeof value === "object" && value !== null && !Array.isArray(value);
11
+ }
12
+ function validateJsonSchema(node, input, path = []) {
13
+ const issues = [];
14
+ if (node.enum !== undefined) {
15
+ if (!node.enum.includes(input)) {
16
+ issues.push(issue(path, `expected one of ${JSON.stringify(node.enum)}`));
17
+ }
18
+ return issues;
19
+ }
20
+ switch (node.type) {
21
+ case "string":
22
+ if (typeof input !== "string")
23
+ issues.push(issue(path, "expected string"));
24
+ break;
25
+ case "boolean":
26
+ if (typeof input !== "boolean")
27
+ issues.push(issue(path, "expected boolean"));
28
+ break;
29
+ case "null":
30
+ if (input !== null)
31
+ issues.push(issue(path, "expected null"));
32
+ break;
33
+ case "number":
34
+ if (typeof input !== "number" || Number.isNaN(input)) {
35
+ issues.push(issue(path, "expected number"));
36
+ }
37
+ break;
38
+ case "integer":
39
+ if (typeof input !== "number" || !Number.isInteger(input)) {
40
+ issues.push(issue(path, "expected integer"));
41
+ }
42
+ break;
43
+ case "array": {
44
+ if (!Array.isArray(input)) {
45
+ issues.push(issue(path, "expected array"));
46
+ break;
47
+ }
48
+ if (node.items !== undefined) {
49
+ input.forEach((element, index) => {
50
+ issues.push(...validateJsonSchema(node.items, element, [...path, index]));
51
+ });
52
+ }
53
+ break;
54
+ }
55
+ case "object": {
56
+ if (!isPlainObject(input)) {
57
+ issues.push(issue(path, "expected object"));
58
+ break;
59
+ }
60
+ const properties = node.properties ?? {};
61
+ const required = node.required ?? [];
62
+ for (const key of required) {
63
+ if (input[key] === undefined) {
64
+ issues.push(issue([...path, key], "required"));
65
+ }
66
+ }
67
+ for (const [key, propSchema] of Object.entries(properties)) {
68
+ const value = input[key];
69
+ if (value === undefined)
70
+ continue;
71
+ issues.push(...validateJsonSchema(propSchema, value, [...path, key]));
72
+ }
73
+ if (node.additionalProperties === false) {
74
+ for (const key of Object.keys(input)) {
75
+ if (!(key in properties)) {
76
+ issues.push(issue([...path, key], "unexpected property"));
77
+ }
78
+ }
79
+ }
80
+ break;
81
+ }
82
+ default:
83
+ break;
84
+ }
85
+ return issues;
86
+ }
87
+
88
+ // src/schema/builder.ts
89
+ var optionalSchemas = new WeakSet;
90
+ function makeSchema(jsonSchema) {
91
+ return {
92
+ jsonSchema,
93
+ safeParse(input) {
94
+ const issues = validateJsonSchema(jsonSchema, input);
95
+ if (issues.length === 0)
96
+ return { success: true, data: input };
97
+ return {
98
+ success: false,
99
+ error: new SchemaValidationError("schema validation failed", { issues })
100
+ };
101
+ },
102
+ parse(input) {
103
+ const result = this.safeParse(input);
104
+ if (!result.success)
105
+ throw result.error;
106
+ return result.data;
107
+ }
108
+ };
109
+ }
110
+ var s = {
111
+ string(opts) {
112
+ const node = { type: "string" };
113
+ if (opts?.description !== undefined)
114
+ node.description = opts.description;
115
+ if (opts?.enum !== undefined)
116
+ node.enum = opts.enum;
117
+ return makeSchema(node);
118
+ },
119
+ number(opts) {
120
+ const node = { type: opts?.int ? "integer" : "number" };
121
+ if (opts?.description !== undefined)
122
+ node.description = opts.description;
123
+ return makeSchema(node);
124
+ },
125
+ boolean(opts) {
126
+ const node = { type: "boolean" };
127
+ if (opts?.description !== undefined)
128
+ node.description = opts.description;
129
+ return makeSchema(node);
130
+ },
131
+ enum(values, opts) {
132
+ const node = { type: "string", enum: values };
133
+ if (opts?.description !== undefined)
134
+ node.description = opts.description;
135
+ return makeSchema(node);
136
+ },
137
+ array(item, opts) {
138
+ const node = { type: "array", items: item.jsonSchema };
139
+ if (opts?.description !== undefined)
140
+ node.description = opts.description;
141
+ return makeSchema(node);
142
+ },
143
+ object(props, opts) {
144
+ const properties = {};
145
+ const required = [];
146
+ for (const [key, prop] of Object.entries(props)) {
147
+ properties[key] = prop.jsonSchema;
148
+ if (!optionalSchemas.has(prop))
149
+ required.push(key);
150
+ }
151
+ const node = {
152
+ type: "object",
153
+ properties,
154
+ additionalProperties: false
155
+ };
156
+ if (required.length > 0)
157
+ node.required = required;
158
+ if (opts?.description !== undefined)
159
+ node.description = opts.description;
160
+ return makeSchema(node);
161
+ },
162
+ optional(inner) {
163
+ const schema = {
164
+ jsonSchema: inner.jsonSchema,
165
+ safeParse(input) {
166
+ if (input === undefined)
167
+ return { success: true, data: undefined };
168
+ return inner.safeParse(input);
169
+ },
170
+ parse(input) {
171
+ const result = this.safeParse(input);
172
+ if (!result.success)
173
+ throw result.error;
174
+ return result.data;
175
+ }
176
+ };
177
+ optionalSchemas.add(schema);
178
+ return schema;
179
+ }
180
+ };
181
+ // src/schema/json-schema.ts
182
+ function toJsonSchema(schema) {
183
+ return schema.jsonSchema;
184
+ }
185
+ function asSchema(impl) {
186
+ return {
187
+ jsonSchema: impl.jsonSchema,
188
+ parse: impl.parse.bind(impl),
189
+ safeParse: impl.safeParse?.bind(impl) ?? ((input) => {
190
+ try {
191
+ return { success: true, data: impl.parse(input) };
192
+ } catch (error) {
193
+ if (error instanceof SchemaValidationError)
194
+ return { success: false, error };
195
+ return {
196
+ success: false,
197
+ error: new SchemaValidationError("schema validation failed", {
198
+ cause: error,
199
+ issues: [{ path: [], message: String(error) }]
200
+ })
201
+ };
202
+ }
203
+ })
204
+ };
205
+ }
206
+ function fromJsonSchema(jsonSchema) {
207
+ return {
208
+ jsonSchema,
209
+ safeParse(input) {
210
+ const issues = validateJsonSchema(jsonSchema, input);
211
+ if (issues.length === 0)
212
+ return { success: true, data: input };
213
+ return {
214
+ success: false,
215
+ error: new SchemaValidationError("schema validation failed", { issues })
216
+ };
217
+ },
218
+ parse(input) {
219
+ const result = this.safeParse(input);
220
+ if (!result.success)
221
+ throw result.error;
222
+ return result.data;
223
+ }
224
+ };
225
+ }
226
+ export { validateJsonSchema, s, toJsonSchema, asSchema, fromJsonSchema };
File without changes
@@ -0,0 +1,32 @@
1
+ // src/messages/factory.ts
2
+ function text(value) {
3
+ return { type: "text", text: value };
4
+ }
5
+ function normalizeContent(content) {
6
+ return typeof content === "string" ? [text(content)] : content;
7
+ }
8
+ function system(content) {
9
+ return { role: "system", content: normalizeContent(content) };
10
+ }
11
+ function user(content) {
12
+ return { role: "user", content: normalizeContent(content) };
13
+ }
14
+ function assistant(content) {
15
+ return { role: "assistant", content: normalizeContent(content) };
16
+ }
17
+ function toolResult(toolCallId, output, opts) {
18
+ const content = typeof output === "string" ? [text(output)] : output;
19
+ return {
20
+ role: "tool",
21
+ content: [
22
+ {
23
+ type: "tool_result",
24
+ toolCallId,
25
+ content,
26
+ ...opts?.isError !== undefined ? { isError: opts.isError } : {}
27
+ }
28
+ ]
29
+ };
30
+ }
31
+
32
+ export { text, normalizeContent, system, user, assistant, toolResult };