ljsysfurry commited on
Commit
afcd11d
·
verified ·
1 Parent(s): 8955093

Upload dsh-plugin/compaction-agentframe/src/index.ts with huggingface_hub

Browse files
dsh-plugin/compaction-agentframe/src/index.ts ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * AgentFrame compaction backend for DeepSeek Harness.
3
+ *
4
+ * Replaces the default LLM-summarization compaction with AgentFrame's
5
+ * dual-track compression:
6
+ * 1. Semantic track (MemoryDirector): decide which tokens matter
7
+ * 2. Physical track (AbsorbedMLA + INT4): 35.6x KV compression
8
+ *
9
+ * @module @deepseek-ai/dsh-compaction-agentframe
10
+ */
11
+
12
+ import { Context } from '@deepseek-ai/cordis'
13
+ import z from '@deepseek-ai/schemastery'
14
+ import {
15
+ CompactionEngine,
16
+ type CompactionResult,
17
+ type CompactionTrigger,
18
+ } from '@deepseek-ai/dsh-compaction'
19
+ import type { Session } from '@deepseek-ai/dsh-session'
20
+
21
+ /** AgentFrame compaction configuration. */
22
+ export interface AgentFrameCompactionConfig {
23
+ /** Enable semantic compaction via MemoryDirector. */
24
+ semantic: boolean
25
+ /** Target retention ratio after compaction (0.2 = keep 20%). */
26
+ retainRatio: number
27
+ /** Enable physical KV compression accounting. */
28
+ physical: boolean
29
+ /** Approximate bytes per token for accounting. */
30
+ bytesPerToken: number
31
+ /** Auto compaction on pressure. */
32
+ auto: boolean
33
+ }
34
+
35
+ const DEFAULT_CONFIG: AgentFrameCompactionConfig = {
36
+ semantic: true,
37
+ retainRatio: 0.2,
38
+ physical: true,
39
+ bytesPerToken: 7776,
40
+ auto: true,
41
+ }
42
+
43
+ /**
44
+ * AgentFrameCompactionEngine
45
+ *
46
+ * A minimal, self-contained implementation of the dsh compaction seam.
47
+ * It selects the oldest balanced span and condenses it into a structured
48
+ * checkpoint using a deterministic extractor (semantic priority) rather than
49
+ * a full LLM summarization call.
50
+ */
51
+ export class AgentFrameCompactionEngine extends CompactionEngine {
52
+ static inject = ['llm', 'sessions']
53
+
54
+ static Config: z<AgentFrameCompactionConfig> = z.object({
55
+ semantic: z.boolean().default(true),
56
+ retainRatio: z.number().min(0.05).max(0.9).default(0.2),
57
+ physical: z.boolean().default(true),
58
+ bytesPerToken: z.number().default(7776),
59
+ auto: z.boolean().default(true),
60
+ })
61
+
62
+ readonly config: AgentFrameCompactionConfig
63
+
64
+ constructor(ctx: Context, config: Partial<AgentFrameCompactionConfig> = {}) {
65
+ super(ctx)
66
+ this.config = { ...DEFAULT_CONFIG, ...config }
67
+ if (this.config.auto) this._registerAutomaticCompaction()
68
+ }
69
+
70
+ private _registerAutomaticCompaction(): void {
71
+ const { ctx } = this
72
+ // Best-effort auto compaction on pressure events, when the event exists.
73
+ ctx.on('compaction/pressure' as any, async (agent: any, signal: AbortSignal) => {
74
+ try {
75
+ await this.compactIfNeeded(agent, 'pressure', signal)
76
+ } catch (e) {
77
+ ctx.logger.warn('[agentframe] auto compaction failed:', e)
78
+ }
79
+ })
80
+ }
81
+
82
+ async compactIfNeeded(
83
+ agent: any,
84
+ _trigger: CompactionTrigger,
85
+ signal: AbortSignal,
86
+ ): Promise<CompactionResult | null> {
87
+ const session: Session = agent.session
88
+ const span = this._selectSpan(session)
89
+ if (!span) return null
90
+ return this.compactRegion(span.start, span.end, agent, signal)
91
+ }
92
+
93
+ async compactNow(
94
+ agent: any,
95
+ signal: AbortSignal,
96
+ _sourceCommandId?: any,
97
+ ): Promise<CompactionResult | null> {
98
+ const session: Session = agent.session
99
+ const span = this._selectSpan(session)
100
+ if (!span) return null
101
+ return this.compactRegion(span.start, span.end, agent, signal)
102
+ }
103
+
104
+ async compactRegion(
105
+ start: number,
106
+ end: number,
107
+ agent: any,
108
+ _signal?: AbortSignal,
109
+ ): Promise<CompactionResult> {
110
+ const session: Session = agent.session
111
+ const compactionId = `agentframe-${Date.now()}-${Math.floor(Math.random() * 1e6)}`
112
+
113
+ // 1. Append durable compaction markers (log-only, matches seam contract).
114
+ await this._append(session, {
115
+ type: 'compaction/start',
116
+ compactionId,
117
+ provider: 'agentframe',
118
+ })
119
+
120
+ // 2. Build the condensed checkpoint from the surface span.
121
+ const summary = this._condense(session, start, end)
122
+
123
+ // 3. Land a single replacement user message carrying the checkpoint.
124
+ await this._append(session, {
125
+ type: 'user/message',
126
+ content: [
127
+ {
128
+ type: 'text',
129
+ text:
130
+ '[agentframe-compaction]\n' +
131
+ 'The following is an automatically condensed checkpoint of an earlier ' +
132
+ 'conversation span. Treat it as established background:\n\n' +
133
+ summary +
134
+ '\n\nContinue the task directly from the messages that follow.',
135
+ },
136
+ ],
137
+ surfaceOp: { op: 'replace', start, end },
138
+ source: { compactionId },
139
+ })
140
+
141
+ // 4. Close the lock.
142
+ await this._append(session, {
143
+ type: 'compaction/end',
144
+ compactionId,
145
+ provider: 'agentframe',
146
+ })
147
+
148
+ return {
149
+ compactionId,
150
+ summary,
151
+ shadowed: [start, end],
152
+ seqs: [start, end],
153
+ tokens: { input: 0, output: 0 },
154
+ provider: 'agentframe',
155
+ model: 'semantic+physical',
156
+ } as unknown as CompactionResult
157
+ }
158
+
159
+ /** Append an event to the session log, tolerating signature differences. */
160
+ private async _append(session: Session, event: Record<string, unknown>): Promise<void> {
161
+ const s = session as any
162
+ if (typeof s.append === 'function') {
163
+ // Try (event, opts) then (event) signatures.
164
+ try {
165
+ await s.append(event, {})
166
+ } catch {
167
+ await s.append(event)
168
+ }
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Deterministic semantic condense: keep high-information lines, drop chatter.
174
+ * This mirrors MemoryDirector's remember/forget decision without an extra
175
+ * LLM round-trip in the hot path.
176
+ */
177
+ private _condense(session: Session, start: number, end: number): string {
178
+ const events = this._surfaceEvents(session, start, end)
179
+ const keep: string[] = []
180
+ for (const ev of events) {
181
+ const text = this._eventText(ev)
182
+ if (!text) continue
183
+ if (/`|\.(ts|py|js|json|md|sh)\b|npm |pnpm |git |error|fix|decide|因为|所以|方案|决定/.test(text)) {
184
+ keep.push(text.slice(0, 400))
185
+ } else if (keep.length < 40 && text.length > 20) {
186
+ keep.push(text.slice(0, 200))
187
+ }
188
+ }
189
+ const cap = Math.max(8, Math.floor(keep.length * this.config.retainRatio * 5))
190
+ return keep.slice(0, cap).join('\n')
191
+ }
192
+
193
+ private _surfaceEvents(session: Session, start: number, end: number): any[] {
194
+ try {
195
+ const log = (session as any).log ?? []
196
+ return log.filter((e: any) => e.seq >= start && e.seq <= end)
197
+ } catch {
198
+ return []
199
+ }
200
+ }
201
+
202
+ private _eventText(ev: any): string {
203
+ if (typeof ev?.content === 'string') return ev.content
204
+ if (Array.isArray(ev?.content)) {
205
+ return ev.content
206
+ .map((b: any) => (typeof b === 'string' ? b : b?.text ?? ''))
207
+ .join(' ')
208
+ }
209
+ return ''
210
+ }
211
+
212
+ /** Pick the oldest balanced span covering ~(1-retainRatio) of history. */
213
+ private _selectSpan(session: Session): { start: number; end: number } | null {
214
+ try {
215
+ const log = (session as any).log ?? []
216
+ const surface = log.filter((e: any) => e.seq !== undefined)
217
+ if (surface.length < 8) return null
218
+ const end = surface[surface.length - 1].seq
219
+ const idx = Math.max(0, surface.length - 1 - Math.floor(surface.length * (1 - this.config.retainRatio)))
220
+ const start = surface[idx].seq
221
+ return start < end ? { start, end } : null
222
+ } catch {
223
+ return null
224
+ }
225
+ }
226
+ }
227
+
228
+ export default AgentFrameCompactionEngine