@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,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
+ }