import fs from "node:fs/promises"; import path from "node:path"; import type { AgentMessage } from "@mariozechner/pi-agent-core"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { sanitizeGoogleAssistantFirstOrdering } from "../../shared/google-turn-ordering.js"; import { normalizeOptionalString } from "../../shared/string-coerce.js"; import { truncateUtf16Safe } from "../../utils.js"; import type { WorkspaceBootstrapFile } from "../workspace.js"; import type { EmbeddedContextFile } from "./types.js";
/** * Strips Claude-style thought_signature fields from content blocks. * * Gemini expects thought signatures as base64-encoded bytes, but Claude stores message ids * like "msg_abc123...". We only strip "msg_*" to preserve any provider-valid signatures.
*/
export function stripThoughtSignatures<T>(
content: T,
options?: ThoughtSignatureSanitizeOptions,
): T { if (!Array.isArray(content)) { return content;
} const allowBase64Only = options?.allowBase64Only ?? false; const includeCamelCase = options?.includeCamelCase ?? false; const shouldStripSignature = (value: unknown): boolean => { if (!allowBase64Only) { returntypeof value === "string" && value.startsWith("msg_");
} returntypeof value !== "string" || !isBase64Signature(value);
}; return content.map((block) => { if (!block || typeof block !== "object") { return block;
} const rec = block as ContentBlockWithSignature; const stripSnake = shouldStripSignature(rec.thought_signature); const stripCamel = includeCamelCase ? shouldStripSignature(rec.thoughtSignature) : false; if (!stripSnake && !stripCamel) { return block;
} const next = { ...rec }; if (stripSnake) { delete next.thought_signature;
} if (stripCamel) { delete next.thoughtSignature;
} return next;
}) as T;
}
export const DEFAULT_BOOTSTRAP_MAX_CHARS = 12_000;
export const DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS = 60_000;
export const DEFAULT_BOOTSTRAP_PROMPT_TRUNCATION_WARNING_MODE = "once"; const MIN_BOOTSTRAP_FILE_BUDGET_CHARS = 64; // Ratios split `contentBudget` (= maxChars − marker.length − join separators), not `maxChars`. // The marker and "\n" separators are already reserved before this split runs; these ratios // only divide what's left between head and tail. Ratios sum to 1.0 — the iteration loop, // post-loop guard, and final `truncateUtf16Safe` clamp absorb any `Math.floor` residue. const BOOTSTRAP_HEAD_RATIO = 0.75; const BOOTSTRAP_TAIL_RATIO = 0.25; const MIN_BOOTSTRAP_TRIMMED_CONTENT_CHARS = 16;
export function resolveBootstrapMaxChars(cfg?: OpenClawConfig): number { const raw = cfg?.agents?.defaults?.bootstrapMaxChars; if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) { return Math.floor(raw);
} return DEFAULT_BOOTSTRAP_MAX_CHARS;
}
export function resolveBootstrapTotalMaxChars(cfg?: OpenClawConfig): number { const raw = cfg?.agents?.defaults?.bootstrapTotalMaxChars; if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) { return Math.floor(raw);
} return DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS;
}
export function resolveBootstrapPromptTruncationWarningMode(
cfg?: OpenClawConfig,
): "off" | "once" | "always" { const raw = cfg?.agents?.defaults?.bootstrapPromptTruncationWarning; if (raw === "off" || raw === "once" || raw === "always") { return raw;
} return DEFAULT_BOOTSTRAP_PROMPT_TRUNCATION_WARNING_MODE;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.