summarize-manual · diff
git:20260905.628458c to git:20260909.115c1a7
22 added, 305 removed. Audit A to A.
---
name: summarize-manual
description: >-
- Operational guide for tool-result summarization: the three compression modes
- (a-priori `summary=true`, a-posteriori `context(action="summarize")`, molt),
- the urgent and idle cadences, delayed provider reconstruction and the
- 0.85/1.0 rebuild boundaries, recovery by `tool_call_id`, and summarize
- versus molt.
- last_changed_at: "2026-09-04T00:00:00Z"
+ Operational guide for recording tool-result summaries, applying them with a full rebuild, recovering raw evidence, and choosing summarize versus molt.
+ last_changed_at: "2026-09-08T00:00:00Z"
related_files:
- src/lingtai/intrinsic_skills/system-manual/SKILL.md
- src/lingtai/tools/system/summarize.py
- src/lingtai/prompts/meta_guidance/catalog/summarize_best_practice.md
- src/lingtai/prompts/meta_guidance/catalog/summarize_reconstruction_threshold.md
maintenance: |
Tracks the summarize-manual topic it documents; update when that integration changes.
---
# Summarize Manual
- `context(action="summarize")` is context hygiene for completed tool results. It
- records an agent-authored compact replacement for one or more prior tool-result
- blocks in runtime history. It does **not** delete the original event; the raw
- result remains in logs for fallback, and the active provider continuation may
- still carry the old raw block until delayed reconstruction applies the compacted
- history.
-
- Use this manual when runtime guidance tells you to summarize, when a result is
- ranked large under `_meta.agent_meta.agent_state.current_tool_result_chars.top_results`,
- when tool output has served its immediate purpose, or when you need to explain
- how summarize differs from molt.
-
- ## 0 · The three modes (a priori, a posteriori, molt)
-
- Tool-result summarization is one face of a larger idea: keeping context lean.
- LingTai gives you three deliberate modes, ordered from local to
- whole-conversation. All three preserve the raw original in durable logs and none
- is canonical.
-
- | Mode | Trigger | When the raw is hidden | Authored by |
- |---|---|---|---|
- | **A priori** — reasoning-guided | `summarize=true` (legacy `summary=true` also accepted) on any migrated family — e.g. `file` (covers read/grep/glob-style bulky reads), `shell`, `daemon` | *before* the result ever enters context | the runtime LLM, driven by your `reasoning` |
- | **A posteriori** — agent-guided | `context(action="summarize")` | *after* you have already seen and digested it | you |
- | **Molt** — context-pressure-triggered | `context(action='molt', ...)` | the whole conversation is continued/reset | you (briefing) |
-
- Sections 1–6 below are mostly about the a-posteriori `summarize` action; §1a
- covers the a-priori `summary=true` option and when to prefer it; §6 contrasts
- both with molt.
-
- ## 1a · A priori summary: `summarize=true` on migrated tool families
-
- Any LingTai Tool Protocol v2-migrated family — `web`, `mcp`, `file` (covering
- read/grep/glob-style bulky reads), `vision`, `avatar`, `soul`, `shell`,
- `notification`, `system`, `daemon`, `email`, `task_card`, `context`, `psyche`,
- `plugin` — accepts an optional boolean root `summarize` (legacy spelling `summary` is
- also honored on any call, for backward compatibility). Default `false`. When
- `true`:
-
- - The tool runs **normally**. The raw result is written to the durable event log
- and (if oversized) spilled, exactly as with `summary=false` — nothing is lost
- and the raw is recoverable by `tool_call_id` (see §4).
- - **Before** the result enters your model-visible context, the runtime replaces
- it with a generated summary. The summary is driven by your `reasoning` field
- on that call — so when you set `summary=true`, make `reasoning` specific about
- what to retain (e.g. "I only need the failing test names and their assertion
- messages", "I only need the list of changed file paths").
- - The replacement is clearly marked **generated and non-canonical** and carries
- a retrieval hint pointing back at the preserved raw by `tool_call_id`.
-
- Prefer it when you can state the retention spec before the call and the output
- is large — rule of thumb >10k chars; leave it `false` when you need exact
- line/file/diff/stderr text you will quote, diff, patch, or compare.
-
- **A priori is preferred but still lossy.** The runtime discards everything
- outside what your `reasoning` named, with no chance for you to notice what
- mattered — so it is **not** a substitute for a-posteriori
- `context(action="summarize")` on high-information-density results whose
- important facts you cannot name in advance (daemon outputs, code reviews, long
- reports). For those, leave `summary=false`, consume the raw, then summarize a
- posteriori once you know what to keep — or molt when the whole conversation is
- the pressure.
-
- **Hard cap.** If the raw visible payload exceeds **500,000 characters**, the
- runtime does **not** call the summarizer LLM. Instead you receive a small
- summary-layer refusal that says the result exceeded the cap, that the raw is
- preserved, and how to retrieve / narrow / rerun. The oversized raw is **not**
- dumped into your context on this path. Narrow the call (tighter command, path,
- pattern, or `offset`/`limit`) and rerun, or rerun with `summary=false` to take
- the raw (capped/spilled) result directly.
-
- **Untrusted output.** The summarizer treats the tool output strictly as data: it
- will not follow instructions embedded inside the tool result. This is the same
- prompt-injection posture the rest of the runtime uses for external text.
-
- **Fail-closed.** `summary=true` is a request *not* to put the raw into context.
- If the summarizer call fails or returns nothing, you get a summary-layer error
- with the retrieval locator — never the raw payload. Rerun with `summary=false`
- if you actually need the raw.
-
- **Reasoning critique as feedback.** A generated `summary=true` result may end
- with a brief, plain-text critique of whether your `reasoning` (the retention
- spec) was specific enough to guide what to keep. Treat it as feedback: sharpen
- your `reasoning` on later `summary=true` calls so the summary keeps what you
- actually need. If the critique says the reasoning was too poor for the summary
- to be trusted, do not rely on the lossy summary — inspect the preserved raw
- original via the retrieval hint / `raw_locator` (by `tool_call_id`, see §4)
- before acting on it. This critique is ordinary summary prose, not a separate
- field — read it, don't parse it.
-
- **Track the a-priori savings.** Each `summary=true` result also carries
- `summary_kind` and generated-summary `summary_effect` fields (`prev_chars`,
- `after_chars`, `saved_chars`). When the savings are weak or negative, or the
- closing critique says the retention spec was vague, sharpen future
- `reasoning`/tool choice and deposit the lesson into pad, knowledge, skills, or
- lingtai as appropriate.
-
- ## 1 · The principle: progressive disclosure
-
- A raw tool result is the first layer: it is useful while you inspect it. After
- you have consumed it and no longer need the raw text visible, the better layer is
- an index that future-you can reason from without carrying the raw bulk. Strongly
- prefer the compact index once summarization is warranted by the §2 gate;
- keep raw output visible while needed for inspection, quotation, or comparison.
-
- A good summary should let future-you decide whether the hidden raw result must
- be reopened. Preserve:
-
- - the conclusion or decision;
- - key evidence, measurements, or error text;
- - paths, URLs, message IDs, tool_call_ids, commit hashes, job IDs, and other
- anchors;
- - validation status and commands/tests run;
- - risks, caveats, and unresolved questions;
- - next steps.
-
- Do not write casual one-liners for consequential results. The summary is the
- progressive-disclosure entry point.
-
- ## 2 · The two summarize cadences
-
- **Summarize cadence.** Strongly prefer a priori `summary=true` on `shell`,
- `file` (read/glob/grep), or `daemon` when you can predict bulky output and
- already know the facts, counts, anchors, or conclusion you need from the call;
- put that retention contract in `reasoning` so raw bulk never spends context.
- Leave it off when exact raw text or unknown high-information details may matter.
- Treat a posteriori `context(action="summarize")` as a last resort, not routine
- cleanup: use it only when context is close to overflowing and a molt is
- unsuitable. Otherwise prefer a priori summary before the call, narrower work,
- or a daemon; at a whole-session boundary, tend durable stores and molt instead.
-
- The urgent and idle patterns below operate within that gate; neither makes
- a-posteriori summarization a routine housekeeping obligation.
-
- ### Urgent cadence: summarize the bulky result now
+ Use this reference after you have inspected a bulky tool result and know what a future turn must retain, or when current Context guidance asks you to compact consumed results. It is the focused procedure; resident `meta_guidance` remains the source for current pressure timing.
- When the §2 execution gate is met, prioritize a long or noisy result — typically
- one that ranks high in
- `_meta.agent_meta.agent_state.current_tool_result_chars.top_results` (above its `threshold`,
- counted in `over_threshold_count`). `agent_meta` is a complete current final-carrier snapshot attached to each eligible final carrier. Its nested `agent_state.current_tool_result_chars` is current on the newest emitted snapshot; older snapshots remain retained historical traces and are not actionable.
+ ## Choose the operation
- 1. Read or inspect the result first.
- 2. Decide what future-you needs from it.
- 3. On a later step, call `context(action="summarize")` on the completed prior
- result. Do not try to summarize the current result in the same tool batch
- before it exists.
- 4. Batch several already-digested results in one summarize call when convenient.
+ - `context(action="summarize")` is **record-only**. It replaces selected prior tool-result blocks in runtime history with your agent-authored summaries, marks them pending, and preserves the raw event for recovery. The active provider continuation may still carry the raw block.
+ - `context(action="rebuild")` is the one active application path. It first re-reads and recomposes **all** canonical prompt sources, then records/applies supplied and pending summaries, then requests provider replay with the new prompt and history. Bare `input={}` is valid, including with no pending summaries.
+ - `context(action="molt")` is the whole-session boundary. Choose it when pressure, an explicit human reset request, or conversation confusion makes a fresh briefing worthwhile; do not use it as task-completion housekeeping.
- ### Idle cleanup cadence: sweep what is already consumed
+ The root `summarize` boolean is a separate generic result-presentation control. It is not the `context` action, is not an item-list input, and does not apply a recorded summary to provider context. The action/schema descriptions are authoritative for fields and requiredness.
- When the task quiets down, inspect older results that are already digested,
- obsolete, or useful only as evidence anchors. This is a decision point, not an
- automatic summarize call: apply the §2 execution gate before replacing them
- with summaries. Prefer avoiding raw bulk in the first place; keep only the
- context the continuing task actually needs.
+ ## A-priori root result summaries
- Idle cleanup is also the right time to decide whether a deliberate molt is
- worth its cost. If the current task is complete, necessary reporting/durable
- stores are tended, no human reply is pending, and no concrete next action
- remains, do not molt automatically; molt only when context pressure (≥85%),
- explicit human request, or conversation confusion makes the fresh briefing
- worth its cost. Summarize is a mini molt for a consumed tool result. Once you
- have decided to molt, do not spend a separate summarize call merely to
- prepare; molt is the stronger whole-conversation summarize boundary.
+ Before a call, root `summarize=true` requests a generated, noncanonical, lossy summary; put the retention specification in `reasoning` and preserve its `raw_locator` (and producer ID) for recovery. If generation fails, it is fail-closed: no raw payload is returned, so rerun narrowly or with `summarize=false`. Check `summary_effect.prev_chars`, `after_chars`, and `saved_chars`; weak savings are a lesson to sharpen the retention specification or choose a narrower call.
- ## 3 · How to call summarize
+ ## Record a summary
- Summarize prior completed tool results only:
+ Summarize only a completed result you have read. Pick targets from the newest `_meta.agent_meta.agent_state.current_tool_result_chars.top_results` IDs. In each item, `tool_call_id` is the producer call ID, not the visible `_tool_call_id` event reference; preserve any `raw_locator` or spill path. Preserve the conclusion, evidence or error, paths/URLs/IDs, validation status, risks, and next step—enough to decide whether the raw result must be reopened. Batch several already-digested results when useful:
```json
{
"action": "summarize",
"input": {
"items": [
- {
- "tool_call_id": "call_abc123",
- "summary": "What future-you needs: conclusion, evidence, anchors, validation, risks, next steps."
- }
+ {"tool_call_id": "call_abc123", "summary": "Conclusion, evidence, anchors, risks, and next step."}
]
},
- "reasoning": "Compact the completed result while preserving its evidence and next steps."
+ "reasoning": "Keep the evidence and recovery anchor needed by the next turn."
}
```
- Operational rules:
-
- - `tool_call_id` is the producer call ID shown on the original result, not the
- visible `_tool_call_id` event ref.
- - A successful summarize updates the runtime-history/chat-history copy and
- persists that compact replacement; it does not mutate the original event log
- and does not by itself prove the active provider continuation has dropped the
- old raw block.
- - If a large-result notification points at that result, successful summarize
- clears the reminder.
- - If the result is still ambiguous, reopen or inspect it before summarizing.
-
- ## 3a · Delayed summarization: summary recorded now, provider reconstruction delayed
-
- Summarize has two decoupled effects:
-
- 1. **Runtime-history replacement now.** The prior tool-result block in local
- history is replaced with your agent-authored summary, stamped `status: pending`,
- and matching large-result reminders may clear.
- 2. **Full reconstruction later.** The current provider continuation may still
- contain the old raw block. A manual `context(action="rebuild")` first re-reads
- and recomposes every canonical system-prompt source, then applies pending/new
- summaries (markers flip to `status: done`), then requests provider replay with
- the new prompt/history. The automatic 1.0 hard forced path uses the
- same full prompt reconstruction contract before fresh replay.
-
- The rebuild action's own result reports the provider round that requested the rebuild.
- Post-rebuild context usage does not exist yet at that point; it only becomes
- observable on the next provider round. Do not read the requesting round's usage
- number as if it already reflects the rebuilt context.
-
- The dynamic pending totals in the result comment scan only `status: pending`
- markers — already-applied (`done`) markers and legacy markers without a status
- are not counted as pending.
-
- Reconstruction is delayed because runtimes append turns onto a stable
- cache/continuation prefix, and rebuilding that prefix on every summarize would
- discard the cache benefit.
+ Recording is not durable-store authoring and does not rebuild. Do not summarize text that still needs exact inspection, quotation, patching, or comparison. If the result is still ambiguous, reopen it first.
- - **Below 1.0 of the context window:** summarize stays pending at the provider
- layer and the session keeps appending. This delay is normal, not a failure.
- - **At or above 0.85 of the context window:** `_meta.agent_meta.agent_state.context.rebuild`
- is stamped continuously. It is a decision prompt / permission, not an automatic
- rebuild — recording summaries never triggers a provider-context rebuild on its
- own. If making already-recorded summaries active in the provider context earlier
- is worth the cost, make one proactive tactical
- `context(action="rebuild", input={})` call. Every call recomposes all canonical
- prompt sources first. With new items it then records/applies them; with no items
- it applies the already-pending set, or simply replays the newly composed prompt
- when none are pending. Bare `{}` is valid. Do not loop rebuild/summarize calls.
- - **At 1.0 of the context window (the full-context HARD boundary):** the runtime
- **forces** a provider-context rebuild / fresh replay on the next request
- **regardless of whether pending summaries exist**, but only **once per
- continuous full-context episode**. The automatic forced rebuild fires a single
- time when provider-reported usage first reaches `1.0` (inclusive); it does NOT
- re-force while usage stays at/above `1.0` (including exactly `1.0`), and it
- re-arms only after a later provider round drops usage strictly below `1.0`, so a
- future crossing can force exactly once again. Both automatic paths — the
- pre-request boundary check and the immediate post-`summarize` release — share
- this one latch, so they cannot double-fire. (Explicit
- `context(action="rebuild")` is independent and always available.)
- If pending summaries exist,
- they are applied and their markers marked done. `summarize` is the only
- historical tool-result body replacement a rebuild applies; the fresh replay
- otherwise preserves each historical timely-transient holder and does not
- strip its agent_meta/guidance or notifications/notification_guidance keys,
- on every provider, without rewriting recorded history — only the LATEST
- holder
- per family represents current state, older holders are historical traces
- and must not be acted on. Every 1.0 forced rebuild ALWAYS carries a one-shot
- `_meta.agent_meta.agent_state.events.reconstruction.warning`: it reports the before→after context
- change, advises that reaching the full boundary means waiting was not ideal (prefer
- a proactive 0.85 `context(action="rebuild")`), and says that if the rebuilt context is still
- above the 0.75 recovery target you should tend durable stores and molt. This is
- one unified warning — it does not branch on whether context dropped low or stayed
- high.
- - **If the forced rebuild does NOT clear the overflow:** the persistent
- `Forced Rebuilt Failed` warning activates. Once the forced fresh replay's own
- first provider response is observed and that post-rebuild provider input is still
- **strictly above** `1.0` (a failed forced request keeps verification pending
- until a successful provider-usage result exists), EVERY following result carries
- a permanent `_meta.agent_meta.agent_state.context.molt` line, verbatim:
- `100% context Forced Rebuild Failed to Bring Usage Below 100%. Context overflowed!! (xxx %) Molt IMMEDIATELY!!`
- (`xxx` = the current measured percentage, one decimal). It rides the same
- permanent current-state channel as the sustained-pressure and cache-miss-budget
- molt reminders (each preserved on its own line when several coexist). Because the
- runtime will NOT keep force-rebuilding while you stay overflowed, this line is
- the signal that the emergency rebuild could not recover the context — molt
- immediately. At exactly `1.0` after the rebuild there is no repeat rebuild and no
- overflow warning (the warning is for strictly `> 1.0`).
+ ## Apply and recover
- Waiting for the 1.0 forced boundary is the emergency path — prefer the proactive
- 0.85 rebuild. If no summary is pending, the forced rebuild has nothing to apply
- (the replay-preservation rule above still holds), so summarize more or molt
- instead. `refresh` is the emergency path for broken/stale context or explicit
- human direction — never the way to "apply" a summary. If summarize or
- a rebuild still cannot bring context below `0.75 * context_window` (the recovery
- target), tend durable stores and molt deliberately.
+ Call one `context(action="rebuild", input={})` when making recorded summaries or a durable prompt-source edit active is worth a provider replay. Reconstruction is deliberately delayed for cache efficiency; do not loop summarize/rebuild calls. If composition fails, the Context contract leaves summaries unapplied and reports the reconstruction error.
- ## 4 · Recovering the original result
+ The rebuild receipt reports the provider round that requested the rebuild; post-rebuild context usage does not exist yet in that receipt. Observe it on the next provider round.
- A summarized block should carry a retrieval hint. The usual fallback is to search
- the agent event log by the preserved `tool_call_id`:
+ Keep the original `tool_call_id` in any summary. The normal fallback is a narrow JSONL search:
```bash
- grep 'call_abc123' <workdir>/logs/events.jsonl
+ rg 'call_abc123' <workdir>/logs/events.jsonl
```
- For structured trace work, use the SQLite/log tooling documented in
- `../../../system-manual/reference/sqlite-log-query/SKILL.md`, for example `lingtai-agent log query`, to
- locate the event and inspect nearby context.
-
- If the original was a spill result, the log entry or summary should also point to
- the spill path under `tmp/tool-results/`. Preserve that path in the summary.
-
- ## 5 · Good and bad uses
-
- Good uses:
-
- - a large test output after you know which tests passed/failed;
- - a long file read after extracting the relevant lines and path;
- - a search sweep after preserving matched files and decisions;
- - a channel read after responding and keeping the message IDs that matter;
- - a resolved error once the recovery path is known.
-
- Bad uses:
-
- - summarizing before you have read or understood the result;
- - hiding evidence that you still need to inspect line by line;
- - replacing a required deliverable with a vague recap;
- - assuming summarize is a durable memory layer.
-
- ## 6 · Summarize is not molt
-
- Neither summary mode updates pad, character, knowledge, skills, or the
- session-journal, and neither sheds the conversation — the mini-molt framing and
- the molt boundary are resident. `context-manual` owns the molt procedure and its
- required checklist. Use them together:
+ For a spilled result, preserve and reopen its `tmp/tool-results/` path. Use `system(action="manual", input={}, reasoning="load System routes")` for settings, cache-miss budget ownership, and current automatic threshold details; this reference does not duplicate System-owned numbers or configuration procedures.
- 1. Summarize bulky consumed tool results so the active context is navigable.
- 2. Tend durable stores for facts, procedures, identity changes, and current plan.
- 3. Molt deliberately while you still have enough context to write a good
- briefing, not only when warnings become urgent.
+ When the current pressure reminder is active, follow the resident cadence: make at most one useful summarize/rebuild pass, then stop repeating it and molt deliberately if the context remains too high. The pressure reminder is a decision aid, not an automatic molt order. A deliberate molt still requires the Context manual's journal gate and concise successor handoff.