慣性聚合 高效追讀感興趣之博客、新聞、科技資訊
閱原文 以慣性聚合開啟

推薦訂閱源

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4 test: trim doctor command hotspots · openclaw/openclaw@c66f16a test: isolate agent auth and spawn hotspots · openclaw/openclaw@9285935 test: stabilize MCP startup disposal race · openclaw/openclaw@dd9d2eb test: merge browser contract server suites · openclaw/openclaw@5817a76 test: narrow ollama provider discovery setup · openclaw/openclaw@a0d9598 build: declare qa-lab aimock runtime dependency · openclaw/openclaw@24431e5 test: speed up safe-bins exec harness · openclaw/openclaw@ee856ab test: preserve tool helpers in embedded runner mocks · openclaw/openclaw@acd86a0 refactor: move memory embeddings into provider plugins · openclaw/openclaw@77e6e4c test: reuse system-run temp fixtures · openclaw/openclaw@7e9ff0f test: trim hotspot wait overhead · openclaw/openclaw@12a59b0 Check: avoid duplicate boundary prep · openclaw/openclaw@baf11b8 test: reduce hotspot fixture overhead · openclaw/openclaw@3a59edd feat(ui): overhaul settings and slash command UX (#67819) thanks @Bun… · openclaw/openclaw@2cfb660 QA Matrix: exit cleanly on failure · openclaw/openclaw@42805d2 QA Matrix: isolate scenario coverage · openclaw/openclaw@7e659e1 Matrix: refresh crypto bootstrap state · openclaw/openclaw@94081d8 QA Lab: add provider registry · openclaw/openclaw@bb7e982 Matrix: add plugin changelog · openclaw/openclaw@4acab55 test: trim more hotspot overhead · openclaw/openclaw@f485311
修cli运行器:续存近尾当重植史超maxHist… · openclaw/openclaw@5c4a733
adele-with-a · 2026-05-24 · via Recent Commits to openclaw:main

@@ -577,13 +577,163 @@ describe("buildCliSessionHistoryPrompt", () => {

577577578578

it("caps rendered reseed history before adding the next user message", () => {

579579

const prompt = buildCliSessionHistoryPrompt({

580-

messages: [{ role: "compactionSummary", summary: "x".repeat(100) }],

580+

messages: [

581+

{ role: "user", content: "x".repeat(100) },

582+

{ role: "assistant", content: "y".repeat(100) },

583+

],

581584

prompt: "current ask must survive",

582585

maxHistoryChars: 20,

583586

});

584587585-

expect(prompt).toContain("[OpenClaw reseed history truncated]");

588+

expect(prompt).toContain("[OpenClaw reseed history truncated; older turns dropped]");

586589

expect(prompt).toContain("<next_user_message>\ncurrent ask must survive\n</next_user_message>");

590+

// Older 100-char prefix must be dropped by the tail slice; the

591+

// post-cap rendered tail is shorter than the dropped prefix.

587592

expect(prompt).not.toContain("x".repeat(80));

588593

});

594+595+

it("keeps the most recent turns when rendered history exceeds the cap", () => {

596+

// Older turns plus a final marker turn whose content is exactly what a

597+

// head-slice would drop first. Asserting the marker survives in the

598+

// rendered prompt locks in tail-slice semantics: a session-recovery

599+

// feature must keep the latest context, not the oldest.

600+

const prompt = buildCliSessionHistoryPrompt({

601+

messages: [

602+

{ role: "user", content: "x".repeat(8000) },

603+

{ role: "assistant", content: "y".repeat(8000) },

604+

{ role: "user", content: "FINAL_USER_MARKER" },

605+

{ role: "assistant", content: "FINAL_ASSISTANT_MARKER" },

606+

],

607+

prompt: "next ask",

608+

});

609+610+

expect(prompt).toBeDefined();

611+

expect(prompt).toContain("FINAL_USER_MARKER");

612+

expect(prompt).toContain("FINAL_ASSISTANT_MARKER");

613+

expect(prompt).toContain("[OpenClaw reseed history truncated; older turns dropped]");

614+

// The oldest 8000-char block must have been dropped — a head-slice

615+

// would have kept it instead of the recent tail.

616+

expect(prompt).not.toContain("x".repeat(8000));

617+

expect(prompt).toContain("<next_user_message>\nnext ask\n</next_user_message>");

618+

});

619+620+

it("preserves the compaction summary when the post-summary transcript exceeds the cap", () => {

621+

// loadCliSessionReseedMessages places a compactionSummary entry first

622+

// so the compacted prior context survives reseed. A blind tail slice

623+

// of the joined history would drop that summary whenever the

624+

// post-summary tail alone exceeds the cap. The structure-aware

625+

// truncation pins the summary as a prefix and caps only the tail.

626+

const prompt = buildCliSessionHistoryPrompt({

627+

messages: [

628+

{ role: "compactionSummary", summary: "COMPACTION_SUMMARY_MARKER pinned context" },

629+

{ role: "user", content: "z".repeat(8000) },

630+

{ role: "assistant", content: "w".repeat(8000) },

631+

{ role: "user", content: "POST_SUMMARY_FINAL_USER" },

632+

{ role: "assistant", content: "POST_SUMMARY_FINAL_ASSISTANT" },

633+

],

634+

prompt: "next ask",

635+

});

636+637+

expect(prompt).toBeDefined();

638+

// Compaction summary must be pinned as a prefix, not sliced away.

639+

expect(prompt).toContain("Compaction summary: COMPACTION_SUMMARY_MARKER pinned context");

640+

// Recent tail still preserved within the post-summary budget.

641+

expect(prompt).toContain("POST_SUMMARY_FINAL_USER");

642+

expect(prompt).toContain("POST_SUMMARY_FINAL_ASSISTANT");

643+

expect(prompt).toContain("[OpenClaw reseed history truncated; older turns dropped]");

644+

// Head of post-summary tail (oldest 8000-char `z` block) must be

645+

// dropped so the cap is honored.

646+

expect(prompt).not.toContain("z".repeat(8000));

647+

expect(prompt).toContain("<next_user_message>\nnext ask\n</next_user_message>");

648+

});

649+650+

it("caps oversize compaction summary while preserving recent post-summary tail", () => {

651+

// Two regressions covered here:

652+

// 1. `tailRaw.slice(-0)` would return the entire tail (JS quirk:

653+

// `String.prototype.slice(-0) === slice(0)`), defeating the cap when

654+

// the summary block consumes the budget.

655+

// 2. Pinning the full summary as-is when the summary itself exceeds

656+

// `maxHistoryChars` would blow past the cap that prevents

657+

// reseeding fresh CLI sessions with unexpectedly huge prompts.

658+

// The summary must itself be truncated to fit the budget while still

659+

// preserving the recent post-summary exact turns.

660+

const summaryText = "OVERSIZE_SUMMARY_MARKER ".repeat(50).trim();

661+

const maxHistoryChars = 200;

662+

const prompt = buildCliSessionHistoryPrompt({

663+

messages: [

664+

{ role: "compactionSummary", summary: summaryText },

665+

{ role: "user", content: "POST_SUMMARY_USER_DROPPED" },

666+

{ role: "assistant", content: "POST_SUMMARY_ASSISTANT_DROPPED" },

667+

],

668+

prompt: "next ask",

669+

// Cap well below the rendered summary block so the summary itself

670+

// must be truncated and the tail budget would naively be 0.

671+

maxHistoryChars,

672+

});

673+674+

expect(prompt).toBeDefined();

675+

// The truncated summary still leads with recognizable load-bearing

676+

// text — head-slicing preserves the orientation/intro of the summary.

677+

expect(prompt).toContain("OVERSIZE_SUMMARY_MARKER");

678+

expect(prompt).toContain("Compaction summary:");

679+

// The leading truncation marker is present so the prompt announces

680+

// what was discarded.

681+

expect(prompt).toContain("[OpenClaw reseed history truncated; older turns dropped]");

682+

// The cap is honored: the rendered <conversation_history> block

683+

// must not blow past `maxHistoryChars` plus a small wrapper allowance.

684+

const historyMatch = prompt?.match(

685+

/<conversation_history>\n([\s\S]*?)\n<\/conversation_history>/,

686+

);

687+

expect(historyMatch).not.toBeNull();

688+

const renderedHistory = historyMatch?.[1] ?? "";

689+

expect(renderedHistory.length).toBeLessThanOrEqual(maxHistoryChars);

690+

// The full untruncated summary must NOT appear — that would defeat

691+

// the cap.

692+

expect(prompt).not.toContain(summaryText);

693+

// Post-summary exact turns are newer than the summary and must still

694+

// survive inside the reserved tail budget.

695+

expect(prompt).toContain("POST_SUMMARY_USER_DROPPED");

696+

expect(prompt).toContain("POST_SUMMARY_ASSISTANT_DROPPED");

697+

expect(prompt).toContain("<next_user_message>\nnext ask\n</next_user_message>");

698+

});

699+700+

it("honors the cap when the summary block plus marker crosses it", () => {

701+

// Edge case: `summaryRendered.length < maxHistoryChars` (the gate that

702+

// routes to the oversize-summary branch is not taken) BUT

703+

// `summaryBlock.length >= maxHistoryChars` once the `\n\n` separator

704+

// is appended, making `remainingBudget <= 0`. Without summary

705+

// truncation in that branch, the rendered history block is

706+

// `summary + separator + marker` — well over `maxHistoryChars`. A

707+

// 199-char rendered summary under a 200-char cap would otherwise

708+

// produce a 257-char history block.

709+

const maxHistoryChars = 200;

710+

// `renderHistoryMessage` prefixes "Compaction summary: " (20 chars)

711+

// before the summary text, so a 179-char summary renders to 199 chars

712+

// — strictly less than the cap, but `summaryBlock = rendered + "\n\n"`

713+

// is 201 chars and `remainingBudget` is negative.

714+

const summaryPrefix = "Compaction summary: ";

715+

const summaryText = "S".repeat(maxHistoryChars - 1 - summaryPrefix.length);

716+

const prompt = buildCliSessionHistoryPrompt({

717+

messages: [

718+

{ role: "compactionSummary", summary: summaryText },

719+

{ role: "user", content: "POST_SUMMARY_TAIL_USER" },

720+

{ role: "assistant", content: "POST_SUMMARY_TAIL_ASSISTANT" },

721+

],

722+

prompt: "next ask",

723+

maxHistoryChars,

724+

});

725+726+

expect(prompt).toBeDefined();

727+

const historyMatch = prompt?.match(

728+

/<conversation_history>\n([\s\S]*?)\n<\/conversation_history>/,

729+

);

730+

expect(historyMatch).not.toBeNull();

731+

const renderedHistory = historyMatch?.[1] ?? "";

732+

expect(renderedHistory.length).toBeLessThanOrEqual(maxHistoryChars);

733+

// Marker is still present so the prompt announces what was discarded.

734+

expect(prompt).toContain("[OpenClaw reseed history truncated; older turns dropped]");

735+

// Near-cap summaries still reserve room for the newest exact turns.

736+

expect(prompt).toContain("POST_SUMMARY_TAIL_USER");

737+

expect(prompt).toContain("POST_SUMMARY_TAIL_ASSISTANT");

738+

});

589739

});