@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,281 @@
|
|
|
1
|
+
import { flowAgent } from "@/core/agents/flow/flow-agent.js";
|
|
2
|
+
import type { StepBuilder } from "@/core/agents/flow/steps/builder.js";
|
|
3
|
+
import type {
|
|
4
|
+
FlowAgent,
|
|
5
|
+
FlowAgentConfigWithOutput,
|
|
6
|
+
FlowAgentHandler,
|
|
7
|
+
} from "@/core/agents/flow/types.js";
|
|
8
|
+
import type { StepInfo } from "@/core/agents/flow/types.js";
|
|
9
|
+
import type { Logger } from "@/core/logger.js";
|
|
10
|
+
import { createDefaultLogger } from "@/core/logger.js";
|
|
11
|
+
import type { ExecutionContext } from "@/lib/context.js";
|
|
12
|
+
import { fireHooks } from "@/lib/hooks.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Factory function for a custom step type.
|
|
16
|
+
*
|
|
17
|
+
* Receives the internal context (for signal, logging) and the
|
|
18
|
+
* user-provided config. Returns the step result.
|
|
19
|
+
*
|
|
20
|
+
* @typeParam TConfig - The config shape users pass to `$.myStep({ ... })`.
|
|
21
|
+
* @typeParam TResult - The return type of the step.
|
|
22
|
+
*/
|
|
23
|
+
export type CustomStepFactory<TConfig, TResult> = (params: {
|
|
24
|
+
/**
|
|
25
|
+
* Execution context.
|
|
26
|
+
*/
|
|
27
|
+
ctx: ExecutionContext;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The config object the user passed to the custom step.
|
|
31
|
+
*/
|
|
32
|
+
config: TConfig;
|
|
33
|
+
}) => Promise<TResult>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Map of custom step names to their factory functions.
|
|
37
|
+
*
|
|
38
|
+
* Uses `config: never` as the base constraint so that any concrete
|
|
39
|
+
* `CustomStepFactory<TConfig, TResult>` is assignable via function
|
|
40
|
+
* parameter contravariance — `never extends TConfig` is always true.
|
|
41
|
+
*/
|
|
42
|
+
export type CustomStepDefinitions = Record<
|
|
43
|
+
string,
|
|
44
|
+
(params: { ctx: ExecutionContext; config: never }) => Promise<unknown>
|
|
45
|
+
>;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Derive typed custom step methods from a definitions map.
|
|
49
|
+
*
|
|
50
|
+
* @typeParam T - The `CustomStepDefinitions` map.
|
|
51
|
+
*/
|
|
52
|
+
export type TypedCustomSteps<T extends CustomStepDefinitions> = {
|
|
53
|
+
[K in keyof T]: T[K] extends CustomStepFactory<infer TConfig, infer TResult>
|
|
54
|
+
? (config: TConfig) => Promise<TResult>
|
|
55
|
+
: never;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Configuration for creating a custom flow engine.
|
|
60
|
+
*
|
|
61
|
+
* @typeParam TCustomSteps - The custom step definitions map.
|
|
62
|
+
*/
|
|
63
|
+
export interface FlowEngineConfig<TCustomSteps extends CustomStepDefinitions> {
|
|
64
|
+
/**
|
|
65
|
+
* Custom step types to add to `$`.
|
|
66
|
+
*/
|
|
67
|
+
$?: TCustomSteps;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Default hook: fires when any flow agent starts.
|
|
71
|
+
*/
|
|
72
|
+
onStart?: (event: { input: unknown }) => void | Promise<void>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Default hook: fires when any flow agent finishes.
|
|
76
|
+
*/
|
|
77
|
+
onFinish?: (event: { input: unknown; result: unknown; duration: number }) => void | Promise<void>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Default hook: fires when any flow agent errors.
|
|
81
|
+
*/
|
|
82
|
+
onError?: (event: { input: unknown; error: Error }) => void | Promise<void>;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Default hook: fires when any step starts.
|
|
86
|
+
*/
|
|
87
|
+
onStepStart?: (event: { step: StepInfo }) => void | Promise<void>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Default hook: fires when any step finishes.
|
|
91
|
+
*/
|
|
92
|
+
onStepFinish?: (event: {
|
|
93
|
+
step: StepInfo;
|
|
94
|
+
result: unknown;
|
|
95
|
+
duration: number;
|
|
96
|
+
}) => void | Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* A `flowAgent` factory with custom steps merged into `$`.
|
|
101
|
+
*
|
|
102
|
+
* @typeParam TCustomSteps - The custom step definitions map.
|
|
103
|
+
*/
|
|
104
|
+
export type FlowFactory<TCustomSteps extends CustomStepDefinitions> = <TInput, TOutput>(
|
|
105
|
+
config: FlowAgentConfigWithOutput<TInput, TOutput>,
|
|
106
|
+
handler: (params: {
|
|
107
|
+
input: TInput;
|
|
108
|
+
$: StepBuilder & TypedCustomSteps<TCustomSteps>;
|
|
109
|
+
log: Logger;
|
|
110
|
+
}) => Promise<TOutput>,
|
|
111
|
+
) => FlowAgent<TInput, TOutput>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Wrap a hook callback so it can be passed to `fireHooks`.
|
|
115
|
+
*
|
|
116
|
+
* Generic over `TEvent` so the hook is called with the correct
|
|
117
|
+
* event type without resorting to `any`.
|
|
118
|
+
*/
|
|
119
|
+
function createHookCaller<TEvent>(
|
|
120
|
+
hook: ((event: TEvent) => void | Promise<void>) | undefined,
|
|
121
|
+
event: TEvent,
|
|
122
|
+
): (() => void | Promise<void>) | undefined {
|
|
123
|
+
if (hook) {
|
|
124
|
+
return () => hook(event);
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Build a merged hook that runs engine and flow agent hooks sequentially.
|
|
131
|
+
*
|
|
132
|
+
* The `(event: never)` constraint is the widest function type under
|
|
133
|
+
* strict mode — any single-argument function is assignable via
|
|
134
|
+
* contravariance (`never extends T` for all `T`).
|
|
135
|
+
*/
|
|
136
|
+
function buildMergedHook<THook extends (event: never) => void | Promise<void>>(
|
|
137
|
+
log: Logger,
|
|
138
|
+
engineHook: THook | undefined,
|
|
139
|
+
flowHook: THook | undefined,
|
|
140
|
+
): THook | undefined {
|
|
141
|
+
if (!engineHook && !flowHook) {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const merged = async (event: unknown): Promise<void> => {
|
|
146
|
+
const engineFn = createHookCaller(
|
|
147
|
+
engineHook as ((event: unknown) => void | Promise<void>) | undefined,
|
|
148
|
+
event,
|
|
149
|
+
);
|
|
150
|
+
const flowFn = createHookCaller(
|
|
151
|
+
flowHook as ((event: unknown) => void | Promise<void>) | undefined,
|
|
152
|
+
event,
|
|
153
|
+
);
|
|
154
|
+
await fireHooks(log, engineFn, flowFn);
|
|
155
|
+
};
|
|
156
|
+
return merged as unknown as THook;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Built-in StepBuilder method names that custom steps must not shadow.
|
|
161
|
+
*
|
|
162
|
+
* @private
|
|
163
|
+
*/
|
|
164
|
+
const RESERVED_STEP_NAMES: ReadonlySet<string> = new Set([
|
|
165
|
+
"step",
|
|
166
|
+
"agent",
|
|
167
|
+
"map",
|
|
168
|
+
"each",
|
|
169
|
+
"reduce",
|
|
170
|
+
"while",
|
|
171
|
+
"all",
|
|
172
|
+
"race",
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Create a custom flow engine with additional step types
|
|
177
|
+
* and/or default hooks.
|
|
178
|
+
*
|
|
179
|
+
* Returns a `flowAgent()`-like factory. Any custom steps defined
|
|
180
|
+
* in `$` are merged into the handler's `$` parameter and fully typed.
|
|
181
|
+
*
|
|
182
|
+
* @typeParam TCustomSteps - The custom step definitions map.
|
|
183
|
+
* @param config - Engine configuration including custom steps
|
|
184
|
+
* and default hooks.
|
|
185
|
+
* @returns A `FlowFactory` that creates flow agents with custom
|
|
186
|
+
* `$` steps and engine-level default hooks.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* const engine = createFlowEngine({
|
|
191
|
+
* $: {
|
|
192
|
+
* retry: async ({ ctx, config }) => {
|
|
193
|
+
* let lastError: Error | undefined
|
|
194
|
+
* for (let attempt = 0; attempt < config.attempts; attempt++) {
|
|
195
|
+
* try {
|
|
196
|
+
* return await config.execute({ attempt })
|
|
197
|
+
* } catch (err) {
|
|
198
|
+
* lastError = err as Error
|
|
199
|
+
* }
|
|
200
|
+
* }
|
|
201
|
+
* throw lastError
|
|
202
|
+
* },
|
|
203
|
+
* },
|
|
204
|
+
* onStart: ({ input }) => telemetry.trackStart(input),
|
|
205
|
+
* })
|
|
206
|
+
*
|
|
207
|
+
* const myFlow = engine({
|
|
208
|
+
* name: 'my-flow',
|
|
209
|
+
* input: MyInput,
|
|
210
|
+
* output: MyOutput,
|
|
211
|
+
* }, async ({ input, $ }) => {
|
|
212
|
+
* const data = await $.retry({
|
|
213
|
+
* attempts: 3,
|
|
214
|
+
* execute: async () => fetch('https://api.example.com/data'),
|
|
215
|
+
* })
|
|
216
|
+
* return data
|
|
217
|
+
* })
|
|
218
|
+
* ```
|
|
219
|
+
*/
|
|
220
|
+
export function createFlowEngine<
|
|
221
|
+
TCustomSteps extends CustomStepDefinitions = Record<string, never>,
|
|
222
|
+
>(engineConfig: FlowEngineConfig<TCustomSteps>): FlowFactory<TCustomSteps> {
|
|
223
|
+
// Validate custom step names at engine creation time
|
|
224
|
+
for (const name of Object.keys(engineConfig.$ ?? {})) {
|
|
225
|
+
if (RESERVED_STEP_NAMES.has(name)) {
|
|
226
|
+
throw new Error(`Custom step "${name}" conflicts with a built-in StepBuilder method`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return function engineCreateFlowAgent<TInput, TOutput>(
|
|
231
|
+
flowConfig: FlowAgentConfigWithOutput<TInput, TOutput>,
|
|
232
|
+
handler: (params: {
|
|
233
|
+
input: TInput;
|
|
234
|
+
$: StepBuilder & TypedCustomSteps<TCustomSteps>;
|
|
235
|
+
log: Logger;
|
|
236
|
+
}) => Promise<TOutput>,
|
|
237
|
+
): FlowAgent<TInput, TOutput> {
|
|
238
|
+
const hookLog = (flowConfig.logger ?? createDefaultLogger()).child({ source: "engine" });
|
|
239
|
+
|
|
240
|
+
const { onStart: engineOnStart } = engineConfig;
|
|
241
|
+
const { onStart: flowOnStart } = flowConfig;
|
|
242
|
+
const { onFinish: engineOnFinish } = engineConfig;
|
|
243
|
+
const { onFinish: flowOnFinish } = flowConfig;
|
|
244
|
+
const { onError: engineOnError } = engineConfig;
|
|
245
|
+
const { onError: flowOnError } = flowConfig;
|
|
246
|
+
const { onStepStart: engineOnStepStart } = engineConfig;
|
|
247
|
+
const { onStepStart: flowOnStepStart } = flowConfig;
|
|
248
|
+
const { onStepFinish: engineOnStepFinish } = engineConfig;
|
|
249
|
+
const { onStepFinish: flowOnStepFinish } = flowConfig;
|
|
250
|
+
|
|
251
|
+
const mergedConfig: FlowAgentConfigWithOutput<TInput, TOutput> = {
|
|
252
|
+
...flowConfig,
|
|
253
|
+
onStart: buildMergedHook(hookLog, engineOnStart, flowOnStart),
|
|
254
|
+
onFinish: buildMergedHook(hookLog, engineOnFinish, flowOnFinish),
|
|
255
|
+
onError: buildMergedHook(hookLog, engineOnError, flowOnError),
|
|
256
|
+
onStepStart: buildMergedHook(hookLog, engineOnStepStart, flowOnStepStart),
|
|
257
|
+
onStepFinish: buildMergedHook(hookLog, engineOnStepFinish, flowOnStepFinish),
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const wrappedHandler: FlowAgentHandler<TInput, TOutput> = async (params) => {
|
|
261
|
+
return handler({
|
|
262
|
+
input: params.input,
|
|
263
|
+
$: params.$ as StepBuilder & TypedCustomSteps<TCustomSteps>,
|
|
264
|
+
log: params.log,
|
|
265
|
+
});
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
return flowAgent(mergedConfig, wrappedHandler, {
|
|
269
|
+
augment$: ($, ctx) => {
|
|
270
|
+
const customSteps: Record<string, (config: unknown) => Promise<unknown>> = {};
|
|
271
|
+
|
|
272
|
+
for (const [name, factory] of Object.entries(engineConfig.$ ?? {})) {
|
|
273
|
+
// eslint-disable-next-line security/detect-object-injection -- Key from Object.entries iteration, not user input
|
|
274
|
+
customSteps[name] = (config: unknown) =>
|
|
275
|
+
factory({ ctx: { signal: ctx.signal, log: ctx.log }, config: config as never });
|
|
276
|
+
}
|
|
277
|
+
return { ...$, ...customSteps } as StepBuilder;
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
}
|