Skip to content

Commit d2a1b24

Browse files
committed
test: honor env auth in gateway live probes
1 parent ed61493 commit d2a1b24

File tree

3 files changed

+73
-18
lines changed

3 files changed

+73
-18
lines changed

src/gateway/gateway-models.profiles.live.test.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
1010
import {
1111
type AuthProfileStore,
1212
ensureAuthProfileStore,
13-
resolveAuthProfileOrder,
1413
saveAuthProfileStore,
1514
} from "../agents/auth-profiles.js";
1615
import {
@@ -43,6 +42,7 @@ import { loadSessionEntry, readSessionMessages } from "./session-utils.js";
4342
const LIVE = isTruthyEnvValue(process.env.LIVE) || isTruthyEnvValue(process.env.OPENCLAW_LIVE_TEST);
4443
const GATEWAY_LIVE = isTruthyEnvValue(process.env.OPENCLAW_LIVE_GATEWAY);
4544
const ZAI_FALLBACK = isTruthyEnvValue(process.env.OPENCLAW_LIVE_GATEWAY_ZAI_FALLBACK);
45+
const REQUIRE_PROFILE_KEYS = isTruthyEnvValue(process.env.OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS);
4646
const PROVIDERS = parseFilter(process.env.OPENCLAW_LIVE_GATEWAY_PROVIDERS);
4747
const THINKING_LEVEL = "high";
4848
const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|thought|antthinking)\s*>/i;
@@ -1383,9 +1383,6 @@ describeLive("gateway live (dev agent, profile keys)", () => {
13831383
await ensureOpenClawModelsJson(cfg);
13841384

13851385
const agentDir = resolveOpenClawAgentDir();
1386-
const authStore = ensureAuthProfileStore(agentDir, {
1387-
allowKeychainPrompt: false,
1388-
});
13891386
const authStorage = discoverAuthStorage(agentDir);
13901387
const modelRegistry = discoverModels(authStorage, agentDir);
13911388
const all = modelRegistry.getAll();
@@ -1399,32 +1396,37 @@ describeLive("gateway live (dev agent, profile keys)", () => {
13991396
? all.filter((m) => filter.has(`${m.provider}/${m.id}`))
14001397
: all.filter((m) => isModernModelRef({ provider: m.provider, id: m.id }));
14011398

1402-
const providerProfileCache = new Map<string, boolean>();
14031399
const candidates: Array<Model<Api>> = [];
1400+
const skipped: Array<{ model: string; error: string }> = [];
14041401
for (const model of wanted) {
14051402
if (shouldSuppressBuiltInModel({ provider: model.provider, id: model.id })) {
14061403
continue;
14071404
}
14081405
if (PROVIDERS && !PROVIDERS.has(model.provider)) {
14091406
continue;
14101407
}
1411-
let hasProfile = providerProfileCache.get(model.provider);
1412-
if (hasProfile === undefined) {
1413-
const order = resolveAuthProfileOrder({
1414-
cfg,
1415-
store: authStore,
1416-
provider: model.provider,
1417-
});
1418-
hasProfile = order.some((profileId) => Boolean(authStore.profiles[profileId]));
1419-
providerProfileCache.set(model.provider, hasProfile);
1420-
}
1421-
if (!hasProfile) {
1422-
continue;
1408+
const modelRef = `${model.provider}/${model.id}`;
1409+
try {
1410+
const apiKeyInfo = await getApiKeyForModel({ model, cfg });
1411+
if (REQUIRE_PROFILE_KEYS && !apiKeyInfo.source.startsWith("profile:")) {
1412+
skipped.push({
1413+
model: modelRef,
1414+
error: `non-profile credential source: ${apiKeyInfo.source}`,
1415+
});
1416+
continue;
1417+
}
1418+
candidates.push(model);
1419+
} catch (error) {
1420+
skipped.push({ model: modelRef, error: String(error) });
14231421
}
1424-
candidates.push(model);
14251422
}
14261423

14271424
if (candidates.length === 0) {
1425+
if (skipped.length > 0) {
1426+
logProgress(
1427+
`[all-models] auth lookup skipped candidates:\n${formatFailurePreview(skipped, 8)}`,
1428+
);
1429+
}
14281430
logProgress("[all-models] no API keys found; skipping");
14291431
return;
14301432
}

src/gateway/live-tool-probe-utils.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,30 @@ describe("live tool probe utils", () => {
136136
},
137137
expected: true,
138138
},
139+
{
140+
name: "retries conversational try-again output",
141+
params: {
142+
text: "Let me try reading the file again:",
143+
nonceA: "nonce-a",
144+
nonceB: "nonce-b",
145+
provider: "zai",
146+
attempt: 0,
147+
maxAttempts: 3,
148+
},
149+
expected: true,
150+
},
151+
{
152+
name: "does not retry generic conversational text without tool-retry context",
153+
params: {
154+
text: "Let me try a different approach.",
155+
nonceA: "nonce-a",
156+
nonceB: "nonce-b",
157+
provider: "zai",
158+
attempt: 0,
159+
maxAttempts: 3,
160+
},
161+
expected: false,
162+
},
139163
{
140164
name: "retries mistral nonce marker echoes without parsed values",
141165
params: {
@@ -234,6 +258,28 @@ describe("live tool probe utils", () => {
234258
},
235259
expected: true,
236260
},
261+
{
262+
name: "retries conversational try-again exec output",
263+
params: {
264+
text: "Let me try reading the file again:",
265+
nonce: "nonce-c",
266+
provider: "zai",
267+
attempt: 0,
268+
maxAttempts: 3,
269+
},
270+
expected: true,
271+
},
272+
{
273+
name: "does not retry generic exec conversational text without tool-retry context",
274+
params: {
275+
text: "Let me try a different approach.",
276+
nonce: "nonce-c",
277+
provider: "zai",
278+
attempt: 0,
279+
maxAttempts: 3,
280+
},
281+
expected: false,
282+
},
237283
{
238284
name: "does not special-case anthropic refusals for other providers",
239285
params: {

src/gateway/live-tool-probe-utils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ function hasMalformedToolOutput(text: string): boolean {
5353
if (trimmed.includes("[object Object]")) {
5454
return true;
5555
}
56+
if (
57+
lower.includes("try reading the file again") ||
58+
lower.includes("trying to read the file again") ||
59+
lower.includes("try the read tool again")
60+
) {
61+
return true;
62+
}
5663
if (/\bread\s*\[/.test(lower) || /\btool\b/.test(lower) || /\bfunction\b/.test(lower)) {
5764
return true;
5865
}

0 commit comments

Comments
 (0)