@faapi/faapi 5.0.1 → 5.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/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-DG0eL3l5.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-DG0eL3l5.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\u6216\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\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\u6216\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\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,45 @@ 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;
5224
5235
  return void 0;
5225
5236
  }
5237
+ function requireStringValue(prop, fieldName, sourceFile) {
5238
+ const value = extractStringValue(prop.initializer);
5239
+ if (value === void 0) {
5240
+ throw SchemaExtractionError.at(
5241
+ prop.initializer,
5242
+ `config.${fieldName}`,
5243
+ "\u4EC5\u652F\u6301\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u6216\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\uFF08\u542B\u63D2\u503C\u7684\u6A21\u677F\u5B57\u7B26\u4E32/\u53D8\u91CF\u5F15\u7528\u65E0\u6CD5\u9759\u6001\u6C42\u503C\uFF09",
5244
+ sourceFile
5245
+ );
5246
+ }
5247
+ return value;
5248
+ }
5249
+ function requireStringArrayValue(prop, fieldName, sourceFile) {
5250
+ const value = extractStringArrayValue(prop.initializer);
5251
+ if (value === void 0) {
5252
+ throw SchemaExtractionError.at(
5253
+ prop.initializer,
5254
+ `config.${fieldName}`,
5255
+ "\u4EC5\u652F\u6301\u5168\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u6570\u7EC4\uFF08\u5143\u7D20\u4E3A\u5B57\u7B26\u4E32\u5B57\u9762\u91CF\u6216\u65E0\u63D2\u503C\u6A21\u677F\u5B57\u7B26\u4E32\uFF09",
5256
+ sourceFile
5257
+ );
5258
+ }
5259
+ return value;
5260
+ }
5261
+ function requireNumberValue(prop, fieldName, sourceFile) {
5262
+ const value = extractNumberValue(prop.initializer);
5263
+ if (value === void 0) {
5264
+ throw SchemaExtractionError.at(
5265
+ prop.initializer,
5266
+ `config.${fieldName}`,
5267
+ "\u4EC5\u652F\u6301\u6570\u5B57\u5B57\u9762\u91CF",
5268
+ sourceFile
5269
+ );
5270
+ }
5271
+ return value;
5272
+ }
5226
5273
  function extractNumberValue(expr) {
5227
5274
  if (ts9.isNumericLiteral(expr)) {
5228
5275
  const num = Number(expr.text);
@@ -5230,11 +5277,14 @@ function extractNumberValue(expr) {
5230
5277
  }
5231
5278
  return void 0;
5232
5279
  }
5280
+ function isStringLikeLiteral(node) {
5281
+ return ts9.isStringLiteral(node) || ts9.isNoSubstitutionTemplateLiteral(node);
5282
+ }
5233
5283
  function extractStringArrayValue(expr) {
5234
5284
  if (!ts9.isArrayLiteralExpression(expr)) return void 0;
5235
5285
  const values = [];
5236
5286
  for (const element of expr.elements) {
5237
- if (!ts9.isStringLiteral(element)) return void 0;
5287
+ if (!isStringLikeLiteral(element)) return void 0;
5238
5288
  values.push(element.text);
5239
5289
  }
5240
5290
  return values;
@@ -5276,6 +5326,28 @@ function hydrateAgents(manifest) {
5276
5326
  maxTurns: a.maxTurns ?? void 0
5277
5327
  }));
5278
5328
  }
5329
+ function validateAgentList(metadata) {
5330
+ const names = /* @__PURE__ */ new Map();
5331
+ for (const a of metadata) {
5332
+ const prev = names.get(a.name);
5333
+ if (prev) {
5334
+ throw new Error(
5335
+ `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`
5336
+ );
5337
+ }
5338
+ names.set(a.name, a.filePath);
5339
+ }
5340
+ for (const a of metadata) {
5341
+ for (const ref of a.agents ?? []) {
5342
+ if (!names.has(ref)) {
5343
+ const available = [...names.keys()].join(", ") || "\u65E0";
5344
+ throw new Error(
5345
+ `agent "${a.name}" \u7684 agents \u5F15\u7528\u4E86\u4E0D\u5B58\u5728\u7684 agent: "${ref}"\uFF08\u6E05\u5355\u4E2D\u53EF\u7528: ${available}\uFF09`
5346
+ );
5347
+ }
5348
+ }
5349
+ }
5350
+ }
5279
5351
  async function generateAgentArtifacts(agents, rootDir, dist) {
5280
5352
  const metadata = [];
5281
5353
  const programByFile = createPrograms(agents.map((m) => path17.resolve(rootDir, m.filePath)));
@@ -5287,10 +5359,14 @@ async function generateAgentArtifacts(agents, rootDir, dist) {
5287
5359
  filePath: manifest.filePath,
5288
5360
  hasRun: manifest.hasRun
5289
5361
  });
5290
- if (result) {
5291
- metadata.push(result);
5362
+ if (!result) {
5363
+ throw new Error(
5364
+ `agent "${manifest.name}" \u6E90\u6587\u4EF6\u4E0D\u5728 Program \u4E2D: ${manifest.filePath}\u2014\u2014\u65E0\u6CD5\u751F\u6210\u6E05\u5355`
5365
+ );
5292
5366
  }
5367
+ metadata.push(result);
5293
5368
  }
5369
+ validateAgentList(metadata);
5294
5370
  const serialized = serializeAgents(metadata, dist);
5295
5371
  const agentsPath = path17.resolve(rootDir, dist, AGENTS_FILE);
5296
5372
  await writeAgentsModule(serialized, agentsPath);