mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-17 18:21:39 +00:00
fix(status): preserve OAuth JSON diagnostics (#103106)
Co-authored-by: 0668001336 <wang.lizhang@xydigit.com>
This commit is contained in:
committed by
GitHub
parent
d2163e672c
commit
fdde2ecde4
@@ -24,6 +24,44 @@ describe("summarizeLogTail", () => {
|
||||
expect(lines).toEqual(["[openai] token refresh 401 invalid_grant · re-auth required"]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["closing brace", "Session invalidated } due to signing in again"],
|
||||
["opening brace", "Session invalidated { due to signing in again"],
|
||||
["escaped quote before a brace", 'Session invalidated after "}" signing in again'],
|
||||
])("keeps OAuth JSON diagnostics with a %s", (_caseName, message) => {
|
||||
const sentinel = "[gateway] synthetic sentinel after OAuth JSON";
|
||||
const lines = summarizeLogTail([
|
||||
"[openai] Token refresh failed: 401 {",
|
||||
`"error":${JSON.stringify({ code: "invalid_grant", message })}`,
|
||||
"}",
|
||||
sentinel,
|
||||
]);
|
||||
|
||||
expect(lines).toEqual([
|
||||
"[openai] token refresh 401 invalid_grant · re-auth required",
|
||||
sentinel,
|
||||
]);
|
||||
});
|
||||
|
||||
it("parses the first complete OAuth JSON object before an adjacent object", () => {
|
||||
const lines = summarizeLogTail([
|
||||
"[openai] Token refresh failed: 401 {",
|
||||
'"error":{"code":"invalid_grant","message":"Session invalidated due to signing in again"}}{"ignored":true}',
|
||||
]);
|
||||
|
||||
expect(lines).toEqual(["[openai] token refresh 401 invalid_grant · re-auth required"]);
|
||||
});
|
||||
|
||||
it("consumes an incomplete OAuth JSON block through the end of the tail", () => {
|
||||
const lines = summarizeLogTail([
|
||||
"[openai] Token refresh failed: 401 {",
|
||||
'"error":{"code":"invalid_grant","message":"Session invalidated due to signing in again"}',
|
||||
"unrelated-looking trailing line",
|
||||
]);
|
||||
|
||||
expect(lines).toEqual(["[openai] token refresh 401"]);
|
||||
});
|
||||
|
||||
it("keeps bounded OAuth diagnostics UTF-16 well-formed", () => {
|
||||
const lines = summarizeLogTail([
|
||||
"[openai] Token refresh failed: 500 {",
|
||||
|
||||
@@ -5,6 +5,7 @@ import { normalizeOptionalString } from "@openclaw/normalization-core/string-coe
|
||||
import { truncateUtf16Safe } from "@openclaw/normalization-core/utf16-slice";
|
||||
import { classifyOAuthRefreshFailureReason } from "../../agents/auth-profiles/oauth-refresh-failure.js";
|
||||
import { readGatewayLogTailLines } from "../../daemon/diagnostics.js";
|
||||
import { extractBalancedJsonPrefix } from "../../shared/balanced-json.js";
|
||||
|
||||
/** Reads the last non-empty lines from a gateway log file, returning an empty list on read failure. */
|
||||
export async function readFileTailLines(filePath: string, maxLines: number): Promise<string[]> {
|
||||
@@ -16,13 +17,6 @@ export async function readFileTailLines(filePath: string, maxLines: number): Pro
|
||||
return out.map((line) => line.trimEnd()).filter((line) => line.trim().length > 0);
|
||||
}
|
||||
|
||||
function countMatches(haystack: string, needle: string): number {
|
||||
if (!haystack || !needle) {
|
||||
return 0;
|
||||
}
|
||||
return haystack.split(needle).length - 1;
|
||||
}
|
||||
|
||||
function shorten(message: string, maxLen: number): string {
|
||||
const cleaned = message.replace(/\s+/g, " ").trim();
|
||||
if (cleaned.length <= maxLen) {
|
||||
@@ -51,16 +45,15 @@ function consumeJsonBlock(
|
||||
return null;
|
||||
}
|
||||
|
||||
const parts: string[] = [startLine.slice(braceAt)];
|
||||
let depth = countMatches(parts[0] ?? "", "{") - countMatches(parts[0] ?? "", "}");
|
||||
let i = startIndex;
|
||||
while (depth > 0 && i + 1 < lines.length) {
|
||||
i += 1;
|
||||
const next = lines[i] ?? "";
|
||||
parts.push(next);
|
||||
depth += countMatches(next, "{") - countMatches(next, "}");
|
||||
const raw = [startLine.slice(braceAt), ...lines.slice(startIndex + 1)].join("\n");
|
||||
const fragment = extractBalancedJsonPrefix(raw);
|
||||
if (!fragment) {
|
||||
// A bounded tail can end mid-object. Consume the rest so orphaned JSON
|
||||
// fields do not escape into the user-facing diagnosis as ordinary lines.
|
||||
return { json: raw, endIndex: lines.length - 1 };
|
||||
}
|
||||
return { json: parts.join("\n"), endIndex: i };
|
||||
const consumedLineOffset = fragment.json.split("\n").length - 1;
|
||||
return { json: fragment.json, endIndex: startIndex + consumedLineOffset };
|
||||
}
|
||||
|
||||
/** Summarizes gateway log tail lines, grouping repeated failures and trimming long output. */
|
||||
|
||||
Reference in New Issue
Block a user