




























@@ -13,6 +13,7 @@ import {
1313readdirSync,
1414realpathSync,
1515rmSync,
16+statSync,
1617writeFileSync,
1718} from "node:fs";
1819import { mkdtempSync } from "node:fs";
@@ -2215,6 +2216,7 @@ async function runInstalledAgentTurn(params) {
22152216for (let attempt = 1; attempt <= 2; attempt += 1) {
22162217const sessionId = `cross-os-release-check-${params.label}-${Date.now()}-${attempt}`;
22172218try {
2219+const logOffset = readLogFileSize(params.logPath);
22182220const result = await runInstalledCli({
22192221cliPath: params.cliPath,
22202222args: buildReleaseAgentTurnArgs(sessionId),
@@ -2223,9 +2225,13 @@ async function runInstalledAgentTurn(params) {
22232225logPath: params.logPath,
22242226timeoutMs: (CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS + 60) * 1000,
22252227});
2226-if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) {
2228+const logText = readLogTextSince(params.logPath, logOffset);
2229+if (!agentOutputHasExpectedOkMarker(result.stdout, { logText })) {
22272230throw new Error("Agent output did not contain the expected OK marker.");
22282231}
2232+if (agentTurnUsedEmbeddedFallback(result, { logText })) {
2233+throw new Error("Agent turn used embedded fallback instead of gateway.");
2234+}
22292235return result;
22302236} catch (error) {
22312237lastError = error;
@@ -3027,16 +3033,21 @@ async function runAgentTurn(params) {
30273033for (let attempt = 1; attempt <= 2; attempt += 1) {
30283034const sessionId = `cross-os-release-check-${params.label}-${Date.now()}-${attempt}`;
30293035try {
3036+const logOffset = readLogFileSize(params.logPath);
30303037const result = await runOpenClaw({
30313038lane: params.lane,
30323039env: params.env,
30333040args: buildReleaseAgentTurnArgs(sessionId),
30343041logPath: params.logPath,
30353042timeoutMs: (CROSS_OS_AGENT_TURN_TIMEOUT_SECONDS + 60) * 1000,
30363043});
3037-if (!agentOutputHasExpectedOkMarker(result.stdout, { logPath: params.logPath })) {
3044+const logText = readLogTextSince(params.logPath, logOffset);
3045+if (!agentOutputHasExpectedOkMarker(result.stdout, { logText })) {
30383046throw new Error("Agent output did not contain the expected OK marker.");
30393047}
3048+if (agentTurnUsedEmbeddedFallback(result, { logText })) {
3049+throw new Error("Agent turn used embedded fallback instead of gateway.");
3050+}
30403051return result;
30413052} catch (error) {
30423053lastError = error;
@@ -3116,16 +3127,30 @@ function buildReleaseAgentTurnArgs(sessionId) {
3116312731173128export function shouldRetryCrossOsAgentTurnError(error) {
31183129const message = error instanceof Error ? error.message : String(error);
3119-return /Agent output did not contain the expected OK marker|model idle timeout|did not produce a response before the model idle timeout|gateway request timeout for agent|Command timed out|timed out and could not be terminated cleanly/u.test(
3130+return /Agent output did not contain the expected OK marker|Agent turn used embedded fallback instead of gateway|model idle timeout|did not produce a response before the model idle timeout|gateway request timeout for agent|Command timed out|timed out and could not be terminated cleanly/u.test(
31203131message,
31213132);
31223133}
312331343135+export function agentTurnUsedEmbeddedFallback(result, options = {}) {
3136+const logText =
3137+typeof options.logText === "string"
3138+ ? options.logText
3139+ : typeof options.logPath === "string"
3140+ ? safeReadTextFile(options.logPath)
3141+ : "";
3142+return /EMBEDDED FALLBACK:/u.test(`${result.stdout ?? ""}\n${result.stderr ?? ""}\n${logText}`);
3143+}
3144+31243145export function agentOutputHasExpectedOkMarker(stdout, options = {}) {
31253146const payloadTexts = parseAgentPayloadTexts(stdout);
31263147if (payloadTexts.some((text) => text.trim() === "OK")) {
31273148return true;
31283149}
3150+if (typeof options.logText === "string") {
3151+const logTexts = parseAgentPayloadTexts(options.logText);
3152+return logTexts.some((text) => text.trim() === "OK");
3153+}
31293154if (typeof options.logPath !== "string") {
31303155return false;
31313156}
@@ -3137,6 +3162,30 @@ export function agentOutputHasExpectedOkMarker(stdout, options = {}) {
31373162}
31383163}
313931643165+function readLogFileSize(logPath) {
3166+try {
3167+return statSync(logPath).size;
3168+} catch {
3169+return 0;
3170+}
3171+}
3172+3173+function readLogTextSince(logPath, offsetBytes) {
3174+try {
3175+return readFileSync(logPath).subarray(offsetBytes).toString("utf8");
3176+} catch {
3177+return "";
3178+}
3179+}
3180+3181+function safeReadTextFile(logPath) {
3182+try {
3183+return readFileSync(logPath, "utf8");
3184+} catch {
3185+return "";
3186+}
3187+}
3188+31403189function parseAgentPayloadTexts(stdout) {
31413190try {
31423191const payload = JSON.parse(stdout);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。