Skip to content

Commit 2781897

Browse files
committed
fix: restore provider policy fallbacks
1 parent 2b3e89c commit 2781897

2 files changed

Lines changed: 47 additions & 12 deletions

File tree

src/agents/models-config.providers.policy.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,22 @@ import {
1111
} from "../plugins/provider-runtime.js";
1212
import type { ProviderConfig } from "./models-config.providers.secrets.js";
1313

14+
function resolveProviderPluginLookupKey(providerKey: string, provider?: ProviderConfig): string {
15+
const api = typeof provider?.api === "string" ? provider.api.trim() : "";
16+
return api || providerKey;
17+
}
18+
1419
export function applyNativeStreamingUsageCompat(
1520
providers: Record<string, ProviderConfig>,
1621
): Record<string, ProviderConfig> {
1722
let changed = false;
1823
const nextProviders: Record<string, ProviderConfig> = {};
1924

2025
for (const [providerKey, provider] of Object.entries(providers)) {
26+
const runtimeProviderKey = resolveProviderPluginLookupKey(providerKey, provider);
2127
const nextProvider =
2228
applyProviderNativeStreamingUsageCompatWithPlugin({
23-
provider: providerKey,
29+
provider: runtimeProviderKey,
2430
context: {
2531
provider: providerKey,
2632
providerConfig: provider,
@@ -37,15 +43,16 @@ export function normalizeProviderSpecificConfig(
3743
providerKey: string,
3844
provider: ProviderConfig,
3945
): ProviderConfig {
46+
const runtimeProviderKey = resolveProviderPluginLookupKey(providerKey, provider);
4047
const normalized =
4148
normalizeProviderConfigWithPlugin({
42-
provider: providerKey,
49+
provider: runtimeProviderKey,
4350
context: {
4451
provider: providerKey,
4552
providerConfig: provider,
4653
},
4754
}) ?? undefined;
48-
if (normalized) {
55+
if (normalized && normalized !== provider) {
4956
return normalized;
5057
}
5158
if (shouldNormalizeGoogleProviderConfig(providerKey, provider)) {
@@ -56,19 +63,21 @@ export function normalizeProviderSpecificConfig(
5663

5764
export function resolveProviderConfigApiKeyResolver(
5865
providerKey: string,
66+
provider?: ProviderConfig,
5967
): ((env: NodeJS.ProcessEnv) => string | undefined) | undefined {
6068
if (providerKey.trim() === "amazon-bedrock") {
6169
return (env) => {
6270
const resolved = resolveBedrockConfigApiKey(env);
6371
return resolved?.trim() || undefined;
6472
};
6573
}
66-
if (!resolveProviderRuntimePlugin({ provider: providerKey })?.resolveConfigApiKey) {
74+
const runtimeProviderKey = resolveProviderPluginLookupKey(providerKey, provider);
75+
if (!resolveProviderRuntimePlugin({ provider: runtimeProviderKey })?.resolveConfigApiKey) {
6776
return undefined;
6877
}
6978
return (env) => {
7079
const resolved = resolveProviderConfigApiKeyWithPlugin({
71-
provider: providerKey,
80+
provider: runtimeProviderKey,
7281
env,
7382
context: {
7483
provider: providerKey,

src/agents/openclaw-tools.subagents.sessions-spawn.lifecycle.test.ts

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,14 @@ async function executeSpawnAndExpectAccepted(params: {
132132
callId: string;
133133
cleanup?: "delete" | "keep";
134134
label?: string;
135+
expectsCompletionMessage?: boolean;
135136
}) {
136137
const result = await params.tool.execute(params.callId, {
137138
task: "do thing",
138139
runTimeoutSeconds: RUN_TIMEOUT_SECONDS,
139140
...(params.cleanup ? { cleanup: params.cleanup } : {}),
140141
...(params.label ? { label: params.label } : {}),
142+
...(params.expectsCompletionMessage === false ? { expectsCompletionMessage: false } : {}),
141143
});
142144
expect(result.details).toMatchObject({
143145
status: "accepted",
@@ -390,6 +392,28 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
390392
});
391393

392394
it("sessions_spawn reports timed out when agent.wait returns timeout", async () => {
395+
let announcedStatus: string | undefined;
396+
setSessionsSpawnAnnounceFlowOverride(async (params) => {
397+
announcedStatus = params.outcome?.status;
398+
const requesterSessionKey = resolveRequesterStoreKey(
399+
loadConfig(),
400+
params.requesterSessionKey,
401+
);
402+
403+
await callGatewayMock({
404+
method: "agent",
405+
params: {
406+
sessionKey: requesterSessionKey,
407+
message: `subagent task ${
408+
params.outcome?.status === "timeout" ? "timed out" : "completed successfully"
409+
}`,
410+
deliver: false,
411+
},
412+
});
413+
414+
return true;
415+
});
416+
393417
const ctx = setupSessionsSpawnGatewayMock({
394418
includeChatHistory: true,
395419
chatHistoryText: "still working",
@@ -401,20 +425,22 @@ describe("openclaw-tools: subagents (sessions_spawn lifecycle)", () => {
401425
tool,
402426
callId: "call-timeout",
403427
cleanup: "keep",
428+
expectsCompletionMessage: false,
404429
});
405430

406-
await waitFor(() => ctx.calls.filter((call) => call.method === "agent").length >= 2);
431+
await waitFor(() => announcedStatus === "timeout");
407432

408-
const mainAgentCall = ctx.calls
433+
const mainMessages = ctx.calls
409434
.filter((call) => call.method === "agent")
410-
.find((call) => {
435+
.filter((call) => {
411436
const params = call.params as { lane?: string } | undefined;
412437
return params?.lane !== "subagent";
413-
});
414-
const mainMessage = (mainAgentCall?.params as { message?: string } | undefined)?.message ?? "";
438+
})
439+
.map((call) => (call.params as { message?: string } | undefined)?.message ?? "");
415440

416-
expect(mainMessage).toContain("timed out");
417-
expect(mainMessage).not.toContain("completed successfully");
441+
expect(announcedStatus).toBe("timeout");
442+
expect(mainMessages.some((message) => message.includes("timed out"))).toBe(true);
443+
expect(mainMessages.some((message) => message.includes("completed successfully"))).toBe(false);
418444
});
419445

420446
it("sessions_spawn announces with requester accountId", async () => {

0 commit comments

Comments
 (0)