micode 0.8.1 → 0.8.2
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/package.json +1 -1
- package/src/hooks/auto-compact.ts +48 -2
package/package.json
CHANGED
|
@@ -4,13 +4,23 @@ import { mkdir, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
// Compact when this percentage of context is used
|
|
7
|
-
const COMPACT_THRESHOLD = 0.
|
|
7
|
+
const COMPACT_THRESHOLD = 0.5;
|
|
8
8
|
|
|
9
9
|
const LEDGER_DIR = "thoughts/ledgers";
|
|
10
10
|
|
|
11
|
+
// Timeout for waiting for compaction to complete (2 minutes)
|
|
12
|
+
const COMPACTION_TIMEOUT_MS = 120_000;
|
|
13
|
+
|
|
14
|
+
interface PendingCompaction {
|
|
15
|
+
resolve: () => void;
|
|
16
|
+
reject: (error: Error) => void;
|
|
17
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
interface AutoCompactState {
|
|
12
21
|
inProgress: Set<string>;
|
|
13
22
|
lastCompactTime: Map<string, number>;
|
|
23
|
+
pendingCompactions: Map<string, PendingCompaction>;
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
// Cooldown between compaction attempts (prevent rapid re-triggering)
|
|
@@ -20,6 +30,7 @@ export function createAutoCompactHook(ctx: PluginInput) {
|
|
|
20
30
|
const state: AutoCompactState = {
|
|
21
31
|
inProgress: new Set(),
|
|
22
32
|
lastCompactTime: new Map(),
|
|
33
|
+
pendingCompactions: new Map(),
|
|
23
34
|
};
|
|
24
35
|
|
|
25
36
|
async function writeSummaryToLedger(sessionID: string): Promise<void> {
|
|
@@ -78,6 +89,17 @@ ${summaryText}
|
|
|
78
89
|
}
|
|
79
90
|
}
|
|
80
91
|
|
|
92
|
+
function waitForCompaction(sessionID: string): Promise<void> {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const timeoutId = setTimeout(() => {
|
|
95
|
+
state.pendingCompactions.delete(sessionID);
|
|
96
|
+
reject(new Error("Compaction timed out"));
|
|
97
|
+
}, COMPACTION_TIMEOUT_MS);
|
|
98
|
+
|
|
99
|
+
state.pendingCompactions.set(sessionID, { resolve, reject, timeoutId });
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
81
103
|
async function triggerCompaction(
|
|
82
104
|
sessionID: string,
|
|
83
105
|
providerID: string,
|
|
@@ -111,15 +133,19 @@ ${summaryText}
|
|
|
111
133
|
})
|
|
112
134
|
.catch(() => {});
|
|
113
135
|
|
|
136
|
+
// Start the compaction - this returns immediately while compaction runs async
|
|
114
137
|
await ctx.client.session.summarize({
|
|
115
138
|
path: { id: sessionID },
|
|
116
139
|
body: { providerID, modelID },
|
|
117
140
|
query: { directory: ctx.directory },
|
|
118
141
|
});
|
|
119
142
|
|
|
143
|
+
// Wait for the session.compacted event to confirm completion
|
|
144
|
+
await waitForCompaction(sessionID);
|
|
145
|
+
|
|
120
146
|
state.lastCompactTime.set(sessionID, Date.now());
|
|
121
147
|
|
|
122
|
-
// Write summary to ledger file
|
|
148
|
+
// Write summary to ledger file (only after compaction is confirmed complete)
|
|
123
149
|
await writeSummaryToLedger(sessionID);
|
|
124
150
|
|
|
125
151
|
await ctx.client.tui
|
|
@@ -153,12 +179,32 @@ ${summaryText}
|
|
|
153
179
|
event: async ({ event }: { event: { type: string; properties?: unknown } }) => {
|
|
154
180
|
const props = event.properties as Record<string, unknown> | undefined;
|
|
155
181
|
|
|
182
|
+
// Handle compaction completion
|
|
183
|
+
if (event.type === "session.compacted") {
|
|
184
|
+
const sessionID = props?.sessionID as string | undefined;
|
|
185
|
+
if (sessionID) {
|
|
186
|
+
const pending = state.pendingCompactions.get(sessionID);
|
|
187
|
+
if (pending) {
|
|
188
|
+
clearTimeout(pending.timeoutId);
|
|
189
|
+
state.pendingCompactions.delete(sessionID);
|
|
190
|
+
pending.resolve();
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
156
196
|
// Cleanup on session delete
|
|
157
197
|
if (event.type === "session.deleted") {
|
|
158
198
|
const sessionInfo = props?.info as { id?: string } | undefined;
|
|
159
199
|
if (sessionInfo?.id) {
|
|
160
200
|
state.inProgress.delete(sessionInfo.id);
|
|
161
201
|
state.lastCompactTime.delete(sessionInfo.id);
|
|
202
|
+
const pending = state.pendingCompactions.get(sessionInfo.id);
|
|
203
|
+
if (pending) {
|
|
204
|
+
clearTimeout(pending.timeoutId);
|
|
205
|
+
state.pendingCompactions.delete(sessionInfo.id);
|
|
206
|
+
pending.reject(new Error("Session deleted"));
|
|
207
|
+
}
|
|
162
208
|
}
|
|
163
209
|
return;
|
|
164
210
|
}
|