@faapi/faapi 5.0.1 → 5.2.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,5 +1,5 @@
1
- import { A as AppRegistries, R as RouteManifest, F as FaapiContext, C as CorsOptions, H as HelmetOptions, L as LoggerOptions, a as FaapiMiddleware, I as InjectorMap, T as ToolMetadata, b as AgentCore, c as AgentMetadata, W as WsRouteManifest } from './routeTypes-DnJuuvq-.js';
2
- export { d as AgentHandleFactory, e as AgentHandleStore, f as AgentPathMeta, g as AgentRegistry, h as AgentToolDescriptor, i as FaapiContextConfig, j as FailOptions, k as Injector, l as RouteInfo, m as RouteInputSchema, n as RouteOutputSchema, o as RouteParamSchema, S as SkillRegistry, p as SseEvent, q as SseWriter, r as ToolCore, s as ToolPathMeta, t as ToolRegistry, u as cors, v as createAppRegistries, w as helmet, x as logger } from './routeTypes-DnJuuvq-.js';
1
+ import { A as AppRegistries, R as RouteManifest, F as FaapiContext, C as CorsOptions, H as HelmetOptions, L as LoggerOptions, a as FaapiMiddleware, I as InjectorMap, T as ToolMetadata, b as AgentCore, c as AgentMetadata, W as WsRouteManifest } from './routeTypes-Bm--uTbm.js';
2
+ export { d as AgentHandleFactory, e as AgentHandleStore, f as AgentPathMeta, g as AgentRegistry, h as AgentToolDescriptor, i as FaapiContextConfig, j as FailOptions, k as Injector, l as RouteInfo, m as RouteInputSchema, n as RouteOutputSchema, o as RouteParamSchema, S as SkillRegistry, p as SseEvent, q as SseWriter, r as ToolCore, s as ToolPathMeta, t as ToolRegistry, u as cors, v as createAppRegistries, w as helmet, x as logger } from './routeTypes-Bm--uTbm.js';
3
3
  import * as node_http from 'node:http';
4
4
  import { Server, IncomingMessage, ServerResponse } from 'node:http';
5
5
  import { Socket } from 'node:net';
@@ -781,8 +781,12 @@ declare class SchemaExtractionError extends Error {
781
781
  *
782
782
  * 所有抛错点应优先使用此工厂——错误无行号时,几百行的类型文件只能靠
783
783
  * 类型名肉眼定位;解析 lib.d.ts 类型别名时还会出现错误文本与文件上下文错位
784
+ *
785
+ * `sourceFile` 可选:未触达 checker 的纯语法遍历路径(binder 未运行)没有
786
+ * parent 指针,`node.getSourceFile()` 返回 undefined,此时调用方需显式传入
787
+ * `program.getSourceFile(filePath)` 的结果以携带位置。
784
788
  */
785
- static at(node: ts.Node, typeText: string, reason: string): SchemaExtractionError;
789
+ static at(node: ts.Node, typeText: string, reason: string, sourceFile?: ts.SourceFile): SchemaExtractionError;
786
790
  }
787
791
  /**
788
792
  * 运行时类型描述
package/dist/index.js CHANGED
@@ -848,15 +848,19 @@ var init_resolveTypeNode = __esm({
848
848
  *
849
849
  * 所有抛错点应优先使用此工厂——错误无行号时,几百行的类型文件只能靠
850
850
  * 类型名肉眼定位;解析 lib.d.ts 类型别名时还会出现错误文本与文件上下文错位
851
+ *
852
+ * `sourceFile` 可选:未触达 checker 的纯语法遍历路径(binder 未运行)没有
853
+ * parent 指针,`node.getSourceFile()` 返回 undefined,此时调用方需显式传入
854
+ * `program.getSourceFile(filePath)` 的结果以携带位置。
851
855
  */
852
- static at(node, typeText, reason) {
853
- const sourceFile = node.getSourceFile();
854
- if (!sourceFile) {
856
+ static at(node, typeText, reason, sourceFile) {
857
+ const sf = sourceFile ?? node.getSourceFile();
858
+ if (!sf) {
855
859
  return new _SchemaExtractionError(typeText, reason);
856
860
  }
857
- const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
861
+ const { line, character } = sf.getLineAndCharacterOfPosition(node.getStart(sf));
858
862
  return new _SchemaExtractionError(typeText, reason, void 0, {
859
- file: sourceFile.fileName,
863
+ file: sf.fileName,
860
864
  line: line + 1,
861
865
  column: character + 1
862
866
  });
@@ -5085,37 +5089,35 @@ import path17 from "path";
5085
5089
 
5086
5090
  // src/ast/extractAgentMetadata.ts
5087
5091
  import ts9 from "typescript";
5092
+ init_resolveTypeNode();
5088
5093
  function extractAgentMetadata(program, filePath, pathMeta) {
5089
5094
  const sourceFile = program.getSourceFile(filePath);
5090
5095
  if (!sourceFile) return null;
5091
5096
  const configFound = findConfigExport(sourceFile);
5092
- let jsDocOwner = null;
5093
- let objectLiteral = null;
5094
- if (configFound) {
5095
- jsDocOwner = configFound.jsDocOwner;
5096
- objectLiteral = configFound.objectLiteral;
5097
- } else if (pathMeta.hasRun) {
5098
- const runNode = findRunExport(sourceFile);
5099
- if (runNode) {
5100
- jsDocOwner = runNode;
5101
- }
5102
- }
5103
- const jsDoc = jsDocOwner ? getJSDocFromNode(jsDocOwner) : void 0;
5097
+ if (!configFound) {
5098
+ throw SchemaExtractionError.at(
5099
+ sourceFile,
5100
+ "config.systemPrompt",
5101
+ "agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09",
5102
+ sourceFile
5103
+ );
5104
+ }
5105
+ if (!configFound.objectLiteral) {
5106
+ throw SchemaExtractionError.at(
5107
+ configFound.jsDocOwner,
5108
+ "config",
5109
+ "\u4EC5\u652F\u6301\u5BF9\u8C61\u5B57\u9762\u91CF\u3001\u7BAD\u5934\u51FD\u6570\u8FD4\u56DE\u5BF9\u8C61\u5B57\u9762\u91CF\u6216\u51FD\u6570\u8FD4\u56DE\u5BF9\u8C61\u5B57\u9762\u91CF",
5110
+ sourceFile
5111
+ );
5112
+ }
5113
+ const objectLiteral = configFound.objectLiteral;
5114
+ const jsDoc = getJSDocFromNode(configFound.jsDocOwner);
5104
5115
  const description = extractDescription(jsDoc);
5105
5116
  const agentNameOverride = extractJSDocTagValue(jsDoc, "agent");
5106
- let systemPrompt;
5107
- let tools;
5108
- let agents;
5109
- let model;
5110
- let maxTurns;
5111
- if (objectLiteral) {
5112
- const fields = extractConfigFields(objectLiteral);
5113
- systemPrompt = fields.systemPrompt;
5114
- tools = fields.tools;
5115
- agents = fields.agents;
5116
- model = fields.model;
5117
- maxTurns = fields.maxTurns;
5118
- }
5117
+ const { systemPrompt, tools, agents, model, maxTurns } = extractConfigFields(
5118
+ objectLiteral,
5119
+ sourceFile
5120
+ );
5119
5121
  return {
5120
5122
  name: agentNameOverride ?? pathMeta.name,
5121
5123
  description,
@@ -5140,8 +5142,9 @@ function findConfigExport(sourceFile) {
5140
5142
  if (ts9.isObjectLiteralExpression(decl.initializer)) {
5141
5143
  result = { jsDocOwner: node, objectLiteral: decl.initializer };
5142
5144
  } else if (ts9.isArrowFunction(decl.initializer)) {
5143
- const returnObj = getReturnObjectLiteral(decl.initializer);
5144
- result = { jsDocOwner: node, objectLiteral: returnObj };
5145
+ result = { jsDocOwner: node, objectLiteral: getReturnObjectLiteral(decl.initializer) };
5146
+ } else {
5147
+ result = { jsDocOwner: node, objectLiteral: null };
5145
5148
  }
5146
5149
  }
5147
5150
  }
@@ -5152,27 +5155,6 @@ function findConfigExport(sourceFile) {
5152
5155
  });
5153
5156
  return result;
5154
5157
  }
5155
- function findRunExport(sourceFile) {
5156
- let result = null;
5157
- ts9.forEachChild(sourceFile, (node) => {
5158
- if (result) return;
5159
- if (ts9.isFunctionDeclaration(node) && hasExportModifier(node) && node.name?.text === "run") {
5160
- result = node;
5161
- return;
5162
- }
5163
- if (ts9.isVariableStatement(node) && hasExportModifier(node)) {
5164
- for (const decl of node.declarationList.declarations) {
5165
- if (result) break;
5166
- const nameText = ts9.isIdentifier(decl.name) ? decl.name.text : "";
5167
- if (nameText !== "run" || !decl.initializer) continue;
5168
- if (ts9.isArrowFunction(decl.initializer) || ts9.isFunctionExpression(decl.initializer)) {
5169
- result = node;
5170
- }
5171
- }
5172
- }
5173
- });
5174
- return result;
5175
- }
5176
5158
  function getReturnObjectLiteral(fn) {
5177
5159
  const body = fn.body;
5178
5160
  if (!body) return null;
@@ -5188,31 +5170,60 @@ function getReturnObjectLiteral(fn) {
5188
5170
  }
5189
5171
  return null;
5190
5172
  }
5191
- function extractConfigFields(objLit) {
5192
- const result = {};
5173
+ function extractConfigFields(objLit, sourceFile) {
5174
+ let systemPrompt;
5175
+ let tools;
5176
+ let agents;
5177
+ let model;
5178
+ let maxTurns;
5193
5179
  for (const prop of objLit.properties) {
5194
- if (!ts9.isPropertyAssignment(prop)) continue;
5180
+ if (ts9.isSpreadAssignment(prop)) continue;
5181
+ if (!ts9.isPropertyAssignment(prop)) {
5182
+ throw SchemaExtractionError.at(
5183
+ prop,
5184
+ "config",
5185
+ "\u4EC5\u652F\u6301 key: value \u5C5E\u6027\u5F62\u5F0F\uFF08\u4E0D\u652F\u6301 shorthand/\u65B9\u6CD5/getter\uFF09",
5186
+ sourceFile
5187
+ );
5188
+ }
5195
5189
  const propName = getPropertyName(prop.name);
5196
- if (!propName) continue;
5190
+ if (!propName) {
5191
+ throw SchemaExtractionError.at(prop.name, "config", "\u4E0D\u652F\u6301 computed \u5C5E\u6027\u540D", sourceFile);
5192
+ }
5197
5193
  switch (propName) {
5198
5194
  case "systemPrompt":
5199
- result.systemPrompt = extractStringValue(prop.initializer);
5195
+ systemPrompt = requireStringValue(prop, "systemPrompt", sourceFile);
5200
5196
  break;
5201
5197
  case "tools":
5202
- result.tools = extractStringArrayValue(prop.initializer);
5198
+ tools = requireStringArrayValue(prop, "tools", sourceFile);
5203
5199
  break;
5204
5200
  case "agents":
5205
- result.agents = extractStringArrayValue(prop.initializer);
5201
+ agents = requireStringArrayValue(prop, "agents", sourceFile);
5206
5202
  break;
5207
5203
  case "model":
5208
- result.model = extractStringValue(prop.initializer);
5204
+ model = requireStringValue(prop, "model", sourceFile);
5209
5205
  break;
5210
5206
  case "maxTurns":
5211
- result.maxTurns = extractNumberValue(prop.initializer);
5207
+ maxTurns = requireNumberValue(prop, "maxTurns", sourceFile);
5212
5208
  break;
5209
+ default:
5210
+ throw SchemaExtractionError.at(
5211
+ prop,
5212
+ `config.${propName}`,
5213
+ "\u672A\u77E5 config \u5B57\u6BB5\u2014\u2014\u4EC5\u652F\u6301 systemPrompt / tools / agents / model / maxTurns",
5214
+ sourceFile
5215
+ );
5213
5216
  }
5214
5217
  }
5215
- return result;
5218
+ if (systemPrompt === void 0) {
5219
+ throw SchemaExtractionError.at(
5220
+ objLit,
5221
+ "config.systemPrompt",
5222
+ "agent \u5FC5\u586B\u2014\u2014\u8BF7\u5728 config \u5757\u58F0\u660E\u7CFB\u7EDF\u63D0\u793A\u8BCD\uFF08\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09",
5223
+ sourceFile
5224
+ );
5225
+ }
5226
+ return { systemPrompt, tools, agents, model, maxTurns };
5216
5227
  }
5217
5228
  function getPropertyName(name) {
5218
5229
  if (ts9.isIdentifier(name)) return name.text;
@@ -5220,9 +5231,52 @@ function getPropertyName(name) {
5220
5231
  return null;
5221
5232
  }
5222
5233
  function extractStringValue(expr) {
5223
- if (ts9.isStringLiteral(expr)) return expr.text;
5234
+ if (isStringLikeLiteral(expr)) return expr.text;
5235
+ if (ts9.isBinaryExpression(expr) && expr.operatorToken.kind === ts9.SyntaxKind.PlusToken) {
5236
+ const left = extractStringValue(expr.left);
5237
+ if (left === void 0) return void 0;
5238
+ const right = extractStringValue(expr.right);
5239
+ if (right === void 0) return void 0;
5240
+ return left + right;
5241
+ }
5224
5242
  return void 0;
5225
5243
  }
5244
+ function requireStringValue(prop, fieldName, sourceFile) {
5245
+ const value = extractStringValue(prop.initializer);
5246
+ if (value === void 0) {
5247
+ throw SchemaExtractionError.at(
5248
+ prop.initializer,
5249
+ `config.${fieldName}`,
5250
+ "\u4EC5\u652F\u6301\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF08\u542B\u63D2\u503C\u7684\u6A21\u677F\u5B57\u7B26\u4E32/\u53D8\u91CF\u5F15\u7528/\u6570\u5B57\u65E0\u6CD5\u9759\u6001\u6C42\u503C\u4E3A\u5B57\u7B26\u4E32\uFF09",
5251
+ sourceFile
5252
+ );
5253
+ }
5254
+ return value;
5255
+ }
5256
+ function requireStringArrayValue(prop, fieldName, sourceFile) {
5257
+ const value = extractStringArrayValue(prop.initializer);
5258
+ if (value === void 0) {
5259
+ throw SchemaExtractionError.at(
5260
+ prop.initializer,
5261
+ `config.${fieldName}`,
5262
+ "\u4EC5\u652F\u6301\u5168\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u6570\u7EC4\uFF08\u5143\u7D20\u4E3A\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u3001\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\u6216\u5176 + \u62FC\u63A5\uFF09",
5263
+ sourceFile
5264
+ );
5265
+ }
5266
+ return value;
5267
+ }
5268
+ function requireNumberValue(prop, fieldName, sourceFile) {
5269
+ const value = extractNumberValue(prop.initializer);
5270
+ if (value === void 0) {
5271
+ throw SchemaExtractionError.at(
5272
+ prop.initializer,
5273
+ `config.${fieldName}`,
5274
+ "\u4EC5\u652F\u6301\u6570\u5B57\u5B57\u9762\u91CF",
5275
+ sourceFile
5276
+ );
5277
+ }
5278
+ return value;
5279
+ }
5226
5280
  function extractNumberValue(expr) {
5227
5281
  if (ts9.isNumericLiteral(expr)) {
5228
5282
  const num = Number(expr.text);
@@ -5230,12 +5284,16 @@ function extractNumberValue(expr) {
5230
5284
  }
5231
5285
  return void 0;
5232
5286
  }
5287
+ function isStringLikeLiteral(node) {
5288
+ return ts9.isStringLiteral(node) || ts9.isNoSubstitutionTemplateLiteral(node);
5289
+ }
5233
5290
  function extractStringArrayValue(expr) {
5234
5291
  if (!ts9.isArrayLiteralExpression(expr)) return void 0;
5235
5292
  const values = [];
5236
5293
  for (const element of expr.elements) {
5237
- if (!ts9.isStringLiteral(element)) return void 0;
5238
- values.push(element.text);
5294
+ const value = extractStringValue(element);
5295
+ if (value === void 0) return void 0;
5296
+ values.push(value);
5239
5297
  }
5240
5298
  return values;
5241
5299
  }
@@ -5276,6 +5334,28 @@ function hydrateAgents(manifest) {
5276
5334
  maxTurns: a.maxTurns ?? void 0
5277
5335
  }));
5278
5336
  }
5337
+ function validateAgentList(metadata) {
5338
+ const names = /* @__PURE__ */ new Map();
5339
+ for (const a of metadata) {
5340
+ const prev = names.get(a.name);
5341
+ if (prev) {
5342
+ throw new Error(
5343
+ `agent \u540D\u91CD\u590D: "${a.name}"\uFF08${prev} \u4E0E ${a.filePath} \u51B2\u7A81\u2014\u2014\u76EE\u5F55\u63A8\u5BFC\u540D\u6216 @agent \u8986\u76D6\u540D\u649E\u540D\uFF09`
5344
+ );
5345
+ }
5346
+ names.set(a.name, a.filePath);
5347
+ }
5348
+ for (const a of metadata) {
5349
+ for (const ref of a.agents ?? []) {
5350
+ if (!names.has(ref)) {
5351
+ const available = [...names.keys()].join(", ") || "\u65E0";
5352
+ throw new Error(
5353
+ `agent "${a.name}" \u7684 agents \u5F15\u7528\u4E86\u4E0D\u5B58\u5728\u7684 agent: "${ref}"\uFF08\u6E05\u5355\u4E2D\u53EF\u7528: ${available}\uFF09`
5354
+ );
5355
+ }
5356
+ }
5357
+ }
5358
+ }
5279
5359
  async function generateAgentArtifacts(agents, rootDir, dist) {
5280
5360
  const metadata = [];
5281
5361
  const programByFile = createPrograms(agents.map((m) => path17.resolve(rootDir, m.filePath)));
@@ -5287,10 +5367,14 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
5287
5367
  filePath: manifest.filePath,
5288
5368
  hasRun: manifest.hasRun
5289
5369
  });
5290
- if (result) {
5291
- metadata.push(result);
5370
+ if (!result) {
5371
+ throw new Error(
5372
+ `agent "${manifest.name}" \u6E90\u6587\u4EF6\u4E0D\u5728 Program \u4E2D: ${manifest.filePath}\u2014\u2014\u65E0\u6CD5\u751F\u6210\u6E05\u5355`
5373
+ );
5292
5374
  }
5375
+ metadata.push(result);
5293
5376
  }
5377
+ validateAgentList(metadata);
5294
5378
  const serialized = serializeAgents(metadata, dist);
5295
5379
  const agentsPath = path17.resolve(rootDir, dist, AGENTS_FILE);
5296
5380
  await writeAgentsModule(serialized, agentsPath);