openclaw/src/agents/pi-extensions/compaction-instructions.ts
정우용 72b6a11a83
fix: preserve persona and language continuity in compaction summaries (#10456)
Merged via squash.

Prepared head SHA: 4518fb20e1037f87493e3668621cb1a45ab8233e
Co-authored-by: keepitmello <71975659+keepitmello@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-13 07:40:32 -07:00

69 lines
2.3 KiB
TypeScript

/**
* Compaction instruction utilities.
*
* Provides default language-preservation instructions and a precedence-based
* resolver for customInstructions used during context compaction summaries.
*/
/**
* Default instructions injected into every safeguard-mode compaction summary.
* Preserves conversation language and persona while keeping the SDK's required
* summary structure intact.
*/
export const DEFAULT_COMPACTION_INSTRUCTIONS =
"Write the summary body in the primary language used in the conversation.\n" +
"Focus on factual content: what was discussed, decisions made, and current state.\n" +
"Keep the required summary structure and section headers unchanged.\n" +
"Do not translate or alter code, file paths, identifiers, or error messages.";
/**
* Upper bound on custom instruction length to prevent prompt bloat.
* ~800 chars ≈ ~200 tokens — keeps summarization quality stable.
*/
const MAX_INSTRUCTION_LENGTH = 800;
function truncateUnicodeSafe(s: string, maxCodePoints: number): string {
const chars = Array.from(s);
if (chars.length <= maxCodePoints) {
return s;
}
return chars.slice(0, maxCodePoints).join("");
}
function normalize(s: string | undefined): string | undefined {
if (s == null) {
return undefined;
}
const trimmed = s.trim();
return trimmed.length > 0 ? trimmed : undefined;
}
/**
* Resolve compaction instructions with precedence:
* event (SDK) → runtime (config) → DEFAULT constant.
*
* Each input is normalized first (trim + empty→undefined) so that blank
* strings don't short-circuit the fallback chain.
*/
export function resolveCompactionInstructions(
eventInstructions: string | undefined,
runtimeInstructions: string | undefined,
): string {
const resolved =
normalize(eventInstructions) ??
normalize(runtimeInstructions) ??
DEFAULT_COMPACTION_INSTRUCTIONS;
return truncateUnicodeSafe(resolved, MAX_INSTRUCTION_LENGTH);
}
/**
* Compose split-turn instructions by combining the SDK's turn-prefix
* instructions with the resolved compaction instructions.
*/
export function composeSplitTurnInstructions(
turnPrefixInstructions: string,
resolvedInstructions: string,
): string {
return [turnPrefixInstructions, "Additional requirements:", resolvedInstructions].join("\n\n");
}