@knightcodeai/cli-win32-x64 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/CHANGELOG.md +196 -0
- package/bin/README.md +36 -0
- package/bin/docs/compaction.md +416 -0
- package/bin/docs/containerization.md +111 -0
- package/bin/docs/custom-provider.md +777 -0
- package/bin/docs/development.md +71 -0
- package/bin/docs/docs.json +156 -0
- package/bin/docs/environment-variables.md +97 -0
- package/bin/docs/extensions.md +3020 -0
- package/bin/docs/images/doom-extension.png +0 -0
- package/bin/docs/images/interactive-mode.png +0 -0
- package/bin/docs/images/tree-view.png +0 -0
- package/bin/docs/index.md +84 -0
- package/bin/docs/json.md +98 -0
- package/bin/docs/keybindings.md +236 -0
- package/bin/docs/llama-cpp.md +101 -0
- package/bin/docs/models.md +571 -0
- package/bin/docs/packages.md +228 -0
- package/bin/docs/prompt-templates.md +96 -0
- package/bin/docs/providers.md +317 -0
- package/bin/docs/quickstart.md +167 -0
- package/bin/docs/rpc.md +1618 -0
- package/bin/docs/sdk.md +1219 -0
- package/bin/docs/security.md +59 -0
- package/bin/docs/session-format.md +438 -0
- package/bin/docs/sessions.md +145 -0
- package/bin/docs/settings.md +368 -0
- package/bin/docs/shell-aliases.md +13 -0
- package/bin/docs/skills.md +231 -0
- package/bin/docs/terminal-setup.md +177 -0
- package/bin/docs/termux.md +127 -0
- package/bin/docs/themes.md +320 -0
- package/bin/docs/tmux.md +63 -0
- package/bin/docs/tui.md +942 -0
- package/bin/docs/usage.md +307 -0
- package/bin/docs/windows.md +39 -0
- package/bin/export-html/template.css +1066 -0
- package/bin/export-html/template.html +55 -0
- package/bin/export-html/template.js +1864 -0
- package/bin/export-html/vendor/highlight.min.js +1213 -0
- package/bin/export-html/vendor/marked.min.js +78 -0
- package/bin/knightcode.exe +0 -0
- package/bin/package.json +76 -0
- package/bin/photon_rs_bg.wasm +0 -0
- package/bin/theme/dark.json +90 -0
- package/bin/theme/light.json +89 -0
- package/bin/theme/theme-schema.json +352 -0
- package/package.json +7 -1
package/bin/CHANGELOG.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# @knightcodeai/cli
|
|
2
|
+
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2990a0f: Tool calls now render as blocks in the transcript. Each one shows a
|
|
8
|
+
`Bash(...)` / `Read(...)` / `Update(...)` header with its result collapsed
|
|
9
|
+
underneath on a `⎿` gutter, instead of the flat before/after dump. The rest of
|
|
10
|
+
the chrome — boxed messages, the rounded input frame, the braille spinner, the
|
|
11
|
+
banner and footer — is unchanged.
|
|
12
|
+
|
|
13
|
+
Fixed a context-window overflow loop. Messages with no provider usage yet are
|
|
14
|
+
estimated at 4 chars/token, but real tokenizers land nearer 3 on code and JSON,
|
|
15
|
+
so reserving `max_tokens` against the raw estimate could push prompt +
|
|
16
|
+
`max_tokens` past the window. The provider rejected it as an overflow, the agent
|
|
17
|
+
compacted, `max_tokens` re-expanded into the freed room, and the next request
|
|
18
|
+
failed the same way. The estimated part is now padded so the reservation stays
|
|
19
|
+
inside the window.
|
|
20
|
+
|
|
21
|
+
## 0.5.0
|
|
22
|
+
|
|
23
|
+
### Minor Changes
|
|
24
|
+
|
|
25
|
+
- dafe408: A rebuilt agent core.
|
|
26
|
+
|
|
27
|
+
The agent loop, session storage, provider layer and terminal UI were all
|
|
28
|
+
replaced. What that buys:
|
|
29
|
+
|
|
30
|
+
- **A measured ~1,100-token floor** for the system prompt and tool definitions —
|
|
31
|
+
every request is smaller, on every model.
|
|
32
|
+
- **Real multi-provider support**: Anthropic, OpenAI/Codex, OpenRouter, Amazon
|
|
33
|
+
Bedrock, xAI, Kimi, GitHub Copilot, and any custom endpoint through
|
|
34
|
+
`models.json`. OAuth sign-in where the provider supports it, API keys
|
|
35
|
+
everywhere else.
|
|
36
|
+
- **Sessions you can leave and come back to**: resume, fork, branch, search, and
|
|
37
|
+
automatic compaction when a conversation outgrows the context window.
|
|
38
|
+
- **Extensions, skills and prompt templates**, discovered from the project or
|
|
39
|
+
installed globally.
|
|
40
|
+
- **Headless mode**: `--print` with `text`, `json` or `rpc` output, for scripting
|
|
41
|
+
and for driving KnightCode from another program.
|
|
42
|
+
|
|
43
|
+
Distribution is unchanged — a self-contained compiled binary per platform, no
|
|
44
|
+
Bun or Node needed at runtime.
|
|
45
|
+
|
|
46
|
+
## 0.4.1
|
|
47
|
+
|
|
48
|
+
### Patch Changes
|
|
49
|
+
|
|
50
|
+
- 5ffa10b: Re-inject the current todo list after each tool round so the model's plan stays in context during long turns. Only fires when the list has unfinished items and has changed since the last round.
|
|
51
|
+
|
|
52
|
+
## 0.4.0
|
|
53
|
+
|
|
54
|
+
### Minor Changes
|
|
55
|
+
|
|
56
|
+
- aa2645e: Harness reliability: safer edits and recovery from flaky model streams.
|
|
57
|
+
|
|
58
|
+
- **No blind or stale edits.** A file must be read before it can be edited, and an edit is rejected if the file changed on disk since that read — so a write can't silently clobber newer changes. The read state is rebuilt from the transcript, so it survives a session resume.
|
|
59
|
+
- **No accidental repeats.** Identical read-only tool calls in one round run once instead of duplicating, and the loop guard stops repeated identical calls sooner.
|
|
60
|
+
- **Auto-retry on flaky streams.** Transient stream failures and empty responses retry with exponential backoff (honoring `Retry-After`); cancelling mid-backoff no longer fires an extra model call.
|
|
61
|
+
- **Tool errors self-correct.** An invalid tool call no longer ends the turn — the model gets the error back and can fix it.
|
|
62
|
+
- **No misleading diffs.** An edit diff shows only after the edit actually applies; failed or rejected edits don't render one.
|
|
63
|
+
|
|
64
|
+
## 0.3.1
|
|
65
|
+
|
|
66
|
+
### Patch Changes
|
|
67
|
+
|
|
68
|
+
- a2679c6: Fix the `/exit` command freezing the terminal in packaged builds. Process cleanup used `spawnSync(process.execPath, ["-e", ...])` as a sleep, but in a compiled standalone binary `process.execPath` is the CLI itself, so it relaunched the TUI and blocked forever. Replaced it with an in-process sleep and made exit terminate the process explicitly.
|
|
69
|
+
|
|
70
|
+
## 0.3.0
|
|
71
|
+
|
|
72
|
+
### Minor Changes
|
|
73
|
+
|
|
74
|
+
- 9531729: Add automatic skill discovery, hot-reload, and path-scoped skills so installed skills surface and get loaded without having to be named explicitly.
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
- **Skill auto-discovery.** Each turn a cheap side-query compares your request against the installed skills, surfaces the relevant ones, and directs the model to load them via the `Skill` tool before responding. Surfaced skills appear as a visible `↳ Relevant skills: …` line in the chat. Controlled by the `skills.autoDiscover` setting (on by default).
|
|
78
|
+
- **Skill hot-reload.** A file watcher picks up added, edited, or removed `SKILL.md` files mid-session, so changes take effect without restarting. Controlled by the `skills.hotReload` setting (on by default).
|
|
79
|
+
- **Path-scoped (conditional) skills.** A skill with a `paths` frontmatter glob is kept out of the always-on skill list and surfaces only when you edit a file matching its globs.
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
- The skill index injected into the system prompt is now size-bounded: descriptions are truncated to fit the budget and, in the extreme, the listing falls back to names only — but every skill name is always shown, so no installed skill becomes undiscoverable.
|
|
83
|
+
|
|
84
|
+
## 0.2.1
|
|
85
|
+
|
|
86
|
+
### Patch Changes
|
|
87
|
+
|
|
88
|
+
- b529674: ### Added
|
|
89
|
+
|
|
90
|
+
Memory follow-ups: feed recent tool usage into the recall selector as an extra relevance signal, frame extraction's "new messages" window from a per-session cursor (so durable facts mentioned during gate-skipped turns are still reconsidered), and drain any in-flight memory extraction on `/exit` (bounded) so a save isn't dropped at shutdown.
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
|
|
94
|
+
`Tab` mode cycle so it reaches `AUTO`: previously `Tab` only toggled between `BUILD` and `PLAN`, making `AUTO` selectable solely via the `/agents` dialog. `Tab` now cycles `BUILD → PLAN → AUTO → BUILD`.
|
|
95
|
+
|
|
96
|
+
### Removed
|
|
97
|
+
|
|
98
|
+
Drop two unused dependencies from `@knightcodeai/cli`: `pretty-ms` (never imported) and `hono` (the toast provider's `useMemo` now imports from `react` instead of `hono/jsx`).
|
|
99
|
+
|
|
100
|
+
- 23a8811: Refresh the supported model catalog: add newer free and paid OpenRouter models, repoint aliases to their successors, change the default model, and drop discontinued entries.
|
|
101
|
+
|
|
102
|
+
### Added
|
|
103
|
+
|
|
104
|
+
Refresh the supported model catalog with new OpenRouter models: `nvidia/nemotron-3-ultra-550b-a55b:free` (Nemotron 3 Ultra 550B), `nex-agi/nex-n2-pro:free` (Nex N2 Pro), `qwen/qwen3.7-plus` (Qwen3.7 Plus), `z-ai/glm-5.2` (GLM 5.2), and `moonshotai/kimi-k2.7-code` (Kimi K2.7 Code). New `qwen` and `nex` model aliases accompany them.
|
|
105
|
+
|
|
106
|
+
### Changed
|
|
107
|
+
|
|
108
|
+
Default model is now `nvidia/nemotron-3-ultra-550b-a55b:free` (was `z-ai/glm-4.5-air:free`). The `glm`, `kimi`, and `nemotron` aliases were repointed to their successor models (`z-ai/glm-5.2`, `moonshotai/kimi-k2.7-code`, `nvidia/nemotron-3-ultra-550b-a55b:free`), and the onboarding shortlist was updated to match the new catalog.
|
|
109
|
+
|
|
110
|
+
### Removed
|
|
111
|
+
|
|
112
|
+
Drop discontinued/older version models: `z-ai/glm-4.5-air:free`, `deepseek/deepseek-v4-flash:free`, `z-ai/glm-5.1`, `moonshotai/kimi-k2.6`, and `nvidia/nemotron-3-super-120b-a12b:free`, along with their `glm_air` and `deepseek` aliases.
|
|
113
|
+
|
|
114
|
+
- b529674: ### Added
|
|
115
|
+
|
|
116
|
+
Accurate per-session cost: enable OpenRouter usage accounting (`usage.include`) so each request returns its **actual** cost. The in-app `/cost` "Session cost" now sums real costs (correct for free/cached/uncurated models) and only falls back to the local price table when a message has no reported cost.
|
|
117
|
+
|
|
118
|
+
Session grouping on OpenRouter: send the session id as the `x-session-id` header so a session's requests are grouped in OpenRouter's logs (Sessions tab) and routed stickily to the same provider for better prompt-cache hits. Requests are also tagged with the session id via the `user` field for per-request "Client User ID" attribution.
|
|
119
|
+
|
|
120
|
+
### Changed
|
|
121
|
+
|
|
122
|
+
OpenRouter app attribution: `HTTP-Referer` → `https://knightcode.raghavseth.in` and `X-Title` → `KnightCode` (was "KnightCode CLI").
|
|
123
|
+
|
|
124
|
+
## 0.2.0
|
|
125
|
+
|
|
126
|
+
### Minor Changes
|
|
127
|
+
|
|
128
|
+
- f2846df: Standalone query engine, concurrent tool scheduler, and Apache-2.0 licensing.
|
|
129
|
+
|
|
130
|
+
This release replaces the React `useChat`-based chat harness with a dedicated,
|
|
131
|
+
framework-agnostic query engine, adds a concurrency-aware tool scheduler, and
|
|
132
|
+
hardens the interactive terminal experience. The project is now formally
|
|
133
|
+
licensed under Apache-2.0.
|
|
134
|
+
|
|
135
|
+
### Added
|
|
136
|
+
- **Standalone query engine.** A new engine loop drives a turn end-to-end,
|
|
137
|
+
independent of the React render tree (`lib/engine/`). It owns engine event and
|
|
138
|
+
params types, a transcript-repair pass that resolves dangling/unresolved tool
|
|
139
|
+
calls, and tool-gating decisions backed by a loop guard to prevent runaway
|
|
140
|
+
tool cycles.
|
|
141
|
+
- **`useQueryEngine` hook.** A thin React hook that drives the engine loop and
|
|
142
|
+
replaces the previous `useChat` harness entirely.
|
|
143
|
+
- **Concurrency-aware tool scheduler.** Engine-owned scheduling policy runs tool
|
|
144
|
+
rounds with bounded concurrency. Introduces an engine `ToolHost` contract and a
|
|
145
|
+
hook adapter so the engine can execute tools without depending on the UI layer.
|
|
146
|
+
- **Cross-session project memory.** Durable, non-obvious facts are extracted
|
|
147
|
+
automatically after completed turns into a per-project store
|
|
148
|
+
(`~/.knightcode/projects/<cwd>/memory/`) with a `MEMORY.md` recall index.
|
|
149
|
+
Relevant memories are recalled into the system prompt, a consolidation
|
|
150
|
+
("dream") pass merges and prunes the store, and a `Memory` tool lets the model
|
|
151
|
+
review, correct, or forget entries.
|
|
152
|
+
- **Per-row tool spinners.** Concurrently running tools each get their own inline
|
|
153
|
+
spinner instead of a single shared indicator.
|
|
154
|
+
- **`@`-mention path expansion.** Paths referenced with `@` in a prompt are
|
|
155
|
+
expanded into the model's context at submit time.
|
|
156
|
+
- **PostToolUse `systemMessage` surfacing.** Messages emitted by `PostToolUse`
|
|
157
|
+
hooks are now surfaced to callers.
|
|
158
|
+
- **Apache-2.0 license.** Added root `LICENSE` and `NOTICE` files and `license`
|
|
159
|
+
fields in the workspace and CLI `package.json`.
|
|
160
|
+
|
|
161
|
+
### Changed
|
|
162
|
+
- Extracted `compactHistory` out of the old `use-chat` module and moved chat
|
|
163
|
+
message types into `lib/engine/messages`.
|
|
164
|
+
- Exposed a hook-free `executeRegisteredTool` for engine use.
|
|
165
|
+
- Unified all interactive prompts onto a single shared permission panel.
|
|
166
|
+
- Dropped the unused `sessionId` from `QueryParams`.
|
|
167
|
+
- Pointed repository URLs at the KnightCodeAI org and scoped the publish
|
|
168
|
+
workflow to publishable paths.
|
|
169
|
+
|
|
170
|
+
### Fixed
|
|
171
|
+
- **Quit behaviour:** `/exit` is now the only way to quit; Ctrl+C never exits.
|
|
172
|
+
- **Permissions:** every confirm-gated tool now shows a permission prompt, and
|
|
173
|
+
every awaited tool decision is guaranteed a resolvable prompt; scoped the
|
|
174
|
+
always-allow sweep correctly.
|
|
175
|
+
- **Markdown rendering:** convert `<br>` to real line breaks in prose, expand
|
|
176
|
+
`<br>` table cells into continuation rows, and stop rendering literal `<br>`
|
|
177
|
+
tags.
|
|
178
|
+
- **Interrupts:** render the interrupted marker after the partial response, with
|
|
179
|
+
a plain interrupted notice (no emoji or completion verb); render interrupted
|
|
180
|
+
aborts and surface queued mid-turn submits.
|
|
181
|
+
- **History integrity:** stop schema-validating history and instead quarantine
|
|
182
|
+
invalid tool calls.
|
|
183
|
+
- **State sync:** synchronize message-ref writes, guard submit re-entry, persist
|
|
184
|
+
the final turn snapshot, queue mid-turn submits, clear finished todos, and only
|
|
185
|
+
clear the compacting state when it was actually set.
|
|
186
|
+
- Hardened file reads, question cancellation, and transcript text handling, plus
|
|
187
|
+
a sweep of code-review findings across the engine and UI.
|
|
188
|
+
|
|
189
|
+
## 0.1.0
|
|
190
|
+
|
|
191
|
+
### Minor Changes
|
|
192
|
+
|
|
193
|
+
- 13af3df: Initial public release: `knightcode` ships as a self-contained compiled binary
|
|
194
|
+
(no Bun required) distributed via platform-specific npm packages, with a headless
|
|
195
|
+
`--version` and `doctor`, embedded database migrations, and a non-blocking update
|
|
196
|
+
check.
|
package/bin/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @knightcodeai/cli
|
|
2
|
+
|
|
3
|
+
`knightcode` — a local-first, bring-your-own-key AI coding CLI for your terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @knightcodeai/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
You don't need Bun — it's bundled into the platform binary. The small launcher
|
|
12
|
+
(`bin/knightcode`) that spawns it runs on Node.js (>=18), which you already have
|
|
13
|
+
if you installed with npm. The right platform binary installs automatically as
|
|
14
|
+
an optional dependency.
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
knightcode
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
On first run, set your OpenRouter API key from inside the app.
|
|
23
|
+
|
|
24
|
+
## Configuration
|
|
25
|
+
|
|
26
|
+
State lives in `~/.knightcode/` (sessions, settings, local SQLite database).
|
|
27
|
+
|
|
28
|
+
| Command / env var | Effect |
|
|
29
|
+
| ----------------- | ------ |
|
|
30
|
+
| `knightcode --version` | Print the installed version |
|
|
31
|
+
| `knightcode doctor` | Print diagnostics (config, database, API key, runtime) |
|
|
32
|
+
| `KNIGHTCODE_NO_UPDATE_CHECK=1` | Disable the background update check |
|
|
33
|
+
|
|
34
|
+
## Supported platforms
|
|
35
|
+
|
|
36
|
+
Linux (x64, arm64), macOS (x64, arm64), Windows (x64).
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# Compaction & Branch Summarization
|
|
2
|
+
|
|
3
|
+
LLMs have limited context windows. When conversations grow too long, KnightCode uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
|
|
4
|
+
|
|
5
|
+
**Source files** ([knightcode](https://github.com/KnightCodeAI/knightcode)):
|
|
6
|
+
- [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Auto-compaction logic
|
|
7
|
+
- [`packages/coding-agent/src/core/compaction/branch-summarization.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) - Branch summarization
|
|
8
|
+
- [`packages/coding-agent/src/core/compaction/utils.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/utils.ts) - Shared utilities (file tracking, serialization)
|
|
9
|
+
- [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/session-manager.ts) - Entry types (`CompactionEntry`, `BranchSummaryEntry`)
|
|
10
|
+
- [`packages/coding-agent/src/core/extensions/types.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/extensions/types.ts) - Extension event types
|
|
11
|
+
|
|
12
|
+
For TypeScript definitions in your project, inspect `node_modules/@knightcodeai/cli/dist/`.
|
|
13
|
+
|
|
14
|
+
## Overview
|
|
15
|
+
|
|
16
|
+
KnightCode has two summarization mechanisms:
|
|
17
|
+
|
|
18
|
+
| Mechanism | Trigger | Purpose |
|
|
19
|
+
|-----------|---------|---------|
|
|
20
|
+
| Compaction | Context exceeds threshold, or `/compact` | Summarize old messages to free up context |
|
|
21
|
+
| Branch summarization | `/tree` navigation | Preserve context when switching branches |
|
|
22
|
+
|
|
23
|
+
Both use the same structured summary format and track file operations cumulatively. Compaction and branch-summary requests use fresh routing session IDs and, where supported by the provider, disable prompt-cache writes because these one-off prompts are unlikely to be reused.
|
|
24
|
+
|
|
25
|
+
## Compaction
|
|
26
|
+
|
|
27
|
+
### When It Triggers
|
|
28
|
+
|
|
29
|
+
Auto-compaction triggers when:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
contextTokens > contextWindow - reserveTokens
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
By default, `reserveTokens` is 16384 tokens (configurable in `~/.knightcode/agent/settings.json` or `<project-dir>/.knightcode/settings.json`). This leaves room for the LLM's response.
|
|
36
|
+
|
|
37
|
+
You can also trigger manually with `/compact [instructions]`, where optional instructions focus the summary.
|
|
38
|
+
|
|
39
|
+
### How It Works
|
|
40
|
+
|
|
41
|
+
1. **Find cut point**: Walk backwards from newest message, accumulating token estimates until `keepRecentTokens` (default 20k, configurable in `~/.knightcode/agent/settings.json` or `<project-dir>/.knightcode/settings.json`) is reached
|
|
42
|
+
2. **Extract messages**: Collect messages from the previous kept boundary (or session start) up to the cut point
|
|
43
|
+
3. **Generate summary**: Call LLM to summarize with structured format, passing the previous summary as iterative context when present
|
|
44
|
+
4. **Append entry**: Save `CompactionEntry` with summary and `firstKeptEntryId`
|
|
45
|
+
5. **Rebuilds context**: Session rebuilds the context for the next request, using summary + messages from `firstKeptEntryId` onwards
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Before compaction:
|
|
49
|
+
|
|
50
|
+
entry: 0 1 2 3 4 5 6 7 8 9
|
|
51
|
+
┌─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
|
|
52
|
+
│ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
|
|
53
|
+
└─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
|
|
54
|
+
└────────┬───────┘ └──────────────┬──────────────┘
|
|
55
|
+
messagesToSummarize kept messages
|
|
56
|
+
↑
|
|
57
|
+
firstKeptEntryId (entry 4)
|
|
58
|
+
|
|
59
|
+
After compaction (new entry appended):
|
|
60
|
+
|
|
61
|
+
entry: 0 1 2 3 4 5 6 7 8 9 10
|
|
62
|
+
┌─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┬─────┐
|
|
63
|
+
│ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
|
|
64
|
+
└─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
|
|
65
|
+
└──────────┬──────┘ └──────────────────────┬───────────────────┘
|
|
66
|
+
not sent to LLM sent to LLM
|
|
67
|
+
↑
|
|
68
|
+
starts from firstKeptEntryId
|
|
69
|
+
|
|
70
|
+
What the LLM sees:
|
|
71
|
+
|
|
72
|
+
┌────────┬─────────┬─────┬─────┬──────┬──────┬─────┬──────┐
|
|
73
|
+
│ system │ summary │ usr │ ass │ tool │ tool │ ass │ tool │
|
|
74
|
+
└────────┴─────────┴─────┴─────┴──────┴──────┴─────┴──────┘
|
|
75
|
+
↑ ↑ └─────────────────┬────────────────┘
|
|
76
|
+
prompt from cmp messages from firstKeptEntryId
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
On repeated compactions, the summarized span starts at the previous compaction's kept boundary (`firstKeptEntryId`), not at the compaction entry itself, falling back to the entry after the previous compaction if that kept entry cannot be found in the path. This preserves messages that survived the earlier compaction by including them in the next summarization pass as well. KnightCode also recalculates `tokensBefore` from the rebuilt session context before writing the new `CompactionEntry`, so the token count reflects the actual pre-compaction context being replaced.
|
|
80
|
+
|
|
81
|
+
### Split Turns
|
|
82
|
+
|
|
83
|
+
A "turn" starts with a user message and includes all assistant responses and tool calls until the next user message. Normally, compaction cuts at turn boundaries.
|
|
84
|
+
|
|
85
|
+
When a single turn exceeds `keepRecentTokens`, the cut point lands mid-turn at an assistant message. This is a "split turn":
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
Split turn (one huge turn exceeds budget):
|
|
89
|
+
|
|
90
|
+
entry: 0 1 2 3 4 5 6 7 8
|
|
91
|
+
┌─────┬─────┬─────┬──────┬─────┬──────┬──────┬─────┬──────┐
|
|
92
|
+
│ hdr │ usr │ ass │ tool │ ass │ tool │ tool │ ass │ tool │
|
|
93
|
+
└─────┴─────┴─────┴──────┴─────┴──────┴──────┴─────┴──────┘
|
|
94
|
+
↑ ↑
|
|
95
|
+
turnStartIndex = 1 firstKeptEntryId = 7
|
|
96
|
+
│ │
|
|
97
|
+
└──── turnPrefixMessages (1-6) ───────┘
|
|
98
|
+
└── kept (7-8)
|
|
99
|
+
|
|
100
|
+
isSplitTurn = true
|
|
101
|
+
messagesToSummarize = [] (no complete turns before)
|
|
102
|
+
turnPrefixMessages = [usr, ass, tool, ass, tool, tool]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For split turns, KnightCode generates two summaries and merges them:
|
|
106
|
+
1. **History summary**: Previous context (if any)
|
|
107
|
+
2. **Turn prefix summary**: The early part of the split turn
|
|
108
|
+
|
|
109
|
+
### Cut Point Rules
|
|
110
|
+
|
|
111
|
+
Valid cut points are:
|
|
112
|
+
- User messages
|
|
113
|
+
- Assistant messages
|
|
114
|
+
- BashExecution messages
|
|
115
|
+
- Custom messages (custom_message, branch_summary)
|
|
116
|
+
|
|
117
|
+
Never cut at tool results (they must stay with their tool call).
|
|
118
|
+
|
|
119
|
+
### CompactionEntry Structure
|
|
120
|
+
|
|
121
|
+
Defined in [`session-manager.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/session-manager.ts):
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface CompactionEntry<T = unknown> {
|
|
125
|
+
type: "compaction";
|
|
126
|
+
id: string;
|
|
127
|
+
parentId: string;
|
|
128
|
+
timestamp: number;
|
|
129
|
+
summary: string;
|
|
130
|
+
firstKeptEntryId: string;
|
|
131
|
+
tokensBefore: number;
|
|
132
|
+
usage?: Usage; // LLM usage that generated the summary
|
|
133
|
+
fromHook?: boolean; // true if provided by extension (legacy field name)
|
|
134
|
+
details?: T; // implementation-specific data
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Default compaction uses this for details (from compaction.ts):
|
|
138
|
+
interface CompactionDetails {
|
|
139
|
+
readFiles: string[];
|
|
140
|
+
modifiedFiles: string[];
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Extensions can store any JSON-serializable data in `details`. The default compaction tracks file operations, but custom extension implementations can use their own structure. Generated and extension-provided summaries store their LLM `usage` when available so session totals include summarization work.
|
|
145
|
+
|
|
146
|
+
See [`prepareCompaction()`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) and [`compact()`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) for the implementation. For direct programmatic summarization, `generateSummary()` returns the summary text and `generateSummaryWithUsage()` returns `{ text, usage }`.
|
|
147
|
+
|
|
148
|
+
## Branch Summarization
|
|
149
|
+
|
|
150
|
+
### When It Triggers
|
|
151
|
+
|
|
152
|
+
When you use `/tree` to navigate to a different branch, KnightCode offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
|
|
153
|
+
|
|
154
|
+
### How It Works
|
|
155
|
+
|
|
156
|
+
1. **Find common ancestor**: Deepest node shared by old and new positions
|
|
157
|
+
2. **Collect entries**: Walk from old leaf back to common ancestor
|
|
158
|
+
3. **Prepare with budget**: Include messages up to token budget (newest first)
|
|
159
|
+
4. **Generate summary**: Call LLM with structured format
|
|
160
|
+
5. **Append entry**: Save `BranchSummaryEntry` at navigation point
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Tree before navigation:
|
|
164
|
+
|
|
165
|
+
┌─ B ─ C ─ D (old leaf, being abandoned)
|
|
166
|
+
A ───┤
|
|
167
|
+
└─ E ─ F (target)
|
|
168
|
+
|
|
169
|
+
Common ancestor: A
|
|
170
|
+
Entries to summarize: B, C, D
|
|
171
|
+
|
|
172
|
+
After navigation with summary:
|
|
173
|
+
|
|
174
|
+
┌─ B ─ C ─ D
|
|
175
|
+
A ───┤
|
|
176
|
+
└─ E ─ F ─ [summary of B,C,D] (new leaf)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Cumulative File Tracking
|
|
180
|
+
|
|
181
|
+
Both compaction and branch summarization track files cumulatively. When generating a summary, knightcode extracts file operations from:
|
|
182
|
+
- Tool calls in the messages being summarized
|
|
183
|
+
- Previous compaction or branch summary `details` (if any)
|
|
184
|
+
|
|
185
|
+
This means file tracking accumulates across multiple compactions or nested branch summaries, preserving the full history of read and modified files.
|
|
186
|
+
|
|
187
|
+
### BranchSummaryEntry Structure
|
|
188
|
+
|
|
189
|
+
Defined in [`session-manager.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/session-manager.ts):
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
interface BranchSummaryEntry<T = unknown> {
|
|
193
|
+
type: "branch_summary";
|
|
194
|
+
id: string;
|
|
195
|
+
parentId: string;
|
|
196
|
+
timestamp: number;
|
|
197
|
+
summary: string;
|
|
198
|
+
fromId: string; // Entry we navigated from
|
|
199
|
+
usage?: Usage; // LLM usage that generated the summary
|
|
200
|
+
fromHook?: boolean; // true if provided by extension (legacy field name)
|
|
201
|
+
details?: T; // implementation-specific data
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Default branch summarization uses this for details (from branch-summarization.ts):
|
|
205
|
+
interface BranchSummaryDetails {
|
|
206
|
+
readFiles: string[];
|
|
207
|
+
modifiedFiles: string[];
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Same as compaction, extensions can store custom data in `details`.
|
|
212
|
+
|
|
213
|
+
See [`collectEntriesForBranchSummary()`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), [`prepareBranchEntries()`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts), and [`generateBranchSummary()`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/branch-summarization.ts) for the implementation.
|
|
214
|
+
|
|
215
|
+
## Summary Format
|
|
216
|
+
|
|
217
|
+
Both compaction and branch summarization use the same structured format:
|
|
218
|
+
|
|
219
|
+
```markdown
|
|
220
|
+
## Goal
|
|
221
|
+
[What the user is trying to accomplish]
|
|
222
|
+
|
|
223
|
+
## Constraints & Preferences
|
|
224
|
+
- [Requirements mentioned by user]
|
|
225
|
+
|
|
226
|
+
## Progress
|
|
227
|
+
### Done
|
|
228
|
+
- [x] [Completed tasks]
|
|
229
|
+
|
|
230
|
+
### In Progress
|
|
231
|
+
- [ ] [Current work]
|
|
232
|
+
|
|
233
|
+
### Blocked
|
|
234
|
+
- [Issues, if any]
|
|
235
|
+
|
|
236
|
+
## Key Decisions
|
|
237
|
+
- **[Decision]**: [Rationale]
|
|
238
|
+
|
|
239
|
+
## Next Steps
|
|
240
|
+
1. [What should happen next]
|
|
241
|
+
|
|
242
|
+
## Critical Context
|
|
243
|
+
- [Data needed to continue]
|
|
244
|
+
|
|
245
|
+
<read-files>
|
|
246
|
+
path/to/file1.ts
|
|
247
|
+
path/to/file2.ts
|
|
248
|
+
</read-files>
|
|
249
|
+
|
|
250
|
+
<modified-files>
|
|
251
|
+
path/to/changed.ts
|
|
252
|
+
</modified-files>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Message Serialization
|
|
256
|
+
|
|
257
|
+
Before summarization, messages are serialized to text via [`serializeConversation()`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/compaction/utils.ts):
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
[User]: What they said
|
|
261
|
+
[Assistant thinking]: Internal reasoning
|
|
262
|
+
[Assistant]: Response text
|
|
263
|
+
[Assistant tool calls]: read(path="foo.ts"); edit(path="bar.ts", ...)
|
|
264
|
+
[Tool result]: Output from tool
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
This prevents the model from treating it as a conversation to continue.
|
|
268
|
+
|
|
269
|
+
Tool results are truncated to 2000 characters during serialization. Content beyond that limit is replaced with a marker indicating how many characters were truncated. This keeps summarization requests within reasonable token budgets, since tool results (especially from `read` and `bash`) are typically the largest contributors to context size.
|
|
270
|
+
|
|
271
|
+
## Custom Summarization via Extensions
|
|
272
|
+
|
|
273
|
+
Extensions can intercept and customize both compaction and branch summarization. See [`extensions/types.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/extensions/types.ts) for event type definitions.
|
|
274
|
+
|
|
275
|
+
### session_before_compact
|
|
276
|
+
|
|
277
|
+
Fired before auto-compaction or `/compact`. Can cancel or provide custom summary. See `SessionBeforeCompactEvent` and `CompactionPreparation` in the types file.
|
|
278
|
+
|
|
279
|
+
```typescript
|
|
280
|
+
knightcode.on("session_before_compact", async (event, ctx) => {
|
|
281
|
+
const { preparation, branchEntries, customInstructions, reason, willRetry, signal } = event;
|
|
282
|
+
|
|
283
|
+
// preparation.messagesToSummarize - messages to summarize
|
|
284
|
+
// preparation.turnPrefixMessages - split turn prefix (if isSplitTurn)
|
|
285
|
+
// preparation.previousSummary - previous compaction summary
|
|
286
|
+
// preparation.fileOps - extracted file operations
|
|
287
|
+
// preparation.tokensBefore - context tokens before compaction
|
|
288
|
+
// preparation.firstKeptEntryId - where kept messages start
|
|
289
|
+
// preparation.settings - compaction settings
|
|
290
|
+
|
|
291
|
+
// branchEntries - all entries on current branch (for custom state)
|
|
292
|
+
// reason - "manual" (/compact), "threshold", or "overflow"
|
|
293
|
+
// willRetry - whether the aborted turn is retried after compaction (overflow recovery)
|
|
294
|
+
// signal - AbortSignal (pass to LLM calls)
|
|
295
|
+
|
|
296
|
+
// Cancel:
|
|
297
|
+
return { cancel: true };
|
|
298
|
+
|
|
299
|
+
// Custom summary:
|
|
300
|
+
return {
|
|
301
|
+
compaction: {
|
|
302
|
+
summary: "Your summary...",
|
|
303
|
+
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
304
|
+
tokensBefore: preparation.tokensBefore,
|
|
305
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
306
|
+
details: { /* custom data */ },
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
#### Converting Messages to Text
|
|
313
|
+
|
|
314
|
+
To generate a summary with your own model, convert messages to text using `serializeConversation`:
|
|
315
|
+
|
|
316
|
+
```typescript
|
|
317
|
+
import { convertToLlm, serializeConversation } from "@knightcodeai/cli";
|
|
318
|
+
|
|
319
|
+
knightcode.on("session_before_compact", async (event, ctx) => {
|
|
320
|
+
const { preparation } = event;
|
|
321
|
+
|
|
322
|
+
// Convert AgentMessage[] to Message[], then serialize to text
|
|
323
|
+
const conversationText = serializeConversation(
|
|
324
|
+
convertToLlm(preparation.messagesToSummarize)
|
|
325
|
+
);
|
|
326
|
+
// Returns:
|
|
327
|
+
// [User]: message text
|
|
328
|
+
// [Assistant thinking]: thinking content
|
|
329
|
+
// [Assistant]: response text
|
|
330
|
+
// [Assistant tool calls]: read(path="..."); bash(command="...")
|
|
331
|
+
// [Tool result]: output text
|
|
332
|
+
|
|
333
|
+
// Now send to your model for summarization
|
|
334
|
+
const { summary, usage } = await myModel.summarize(conversationText);
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
compaction: {
|
|
338
|
+
summary,
|
|
339
|
+
firstKeptEntryId: preparation.firstKeptEntryId,
|
|
340
|
+
tokensBefore: preparation.tokensBefore,
|
|
341
|
+
usage,
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
See [custom-compaction.ts](../examples/extensions/custom-compaction.ts) for a complete example using a different model.
|
|
348
|
+
|
|
349
|
+
### session_compact_failed
|
|
350
|
+
|
|
351
|
+
Fired when manual or automatic compaction fails or is aborted. This is useful for telemetry extensions that need to pair `session_before_compact` attempts with terminal outcomes.
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
knightcode.on("session_compact_failed", async (event, ctx) => {
|
|
355
|
+
const { reason, errorMessage, aborted, willRetry, fromExtension } = event;
|
|
356
|
+
// reason - "manual" (/compact), "threshold", or "overflow"
|
|
357
|
+
// errorMessage - present for non-abort failures
|
|
358
|
+
// aborted - true for cancelled/aborted compactions
|
|
359
|
+
// willRetry - whether the aborted turn would have retried after compaction
|
|
360
|
+
// fromExtension - whether extension-provided compaction content was being used
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### session_before_tree
|
|
365
|
+
|
|
366
|
+
Fired before `/tree` navigation. Always fires regardless of whether user chose to summarize. Can cancel navigation or provide custom summary.
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
knightcode.on("session_before_tree", async (event, ctx) => {
|
|
370
|
+
const { preparation, signal } = event;
|
|
371
|
+
|
|
372
|
+
// preparation.targetId - where we're navigating to
|
|
373
|
+
// preparation.oldLeafId - current position (being abandoned)
|
|
374
|
+
// preparation.commonAncestorId - shared ancestor
|
|
375
|
+
// preparation.entriesToSummarize - entries that would be summarized
|
|
376
|
+
// preparation.userWantsSummary - whether user chose to summarize
|
|
377
|
+
|
|
378
|
+
// Cancel navigation entirely:
|
|
379
|
+
return { cancel: true };
|
|
380
|
+
|
|
381
|
+
// Provide custom summary (only used if userWantsSummary is true):
|
|
382
|
+
if (preparation.userWantsSummary) {
|
|
383
|
+
return {
|
|
384
|
+
summary: {
|
|
385
|
+
summary: "Your summary...",
|
|
386
|
+
// usage: summaryResponse.usage, // Optional; included in session totals
|
|
387
|
+
details: { /* custom data */ },
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
See `SessionBeforeTreeEvent` and `TreePreparation` in the types file.
|
|
395
|
+
|
|
396
|
+
## Settings
|
|
397
|
+
|
|
398
|
+
Configure compaction in `~/.knightcode/agent/settings.json` or `<project-dir>/.knightcode/settings.json`:
|
|
399
|
+
|
|
400
|
+
```json
|
|
401
|
+
{
|
|
402
|
+
"compaction": {
|
|
403
|
+
"enabled": true,
|
|
404
|
+
"reserveTokens": 16384,
|
|
405
|
+
"keepRecentTokens": 20000
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
| Setting | Default | Description |
|
|
411
|
+
|---------|---------|-------------|
|
|
412
|
+
| `enabled` | `true` | Enable auto-compaction |
|
|
413
|
+
| `reserveTokens` | `16384` | Tokens to reserve for LLM response |
|
|
414
|
+
| `keepRecentTokens` | `20000` | Recent tokens to keep (not summarized) |
|
|
415
|
+
|
|
416
|
+
Disable auto-compaction with `"enabled": false`. You can still compact manually with `/compact`.
|