






















@@ -16,6 +16,18 @@ import {
1616selectHighSignalLiveItems,
1717shouldExcludeProviderFromDefaultHighSignalLiveSweep,
1818} from "./live-model-filter.js";
19+import {
20+buildLiveModelFileProbeContext,
21+buildLiveModelImageProbeContext,
22+extractAssistantText,
23+fileProbeTextMatches,
24+imageProbeTextMatches,
25+isLiveModelProbeEnabled,
26+LIVE_MODEL_FILE_PROBE_ENV,
27+LIVE_MODEL_FILE_PROBE_TOKEN,
28+LIVE_MODEL_IMAGE_PROBE_ENV,
29+modelSupportsImageInput,
30+} from "./live-model-turn-probes.js";
1931import { createLiveTargetMatcher } from "./live-target-matcher.js";
2032import { isLiveProfileKeyModeEnabled, isLiveTestEnabled } from "./live-test-helpers.js";
2133import { getApiKeyForModel, requireApiKey } from "./model-auth.js";
@@ -37,6 +49,8 @@ const LIVE_SETUP_TIMEOUT_MS = Math.max(
3749toInt(process.env.OPENCLAW_LIVE_SETUP_TIMEOUT_MS, 45_000),
3850);
3951const LIVE_MODELS_JSON_TIMEOUT_MS = resolveLiveModelsJsonTimeoutMs();
52+const LIVE_FILE_PROBE_ENABLED = isLiveModelProbeEnabled(process.env, LIVE_MODEL_FILE_PROBE_ENV);
53+const LIVE_IMAGE_PROBE_ENABLED = isLiveModelProbeEnabled(process.env, LIVE_MODEL_IMAGE_PROBE_ENV);
40544155const describeLive = LIVE ? describe : describe.skip;
4256@@ -432,6 +446,60 @@ async function completeOkWithRetry(params: {
432446return await runOnce(256);
433447}
434448449+async function runExtraTurnProbes(params: {
450+model: Model<Api>;
451+apiKey: string;
452+timeoutMs: number;
453+progressLabel: string;
454+}) {
455+const options = {
456+apiKey: params.apiKey,
457+reasoning: resolveTestReasoning(params.model),
458+maxTokens: 64,
459+};
460+if (LIVE_FILE_PROBE_ENABLED) {
461+logProgress(`${params.progressLabel}: file-read probe`);
462+const file = await completeSimpleWithTimeout(
463+params.model,
464+buildLiveModelFileProbeContext({ systemPrompt: resolveLiveSystemPrompt(params.model) }),
465+options,
466+params.timeoutMs,
467+`${params.progressLabel}: file-read probe`,
468+);
469+if (file.stopReason === "error") {
470+throw new Error(file.errorMessage || "file-read probe returned error with no message");
471+}
472+const fileText = extractAssistantText(file);
473+if (!fileProbeTextMatches(fileText)) {
474+throw new Error(`file-read probe did not return ${LIVE_MODEL_FILE_PROBE_TOKEN}: ${fileText}`);
475+}
476+}
477+478+if (!LIVE_IMAGE_PROBE_ENABLED) {
479+return;
480+}
481+if (!modelSupportsImageInput(params.model)) {
482+logProgress(`${params.progressLabel}: image probe skipped (no image input)`);
483+return;
484+}
485+486+logProgress(`${params.progressLabel}: image probe`);
487+const image = await completeSimpleWithTimeout(
488+params.model,
489+buildLiveModelImageProbeContext({ systemPrompt: resolveLiveSystemPrompt(params.model) }),
490+options,
491+params.timeoutMs,
492+`${params.progressLabel}: image probe`,
493+);
494+if (image.stopReason === "error") {
495+throw new Error(image.errorMessage || "image probe returned error with no message");
496+}
497+const imageText = extractAssistantText(image);
498+if (!imageProbeTextMatches(imageText)) {
499+throw new Error(`image probe did not return ok: ${imageText}`);
500+}
501+}
502+435503describeLive("live models (profile keys)", () => {
436504it(
437505"completes across selected models",
@@ -688,6 +756,12 @@ describeLive("live models (profile keys)", () => {
688756.map((b) => b.text.trim())
689757.join(" ");
690758expect(secondText.length).toBeGreaterThan(0);
759+await runExtraTurnProbes({
760+ model,
761+ apiKey,
762+timeoutMs: perModelTimeoutMs,
763+ progressLabel,
764+});
691765logProgress(`${progressLabel}: done`);
692766break;
693767}
@@ -761,6 +835,12 @@ describeLive("live models (profile keys)", () => {
761835break;
762836}
763837expect(ok.text.length).toBeGreaterThan(0);
838+await runExtraTurnProbes({
839+ model,
840+ apiKey,
841+timeoutMs: perModelTimeoutMs,
842+ progressLabel,
843+});
764844logProgress(`${progressLabel}: done`);
765845break;
766846} catch (err) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。