@retaw106/mmc-oc 2.5.0 → 2.7.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/dist/{context-xx09sh1g.js → context-9q17e52a.js} +553 -214
- package/dist/features/magic-context/auto-search-diagnostics.d.ts +27 -0
- package/dist/features/magic-context/auto-search-diagnostics.d.ts.map +1 -0
- package/dist/features/magic-context/compaction-marker.d.ts +34 -6
- package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +1 -24
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +4 -0
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/session-decision-calibration.d.ts.map +1 -1
- package/dist/features/magic-context/session-retention.fixture.d.ts +4 -0
- package/dist/features/magic-context/session-retention.fixture.d.ts.map +1 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts +21 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-native-replay.d.ts +2 -0
- package/dist/features/magic-context/storage-native-replay.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts +4 -11
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/features/magic-context/tool-definition-tokens.d.ts +113 -58
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/features/magic-context/work-metrics.d.ts +5 -3
- package/dist/features/magic-context/work-metrics.d.ts.map +1 -1
- package/dist/hooks/magic-context/apply-operations.d.ts +32 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/ask-answer-notice.d.ts +25 -0
- package/dist/hooks/magic-context/ask-answer-notice.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-observation.d.ts +13 -0
- package/dist/hooks/magic-context/auto-search-observation.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +5 -5
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-publication.d.ts +14 -0
- package/dist/hooks/magic-context/compaction-marker-publication.d.ts.map +1 -0
- package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +11 -0
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +11 -3
- package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
- package/dist/hooks/magic-context/historian-history-wait.d.ts +16 -0
- package/dist/hooks/magic-context/historian-history-wait.d.ts.map +1 -0
- package/dist/hooks/magic-context/history-boundary-repair.d.ts +1 -1
- package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts +3 -1
- package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay-fit.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
- package/dist/hooks/magic-context/lkg-slot.d.ts +2 -0
- package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +8 -2
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-raw.d.ts +20 -0
- package/dist/hooks/magic-context/read-session-raw.d.ts.map +1 -1
- package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts +42 -0
- package/dist/hooks/magic-context/signed-thinking-fit-snapshot.d.ts.map +1 -0
- package/dist/hooks/magic-context/tag-messages.d.ts +2 -0
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/todo-view.d.ts +2 -2
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-bpjjcdy9.js → index-8rmt6s4f.js} +77 -31
- package/dist/{index-mjf0p7yq.js → index-cgjyhwdk.js} +1 -1
- package/dist/{index-k25thxq7.js → index-s3ebcy63.js} +1 -1
- package/dist/{index-1vxffj5j.js → index-t0zx3tgz.js} +408 -89
- package/dist/{index-0d40b4q8.js → index-xrxpbe74.js} +9355 -9215
- package/dist/index.js +14 -4
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/{read-session-chunk-eb3fy45y.js → read-session-chunk-2s8x6xps.js} +2 -2
- package/dist/{recomp-orchestrator-mmpy5cb7.js → recomp-orchestrator-gzd1at06.js} +5 -5
- package/dist/{send-session-notification-zpqs213d.js → send-session-notification-vdppp5x6.js} +2 -2
- package/dist/shared/search-text.d.ts +2 -0
- package/dist/shared/search-text.d.ts.map +1 -1
- package/dist/shared/tag-transcript.d.ts +2 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/shared/transcript.d.ts +3 -1
- package/dist/shared/transcript.d.ts.map +1 -1
- package/dist/tools/ctx-expand/render.d.ts +5 -3
- package/dist/tools/ctx-expand/render.d.ts.map +1 -1
- package/dist/tools/ctx-expand/tools.d.ts +2 -0
- package/dist/tools/ctx-expand/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/parameter-descriptions.d.ts +10 -10
- package/dist/tools/parameter-descriptions.d.ts.map +1 -1
- package/dist/tui.js +2144 -0
- package/dist/v2/hooks/context.d.ts +5 -1
- package/dist/v2/hooks/context.d.ts.map +1 -1
- package/dist/v2/hooks/store.d.ts.map +1 -1
- package/dist/v2/message-times.d.ts +17 -0
- package/dist/v2/message-times.d.ts.map +1 -0
- package/dist/v2/server.js +11211 -10345
- package/dist/v2/store-reader.d.ts +14 -4
- package/dist/v2/store-reader.d.ts.map +1 -1
- package/dist/v2/tui/client.d.ts +57 -0
- package/dist/v2/tui/client.d.ts.map +1 -0
- package/dist/v2/tui/context-rpc.d.ts +63 -0
- package/dist/v2/tui/context-rpc.d.ts.map +1 -0
- package/dist/v2/tui/entry.d.ts +8 -0
- package/dist/v2/tui/entry.d.ts.map +1 -0
- package/dist/v2/tui/notification-socket.d.ts +26 -0
- package/dist/v2/tui/notification-socket.d.ts.map +1 -0
- package/dist/v2/tui/session-directory.d.ts +22 -0
- package/dist/v2/tui/session-directory.d.ts.map +1 -0
- package/dist/v2/tui/types.d.ts +110 -0
- package/dist/v2/tui/types.d.ts.map +1 -0
- package/dist/web/main.js +85 -11
- package/dist/{wrapup-orchestrator-jq589pgr.js → wrapup-orchestrator-ghq4y406.js} +5 -5
- package/package.json +13 -3
- package/src/config/latch-permanence-guard.test.ts +0 -5
- package/src/shared/prompt-surface-a1-golden.md +8 -9
- package/src/shared/search-text.test.ts +36 -1
- package/src/shared/search-text.ts +48 -0
- package/src/shared/sqlite-transaction-mode-guard.test.ts +2 -0
- package/src/shared/tag-transcript.ts +47 -4
- package/src/shared/transcript.ts +1 -1
- package/src/shared/write-transaction-attribution.test.ts +1 -6
- package/tui.js +4 -0
- package/dist/features/magic-context/message-index-sweep.d.ts +0 -11
- package/dist/features/magic-context/message-index-sweep.d.ts.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Magic Context agent-facing surface (exported from source)
|
|
2
2
|
|
|
3
|
-
Generated by `packages/plugin/scripts/export-agent-surface.ts` at 2026-10
|
|
3
|
+
Generated by `packages/plugin/scripts/export-agent-surface.ts` at 2026-11-10.
|
|
4
4
|
Token counts are Claude BPE estimates on the raw text.
|
|
5
5
|
|
|
6
6
|
## 1. System-prompt guidance section
|
|
@@ -201,7 +201,7 @@ Finer recovery:
|
|
|
201
201
|
}
|
|
202
202
|
```
|
|
203
203
|
|
|
204
|
-
### mmc_note — description ~319 tokens, params ~
|
|
204
|
+
### mmc_note — description ~319 tokens, params ~196 tokens (total ~515)
|
|
205
205
|
|
|
206
206
|
**Description:**
|
|
207
207
|
|
|
@@ -228,7 +228,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
|
|
|
228
228
|
```json
|
|
229
229
|
{
|
|
230
230
|
"action": {
|
|
231
|
-
"description": "write | read | update | dismiss.
|
|
231
|
+
"description": "write | read | update | dismiss.",
|
|
232
232
|
"type": "string",
|
|
233
233
|
"enum": [
|
|
234
234
|
"write",
|
|
@@ -259,8 +259,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
|
|
|
259
259
|
"type": "number"
|
|
260
260
|
},
|
|
261
261
|
"note_ids": {
|
|
262
|
-
"description": "Note ids: one for update, 1–50 for dismiss or
|
|
263
|
-
"minItems": 1,
|
|
262
|
+
"description": "Note ids: one for update, 1–50 for dismiss, or 1–50 to read those notes in full. Write and a plain read take an empty list.",
|
|
264
263
|
"maxItems": 50,
|
|
265
264
|
"type": "array",
|
|
266
265
|
"items": {
|
|
@@ -272,7 +271,7 @@ First line is the title (under 80 chars), followed by detail. Operations:
|
|
|
272
271
|
}
|
|
273
272
|
```
|
|
274
273
|
|
|
275
|
-
### mmc_memory — description ~279 tokens, params ~
|
|
274
|
+
### mmc_memory — description ~279 tokens, params ~198 tokens (total ~477)
|
|
276
275
|
|
|
277
276
|
**Description:**
|
|
278
277
|
|
|
@@ -306,11 +305,11 @@ Examples: category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/op
|
|
|
306
305
|
]
|
|
307
306
|
},
|
|
308
307
|
"content": {
|
|
309
|
-
"description": "The memory text — one standalone fact (write, update, merge).",
|
|
308
|
+
"description": "The memory text — one standalone fact (write, update, merge). Archive and get take an empty string.",
|
|
310
309
|
"type": "string"
|
|
311
310
|
},
|
|
312
311
|
"category": {
|
|
313
|
-
"description": "Kind of fact
|
|
312
|
+
"description": "Kind of fact: the new fact's kind for write; on update/merge, the memory's current category to keep it. Archive and get ignore it.",
|
|
314
313
|
"type": "string",
|
|
315
314
|
"enum": [
|
|
316
315
|
"PROJECT_RULES",
|
|
@@ -321,7 +320,7 @@ Examples: category="CONFIG_VALUES", content="OpenCode source is at ~/Work/OSS/op
|
|
|
321
320
|
]
|
|
322
321
|
},
|
|
323
322
|
"ids": {
|
|
324
|
-
"description": "Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get.",
|
|
323
|
+
"description": "Memory ids from <project-memory>: one for update, one or more for archive, two or more for merge, 1–20 for get. Write takes an empty list.",
|
|
325
324
|
"type": "array",
|
|
326
325
|
"items": {
|
|
327
326
|
"type": "number"
|
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
import { expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
cleanSearchText,
|
|
4
|
+
hintKeywordRelevance,
|
|
5
|
+
keywordRelevance,
|
|
6
|
+
matchedSearchSnippet,
|
|
7
|
+
} from "./search-text";
|
|
8
|
+
|
|
9
|
+
test("hint scoring preserves exact English and other space-separated keyword scores", () => {
|
|
10
|
+
const cases: Array<[string, string, number]> = [
|
|
11
|
+
["explain historian cache wiring", "cache icons", 0.2],
|
|
12
|
+
["historian cache wiring", "historian cache wiring details", 0.8000000000000002],
|
|
13
|
+
["please explain cache wiring to me", "cache wiring", 0.5333333333333333],
|
|
14
|
+
["CACHE cache cache_timeout", "cache_timeout", 0.4],
|
|
15
|
+
["how are you", "how are you", 0],
|
|
16
|
+
["historian cache", "<task>historian cache</task>", 0],
|
|
17
|
+
["résumé über prüfen", "über prüfen", 0.5333333333333333],
|
|
18
|
+
["память кеш", "кеш", 0.4],
|
|
19
|
+
["ذاكرة تخزين", "تخزين", 0.4],
|
|
20
|
+
];
|
|
21
|
+
for (const [query, content, expected] of cases) {
|
|
22
|
+
expect(keywordRelevance(query, content)).toBe(expected);
|
|
23
|
+
expect(hintKeywordRelevance(query, content)).toBe(expected);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("only hint scoring splits unspaced CJK runs into overlapping character bigrams", () => {
|
|
28
|
+
expect(keywordRelevance("MC_Maze 残差怎样汇总?", "MC_Maze 残差按种子汇总。")).toBe(0.4);
|
|
29
|
+
expect(hintKeywordRelevance("残差", "残留")).toBe(0);
|
|
30
|
+
expect(hintKeywordRelevance("差", "残差")).toBe(0.8);
|
|
31
|
+
expect(hintKeywordRelevance("𠮷野家", "𠮷野川")).toBe(0.8);
|
|
32
|
+
expect(hintKeywordRelevance("かながき", "かながきです")).toBe(0.8);
|
|
33
|
+
expect(hintKeywordRelevance("カタカナ", "カタカナです")).toBe(0.8);
|
|
34
|
+
expect(hintKeywordRelevance("프로젝트캐시", "프로젝트의캐시")).toBe(0.8);
|
|
35
|
+
expect(hintKeywordRelevance("cache残差", "cache残差按种子汇总")).toBe(0.8);
|
|
36
|
+
expect(hintKeywordRelevance("差", "<task>残差</task> unrelated")).toBe(0);
|
|
37
|
+
});
|
|
3
38
|
|
|
4
39
|
test("notification trees never contribute relevance or display text", () => {
|
|
5
40
|
expect(
|
|
@@ -35,6 +35,54 @@ export function keywordRelevance(query: string, content: string): number {
|
|
|
35
35
|
return (0.8 * needles.filter((term) => words.has(term)).length) / needles.length;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
const CJK_RUN = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+$/u;
|
|
39
|
+
const CJK_RUN_SPLIT = /([\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+)/u;
|
|
40
|
+
|
|
41
|
+
function hintTerms(text: string): string[] {
|
|
42
|
+
return [
|
|
43
|
+
...new Set(
|
|
44
|
+
terms(text)
|
|
45
|
+
.flatMap((term) => term.split(CJK_RUN_SPLIT))
|
|
46
|
+
.filter((term) => term.length > 0 && !QUERY_STOP_WORDS.has(term)),
|
|
47
|
+
),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function characterBigrams(run: string): string[] {
|
|
52
|
+
const characters = [...run];
|
|
53
|
+
return characters.length === 1
|
|
54
|
+
? characters
|
|
55
|
+
: characters.slice(1).map((character, index) => characters[index] + character);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Match unspaced clauses for hints without changing retrieval or snippet scoring. */
|
|
59
|
+
export function hintKeywordRelevance(query: string, content: string): number {
|
|
60
|
+
const needles = hintTerms(query);
|
|
61
|
+
if (needles.length === 0) return 0;
|
|
62
|
+
const words = new Set(hintTerms(cleanSearchText(content)));
|
|
63
|
+
const runs = [...words].filter((word) => CJK_RUN.test(word));
|
|
64
|
+
const bigrams = new Set(runs.flatMap(characterBigrams));
|
|
65
|
+
let matched = 0;
|
|
66
|
+
for (const needle of needles) {
|
|
67
|
+
if (!CJK_RUN.test(needle)) {
|
|
68
|
+
matched += Number(words.has(needle));
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const grams = characterBigrams(needle);
|
|
72
|
+
if ([...needle].length === 1) {
|
|
73
|
+
matched += Number(runs.some((run) => run.includes(needle)));
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Count each clause as one term so filler bigrams across word boundaries
|
|
77
|
+
// do not dilute it; require half coverage so shared function words alone do not pass.
|
|
78
|
+
matched += Math.min(
|
|
79
|
+
1,
|
|
80
|
+
grams.filter((gram) => bigrams.has(gram)).length / Math.ceil(grams.length / 2),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return (0.8 * matched) / needles.length;
|
|
84
|
+
}
|
|
85
|
+
|
|
38
86
|
/** Pick the densest matching passage before compression discards matched words. */
|
|
39
87
|
export function matchedSearchSnippet(content: string, query: string, cap = 220): string {
|
|
40
88
|
const text = cleanSearchText(content);
|
|
@@ -27,6 +27,8 @@ const READ_ONLY_DEFERRED_TRANSACTIONS: Record<string, string> = {
|
|
|
27
27
|
"pins one read snapshot so the session's rowid coverage proof and the filtered message search see the same rows; never writes (read-only connections use it too)",
|
|
28
28
|
"packages/plugin/src/hooks/magic-context/lkg-persist.ts#loadPersistedLkgSlot":
|
|
29
29
|
"reads an LKG slot row and its prefix slices as one consistent snapshot even while another connection saves the slot; never writes (a failed verification clear opens its own transaction)",
|
|
30
|
+
"packages/plugin/src/hooks/magic-context/compaction-marker-manager.ts#reconcileForkOrphanedCompactionMarkers":
|
|
31
|
+
"reads publication intent and finalized ownership as one context.db snapshot while host-order probes use the already-open host connection; never writes context.db",
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
const REPOSITORY_ROOT = resolve(import.meta.dir, "../../../..");
|
|
@@ -75,6 +75,8 @@ import type { Transcript, TranscriptMessage, TranscriptPart } from "./transcript
|
|
|
75
75
|
export { TEXT_TAG_IDENTITY_MARKER };
|
|
76
76
|
|
|
77
77
|
export interface TagTranscriptOptions {
|
|
78
|
+
/** Independently validated text sources; does not authorize tool accounting reuse. */
|
|
79
|
+
reuseTextMessageIds?: ReadonlySet<string>;
|
|
78
80
|
/**
|
|
79
81
|
* When true, skip injecting `§N§` prefix into visible text. Tags
|
|
80
82
|
* still get assigned in the DB so historian/drops can reference
|
|
@@ -305,6 +307,12 @@ interface ToolAggregate {
|
|
|
305
307
|
maxByteSize: number;
|
|
306
308
|
/** Token count paired with maxByteSize (the same output occurrence). */
|
|
307
309
|
maxTokenCount: number;
|
|
310
|
+
/**
|
|
311
|
+
* Whether maxTokenCount is a real count. Legacy rows can store bytes with a
|
|
312
|
+
* NULL token_count; seeding 0 from that must not look like a stored count,
|
|
313
|
+
* or unchanged results would never be recounted.
|
|
314
|
+
*/
|
|
315
|
+
tokenCountKnown: boolean;
|
|
308
316
|
/** Tool name from the first occurrence we see one on. */
|
|
309
317
|
toolName: string | null;
|
|
310
318
|
/** Input byte size from the invocation occurrence (for storage projection). */
|
|
@@ -417,7 +425,10 @@ export function tagTranscript(
|
|
|
417
425
|
targets,
|
|
418
426
|
skipPrefixInjection,
|
|
419
427
|
entryFingerprint: options.entryFingerprintByMessageId?.get(messageId) ?? null,
|
|
420
|
-
reuseIdentity:
|
|
428
|
+
reuseIdentity:
|
|
429
|
+
reuseIdentity ||
|
|
430
|
+
options.reuseTextMessageIds?.has(messageId) === true ||
|
|
431
|
+
contentDerivedTextIds !== undefined,
|
|
421
432
|
timing,
|
|
422
433
|
textIdentitySourceCache: options.textIdentitySourceCache,
|
|
423
434
|
textTokenCache: options.textTokenCache,
|
|
@@ -508,6 +519,13 @@ export function tagTranscript(
|
|
|
508
519
|
timing,
|
|
509
520
|
options.toolTokenCache,
|
|
510
521
|
tokenCacheKey,
|
|
522
|
+
{
|
|
523
|
+
byteSize: existing.maxByteSize,
|
|
524
|
+
tokenCount: existing.tokenCountKnown
|
|
525
|
+
? existing.maxTokenCount
|
|
526
|
+
: null,
|
|
527
|
+
inputTokenCount: existing.inputTokenCount,
|
|
528
|
+
},
|
|
511
529
|
);
|
|
512
530
|
text = accounting.text;
|
|
513
531
|
if (part.kind === "tool_result") {
|
|
@@ -596,6 +614,7 @@ export function tagTranscript(
|
|
|
596
614
|
// genuinely larger folded result can still bump accounting.
|
|
597
615
|
maxByteSize: reusableAccounting.byteSize,
|
|
598
616
|
maxTokenCount: reusableAccounting.tokenCount ?? 0,
|
|
617
|
+
tokenCountKnown: reusableAccounting.tokenCount !== null,
|
|
599
618
|
toolName: null,
|
|
600
619
|
inputByteSize: reusableAccounting.inputByteSize,
|
|
601
620
|
inputTokenCount: reusableAccounting.inputTokenCount,
|
|
@@ -623,6 +642,7 @@ export function tagTranscript(
|
|
|
623
642
|
timing,
|
|
624
643
|
options.toolTokenCache,
|
|
625
644
|
tokenCacheKey,
|
|
645
|
+
tagger.getToolTagAccounting(sessionId, callId, messageId),
|
|
626
646
|
);
|
|
627
647
|
text = accounting.text;
|
|
628
648
|
const outputByteSize = part.kind === "tool_result" ? accounting.byteSize : 0;
|
|
@@ -657,6 +677,11 @@ export function tagTranscript(
|
|
|
657
677
|
occurrences: [{ message, part, kind: part.kind }],
|
|
658
678
|
maxByteSize: persistedAccounting?.byteSize ?? outputByteSize,
|
|
659
679
|
maxTokenCount: persistedAccounting?.tokenCount ?? outputTokenCount,
|
|
680
|
+
// A fresh allocation just wrote outputTokenCount (0 for an
|
|
681
|
+
// invocation); an existing row keeps its NULL as unknown.
|
|
682
|
+
tokenCountKnown: persistedAccounting
|
|
683
|
+
? persistedAccounting.tokenCount !== null
|
|
684
|
+
: true,
|
|
660
685
|
toolName: accounting.toolName,
|
|
661
686
|
inputByteSize:
|
|
662
687
|
persistedAccounting?.inputByteSize ??
|
|
@@ -745,7 +770,9 @@ function syncToolAggregateAccounting(
|
|
|
745
770
|
): void {
|
|
746
771
|
tagger.setToolTagAccounting(sessionId, aggregate.tagId, {
|
|
747
772
|
byteSize: aggregate.maxByteSize,
|
|
748
|
-
|
|
773
|
+
// Unknown stays unknown so the next occurrence/pass recounts instead of
|
|
774
|
+
// caching a fabricated 0 for a legacy row.
|
|
775
|
+
tokenCount: aggregate.tokenCountKnown ? aggregate.maxTokenCount : null,
|
|
749
776
|
inputByteSize: aggregate.inputByteSize,
|
|
750
777
|
inputTokenCount: aggregate.inputTokenCount,
|
|
751
778
|
});
|
|
@@ -770,6 +797,7 @@ function applyGrownToolResultAccounting(args: GrownToolResultAccountingArgs): vo
|
|
|
770
797
|
}
|
|
771
798
|
args.aggregate.maxByteSize = args.byteSize;
|
|
772
799
|
args.aggregate.maxTokenCount = tokenCount;
|
|
800
|
+
args.aggregate.tokenCountKnown = true;
|
|
773
801
|
updateTagByteSize(args.db, args.sessionId, args.aggregate.tagId, args.byteSize);
|
|
774
802
|
updateTagTokenCount(args.db, args.sessionId, args.aggregate.tagId, tokenCount);
|
|
775
803
|
syncToolAggregateAccounting(args.tagger, args.sessionId, args.aggregate);
|
|
@@ -780,12 +808,22 @@ function readAggregateToolAccounting(
|
|
|
780
808
|
timing: TagTranscriptTiming | undefined,
|
|
781
809
|
tokenCache?: Map<string, { text: string; tokenCount: number }>,
|
|
782
810
|
tokenCacheKey?: string,
|
|
811
|
+
persisted?: { byteSize: number; tokenCount: number | null; inputTokenCount: number | null },
|
|
783
812
|
): AggregateToolAccounting {
|
|
784
813
|
const text = part.getText() ?? "";
|
|
785
814
|
const byteSize = getToolPartByteSize(part, text);
|
|
786
|
-
|
|
815
|
+
// Persisted tool-result accounting tracks the largest byte size seen. Skip
|
|
816
|
+
// output tokenization when that size has not grown and a count is stored;
|
|
817
|
+
// known input counts also need no tokenization. Growth and missing counts still take
|
|
818
|
+
// the original counting path, even when the identity was not reusable.
|
|
819
|
+
const metadata = part.getToolMetadata({
|
|
820
|
+
skipInputTokenCount: persisted?.inputTokenCount != null,
|
|
821
|
+
});
|
|
787
822
|
let tokenCount = 0;
|
|
788
|
-
if (
|
|
823
|
+
if (
|
|
824
|
+
part.kind === "tool_result" &&
|
|
825
|
+
(!persisted || persisted.tokenCount === null || byteSize > persisted.byteSize)
|
|
826
|
+
) {
|
|
789
827
|
const tokenStart = timing ? performance.now() : 0;
|
|
790
828
|
tokenCount = getCachedToolPartTokenCount(part, text, tokenCache, tokenCacheKey);
|
|
791
829
|
if (timing) timing.tokenCounting += performance.now() - tokenStart;
|
|
@@ -1414,6 +1452,11 @@ function buildAggregateTarget(
|
|
|
1414
1452
|
},
|
|
1415
1453
|
// Open invocations still belong to the current turn; only complete arcs reclaim.
|
|
1416
1454
|
prepareDrop: () => !occurrences.some((occ) => occ.part.canRemove?.() === "defer"),
|
|
1455
|
+
prepareReplayDrop: () => {
|
|
1456
|
+
if (complete() && !requiresToolArcSkeleton) {
|
|
1457
|
+
for (const occ of occurrences) occ.part.canRemove?.();
|
|
1458
|
+
}
|
|
1459
|
+
},
|
|
1417
1460
|
canDrop: () => complete() && !occurrences.some((occ) => occ.part.hasUserAnswer?.()),
|
|
1418
1461
|
requiresToolArcSkeleton,
|
|
1419
1462
|
// Non-mutating read of the invocation input (the tool_use occurrence
|
package/src/shared/transcript.ts
CHANGED
|
@@ -132,7 +132,7 @@ export interface TranscriptPart {
|
|
|
132
132
|
*
|
|
133
133
|
* For non-tool parts both byte fields are undefined/0.
|
|
134
134
|
*/
|
|
135
|
-
getToolMetadata(): {
|
|
135
|
+
getToolMetadata(options?: { skipInputTokenCount?: boolean }): {
|
|
136
136
|
toolName: string | undefined;
|
|
137
137
|
inputByteSize: number;
|
|
138
138
|
inputTokenCount: number;
|
|
@@ -14,11 +14,7 @@ const fencedSources: Array<{ path: string; sites: string[]; reporterCalls?: stri
|
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
path: "packages/plugin/src/features/magic-context/message-index.ts",
|
|
17
|
-
sites: [
|
|
18
|
-
"message_index_incremental",
|
|
19
|
-
"message_index_reconcile",
|
|
20
|
-
"message_index_orphan_sweep",
|
|
21
|
-
],
|
|
17
|
+
sites: ["message_index_incremental", "message_index_reconcile"],
|
|
22
18
|
},
|
|
23
19
|
{
|
|
24
20
|
path: "packages/plugin/src/features/magic-context/storage-meta-persisted.ts",
|
|
@@ -101,7 +97,6 @@ const newlyCoveredSites = [
|
|
|
101
97
|
"opencode_soft_refresh_cache",
|
|
102
98
|
"message_index_incremental",
|
|
103
99
|
"message_index_reconcile",
|
|
104
|
-
"message_index_orphan_sweep",
|
|
105
100
|
"message_index_clear",
|
|
106
101
|
"message_fts_rowid_backfill",
|
|
107
102
|
"storage_meta_wrapup_expiry_cleanup",
|
package/tui.js
ADDED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Database } from "../../shared/sqlite";
|
|
2
|
-
import { type MessageHistoryOrphanSweepOptions, type MessageHistoryOrphanSweepResult } from "./message-index";
|
|
3
|
-
/**
|
|
4
|
-
* Scope wrapper for the background sweep. It lives beside `message-index` rather
|
|
5
|
-
* than inside it: importing the transform-pass scope helpers into
|
|
6
|
-
* `message-index.ts` itself changes the bundled module graph in a way that hits
|
|
7
|
-
* a Bun 1.4.2 packaging bug (a top-level `__promiseAll` init call is emitted
|
|
8
|
-
* without its definition, which crashes node hosts at import time).
|
|
9
|
-
*/
|
|
10
|
-
export declare function sweepOrphanedOpenCodeMessageIndexes(db: Database, openReadableOpenCodeDb: () => Database | null, options?: MessageHistoryOrphanSweepOptions): MessageHistoryOrphanSweepResult;
|
|
11
|
-
//# sourceMappingURL=message-index-sweep.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message-index-sweep.d.ts","sourceRoot":"","sources":["../../../src/features/magic-context/message-index-sweep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EACH,KAAK,gCAAgC,EACrC,KAAK,+BAA+B,EAEvC,MAAM,iBAAiB,CAAC;AAEzB;;;;;;GAMG;AACH,wBAAgB,mCAAmC,CAC/C,EAAE,EAAE,QAAQ,EACZ,sBAAsB,EAAE,MAAM,QAAQ,GAAG,IAAI,EAC7C,OAAO,GAAE,gCAAqC,GAC/C,+BAA+B,CAMjC"}
|