@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 +142 -45
- package/dist/index.js +194 -65
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -419,9 +419,12 @@ function finalizeStreamChunk(accumulators, finishReason, usage) {
|
|
|
419
419
|
|
|
420
420
|
// src/provider.ts
|
|
421
421
|
var AgentAbortError = class extends Error {
|
|
422
|
-
|
|
422
|
+
/** 中断时刻的部分对话历史(完整轮组快照,可直接用于续跑) */
|
|
423
|
+
messages;
|
|
424
|
+
constructor(message = "Agent execution aborted", messages = []) {
|
|
423
425
|
super(message);
|
|
424
426
|
this.name = "AgentAbortError";
|
|
427
|
+
this.messages = messages;
|
|
425
428
|
}
|
|
426
429
|
};
|
|
427
430
|
function createProvider(config) {
|
|
@@ -442,10 +445,13 @@ function isTracingToolResult(value) {
|
|
|
442
445
|
var ReactLoopError = class extends Error {
|
|
443
446
|
/** 配置的 maxTurns 值 */
|
|
444
447
|
maxTurns;
|
|
445
|
-
|
|
448
|
+
/** 超限时的完整对话历史(业务方可提高 maxTurns 后经 `config.messages` 续跑,轮数重新计数) */
|
|
449
|
+
messages;
|
|
450
|
+
constructor(message, maxTurns, messages = []) {
|
|
446
451
|
super(message);
|
|
447
452
|
this.name = "ReactLoopError";
|
|
448
453
|
this.maxTurns = maxTurns;
|
|
454
|
+
this.messages = messages;
|
|
449
455
|
}
|
|
450
456
|
};
|
|
451
457
|
var DEFAULT_MAX_TURNS = 10;
|
|
@@ -474,6 +480,19 @@ function buildInitialMessages(input, systemPrompt) {
|
|
|
474
480
|
messages.push({ role: "user", content: input });
|
|
475
481
|
return messages;
|
|
476
482
|
}
|
|
483
|
+
function initLoopMessages(input, config) {
|
|
484
|
+
if (config.messages?.length) {
|
|
485
|
+
const messages = [...config.messages];
|
|
486
|
+
if (config.systemPrompt && !messages.some((m) => m.role === "system")) {
|
|
487
|
+
messages.unshift({ role: "system", content: config.systemPrompt });
|
|
488
|
+
}
|
|
489
|
+
if (input) {
|
|
490
|
+
messages.push({ role: "user", content: input });
|
|
491
|
+
}
|
|
492
|
+
return messages;
|
|
493
|
+
}
|
|
494
|
+
return buildInitialMessages(input ?? "", config.systemPrompt);
|
|
495
|
+
}
|
|
477
496
|
function estimateTokens(chars) {
|
|
478
497
|
return Math.ceil(chars / 2);
|
|
479
498
|
}
|
|
@@ -532,7 +551,7 @@ function extractSubAgentName(toolName) {
|
|
|
532
551
|
}
|
|
533
552
|
async function reactLoop(input, config) {
|
|
534
553
|
const enableTracing = config.enableTracing ?? false;
|
|
535
|
-
const messages =
|
|
554
|
+
const messages = initLoopMessages(input, config);
|
|
536
555
|
const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
537
556
|
const extras = buildRequestExtras(config);
|
|
538
557
|
let totalUsage;
|
|
@@ -541,17 +560,25 @@ async function reactLoop(input, config) {
|
|
|
541
560
|
const traceEvents = enableTracing ? [] : void 0;
|
|
542
561
|
while (turns < maxTurns) {
|
|
543
562
|
if (config.signal?.aborted) {
|
|
544
|
-
throw new AgentAbortError();
|
|
563
|
+
throw new AgentAbortError(void 0, messages);
|
|
545
564
|
}
|
|
546
565
|
turns++;
|
|
547
566
|
const llmStartedAt = enableTracing ? nowMs() : 0;
|
|
548
567
|
const outgoing = config.maxHistoryTokens ? trimHistory(messages, config.maxHistoryTokens) : messages;
|
|
549
568
|
const inputSnapshot = enableTracing ? [...outgoing] : void 0;
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
569
|
+
let response;
|
|
570
|
+
try {
|
|
571
|
+
response = await config.provider.complete({
|
|
572
|
+
messages: [...outgoing],
|
|
573
|
+
...extras,
|
|
574
|
+
signal: config.signal
|
|
575
|
+
});
|
|
576
|
+
} catch (err) {
|
|
577
|
+
if (err instanceof AgentAbortError) {
|
|
578
|
+
throw new AgentAbortError(err.message, messages);
|
|
579
|
+
}
|
|
580
|
+
throw err;
|
|
581
|
+
}
|
|
555
582
|
if (response.usage) {
|
|
556
583
|
totalUsage = accumulateUsage(totalUsage, response.usage);
|
|
557
584
|
}
|
|
@@ -667,19 +694,20 @@ async function reactLoop(input, config) {
|
|
|
667
694
|
}
|
|
668
695
|
throw new ReactLoopError(
|
|
669
696
|
`Max turns (${maxTurns}) exceeded \u2014 agent did not converge to a final answer`,
|
|
670
|
-
maxTurns
|
|
697
|
+
maxTurns,
|
|
698
|
+
messages
|
|
671
699
|
);
|
|
672
700
|
}
|
|
673
701
|
async function* reactLoopStream(input, config) {
|
|
674
702
|
const enableTracing = config.enableTracing ?? false;
|
|
675
|
-
const messages =
|
|
703
|
+
const messages = initLoopMessages(input, config);
|
|
676
704
|
const maxTurns = config.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
677
705
|
const extras = buildRequestExtras(config);
|
|
678
706
|
let totalUsage;
|
|
679
707
|
let turns = 0;
|
|
680
708
|
while (turns < maxTurns) {
|
|
681
709
|
if (config.signal?.aborted) {
|
|
682
|
-
throw new AgentAbortError();
|
|
710
|
+
throw new AgentAbortError(void 0, messages);
|
|
683
711
|
}
|
|
684
712
|
turns++;
|
|
685
713
|
const llmStartedAt = enableTracing ? nowMs() : 0;
|
|
@@ -689,25 +717,32 @@ async function* reactLoopStream(input, config) {
|
|
|
689
717
|
let toolCalls;
|
|
690
718
|
let finishReason;
|
|
691
719
|
let turnUsage;
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
toolCalls
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
720
|
+
try {
|
|
721
|
+
for await (const chunk of config.provider.stream({
|
|
722
|
+
messages: [...outgoing],
|
|
723
|
+
...extras,
|
|
724
|
+
signal: config.signal
|
|
725
|
+
})) {
|
|
726
|
+
if (typeof chunk.deltaContent === "string" && chunk.deltaContent.length > 0) {
|
|
727
|
+
turnContent += chunk.deltaContent;
|
|
728
|
+
yield { deltaContent: chunk.deltaContent };
|
|
729
|
+
}
|
|
730
|
+
if (chunk.toolCalls && chunk.toolCalls.length > 0) {
|
|
731
|
+
toolCalls = chunk.toolCalls;
|
|
732
|
+
}
|
|
733
|
+
if (chunk.finishReason) {
|
|
734
|
+
finishReason = chunk.finishReason;
|
|
735
|
+
}
|
|
736
|
+
if (chunk.usage) {
|
|
737
|
+
totalUsage = accumulateUsage(totalUsage, chunk.usage);
|
|
738
|
+
turnUsage = chunk.usage;
|
|
739
|
+
}
|
|
706
740
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
741
|
+
} catch (err) {
|
|
742
|
+
if (err instanceof AgentAbortError) {
|
|
743
|
+
throw new AgentAbortError(err.message, messages);
|
|
710
744
|
}
|
|
745
|
+
throw err;
|
|
711
746
|
}
|
|
712
747
|
const assistantMessage = {
|
|
713
748
|
role: "assistant",
|
|
@@ -806,12 +841,49 @@ async function* reactLoopStream(input, config) {
|
|
|
806
841
|
}
|
|
807
842
|
throw new ReactLoopError(
|
|
808
843
|
`Max turns (${maxTurns}) exceeded \u2014 agent did not converge to a final answer`,
|
|
809
|
-
maxTurns
|
|
844
|
+
maxTurns,
|
|
845
|
+
messages
|
|
810
846
|
);
|
|
811
847
|
}
|
|
812
848
|
|
|
813
849
|
// src/agent.ts
|
|
814
850
|
var DEFAULT_MAX_AGENT_DEPTH = 3;
|
|
851
|
+
var VALID_MESSAGE_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant", "tool"]);
|
|
852
|
+
function isProviderInstance(value) {
|
|
853
|
+
return typeof value === "object" && value !== null && typeof value.complete === "function" && typeof value.stream === "function";
|
|
854
|
+
}
|
|
855
|
+
function isProviderConfig(value) {
|
|
856
|
+
return typeof value === "object" && value !== null && typeof value.provider === "string";
|
|
857
|
+
}
|
|
858
|
+
function materializeProvider(external) {
|
|
859
|
+
if (isProviderInstance(external)) return external;
|
|
860
|
+
if (isProviderConfig(external)) {
|
|
861
|
+
return createProvider({ ...external, models: external.models ?? {} });
|
|
862
|
+
}
|
|
863
|
+
throw new AgentError(
|
|
864
|
+
'options.provider must be an LlmConfig object (with a string "provider" field) or an LLMProvider instance (with complete/stream methods)'
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
function validateResumeHistory(messages) {
|
|
868
|
+
messages.forEach((message, index) => {
|
|
869
|
+
if (!VALID_MESSAGE_ROLES.has(message.role)) {
|
|
870
|
+
throw new AgentError(
|
|
871
|
+
`Invalid resume history at messages[${index}]: unknown role "${String(message.role)}"`
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
875
|
+
const missing = new Set(message.toolCalls.map((call) => call.id));
|
|
876
|
+
for (let j = index + 1; j < messages.length && messages[j].role === "tool"; j++) {
|
|
877
|
+
missing.delete(messages[j].toolCallId ?? "");
|
|
878
|
+
}
|
|
879
|
+
if (missing.size > 0) {
|
|
880
|
+
throw new AgentError(
|
|
881
|
+
`Invalid resume history at messages[${index}]: assistant tool call(s) [${Array.from(missing).join(", ")}] have no matching tool result (history truncated mid-turn \u2014 persist the full turn group from AgentAbortError.messages / ReactLoopError.messages)`
|
|
882
|
+
);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
}
|
|
815
887
|
var AgentError = class extends Error {
|
|
816
888
|
constructor(message) {
|
|
817
889
|
super(message);
|
|
@@ -860,16 +932,19 @@ var Agent = class _Agent {
|
|
|
860
932
|
* reactLoop 不知 agent 名(只关心循环逻辑),返回的 `result.trace.agentName` 为空字符串。
|
|
861
933
|
* 本方法在 reactLoop 返回后填充 `this.deps.agentName`,让顶层 trace 标识"是哪个 agent 跑的"。
|
|
862
934
|
*
|
|
863
|
-
* @param input
|
|
864
|
-
*
|
|
935
|
+
* @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
|
|
936
|
+
* 都为空时抛 `AgentError`)
|
|
937
|
+
* @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
|
|
938
|
+
* temperature / maxTokens / messages / enableTracing
|
|
865
939
|
* (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
|
|
866
940
|
* @returns 最终结果(content + messages + turns + stopReason + usage + trace?)
|
|
867
|
-
* @throws {AgentError} agent
|
|
868
|
-
* @throws {ReactLoopError} 超出 maxTurns
|
|
941
|
+
* @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
|
|
942
|
+
* @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
|
|
943
|
+
* @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
|
|
869
944
|
* @throws {Error} provider.complete 抛错时立即传播
|
|
870
945
|
*/
|
|
871
946
|
async run(input, options) {
|
|
872
|
-
const config = await this.buildLoopConfig(options);
|
|
947
|
+
const config = await this.buildLoopConfig(input, options);
|
|
873
948
|
const result = await reactLoop(input, config);
|
|
874
949
|
if (result.trace) {
|
|
875
950
|
result.trace.agentName = options?.agent ?? this.deps.agentName;
|
|
@@ -879,16 +954,19 @@ var Agent = class _Agent {
|
|
|
879
954
|
/**
|
|
880
955
|
* 流式执行——组装 config 调 [reactLoopStream](./reactLoop.md)
|
|
881
956
|
*
|
|
882
|
-
* @param input
|
|
883
|
-
*
|
|
957
|
+
* @param input 用户输入(可选——续跑场景不传新输入;input 与 `options.messages`
|
|
958
|
+
* 都为空时抛 `AgentError`)
|
|
959
|
+
* @param options 临时覆盖本次调用的 provider(外部 provider)/ model(字符串 key)/
|
|
960
|
+
* temperature / maxTokens / messages
|
|
884
961
|
* (不修改 agent 自身状态,详见 [agentHandle](./agentHandle.md))
|
|
885
962
|
* @yields 流式 chunk(deltaContent / toolCall / toolResult / done)
|
|
886
|
-
* @throws {AgentError} agent
|
|
887
|
-
* @throws {ReactLoopError} 超出 maxTurns
|
|
963
|
+
* @throws {AgentError} agent 未注册;input 与 messages 都为空;续跑历史结构非法
|
|
964
|
+
* @throws {ReactLoopError} 超出 maxTurns(`error.messages` 携带完整历史,可续跑)
|
|
965
|
+
* @throws {AgentAbortError} 中断(`error.messages` 携带断点历史,可续跑)
|
|
888
966
|
* @throws {Error} provider.stream 抛错时立即传播
|
|
889
967
|
*/
|
|
890
968
|
async *stream(input, options) {
|
|
891
|
-
const config = await this.buildLoopConfig(options);
|
|
969
|
+
const config = await this.buildLoopConfig(input, options);
|
|
892
970
|
yield* reactLoopStream(input, config);
|
|
893
971
|
}
|
|
894
972
|
/**
|
|
@@ -938,7 +1016,9 @@ var Agent = class _Agent {
|
|
|
938
1016
|
* 3. buildToolDefinitions 组装 tool 列表(用有效 agent 名查 tools / sub-agents)
|
|
939
1017
|
* 4. config 字段优先级(高 → 低):`options` > agent 元数据 > 全局 AgentRuntimeConfig / deps.defaultProvider
|
|
940
1018
|
*
|
|
941
|
-
* `options.
|
|
1019
|
+
* `options.provider`(外部 provider)存在时由 {@link resolveExternalProvider} 物化,
|
|
1020
|
+
* 优先级最高——`options.model` 变为原始 model 名原样透传(不解析 llms key)。
|
|
1021
|
+
* 否则 `options.model` 是字符串 key,由 {@link resolveModelKey} 解析为 provider + model
|
|
942
1022
|
* (支持 llms key 精确匹配 / `provider/model` 一体化 / 纯 model 名模糊匹配)。
|
|
943
1023
|
* 不传 `options.model` 时用 `deps.defaultProvider` + agent 元数据 `config.model`。
|
|
944
1024
|
* 详见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」。
|
|
@@ -946,15 +1026,28 @@ var Agent = class _Agent {
|
|
|
946
1026
|
* `options.agent` 覆盖本次调用的 agent 名——不传时用 `deps.agentName`(来自
|
|
947
1027
|
* `config.agent.defaultAgent`)。`defaultAgent` 未设且 `options.agent` 未传时抛
|
|
948
1028
|
* `AgentError`。
|
|
1029
|
+
*
|
|
1030
|
+
* **输入守卫**(续跑入口,见 [reactLoop.md](./reactLoop.md) 中断恢复章节):
|
|
1031
|
+
* `input` 与 `options.messages` 都为空时抛 `AgentError`(不发送空请求);
|
|
1032
|
+
* `options.messages` 提供时先经 `validateResumeHistory` 结构校验,非法抛
|
|
1033
|
+
* `AgentError`,不发起 LLM 请求。
|
|
949
1034
|
*/
|
|
950
|
-
async buildLoopConfig(options) {
|
|
1035
|
+
async buildLoopConfig(input, options) {
|
|
1036
|
+
if (!input && !options?.messages?.length) {
|
|
1037
|
+
throw new AgentError(
|
|
1038
|
+
"agent.run/stream requires non-empty input, or options.messages to resume from (AgentAbortError.messages / ReactLoopError.messages / previous result.messages)"
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
if (options?.messages?.length) {
|
|
1042
|
+
validateResumeHistory(options.messages);
|
|
1043
|
+
}
|
|
951
1044
|
const agentName = options?.agent ?? this.deps.agentName;
|
|
952
1045
|
const meta = this.deps.getAgent(agentName);
|
|
953
1046
|
if (!meta) {
|
|
954
1047
|
throw new AgentError(`Agent "${agentName}" is not registered`);
|
|
955
1048
|
}
|
|
956
1049
|
const tools = await this.buildToolDefinitions(agentName);
|
|
957
|
-
const { provider, model } = this.resolveModelKey(options?.model, meta);
|
|
1050
|
+
const { provider, model } = options?.provider !== void 0 ? this.resolveExternalProvider(options.provider, options?.model) : this.resolveModelKey(options?.model, meta);
|
|
958
1051
|
const enableTracing = options?.enableTracing ?? this.deps.config?.enableTracing ?? false;
|
|
959
1052
|
return {
|
|
960
1053
|
provider,
|
|
@@ -965,15 +1058,45 @@ var Agent = class _Agent {
|
|
|
965
1058
|
maxTurns: meta.maxTurns ?? this.deps.config?.maxTurns,
|
|
966
1059
|
tools,
|
|
967
1060
|
signal: options?.signal,
|
|
1061
|
+
messages: options?.messages,
|
|
968
1062
|
enableTracing,
|
|
969
1063
|
executeTool: async (name, args) => this.executeTool(name, args, enableTracing)
|
|
970
1064
|
};
|
|
971
1065
|
}
|
|
1066
|
+
/**
|
|
1067
|
+
* 解析外部 provider(`options.provider`)→ provider + model
|
|
1068
|
+
*
|
|
1069
|
+
* 规则见 [agentHandle.md](./agentHandle.md) 的「`options.provider` 外部 provider」章节:
|
|
1070
|
+
* - `LLMProvider` 实例 → 直接使用,`modelKey` 原样透传(可为 `undefined`,自定义 provider 自决)
|
|
1071
|
+
* - `LlmConfig` 配置对象 → `createProvider` 现场创建,`modelKey` 原样透传;
|
|
1072
|
+
* 缺省回落该 config `models` 第一个 key,两者皆无抛 `AgentError`(早失败,不发请求)
|
|
1073
|
+
* - `modelKey` 不做 llms key 解析、不拆 `/`(支持 OpenRouter 等带斜杠的 model id)
|
|
1074
|
+
*
|
|
1075
|
+
* 仅本次调用生效:不进 providers Map、sub-agent 递归不继承(executeSubAgent 构造
|
|
1076
|
+
* subDeps 时不携带 options,sub-agent 走默认解析链路)。
|
|
1077
|
+
*
|
|
1078
|
+
* @throws {AgentError} provider 形式非法;LlmConfig 形式下 model 缺失
|
|
1079
|
+
*/
|
|
1080
|
+
resolveExternalProvider(external, modelKey) {
|
|
1081
|
+
const provider = materializeProvider(external);
|
|
1082
|
+
if (isProviderInstance(external)) {
|
|
1083
|
+
return { provider, model: modelKey };
|
|
1084
|
+
}
|
|
1085
|
+
const firstModel = Object.keys(external.models ?? {})[0];
|
|
1086
|
+
const model = modelKey ?? firstModel;
|
|
1087
|
+
if (model === void 0) {
|
|
1088
|
+
throw new AgentError(
|
|
1089
|
+
"External provider requires a model: pass options.model or declare models in the provider config"
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
return { provider, model };
|
|
1093
|
+
}
|
|
972
1094
|
/**
|
|
973
1095
|
* 解析 `options.model` 字符串 key → provider + model
|
|
974
1096
|
*
|
|
975
1097
|
* 规则见 [agentHandle.md](./agentHandle.md) 的「`options.model` 字符串 key 解析规则」:
|
|
976
|
-
* 1. `undefined` → `deps.defaultProvider`
|
|
1098
|
+
* 1. `undefined` → `deps.defaultProvider`(未配置时抛 `AgentError`——外部 provider 模式
|
|
1099
|
+
* 要求调用方传 `options.provider`)+ `meta.model`
|
|
977
1100
|
* 2. 精确匹配 `deps.providers` 的 key → 该 provider + 其 `models` 第一个 key
|
|
978
1101
|
* 3. 含 `/` → `provider/model` 形式,`deps.providers.get(provider)` + 该 model
|
|
979
1102
|
* (要求该 model 在 `deps.llms[provider].models` 里)
|
|
@@ -982,10 +1105,16 @@ var Agent = class _Agent {
|
|
|
982
1105
|
* - 多个 → 抛 `AgentError`(要求用 `provider/model` 消歧)
|
|
983
1106
|
* - 无 → 抛 `AgentError`
|
|
984
1107
|
*
|
|
985
|
-
* @throws {AgentError} key 解析失败(provider/model
|
|
1108
|
+
* @throws {AgentError} key 解析失败(provider/model 不存在或歧义);deps.defaultProvider
|
|
1109
|
+
* 未配置(外部 provider 模式下调用方未传 options.provider)
|
|
986
1110
|
*/
|
|
987
1111
|
resolveModelKey(key, meta) {
|
|
988
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
|
+
}
|
|
989
1118
|
return { provider: this.deps.defaultProvider, model: meta.model };
|
|
990
1119
|
}
|
|
991
1120
|
const byProviderKey = this.deps.providers.get(key);
|
|
@@ -1000,7 +1129,9 @@ var Agent = class _Agent {
|
|
|
1000
1129
|
const modelName = key.slice(slashIdx + 1);
|
|
1001
1130
|
const provider = this.deps.providers.get(providerName);
|
|
1002
1131
|
if (!provider) {
|
|
1003
|
-
throw new AgentError(
|
|
1132
|
+
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.`
|
|
1134
|
+
);
|
|
1004
1135
|
}
|
|
1005
1136
|
const llmConfig = this.deps.llms[providerName];
|
|
1006
1137
|
if (!llmConfig || !llmConfig.models[modelName]) {
|
|
@@ -1026,7 +1157,7 @@ var Agent = class _Agent {
|
|
|
1026
1157
|
);
|
|
1027
1158
|
}
|
|
1028
1159
|
throw new AgentError(
|
|
1029
|
-
`Model "${key}" not found in any provider. Declare it in config.agent.llms.*.models.`
|
|
1160
|
+
`Model "${key}" not found in any provider. Declare it in config.agent.llms.*.models, or pass options.provider to use an external provider.`
|
|
1030
1161
|
);
|
|
1031
1162
|
}
|
|
1032
1163
|
/**
|
|
@@ -1210,14 +1341,13 @@ var agentPlugin = {
|
|
|
1210
1341
|
setup(ctx) {
|
|
1211
1342
|
const registries = ctx.registries;
|
|
1212
1343
|
const agentConfig = readAgentConfig(ctx);
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1344
|
+
const llms = agentConfig?.llms ?? {};
|
|
1345
|
+
if (Object.keys(llms).length === 0) {
|
|
1346
|
+
console.log(
|
|
1347
|
+
"- @faapi/agent: no llms configured \u2014 use agent.run(input, { provider }) to pass an external provider per call"
|
|
1216
1348
|
);
|
|
1217
|
-
return;
|
|
1218
1349
|
}
|
|
1219
|
-
const defaultAgent = agentConfig
|
|
1220
|
-
const llms = agentConfig.llms;
|
|
1350
|
+
const defaultAgent = agentConfig?.defaultAgent ?? "";
|
|
1221
1351
|
const providers = /* @__PURE__ */ new Map();
|
|
1222
1352
|
for (const [name, llmConfig] of Object.entries(llms)) {
|
|
1223
1353
|
if (!llmConfig.apiKey || llmConfig.apiKey.trim() === "") {
|
|
@@ -1227,22 +1357,21 @@ var agentPlugin = {
|
|
|
1227
1357
|
}
|
|
1228
1358
|
providers.set(name, createProvider(llmConfig));
|
|
1229
1359
|
}
|
|
1230
|
-
const defaultLlm = agentConfig
|
|
1231
|
-
const defaultProvider = providers.get(defaultLlm);
|
|
1232
|
-
if (!defaultProvider) {
|
|
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) {
|
|
1233
1363
|
console.warn(
|
|
1234
|
-
`! @faapi/agent: config.agent.defaultLlm "${defaultLlm}" not found in llms, agent
|
|
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`
|
|
1235
1365
|
);
|
|
1236
|
-
return;
|
|
1237
1366
|
}
|
|
1238
1367
|
const runtimeConfig = {
|
|
1239
|
-
maxTurns: agentConfig
|
|
1240
|
-
maxAgentDepth: agentConfig
|
|
1241
|
-
maxHistoryTokens: agentConfig
|
|
1368
|
+
maxTurns: agentConfig?.maxTurns,
|
|
1369
|
+
maxAgentDepth: agentConfig?.maxAgentDepth,
|
|
1370
|
+
maxHistoryTokens: agentConfig?.maxHistoryTokens,
|
|
1242
1371
|
// 鉴权钩子(authHooks,见 ./authHooks.md)——业务方在 config.agent 声明
|
|
1243
|
-
beforeToolCall: agentConfig
|
|
1244
|
-
afterToolCall: agentConfig
|
|
1245
|
-
filterTools: agentConfig
|
|
1372
|
+
beforeToolCall: agentConfig?.beforeToolCall,
|
|
1373
|
+
afterToolCall: agentConfig?.afterToolCall,
|
|
1374
|
+
filterTools: agentConfig?.filterTools
|
|
1246
1375
|
};
|
|
1247
1376
|
const rootDir = ctx.rootDir;
|
|
1248
1377
|
const schemaCache = /* @__PURE__ */ new Map();
|
|
@@ -1289,7 +1418,7 @@ var agentPlugin = {
|
|
|
1289
1418
|
});
|
|
1290
1419
|
});
|
|
1291
1420
|
console.log(
|
|
1292
|
-
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})`
|
|
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"
|
|
1293
1422
|
);
|
|
1294
1423
|
}
|
|
1295
1424
|
};
|