@faapi/agent 4.4.0 → 5.0.1

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.js CHANGED
@@ -919,7 +919,7 @@ var Agent = class _Agent {
919
919
  */
920
920
  schemaCache = /* @__PURE__ */ new Map();
921
921
  /**
922
- * @param deps 运行时依赖(访问器 + providers Map + defaultProvider + llms + config)
922
+ * @param deps 运行时依赖(访问器 + providers Map + llms + config)
923
923
  * @param depth 递归深度(默认 1 = 根 agent;sub-agent 递归时传入 depth+1)
924
924
  */
925
925
  constructor(deps, depth = 1) {
@@ -930,15 +930,17 @@ var Agent = class _Agent {
930
930
  * 非流式执行——组装 config 调 [reactLoop](./reactLoop.md)
931
931
  *
932
932
  * reactLoop 不知 agent 名(只关心循环逻辑),返回的 `result.trace.agentName` 为空字符串。
933
- * 本方法在 reactLoop 返回后填充 `this.deps.agentName`,让顶层 trace 标识"是哪个 agent 跑的"。
933
+ * 本方法在 reactLoop 返回后填充 `options.agent`,让顶层 trace 标识"是哪个 agent 跑的"。
934
934
  *
935
935
  * @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
936
936
  * 都为空时抛 `AgentError`)
937
- * @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
938
- * temperature / maxTokens / messages / enableTracing
937
+ * @param options 本次调用配置——`agent`(agent 名,必须显式传,无默认 agent)/
938
+ * provider(外部 provider)/ model(字符串 key)/ temperature /
939
+ * maxTokens / messages / enableTracing
939
940
  * (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
940
941
  * @returns 最终结果(content + messages + turns + stopReason + usage + trace?)
941
- * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
942
+ * @throws {AgentError} 未传 options.agent;agent 未注册;input 与 messages 都为空;
943
+ * 续跑历史结构非法;provider/model 无法解析
942
944
  * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
943
945
  * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
944
946
  * @throws {Error} provider.complete 抛错时立即传播
@@ -947,7 +949,7 @@ var Agent = class _Agent {
947
949
  const config = await this.buildLoopConfig(input, options);
948
950
  const result = await reactLoop(input, config);
949
951
  if (result.trace) {
950
- result.trace.agentName = options?.agent ?? this.deps.agentName;
952
+ result.trace.agentName = options?.agent ?? "";
951
953
  }
952
954
  return result;
953
955
  }
@@ -956,11 +958,12 @@ var Agent = class _Agent {
956
958
  *
957
959
  * @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
958
960
  * 都为空时抛 `AgentError`)
959
- * @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
961
+ * @param options 本次调用配置——`agent`(必须显式传)/ provider / model /
960
962
  * temperature / maxTokens / messages
961
963
  * (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
962
964
  * @yields 流式 chunk(deltaContent / toolCall / toolResult / done)
963
- * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
965
+ * @throws {AgentError} 未传 options.agent;agent 未注册;input 与 messages 都为空;
966
+ * 续跑历史结构非法;provider/model 无法解析
964
967
  * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
965
968
  * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
966
969
  * @throws {Error} provider.stream 抛错时立即传播
@@ -970,15 +973,16 @@ var Agent = class _Agent {
970
973
  yield* reactLoopStream(input, config);
971
974
  }
972
975
  /**
973
- * 把自身包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
976
+ * 把指定 agent 包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
974
977
  *
975
978
  * 与 [agentRegistry.asTool](../../faapi/src/injection/agentRegistry.md) 同构——
976
979
  * Agent 类自带此方法便于在注入器场景直接调用(不必再过注册表)。
977
980
  *
981
+ * @param name agent 名(显式指定——无默认 agent)
978
982
  * @returns `AgentToolDescriptor` 或 `undefined`(agent 未注册)
979
983
  */
980
- asTool() {
981
- const meta = this.deps.getAgent(this.deps.agentName);
984
+ asTool(name) {
985
+ const meta = this.deps.getAgent(name);
982
986
  if (!meta) return void 0;
983
987
  return {
984
988
  kind: "agent",
@@ -1010,23 +1014,19 @@ var Agent = class _Agent {
1010
1014
  /**
1011
1015
  * 组装 ReactLoopConfig
1012
1016
  *
1013
- * 1. 解析有效 agent 名:`options.agent` > `deps.agentName`(`config.agent.defaultAgent`)
1017
+ * 1. 解析有效 agent 名:`options.agent`(必须显式传——无默认 agent,不传抛 AgentError)
1014
1018
  * 2. 查 agent 元数据(未注册抛 AgentError)——用 `getAgent` 拿 AgentCore
1015
1019
  * (LLM-facing 字段:systemPrompt / model / maxTurns)
1016
1020
  * 3. buildToolDefinitions 组装 tool 列表(用有效 agent 名查 tools / sub-agents)
1017
- * 4. config 字段优先级(高 → 低):`options` > agent 元数据 > 全局 AgentRuntimeConfig / deps.defaultProvider
1021
+ * 4. config 字段优先级(高 → 低):`options` > agent 元数据 > 全局 AgentRuntimeConfig
1018
1022
  *
1019
1023
  * `options.provider`(外部 provider)存在时由 {@link resolveExternalProvider} 物化,
1020
1024
  * 优先级最高——`options.model` 变为原始 model 名原样透传(不解析 llms key)。
1021
1025
  * 否则 `options.model` 是字符串 key,由 {@link resolveModelKey} 解析为 provider + model
1022
- * (支持 llms key 精确匹配 / `provider/model` 一体化 / 纯 model 名模糊匹配)。
1023
- * 不传 `options.model` 时用 `deps.defaultProvider` + agent 元数据 `config.model`。
1026
+ * (支持 llms key 精确匹配 / `provider/model` 一体化 / 纯 model 名模糊匹配;
1027
+ * 未传 `options.model` 时用 agent 元数据 `config.model` 作为缺省 key)。
1024
1028
  * 详见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」。
1025
1029
  *
1026
- * `options.agent` 覆盖本次调用的 agent 名——不传时用 `deps.agentName`(来自
1027
- * `config.agent.defaultAgent`)。`defaultAgent` 未设且 `options.agent` 未传时抛
1028
- * `AgentError`。
1029
- *
1030
1030
  * **输入守卫**(续跑入口,见 [reactLoop.md](./reactLoop.md) 中断恢复章节):
1031
1031
  * `input` 与 `options.messages` 都为空时抛 `AgentError`(不发送空请求);
1032
1032
  * `options.messages` 提供时先经 `validateResumeHistory` 结构校验,非法抛
@@ -1041,7 +1041,12 @@ var Agent = class _Agent {
1041
1041
  if (options?.messages?.length) {
1042
1042
  validateResumeHistory(options.messages);
1043
1043
  }
1044
- const agentName = options?.agent ?? this.deps.agentName;
1044
+ const agentName = options?.agent;
1045
+ if (!agentName) {
1046
+ throw new AgentError(
1047
+ 'agent.run/stream requires options.agent (no default agent) \u2014 pass { agent: "name" } to specify which agent to run'
1048
+ );
1049
+ }
1045
1050
  const meta = this.deps.getAgent(agentName);
1046
1051
  if (!meta) {
1047
1052
  throw new AgentError(`Agent "${agentName}" is not registered`);
@@ -1049,6 +1054,7 @@ var Agent = class _Agent {
1049
1054
  const tools = await this.buildToolDefinitions(agentName);
1050
1055
  const { provider, model } = options?.provider !== void 0 ? this.resolveExternalProvider(options.provider, options?.model) : this.resolveModelKey(options?.model, meta);
1051
1056
  const enableTracing = options?.enableTracing ?? this.deps.config?.enableTracing ?? false;
1057
+ const callCtx = { agentName, enableTracing, provider, model };
1052
1058
  return {
1053
1059
  provider,
1054
1060
  systemPrompt: meta.systemPrompt,
@@ -1060,7 +1066,7 @@ var Agent = class _Agent {
1060
1066
  signal: options?.signal,
1061
1067
  messages: options?.messages,
1062
1068
  enableTracing,
1063
- executeTool: async (name, args) => this.executeTool(name, args, enableTracing)
1069
+ executeTool: async (name, args) => this.executeTool(name, args, callCtx)
1064
1070
  };
1065
1071
  }
1066
1072
  /**
@@ -1094,43 +1100,42 @@ var Agent = class _Agent {
1094
1100
  /**
1095
1101
  * 解析 `options.model` 字符串 key → provider + model
1096
1102
  *
1097
- * 规则见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」:
1098
- * 1. `undefined` `deps.defaultProvider`(未配置时抛 `AgentError`——外部 provider 模式
1099
- * 要求调用方传 `options.provider`)+ `meta.model`
1100
- * 2. 精确匹配 `deps.providers` 的 key → 该 provider + 其 `models` 第一个 key
1101
- * 3. `/` `provider/model` 形式,`deps.providers.get(provider)` + 该 model
1103
+ * 规则见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」。
1104
+ * 无默认 provider——`key` 未传时用 agent 元数据 `config.model` 作为缺省 key;
1105
+ * 两者皆无抛 `AgentError`(要求调用方传 `options.model` `options.provider`)。
1106
+ * 1. 精确匹配 `deps.providers` 的 key → 该 provider + 其 `models` 第一个 key
1107
+ * (该 provider 未声明 `models` 时回落 `meta.model`)
1108
+ * 2. 含 `/` → `provider/model` 形式,`deps.providers.get(provider)` + 该 model
1102
1109
  * (要求该 model 在 `deps.llms[provider].models` 里)
1103
- * 4. 不含 `/` 且非 provider key → 在所有 provider 的 `models` 里按 model 名查找
1110
+ * 3. 不含 `/` 且非 provider key → 在所有 provider 的 `models` 里按 model 名查找
1104
1111
  * - 唯一 → 该 provider + 该 model
1105
1112
  * - 多个 → 抛 `AgentError`(要求用 `provider/model` 消歧)
1106
1113
  * - 无 → 抛 `AgentError`
1107
1114
  *
1108
- * @throws {AgentError} key 解析失败(provider/model 不存在或歧义);deps.defaultProvider
1109
- * 未配置(外部 provider 模式下调用方未传 options.provider)
1115
+ * @throws {AgentError} key 与 `meta.model` 均缺省;key 解析失败(provider/model
1116
+ * 不存在或歧义)
1110
1117
  */
1111
1118
  resolveModelKey(key, meta) {
1112
- if (key === void 0) {
1113
- if (!this.deps.defaultProvider) {
1114
- throw new AgentError(
1115
- "No default LLM provider: configure config.agent.llms, or pass options.provider (external provider) on this call"
1116
- );
1117
- }
1118
- return { provider: this.deps.defaultProvider, model: meta.model };
1119
+ const effectiveKey = key ?? meta.model;
1120
+ if (effectiveKey === void 0) {
1121
+ throw new AgentError(
1122
+ 'No LLM provider resolved: pass options.model (a provider key / "provider/model" / model name from config.agent.llms), options.provider (external provider), or declare model in the agent config'
1123
+ );
1119
1124
  }
1120
- const byProviderKey = this.deps.providers.get(key);
1125
+ const byProviderKey = this.deps.providers.get(effectiveKey);
1121
1126
  if (byProviderKey) {
1122
- const llmConfig = this.deps.llms[key];
1127
+ const llmConfig = this.deps.llms[effectiveKey];
1123
1128
  const firstModel = llmConfig ? Object.keys(llmConfig.models)[0] : void 0;
1124
1129
  return { provider: byProviderKey, model: firstModel ?? meta.model };
1125
1130
  }
1126
- if (key.includes("/")) {
1127
- const slashIdx = key.indexOf("/");
1128
- const providerName = key.slice(0, slashIdx);
1129
- const modelName = key.slice(slashIdx + 1);
1131
+ if (effectiveKey.includes("/")) {
1132
+ const slashIdx = effectiveKey.indexOf("/");
1133
+ const providerName = effectiveKey.slice(0, slashIdx);
1134
+ const modelName = effectiveKey.slice(slashIdx + 1);
1130
1135
  const provider = this.deps.providers.get(providerName);
1131
1136
  if (!provider) {
1132
1137
  throw new AgentError(
1133
- `Unknown provider "${providerName}" in model key "${key}". Declare it in config.agent.llms, or pass options.provider to use an external provider.`
1138
+ `Unknown provider "${providerName}" in model key "${effectiveKey}". Declare it in config.agent.llms, or pass options.provider to use an external provider.`
1134
1139
  );
1135
1140
  }
1136
1141
  const llmConfig = this.deps.llms[providerName];
@@ -1144,20 +1149,20 @@ var Agent = class _Agent {
1144
1149
  const matches = [];
1145
1150
  for (const [providerName, provider] of this.deps.providers) {
1146
1151
  const llmConfig = this.deps.llms[providerName];
1147
- if (llmConfig && llmConfig.models[key]) {
1152
+ if (llmConfig && llmConfig.models[effectiveKey]) {
1148
1153
  matches.push({ provider, providerName });
1149
1154
  }
1150
1155
  }
1151
1156
  if (matches.length === 1) {
1152
- return { provider: matches[0].provider, model: key };
1157
+ return { provider: matches[0].provider, model: effectiveKey };
1153
1158
  }
1154
1159
  if (matches.length > 1) {
1155
1160
  throw new AgentError(
1156
- `Model "${key}" is ambiguous (found in providers: ${matches.map((m) => m.providerName).join(", ")}). Use "provider/model" to disambiguate.`
1161
+ `Model "${effectiveKey}" is ambiguous (found in providers: ${matches.map((m) => m.providerName).join(", ")}). Use "provider/model" to disambiguate.`
1157
1162
  );
1158
1163
  }
1159
1164
  throw new AgentError(
1160
- `Model "${key}" not found in any provider. Declare it in config.agent.llms.*.models, or pass options.provider to use an external provider.`
1165
+ `Model "${effectiveKey}" not found in any provider. Declare it in config.agent.llms.*.models, or pass options.provider to use an external provider.`
1161
1166
  );
1162
1167
  }
1163
1168
  /**
@@ -1203,15 +1208,16 @@ var Agent = class _Agent {
1203
1208
  * - `agent.` 前缀 → {@link executeSubAgent} 递归(含 enableTracing + TracingToolResult 包装)
1204
1209
  * - 常规 tool → `loadToolModule` 加载 handler + 可选 input 校验 → 调用
1205
1210
  *
1206
- * `enableTracing` 由 [buildLoopConfig](#buildLoopConfig) 闭包捕获传入,用于 sub-agent
1207
- * 调用时决定是否包装 [TracingToolResult](./trace.md) 携带 sub-trace。
1211
+ * `callCtx` 由 [buildLoopConfig](#buildLoopConfig) 闭包捕获传入——本次调用的有效
1212
+ * agent 名(白名单校验)、enableTracing(sub-agent tracing 包装)与解析出的
1213
+ * provider/model(sub-agent 递归继承)。常规 tool 不需要 tracing 包装,直接返回结果。
1208
1214
  *
1209
1215
  * **常规 tool 校验失败**:不抛错,返回 `{ error }` 对象——reactLoop stringify 后
1210
1216
  * 作为 tool 结果回传 LLM,LLM 可据此修正参数重试。
1211
1217
  *
1212
1218
  * **tool 未找到 / 加载失败**:抛错,被 reactLoop catch 后同样回传 LLM。
1213
1219
  */
1214
- async executeTool(rawName, rawArgs, enableTracing) {
1220
+ async executeTool(rawName, rawArgs, callCtx) {
1215
1221
  const name = rawName;
1216
1222
  let args = rawArgs;
1217
1223
  const guard = this.deps.config?.beforeToolCall?.(name, args, this.deps.ctx);
@@ -1220,19 +1226,19 @@ var Agent = class _Agent {
1220
1226
  if ("args" in guard) args = guard.args;
1221
1227
  }
1222
1228
  const declared = /* @__PURE__ */ new Set();
1223
- for (const tool2 of this.deps.resolveAgentTools(this.deps.agentName)) {
1229
+ for (const tool2 of this.deps.resolveAgentTools(callCtx.agentName)) {
1224
1230
  declared.add(tool2.name);
1225
1231
  }
1226
- for (const sub of this.deps.resolveSubAgents(this.deps.agentName)) {
1232
+ for (const sub of this.deps.resolveSubAgents(callCtx.agentName)) {
1227
1233
  declared.add(`agent.${sub.name}`);
1228
1234
  }
1229
1235
  if (!declared.has(name)) {
1230
1236
  return {
1231
- error: `Tool "${name}" is not declared by agent "${this.deps.agentName}" (add it to the agent's tools/agents declaration)`
1237
+ error: `Tool "${name}" is not declared by agent "${callCtx.agentName}" (add it to the agent's tools/agents declaration)`
1232
1238
  };
1233
1239
  }
1234
1240
  if (name.startsWith("agent.")) {
1235
- return await this.executeSubAgent(name.slice(6), args, enableTracing);
1241
+ return await this.executeSubAgent(name.slice(6), args, callCtx);
1236
1242
  }
1237
1243
  const tool = this.deps.getTool(name);
1238
1244
  if (!tool) {
@@ -1257,7 +1263,9 @@ var Agent = class _Agent {
1257
1263
  *
1258
1264
  * 1. `maxAgentDepth` 防护——超限抛 {@link AgentRecursionError}
1259
1265
  * 2. sub-agent handler 导出 `run` 时调自定义 `mod.run(args)`(无 trace,与常规 tool 一致)
1260
- * 3. 无 `run` 时调 `subAgent.run(stringify(args), { enableTracing })` 走默认 reactLoop
1266
+ * 3. 无 `run` 时调 `subAgent.run(stringify(args), { agent, provider, model, enableTracing })`
1267
+ * 走默认 reactLoop——继承父调用的 provider,sub 元数据声明 `model` 时优先用自身的,
1268
+ * 未声明时沿用父 model
1261
1269
  *
1262
1270
  * **tracing 路径**:`enableTracing=true` 时,subAgent.run 返回的 `result.trace`(agentName
1263
1271
  * 已被 `Agent.run` 填为 subName)被包装为 [TracingToolResult](./trace.md) 返回给 reactLoop。
@@ -1275,14 +1283,13 @@ var Agent = class _Agent {
1275
1283
  * 而非 `getAgent`(返回 AgentCore,无代码加载细节)。DB skill 无文件,
1276
1284
  * `getAgentEntry` 返回 `undefined`,走默认 reactLoop。
1277
1285
  */
1278
- async executeSubAgent(subName, args, enableTracing) {
1286
+ async executeSubAgent(subName, args, callCtx) {
1279
1287
  const newDepth = this.depth + 1;
1280
1288
  const maxDepth = this.deps.config?.maxAgentDepth ?? DEFAULT_MAX_AGENT_DEPTH;
1281
1289
  if (newDepth > maxDepth) {
1282
1290
  throw new AgentRecursionError(maxDepth, newDepth);
1283
1291
  }
1284
- const subDeps = { ...this.deps, agentName: subName };
1285
- const subAgent = new _Agent(subDeps, newDepth);
1292
+ const subAgent = new _Agent(this.deps, newDepth);
1286
1293
  const entry = this.deps.getAgentEntry(subName);
1287
1294
  if (entry?.hasRun) {
1288
1295
  const mod = await this.deps.loadAgentModule(entry.filePath, entry.hasRun);
@@ -1292,11 +1299,15 @@ var Agent = class _Agent {
1292
1299
  return result2;
1293
1300
  }
1294
1301
  }
1302
+ const subMeta = this.deps.getAgent(subName);
1295
1303
  const result = await subAgent.run(typeof args === "string" ? args : JSON.stringify(args), {
1296
- enableTracing
1304
+ agent: subName,
1305
+ provider: callCtx.provider,
1306
+ model: subMeta?.model ?? callCtx.model,
1307
+ enableTracing: callCtx.enableTracing
1297
1308
  });
1298
1309
  this.deps.config?.afterToolCall?.(`agent.${subName}`, args, result.content, this.deps.ctx);
1299
- if (enableTracing && result.trace) {
1310
+ if (callCtx.enableTracing && result.trace) {
1300
1311
  return {
1301
1312
  __trace: true,
1302
1313
  result: result.content,
@@ -1344,10 +1355,9 @@ var agentPlugin = {
1344
1355
  const llms = agentConfig?.llms ?? {};
1345
1356
  if (Object.keys(llms).length === 0) {
1346
1357
  console.log(
1347
- "- @faapi/agent: no llms configured \u2014 use agent.run(input, { provider }) to pass an external provider per call"
1358
+ "- @faapi/agent: no llms configured \u2014 use agent.run(input, { agent, provider }) to pass an external provider per call"
1348
1359
  );
1349
1360
  }
1350
- const defaultAgent = agentConfig?.defaultAgent ?? "";
1351
1361
  const providers = /* @__PURE__ */ new Map();
1352
1362
  for (const [name, llmConfig] of Object.entries(llms)) {
1353
1363
  if (!llmConfig.apiKey || llmConfig.apiKey.trim() === "") {
@@ -1357,13 +1367,6 @@ var agentPlugin = {
1357
1367
  }
1358
1368
  providers.set(name, createProvider(llmConfig));
1359
1369
  }
1360
- const defaultLlm = agentConfig?.defaultLlm ?? Object.keys(llms)[0];
1361
- const defaultProvider = defaultLlm !== void 0 ? providers.get(defaultLlm) : void 0;
1362
- if (defaultLlm !== void 0 && !defaultProvider) {
1363
- console.warn(
1364
- `! @faapi/agent: config.agent.defaultLlm "${defaultLlm}" not found in llms \u2014 no default provider, use agent.run(input, { provider }) to pass an external provider per call`
1365
- );
1366
- }
1367
1370
  const runtimeConfig = {
1368
1371
  maxTurns: agentConfig?.maxTurns,
1369
1372
  maxAgentDepth: agentConfig?.maxAgentDepth,
@@ -1394,10 +1397,7 @@ var agentPlugin = {
1394
1397
  ctx.registries.agentHandle.register((ctx2) => {
1395
1398
  return new Agent({
1396
1399
  providers,
1397
- defaultProvider,
1398
1400
  llms,
1399
- defaultLlm,
1400
- agentName: defaultAgent ?? "",
1401
1401
  rootDir,
1402
1402
  config: runtimeConfig,
1403
1403
  // ctx 传递链(authHooks):捕获请求上下文,tool handler / sub-agent /
@@ -1418,7 +1418,7 @@ var agentPlugin = {
1418
1418
  });
1419
1419
  });
1420
1420
  console.log(
1421
- defaultProvider ? defaultAgent ? `- @faapi/agent: default agent "${defaultAgent}" (provider: ${defaultLlm}) available via agent parameter injection` : `- @faapi/agent: no defaultAgent set \u2014 use agent.run(input, { agent: 'name' }) to specify agent (provider: ${defaultLlm})` : "- @faapi/agent: no default provider \u2014 use agent.run(input, { provider }) to pass an external provider per call"
1421
+ Object.keys(llms).length > 0 ? `- @faapi/agent: providers [${Object.keys(llms).join(", ")}] \u2014 call agent.run(input, { agent, model }) to execute (no default agent/provider)` : "- @faapi/agent: no llms configured \u2014 use agent.run(input, { agent, provider }) to pass an external provider per call"
1422
1422
  );
1423
1423
  }
1424
1424
  };