@funkai/agents 0.1.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 (153) hide show
  1. package/.generated/req.txt +1 -0
  2. package/.turbo/turbo-build.log +21 -0
  3. package/.turbo/turbo-test$colon$coverage.log +109 -0
  4. package/.turbo/turbo-test.log +141 -0
  5. package/.turbo/turbo-typecheck.log +4 -0
  6. package/CHANGELOG.md +16 -0
  7. package/ISSUES.md +540 -0
  8. package/LICENSE +21 -0
  9. package/README.md +128 -0
  10. package/banner.svg +97 -0
  11. package/coverage/lcov-report/base.css +224 -0
  12. package/coverage/lcov-report/block-navigation.js +87 -0
  13. package/coverage/lcov-report/core/agents/base/agent.ts.html +1705 -0
  14. package/coverage/lcov-report/core/agents/base/index.html +146 -0
  15. package/coverage/lcov-report/core/agents/base/output.ts.html +256 -0
  16. package/coverage/lcov-report/core/agents/base/utils.ts.html +694 -0
  17. package/coverage/lcov-report/core/agents/flow/engine.ts.html +928 -0
  18. package/coverage/lcov-report/core/agents/flow/flow-agent.ts.html +1462 -0
  19. package/coverage/lcov-report/core/agents/flow/index.html +146 -0
  20. package/coverage/lcov-report/core/agents/flow/messages.ts.html +508 -0
  21. package/coverage/lcov-report/core/agents/flow/steps/factory.ts.html +1975 -0
  22. package/coverage/lcov-report/core/agents/flow/steps/index.html +116 -0
  23. package/coverage/lcov-report/core/index.html +131 -0
  24. package/coverage/lcov-report/core/logger.ts.html +541 -0
  25. package/coverage/lcov-report/core/models/providers/index.html +116 -0
  26. package/coverage/lcov-report/core/models/providers/openai.ts.html +337 -0
  27. package/coverage/lcov-report/core/provider/index.html +131 -0
  28. package/coverage/lcov-report/core/provider/provider.ts.html +346 -0
  29. package/coverage/lcov-report/core/provider/usage.ts.html +376 -0
  30. package/coverage/lcov-report/core/tool.ts.html +577 -0
  31. package/coverage/lcov-report/favicon.png +0 -0
  32. package/coverage/lcov-report/index.html +221 -0
  33. package/coverage/lcov-report/lib/hooks.ts.html +262 -0
  34. package/coverage/lcov-report/lib/index.html +161 -0
  35. package/coverage/lcov-report/lib/middleware.ts.html +274 -0
  36. package/coverage/lcov-report/lib/runnable.ts.html +151 -0
  37. package/coverage/lcov-report/lib/trace.ts.html +520 -0
  38. package/coverage/lcov-report/prettify.css +1 -0
  39. package/coverage/lcov-report/prettify.js +2 -0
  40. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  41. package/coverage/lcov-report/sorter.js +210 -0
  42. package/coverage/lcov-report/utils/attempt.ts.html +199 -0
  43. package/coverage/lcov-report/utils/error.ts.html +421 -0
  44. package/coverage/lcov-report/utils/index.html +176 -0
  45. package/coverage/lcov-report/utils/resolve.ts.html +208 -0
  46. package/coverage/lcov-report/utils/result.ts.html +538 -0
  47. package/coverage/lcov-report/utils/zod.ts.html +178 -0
  48. package/coverage/lcov.info +1566 -0
  49. package/dist/index.d.mts +2883 -0
  50. package/dist/index.d.mts.map +1 -0
  51. package/dist/index.mjs +2312 -0
  52. package/dist/index.mjs.map +1 -0
  53. package/docs/core/agent.md +231 -0
  54. package/docs/core/hooks.md +95 -0
  55. package/docs/core/overview.md +87 -0
  56. package/docs/core/step.md +279 -0
  57. package/docs/core/tools.md +98 -0
  58. package/docs/core/workflow.md +235 -0
  59. package/docs/guides/create-agent.md +224 -0
  60. package/docs/guides/create-tool.md +137 -0
  61. package/docs/guides/create-workflow.md +374 -0
  62. package/docs/overview.md +244 -0
  63. package/docs/provider/models.md +55 -0
  64. package/docs/provider/overview.md +106 -0
  65. package/docs/provider/usage.md +100 -0
  66. package/docs/research/experimental-context.md +167 -0
  67. package/docs/research/gap-analysis.md +86 -0
  68. package/docs/research/prepare-step-and-active-tools.md +138 -0
  69. package/docs/research/sub-agent-model.md +249 -0
  70. package/docs/troubleshooting.md +60 -0
  71. package/logo.svg +17 -0
  72. package/models.config.json +18 -0
  73. package/package.json +60 -0
  74. package/scripts/generate-models.ts +324 -0
  75. package/src/core/agents/base/agent.test.ts +1522 -0
  76. package/src/core/agents/base/agent.ts +547 -0
  77. package/src/core/agents/base/output.test.ts +93 -0
  78. package/src/core/agents/base/output.ts +57 -0
  79. package/src/core/agents/base/types.test-d.ts +69 -0
  80. package/src/core/agents/base/types.ts +503 -0
  81. package/src/core/agents/base/utils.test.ts +397 -0
  82. package/src/core/agents/base/utils.ts +197 -0
  83. package/src/core/agents/flow/engine.test.ts +452 -0
  84. package/src/core/agents/flow/engine.ts +281 -0
  85. package/src/core/agents/flow/flow-agent.test.ts +1027 -0
  86. package/src/core/agents/flow/flow-agent.ts +473 -0
  87. package/src/core/agents/flow/messages.test.ts +198 -0
  88. package/src/core/agents/flow/messages.ts +141 -0
  89. package/src/core/agents/flow/steps/agent.test.ts +280 -0
  90. package/src/core/agents/flow/steps/agent.ts +87 -0
  91. package/src/core/agents/flow/steps/all.test.ts +300 -0
  92. package/src/core/agents/flow/steps/all.ts +73 -0
  93. package/src/core/agents/flow/steps/builder.ts +124 -0
  94. package/src/core/agents/flow/steps/each.test.ts +257 -0
  95. package/src/core/agents/flow/steps/each.ts +61 -0
  96. package/src/core/agents/flow/steps/factory.test-d.ts +50 -0
  97. package/src/core/agents/flow/steps/factory.test.ts +1025 -0
  98. package/src/core/agents/flow/steps/factory.ts +645 -0
  99. package/src/core/agents/flow/steps/map.test.ts +273 -0
  100. package/src/core/agents/flow/steps/map.ts +75 -0
  101. package/src/core/agents/flow/steps/race.test.ts +290 -0
  102. package/src/core/agents/flow/steps/race.ts +59 -0
  103. package/src/core/agents/flow/steps/reduce.test.ts +310 -0
  104. package/src/core/agents/flow/steps/reduce.ts +73 -0
  105. package/src/core/agents/flow/steps/result.ts +27 -0
  106. package/src/core/agents/flow/steps/step.test.ts +402 -0
  107. package/src/core/agents/flow/steps/step.ts +51 -0
  108. package/src/core/agents/flow/steps/while.test.ts +283 -0
  109. package/src/core/agents/flow/steps/while.ts +75 -0
  110. package/src/core/agents/flow/types.ts +348 -0
  111. package/src/core/logger.test.ts +163 -0
  112. package/src/core/logger.ts +152 -0
  113. package/src/core/models/index.test.ts +137 -0
  114. package/src/core/models/index.ts +152 -0
  115. package/src/core/models/providers/openai.ts +84 -0
  116. package/src/core/provider/provider.test.ts +128 -0
  117. package/src/core/provider/provider.ts +99 -0
  118. package/src/core/provider/types.ts +98 -0
  119. package/src/core/provider/usage.test.ts +304 -0
  120. package/src/core/provider/usage.ts +97 -0
  121. package/src/core/tool.test.ts +65 -0
  122. package/src/core/tool.ts +164 -0
  123. package/src/core/types.ts +66 -0
  124. package/src/index.ts +95 -0
  125. package/src/lib/context.test.ts +86 -0
  126. package/src/lib/context.ts +49 -0
  127. package/src/lib/hooks.test.ts +102 -0
  128. package/src/lib/hooks.ts +59 -0
  129. package/src/lib/middleware.test.ts +122 -0
  130. package/src/lib/middleware.ts +63 -0
  131. package/src/lib/runnable.test.ts +41 -0
  132. package/src/lib/runnable.ts +22 -0
  133. package/src/lib/trace.test.ts +291 -0
  134. package/src/lib/trace.ts +145 -0
  135. package/src/models/index.ts +123 -0
  136. package/src/models/providers/index.ts +15 -0
  137. package/src/models/providers/openai.ts +84 -0
  138. package/src/testing/context.ts +32 -0
  139. package/src/testing/index.ts +2 -0
  140. package/src/testing/logger.ts +19 -0
  141. package/src/utils/attempt.test.ts +127 -0
  142. package/src/utils/attempt.ts +38 -0
  143. package/src/utils/error.test.ts +179 -0
  144. package/src/utils/error.ts +112 -0
  145. package/src/utils/resolve.test.ts +38 -0
  146. package/src/utils/resolve.ts +41 -0
  147. package/src/utils/result.test.ts +79 -0
  148. package/src/utils/result.ts +151 -0
  149. package/src/utils/zod.test.ts +69 -0
  150. package/src/utils/zod.ts +31 -0
  151. package/tsconfig.json +25 -0
  152. package/tsdown.config.ts +15 -0
  153. package/vitest.config.ts +46 -0
@@ -0,0 +1,283 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+
3
+ import { createStepBuilder } from "@/core/agents/flow/steps/factory.js";
4
+ import { createMockCtx } from "@/testing/index.js";
5
+
6
+ describe("while()", () => {
7
+ it("loops while condition is true", async () => {
8
+ const ctx = createMockCtx();
9
+ const $ = createStepBuilder({ ctx });
10
+
11
+ const result = await $.while({
12
+ id: "while-count",
13
+ condition: ({ index }) => index < 3,
14
+ execute: async ({ index }) => index,
15
+ });
16
+
17
+ expect(result.ok).toBe(true);
18
+ if (!result.ok) {
19
+ return;
20
+ }
21
+ expect(result.value).toBe(2);
22
+ expect(result.step.type).toBe("while");
23
+ });
24
+
25
+ it("returns undefined when condition is initially false", async () => {
26
+ const ctx = createMockCtx();
27
+ const $ = createStepBuilder({ ctx });
28
+
29
+ const result = await $.while({
30
+ id: "while-none",
31
+ condition: () => false,
32
+ execute: async () => "should not run",
33
+ });
34
+
35
+ expect(result.ok).toBe(true);
36
+ if (!result.ok) {
37
+ return;
38
+ }
39
+ expect(result.value).toBeUndefined();
40
+ });
41
+
42
+ it("does not call execute when condition is initially false", async () => {
43
+ const ctx = createMockCtx();
44
+ const $ = createStepBuilder({ ctx });
45
+ const executeSpy = vi.fn(async () => "value");
46
+
47
+ await $.while({
48
+ id: "while-no-exec",
49
+ condition: () => false,
50
+ execute: executeSpy,
51
+ });
52
+
53
+ expect(executeSpy).not.toHaveBeenCalled();
54
+ });
55
+
56
+ it("executes exactly once when condition is true only for first iteration", async () => {
57
+ const ctx = createMockCtx();
58
+ const $ = createStepBuilder({ ctx });
59
+ const iterations: number[] = [];
60
+
61
+ const result = await $.while({
62
+ id: "while-once",
63
+ condition: ({ index }) => index < 1,
64
+ execute: async ({ index }) => {
65
+ iterations.push(index);
66
+ return `iter-${index}`;
67
+ },
68
+ });
69
+
70
+ expect(result.ok).toBe(true);
71
+ if (!result.ok) {
72
+ return;
73
+ }
74
+ expect(result.value).toBe("iter-0");
75
+ expect(iterations).toEqual([0]);
76
+ });
77
+
78
+ it("passes previous value to condition", async () => {
79
+ const ctx = createMockCtx();
80
+ const $ = createStepBuilder({ ctx });
81
+ const conditionValues: Array<number | undefined> = [];
82
+
83
+ await $.while<number>({
84
+ id: "while-val",
85
+ condition: ({ value, index }) => {
86
+ conditionValues.push(value);
87
+ return index < 3;
88
+ },
89
+ execute: async ({ index }) => (index + 1) * 10,
90
+ });
91
+
92
+ expect(conditionValues).toEqual([undefined, 10, 20, 30]);
93
+ });
94
+
95
+ it("returns ok: false when execute throws", async () => {
96
+ const ctx = createMockCtx();
97
+ const $ = createStepBuilder({ ctx });
98
+
99
+ const result = await $.while({
100
+ id: "while-err",
101
+ condition: () => true,
102
+ execute: async ({ index }) => {
103
+ if (index === 2) {
104
+ throw new Error("while error");
105
+ }
106
+ return index;
107
+ },
108
+ });
109
+
110
+ expect(result.ok).toBe(false);
111
+ if (result.ok) {
112
+ return;
113
+ }
114
+ expect(result.error.message).toBe("while error");
115
+ expect(result.error.stepId).toBe("while-err");
116
+ });
117
+
118
+ it("stops iteration on error", async () => {
119
+ const ctx = createMockCtx();
120
+ const $ = createStepBuilder({ ctx });
121
+ const iterations: number[] = [];
122
+
123
+ await $.while({
124
+ id: "while-stop",
125
+ condition: () => true,
126
+ execute: async ({ index }) => {
127
+ iterations.push(index);
128
+ if (index === 1) {
129
+ throw new Error("stop");
130
+ }
131
+ return index;
132
+ },
133
+ });
134
+
135
+ expect(iterations).toEqual([0, 1]);
136
+ });
137
+
138
+ it("respects abort signal", async () => {
139
+ const controller = new AbortController();
140
+ const ctx = createMockCtx({ signal: controller.signal });
141
+ const $ = createStepBuilder({ ctx });
142
+
143
+ controller.abort();
144
+
145
+ const result = await $.while({
146
+ id: "while-aborted",
147
+ condition: () => true,
148
+ execute: async ({ index }) => index,
149
+ });
150
+
151
+ expect(result.ok).toBe(false);
152
+ if (result.ok) {
153
+ return;
154
+ }
155
+ expect(result.error.message).toBe("Aborted");
156
+ });
157
+
158
+ it("fires onStart and onFinish hooks", async () => {
159
+ const order: string[] = [];
160
+ const ctx = createMockCtx();
161
+ const $ = createStepBuilder({ ctx });
162
+
163
+ await $.while({
164
+ id: "while-hooks",
165
+ condition: ({ index }) => index < 2,
166
+ onStart: () => {
167
+ order.push("onStart");
168
+ },
169
+ execute: async ({ index }) => {
170
+ order.push(`execute:${index}`);
171
+ return index;
172
+ },
173
+ onFinish: () => {
174
+ order.push("onFinish");
175
+ },
176
+ });
177
+
178
+ expect(order).toEqual(["onStart", "execute:0", "execute:1", "onFinish"]);
179
+ });
180
+
181
+ it("fires onError hook on failure", async () => {
182
+ const onError = vi.fn();
183
+ const ctx = createMockCtx();
184
+ const $ = createStepBuilder({ ctx });
185
+
186
+ await $.while({
187
+ id: "while-onerror",
188
+ condition: () => true,
189
+ execute: async () => {
190
+ throw new Error("while failure");
191
+ },
192
+ onError,
193
+ });
194
+
195
+ expect(onError).toHaveBeenCalledTimes(1);
196
+ expect(onError).toHaveBeenCalledWith(
197
+ expect.objectContaining({
198
+ id: "while-onerror",
199
+ error: expect.any(Error),
200
+ }),
201
+ );
202
+ });
203
+
204
+ it("onFinish receives last value and duration", async () => {
205
+ const onFinish = vi.fn();
206
+ const ctx = createMockCtx();
207
+ const $ = createStepBuilder({ ctx });
208
+
209
+ await $.while({
210
+ id: "while-finish",
211
+ condition: ({ index }) => index < 3,
212
+ execute: async ({ index }) => index * 10,
213
+ onFinish,
214
+ });
215
+
216
+ expect(onFinish).toHaveBeenCalledWith(
217
+ expect.objectContaining({
218
+ id: "while-finish",
219
+ result: 20,
220
+ duration: expect.any(Number),
221
+ }),
222
+ );
223
+ });
224
+
225
+ it("onFinish receives undefined when condition is initially false", async () => {
226
+ const onFinish = vi.fn();
227
+ const ctx = createMockCtx();
228
+ const $ = createStepBuilder({ ctx });
229
+
230
+ await $.while({
231
+ id: "while-finish-none",
232
+ condition: () => false,
233
+ execute: async () => "never",
234
+ onFinish,
235
+ });
236
+
237
+ expect(onFinish).toHaveBeenCalledWith(
238
+ expect.objectContaining({
239
+ id: "while-finish-none",
240
+ result: undefined,
241
+ }),
242
+ );
243
+ });
244
+
245
+ it("records trace entry", async () => {
246
+ const ctx = createMockCtx();
247
+ const $ = createStepBuilder({ ctx });
248
+
249
+ await $.while({
250
+ id: "while-trace",
251
+ condition: ({ index }) => index < 2,
252
+ execute: async ({ index }) => index,
253
+ });
254
+
255
+ const traceEntry = ctx.trace[0];
256
+ if (traceEntry === undefined) {
257
+ throw new Error("Expected trace entry");
258
+ }
259
+ expect(traceEntry.id).toBe("while-trace");
260
+ expect(traceEntry.type).toBe("while");
261
+ expect(traceEntry.output).toBe(1);
262
+ });
263
+
264
+ it("provides child $ for nested operations", async () => {
265
+ const ctx = createMockCtx();
266
+ const $$ = createStepBuilder({ ctx });
267
+
268
+ await $$.while({
269
+ id: "while-nested",
270
+ condition: ({ index }) => index < 1,
271
+ execute: async ({ index, $ }) => {
272
+ await $.step({ id: "inner", execute: async () => index });
273
+ return index;
274
+ },
275
+ });
276
+
277
+ const traceEntry = ctx.trace[0];
278
+ if (traceEntry === undefined) {
279
+ throw new Error("Expected trace entry");
280
+ }
281
+ expect(traceEntry.children).toHaveLength(1);
282
+ });
283
+ });
@@ -0,0 +1,75 @@
1
+ import type { StepBuilder } from "@/core/agents/flow/steps/builder.js";
2
+
3
+ /**
4
+ * Configuration for `$.while()` — conditional loop.
5
+ *
6
+ * Runs while a condition holds. Each iteration is tracked. Returns
7
+ * the **last value** (`undefined` if the condition was false on
8
+ * first check).
9
+ *
10
+ * @typeParam T - The value type produced by each iteration.
11
+ */
12
+ export interface WhileConfig<T> {
13
+ /**
14
+ * Unique step identifier.
15
+ *
16
+ * Appears in the execution trace. Individual iterations appear
17
+ * as children of this entry.
18
+ */
19
+ id: string;
20
+
21
+ /**
22
+ * Loop condition — evaluated before each iteration.
23
+ *
24
+ * Called with the last iteration's value (or `undefined` before
25
+ * the first iteration) and the current iteration index.
26
+ *
27
+ * @param params - Condition parameters.
28
+ * @param params.value - The last iteration's value, or `undefined`
29
+ * before the first iteration.
30
+ * @param params.index - The zero-based iteration index.
31
+ * @returns `true` to continue looping, `false` to stop.
32
+ */
33
+ condition: (params: { value: T | undefined; index: number }) => boolean;
34
+
35
+ /**
36
+ * Execute one iteration.
37
+ *
38
+ * @param params - Execution parameters.
39
+ * @param params.index - The zero-based iteration index.
40
+ * @param params.$ - The step builder for nesting further operations.
41
+ * @returns The value for this iteration.
42
+ */
43
+ execute: (params: { index: number; $: StepBuilder }) => Promise<T>;
44
+
45
+ /**
46
+ * Hook: fires when the while loop starts.
47
+ *
48
+ * @param event - Event containing the step id.
49
+ * @param event.id - The step's unique identifier.
50
+ */
51
+ onStart?: (event: { id: string }) => void | Promise<void>;
52
+
53
+ /**
54
+ * Hook: fires when the while loop finishes.
55
+ *
56
+ * @param event - Event containing the step id, last value, and duration.
57
+ * @param event.id - The step's unique identifier.
58
+ * @param event.result - The last iteration's value, or `undefined`.
59
+ * @param event.duration - Wall-clock time in milliseconds.
60
+ */
61
+ onFinish?: (event: {
62
+ id: string;
63
+ result: T | undefined;
64
+ duration: number;
65
+ }) => void | Promise<void>;
66
+
67
+ /**
68
+ * Hook: fires if the while loop encounters an error.
69
+ *
70
+ * @param event - Event containing the step id and error.
71
+ * @param event.id - The step's unique identifier.
72
+ * @param event.error - The error that occurred.
73
+ */
74
+ onError?: (event: { id: string; error: Error }) => void | Promise<void>;
75
+ }
@@ -0,0 +1,348 @@
1
+ import type { ZodType } from "zod";
2
+
3
+ import type { GenerateResult, Message, StreamResult } from "@/core/agents/base/types.js";
4
+ import type { StepBuilder } from "@/core/agents/flow/steps/builder.js";
5
+ import type { Logger } from "@/core/logger.js";
6
+ import type { TraceEntry, OperationType } from "@/lib/trace.js";
7
+ import type { Result } from "@/utils/result.js";
8
+
9
+ /**
10
+ * Information about a step in a flow agent execution.
11
+ *
12
+ * Passed to flow agent-level hooks (`onStepStart`, `onStepFinish`)
13
+ * and included in step events.
14
+ */
15
+ export interface StepInfo {
16
+ /**
17
+ * The id from the `$` config.
18
+ *
19
+ * Matches the `id` field on the step config that produced this event.
20
+ */
21
+ id: string;
22
+
23
+ /**
24
+ * Auto-incrementing index within the flow agent execution.
25
+ *
26
+ * Starts at `0` for the first `$` call and increments for each
27
+ * subsequent tracked operation.
28
+ */
29
+ index: number;
30
+
31
+ /**
32
+ * What kind of `$` call produced this step.
33
+ *
34
+ * Discriminant for filtering or grouping step events.
35
+ */
36
+ type: OperationType;
37
+ }
38
+
39
+ /**
40
+ * Result of a completed flow agent generation.
41
+ *
42
+ * Extends `GenerateResult` with flow-specific fields (`trace`, `duration`).
43
+ * Consumers who only care about the `Runnable` / `Agent` contract see
44
+ * `{ output, messages, usage, finishReason }`. Consumers who know they
45
+ * have a `FlowAgent` can access `trace` and `duration`.
46
+ *
47
+ * @typeParam TOutput - The validated output type.
48
+ */
49
+ export interface FlowAgentGenerateResult<TOutput> extends GenerateResult<TOutput> {
50
+ /**
51
+ * The full execution trace.
52
+ *
53
+ * A frozen tree of `TraceEntry` nodes representing every tracked `$`
54
+ * operation that ran during the flow.
55
+ */
56
+ trace: readonly TraceEntry[];
57
+
58
+ /**
59
+ * Total wall-clock time in milliseconds.
60
+ *
61
+ * Measured from the start of the flow to the completion
62
+ * of all operations.
63
+ */
64
+ duration: number;
65
+ }
66
+
67
+ /**
68
+ * Shared configuration fields for all flow agent variants.
69
+ *
70
+ * @typeParam TInput - Input type, inferred from the `input` Zod schema.
71
+ */
72
+ export interface FlowAgentConfigBase<TInput> {
73
+ /**
74
+ * Unique flow agent name.
75
+ *
76
+ * Used in logging, trace entries, and hook events.
77
+ */
78
+ name: string;
79
+
80
+ /**
81
+ * Zod schema for validating flow agent input.
82
+ *
83
+ * The raw input passed to `.generate()` is validated against this
84
+ * schema before the handler is called.
85
+ */
86
+ input: ZodType<TInput>;
87
+
88
+ /**
89
+ * Pino-compatible logger.
90
+ *
91
+ * When omitted, the SDK creates a default console-based instance.
92
+ * The framework automatically creates scoped child loggers
93
+ * with contextual bindings (`flowAgentId`, `stepId`).
94
+ */
95
+ logger?: Logger;
96
+
97
+ /**
98
+ * Hook: fires when the flow agent starts execution.
99
+ *
100
+ * @param event - Event containing the validated input.
101
+ */
102
+ onStart?: (event: { input: TInput }) => void | Promise<void>;
103
+
104
+ /**
105
+ * Hook: fires when the flow agent encounters an error.
106
+ *
107
+ * @param event - Event containing the input and error.
108
+ */
109
+ onError?: (event: { input: TInput; error: Error }) => void | Promise<void>;
110
+
111
+ /**
112
+ * Hook: fires when any tracked `$` step starts.
113
+ *
114
+ * @param event - Event containing step info.
115
+ */
116
+ onStepStart?: (event: { step: StepInfo }) => void | Promise<void>;
117
+
118
+ /**
119
+ * Hook: fires when any tracked `$` step finishes.
120
+ *
121
+ * @param event - Event containing step info, result, and duration.
122
+ */
123
+ onStepFinish?: (event: {
124
+ step: StepInfo;
125
+ result: unknown;
126
+ duration: number;
127
+ }) => void | Promise<void>;
128
+ }
129
+
130
+ /**
131
+ * Flow agent config with a structured output schema.
132
+ *
133
+ * The handler must return a value matching `TOutput`, which is
134
+ * validated against the `output` Zod schema before being returned.
135
+ *
136
+ * @typeParam TInput - Input type, inferred from the `input` Zod schema.
137
+ * @typeParam TOutput - Output type, inferred from the `output` Zod schema.
138
+ */
139
+ export interface FlowAgentConfigWithOutput<TInput, TOutput> extends FlowAgentConfigBase<TInput> {
140
+ /**
141
+ * Zod schema for validating flow agent output.
142
+ *
143
+ * The handler's return value is validated against this schema
144
+ * before being returned to the caller.
145
+ */
146
+ output: ZodType<TOutput>;
147
+
148
+ /**
149
+ * Hook: fires when the flow agent finishes successfully.
150
+ *
151
+ * @param event - Event containing input, result, and duration.
152
+ */
153
+ onFinish?: (event: {
154
+ input: TInput;
155
+ result: FlowAgentGenerateResult<TOutput>;
156
+ duration: number;
157
+ }) => void | Promise<void>;
158
+ }
159
+
160
+ /**
161
+ * Flow agent config without an output schema.
162
+ *
163
+ * The handler returns `void` — it orchestrates sub-agents and steps
164
+ * without producing structured output. The collected text from
165
+ * sub-agent responses becomes the `string` output.
166
+ *
167
+ * @typeParam TInput - Input type, inferred from the `input` Zod schema.
168
+ */
169
+ export interface FlowAgentConfigWithoutOutput<TInput> extends FlowAgentConfigBase<TInput> {
170
+ /**
171
+ * No output schema — the flow agent collects text from sub-agent
172
+ * responses and returns it as a `string`.
173
+ */
174
+ output?: undefined;
175
+
176
+ /**
177
+ * Hook: fires when the flow agent finishes successfully.
178
+ *
179
+ * @param event - Event containing input, result (with string output), and duration.
180
+ */
181
+ onFinish?: (event: {
182
+ input: TInput;
183
+ result: FlowAgentGenerateResult<string>;
184
+ duration: number;
185
+ }) => void | Promise<void>;
186
+ }
187
+
188
+ /**
189
+ * Configuration for creating a flow agent.
190
+ *
191
+ * Two variants:
192
+ * - **With output**: Provide an `output` Zod schema. The handler returns
193
+ * `TOutput`, which is validated against the schema.
194
+ * - **Without output**: Omit `output`. The handler returns `void` and
195
+ * the collected text from sub-agent responses becomes the `string` output.
196
+ *
197
+ * @typeParam TInput - Input type, inferred from the `input` Zod schema.
198
+ * @typeParam TOutput - Output type, inferred from the `output` Zod schema.
199
+ */
200
+ export type FlowAgentConfig<TInput, TOutput = void> =
201
+ | FlowAgentConfigWithOutput<TInput, TOutput>
202
+ | FlowAgentConfigWithoutOutput<TInput>;
203
+
204
+ /**
205
+ * Per-call overrides for flow agent generation.
206
+ *
207
+ * Passed as the optional second parameter to `.generate()` or `.stream()`.
208
+ */
209
+ export interface FlowAgentOverrides {
210
+ /**
211
+ * Abort signal for cancellation.
212
+ *
213
+ * When fired, all in-flight operations should clean up and exit.
214
+ * Propagated through the entire execution tree.
215
+ */
216
+ signal?: AbortSignal;
217
+
218
+ /**
219
+ * Override the logger for this call.
220
+ *
221
+ * When provided, replaces the logger configured at creation time.
222
+ */
223
+ logger?: Logger;
224
+
225
+ /**
226
+ * Per-call hook — fires after base `onStart`.
227
+ */
228
+ onStart?: (event: { input: unknown }) => void | Promise<void>;
229
+
230
+ /**
231
+ * Per-call hook — fires after base `onFinish`.
232
+ */
233
+ onFinish?: (event: {
234
+ input: unknown;
235
+ result: GenerateResult;
236
+ duration: number;
237
+ }) => void | Promise<void>;
238
+
239
+ /**
240
+ * Per-call hook — fires after base `onError`.
241
+ */
242
+ onError?: (event: { input: unknown; error: Error }) => void | Promise<void>;
243
+
244
+ /**
245
+ * Per-call hook — fires after base `onStepFinish`.
246
+ */
247
+ onStepFinish?: (event: {
248
+ step: StepInfo;
249
+ result: unknown;
250
+ duration: number;
251
+ }) => void | Promise<void>;
252
+ }
253
+
254
+ /**
255
+ * Parameters passed to the flow agent handler function.
256
+ *
257
+ * @typeParam TInput - The validated input type.
258
+ */
259
+ export interface FlowAgentParams<TInput> {
260
+ /**
261
+ * Validated input.
262
+ */
263
+ input: TInput;
264
+
265
+ /**
266
+ * Composable step builder utilities.
267
+ *
268
+ * Provides tracked operations (`$.step`, `$.agent`, `$.map`, etc.)
269
+ * that register data flow for observability and produce synthetic
270
+ * tool-call messages.
271
+ */
272
+ $: StepBuilder;
273
+
274
+ /**
275
+ * Scoped logger for the current flow execution.
276
+ */
277
+ log: Logger;
278
+ }
279
+
280
+ /**
281
+ * The flow agent handler function.
282
+ *
283
+ * This IS the flow — no step arrays, no definition objects.
284
+ * State is just variables. `$` is passed in for tracked operations.
285
+ *
286
+ * @typeParam TInput - The validated input type.
287
+ * @typeParam TOutput - The output type to return.
288
+ */
289
+ export type FlowAgentHandler<TInput, TOutput> = (
290
+ params: FlowAgentParams<TInput>,
291
+ ) => Promise<TOutput>;
292
+
293
+ /**
294
+ * A created flow agent — exposes `.generate()`, `.stream()`, and `.fn()`.
295
+ *
296
+ * Flow agents are imperative handlers that use `$` for tracked operations.
297
+ * They satisfy the same `Runnable` interface as regular agents, so they
298
+ * can be used as sub-agents, tool-wrapped delegatees, etc.
299
+ *
300
+ * @typeParam TInput - Validated input type.
301
+ * @typeParam TOutput - Validated output type.
302
+ */
303
+ export interface FlowAgent<TInput, TOutput> {
304
+ /**
305
+ * Run the flow agent to completion.
306
+ *
307
+ * Validates input, executes the handler, validates output, and
308
+ * returns the result with messages, trace, and timing.
309
+ *
310
+ * @param input - Raw input (validated against the `input` Zod schema).
311
+ * @param config - Optional per-call overrides.
312
+ * @returns A `Result` wrapping the `FlowAgentGenerateResult`.
313
+ */
314
+ generate(
315
+ input: TInput,
316
+ config?: FlowAgentOverrides,
317
+ ): Promise<Result<FlowAgentGenerateResult<TOutput>>>;
318
+
319
+ /**
320
+ * Run the flow agent with streaming step progress.
321
+ *
322
+ * Returns immediately with `fullStream` — an `AsyncIterableStream`
323
+ * of typed `StreamPart` events for each step. `output`, `messages`,
324
+ * and `usage` are promises that resolve after the flow completes.
325
+ *
326
+ * @param input - Raw input (validated against the `input` Zod schema).
327
+ * @param config - Optional per-call overrides.
328
+ * @returns A `Result` wrapping the `StreamResult`.
329
+ */
330
+ stream(input: TInput, config?: FlowAgentOverrides): Promise<Result<StreamResult<TOutput>>>;
331
+
332
+ /**
333
+ * Returns a plain function that calls `.generate()`.
334
+ */
335
+ fn(): (
336
+ input: TInput,
337
+ config?: FlowAgentOverrides,
338
+ ) => Promise<Result<FlowAgentGenerateResult<TOutput>>>;
339
+ }
340
+
341
+ /**
342
+ * @internal
343
+ * Options that the engine uses to inject custom step augmentation
344
+ * into flowAgent(). Not exported — only accessible within the package.
345
+ */
346
+ export interface InternalFlowAgentOptions {
347
+ augment$?: ($: StepBuilder, ctx: import("@/lib/context.js").Context) => StepBuilder;
348
+ }