fix: align AGENTS.md template section names with post-compaction extraction (#25029) (#25098)

Merged via squash.

Prepared head SHA: 8cd6cc8049
Co-authored-by: echoVic <16428813+echoVic@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
This commit is contained in:
青雲
2026-03-05 04:16:00 +08:00
committed by GitHub
parent 4242c5152f
commit 96021a2b17
6 changed files with 72 additions and 7 deletions

View File

@@ -85,6 +85,7 @@ Docs: https://docs.openclaw.ai
- Agents/bootstrap truncation warning handling: unify bootstrap budget/truncation analysis across embedded + CLI runtime, `/context`, and `openclaw doctor`; add `agents.defaults.bootstrapPromptTruncationWarning` (`off|once|always`, default `once`) and persist warning-signature metadata so truncation warnings are consistent and deduped across turns. (#32769) Thanks @gumadeiras.
- Agents/Skills runtime loading: propagate run config into embedded attempt and compaction skill-entry loading so explicitly enabled bundled companion skills are discovered consistently when skill snapshots do not already provide resolved entries. Thanks @gumadeiras.
- Agents/Session startup date grounding: substitute `YYYY-MM-DD` placeholders in startup/post-compaction AGENTS context and append runtime current-time lines for `/new` and `/reset` prompts so daily-memory references resolve correctly. (#32381) Thanks @chengzhichao-xydt.
- Agents/Compaction template heading alignment: update AGENTS template section names to `Session Startup`/`Red Lines` and keep legacy `Every Session`/`Safety` fallback extraction so post-compaction context remains intact across template versions. (#25098) thanks @echoVic.
- Agents/Compaction continuity: expand staged-summary merge instructions to preserve active task status, batch progress, latest user request, and follow-up commitments so compaction handoffs retain in-flight work context. (#8903) thanks @joetomasone.
- Agents/Compaction safeguard structure hardening: require exact fallback summary headings, sanitize untrusted compaction instruction text before prompt embedding, and keep structured sections when preserving all turns. (#25555) thanks @rodrigouroz.
- Gateway/status self version reporting: make Gateway self version in `openclaw status` prefer runtime `VERSION` (while preserving explicit `OPENCLAW_VERSION` override), preventing stale post-upgrade app version output. (#32655) thanks @liuxiaopai-ai.

View File

@@ -13,7 +13,7 @@ This folder is home. Treat it that way.
If `BOOTSTRAP.md` exists, that's your birth certificate. Follow it, figure out who you are, then delete it. You won't need it again.
## Every Session
## Session Startup
Before doing anything else:
@@ -52,7 +52,7 @@ Capture what matters. Decisions, context, things to remember. Skip the secrets u
- When you make a mistake → document it so future-you doesn't repeat it
- **Text > Brain** 📝
## Safety
## Red Lines
- Don't exfiltrate private data. Ever.
- Don't run destructive commands without asking.

View File

@@ -19,7 +19,7 @@ x-i18n:
如果 `BOOTSTRAP.md` 存在,那就是你的"出生证明"。按照它的指引,弄清楚你是谁,然后删除它。你不会再需要它了。
## 每次会话
## 会话启动
在做任何事情之前:
@@ -58,7 +58,7 @@ x-i18n:
- 当你犯了错误 → 记录下来,这样未来的你不会重蹈覆辙
- **文件 > 大脑** 📝
## 安全
## 红线
- 不要泄露隐私数据。绝对不要。
- 不要在未询问的情况下执行破坏性命令。

View File

@@ -522,6 +522,7 @@ function appendSummarySection(summary: string, section: string): string {
/**
* Read and format critical workspace context for compaction summary.
* Extracts "Session Startup" and "Red Lines" from AGENTS.md.
* Falls back to legacy names "Every Session" and "Safety".
* Limited to 2000 chars to avoid bloating the summary.
*/
async function readWorkspaceContextForSummary(): Promise<string> {
@@ -546,7 +547,12 @@ async function readWorkspaceContextForSummary(): Promise<string> {
fs.closeSync(opened.fd);
}
})();
const sections = extractSections(content, ["Session Startup", "Red Lines"]);
// Accept legacy section names ("Every Session", "Safety") as fallback
// for backward compatibility with older AGENTS.md templates.
let sections = extractSections(content, ["Session Startup", "Red Lines"]);
if (sections.length === 0) {
sections = extractSections(content, ["Every Session", "Safety"]);
}
if (sections.length === 0) {
return "";

View File

@@ -226,4 +226,57 @@ Read WORKFLOW.md on startup.
expect(result).not.toBeNull();
expect(result).toContain("Current time:");
});
it("falls back to legacy section names (Every Session / Safety)", async () => {
const content = `# Rules
## Every Session
Read SOUL.md and USER.md.
## Safety
Don't exfiltrate private data.
## Other
Ignore this.
`;
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), content);
const result = await readPostCompactionContext(tmpDir);
expect(result).not.toBeNull();
expect(result).toContain("Every Session");
expect(result).toContain("Read SOUL.md");
expect(result).toContain("Safety");
expect(result).toContain("Don't exfiltrate");
expect(result).not.toContain("Other");
});
it("prefers new section names over legacy when both exist", async () => {
const content = `# Rules
## Session Startup
New startup instructions.
## Every Session
Old startup instructions.
## Red Lines
New red lines.
## Safety
Old safety rules.
`;
fs.writeFileSync(path.join(tmpDir, "AGENTS.md"), content);
const result = await readPostCompactionContext(tmpDir);
expect(result).not.toBeNull();
expect(result).toContain("New startup instructions");
expect(result).toContain("New red lines");
expect(result).not.toContain("Old startup instructions");
expect(result).not.toContain("Old safety rules");
});
});

View File

@@ -53,9 +53,14 @@ export async function readPostCompactionContext(
}
})();
// Extract "## Session Startup" and "## Red Lines" sections
// Extract "## Session Startup" and "## Red Lines" sections.
// Also accept legacy names "Every Session" and "Safety" for backward
// compatibility with older AGENTS.md templates.
// Each section ends at the next "## " heading or end of file
const sections = extractSections(content, ["Session Startup", "Red Lines"]);
let sections = extractSections(content, ["Session Startup", "Red Lines"]);
if (sections.length === 0) {
sections = extractSections(content, ["Every Session", "Safety"]);
}
if (sections.length === 0) {
return null;