


























@@ -28,6 +28,31 @@ type AgentHarnessPolicy = {
2828fallback: EmbeddedAgentHarnessFallback;
2929};
303031+type AgentHarnessSelectionCandidate = {
32+id: string;
33+label: string;
34+pluginId?: string;
35+supported?: boolean;
36+priority?: number;
37+reason?: string;
38+};
39+40+type AgentHarnessSelectionDecision = {
41+harness: AgentHarness;
42+policy: AgentHarnessPolicy;
43+selectedHarnessId: string;
44+selectedReason:
45+| "pinned"
46+| "forced_pi"
47+| "forced_plugin"
48+| "forced_plugin_fallback_to_pi"
49+// Auto mode chose a registered plugin harness that supports the provider/model.
50+| "auto_plugin"
51+// Auto mode found no supporting plugin harness, so PI handled the run.
52+| "auto_pi_fallback";
53+candidates: AgentHarnessSelectionCandidate[];
54+};
55+3156function listPluginAgentHarnesses(): AgentHarness[] {
3257return listRegisteredAgentHarnesses().map((entry) => entry.harness);
3358}
@@ -51,20 +76,41 @@ export function selectAgentHarness(params: {
5176sessionKey?: string;
5277agentHarnessId?: string;
5378}): AgentHarness {
54-const policy =
55-resolvePinnedAgentHarnessPolicy(params.agentHarnessId) ?? resolveAgentHarnessPolicy(params);
79+return selectAgentHarnessDecision(params).harness;
80+}
81+82+function selectAgentHarnessDecision(params: {
83+provider: string;
84+modelId?: string;
85+config?: OpenClawConfig;
86+agentId?: string;
87+sessionKey?: string;
88+agentHarnessId?: string;
89+}): AgentHarnessSelectionDecision {
90+const pinnedPolicy = resolvePinnedAgentHarnessPolicy(params.agentHarnessId);
91+const policy = pinnedPolicy ?? resolveAgentHarnessPolicy(params);
5692// PI is intentionally not part of the plugin candidate list. It is the legacy
5793// fallback path, so `fallback: "none"` can prove that only plugin harnesses run.
5894const pluginHarnesses = listPluginAgentHarnesses();
5995const piHarness = createPiAgentHarness();
6096const runtime = policy.runtime;
6197if (runtime === "pi") {
62-return piHarness;
98+return buildSelectionDecision({
99+harness: piHarness,
100+ policy,
101+selectedReason: pinnedPolicy ? "pinned" : "forced_pi",
102+candidates: listHarnessCandidates(pluginHarnesses),
103+});
63104}
64105if (runtime !== "auto") {
65106const forced = pluginHarnesses.find((entry) => entry.id === runtime);
66107if (forced) {
67-return forced;
108+return buildSelectionDecision({
109+harness: forced,
110+ policy,
111+selectedReason: pinnedPolicy ? "pinned" : "forced_plugin",
112+candidates: listHarnessCandidates(pluginHarnesses),
113+});
68114}
69115if (policy.fallback === "none") {
70116throw new Error(
@@ -74,18 +120,23 @@ export function selectAgentHarness(params: {
74120log.warn("requested agent harness is not registered; falling back to embedded PI backend", {
75121requestedRuntime: runtime,
76122});
77-return piHarness;
123+return buildSelectionDecision({
124+harness: piHarness,
125+ policy,
126+selectedReason: "forced_plugin_fallback_to_pi",
127+candidates: listHarnessCandidates(pluginHarnesses),
128+});
78129}
7913080-const supported = pluginHarnesses
81-.map((harness) => ({
82- harness,
83-support: harness.supports({
84- provider: params.provider,
85- modelId: params.modelId,
86- requestedRuntime: runtime,
87- }),
88- }))
131+const candidates = pluginHarnesses.map((harness) => ({
132+ harness,
133+support: harness.supports({
134+provider: params.provider,
135+modelId: params.modelId,
136+requestedRuntime: runtime,
137+}),
138+}));
139+const supported = candidates
89140.filter(
90141(
91142entry,
@@ -98,27 +149,44 @@ export function selectAgentHarness(params: {
9814999150const selected = supported[0]?.harness;
100151if (selected) {
101-return selected;
152+return buildSelectionDecision({
153+harness: selected,
154+ policy,
155+selectedReason: "auto_plugin",
156+candidates: candidates.map(toSelectionCandidate),
157+});
102158}
103159if (policy.fallback === "none") {
104160throw new Error(
105161`No registered agent harness supports ${formatProviderModel(params)} and PI fallback is disabled.`,
106162);
107163}
108-return piHarness;
164+return buildSelectionDecision({
165+harness: piHarness,
166+ policy,
167+selectedReason: "auto_pi_fallback",
168+candidates: candidates.map(toSelectionCandidate),
169+});
109170}
110171111172export async function runAgentHarnessAttemptWithFallback(
112173params: EmbeddedRunAttemptParams,
113174): Promise<EmbeddedRunAttemptResult> {
114-const harness = selectAgentHarness({
175+const selection = selectAgentHarnessDecision({
115176provider: params.provider,
116177modelId: params.modelId,
117178config: params.config,
118179agentId: params.agentId,
119180sessionKey: params.sessionKey,
120181agentHarnessId: params.agentHarnessId,
121182});
183+const harness = selection.harness;
184+logAgentHarnessSelection(selection, {
185+provider: params.provider,
186+modelId: params.modelId,
187+sessionKey: params.sessionKey,
188+agentId: params.agentId,
189+});
122190if (harness.id === "pi") {
123191const result = await harness.runAttempt(params);
124192return { ...result, agentHarnessId: harness.id };
@@ -138,6 +206,63 @@ export async function runAgentHarnessAttemptWithFallback(
138206}
139207}
140208209+function listHarnessCandidates(harnesses: AgentHarness[]): AgentHarnessSelectionCandidate[] {
210+return harnesses.map((harness) => ({
211+id: harness.id,
212+label: harness.label,
213+pluginId: harness.pluginId,
214+}));
215+}
216+217+function toSelectionCandidate(entry: {
218+harness: AgentHarness;
219+support: AgentHarnessSupport;
220+}): AgentHarnessSelectionCandidate {
221+return {
222+id: entry.harness.id,
223+label: entry.harness.label,
224+pluginId: entry.harness.pluginId,
225+supported: entry.support.supported,
226+priority: entry.support.supported ? entry.support.priority : undefined,
227+reason: entry.support.reason,
228+};
229+}
230+231+function buildSelectionDecision(params: {
232+harness: AgentHarness;
233+policy: AgentHarnessPolicy;
234+selectedReason: AgentHarnessSelectionDecision["selectedReason"];
235+candidates: AgentHarnessSelectionCandidate[];
236+}): AgentHarnessSelectionDecision {
237+return {
238+harness: params.harness,
239+policy: params.policy,
240+selectedHarnessId: params.harness.id,
241+selectedReason: params.selectedReason,
242+candidates: params.candidates,
243+};
244+}
245+246+function logAgentHarnessSelection(
247+selection: AgentHarnessSelectionDecision,
248+params: { provider: string; modelId?: string; sessionKey?: string; agentId?: string },
249+) {
250+if (!log.isEnabled("debug")) {
251+return;
252+}
253+log.debug("agent harness selected", {
254+provider: params.provider,
255+modelId: params.modelId,
256+sessionKey: params.sessionKey,
257+agentId: params.agentId,
258+selectedHarnessId: selection.selectedHarnessId,
259+selectedReason: selection.selectedReason,
260+runtime: selection.policy.runtime,
261+fallback: selection.policy.fallback,
262+candidates: selection.candidates,
263+});
264+}
265+141266function resolvePinnedAgentHarnessPolicy(
142267agentHarnessId: string | undefined,
143268): AgentHarnessPolicy | undefined {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。