smart-compaction 0.1.0 → 0.2.0
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/README.md +45 -20
- package/context-status.js +54 -0
- package/cordis.patch.yml +2 -1
- package/index.js +56 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# smart-compaction
|
|
2
2
|
|
|
3
3
|
A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) plugin that gives the
|
|
4
|
-
model
|
|
5
|
-
right after finishing a step, never mid-edit — instead of only ever being interrupted by dsh's
|
|
6
|
-
automatic token-threshold trigger
|
|
4
|
+
model two tools: `compact_now`, so it can trigger compaction itself at a point *it* knows is safe
|
|
5
|
+
— right after finishing a step, never mid-edit — instead of only ever being interrupted by dsh's
|
|
6
|
+
automatic token-threshold trigger; and `context_status`, so it can check real, current token
|
|
7
|
+
usage against its actual context window instead of guessing whether a conversation "feels long."
|
|
7
8
|
|
|
8
9
|
## Why
|
|
9
10
|
|
|
@@ -19,7 +20,9 @@ blind token counter.
|
|
|
19
20
|
|
|
20
21
|
## What it does
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
Two tools, both no-argument.
|
|
24
|
+
|
|
25
|
+
**`compact_now`**
|
|
23
26
|
|
|
24
27
|
- Selects the largest currently-compactable span of conversation history — the same
|
|
25
28
|
tool-call-pairing-safe boundary logic dsh's own compaction already guarantees, reimplemented
|
|
@@ -31,6 +34,21 @@ One tool: **`compact_now`**. No arguments.
|
|
|
31
34
|
- No-ops harmlessly (`"Not enough compactable history yet."`) if there isn't enough history yet —
|
|
32
35
|
safe for the model to call speculatively.
|
|
33
36
|
|
|
37
|
+
**`context_status`**
|
|
38
|
+
|
|
39
|
+
- Read-only — never modifies the session, safe to call anytime.
|
|
40
|
+
- Reports current token usage and the model's actual context-window size for *this* session,
|
|
41
|
+
e.g. `"~42,300 / 77,824 tokens used (54.3%)."`
|
|
42
|
+
- Reads dsh's own `contextPressure` session projection (registered by
|
|
43
|
+
`@deepseek-ai/dsh-token-meter`, mounted wherever `compaction-basic` is) via the public
|
|
44
|
+
`ctx.sessionProjections.stateOf()` API — the same numbers the web UI's own context meter
|
|
45
|
+
reads. Nothing is hardcoded: the context-window figure comes from whatever model this
|
|
46
|
+
session is actually routed to, so it's correct unchanged across different models, profiles,
|
|
47
|
+
and context-window sizes.
|
|
48
|
+
- Exists because, without it, the model has zero visibility into its own context usage — the
|
|
49
|
+
only prior signal was a vague "if the conversation feels long" in `compact_now`'s own
|
|
50
|
+
description.
|
|
51
|
+
|
|
34
52
|
## How it works
|
|
35
53
|
|
|
36
54
|
Two entry points exist on dsh's compaction service: `compactNow()` (what the human `/compact`
|
|
@@ -56,24 +74,31 @@ array yourself.)
|
|
|
56
74
|
No build step, no config. Restart your dsh service after adding it — new bundles are only picked
|
|
57
75
|
up on boot.
|
|
58
76
|
|
|
59
|
-
|
|
60
|
-
do (e.g. `@deepseek-ai/dsh-web-app`-based profiles don't by default). If yours
|
|
61
|
-
still installs cleanly (it won't break your profile's boot) but returns an
|
|
62
|
-
called: `"no compaction service is configured on this profile"`. Add a
|
|
63
|
-
get one.
|
|
77
|
+
**`compact_now` requires a `compaction` service on your profile.** Most profile templates ship
|
|
78
|
+
one, but not all do (e.g. `@deepseek-ai/dsh-web-app`-based profiles don't by default). If yours
|
|
79
|
+
doesn't, `compact_now` still installs cleanly (it won't break your profile's boot) but returns an
|
|
80
|
+
error every time it's called: `"no compaction service is configured on this profile"`. Add a
|
|
81
|
+
`compaction-basic` bundle to get one.
|
|
82
|
+
|
|
83
|
+
**`context_status` requires `@deepseek-ai/dsh-token-meter` mounted** (it registers the
|
|
84
|
+
`contextPressure` projection this tool reads). It's normally pulled in wherever `compaction-basic`
|
|
85
|
+
is, so if `compact_now` works, `context_status` should too. If it isn't mounted, the tool still
|
|
86
|
+
installs cleanly and just reports `available: false` instead of erroring.
|
|
64
87
|
|
|
65
88
|
### Tell the model when to use it
|
|
66
89
|
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
Neither tool calls itself — nothing uses them unless instructed to. Add something like this to
|
|
91
|
+
your `AGENTS.md` (or whatever your profile injects as standing instructions):
|
|
69
92
|
|
|
70
|
-
> After marking a todo item `completed` (never while one is `in_progress`),
|
|
71
|
-
>
|
|
72
|
-
>
|
|
93
|
+
> After marking a todo item `completed` (never while one is `in_progress`), call `context_status`.
|
|
94
|
+
> If usage is climbing past roughly 70-80% of the context window, call `compact_now` too. Both are
|
|
95
|
+
> safe to call speculatively — `context_status` is read-only, and `compact_now` no-ops if there
|
|
96
|
+
> isn't enough history to compact yet.
|
|
73
97
|
|
|
74
|
-
Tying
|
|
75
|
-
self-contained unit of work," instead of asking the model to estimate its own remaining work
|
|
76
|
-
which it's generally bad at.
|
|
98
|
+
Tying this to todo-completion matters: it's a real, already-tracked signal for "I just finished a
|
|
99
|
+
self-contained unit of work," instead of asking the model to estimate its own remaining work or
|
|
100
|
+
guess whether a conversation "feels long," both of which it's generally bad at. `context_status`
|
|
101
|
+
replaces that guess with the real number.
|
|
77
102
|
|
|
78
103
|
## Building from source
|
|
79
104
|
|
|
@@ -86,8 +111,8 @@ pnpm install
|
|
|
86
111
|
node test.js
|
|
87
112
|
```
|
|
88
113
|
|
|
89
|
-
`test.js` is a pure unit-test check of the range-selection logic (`select-range.js`)
|
|
90
|
-
dsh/Ollama session required.
|
|
114
|
+
`test.js` is a pure unit-test check of the range-selection logic (`select-range.js`) and the
|
|
115
|
+
context-usage summary logic (`context-status.js`) — no live dsh/Ollama session required.
|
|
91
116
|
|
|
92
117
|
## Configuration
|
|
93
118
|
|
|
@@ -95,7 +120,7 @@ None. The tool takes no arguments and needs no setup beyond installing it.
|
|
|
95
120
|
|
|
96
121
|
## Status
|
|
97
122
|
|
|
98
|
-
|
|
123
|
+
`compact_now` verified end-to-end against a real dsh session, including:
|
|
99
124
|
|
|
100
125
|
- Basic call: the tool loads, the model calls it, it selects a valid boundary-safe range, and it
|
|
101
126
|
drives `compactRegion()` mid-turn without ever hitting the `busy` failure this design exists to
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure summary of dsh's own `contextPressure` session-projection state.
|
|
3
|
+
*
|
|
4
|
+
* That projection is registered by `@deepseek-ai/dsh-token-meter` (mounted
|
|
5
|
+
* on any profile that runs `compaction-basic`) and read here through the
|
|
6
|
+
* public `ctx.sessionProjections.stateOf(session, 'contextPressure')` API —
|
|
7
|
+
* the exact same numbers the web UI's own context meter reads. Nothing about
|
|
8
|
+
* a model or its context-window size is hardcoded: `contextWindow` is
|
|
9
|
+
* whatever the last `request/context` event actually logged for whichever
|
|
10
|
+
* model this session is really routed to, so this works unchanged across
|
|
11
|
+
* profiles, models, and context-window sizes.
|
|
12
|
+
*
|
|
13
|
+
* The `usedTokens` formula mirrors token-meter's own private
|
|
14
|
+
* `contextPressureProjectionDefinition.wire.view` (not part of that
|
|
15
|
+
* package's public exports — see the doc comment above it in
|
|
16
|
+
* `usage-projection.ts` for the reasoning): prompt-side pressure from the
|
|
17
|
+
* last real provider usage sample, adjusted by how much the tracked surface
|
|
18
|
+
* has grown or shrunk (e.g. via compaction) since that sample was taken.
|
|
19
|
+
* Before any request has completed this session, no usage sample exists yet
|
|
20
|
+
* — `surfaceTokens` alone is the best available estimate, flagged
|
|
21
|
+
* `estimated: true`.
|
|
22
|
+
*
|
|
23
|
+
* @see HANDOFF.md for the full research trail behind this file.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {import('@deepseek-ai/dsh-token-meter').ContextPressureState | undefined} state
|
|
28
|
+
* @returns {{
|
|
29
|
+
* available: boolean,
|
|
30
|
+
* contextWindow?: number,
|
|
31
|
+
* usedTokens?: number,
|
|
32
|
+
* percentUsed?: number,
|
|
33
|
+
* estimated?: boolean,
|
|
34
|
+
* }}
|
|
35
|
+
*/
|
|
36
|
+
export function summarizeContextUsage(state) {
|
|
37
|
+
if (state === undefined) return { available: false }
|
|
38
|
+
if (state.contextWindow === undefined) {
|
|
39
|
+
return { available: true, usedTokens: state.surfaceTokens, estimated: true }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const hasSample = state.pressureTokens !== undefined && state.sampledSurfaceTokens !== undefined
|
|
43
|
+
const usedTokens = hasSample
|
|
44
|
+
? Math.max(0, state.pressureTokens + state.surfaceTokens - state.sampledSurfaceTokens)
|
|
45
|
+
: state.surfaceTokens
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
available: true,
|
|
49
|
+
contextWindow: state.contextWindow,
|
|
50
|
+
usedTokens,
|
|
51
|
+
percentUsed: Math.round((usedTokens / state.contextWindow) * 1000) / 10,
|
|
52
|
+
estimated: !hasSample,
|
|
53
|
+
}
|
|
54
|
+
}
|
package/cordis.patch.yml
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# This bundle's own default layer: mounts the plugin under id
|
|
2
|
-
# `tool-compact-now`.
|
|
2
|
+
# `tool-compact-now`. One module registers both the `compact_now` and
|
|
3
|
+
# `context_status` tools — nothing to configure, the tool takes no config.
|
|
3
4
|
- insert:
|
|
4
5
|
- id: tool-compact-now
|
|
5
6
|
name: 'smart-compaction'
|
package/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh plugin: registers a `compact_now` tool on `ctx.tools` so the model can
|
|
3
3
|
* voluntarily trigger compaction at a point it judges safe, instead of only
|
|
4
|
-
* ever being interrupted by dsh's automatic token-threshold trigger.
|
|
4
|
+
* ever being interrupted by dsh's automatic token-threshold trigger. Also
|
|
5
|
+
* registers `context_status`, so the model can check real, current token
|
|
6
|
+
* usage against its actual context window on demand instead of guessing
|
|
7
|
+
* whether "the conversation feels long" — see context-status.js.
|
|
5
8
|
*
|
|
6
9
|
* Calls `ctx.compaction.compactRegion()` directly — NOT `compactNow()` (what
|
|
7
10
|
* the human `/compact` command uses). `compactRegion` doesn't require an
|
|
@@ -14,6 +17,7 @@
|
|
|
14
17
|
|
|
15
18
|
import { toolPairingBalancedBefore } from '@deepseek-ai/dsh-compaction'
|
|
16
19
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
20
|
+
import { summarizeContextUsage } from './context-status.js'
|
|
17
21
|
import { selectCompactableRange } from './select-range.js'
|
|
18
22
|
|
|
19
23
|
export const name = 'tool-compact-now'
|
|
@@ -87,4 +91,55 @@ export function apply(ctx) {
|
|
|
87
91
|
}
|
|
88
92
|
},
|
|
89
93
|
}))
|
|
94
|
+
|
|
95
|
+
ctx.tools.register(defineTool({
|
|
96
|
+
name: 'context_status',
|
|
97
|
+
description: CONTEXT_STATUS_DESCRIPTION,
|
|
98
|
+
parameters: {},
|
|
99
|
+
output: {
|
|
100
|
+
schema: {
|
|
101
|
+
type: 'object',
|
|
102
|
+
additionalProperties: false,
|
|
103
|
+
properties: {
|
|
104
|
+
available: { type: 'boolean', required: true },
|
|
105
|
+
contextWindow: { type: 'integer' },
|
|
106
|
+
usedTokens: { type: 'integer' },
|
|
107
|
+
percentUsed: { type: 'number' },
|
|
108
|
+
estimated: { type: 'boolean' },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
render: (_args, value) => [{ type: 'text', text: renderContextStatus(value) }],
|
|
112
|
+
},
|
|
113
|
+
async execute(_args, exec) {
|
|
114
|
+
if (!exec.agent) {
|
|
115
|
+
throw new Error('context_status requires an owning agent session')
|
|
116
|
+
}
|
|
117
|
+
const projections = ctx.get('sessionProjections')
|
|
118
|
+
if (!projections) return { available: false }
|
|
119
|
+
const state = projections.stateOf(exec.agent.session, 'contextPressure')
|
|
120
|
+
return summarizeContextUsage(state)
|
|
121
|
+
},
|
|
122
|
+
}))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const CONTEXT_STATUS_DESCRIPTION =
|
|
126
|
+
'Check real, current context-window usage for this session: tokens used so far and the '
|
|
127
|
+
+ 'model\'s actual context-window size, whatever model this session happens to be running. '
|
|
128
|
+
+ 'Use this instead of guessing whether the conversation "feels long" before deciding to call '
|
|
129
|
+
+ 'compact_now — automatic compaction generally triggers well before the window fills, '
|
|
130
|
+
+ 'typically somewhere around 70-90% depending on profile config, so usage climbing past that '
|
|
131
|
+
+ 'range is a good signal to call compact_now proactively rather than wait to be interrupted. '
|
|
132
|
+
+ 'Harmless to call anytime; read-only, never modifies the session.'
|
|
133
|
+
|
|
134
|
+
function renderContextStatus(value) {
|
|
135
|
+
if (!value.available) {
|
|
136
|
+
return 'Context usage isn\'t available on this profile (no token-meter service mounted).'
|
|
137
|
+
}
|
|
138
|
+
if (value.contextWindow === undefined) {
|
|
139
|
+
return `~${value.usedTokens} tokens used so far this session; context-window size isn't `
|
|
140
|
+
+ 'known yet (no model request has completed yet).'
|
|
141
|
+
}
|
|
142
|
+
const note = value.estimated ? ' (estimated — no confirmed usage sample yet)' : ''
|
|
143
|
+
return `~${value.usedTokens.toLocaleString()} / ${value.contextWindow.toLocaleString()} tokens `
|
|
144
|
+
+ `used (${value.percentUsed}%)${note}.`
|
|
90
145
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smart-compaction",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "dsh plugin: a compact_now tool letting the model trigger compaction itself at a safe point, instead of only the automatic token-threshold trigger.",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "dsh plugin: a compact_now tool letting the model trigger compaction itself at a safe point, plus a context_status tool so it can check real token usage against its context window, instead of only the automatic token-threshold trigger.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"engines": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dshhub": {
|
|
31
31
|
"schemaVersion": 1,
|
|
32
32
|
"displayName": "Smart Compaction",
|
|
33
|
-
"summary": "Gives the model a compact_now tool so it can trigger compaction itself at a safe point, instead of only being interrupted by the automatic token-threshold trigger.",
|
|
33
|
+
"summary": "Gives the model a compact_now tool so it can trigger compaction itself at a safe point, plus a context_status tool to check real token usage against its context window, instead of only being interrupted by the automatic token-threshold trigger.",
|
|
34
34
|
"categories": [
|
|
35
35
|
"Sessions & Messages",
|
|
36
36
|
"Tools & Capabilities"
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
],
|
|
42
42
|
"capabilities": {
|
|
43
43
|
"provides": [
|
|
44
|
-
"tool:compact_now"
|
|
44
|
+
"tool:compact_now",
|
|
45
|
+
"tool:context_status"
|
|
45
46
|
]
|
|
46
47
|
},
|
|
47
48
|
"compatibility": {
|
|
@@ -53,6 +54,7 @@
|
|
|
53
54
|
"files": [
|
|
54
55
|
"index.js",
|
|
55
56
|
"select-range.js",
|
|
57
|
+
"context-status.js",
|
|
56
58
|
"cordis.patch.yml"
|
|
57
59
|
],
|
|
58
60
|
"peerDependencies": {
|