@faapi/faapi 3.2.1 → 4.0.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.
@@ -72,6 +72,217 @@ interface SseWriter {
72
72
  readonly response: Response;
73
73
  }
74
74
 
75
+ /**
76
+ * Tool 的 LLM 可见核心字段
77
+ *
78
+ * 描述"tool 是什么"——LLM 真正需要消费的字段(发往 LLM 的 tool 定义只含
79
+ * `name` / `description` / input schema),**不含**代码本体加载细节
80
+ * (`filePath` / `functionName` / `inputTypeName`)。
81
+ *
82
+ * 与 [AgentCore](./extractAgentMetadata.md) 对称——LLM-facing 字段与代码加载
83
+ * 细节分离,便于未来扩展(如 DB-driven tool 只实现 `ToolCore` 即可)。
84
+ *
85
+ * `toolRegistry` 查询入口 / `@faapi/agent` 子包的 `buildToolDefinitions`
86
+ * 都消费 `ToolCore` 字段组装 LLM tool 列表。
87
+ */
88
+ interface ToolCore {
89
+ /** tool 名(`@tool` JSDoc 覆盖值 或 路径推导值) */
90
+ name: string;
91
+ /** JSDoc 描述(tool 描述,对 LLM 可见),无 JSDoc 或 JSDoc 无自由文本时为 `undefined` */
92
+ description?: string;
93
+ }
94
+ /**
95
+ * Tool 完整元数据(文件型 tool)
96
+ *
97
+ * 继承 [ToolCore](./extractToolMetadata.md) 的 LLM 字段,额外扩展**代码本体加载细节**:
98
+ * - `filePath` — `loadToolModule` 加载 `handler.js` 产物定位函数用
99
+ * - `functionName` — 源码导出函数名(不受 `@tool` 覆盖影响,AST 定位 + 运行时 resolveExport 用)
100
+ * - `inputTypeName` — 第一个参数的 TypeReference 名(供 [extractTypeInfo](./extractHandlerTypes.md)
101
+ * 生成 zod schema;运行时 `resolveToolSchema` 据此定位 `zod.js`)
102
+ *
103
+ * 由 [extractToolMetadata](./extractToolMetadata.md) 产出,合并路径推导字段
104
+ * (来自 [scanTools](../tools/scanTools.md) 的 `ToolManifest`)与 AST 提取字段
105
+ * (JSDoc 描述、`@tool` 覆盖名、第一个参数 interface 名)。
106
+ *
107
+ * 字段来源:
108
+ * - `name` — `@tool` JSDoc 覆盖值,或 `pathMeta.name`(路径推导)
109
+ * - `description` — JSDoc 注释块自由文本(对 LLM 可见)
110
+ * - `filePath` / `functionName` — 由 `pathMeta` 透传
111
+ * - `inputTypeName` — 第一个参数的 TypeReference 名(供 [extractTypeInfo](./extractHandlerTypes.md) 生成 zod schema)
112
+ */
113
+ interface ToolMetadata extends ToolCore {
114
+ /** 第一个参数的 interface/type 名(用于生成 zod schema),
115
+ * 无参数/参数无类型标注/参数为内联类型字面量时为 `undefined` */
116
+ inputTypeName?: string;
117
+ /** 源码相对路径(从 `pathMeta` 透传) */
118
+ filePath: string;
119
+ /** 源码中的导出函数名(从 `pathMeta` 透传,AST 定位用,不受 `@tool` 覆盖影响) */
120
+ functionName: string;
121
+ }
122
+ /**
123
+ * 路径推导的 tool 元数据(由 [scanTools](../tools/scanTools.ts) 计算)
124
+ *
125
+ * 透传到 [ToolMetadata](./extractToolMetadata.ts) 输出,与 AST 提取字段合并。
126
+ */
127
+ interface ToolPathMeta {
128
+ /** 路径推导的 tool 名(如 `weather.getWeather`) */
129
+ name: string;
130
+ /** 源码相对路径(如 `src/tools/weather/handler.ts`) */
131
+ filePath: string;
132
+ }
133
+
134
+ /**
135
+ * Agent 的 LLM 可见核心字段
136
+ *
137
+ * 描述"agent 是什么"——LLM 真正需要消费的字段,**不含**代码本体加载细节
138
+ * (filePath / hasRun)。文件型 agent 与 DB-driven skill 都实现此接口。
139
+ *
140
+ * - 文件型 agent:由 [AgentMetadata](./extractAgentMetadata.md) 继承扩展,
141
+ * 额外含 `filePath` / `hasRun`(代码本体加载用)
142
+ * - DB-driven skill:业务方 plugin 从 DB 字段映射到本接口即可,无需填占位值
143
+ * (skill 无源文件,不走 `loadAgentModule`,自然不读 filePath / hasRun)
144
+ *
145
+ * `@faapi/agent` 子包的 `Agent` 类、`agentRegistry` 查询入口、`asTool` 包装
146
+ * 都消费 `AgentCore`,实现"agent 与 skill 走同一运行时链路"。
147
+ */
148
+ interface AgentCore {
149
+ /** agent 名(`@agent` JSDoc 覆盖值 或 目录推导值) */
150
+ name: string;
151
+ /** JSDoc 描述(agent 描述,对 LLM 可见),无 JSDoc 或 JSDoc 无自由文本时为 `undefined` */
152
+ description?: string;
153
+ /** 系统提示词(config 块字面量提取),无/非字面量时为 `undefined` */
154
+ systemPrompt?: string;
155
+ /** agent 显式声明可用的 tool 引用列表(config 块字面量提取),无/含非字面量元素时为 `undefined` */
156
+ tools?: string[];
157
+ /** 可调用的其他 agent 名列表(config 块字面量提取),无/含非字面量元素时为 `undefined` */
158
+ agents?: string[];
159
+ /** LLM 模型名(config 块字面量提取),无/非字面量时为 `undefined` */
160
+ model?: string;
161
+ /** 最大对话轮数(config 块字面量提取),无/非字面量时为 `undefined` */
162
+ maxTurns?: number;
163
+ }
164
+ /**
165
+ * Agent 完整元数据(文件型 agent)
166
+ *
167
+ * 继承 [AgentCore](./extractAgentMetadata.md) 的 LLM 字段,额外扩展**代码本体加载细节**:
168
+ * - `filePath` — `loadAgentModule` 加载 `handler.js` 产物提取 `run` 函数用
169
+ * - `hasRun` — 是否导出 `run` 函数(`Agent.executeSubAgent` 据此决定走自定义 run
170
+ * 还是默认 reactLoop)
171
+ *
172
+ * DB-driven skill 不实现此接口(无源文件,无需加载),只实现 `AgentCore`。
173
+ *
174
+ * 由 [extractAgentMetadata](./extractAgentMetadata.md) 产出,合并路径推导字段
175
+ * (来自 [scanAgents](../agents/scanAgents.md) 的 `AgentManifest`)与 AST 提取字段
176
+ * (JSDoc 描述、`@agent` 覆盖名、config 块字段)。
177
+ *
178
+ * 字段来源:
179
+ * - `name` — `@agent` JSDoc 覆盖值,或 `pathMeta.name`(目录推导)
180
+ * - `filePath` / `hasRun` — 由 `pathMeta` 透传
181
+ * - `description` — JSDoc 注释块自由文本(对 LLM 可见)
182
+ * - `systemPrompt` / `tools` / `agents` / `model` / `maxTurns` — config 块字面量提取
183
+ */
184
+ interface AgentMetadata extends AgentCore {
185
+ /** 源码相对路径(从 `pathMeta` 透传),`loadAgentModule` 据此加载 `handler.js` 提取 `run` */
186
+ filePath: string;
187
+ /** 是否导出 `run` 函数(从 `pathMeta` 透传),`Agent.executeSubAgent` 据此选择自定义 run / 默认 reactLoop */
188
+ hasRun: boolean;
189
+ }
190
+ /**
191
+ * 路径推导的 agent 元数据(由 [scanAgents](../agents/scanAgents.ts) 计算)
192
+ *
193
+ * 透传到 [AgentMetadata](./extractAgentMetadata.ts) 输出,与 AST 提取字段合并。
194
+ * 与 [ToolPathMeta](./extractToolMetadata.md) 对称。
195
+ */
196
+ interface AgentPathMeta {
197
+ /** 目录推导的 agent 名(如 `researcher`) */
198
+ name: string;
199
+ /** 源码相对路径(如 `src/agents/researcher/handler.ts`) */
200
+ filePath: string;
201
+ /** 是否导出 `run` 函数(scanAgents 正则检测) */
202
+ hasRun: boolean;
203
+ }
204
+
205
+ /**
206
+ * app 级注册表(方案 A:注册表实例化)
207
+ *
208
+ * 每个应用实例(`createAppBase`)持有一套独立的注册表,随 app 创建、随
209
+ * `app.close()` 销毁——多 app 同进程(测试 / 嵌入 / 多租户)互不串台。
210
+ * 此前注册表是模块级全局单例 + hydrate 整体替换语义,后创建的 app 会覆盖
211
+ * 先创建的 app 的清单,任一 app close 会清空全部(详见各模块 .md)。
212
+ *
213
+ * 原四个模块(toolRegistry / agentRegistry / skillRegistry / agentHandle)
214
+ * 保留同名全局函数作为**默认实例的便捷访问器**(供编程式直调 / 单元测试 /
215
+ * 无 app 上下文的场景),内部全部路由到本模块的 `defaultRegistries`。
216
+ * 框架自身链路(hydrate / 请求注入 / `@faapi/agent` 插件 / lifecycle 钩子)
217
+ * 一律走 app 实例,不再读写全局默认实例。
218
+ */
219
+ interface ToolRegistry {
220
+ /** 全量替换(tool 清单来自编译期产物,reload 时整体重新生成) */
221
+ hydrate(tools: ToolMetadata[]): void;
222
+ /** 按全名查找(如 `weather.getWeather`) */
223
+ get(name: string): ToolMetadata | undefined;
224
+ /** 所有已注册 tool(副本) */
225
+ list(): ToolMetadata[];
226
+ clear(): void;
227
+ }
228
+ /** agent 包装为 tool 的描述符(reactLoop 据此识别 sub-agent 递归) */
229
+ interface AgentToolDescriptor {
230
+ kind: 'agent';
231
+ name: string;
232
+ agentName: string;
233
+ description?: string;
234
+ metadata: AgentCore;
235
+ }
236
+ interface AgentRegistry {
237
+ /** 全量替换(与 hydrateToolRegistry 同构) */
238
+ hydrate(agents: AgentMetadata[]): void;
239
+ /** LLM 可见元数据(AgentCore) */
240
+ getAgent(name: string): AgentCore | undefined;
241
+ /** 完整元数据(含 filePath / hasRun,供加载 handler.js 执行 run) */
242
+ getAgentEntry(name: string): AgentMetadata | undefined;
243
+ /** 所有已注册 agent 的 LLM 可见元数据(副本) */
244
+ listAgents(): AgentCore[];
245
+ /** 包装为 tool 描述符 */
246
+ asTool(name: string): AgentToolDescriptor | undefined;
247
+ /**
248
+ * 解析 agent 显式声明的 tool 集合。
249
+ * 跨注册表依赖:经由构造时绑定的 tool 注册表查找(同属一套 AppRegistries,
250
+ * 由 createAppBase 在同一启动阶段水合)
251
+ */
252
+ resolveAgentTools(name: string): ToolMetadata[];
253
+ /** 解析 agent 可调用的子 agent 集合 */
254
+ resolveSubAgents(name: string): AgentCore[];
255
+ clear(): void;
256
+ }
257
+ interface SkillRegistry {
258
+ /** 全量替换(DB change stream 场景也可用 upsert 增量) */
259
+ hydrate(skills: AgentCore[]): void;
260
+ /** 增量注册 / 覆盖(业务方监听 DB 单条变更) */
261
+ upsert(skill: AgentCore): void;
262
+ remove(name: string): void;
263
+ get(name: string): AgentCore | undefined;
264
+ list(): AgentCore[];
265
+ clear(): void;
266
+ }
267
+ /** agent handle 工厂函数(由 `@faapi/agent` 插件注册) */
268
+ type AgentHandleFactory = (ctx: FaapiContext) => unknown;
269
+ interface AgentHandleStore {
270
+ /** 注册工厂(null 清理);二次注册覆盖 */
271
+ register(factory: AgentHandleFactory | null): void;
272
+ /** 工厂已注册时返回 AgentHandle 实例,未注册返回 undefined */
273
+ get(ctx: FaapiContext): unknown;
274
+ clear(): void;
275
+ }
276
+ /** 一个 app 实例持有的全套注册表 */
277
+ interface AppRegistries {
278
+ tool: ToolRegistry;
279
+ agent: AgentRegistry;
280
+ skill: SkillRegistry;
281
+ agentHandle: AgentHandleStore;
282
+ }
283
+ /** 创建一套 app 级注册表(`createAppBase` 每次调用创建独立实例) */
284
+ declare function createAppRegistries(): AppRegistries;
285
+
75
286
  interface CookieOptions {
76
287
  domain?: string;
77
288
  path?: string;
@@ -123,7 +334,14 @@ interface FailOptions {
123
334
  */
124
335
  interface FaapiContextConfig extends Record<string, unknown> {
125
336
  }
337
+
126
338
  interface FaapiContext {
339
+ /**
340
+ * app 级注册表(tool/agent/skill/agentHandle,方案 A 实例化)。
341
+ * 经 createContext 进入请求链路时由框架注入;编程式构造的 ctx 可不传
342
+ * (injectParams 等消费方回退到默认全局实例)
343
+ */
344
+ registries?: AppRegistries;
127
345
  request: Request;
128
346
  params: Record<string, string>;
129
347
  query: URLSearchParams;
@@ -488,4 +706,4 @@ interface RouteInfo {
488
706
  output: RouteOutputSchema | null;
489
707
  }
490
708
 
491
- export { type CorsOptions as C, type FaapiContext as F, type HelmetOptions as H, type InjectorMap as I, type LoggerOptions as L, type RouteManifest as R, type SseEvent as S, type WsRouteManifest as W, type FaapiMiddleware as a, type FaapiContextConfig as b, type FailOptions as c, type Injector as d, type RouteInfo as e, type RouteInputSchema as f, type RouteOutputSchema as g, type RouteParamSchema as h, type SseWriter as i, cors as j, helmet as k, logger as l };
709
+ export { type AppRegistries as A, type CorsOptions as C, type FaapiContext as F, type HelmetOptions as H, type InjectorMap as I, type LoggerOptions as L, type RouteManifest as R, type SkillRegistry as S, type ToolMetadata as T, type WsRouteManifest as W, type FaapiMiddleware as a, type AgentCore as b, type AgentMetadata as c, type AgentHandleFactory as d, type AgentHandleStore as e, type AgentPathMeta as f, type AgentRegistry as g, type AgentToolDescriptor as h, type FaapiContextConfig as i, type FailOptions as j, type Injector as k, type RouteInfo as l, type RouteInputSchema as m, type RouteOutputSchema as n, type RouteParamSchema as o, type SseEvent as p, type SseWriter as q, type ToolCore as r, type ToolPathMeta as s, type ToolRegistry as t, cors as u, createAppRegistries as v, helmet as w, logger as x };
package/dist/testing.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { F as FaapiContext, a as FaapiMiddleware, I as InjectorMap, R as RouteManifest, W as WsRouteManifest, C as CorsOptions, H as HelmetOptions, L as LoggerOptions } from './routeTypes-FtbRkpVF.js';
1
+ import { F as FaapiContext, a as FaapiMiddleware, I as InjectorMap, R as RouteManifest, W as WsRouteManifest, C as CorsOptions, H as HelmetOptions, L as LoggerOptions } from './routeTypes-DnJuuvq-.js';
2
2
  import { Server } from 'node:http';
3
3
  import { WebSocket } from 'ws';
4
4
 
@@ -23,6 +23,8 @@ declare function createTestContext(options: CreateTestContextOptions): FaapiCont
23
23
  * createTestContext 的选项
24
24
  */
25
25
  interface CreateTestContextOptions {
26
+ /** app 级注册表(测试 handler 声明 agent/agents 参数时注入用,可选) */
27
+ registries?: FaapiContext['registries'];
26
28
  /** 请求方法,默认 'GET' */
27
29
  method?: string;
28
30
  /** 请求路径,必填,如 '/api/user'(无需写 host) */