@faapi/faapi 6.30.0 → 6.32.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/dist/index.d.ts CHANGED
@@ -1,11 +1,8 @@
1
- import { A as AppRegistries, F as FaapiContext, T as TaskClient, L as LogConfig, a as TaskFailedHandler, b as TaskQueueDeps, c as TaskQueue, d as TaskDriver, e as TaskRegistry, f as TaskManifest, g as ToolMetadata, h as AgentCore, i as AgentMetadata, C as CreateLoggerOptions, j as Logger } from './contextTypes-DhagvRH_.js';
2
- export { k as AgentHandleFactory, l as AgentHandleStore, m as AgentPathMeta, n as AgentRegistry, o as AgentToolDescriptor, p as FaapiContextConfig, q as FaapiTaskMeta, r as FailOptions, s as LogEntry, t as LogLevel, u as LogSink, S as SkillRegistry, v as SseEvent, w as SseOptions, x as SseWriter, y as TaskContext, z as TaskDriverJob, B as TaskDriverProcess, D as TaskDriverRecord, E as TaskFailedInfo, G as TaskJob, H as TaskJobStatus, I as TaskMetadata, J as TaskModule, K as TaskRegistriesSnapshot, M as TaskRegistriesView, N as ToolCore, O as ToolPathMeta, P as ToolRegistry, Q as createAppRegistries, R as createTaskRegistriesView, U as createTaskRegistry } from './contextTypes-DhagvRH_.js';
3
- import { F as FaapiMiddleware, R as RouteManifest, C as CorsOptions, H as HelmetOptions, I as InjectorMap, W as WsRouteManifest } from './routeTypes-0rwuIws-.js';
4
- export { a as Injector, b as RouteInfo, c as RouteInputSchema, d as RouteOutputSchema, e as RouteParamSchema, f as cors, h as helmet } from './routeTypes-0rwuIws-.js';
5
- import * as node_http from 'node:http';
6
- import { Server, IncomingMessage, ServerResponse } from 'node:http';
7
- import { Socket } from 'node:net';
1
+ import { F as FaapiMiddleware, R as RouteManifest, W as WsRouteManifest, T as TaskQueueDeps, a as TaskQueue, b as TaskDriver, c as TaskRegistry, d as TaskManifest, A as AgentCore, e as AgentMetadata, f as ToolMetadata, g as FaapiContext, h as FaapiConfig, L as LogConfig, C as CreateLoggerOptions, i as Logger, j as AppRegistries, k as TaskClient } from './contextTypes-WKsf3cCE.js';
2
+ export { l as AgentConfig, m as AgentHandleFactory, n as AgentHandleStore, o as AgentPathMeta, p as AgentRegistry, q as AgentToolDescriptor, r as CorsOptions, s as FaapiContextConfig, t as FaapiPlugin, u as FaapiTaskMeta, v as FailOptions, H as HelmetOptions, I as Injector, w as InjectorMap, x as LifecycleContext, y as LifecycleHooks, z as LlmChannelStore, B as LlmComplete, D as LlmCompleteOptions, E as LlmConfig, G as LlmModelConfig, J as LogEntry, K as LogLevel, M as LogSink, P as PluginContext, N as PluginDeclaration, O as RequestHandler, Q as ResponseConfig, S as RouteInfo, U as RouteInputSchema, V as RouteOutputSchema, X as RouteParamSchema, Y as SkillRegistry, Z as SseEvent, _ as SseOptions, $ as SseWriter, a0 as TaskBullMqOptions, a1 as TaskConfig, a2 as TaskContext, a3 as TaskDriverJob, a4 as TaskDriverProcess, a5 as TaskDriverRecord, a6 as TaskFailedHandler, a7 as TaskFailedInfo, a8 as TaskJob, a9 as TaskJobStatus, aa as TaskMetadata, ab as TaskModule, ac as TaskPgBossOptions, ad as TaskRegistriesSnapshot, ae as TaskRegistriesView, af as ToolCore, ag as ToolPathMeta, ah as ToolRegistry, ai as UpgradeHandler, aj as cors, ak as createAppRegistries, al as createTaskRegistriesView, am as createTaskRegistry, an as helmet } from './contextTypes-WKsf3cCE.js';
8
3
  import ts from 'typescript';
4
+ import { Server } from 'node:http';
5
+ import 'node:net';
9
6
 
10
7
  type LoggerFn = (messageOrObj: string | Record<string, unknown>, message?: string) => void;
11
8
  interface LoggerOptions {
@@ -35,758 +32,6 @@ interface LoggerOptions {
35
32
  */
36
33
  declare function logger(options?: LoggerOptions): FaapiMiddleware;
37
34
 
38
- /** HTTP 请求 handler 类型 */
39
- type RequestHandler = (req: IncomingMessage, res: ServerResponse) => void;
40
- /** WebSocket 升级 handler 类型 */
41
- type UpgradeHandler = (req: IncomingMessage, socket: Socket, head: Buffer) => void;
42
- /**
43
- * 插件上下文:插件 setup 函数接收的框架能力
44
- *
45
- * 插件通过 ctx 访问路由、服务器实例等,不需要直接依赖框架内部模块。
46
- *
47
- * 插件可通过 `wrapHandler` / `wrapUpgradeHandler` 在 server.listen 之前包装请求处理逻辑,
48
- * 用于集成其他框架(如 Next.js):`/api/*` 走 faapi,其余走被集成框架。
49
- */
50
- interface PluginContext {
51
- /** 项目根目录 */
52
- rootDir: string;
53
- /** app 级注册表(tool/agent/skill/agentHandle 实例,随 app 生命周期) */
54
- registries: AppRegistries;
55
- /** 当前路由清单(setup 时的快照,reloadRoutes 后不会更新;需最新路由用 getRoutes()) */
56
- routes: RouteManifest;
57
- /** 获取最新路由清单(reloadRoutes 后返回更新后的数组) */
58
- getRoutes: () => RouteManifest;
59
- /** HTTP 服务器实例(未 listen) */
60
- server: Server;
61
- /** 自定义业务配置(faapi.config.ts 中的自定义 key) */
62
- config: Record<string, unknown>;
63
- /** 插件选项(来自声明中的 options 字段或元组第二个元素) */
64
- options?: unknown;
65
- /**
66
- * 注册 HTTP handler 包装函数(在 server.listen 之前应用,按注册顺序嵌套)
67
- *
68
- * 包装函数接收原始 handler,返回新的 handler。多个包装器按注册顺序嵌套:
69
- * finalHandler = wrap1(wrap2(originalHandler))
70
- *
71
- * 典型场景:集成 Next.js,`/api/*` 走 faapi,其余走 Next.js getRequestHandler。
72
- */
73
- wrapHandler?: (fn: (original: RequestHandler) => RequestHandler) => void;
74
- /**
75
- * 注册 WS upgrade handler 包装函数(在 server.listen 之前应用,按注册顺序嵌套)
76
- *
77
- * 包装函数接收原始 upgrade handler(可能为 undefined,表示 faapi 无 WS 路由),
78
- * 返回新的 upgrade handler。多个包装器按注册顺序嵌套。
79
- *
80
- * 典型场景:faapi WS 路由走 original,其余走 Next.js HMR。
81
- */
82
- wrapUpgradeHandler?: (fn: (original: UpgradeHandler | undefined) => UpgradeHandler) => void;
83
- }
84
- /**
85
- * faapi 插件接口
86
- *
87
- * 插件是一个对象,包含 name 和 setup 函数。
88
- * 框架在 server 创建后、listen 之前按声明顺序加载插件,调用 setup(ctx)。
89
- *
90
- * 插件可通过 ctx.wrapHandler / ctx.wrapUpgradeHandler 包装请求处理逻辑,
91
- * 用于集成其他框架(如 Next.js)。
92
- *
93
- * ```ts
94
- * import type { FaapiPlugin, PluginContext } from '@faapi/faapi';
95
- *
96
- * export default {
97
- * name: 'my-plugin',
98
- * setup(ctx: PluginContext) {
99
- * console.log(`Plugin loaded, ${ctx.routes.length} routes found`);
100
- * },
101
- * } satisfies FaapiPlugin;
102
- * ```
103
- */
104
- interface FaapiPlugin {
105
- /** 插件名称(用于去重和日志) */
106
- name: string;
107
- /** 插件初始化函数,在 server 创建后、listen 之前调用 */
108
- setup: (ctx: PluginContext) => Promise<void> | void;
109
- }
110
- /**
111
- * 插件声明:用户在 faapi.config.ts 的 plugins 字段中使用
112
- *
113
- * 支持三种形式:
114
- * - 包名字符串:`'@faapi/schema'`
115
- * - 带选项的元组:`['@faapi/schema', { stdio: true }]`
116
- * - 完整声明对象:`{ package: '@faapi/schema', enable: true }`
117
- * - 本地路径:`{ path: './my-plugin' }`
118
- */
119
- type PluginDeclaration = string | [string, unknown] | {
120
- package: string;
121
- enable?: boolean;
122
- options?: unknown;
123
- } | {
124
- path: string;
125
- enable?: boolean;
126
- options?: unknown;
127
- };
128
-
129
- interface CompressionOptions {
130
- /**
131
- * 最小压缩字节数,body 低于该值不压缩(小 payload 压缩后反而变大)
132
- * @default 1024
133
- */
134
- threshold?: number;
135
- }
136
-
137
- interface EtagOptions {
138
- /**
139
- * 生成弱 ETag(`W/"<hash>"`)。弱校验器允许压缩等表示差异下的 304 协商,
140
- * 与 compression 中间件配合正确;强 ETag 需对每个表示(编码)单独生成
141
- * @default true
142
- */
143
- weak?: boolean;
144
- }
145
-
146
- interface Http2Options {
147
- key?: string;
148
- cert?: string;
149
- }
150
-
151
- /**
152
- * 生命周期钩子
153
- *
154
- * 执行时序:onBoot(.listen 调用前)→ server.listen → listen 回调内 onReady → 运行期 onError → 关闭时 onClose
155
- */
156
- interface LifecycleHooks {
157
- /**
158
- * 服务器 listen 之前调用(启动校验钩子)
159
- *
160
- * 时机:`app.listen()` 内、`server.listen` 调用之前——server 已创建但未监听
161
- * (`server.listening === false`),路由/tool/agent 清单已水合、插件已加载。
162
- *
163
- * 适合启动校验(环境变量、下游依赖可达性)、DB 迁移等**失败即不该暴露端口**的逻辑:
164
- * 钩子抛错 → `listen()` 以原始错误 reject,`server.listen` 不会被调用,端口不暴露。
165
- *
166
- * 与 onReady 的差异:onReady 在 listen 回调内执行,失败时端口已开,
167
- * 存在"接受连接但不服务"的窗口——启动校验请用 onBoot,资源初始化用 onReady。
168
- */
169
- onBoot?: (ctx: LifecycleContext) => Promise<void> | void;
170
- /** 服务器启动后调用(适合初始化数据库连接等) */
171
- onReady?: (ctx: LifecycleContext) => Promise<void> | void;
172
- /** 服务器关闭时调用(适合清理资源、优雅关闭) */
173
- onClose?: (ctx: LifecycleContext) => Promise<void> | void;
174
- /**
175
- * 请求错误已被处理为响应后调用(参考 Fastify onError 语义)
176
- *
177
- * 时机:handler 抛错 → 全局中间件 try/catch(若有) → 框架内置 formatErrorResponse 兜底
178
- * → 响应发出后 → onError 触发副作用
179
- *
180
- * 职责:日志上报、告警、链路追踪等副作用。**不修改、不替换已生成的响应**。
181
- * 自身抛错会被捕获并忽略,不影响响应已发送的事实。
182
- *
183
- * 与全局错误中间件的区别:
184
- * - 全局错误中间件:把 error 翻译成 Response(主入口,决定响应内容)
185
- * - onError:响应发出后的副作用(不能改响应)
186
- */
187
- onError?: (error: unknown, ctx: FaapiContext) => Promise<void> | void;
188
- }
189
- /**
190
- * pg-boss 驱动选项(透传给 @faapi/task-pgboss)
191
- *
192
- * 主包不依赖 pg-boss,这里只声明常用连接字段的透传形状;完整项见 pg-boss 文档
193
- * (ConstructorOptions)。
194
- */
195
- interface TaskPgBossOptions {
196
- /** PostgreSQL 连接串(如 `postgres://localhost:5432/app`) */
197
- connectionString?: string;
198
- /** 其余 pg-boss ConstructorOptions 字段原样透传 */
199
- [key: string]: unknown;
200
- }
201
- /**
202
- * BullMQ 驱动选项(透传给 @faapi/task-bullmq)
203
- */
204
- interface TaskBullMqOptions {
205
- /** Redis 连接配置(透传给 Queue / Worker 的 connection) */
206
- connection?: {
207
- host?: string;
208
- port?: number;
209
- password?: string;
210
- db?: number;
211
- [key: string]: unknown;
212
- };
213
- /** 队列名前缀(默认 `faapi`——同一 Redis 下多个 faapi 应用隔离用) */
214
- prefix?: string;
215
- }
216
- /**
217
- * 任务子系统配置
218
- *
219
- * 任务队列由持久化驱动承载(内置 memory 驱动已移除):存在任务清单
220
- * (`src/tasks/` 下的 task.ts)时必须显式配置 `driver`,否则启动报错;
221
- * 无任务清单的项目不加载驱动(零任务项目无需安装驱动子包)。
222
- */
223
- interface TaskConfig {
224
- /**
225
- * 队列驱动:'pgboss'(@faapi/task-pgboss,Postgres)| 'bullmq'(@faapi/task-bullmq,Redis)
226
- *
227
- * 有任务清单时必填;也可在编程式场景传入自定义 TaskDriver 实例
228
- */
229
- driver?: 'pgboss' | 'bullmq';
230
- /** `driver: 'pgboss'` 时的选项(透传给 @faapi/task-pgboss) */
231
- pgboss?: TaskPgBossOptions;
232
- /** `driver: 'bullmq'` 时的选项(透传给 @faapi/task-bullmq) */
233
- bullmq?: TaskBullMqOptions;
234
- /**
235
- * 是否启动任务队列(默认 true)
236
- *
237
- * 多实例部署时可在非 worker 节点设 `FAAPI_TASKS_DISABLED=1` 或 `task.enabled: false`,
238
- * API 节点照常入队(入队能力保留),但不消费执行。
239
- */
240
- enabled?: boolean;
241
- /** 优雅停机时等待在跑任务的最长时间(毫秒,默认 10000;超时 abort) */
242
- shutdownTimeoutMs?: number;
243
- /**
244
- * 任务执行失败/取消钩子——每次 process 抛错后触发(含将重试的失败),
245
- * `info.willRetry` 按任务 meta.retries 推算、`info.cancelled` 标记框架终止;
246
- * 用于告警/死信上报等副作用,自身抛错被忽略
247
- */
248
- onFailed?: TaskFailedHandler;
249
- }
250
- /**
251
- * 生命周期上下文
252
- */
253
- interface LifecycleContext {
254
- /** 项目根目录 */
255
- rootDir: string;
256
- /** 当前路由清单 */
257
- routes: RouteManifest;
258
- /** 服务器实例(onBoot 钩子触发时已创建但未监听,`listening === false`) */
259
- server: node_http.Server;
260
- /** app 级注册表——skill 等运行时动态注册路径(`registries.skill.upsert(...)`) */
261
- registries: AppRegistries;
262
- /** 任务客户端——onBoot/onReady 中投递异步任务(`tasks.enqueue(name, payload)`) */
263
- tasks: TaskClient;
264
- }
265
- /**
266
- * 统一响应包装配置
267
- *
268
- * 配置后,框架自动:
269
- * - 成功响应:handler return 非 Response 的值时,用 ok 函数包裹
270
- * - 错误响应:ctx.fail() 用 fail 函数包装 body
271
- *
272
- * 未配置 response 时,使用框架默认实现:
273
- * - ok: (data) => ({ data })
274
- * - fail: ({ status, code, message }) => 省略的字段不放入 error 对象
275
- *
276
- * ```ts
277
- * import type { FaapiConfig } from '@faapi/faapi';
278
- * export default {
279
- * response: {
280
- * // 自定义成功包装(默认 { data })
281
- * ok: (data) => ({ code: 0, data }),
282
- * // 自定义错误包装(默认 { error: { message, ...code?, ...status? } })
283
- * fail: ({ status, code, message }) => ({ error: { code, message } }),
284
- * },
285
- * } satisfies FaapiConfig;
286
- * ```
287
- */
288
- interface ResponseConfig {
289
- /**
290
- * 成功响应包装函数
291
- *
292
- * handler return 非 Response 的值时调用。
293
- * 默认: (data) => ({ data })
294
- */
295
- ok?: (data: unknown) => unknown;
296
- /**
297
- * 错误响应包装函数
298
- *
299
- * ctx.fail() 调用时使用,接收 { status?, code?, message }。
300
- * status 和 code 均可能为 undefined(用户调用 ctx.fail 时省略则不传),
301
- * 默认实现只把非 undefined 的字段放入 error 对象。
302
- */
303
- fail?: (error: {
304
- status?: number;
305
- code?: string;
306
- message: string;
307
- }) => unknown;
308
- }
309
- /**
310
- * model 级配置(Phase 3.5)
311
- *
312
- * 挂在 provider 下的单个 model 配置,model 特定字段透传给 LLM API
313
- * (覆盖 provider 级同名字段)。空对象 `{}` 表示用 provider 级默认。
314
- *
315
- * ```ts
316
- * models: {
317
- * 'gpt-4o': {}, // 用 provider 级默认
318
- * 'gpt-4o-mini': { temperature: 0.5 }, // 覆盖 temperature
319
- * }
320
- * ```
321
- */
322
- interface LlmModelConfig {
323
- [key: string]: unknown;
324
- }
325
- /**
326
- * LLM provider 配置(Phase 2.4,Phase 3.5 改为嵌套级联结构)
327
- *
328
- * 嵌套级联:provider 在外层,model 在 `models` 下挂多个。
329
- * provider 级字段(`apiKey` / `baseURL`)共享给所有 model;
330
- * model 级字段在 `models[modelName]` 里覆盖 provider 级同名字段。
331
- *
332
- * `config.agent.llms` 的 key 是 provider 名(如 `'openai'` / `'anthropic'`)。
333
- * 无全局默认 provider——每次 `agent.run/stream` 调用通过 `options.model`(llms key /
334
- * `provider/model` / 纯 model 名)或 `options.provider`(外部 provider)显式指定。
335
- *
336
- * 由 Phase 3.2 的 `@faapi/agent` 插件读取,调 `createProvider` 创建实例存 Map。
337
- *
338
- * ```ts
339
- * llms: {
340
- * openai: {
341
- * provider: 'openai',
342
- * apiKey: process.env.OPENAI_API_KEY,
343
- * baseURL: 'https://api.openai.com/v1',
344
- * models: { 'gpt-4o': {}, 'gpt-4o-mini': { temperature: 0.5 } },
345
- * },
346
- * anthropic: {
347
- * provider: 'anthropic',
348
- * apiKey: process.env.ANTHROPIC_API_KEY,
349
- * models: { 'claude-3-5-sonnet': {} },
350
- * },
351
- * }
352
- * ```
353
- */
354
- interface LlmConfig {
355
- /**
356
- * LLM 提供方标识(如 'openai' / 'anthropic')
357
- *
358
- * Phase 3.2 的 provider 模块按此值选择对应的 LLM 适配器。
359
- */
360
- provider: string;
361
- /**
362
- * API key(从 `process.env` 读取,避免硬编码)
363
- *
364
- * 如 `process.env.OPENAI_API_KEY`。
365
- */
366
- apiKey?: string;
367
- /**
368
- * API 基础 URL(可选,用于 OpenAI 兼容 API 如 Azure OpenAI / 中转服务)
369
- *
370
- * 未设置时用 provider 对应的官方默认值(如 'https://api.openai.com/v1')。
371
- */
372
- baseURL?: string;
373
- /**
374
- * 该 provider 下挂的 model 列表(key 是 model 名)
375
- *
376
- * handler 通过 `agent.run(input, { model: 'gpt-4o' })` 切换 model,
377
- * 框架按 model 名在所有 provider 的 `models` 里查找定位 provider(详见
378
- * [agentHandle](../../agent/src/agentHandle.md) 的 Run-level 覆盖优先级表)。
379
- * model 级字段(如 `temperature`)覆盖 provider 级同名字段。
380
- */
381
- models: Record<string, LlmModelConfig>;
382
- /**
383
- * LLM 请求超时(毫秒,可选——未设置时无超时)
384
- *
385
- * provider 层用 `AbortSignal.timeout` 实现,与 run-level 的 `signal` 组合生效。
386
- * 超时触发抛 `LLMProviderError`(message 含 timed out),计入重试(429/5xx/网络错误同策略)。
387
- */
388
- timeoutMs?: number;
389
- /**
390
- * 429 / 5xx / 网络错误的最大重试次数(默认 2,设 0 关闭重试)
391
- *
392
- * 退避策略:优先尊重响应的 `Retry-After` 头(秒,封顶 30s),否则指数退避
393
- * 500ms * 2^attempt。4xx 其他状态(400/401 等)是确定性错误,不重试。
394
- * 流式请求仅在「连接建立前」重试,流开始输出后中断不重试。
395
- */
396
- maxRetries?: number;
397
- /**
398
- * 其他透传参数(provider 级,如 temperature / top_p / max_tokens)
399
- *
400
- * 这些字段原样传给 LLM API,由 provider 适配器处理。
401
- * model 级 `models[modelName]` 的同名字段优先。
402
- */
403
- [key: string]: unknown;
404
- }
405
- /**
406
- * agent 子系统全局配置(Phase 2.4,Phase 3.5 LLM 配置改为嵌套级联)
407
- *
408
- * 提供 agent 子系统的全局配置,所有字段均可选。
409
- * 无全局默认 agent / 默认 provider——`agent.run/stream` 每次调用必须显式传
410
- * `options.agent`(agent 名)和 `options.model` / `options.provider`(LLM 定位);
411
- * agent 自身 `config.maxTurns` / `config.model` 优先于全局配置,其中 `config.model`
412
- * 在调用未传 `options.model` 时作为缺省 key 参与 llms 解析。
413
- *
414
- * ```ts
415
- * import type { FaapiConfig } from '@faapi/faapi';
416
- * export default {
417
- * agent: {
418
- * llms: {
419
- * openai: {
420
- * provider: 'openai',
421
- * apiKey: process.env.OPENAI_API_KEY,
422
- * models: { 'gpt-4o': {}, 'gpt-4o-mini': { temperature: 0.5 } },
423
- * },
424
- * },
425
- * maxTurns: 10,
426
- * maxAgentDepth: 3,
427
- * },
428
- * } satisfies FaapiConfig;
429
- * ```
430
- *
431
- * 详见 `src/config/configTypes.md` agent 配置块章节。
432
- */
433
- interface AgentConfig {
434
- /**
435
- * LLM provider 配置映射(Phase 3.5 改为嵌套级联结构,key 是 provider 名)
436
- *
437
- * 值是 [LlmConfig](含 `models`)。plugin setup 时遍历每个 LlmConfig 调
438
- * `createProvider` 创建实例存 Map,handler 通过 `agent.run(input, { model })`
439
- * 切换 provider + model(详见 [agentHandle](../../agent/src/agentHandle.md))。
440
- *
441
- * 可选——未设置时插件仍注册 agent handle 工厂(外部 provider 模式),
442
- * `agent.run/stream` 需通过 `options.provider` 传入外部 provider 才能调用 LLM。
443
- */
444
- llms?: Record<string, LlmConfig>;
445
- /**
446
- * 默认最大对话轮数(覆盖 agent 自身 `config.maxTurns`,agent 自身配置优先)
447
- *
448
- * Phase 3.3 的 reactLoop 使用此值作为递归深度防护。
449
- */
450
- maxTurns?: number;
451
- /**
452
- * agent 调用 agent 的最大递归深度(防护无限递归,Phase 3.3 reactLoop 使用)
453
- *
454
- * 默认值由 Phase 3.x 的 @faapi/agent 插件定义(如 3)。
455
- */
456
- maxAgentDepth?: number;
457
- /**
458
- * 启用 tracing 的全局默认值(默认 false——opt-in,不开启零开销)
459
- *
460
- * 开启时 `agent.run()` / `agent.stream()` 返回的 `result.trace` /
461
- * `chunk.traceEvent` 填充结构化调用明细(按轮次组织的 LLM 调用、tool 调用、
462
- * sub-agent 嵌套调用事件,含 timing 与 token 用量)。
463
- *
464
- * 三层覆盖优先级:`AgentRunOptions.enableTracing` > agent 自身配置 >
465
- * 此全局配置 > 默认 `false`。
466
- *
467
- * tracing 采集每轮 LLM 消息快照与 tool 明细,有真实内存/CPU 开销——
468
- * 需要观测的端点显式开启:
469
- *
470
- * ```ts
471
- * import type { FaapiConfig } from '@faapi/faapi';
472
- * export default {
473
- * agent: {
474
- * enableTracing: true, // 全局开启;单次调用可用 run(input, { enableTracing: true }) 覆盖
475
- * llms: { openai: { provider: 'openai', apiKey: '...', models: { 'gpt-4o': {} } } },
476
- * },
477
- * } satisfies FaapiConfig;
478
- * ```
479
- *
480
- * 详见 `@faapi/agent` 的 [trace](../../agent/src/trace.md) 文档。
481
- */
482
- enableTracing?: boolean;
483
- /**
484
- * 发送给 LLM 的历史 token 预算(近似估算,未设置 = 不裁剪)
485
- *
486
- * 多轮 tool 循环中对话历史只增不减,大 tool 结果会撑爆模型上下文窗口导致
487
- * 下一轮 400。超预算时从最旧的轮组开始裁剪(system 与初始 user 保留、
488
- * tool 配对不拆散),只作用于发给 LLM 的消息副本。详见 @faapi/agent 的
489
- * reactLoop 文档历史裁剪章节。
490
- */
491
- maxHistoryTokens?: number;
492
- /**
493
- * 执行守卫(authHooks,见 @faapi/agent 的 authHooks 文档)
494
- *
495
- * 每次 tool / sub-agent 执行前调用(`agent-x` 派发名称为 sub-agent 递归)。
496
- * 三种返回:`void` 放行;`{ error }` 拒绝(不执行,error 回传 LLM 调整策略);
497
- * `{ args }` 改写后放行(多租户场景强制注入可信值,不信 LLM 传入的标识参数)。
498
- *
499
- * ctx 为请求上下文透传(`Partial<FaapiContext>`,框架零读取):HTTP 请求是完整
500
- * ctx,任务内组装 Agent 时业务方显式传窄对象(如鉴权硬闸需要的
501
- * `{ currentUserId }`),编程式直调为 undefined。
502
- *
503
- * 典型用法:中间件解析 `ctx.workspace` 后在此校验/强制改写 `args.workspaceId`。
504
- */
505
- beforeToolCall?: (name: string, args: Record<string, unknown>, ctx: Partial<FaapiContext> | undefined) => void | {
506
- error: string;
507
- } | {
508
- args: Record<string, unknown>;
509
- };
510
- /**
511
- * 审计钩子(authHooks):tool / sub-agent 成功返回后调用,返回值忽略。
512
- * 用于日志/审计/计量;异常路径不调用。
513
- */
514
- afterToolCall?: (name: string, args: Record<string, unknown>, result: unknown, ctx: Partial<FaapiContext> | undefined) => void;
515
- /**
516
- * 可见性过滤(authHooks):LLM 可见 tools 清单组装完成后调用,
517
- * 返回过滤后的数组(含 agent-as-tool 项)。每次 agent.run / stream 生效——
518
- * 无权 tool 不进 LLM 视野,比执行时拒绝省一轮 LLM 调用。
519
- *
520
- * tools 为 OpenAI chat completions 规范形(`type: 'function'` +
521
- * `function: { name, description?, parameters? }`),按 `tool.function.name` 过滤。
522
- */
523
- filterTools?: (tools: Array<{
524
- type: 'function';
525
- function: {
526
- name: string;
527
- description?: string;
528
- parameters?: Record<string, unknown>;
529
- };
530
- }>, ctx: Partial<FaapiContext> | undefined) => Array<{
531
- type: 'function';
532
- function: {
533
- name: string;
534
- description?: string;
535
- parameters?: Record<string, unknown>;
536
- };
537
- }>;
538
- }
539
- /**
540
- * faapi 配置文件类型
541
- *
542
- * 在项目根目录创建 faapi.config.ts:
543
- * ```ts
544
- * import type { FaapiConfig } from '@faapi/faapi';
545
- * export default {
546
- * cors: { origin: '*' },
547
- * } satisfies FaapiConfig;
548
- * ```
549
- *
550
- * 自定义业务配置(任意 key):
551
- * ```ts
552
- * import type { FaapiConfig } from '@faapi/faapi';
553
- * export default {
554
- * cors: { origin: '*' },
555
- * // 通过 process.env.XXX 读取 .env 文件加载的环境变量
556
- * db: { host: process.env.DB_HOST ?? 'localhost', port: 5432 },
557
- * } satisfies FaapiConfig;
558
- * ```
559
- *
560
- * 多环境差异通过 `.env` 系列文件实现(见 `loadEnv`):
561
- * - `.env` / `.env.local` / `.env.{env}` / `.env.{env}.local`
562
- * - 环境由 `NODE_ENV > 'development'` 决定
563
- *
564
- * 框架元信息通过环境变量配置(不放在 config 内):
565
- * - `PORT`:服务端口,默认 3000
566
- * - `FAAPI_DIST`:产物输出目录,dev 固定为 `.faapi`(不可修改),prod 默认为 `dist`(可通过 `--dist` 修改)
567
- */
568
- interface FaapiConfig {
569
- /** CORS 配置,false 禁用 */
570
- cors?: CorsOptions | boolean;
571
- /** 生命周期钩子 */
572
- lifecycle?: LifecycleHooks;
573
- /** 安全头配置,false 禁用 */
574
- helmet?: HelmetOptions | boolean;
575
- /**
576
- * 响应压缩(gzip/deflate/br 协商),默认关闭。
577
- * Vary: Accept-Encoding 自动附加;SSE/流式响应跳过,详见 middleware/compression.md
578
- */
579
- compression?: CompressionOptions | boolean;
580
- /**
581
- * ETag/304 条件请求协商(GET/HEAD 2xx 弱 ETag),默认关闭。
582
- * handler 显式 ctx.setETag() 时不覆盖,详见 middleware/etag.md
583
- */
584
- etag?: EtagOptions | boolean;
585
- /** 请求体大小限制(字节),默认 10MB(10 * 1024 * 1024) */
586
- bodyLimit?: number;
587
- /**
588
- * 日志全局配置——唯一日志配置入口,业务日志与请求日志同管道(egg 模型,
589
- * 详见 logger/logger.md;`config.logger` 独立配置已废除)
590
- *
591
- * - `false`:全部静默(含 error 与请求日志,测试降噪)
592
- * - `true` / 缺省:console 输出(consoleLevel 默认 'info'),管道不过滤
593
- * - `LogConfig`:`dir` egg 风格文件输出(app.log 全量 + error.log 仅 error,
594
- * splitByLevel 按级别四文件)或 `sink` 自定义管道接管(接 pino/winston),
595
- * 两者互斥;`level` 管道阈值(不配不过滤)、`consoleLevel` console 出口阈值
596
- * (不配 'info',false 关 console);请求日志无条件并入(`accessLog: false` 关闭)
597
- *
598
- * 生效范围:`ctx.log` / 参数注入 `log` / `createLogger` / `taskCtx.log` /
599
- * 请求日志中间件。日志全局配置是进程级资源,多 app 同进程时后启动覆盖先启动。
600
- *
601
- * ```ts
602
- * export default {
603
- * log: {
604
- * // 方式一:egg 风格文件输出(请求日志自动并入)
605
- * dir: 'logs',
606
- * // 方式二:自定义管道接管
607
- * // sink: (entry) => pinoLogger[entry.level]({ scope: entry.scope, ...entry.fields }, entry.message),
608
- * },
609
- * } satisfies FaapiConfig;
610
- * ```
611
- */
612
- log?: LogConfig | boolean;
613
- /** HTTP/2 配置,false 禁用(默认 http/1.1) */
614
- http2?: Http2Options | boolean;
615
- /**
616
- * 是否信任反向代理头(X-Forwarded-For),默认 false
617
- *
618
- * - `true`:`ctx.ip` 取 `x-forwarded-for` 第一个 IP——部署在 nginx/CDN 等受信任
619
- * 反向代理之后时开启
620
- * - `false`(默认):直取 socket 地址。客户端直连时 XFF 可被任意伪造,
621
- * 安全默认不信任(同时影响 HTTP 与 WS 握手的 `ctx.ip`)
622
- */
623
- trustedProxy?: boolean;
624
- /**
625
- * 统一响应包装配置
626
- *
627
- * 配置后,框架自动包裹 handler 返回值:
628
- * - 成功响应:handler return 非 Response → 用 ok 函数包裹(默认 `{ data }`)
629
- * - 错误响应:ctx.fail() 用 fail 函数包装(默认 `{ error: { message, ...code? } }`)
630
- *
631
- * 未配置 response 时,使用框架默认实现(见 ResponseConfig)。
632
- * 配置 response 后,ok/fail 各字段均可选,按需覆盖。
633
- *
634
- * ```ts
635
- * import type { FaapiConfig } from '@faapi/faapi';
636
- * export default {
637
- * response: {
638
- * ok: (data) => ({ code: 0, data }),
639
- * fail: ({ status, code, message }) => ({ error: { code, message } }),
640
- * },
641
- * } satisfies FaapiConfig;
642
- * ```
643
- *
644
- * 详见 `src/config/configTypes.md` 统一响应包装章节。
645
- */
646
- response?: ResponseConfig;
647
- /**
648
- * 全局中间件:对所有路由(HTTP + WebSocket 握手)生效
649
- *
650
- * 执行顺序:全局中间件在最外层,目录中间件在内层,handler 最内层。
651
- * 全局中间件拦截(返回 Response)则目录中间件和 handler 不执行。
652
- * 全局中间件塞入 ctx 的值,目录中间件和 handler 可读取。
653
- *
654
- * 与 CORS 的关系:CORS 由 `cors` 字段配置,全局中间件在 CORS 之后执行。
655
- *
656
- * ```ts
657
- * import type { FaapiConfig, FaapiMiddleware } from '@faapi/faapi';
658
- *
659
- * const requestId: FaapiMiddleware = async (ctx, next) => {
660
- * ctx.requestId = crypto.randomUUID();
661
- * await next();
662
- * };
663
- *
664
- * export default {
665
- * middlewares: [requestId],
666
- * } satisfies FaapiConfig;
667
- * ```
668
- *
669
- * 详见 `src/middleware/README.md` 全局中间件章节。
670
- */
671
- middlewares?: FaapiMiddleware[];
672
- /**
673
- * 全局注入器:对所有路由的 handler 参数注入生效
674
- *
675
- * 合并规则:`{ ...全局注入器, ...目录注入器 }`,目录注入器覆盖全局同名。
676
- * 全局注入器独立于中间件链,仅提供依赖(db、redis 等),不参与请求流程。
677
- *
678
- * ```ts
679
- * import type { FaapiConfig, InjectorMap } from '@faapi/faapi';
680
- *
681
- * export default {
682
- * injectors: {
683
- * db: () => getDbConnection(),
684
- * redis: () => getRedis(),
685
- * },
686
- * } satisfies FaapiConfig;
687
- * ```
688
- *
689
- * 详见 `src/middleware/README.md` 全局注入器章节。
690
- */
691
- injectors?: InjectorMap;
692
- /**
693
- * 插件:应用级扩展,在 server 启动后、onReady 之前按声明顺序加载
694
- *
695
- * 与中间件的区别:中间件拦截每个请求,插件在启动时初始化(如启动后台服务、注册协议等)
696
- *
697
- * ```ts
698
- * import type { FaapiConfig } from '@faapi/faapi';
699
- * export default {
700
- * plugins: [
701
- * '@faapi/schema', // 包名
702
- * ['@faapi/schema', { stdio: true }], // 带选项
703
- * { package: '@faapi/schema', enable: true }, // 完整声明
704
- * { path: './my-plugin' }, // 本地路径
705
- * ],
706
- * } satisfies FaapiConfig;
707
- * ```
708
- */
709
- plugins?: PluginDeclaration[];
710
- /**
711
- * agent 子系统全局配置(Phase 2.4)
712
- *
713
- * 提供 agent 子系统的全局配置:LLM 提供方、最大对话轮数、
714
- * agent 调用 agent 的最大递归深度。
715
- *
716
- * 无全局默认 agent / 默认 provider——`agent.run/stream` 每次调用显式传
717
- * `options.agent` + `options.model` / `options.provider`。
718
- * agent 自身 `config.maxTurns` / `config.model` 优先于全局配置。
719
- * tool 引用列表只在每个 agent 自身的 `config.tools` 里声明(无全局共享 defaultTools)。
720
- *
721
- * ```ts
722
- * import type { FaapiConfig } from '@faapi/faapi';
723
- * export default {
724
- * agent: {
725
- * llms: {
726
- * openai: {
727
- * provider: 'openai',
728
- * apiKey: process.env.OPENAI_API_KEY,
729
- * models: { 'gpt-4o': {} },
730
- * },
731
- * },
732
- * maxTurns: 10,
733
- * maxAgentDepth: 3,
734
- * },
735
- * } satisfies FaapiConfig;
736
- * ```
737
- *
738
- * 详见 `src/config/configTypes.md` agent 配置块章节。
739
- */
740
- agent?: AgentConfig;
741
- /**
742
- * 任务子系统全局配置(队列驱动、启停、停机超时)
743
- *
744
- * ```ts
745
- * import type { FaapiConfig } from '@faapi/faapi';
746
- * export default {
747
- * task: { enabled: true, shutdownTimeoutMs: 10_000 },
748
- * } satisfies FaapiConfig;
749
- * ```
750
- *
751
- * 详见 `src/task/README.md`。
752
- */
753
- task?: TaskConfig;
754
- /**
755
- * 扩展 ctx:在每次请求创建上下文后调用,可挂载自定义方法(如 ctx.xml、ctx.stream)
756
- *
757
- * 类型增强:用户通过 `declare module '@faapi/faapi'` 扩展 FaapiContext 接口获得类型提示
758
- *
759
- * ```ts
760
- * // faapi.config.ts
761
- * declare module '@faapi/faapi' {
762
- * interface FaapiContext {
763
- * xml(data: string): Response;
764
- * }
765
- * }
766
- * export default {
767
- * extendContext(ctx) {
768
- * ctx.xml = (data) => new Response(data, { headers: { 'Content-Type': 'application/xml' } });
769
- * },
770
- * } satisfies FaapiConfig;
771
- * ```
772
- */
773
- extendContext?: (ctx: FaapiContext) => void;
774
- /**
775
- * 自定义业务配置(任意 key)
776
- *
777
- * 用户可以在这里放数据库连接、Redis 配置等
778
- * 通过 ctx.config 访问
779
- *
780
- * ```ts
781
- * export default {
782
- * db: { host: 'localhost', port: 5432 },
783
- * redis: { host: '127.0.0.1', port: 6379 },
784
- * } satisfies FaapiConfig;
785
- * ```
786
- */
787
- [key: string]: unknown;
788
- }
789
-
790
35
  /**
791
36
  * WebSocket Handler 类型定义与 socket 封装
792
37
  *
@@ -1299,31 +544,44 @@ interface ToolSchemaModule {
1299
544
  * 计算 tool 的 zod.js 绝对路径(纯路径计算,无 fs 访问)
1300
545
  *
1301
546
  * 与 [loadToolSchema](./loadToolSchema.ts) 内部使用的路径逻辑同源(共享 `getDist()`),
547
+ /**
548
+ * zod.js 定位的最小来源结构——`ToolMetadata` 与 `AgentMetadata`(派发入参 schema
549
+ * 声明场景)均满足,加载器无需感知来源差异
550
+ */
551
+ interface SchemaSourceRef {
552
+ /** 源码/产物相对路径(与 zod.js 同级,推导 zod.js 路径用) */
553
+ filePath: string;
554
+ /** schema 类型名(`undefined` = 无 schema 声明) */
555
+ inputTypeName?: string;
556
+ }
557
+ /**
558
+ * 计算 zod.js 的绝对路径(纯路径计算,无 fs 访问)
559
+ *
560
+ * 与 [loadToolSchema](./loadToolSchema.ts) 内部使用的路径逻辑同源(共享 `getDist()`),
1302
561
  * 供 `@faapi/agent` 的跨请求 schema 缓存用作缓存键 + mtime 校验目标。
1303
562
  *
1304
- * @param tool tool 元数据(含 `filePath`)
1305
- * @param rootDir 项目根目录(`tool.filePath` 是相对路径时拼接)
563
+ * @param ref schema 来源元数据(tool / agent 均可,含 `filePath`)
564
+ * @param rootDir 项目根目录(`ref.filePath` 是相对路径时拼接)
1306
565
  */
1307
- declare function getToolSchemaPath(tool: ToolMetadata, rootDir?: string): string;
566
+ declare function getToolSchemaPath(ref: SchemaSourceRef, rootDir?: string): string;
1308
567
  /**
1309
- * 动态加载 tool 的 zod.js schema 模块
568
+ * 动态加载 zod.js schema 模块(tool input 与 agent 派发入参共用)
1310
569
  *
1311
570
  * 与 [loadToolModule](./loadToolModule.md) 对称——一个加载 handler.js(tool 函数),
1312
- * 一个加载 zod.js(tool schema)。
571
+ * 一个加载 zod.js(schema 模块)。tool 的 zod.js 与 handler.js 同级;agent 声明
572
+ * `Input` 时同样生成同级 zod.js(见 generateAgentArtifacts),同一加载器服务两类来源。
1313
573
  *
1314
574
  * 行为:
1315
- * - `tool.inputTypeName` 为 `undefined` → 返回 `undefined`(无 schema,用自由 schema)
1316
- * - zod.js 文件不存在 → 返回 `undefined`(schema 可选,缺失用自由 schema)
575
+ * - `ref.inputTypeName` 为 `undefined` → 返回 `undefined`(无 schema 声明)
576
+ * - zod.js 文件不存在 → 返回 `undefined`(schema 缺失,调用方按各自语义处理——
577
+ * tool 用自由 schema `{ type: 'object' }`;agent 派发入参在声明了 `inputTypeName`
578
+ * 时视为产物异常,由 `@faapi/agent` 侧显式抛错)
1317
579
  * - import 失败 / 导出名不匹配 → 返回 `undefined`
1318
580
  *
1319
- * 与 route schema 不同(route schema 缺失抛 `InternalError`),tool schema 是可选的——
1320
- * `@faapi/agent` 的 `resolveToolSchema` 未提供时用自由 schema `{ type: 'object' }`,
1321
- * LLM 自由传参,handler 内部自行处理参数合法性。
1322
- *
1323
- * @param tool tool 元数据(含 `filePath` + `inputTypeName`)
1324
- * @param rootDir 项目根目录(用于计算 zod.js 绝对路径,`tool.filePath` 是相对路径时拼接)
581
+ * @param ref schema 来源元数据(tool / agent 均可,含 `filePath` + `inputTypeName`)
582
+ * @param rootDir 项目根目录(用于计算 zod.js 绝对路径,`ref.filePath` 是相对路径时拼接)
1325
583
  */
1326
- declare function loadToolSchema(tool: ToolMetadata, rootDir?: string): Promise<ToolSchemaModule | undefined>;
584
+ declare function loadToolSchema(ref: SchemaSourceRef, rootDir?: string): Promise<ToolSchemaModule | undefined>;
1327
585
 
1328
586
  /**
1329
587
  * 按名查找单个 agent 的 LLM 可见元数据(默认实例)
@@ -1768,4 +1026,4 @@ type ProdApp = AppBase;
1768
1026
  */
1769
1027
  declare function createProdApp(options?: CreateAppOptions): Promise<ProdApp>;
1770
1028
 
1771
- export { type AgentConfig, AgentCore, AgentMetadata, type ProdApp as App, AppRegistries, CorsOptions, type CreateAppOptions, CreateLoggerOptions, type CronScheduler, type DevApp, type FaapiConfig, FaapiContext, FaapiError, FaapiMiddleware, type FaapiPlugin, type HandlerTypeInfo, HelmetOptions, type InjectOptions, type InjectResponse, InjectorMap, InternalError, LLM_TOOL_NAME_PATTERN, type LifecycleContext, type LifecycleHooks, type LlmConfig, type LlmModelConfig, LogConfig, Logger, type LoggerOptions, MethodNotAllowedError, ModuleLoadError, type PluginContext, type PluginDeclaration, type ProdApp, type PropertyType, type RequestHandler, type ResponseConfig, RouteManifest, RouteNotFoundError, type RouteSchemaSource, type RuntimeType, SUB_AGENT_TOOL_PREFIX, SchemaExtractionError, TASK_PATTERNS, type TaskBullMqOptions, TaskClient, type TaskConfig, TaskDriver, TaskFailedHandler, TaskManifest, type TaskPgBossOptions, TaskQueue, TaskRegistry, ToolMetadata, type ToolModule, type ToolSchemaModule, type TypeConstraint, type UpgradeHandler, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, clearAgentHandleFactory, collectRouteSchemaSources, configureLogging, createProdApp as createApp, createCronScheduler, createDevApp, createLogger, createProdApp, createProgram, createPrograms, createTaskQueue, extractTypeInfo, flushLogging, getAgent, getAgentEntry, getApp, getInputTypeForMethod, getSkill, getTool, getToolSchemaPath, hydrateSkillRegistry, invalidateProgramCache, listSkills, loadConfig, loadEnv, loadTaskDriver, loadToolModule, loadToolSchema, logger, readResource, registerAgentHandleFactory, removeSkill, resolveAgentTools, resolveSubAgents, resolveTypeNode, scanTasks, subAgentToolName, upsertSkill };
1029
+ export { AgentCore, AgentMetadata, type ProdApp as App, AppRegistries, type CreateAppOptions, CreateLoggerOptions, type CronScheduler, type DevApp, FaapiConfig, FaapiContext, FaapiError, FaapiMiddleware, type HandlerTypeInfo, type InjectOptions, type InjectResponse, InternalError, LLM_TOOL_NAME_PATTERN, LogConfig, Logger, type LoggerOptions, MethodNotAllowedError, ModuleLoadError, type ProdApp, type PropertyType, RouteManifest, RouteNotFoundError, type RouteSchemaSource, type RuntimeType, SUB_AGENT_TOOL_PREFIX, SchemaExtractionError, type SchemaSourceRef, TASK_PATTERNS, TaskClient, TaskDriver, TaskManifest, TaskQueue, TaskRegistry, ToolMetadata, type ToolModule, type ToolSchemaModule, type TypeConstraint, ValidationError, type ValidationErrorCode, type ValidationIssue, type WsContext, type WsEventHandlers, type WsHandler, type WsSocket, clearAgentHandleFactory, collectRouteSchemaSources, configureLogging, createProdApp as createApp, createCronScheduler, createDevApp, createLogger, createProdApp, createProgram, createPrograms, createTaskQueue, extractTypeInfo, flushLogging, getAgent, getAgentEntry, getApp, getInputTypeForMethod, getSkill, getTool, getToolSchemaPath, hydrateSkillRegistry, invalidateProgramCache, listSkills, loadConfig, loadEnv, loadTaskDriver, loadToolModule, loadToolSchema, logger, readResource, registerAgentHandleFactory, removeSkill, resolveAgentTools, resolveSubAgents, resolveTypeNode, scanTasks, subAgentToolName, upsertSkill };