@faapi/agent 4.4.0 → 4.5.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/README.md CHANGED
@@ -44,12 +44,13 @@ import type { FaapiConfig } from '@faapi/faapi';
44
44
 
45
45
  export default {
46
46
  agent: {
47
- llm: {
48
- provider: 'openai',
49
- apiKey: process.env.OPENAI_API_KEY,
50
- model: 'gpt-4o',
47
+ llms: {
48
+ openai: {
49
+ provider: 'openai',
50
+ apiKey: process.env.OPENAI_API_KEY,
51
+ models: { 'gpt-4o': {} },
52
+ },
51
53
  },
52
- defaultAgent: 'researcher',
53
54
  maxTurns: 10,
54
55
  maxAgentDepth: 3,
55
56
  },
@@ -57,6 +58,18 @@ export default {
57
58
  } satisfies FaapiConfig;
58
59
  ```
59
60
 
61
+ 无默认 agent / 默认 provider——handler 调用时显式指定 agent 名与 model/provider:
62
+
63
+ ```ts
64
+ // src/api/chat/handler.ts
65
+ import type { AgentHandle } from '@faapi/agent';
66
+
67
+ export async function POST(agent: AgentHandle, body: { input: string }) {
68
+ const result = await agent.run(body.input, { agent: 'researcher', model: 'gpt-4o' });
69
+ return { content: result.content, turns: result.turns };
70
+ }
71
+ ```
72
+
60
73
  CLI 启动时动态加载——未安装时自动跳过,不影响核心功能。需单独安装:`pnpm add @faapi/agent`。
61
74
 
62
75
  ## 多 agent 组织
package/dist/index.d.ts CHANGED
@@ -510,7 +510,7 @@ declare function reactLoopStream(input: string | undefined, config: ReactLoopCon
510
510
  *
511
511
  * // src/api/chat/handler.ts
512
512
  * export function POST(agent: AgentHandle, body: { input: string }) {
513
- * const result = await agent.run(body.input);
513
+ * const result = await agent.run(body.input, { agent: 'researcher', model: 'gpt-4o' });
514
514
  * return { content: result.content, turns: result.turns };
515
515
  * }
516
516
  * ```
@@ -518,14 +518,15 @@ declare function reactLoopStream(input: string | undefined, config: ReactLoopCon
518
518
  * 仅在 `@faapi/agent` 插件未加载时注入 `undefined`,handler 需自行处理。
519
519
  * `config.agent.llms` 未配置时工厂照常注册(外部 provider 模式)——
520
520
  * `agent.run/stream` 需调用方传 `options.provider` 才能调用 LLM。
521
+ * 无默认 agent——每次 `run` / `stream` 必须显式传 `options.agent`。
521
522
  *
522
523
  * 详见 [agentHandle.md](./agentHandle.md)。
523
524
  */
524
525
  /**
525
- * `agent.run` / `agent.stream` 的 options 参数——临时覆盖本次调用的 LLM 配置
526
+ * `agent.run` / `agent.stream` 的 options 参数——本次调用的 LLM 配置
526
527
  *
527
- * 所有字段可选,不传或 `undefined` 时回落到下一优先级(agent 元数据 → 全局配置)。
528
- * **不修改 agent 自身状态**——下一次调用仍用默认配置。
528
+ * `agent` 必须显式传(无默认 agent);其余字段可选,不传或 `undefined` 时回落到
529
+ * 下一优先级(agent 元数据 → 全局配置)。**不修改 agent 自身状态**。
529
530
  *
530
531
  * `model` 是字符串 key,支持三种形式(解析规则见 [agentHandle.md](./agentHandle.md) 的
531
532
  * 「`options.model` 字符串 key 解析规则」):
@@ -533,23 +534,20 @@ declare function reactLoopStream(input: string | undefined, config: ReactLoopCon
533
534
  * - `provider/model` 一体化(如 `'openai/gpt-4o'`)
534
535
  * - 纯 model 名(如 `'gpt-4o'`)—— 在所有 provider 的 `models` 里查找,唯一时切到对应 provider
535
536
  *
537
+ * 不传 `model` 时用 agent 元数据 `config.model` 作为缺省 key 参与同一套解析。
536
538
  * 优先级(高 → 低):`options` > agent 元数据(`config.model` / `config.maxTurns`)> 全局
537
- * `AgentRuntimeConfig` / `defaultLlm` provider。详见 [agentHandle.md](./agentHandle.md) 的
538
- * Run-level 覆盖优先级表。
539
- *
540
- * `agent` 字段覆盖本次调用的 agent 名(不传时用 `config.agent.defaultAgent`,
541
- * 未设 defaultAgent 时必须显式传入)。
539
+ * `AgentRuntimeConfig`。详见 [agentHandle.md](./agentHandle.md) 的 Run-level 覆盖优先级表。
542
540
  *
543
541
  * @example
544
542
  * ```ts
543
+ * // 指定 agent(必须——无默认 agent)
544
+ * await agent.run(input, { agent: 'researcher' });
545
+ *
545
546
  * // 按请求切模型(纯 model 名,在 llms 里唯一时切到对应 provider)
546
- * await agent.run(input, { model: 'gpt-4o-mini' });
547
+ * await agent.run(input, { agent: 'researcher', model: 'gpt-4o-mini' });
547
548
  *
548
549
  * // provider/model 一体化形式(精确切换)
549
- * await agent.run(input, { model: 'anthropic/claude-3-5-sonnet' });
550
- *
551
- * // 指定 agent(不依赖 defaultAgent 配置)
552
- * await agent.run(input, { agent: 'researcher' });
550
+ * await agent.run(input, { agent: 'researcher', model: 'anthropic/claude-3-5-sonnet' });
553
551
  * ```
554
552
  */
555
553
  interface AgentRunOptions {
@@ -561,16 +559,17 @@ interface AgentRunOptions {
561
559
  */
562
560
  signal?: AbortSignal;
563
561
  /**
564
- * 覆盖本次调用的 agent 名(从 agentRegistry 查找对应元数据 / tools / sub-agents)
562
+ * 本次调用的 agent 名(必须显式传——config.agent defaultAgent 默认值)
565
563
  *
566
- * 不传时用 `config.agent.defaultAgent`。`defaultAgent` 未设时必须显式传入,
567
- * 否则抛 `AgentError`。
564
+ * agentRegistry 查找对应元数据 / tools / sub-agents。
565
+ * 不传抛 `AgentError`。
568
566
  */
569
567
  agent?: string;
570
568
  /**
571
569
  * 切换 provider + model 的字符串 key(支持 llms key / `provider/model` / 纯 model 名)
572
570
  *
573
- * 不传时用 `defaultLlm` provider + agent 元数据 `config.model`。
571
+ * 不传时用 agent 元数据 `config.model` 作为缺省 key 参与解析;
572
+ * 两者皆无且未传 `provider` 时抛 `AgentError`(无默认 provider)。
574
573
  * `provider` 字段存在时本字段变为「原始 model 名」原样透传给外部 provider
575
574
  * (不做 llms key 解析,支持带 / 的 model id),详见 {@link AgentRunOptions.provider}。
576
575
  */
@@ -590,8 +589,9 @@ interface AgentRunOptions {
590
589
  * LlmConfig 形式下 `options.model` 缺省时回落该 config 的 `models` 第一个 key,
591
590
  * 两者皆无抛 `AgentError`;LLMProvider 实例形式下可为 `undefined`(自定义 provider 自决)。
592
591
  *
593
- * 仅影响本次调用——不进 providers Map、不修改 agent 状态,**sub-agent 递归不继承**
594
- * sub-agent 仍走默认解析链路),下一次调用仍用默认配置。
592
+ * 仅影响本次调用——不进 providers Map、不修改 agent 状态。
593
+ * **sub-agent 递归继承父调用解析出的 provider**(sub 的 model 用其元数据声明的
594
+ * `config.model`,未声明时沿用父 model),不继承 options 对象本身。
595
595
  */
596
596
  provider?: LlmConfig | LLMProvider;
597
597
  /** 采样温度(透传给 LLM API,覆盖 provider/model 级 temperature) */
@@ -657,14 +657,15 @@ interface AgentHandle {
657
657
  */
658
658
  stream(input?: string, options?: AgentRunOptions): AsyncIterable<ReactLoopStreamChunk>;
659
659
  /**
660
- * 把自身包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
660
+ * 把指定 agent 包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
661
661
  *
662
- * 用于 agent-as-tool 场景:父 agent 把子 agent 包装为 tool,
662
+ * 用于 agent-as-tool 场景:把 agent 包装为 tool,
663
663
  * 加入 LLM 可见 tool 列表,LLM 调用时触发 sub-agent 递归执行。
664
664
  *
665
+ * @param name agent 名(显式指定——无默认 agent)
665
666
  * @returns `AgentToolDescriptor` 或 `undefined`(agent 未注册)
666
667
  */
667
- asTool(): AgentToolDescriptor | undefined;
668
+ asTool(name: string): AgentToolDescriptor | undefined;
668
669
  }
669
670
 
670
671
  /**
@@ -759,19 +760,8 @@ interface ToolSchemaResolution {
759
760
  interface AgentDeps {
760
761
  /** LLM provider 实例映射(key 是 provider 名,来自 config.agent.llms;未配置时为空 Map) */
761
762
  providers: Map<string, LLMProvider>;
762
- /**
763
- * 默认 provider 实例(config.agent.defaultLlm 对应,或 llms 第一个 key)
764
- *
765
- * 可选——config.agent.llms 未配置时为 undefined(外部 provider 模式),
766
- * 此时 run/stream 必须传 options.provider,否则 resolveModelKey 抛 AgentError。
767
- */
768
- defaultProvider?: LLMProvider;
769
763
  /** LLM provider 配置映射(含 models,用于 options.model key 解析;llms 未配置时为空对象) */
770
764
  llms: Record<string, LlmConfig>;
771
- /** 默认 provider key(config.agent.defaultLlm,或 llms 第一个 key;llms 未配置时为 undefined) */
772
- defaultLlm?: string;
773
- /** 当前 agent 名 */
774
- agentName: string;
775
765
  /** 项目根目录(Phase 3.5 接线时用于加载器) */
776
766
  rootDir: string;
777
767
  /** 全局 agent 配置覆盖 */
@@ -842,7 +832,7 @@ declare class Agent {
842
832
  */
843
833
  private readonly schemaCache;
844
834
  /**
845
- * @param deps 运行时依赖(访问器 + providers Map + defaultProvider + llms + config)
835
+ * @param deps 运行时依赖(访问器 + providers Map + llms + config)
846
836
  * @param depth 递归深度(默认 1 = 根 agent;sub-agent 递归时传入 depth+1)
847
837
  */
848
838
  constructor(deps: AgentDeps, depth?: number);
@@ -850,15 +840,17 @@ declare class Agent {
850
840
  * 非流式执行——组装 config 调 [reactLoop](./reactLoop.md)
851
841
  *
852
842
  * reactLoop 不知 agent 名(只关心循环逻辑),返回的 `result.trace.agentName` 为空字符串。
853
- * 本方法在 reactLoop 返回后填充 `this.deps.agentName`,让顶层 trace 标识"是哪个 agent 跑的"。
843
+ * 本方法在 reactLoop 返回后填充 `options.agent`,让顶层 trace 标识"是哪个 agent 跑的"。
854
844
  *
855
845
  * @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
856
846
  * 都为空时抛 `AgentError`)
857
- * @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
858
- * temperature / maxTokens / messages / enableTracing
847
+ * @param options 本次调用配置——`agent`(agent 名,必须显式传,无默认 agent)/
848
+ * provider(外部 provider)/ model(字符串 key)/ temperature /
849
+ * maxTokens / messages / enableTracing
859
850
  * (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
860
851
  * @returns 最终结果(content + messages + turns + stopReason + usage + trace?)
861
- * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
852
+ * @throws {AgentError} 未传 options.agent;agent 未注册;input 与 messages 都为空;
853
+ * 续跑历史结构非法;provider/model 无法解析
862
854
  * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
863
855
  * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
864
856
  * @throws {Error} provider.complete 抛错时立即传播
@@ -869,25 +861,27 @@ declare class Agent {
869
861
  *
870
862
  * @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
871
863
  * 都为空时抛 `AgentError`)
872
- * @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
864
+ * @param options 本次调用配置——`agent`(必须显式传)/ provider / model /
873
865
  * temperature / maxTokens / messages
874
866
  * (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
875
867
  * @yields 流式 chunk(deltaContent / toolCall / toolResult / done)
876
- * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
868
+ * @throws {AgentError} 未传 options.agent;agent 未注册;input 与 messages 都为空;
869
+ * 续跑历史结构非法;provider/model 无法解析
877
870
  * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
878
871
  * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
879
872
  * @throws {Error} provider.stream 抛错时立即传播
880
873
  */
881
874
  stream(input?: string, options?: AgentRunOptions): AsyncIterable<ReactLoopStreamChunk>;
882
875
  /**
883
- * 把自身包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
876
+ * 把指定 agent 包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
884
877
  *
885
878
  * 与 [agentRegistry.asTool](../../faapi/src/injection/agentRegistry.md) 同构——
886
879
  * Agent 类自带此方法便于在注入器场景直接调用(不必再过注册表)。
887
880
  *
881
+ * @param name agent 名(显式指定——无默认 agent)
888
882
  * @returns `AgentToolDescriptor` 或 `undefined`(agent 未注册)
889
883
  */
890
- asTool(): AgentToolDescriptor | undefined;
884
+ asTool(name: string): AgentToolDescriptor | undefined;
891
885
  /**
892
886
  * 查询 tool schema(带缓存)
893
887
  *
@@ -901,23 +895,19 @@ declare class Agent {
901
895
  /**
902
896
  * 组装 ReactLoopConfig
903
897
  *
904
- * 1. 解析有效 agent 名:`options.agent` > `deps.agentName`(`config.agent.defaultAgent`)
898
+ * 1. 解析有效 agent 名:`options.agent`(必须显式传——无默认 agent,不传抛 AgentError)
905
899
  * 2. 查 agent 元数据(未注册抛 AgentError)——用 `getAgent` 拿 AgentCore
906
900
  * (LLM-facing 字段:systemPrompt / model / maxTurns)
907
901
  * 3. buildToolDefinitions 组装 tool 列表(用有效 agent 名查 tools / sub-agents)
908
- * 4. config 字段优先级(高 → 低):`options` > agent 元数据 > 全局 AgentRuntimeConfig / deps.defaultProvider
902
+ * 4. config 字段优先级(高 → 低):`options` > agent 元数据 > 全局 AgentRuntimeConfig
909
903
  *
910
904
  * `options.provider`(外部 provider)存在时由 {@link resolveExternalProvider} 物化,
911
905
  * 优先级最高——`options.model` 变为原始 model 名原样透传(不解析 llms key)。
912
906
  * 否则 `options.model` 是字符串 key,由 {@link resolveModelKey} 解析为 provider + model
913
- * (支持 llms key 精确匹配 / `provider/model` 一体化 / 纯 model 名模糊匹配)。
914
- * 不传 `options.model` 时用 `deps.defaultProvider` + agent 元数据 `config.model`。
907
+ * (支持 llms key 精确匹配 / `provider/model` 一体化 / 纯 model 名模糊匹配;
908
+ * 未传 `options.model` 时用 agent 元数据 `config.model` 作为缺省 key)。
915
909
  * 详见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」。
916
910
  *
917
- * `options.agent` 覆盖本次调用的 agent 名——不传时用 `deps.agentName`(来自
918
- * `config.agent.defaultAgent`)。`defaultAgent` 未设且 `options.agent` 未传时抛
919
- * `AgentError`。
920
- *
921
911
  * **输入守卫**(续跑入口,见 [reactLoop.md](./reactLoop.md) 中断恢复章节):
922
912
  * `input` 与 `options.messages` 都为空时抛 `AgentError`(不发送空请求);
923
913
  * `options.messages` 提供时先经 `validateResumeHistory` 结构校验,非法抛
@@ -942,19 +932,20 @@ declare class Agent {
942
932
  /**
943
933
  * 解析 `options.model` 字符串 key → provider + model
944
934
  *
945
- * 规则见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」:
946
- * 1. `undefined` `deps.defaultProvider`(未配置时抛 `AgentError`——外部 provider 模式
947
- * 要求调用方传 `options.provider`)+ `meta.model`
948
- * 2. 精确匹配 `deps.providers` 的 key → 该 provider + 其 `models` 第一个 key
949
- * 3. `/` `provider/model` 形式,`deps.providers.get(provider)` + 该 model
935
+ * 规则见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」。
936
+ * 无默认 provider——`key` 未传时用 agent 元数据 `config.model` 作为缺省 key;
937
+ * 两者皆无抛 `AgentError`(要求调用方传 `options.model` `options.provider`)。
938
+ * 1. 精确匹配 `deps.providers` 的 key → 该 provider + 其 `models` 第一个 key
939
+ * (该 provider 未声明 `models` 时回落 `meta.model`)
940
+ * 2. 含 `/` → `provider/model` 形式,`deps.providers.get(provider)` + 该 model
950
941
  * (要求该 model 在 `deps.llms[provider].models` 里)
951
- * 4. 不含 `/` 且非 provider key → 在所有 provider 的 `models` 里按 model 名查找
942
+ * 3. 不含 `/` 且非 provider key → 在所有 provider 的 `models` 里按 model 名查找
952
943
  * - 唯一 → 该 provider + 该 model
953
944
  * - 多个 → 抛 `AgentError`(要求用 `provider/model` 消歧)
954
945
  * - 无 → 抛 `AgentError`
955
946
  *
956
- * @throws {AgentError} key 解析失败(provider/model 不存在或歧义);deps.defaultProvider
957
- * 未配置(外部 provider 模式下调用方未传 options.provider)
947
+ * @throws {AgentError} key 与 `meta.model` 均缺省;key 解析失败(provider/model
948
+ * 不存在或歧义)
958
949
  */
959
950
  private resolveModelKey;
960
951
  /**
@@ -977,8 +968,9 @@ declare class Agent {
977
968
  * - `agent.` 前缀 → {@link executeSubAgent} 递归(含 enableTracing + TracingToolResult 包装)
978
969
  * - 常规 tool → `loadToolModule` 加载 handler + 可选 input 校验 → 调用
979
970
  *
980
- * `enableTracing` 由 [buildLoopConfig](#buildLoopConfig) 闭包捕获传入,用于 sub-agent
981
- * 调用时决定是否包装 [TracingToolResult](./trace.md) 携带 sub-trace。
971
+ * `callCtx` 由 [buildLoopConfig](#buildLoopConfig) 闭包捕获传入——本次调用的有效
972
+ * agent 名(白名单校验)、enableTracing(sub-agent tracing 包装)与解析出的
973
+ * provider/model(sub-agent 递归继承)。常规 tool 不需要 tracing 包装,直接返回结果。
982
974
  *
983
975
  * **常规 tool 校验失败**:不抛错,返回 `{ error }` 对象——reactLoop stringify 后
984
976
  * 作为 tool 结果回传 LLM,LLM 可据此修正参数重试。
@@ -991,7 +983,9 @@ declare class Agent {
991
983
  *
992
984
  * 1. `maxAgentDepth` 防护——超限抛 {@link AgentRecursionError}
993
985
  * 2. sub-agent handler 导出 `run` 时调自定义 `mod.run(args)`(无 trace,与常规 tool 一致)
994
- * 3. 无 `run` 时调 `subAgent.run(stringify(args), { enableTracing })` 走默认 reactLoop
986
+ * 3. 无 `run` 时调 `subAgent.run(stringify(args), { agent, provider, model, enableTracing })`
987
+ * 走默认 reactLoop——继承父调用的 provider,sub 元数据声明 `model` 时优先用自身的,
988
+ * 未声明时沿用父 model
995
989
  *
996
990
  * **tracing 路径**:`enableTracing=true` 时,subAgent.run 返回的 `result.trace`(agentName
997
991
  * 已被 `Agent.run` 填为 subName)被包装为 [TracingToolResult](./trace.md) 返回给 reactLoop。
@@ -1029,8 +1023,6 @@ declare class Agent {
1029
1023
  * models: { 'gpt-4o': {}, 'gpt-4o-mini': { temperature: 0.5 } },
1030
1024
  * },
1031
1025
  * },
1032
- * defaultLlm: 'openai',
1033
- * defaultAgent: 'researcher',
1034
1026
  * maxTurns: 10,
1035
1027
  * },
1036
1028
  * plugins: ['@faapi/agent'],
@@ -1039,20 +1031,18 @@ declare class Agent {
1039
1031
  *
1040
1032
  * 插件 setup 时:
1041
1033
  * 1. 遍历 `config.agent.llms`(可选)→ 每项调 `createProvider` → `Map<providerKey, LLMProvider>`
1042
- * 2. 读 `config.agent.defaultLlm` `defaultProvider`(未设时用 `llms` 第一个 key;
1043
- * `llms` 未配置/未命中时为 `undefined`——外部 provider 模式,照常注册工厂)
1044
- * 3. 读 `config.agent.defaultAgent`(可选) / `maxTurns` / `maxAgentDepth`
1045
- * 4. 从 `@faapi/faapi` import 注册表/加载器访问器(getAgent / getTool / resolveAgentTools /
1034
+ * 2. 读 `config.agent.maxTurns` / `maxAgentDepth`
1035
+ * 3. 从 `@faapi/faapi` import 注册表/加载器访问器(getAgent / getTool / resolveAgentTools /
1046
1036
  * resolveSubAgents / loadAgentModule / loadToolModule)
1047
- * 5. `registerAgentHandleFactory` 注册工厂——每次请求时构造 [Agent](./agent.md) 实例注入到
1037
+ * 4. `registerAgentHandleFactory` 注册工厂——每次请求时构造 [Agent](./agent.md) 实例注入到
1048
1038
  * handler 的 `agent` 参数
1049
1039
  *
1040
+ * 无默认 agent / 默认 provider——`agent.run/stream` 每次调用显式传 `options.agent` +
1041
+ * `options.model` / `options.provider`。
1042
+ *
1050
1043
  * `agent.llms` 可选——未配置时工厂照常注册(外部 provider 模式),`agent.run/stream`
1051
1044
  * 需调用方传 `options.provider` 才能调用 LLM。只有插件未加载时 `agent` 参数才注入 `undefined`。
1052
1045
  *
1053
- * `defaultAgent` 可选——未设时 handler 需通过 `agent.run(input, { agent: 'name' })`
1054
- * 显式指定 agent 名。
1055
- *
1056
1046
  * 详见 [plugin.md](./plugin.md)。
1057
1047
  */
1058
1048