@faapi/agent 4.2.1 → 4.4.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
@@ -114,9 +114,16 @@ interface LLMCompleteRequest {
114
114
  * 外部 `AbortSignal` 触发时抛出(请求前预检查或请求中断)。
115
115
  * 业务方通过 `instanceof AgentAbortError` 区分「用户取消」与真实错误——
116
116
  * 取消不是故障,不应触发告警/重试逻辑。
117
+ *
118
+ * `messages` 为中断时刻的部分对话历史(截至最后一个完整轮组),由
119
+ * [reactLoop](./reactLoop.md) 在循环边界附加(provider 层不感知历史,恒为空数组)。
120
+ * 业务方持久化后经 `config.messages` / `AgentRunOptions.messages` 从断点续跑,
121
+ * 语义详见 [reactLoop.md](./reactLoop.md) 中断恢复章节。
117
122
  */
118
123
  declare class AgentAbortError extends Error {
119
- constructor(message?: string);
124
+ /** 中断时刻的部分对话历史(完整轮组快照,可直接用于续跑) */
125
+ readonly messages: LLMMessage[];
126
+ constructor(message?: string, messages?: LLMMessage[]);
120
127
  }
121
128
  /**
122
129
  * LLM 响应的停止原因
@@ -375,6 +382,16 @@ interface ReactLoopConfig {
375
382
  * 消息副本,本地 `messages` 与 trace 不受影响。详见 reactLoop.md 的历史裁剪章节。
376
383
  */
377
384
  maxHistoryTokens?: number;
385
+ /**
386
+ * 初始对话历史(续跑 / 多轮对话)
387
+ *
388
+ * 提供时以其为基础(历史应含 system):历史无 `system` 消息且配置了
389
+ * `systemPrompt` 时自动在最前插入(agent 人格不因续跑丢失);`input` 非空时
390
+ * 追加为新的 `user` 消息(多轮对话),为空时纯续跑。历史经 `Agent` 层结构校验
391
+ * (assistant.toolCalls 与 tool 结果按 toolCallId 配对完整)。
392
+ * 续跑源见 [reactLoop.md](./reactLoop.md) 中断恢复章节。
393
+ */
394
+ messages?: LLMMessage[];
378
395
  /**
379
396
  * 启用 tracing(默认 true)。开启时填充 `ReactLoopResult.trace` /
380
397
  * `ReactLoopStreamChunk.traceEvent`,详见 [trace.md](./trace.md)。
@@ -447,32 +464,36 @@ interface ReactLoopStreamChunk {
447
464
  declare class ReactLoopError extends Error {
448
465
  /** 配置的 maxTurns 值 */
449
466
  readonly maxTurns: number;
450
- constructor(message: string, maxTurns: number);
467
+ /** 超限时的完整对话历史(业务方可提高 maxTurns 后经 `config.messages` 续跑,轮数重新计数) */
468
+ readonly messages: LLMMessage[];
469
+ constructor(message: string, maxTurns: number, messages?: LLMMessage[]);
451
470
  }
452
471
  /**
453
472
  * 执行 ReAct 循环(非流式)
454
473
  *
455
474
  * 反复调 `provider.complete()` → 执行 tool → 回传结果,直到 LLM 返回 `stop`(或其他非 `tool_calls` 原因)或超出 `maxTurns`。
456
475
  *
457
- * @param input 用户输入
476
+ * @param input 用户输入(续跑场景可为空,历史经 `config.messages` 提供)
458
477
  * @param config 循环配置
459
478
  * @returns 最终结果(content + messages + turns + stopReason + usage)
460
- * @throws {ReactLoopError} 超出 maxTurns
479
+ * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
480
+ * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
461
481
  * @throws {Error} provider.complete 抛错时立即传播
462
482
  */
463
- declare function reactLoop(input: string, config: ReactLoopConfig): Promise<ReactLoopResult>;
483
+ declare function reactLoop(input: string | undefined, config: ReactLoopConfig): Promise<ReactLoopResult>;
464
484
  /**
465
485
  * 执行 ReAct 循环(流式)
466
486
  *
467
487
  * 使用 `provider.stream()` 异步迭代 chunks,yield `deltaContent` + `toolCall` + `toolResult` + `done`。
468
488
  *
469
- * @param input 用户输入
489
+ * @param input 用户输入(续跑场景可为空,历史经 `config.messages` 提供)
470
490
  * @param config 循环配置
471
491
  * @yields {ReactLoopStreamChunk} 流式 chunk
472
- * @throws {ReactLoopError} 超出 maxTurns
492
+ * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
493
+ * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
473
494
  * @throws {Error} provider.stream 抛错时立即传播
474
495
  */
475
- declare function reactLoopStream(input: string, config: ReactLoopConfig): AsyncIterable<ReactLoopStreamChunk>;
496
+ declare function reactLoopStream(input: string | undefined, config: ReactLoopConfig): AsyncIterable<ReactLoopStreamChunk>;
476
497
 
477
498
  /**
478
499
  * agent handle——注入到 handler 的 `agent` 参数,提供可调用的 agent 运行入口
@@ -494,8 +515,9 @@ declare function reactLoopStream(input: string, config: ReactLoopConfig): AsyncI
494
515
  * }
495
516
  * ```
496
517
  *
497
- * 工厂未注册(`@faapi/agent` 插件未加载或 `config.agent.llm` / `defaultAgent` 未配置)
498
- * 时注入 `undefined`,handler 需自行处理。
518
+ * 仅在 `@faapi/agent` 插件未加载时注入 `undefined`,handler 需自行处理。
519
+ * `config.agent.llms` 未配置时工厂照常注册(外部 provider 模式)——
520
+ * `agent.run/stream` 需调用方传 `options.provider` 才能调用 LLM。
499
521
  *
500
522
  * 详见 [agentHandle.md](./agentHandle.md)。
501
523
  */
@@ -549,8 +571,29 @@ interface AgentRunOptions {
549
571
  * 切换 provider + model 的字符串 key(支持 llms key / `provider/model` / 纯 model 名)
550
572
  *
551
573
  * 不传时用 `defaultLlm` provider + agent 元数据 `config.model`。
574
+ * `provider` 字段存在时本字段变为「原始 model 名」原样透传给外部 provider
575
+ * (不做 llms key 解析,支持带 / 的 model id),详见 {@link AgentRunOptions.provider}。
552
576
  */
553
577
  model?: string;
578
+ /**
579
+ * 外部 provider(本次调用临时使用,优先级最高——完全不查 `config.agent.llms`)
580
+ *
581
+ * 两种形式(运行时按形状判别,两者皆非抛 `AgentError`):
582
+ * - `LlmConfig` 对象(含字符串 `provider` 字段)→ 现场调 `createProvider` 创建适配器
583
+ * (浅拷贝 + `models` 兜底 `{}`,不改调用方对象),适用于 BYOK(用户自带 apiKey)/
584
+ * 按请求指定 baseURL 网关
585
+ * - `LLMProvider` 实例(有 `complete` / `stream` 方法)→ 直接使用,适用于框架未内置
586
+ * 适配器的 LLM 服务(内部自研模型网关等)
587
+ *
588
+ * 传入时 `options.model` 语义变为「原始 model 名」——不做 llms key 解析、不拆 `/`,
589
+ * 原样透传给该 provider(支持 OpenRouter 等带 `/` 的 model id)。
590
+ * LlmConfig 形式下 `options.model` 缺省时回落该 config 的 `models` 第一个 key,
591
+ * 两者皆无抛 `AgentError`;LLMProvider 实例形式下可为 `undefined`(自定义 provider 自决)。
592
+ *
593
+ * 仅影响本次调用——不进 providers Map、不修改 agent 状态,**sub-agent 递归不继承**
594
+ * (sub-agent 仍走默认解析链路),下一次调用仍用默认配置。
595
+ */
596
+ provider?: LlmConfig | LLMProvider;
554
597
  /** 采样温度(透传给 LLM API,覆盖 provider/model 级 temperature) */
555
598
  temperature?: number;
556
599
  /** 最大生成 token 数(透传给 LLM API) */
@@ -563,6 +606,20 @@ interface AgentRunOptions {
563
606
  * 结构化调用明细,详见 [trace.md](./trace.md)。
564
607
  */
565
608
  enableTracing?: boolean;
609
+ /**
610
+ * 初始对话历史(续跑 / 多轮对话)
611
+ *
612
+ * 提供时以其为基础,agent 的 systemPrompt 缺失时自动补齐;`input` 非空时追加为
613
+ * 新的 user 消息(多轮对话),为空时纯续跑。续跑源:
614
+ * - `AgentAbortError.messages` —— 中断断点(客户端断开 / 请求取消)
615
+ * - `ReactLoopError.messages` —— maxTurns 超限(提高预算后续跑)
616
+ * - 上次 `result.messages` —— 多轮对话拼接
617
+ *
618
+ * 历史经结构校验(assistant.toolCalls 与 tool 结果按 toolCallId 配对完整、
619
+ * role 合法),非法抛 `AgentError`,不发起 LLM 请求。
620
+ * 语义详见 [reactLoop.md](./reactLoop.md) 中断恢复章节。
621
+ */
622
+ messages?: LLMMessage[];
566
623
  }
567
624
  interface AgentHandle {
568
625
  /**
@@ -571,30 +628,34 @@ interface AgentHandle {
571
628
  * 组装 ReAct 循环 config(systemPrompt + tools + maxTurns + 应用 `options` 覆盖)→ 调
572
629
  * [reactLoop](./reactLoop.md) → 返回最终结果。
573
630
  *
574
- * @param input 用户输入文本
575
- * @param options 临时覆盖本次调用的 model(字符串 key)/ temperature / maxTokens
576
- * (不修改 agent 自身状态,详见 {@link AgentRunOptions})
631
+ * @param input 用户输入文本(可选——续跑场景不传新输入;input 与
632
+ * `options.messages` 都为空时抛 `AgentError`)
633
+ * @param options 临时覆盖本次调用的 model(字符串 key)/ temperature / maxTokens /
634
+ * messages(不修改 agent 自身状态,详见 {@link AgentRunOptions})
577
635
  * @returns 循环结果(content + messages + turns + stopReason + usage)
578
- * @throws {AgentError} agent 未注册
579
- * @throws {ReactLoopError} 超出 maxTurns
636
+ * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
637
+ * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 可续跑)
638
+ * @throws {AgentAbortError} 中断(`error.messages` 为断点历史,可续跑)
580
639
  * @throws {Error} LLM provider 抛错时立即传播
581
640
  */
582
- run(input: string, options?: AgentRunOptions): Promise<ReactLoopResult>;
641
+ run(input?: string, options?: AgentRunOptions): Promise<ReactLoopResult>;
583
642
  /**
584
643
  * 流式执行 agent
585
644
  *
586
645
  * 组装 config(应用 `options` 覆盖)→ 调 [reactLoopStream](./reactLoop.md) → yield 流式 chunk。
587
646
  * 适用于 LLM token 流式输出、tool 调用过程展示等场景。
588
647
  *
589
- * @param input 用户输入文本
590
- * @param options 临时覆盖本次调用的 model(字符串 key)/ temperature / maxTokens
591
- * (不修改 agent 自身状态,详见 {@link AgentRunOptions})
648
+ * @param input 用户输入文本(可选——续跑场景不传新输入;input 与
649
+ * `options.messages` 都为空时抛 `AgentError`)
650
+ * @param options 临时覆盖本次调用的 model(字符串 key)/ temperature / maxTokens /
651
+ * messages(不修改 agent 自身状态,详见 {@link AgentRunOptions})
592
652
  * @yields 流式 chunk(deltaContent / toolCall / toolResult / done)
593
- * @throws {AgentError} agent 未注册
594
- * @throws {ReactLoopError} 超出 maxTurns
653
+ * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
654
+ * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 可续跑)
655
+ * @throws {AgentAbortError} 中断(`error.messages` 为断点历史,可续跑)
595
656
  * @throws {Error} LLM provider 抛错时立即传播
596
657
  */
597
- stream(input: string, options?: AgentRunOptions): AsyncIterable<ReactLoopStreamChunk>;
658
+ stream(input?: string, options?: AgentRunOptions): AsyncIterable<ReactLoopStreamChunk>;
598
659
  /**
599
660
  * 把自身包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
600
661
  *
@@ -696,14 +757,19 @@ interface ToolSchemaResolution {
696
757
  * 访问器签名与 faapi 核心对称(见 [agent.md](./agent.md) 依赖注入章节)。
697
758
  */
698
759
  interface AgentDeps {
699
- /** LLM provider 实例映射(key 是 provider 名,来自 config.agent.llms) */
760
+ /** LLM provider 实例映射(key 是 provider 名,来自 config.agent.llms;未配置时为空 Map) */
700
761
  providers: Map<string, LLMProvider>;
701
- /** 默认 provider 实例(config.agent.defaultLlm 对应,或 llms 第一个 key) */
702
- defaultProvider: LLMProvider;
703
- /** LLM provider 配置映射(含 models,用于 options.model key 解析) */
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
+ /** LLM provider 配置映射(含 models,用于 options.model key 解析;llms 未配置时为空对象) */
704
770
  llms: Record<string, LlmConfig>;
705
- /** 默认 provider key(config.agent.defaultLlm,或 llms 第一个 key) */
706
- defaultLlm: string;
771
+ /** 默认 provider key(config.agent.defaultLlm,或 llms 第一个 key;llms 未配置时为 undefined) */
772
+ defaultLlm?: string;
707
773
  /** 当前 agent 名 */
708
774
  agentName: string;
709
775
  /** 项目根目录(Phase 3.5 接线时用于加载器) */
@@ -786,27 +852,33 @@ declare class Agent {
786
852
  * reactLoop 不知 agent 名(只关心循环逻辑),返回的 `result.trace.agentName` 为空字符串。
787
853
  * 本方法在 reactLoop 返回后填充 `this.deps.agentName`,让顶层 trace 标识"是哪个 agent 跑的"。
788
854
  *
789
- * @param input 用户输入
790
- * @param options 临时覆盖本次调用的 model(字符串 key)/ temperature / maxTokens / enableTracing
855
+ * @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
856
+ * 都为空时抛 `AgentError`)
857
+ * @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
858
+ * temperature / maxTokens / messages / enableTracing
791
859
  * (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
792
860
  * @returns 最终结果(content + messages + turns + stopReason + usage + trace?)
793
- * @throws {AgentError} agent 未注册
794
- * @throws {ReactLoopError} 超出 maxTurns
861
+ * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
862
+ * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
863
+ * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
795
864
  * @throws {Error} provider.complete 抛错时立即传播
796
865
  */
797
- run(input: string, options?: AgentRunOptions): Promise<ReactLoopResult>;
866
+ run(input?: string, options?: AgentRunOptions): Promise<ReactLoopResult>;
798
867
  /**
799
868
  * 流式执行——组装 config 调 [reactLoopStream](./reactLoop.md)
800
869
  *
801
- * @param input 用户输入
802
- * @param options 临时覆盖本次调用的 model(字符串 key)/ temperature / maxTokens
870
+ * @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
871
+ * 都为空时抛 `AgentError`)
872
+ * @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
873
+ * temperature / maxTokens / messages
803
874
  * (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
804
875
  * @yields 流式 chunk(deltaContent / toolCall / toolResult / done)
805
- * @throws {AgentError} agent 未注册
806
- * @throws {ReactLoopError} 超出 maxTurns
876
+ * @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
877
+ * @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
878
+ * @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
807
879
  * @throws {Error} provider.stream 抛错时立即传播
808
880
  */
809
- stream(input: string, options?: AgentRunOptions): AsyncIterable<ReactLoopStreamChunk>;
881
+ stream(input?: string, options?: AgentRunOptions): AsyncIterable<ReactLoopStreamChunk>;
810
882
  /**
811
883
  * 把自身包装为 `AgentToolDescriptor` 供 LLM 当 tool 调用
812
884
  *
@@ -835,7 +907,9 @@ declare class Agent {
835
907
  * 3. buildToolDefinitions 组装 tool 列表(用有效 agent 名查 tools / sub-agents)
836
908
  * 4. config 字段优先级(高 → 低):`options` > agent 元数据 > 全局 AgentRuntimeConfig / deps.defaultProvider
837
909
  *
838
- * `options.model` 是字符串 key,由 {@link resolveModelKey} 解析为 provider + model
910
+ * `options.provider`(外部 provider)存在时由 {@link resolveExternalProvider} 物化,
911
+ * 优先级最高——`options.model` 变为原始 model 名原样透传(不解析 llms key)。
912
+ * 否则 `options.model` 是字符串 key,由 {@link resolveModelKey} 解析为 provider + model
839
913
  * (支持 llms key 精确匹配 / `provider/model` 一体化 / 纯 model 名模糊匹配)。
840
914
  * 不传 `options.model` 时用 `deps.defaultProvider` + agent 元数据 `config.model`。
841
915
  * 详见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」。
@@ -843,13 +917,34 @@ declare class Agent {
843
917
  * `options.agent` 覆盖本次调用的 agent 名——不传时用 `deps.agentName`(来自
844
918
  * `config.agent.defaultAgent`)。`defaultAgent` 未设且 `options.agent` 未传时抛
845
919
  * `AgentError`。
920
+ *
921
+ * **输入守卫**(续跑入口,见 [reactLoop.md](./reactLoop.md) 中断恢复章节):
922
+ * `input` 与 `options.messages` 都为空时抛 `AgentError`(不发送空请求);
923
+ * `options.messages` 提供时先经 `validateResumeHistory` 结构校验,非法抛
924
+ * `AgentError`,不发起 LLM 请求。
846
925
  */
847
926
  private buildLoopConfig;
927
+ /**
928
+ * 解析外部 provider(`options.provider`)→ provider + model
929
+ *
930
+ * 规则见 [agentHandle.md](./agentHandle.md) 的「`options.provider` 外部 provider」章节:
931
+ * - `LLMProvider` 实例 → 直接使用,`modelKey` 原样透传(可为 `undefined`,自定义 provider 自决)
932
+ * - `LlmConfig` 配置对象 → `createProvider` 现场创建,`modelKey` 原样透传;
933
+ * 缺省回落该 config `models` 第一个 key,两者皆无抛 `AgentError`(早失败,不发请求)
934
+ * - `modelKey` 不做 llms key 解析、不拆 `/`(支持 OpenRouter 等带斜杠的 model id)
935
+ *
936
+ * 仅本次调用生效:不进 providers Map、sub-agent 递归不继承(executeSubAgent 构造
937
+ * subDeps 时不携带 options,sub-agent 走默认解析链路)。
938
+ *
939
+ * @throws {AgentError} provider 形式非法;LlmConfig 形式下 model 缺失
940
+ */
941
+ private resolveExternalProvider;
848
942
  /**
849
943
  * 解析 `options.model` 字符串 key → provider + model
850
944
  *
851
945
  * 规则见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」:
852
- * 1. `undefined` → `deps.defaultProvider` + `meta.model`
946
+ * 1. `undefined` → `deps.defaultProvider`(未配置时抛 `AgentError`——外部 provider 模式
947
+ * 要求调用方传 `options.provider`)+ `meta.model`
853
948
  * 2. 精确匹配 `deps.providers` 的 key → 该 provider + 其 `models` 第一个 key
854
949
  * 3. 含 `/` → `provider/model` 形式,`deps.providers.get(provider)` + 该 model
855
950
  * (要求该 model 在 `deps.llms[provider].models` 里)
@@ -858,7 +953,8 @@ declare class Agent {
858
953
  * - 多个 → 抛 `AgentError`(要求用 `provider/model` 消歧)
859
954
  * - 无 → 抛 `AgentError`
860
955
  *
861
- * @throws {AgentError} key 解析失败(provider/model 不存在或歧义)
956
+ * @throws {AgentError} key 解析失败(provider/model 不存在或歧义);deps.defaultProvider
957
+ * 未配置(外部 provider 模式下调用方未传 options.provider)
862
958
  */
863
959
  private resolveModelKey;
864
960
  /**
@@ -942,16 +1038,17 @@ declare class Agent {
942
1038
  * ```
943
1039
  *
944
1040
  * 插件 setup 时:
945
- * 1. 遍历 `config.agent.llms` 每项调 `createProvider` → `Map<providerKey, LLMProvider>`
946
- * 2. 读 `config.agent.defaultLlm` → `defaultProvider`(未设时用 `llms` 第一个 key
1041
+ * 1. 遍历 `config.agent.llms`(可选)→ 每项调 `createProvider` → `Map<providerKey, LLMProvider>`
1042
+ * 2. 读 `config.agent.defaultLlm` → `defaultProvider`(未设时用 `llms` 第一个 key;
1043
+ * `llms` 未配置/未命中时为 `undefined`——外部 provider 模式,照常注册工厂)
947
1044
  * 3. 读 `config.agent.defaultAgent`(可选) / `maxTurns` / `maxAgentDepth`
948
1045
  * 4. 从 `@faapi/faapi` import 注册表/加载器访问器(getAgent / getTool / resolveAgentTools /
949
1046
  * resolveSubAgents / loadAgentModule / loadToolModule)
950
1047
  * 5. `registerAgentHandleFactory` 注册工厂——每次请求时构造 [Agent](./agent.md) 实例注入到
951
1048
  * handler 的 `agent` 参数
952
1049
  *
953
- * 配置缺失时(`agent.llms` 未设置)跳过工厂注册并打印警告,
954
- * handler `agent` 参数注入 `undefined`。
1050
+ * `agent.llms` 可选——未配置时工厂照常注册(外部 provider 模式),`agent.run/stream`
1051
+ * 需调用方传 `options.provider` 才能调用 LLM。只有插件未加载时 `agent` 参数才注入 `undefined`。
955
1052
  *
956
1053
  * `defaultAgent` 可选——未设时 handler 需通过 `agent.run(input, { agent: 'name' })`
957
1054
  * 显式指定 agent 名。