@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.
- package/.generated/req.txt +1 -0
- package/.turbo/turbo-build.log +21 -0
- package/.turbo/turbo-test$colon$coverage.log +109 -0
- package/.turbo/turbo-test.log +141 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/CHANGELOG.md +16 -0
- package/ISSUES.md +540 -0
- package/LICENSE +21 -0
- package/README.md +128 -0
- package/banner.svg +97 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/core/agents/base/agent.ts.html +1705 -0
- package/coverage/lcov-report/core/agents/base/index.html +146 -0
- package/coverage/lcov-report/core/agents/base/output.ts.html +256 -0
- package/coverage/lcov-report/core/agents/base/utils.ts.html +694 -0
- package/coverage/lcov-report/core/agents/flow/engine.ts.html +928 -0
- package/coverage/lcov-report/core/agents/flow/flow-agent.ts.html +1462 -0
- package/coverage/lcov-report/core/agents/flow/index.html +146 -0
- package/coverage/lcov-report/core/agents/flow/messages.ts.html +508 -0
- package/coverage/lcov-report/core/agents/flow/steps/factory.ts.html +1975 -0
- package/coverage/lcov-report/core/agents/flow/steps/index.html +116 -0
- package/coverage/lcov-report/core/index.html +131 -0
- package/coverage/lcov-report/core/logger.ts.html +541 -0
- package/coverage/lcov-report/core/models/providers/index.html +116 -0
- package/coverage/lcov-report/core/models/providers/openai.ts.html +337 -0
- package/coverage/lcov-report/core/provider/index.html +131 -0
- package/coverage/lcov-report/core/provider/provider.ts.html +346 -0
- package/coverage/lcov-report/core/provider/usage.ts.html +376 -0
- package/coverage/lcov-report/core/tool.ts.html +577 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +221 -0
- package/coverage/lcov-report/lib/hooks.ts.html +262 -0
- package/coverage/lcov-report/lib/index.html +161 -0
- package/coverage/lcov-report/lib/middleware.ts.html +274 -0
- package/coverage/lcov-report/lib/runnable.ts.html +151 -0
- package/coverage/lcov-report/lib/trace.ts.html +520 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/utils/attempt.ts.html +199 -0
- package/coverage/lcov-report/utils/error.ts.html +421 -0
- package/coverage/lcov-report/utils/index.html +176 -0
- package/coverage/lcov-report/utils/resolve.ts.html +208 -0
- package/coverage/lcov-report/utils/result.ts.html +538 -0
- package/coverage/lcov-report/utils/zod.ts.html +178 -0
- package/coverage/lcov.info +1566 -0
- package/dist/index.d.mts +2883 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2312 -0
- package/dist/index.mjs.map +1 -0
- package/docs/core/agent.md +231 -0
- package/docs/core/hooks.md +95 -0
- package/docs/core/overview.md +87 -0
- package/docs/core/step.md +279 -0
- package/docs/core/tools.md +98 -0
- package/docs/core/workflow.md +235 -0
- package/docs/guides/create-agent.md +224 -0
- package/docs/guides/create-tool.md +137 -0
- package/docs/guides/create-workflow.md +374 -0
- package/docs/overview.md +244 -0
- package/docs/provider/models.md +55 -0
- package/docs/provider/overview.md +106 -0
- package/docs/provider/usage.md +100 -0
- package/docs/research/experimental-context.md +167 -0
- package/docs/research/gap-analysis.md +86 -0
- package/docs/research/prepare-step-and-active-tools.md +138 -0
- package/docs/research/sub-agent-model.md +249 -0
- package/docs/troubleshooting.md +60 -0
- package/logo.svg +17 -0
- package/models.config.json +18 -0
- package/package.json +60 -0
- package/scripts/generate-models.ts +324 -0
- package/src/core/agents/base/agent.test.ts +1522 -0
- package/src/core/agents/base/agent.ts +547 -0
- package/src/core/agents/base/output.test.ts +93 -0
- package/src/core/agents/base/output.ts +57 -0
- package/src/core/agents/base/types.test-d.ts +69 -0
- package/src/core/agents/base/types.ts +503 -0
- package/src/core/agents/base/utils.test.ts +397 -0
- package/src/core/agents/base/utils.ts +197 -0
- package/src/core/agents/flow/engine.test.ts +452 -0
- package/src/core/agents/flow/engine.ts +281 -0
- package/src/core/agents/flow/flow-agent.test.ts +1027 -0
- package/src/core/agents/flow/flow-agent.ts +473 -0
- package/src/core/agents/flow/messages.test.ts +198 -0
- package/src/core/agents/flow/messages.ts +141 -0
- package/src/core/agents/flow/steps/agent.test.ts +280 -0
- package/src/core/agents/flow/steps/agent.ts +87 -0
- package/src/core/agents/flow/steps/all.test.ts +300 -0
- package/src/core/agents/flow/steps/all.ts +73 -0
- package/src/core/agents/flow/steps/builder.ts +124 -0
- package/src/core/agents/flow/steps/each.test.ts +257 -0
- package/src/core/agents/flow/steps/each.ts +61 -0
- package/src/core/agents/flow/steps/factory.test-d.ts +50 -0
- package/src/core/agents/flow/steps/factory.test.ts +1025 -0
- package/src/core/agents/flow/steps/factory.ts +645 -0
- package/src/core/agents/flow/steps/map.test.ts +273 -0
- package/src/core/agents/flow/steps/map.ts +75 -0
- package/src/core/agents/flow/steps/race.test.ts +290 -0
- package/src/core/agents/flow/steps/race.ts +59 -0
- package/src/core/agents/flow/steps/reduce.test.ts +310 -0
- package/src/core/agents/flow/steps/reduce.ts +73 -0
- package/src/core/agents/flow/steps/result.ts +27 -0
- package/src/core/agents/flow/steps/step.test.ts +402 -0
- package/src/core/agents/flow/steps/step.ts +51 -0
- package/src/core/agents/flow/steps/while.test.ts +283 -0
- package/src/core/agents/flow/steps/while.ts +75 -0
- package/src/core/agents/flow/types.ts +348 -0
- package/src/core/logger.test.ts +163 -0
- package/src/core/logger.ts +152 -0
- package/src/core/models/index.test.ts +137 -0
- package/src/core/models/index.ts +152 -0
- package/src/core/models/providers/openai.ts +84 -0
- package/src/core/provider/provider.test.ts +128 -0
- package/src/core/provider/provider.ts +99 -0
- package/src/core/provider/types.ts +98 -0
- package/src/core/provider/usage.test.ts +304 -0
- package/src/core/provider/usage.ts +97 -0
- package/src/core/tool.test.ts +65 -0
- package/src/core/tool.ts +164 -0
- package/src/core/types.ts +66 -0
- package/src/index.ts +95 -0
- package/src/lib/context.test.ts +86 -0
- package/src/lib/context.ts +49 -0
- package/src/lib/hooks.test.ts +102 -0
- package/src/lib/hooks.ts +59 -0
- package/src/lib/middleware.test.ts +122 -0
- package/src/lib/middleware.ts +63 -0
- package/src/lib/runnable.test.ts +41 -0
- package/src/lib/runnable.ts +22 -0
- package/src/lib/trace.test.ts +291 -0
- package/src/lib/trace.ts +145 -0
- package/src/models/index.ts +123 -0
- package/src/models/providers/index.ts +15 -0
- package/src/models/providers/openai.ts +84 -0
- package/src/testing/context.ts +32 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/logger.ts +19 -0
- package/src/utils/attempt.test.ts +127 -0
- package/src/utils/attempt.ts +38 -0
- package/src/utils/error.test.ts +179 -0
- package/src/utils/error.ts +112 -0
- package/src/utils/resolve.test.ts +38 -0
- package/src/utils/resolve.ts +41 -0
- package/src/utils/result.test.ts +79 -0
- package/src/utils/result.ts +151 -0
- package/src/utils/zod.test.ts +69 -0
- package/src/utils/zod.ts +31 -0
- package/tsconfig.json +25 -0
- package/tsdown.config.ts +15 -0
- package/vitest.config.ts +46 -0
|
@@ -0,0 +1,310 @@
|
|
|
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("reduce()", () => {
|
|
7
|
+
it("accumulates values sequentially", async () => {
|
|
8
|
+
const ctx = createMockCtx();
|
|
9
|
+
const $ = createStepBuilder({ ctx });
|
|
10
|
+
|
|
11
|
+
const result = await $.reduce({
|
|
12
|
+
id: "reduce-sum",
|
|
13
|
+
input: [1, 2, 3, 4],
|
|
14
|
+
initial: 0,
|
|
15
|
+
execute: async ({ item, accumulator }) => accumulator + item,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(result.ok).toBe(true);
|
|
19
|
+
if (!result.ok) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
expect(result.value).toBe(10);
|
|
23
|
+
expect(result.step.type).toBe("reduce");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("uses initial value when input is empty", async () => {
|
|
27
|
+
const ctx = createMockCtx();
|
|
28
|
+
const $ = createStepBuilder({ ctx });
|
|
29
|
+
|
|
30
|
+
const result = await $.reduce({
|
|
31
|
+
id: "reduce-empty",
|
|
32
|
+
input: [],
|
|
33
|
+
initial: 42,
|
|
34
|
+
execute: async ({ accumulator }) => accumulator,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(result.ok).toBe(true);
|
|
38
|
+
if (!result.ok) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
expect(result.value).toBe(42);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("handles single-item input", async () => {
|
|
45
|
+
const ctx = createMockCtx();
|
|
46
|
+
const $ = createStepBuilder({ ctx });
|
|
47
|
+
|
|
48
|
+
const result = await $.reduce({
|
|
49
|
+
id: "reduce-single",
|
|
50
|
+
input: [5],
|
|
51
|
+
initial: 10,
|
|
52
|
+
execute: async ({ item, accumulator }) => accumulator + item,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(result.ok).toBe(true);
|
|
56
|
+
if (!result.ok) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
expect(result.value).toBe(15);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("processes items in order", async () => {
|
|
63
|
+
const ctx = createMockCtx();
|
|
64
|
+
const $ = createStepBuilder({ ctx });
|
|
65
|
+
const order: string[] = [];
|
|
66
|
+
|
|
67
|
+
const result = await $.reduce({
|
|
68
|
+
id: "reduce-order",
|
|
69
|
+
input: ["a", "b", "c"],
|
|
70
|
+
initial: "",
|
|
71
|
+
execute: async ({ item, accumulator }) => {
|
|
72
|
+
order.push(item);
|
|
73
|
+
return accumulator + item;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(result.ok).toBe(true);
|
|
78
|
+
if (!result.ok) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
expect(result.value).toBe("abc");
|
|
82
|
+
expect(order).toEqual(["a", "b", "c"]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("passes index to execute callback", async () => {
|
|
86
|
+
const ctx = createMockCtx();
|
|
87
|
+
const $ = createStepBuilder({ ctx });
|
|
88
|
+
const indices: number[] = [];
|
|
89
|
+
|
|
90
|
+
await $.reduce({
|
|
91
|
+
id: "reduce-index",
|
|
92
|
+
input: ["x", "y", "z"],
|
|
93
|
+
initial: "",
|
|
94
|
+
execute: async ({ accumulator, index }) => {
|
|
95
|
+
indices.push(index);
|
|
96
|
+
return accumulator;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(indices).toEqual([0, 1, 2]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("returns ok: false when execute throws", async () => {
|
|
104
|
+
const ctx = createMockCtx();
|
|
105
|
+
const $ = createStepBuilder({ ctx });
|
|
106
|
+
|
|
107
|
+
const result = await $.reduce({
|
|
108
|
+
id: "reduce-err",
|
|
109
|
+
input: [1, 2, 3],
|
|
110
|
+
initial: 0,
|
|
111
|
+
execute: async ({ item }) => {
|
|
112
|
+
if (item === 2) {
|
|
113
|
+
throw new Error("reduce error");
|
|
114
|
+
}
|
|
115
|
+
return item;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(result.ok).toBe(false);
|
|
120
|
+
if (result.ok) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
expect(result.error.message).toBe("reduce error");
|
|
124
|
+
expect(result.error.stepId).toBe("reduce-err");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("stops processing on error", async () => {
|
|
128
|
+
const ctx = createMockCtx();
|
|
129
|
+
const $ = createStepBuilder({ ctx });
|
|
130
|
+
const processed: number[] = [];
|
|
131
|
+
|
|
132
|
+
await $.reduce({
|
|
133
|
+
id: "reduce-stop",
|
|
134
|
+
input: [1, 2, 3],
|
|
135
|
+
initial: 0,
|
|
136
|
+
execute: async ({ item, accumulator }) => {
|
|
137
|
+
if (item === 2) {
|
|
138
|
+
throw new Error("stop");
|
|
139
|
+
}
|
|
140
|
+
processed.push(item);
|
|
141
|
+
return accumulator + item;
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
expect(processed).toEqual([1]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("respects abort signal", async () => {
|
|
149
|
+
const controller = new AbortController();
|
|
150
|
+
const ctx = createMockCtx({ signal: controller.signal });
|
|
151
|
+
const $ = createStepBuilder({ ctx });
|
|
152
|
+
|
|
153
|
+
controller.abort();
|
|
154
|
+
|
|
155
|
+
const result = await $.reduce({
|
|
156
|
+
id: "reduce-aborted",
|
|
157
|
+
input: [1, 2, 3],
|
|
158
|
+
initial: 0,
|
|
159
|
+
execute: async ({ item, accumulator }) => accumulator + item,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(result.ok).toBe(false);
|
|
163
|
+
if (result.ok) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
expect(result.error.message).toBe("Aborted");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("can reduce objects", async () => {
|
|
170
|
+
const ctx = createMockCtx();
|
|
171
|
+
const $ = createStepBuilder({ ctx });
|
|
172
|
+
|
|
173
|
+
const result = await $.reduce({
|
|
174
|
+
id: "reduce-obj",
|
|
175
|
+
input: [
|
|
176
|
+
{ key: "a", val: 1 },
|
|
177
|
+
{ key: "b", val: 2 },
|
|
178
|
+
],
|
|
179
|
+
initial: {} as Record<string, number>,
|
|
180
|
+
execute: async ({ item, accumulator }) => ({
|
|
181
|
+
...accumulator,
|
|
182
|
+
[item.key]: item.val,
|
|
183
|
+
}),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
expect(result.ok).toBe(true);
|
|
187
|
+
if (!result.ok) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
expect(result.value).toEqual({ a: 1, b: 2 });
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("fires onStart and onFinish hooks", async () => {
|
|
194
|
+
const order: string[] = [];
|
|
195
|
+
const ctx = createMockCtx();
|
|
196
|
+
const $ = createStepBuilder({ ctx });
|
|
197
|
+
|
|
198
|
+
await $.reduce({
|
|
199
|
+
id: "reduce-hooks",
|
|
200
|
+
input: [1, 2],
|
|
201
|
+
initial: 0,
|
|
202
|
+
onStart: () => {
|
|
203
|
+
order.push("onStart");
|
|
204
|
+
},
|
|
205
|
+
execute: async ({ item, accumulator }) => {
|
|
206
|
+
order.push(`execute:${item}`);
|
|
207
|
+
return accumulator + item;
|
|
208
|
+
},
|
|
209
|
+
onFinish: () => {
|
|
210
|
+
order.push("onFinish");
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(order).toEqual(["onStart", "execute:1", "execute:2", "onFinish"]);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it("fires onError hook on failure", async () => {
|
|
218
|
+
const onError = vi.fn();
|
|
219
|
+
const ctx = createMockCtx();
|
|
220
|
+
const $ = createStepBuilder({ ctx });
|
|
221
|
+
|
|
222
|
+
await $.reduce({
|
|
223
|
+
id: "reduce-onerror",
|
|
224
|
+
input: [1],
|
|
225
|
+
initial: 0,
|
|
226
|
+
execute: async () => {
|
|
227
|
+
throw new Error("reduce failure");
|
|
228
|
+
},
|
|
229
|
+
onError,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
expect(onError).toHaveBeenCalledTimes(1);
|
|
233
|
+
expect(onError).toHaveBeenCalledWith(
|
|
234
|
+
expect.objectContaining({
|
|
235
|
+
id: "reduce-onerror",
|
|
236
|
+
error: expect.any(Error),
|
|
237
|
+
}),
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("onFinish receives the final accumulated result", async () => {
|
|
242
|
+
const onFinish = vi.fn();
|
|
243
|
+
const ctx = createMockCtx();
|
|
244
|
+
const $ = createStepBuilder({ ctx });
|
|
245
|
+
|
|
246
|
+
await $.reduce({
|
|
247
|
+
id: "reduce-finish",
|
|
248
|
+
input: [10, 20, 30],
|
|
249
|
+
initial: 0,
|
|
250
|
+
execute: async ({ item, accumulator }) => accumulator + item,
|
|
251
|
+
onFinish,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
expect(onFinish).toHaveBeenCalledWith(
|
|
255
|
+
expect.objectContaining({
|
|
256
|
+
id: "reduce-finish",
|
|
257
|
+
result: 60,
|
|
258
|
+
duration: expect.any(Number),
|
|
259
|
+
}),
|
|
260
|
+
);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("records trace entry", async () => {
|
|
264
|
+
const ctx = createMockCtx();
|
|
265
|
+
const $ = createStepBuilder({ ctx });
|
|
266
|
+
|
|
267
|
+
await $.reduce({
|
|
268
|
+
id: "reduce-trace",
|
|
269
|
+
input: [1, 2],
|
|
270
|
+
initial: 0,
|
|
271
|
+
execute: async ({ item, accumulator }) => accumulator + item,
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const traceEntry = ctx.trace[0];
|
|
275
|
+
if (traceEntry === undefined) {
|
|
276
|
+
throw new Error("Expected trace entry");
|
|
277
|
+
}
|
|
278
|
+
expect(traceEntry.id).toBe("reduce-trace");
|
|
279
|
+
expect(traceEntry.type).toBe("reduce");
|
|
280
|
+
expect(traceEntry.input).toEqual([1, 2]);
|
|
281
|
+
expect(traceEntry.output).toBe(3);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("provides child $ for nested operations", async () => {
|
|
285
|
+
const ctx = createMockCtx();
|
|
286
|
+
const $$ = createStepBuilder({ ctx });
|
|
287
|
+
|
|
288
|
+
await $$.reduce({
|
|
289
|
+
id: "reduce-nested",
|
|
290
|
+
input: [1],
|
|
291
|
+
initial: 0,
|
|
292
|
+
execute: async ({ item, accumulator, $ }) => {
|
|
293
|
+
const inner = await $.step({
|
|
294
|
+
id: "inner",
|
|
295
|
+
execute: async () => item + accumulator,
|
|
296
|
+
});
|
|
297
|
+
if (!inner.ok) {
|
|
298
|
+
throw new Error("inner failed");
|
|
299
|
+
}
|
|
300
|
+
return inner.value;
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
const traceEntry = ctx.trace[0];
|
|
305
|
+
if (traceEntry === undefined) {
|
|
306
|
+
throw new Error("Expected trace entry");
|
|
307
|
+
}
|
|
308
|
+
expect(traceEntry.children).toHaveLength(1);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { StepBuilder } from "@/core/agents/flow/steps/builder.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configuration for `$.reduce()` — sequential accumulation.
|
|
5
|
+
*
|
|
6
|
+
* Each step depends on the previous result. Returns the final
|
|
7
|
+
* accumulated value.
|
|
8
|
+
*
|
|
9
|
+
* @typeParam T - Input item type.
|
|
10
|
+
* @typeParam R - Accumulator/result type.
|
|
11
|
+
*/
|
|
12
|
+
export interface ReduceConfig<T, R> {
|
|
13
|
+
/**
|
|
14
|
+
* Unique step identifier.
|
|
15
|
+
*
|
|
16
|
+
* Appears in the execution trace.
|
|
17
|
+
*/
|
|
18
|
+
id: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Array of items to reduce over.
|
|
22
|
+
*
|
|
23
|
+
* Each item is passed to the `execute` callback along with the
|
|
24
|
+
* current accumulator value.
|
|
25
|
+
*/
|
|
26
|
+
input: readonly T[];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Initial accumulator value.
|
|
30
|
+
*
|
|
31
|
+
* Used as the `accumulator` parameter for the first `execute` call.
|
|
32
|
+
*/
|
|
33
|
+
initial: R;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Reduce function — processes one item and returns the new accumulator.
|
|
37
|
+
*
|
|
38
|
+
* @param params - Execution parameters.
|
|
39
|
+
* @param params.item - The current item from the input array.
|
|
40
|
+
* @param params.accumulator - The current accumulated value.
|
|
41
|
+
* @param params.index - The item's zero-based index in the input array.
|
|
42
|
+
* @param params.$ - The step builder for nesting further operations.
|
|
43
|
+
* @returns The updated accumulator value.
|
|
44
|
+
*/
|
|
45
|
+
execute: (params: { item: T; accumulator: R; index: number; $: StepBuilder }) => Promise<R>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Hook: fires when the reduce operation starts.
|
|
49
|
+
*
|
|
50
|
+
* @param event - Event containing the step id.
|
|
51
|
+
* @param event.id - The step's unique identifier.
|
|
52
|
+
*/
|
|
53
|
+
onStart?: (event: { id: string }) => void | Promise<void>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Hook: fires when all items are reduced.
|
|
57
|
+
*
|
|
58
|
+
* @param event - Event containing the step id, final result, and duration.
|
|
59
|
+
* @param event.id - The step's unique identifier.
|
|
60
|
+
* @param event.result - The final accumulated value.
|
|
61
|
+
* @param event.duration - Wall-clock time in milliseconds.
|
|
62
|
+
*/
|
|
63
|
+
onFinish?: (event: { id: string; result: R; duration: number }) => void | Promise<void>;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Hook: fires if the reduce operation encounters an error.
|
|
67
|
+
*
|
|
68
|
+
* @param event - Event containing the step id and error.
|
|
69
|
+
* @param event.id - The step's unique identifier.
|
|
70
|
+
* @param event.error - The error that occurred.
|
|
71
|
+
*/
|
|
72
|
+
onError?: (event: { id: string; error: Error }) => void | Promise<void>;
|
|
73
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { StepInfo } from "@/core/agents/flow/types.js";
|
|
2
|
+
import type { ResultError } from "@/utils/result.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Error information for a failed step.
|
|
6
|
+
*
|
|
7
|
+
* Extends {@link ResultError} with the step's `id` so error handlers
|
|
8
|
+
* can correlate failures back to a specific `$` call.
|
|
9
|
+
*/
|
|
10
|
+
export interface StepError extends ResultError {
|
|
11
|
+
/**
|
|
12
|
+
* The `id` from the step config that failed.
|
|
13
|
+
*/
|
|
14
|
+
stepId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Discriminated union for step operation results.
|
|
19
|
+
*
|
|
20
|
+
* The success value is available via `.value`. Callers pattern-match
|
|
21
|
+
* on `ok` instead of using try/catch.
|
|
22
|
+
*
|
|
23
|
+
* @typeParam T - The success payload type.
|
|
24
|
+
*/
|
|
25
|
+
export type StepResult<T> =
|
|
26
|
+
| { ok: true; value: T; step: StepInfo; duration: number }
|
|
27
|
+
| { ok: false; error: StepError; step: StepInfo; duration: number };
|