Skip to content

Commit c6fab38

Browse files
author
SqlRush
committed
Accept adjacent microcompact cache fields
1 parent be53fe3 commit c6fab38

4 files changed

Lines changed: 44 additions & 10 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
418418

419419
本轮补充:conversation runner 现在会在用户消息入队后计算 compact token warning state,并在触发 warning/error/auto-compact/blocking 阈值时发出 `token_warning` event;warning state 接入 blocking-limit override,auto-compact threshold 判断接入 `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`,使 runtime warning 和自动压缩使用同一套 window 输入。
420420

421-
本轮补充:microcompact disk cache loader 现在读取 Go 默认、camelCasesnake_case 字段别名,并容忍计数字段的数字字符串,以及 RFC3339、Unix 秒、Unix 毫秒时间字段,提升 cached microcompact 文件在不同实现/版本间的恢复率。
421+
本轮补充:microcompact disk cache loader 现在读取 Go 默认、camelCasesnake_case 和相邻实现常见字段别名,包括 `content`/`text` summary、`cacheKey`/`key`/`hash` digest、cache-hit 别名、计数字段别名/数字字符串,以及 RFC3339、Unix 秒、Unix 毫秒时间字段,提升 cached microcompact 文件在不同实现/版本间的恢复率。
422422

423423
本轮补充:contract content block 解码现在接受文本块字段别名 `body`/`message`/`value`/`output`/`contentText`/`content_text`,并在 `text`/`thinking` block 中从字符串 `content` 回填文本,transcript resume 可恢复这些嵌套文本块格式。
424424

docs/first-second-parity-audit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ M6 progress now includes:
123123

124124
- `internal/memory`: recursive `.md` memory scanning, frontmatter parsing, newest-first capped manifests, root-to-leaf `CLAUDE.md` discovery/loading, and team-memory secret detection.
125125
- `internal/compact`: effective context window calculations, auto-compact thresholds, token warning state, compact summary prompt construction, compact API runner, compact boundary/summary plan generation, auto-compact window env override application, microcompact/cache primitives, persistent cached microcompact storage, structural/rich-content microcompact cache digests, cache version/TTL/prune handling for disk and in-memory caches, memory-cache write-through to disk, atomic cache writes, corrupt-cache fail-open behavior, and filename/digest mismatch pruning.
126-
- `internal/compact`: microcompact disk cache loading now accepts Go default, camelCase, and snake_case field aliases, including numeric strings for count fields and RFC3339/Unix-seconds/Unix-millis time fields, so cached microcompact records from adjacent implementations remain usable.
126+
- `internal/compact`: microcompact disk cache loading now accepts Go default, camelCase, snake_case, and adjacent cache field aliases such as `content`/`text` summary, `cacheKey`/`key`/`hash` digest, cache-hit aliases, numeric strings for count fields, and RFC3339/Unix-seconds/Unix-millis time fields, so cached microcompact records from adjacent implementations remain usable.
127127
- `internal/conversation`: optional auto-compact can now run before the main request, fail open with a consecutive-failure circuit breaker, emit runtime `token_warning` events from compact warning state, persist compact boundary metadata to transcript, write a session-memory summary, inject recalled session-memory snippets into API request context when enabled, and optionally extract turn-end memory facts into session memory.
128128
- `internal/memory`: session-memory summaries can now be loaded with frontmatter field aliases, rolled up/pruned into an archive summary with prior rollup archives excluded from candidate compaction and merged across archive IDs, rune-safe rollup truncation, recalled by query with deterministic scoring and recency ordering, ranked through a model-assisted candidate/session-id selection path with fallback when selected IDs are invalid or excluded, alternate/camel response-key parsing, fenced/prose JSON extraction, scalar session-id parsing, nested/wrapped/collection-alias selection parsing, and nested selected-memory item parsing, and injected into resume context through the same optional recall agent path; deterministic and model-backed memory fact extraction can summarize user preferences, requests, decisions, and tool-use facts, including fenced/prose JSON, wrapped facts responses, alternate and structured fact field names, nested source objects, nested fact response shapes, and fact kind aliases.
129129
- `internal/session`: project session listing and pagination, prompt-history lock/buffered flush/field aliases, lightweight transcript index/title/text-preview inference, line-offset transcript indexing/window/byte-budget-window/parent-chain/resume/tail/byte-budget-tail loading, AI-title/last-prompt/task/agent/PR/worktree transcript metadata loading and type/field aliases, transcript message/session UUID field aliases, tombstone metadata loading with target/session/reason aliases and delete/relink replay, agent-scoped content replacement metadata/record field-alias loading, session-scoped metadata reappend including AI-title/last-prompt/task-summary, streaming transcript search snippets for resume/search UI, official `subagents/agent-*.jsonl` transcript layout with legacy sidechain listing, agent metadata sidecar read/write/field aliases, sidechain runtime start/append/finish/cancel/fail summary bridging plus parent-chain append/finish, sidechain manager orchestration for spawn/append/finish/cancel/fail/list/resume, sidechain state/list/resume support with content-field aliases, sidechain resume context construction, sidechain conversation and agent-scoped content-replacement reconstruction, transcript tail/window loading and byte-budget tail loading for bounded-memory resume/UI paths, lightweight transcript metadata loading, remote-history token refresh retry, page-field/event-list/records/entries/last-id/cursor/event-id/has-next aliases plus wrapped-data/links/paging/bare-array/keyed-event-map responses, before_id resume, fallback field fill, and duplicate-aware parent linking during transcript materialization.

internal/compact/compact_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,40 @@ func TestLoadMicroResultAcceptsFieldAliases(t *testing.T) {
278278
}
279279
}
280280

281+
func TestLoadMicroResultAcceptsAdjacentCacheFieldAliases(t *testing.T) {
282+
cacheDir := filepath.Join(t.TempDir(), "micro")
283+
if err := os.MkdirAll(cacheDir, 0o755); err != nil {
284+
t.Fatal(err)
285+
}
286+
digest := "adjacent"
287+
data := `{
288+
"content": "adjacent summary",
289+
"cacheKey": "adjacent",
290+
"cacheHit": true,
291+
"summarizedMessages": "5",
292+
"retained_messages": 1,
293+
"cacheVersion": "microcompact.v1",
294+
"created": 100,
295+
"expiresMs": "3700000"
296+
}`
297+
if err := os.WriteFile(microResultPath(cacheDir, digest), []byte(data), 0o600); err != nil {
298+
t.Fatal(err)
299+
}
300+
result, ok, err := LoadMicroResult(cacheDir, digest)
301+
if err != nil {
302+
t.Fatal(err)
303+
}
304+
if !ok {
305+
t.Fatal("expected adjacent cache result")
306+
}
307+
if result.Summary != "adjacent summary" || result.Digest != digest || !result.Cached || result.MessagesSummarized != 5 || result.MessagesKept != 1 || result.Version != DefaultMicroCacheVersion {
308+
t.Fatalf("result = %#v", result)
309+
}
310+
if !result.CreatedAt.Equal(time.Unix(100, 0).UTC()) || !result.ExpiresAt.Equal(time.Unix(3700, 0).UTC()) {
311+
t.Fatalf("result times = %#v", result)
312+
}
313+
}
314+
281315
func TestLoadMicroResultAcceptsNumericTimeAliases(t *testing.T) {
282316
cacheDir := filepath.Join(t.TempDir(), "micro")
283317
if err := os.MkdirAll(cacheDir, 0o755); err != nil {

internal/compact/micro.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,42 +47,42 @@ func (r *MicroResult) UnmarshalJSON(data []byte) error {
4747
return err
4848
}
4949
var result MicroResult
50-
if value, ok, err := microStringJSONField(fields, "Summary", "summary"); err != nil {
50+
if value, ok, err := microStringJSONField(fields, "Summary", "summary", "summaryText", "summary_text", "content", "text", "value", "output"); err != nil {
5151
return err
5252
} else if ok {
5353
result.Summary = value
5454
}
55-
if value, ok, err := microStringJSONField(fields, "Digest", "digest"); err != nil {
55+
if value, ok, err := microStringJSONField(fields, "Digest", "digest", "cacheKey", "cache_key", "key", "hash"); err != nil {
5656
return err
5757
} else if ok {
5858
result.Digest = value
5959
}
60-
if value, ok, err := microBoolJSONField(fields, "Cached", "cached"); err != nil {
60+
if value, ok, err := microBoolJSONField(fields, "Cached", "cached", "isCached", "is_cached", "fromCache", "from_cache", "cacheHit", "cache_hit"); err != nil {
6161
return err
6262
} else if ok {
6363
result.Cached = value
6464
}
65-
if value, ok, err := microIntJSONField(fields, "MessagesSummarized", "messagesSummarized", "messages_summarized"); err != nil {
65+
if value, ok, err := microIntJSONField(fields, "MessagesSummarized", "messagesSummarized", "messages_summarized", "summarized", "summarizedMessages", "summarized_messages", "messageCount", "message_count", "inputMessages", "input_messages"); err != nil {
6666
return err
6767
} else if ok {
6868
result.MessagesSummarized = value
6969
}
70-
if value, ok, err := microIntJSONField(fields, "MessagesKept", "messagesKept", "messages_kept"); err != nil {
70+
if value, ok, err := microIntJSONField(fields, "MessagesKept", "messagesKept", "messages_kept", "kept", "keptMessages", "kept_messages", "retained", "retainedMessages", "retained_messages"); err != nil {
7171
return err
7272
} else if ok {
7373
result.MessagesKept = value
7474
}
75-
if value, ok, err := microStringJSONField(fields, "Version", "version"); err != nil {
75+
if value, ok, err := microStringJSONField(fields, "Version", "version", "cacheVersion", "cache_version", "schemaVersion", "schema_version"); err != nil {
7676
return err
7777
} else if ok {
7878
result.Version = value
7979
}
80-
if value, ok, err := microTimeJSONField(fields, "CreatedAt", "createdAt", "created_at", "createdAtMs", "created_at_ms", "createdAtMillis", "created_at_millis", "createdAtUnix", "created_at_unix", "createdAtUnixMs", "created_at_unix_ms"); err != nil {
80+
if value, ok, err := microTimeJSONField(fields, "CreatedAt", "createdAt", "created_at", "created", "createdMs", "created_ms", "createdAtMs", "created_at_ms", "createdAtMillis", "created_at_millis", "createdAtUnix", "created_at_unix", "createdAtUnixMs", "created_at_unix_ms"); err != nil {
8181
return err
8282
} else if ok {
8383
result.CreatedAt = value
8484
}
85-
if value, ok, err := microTimeJSONField(fields, "ExpiresAt", "expiresAt", "expires_at", "expiresAtMs", "expires_at_ms", "expiresAtMillis", "expires_at_millis", "expiresAtUnix", "expires_at_unix", "expiresAtUnixMs", "expires_at_unix_ms"); err != nil {
85+
if value, ok, err := microTimeJSONField(fields, "ExpiresAt", "expiresAt", "expires_at", "expires", "expiresMs", "expires_ms", "expiresAtMs", "expires_at_ms", "expiresAtMillis", "expires_at_millis", "expiresAtUnix", "expires_at_unix", "expiresAtUnixMs", "expires_at_unix_ms"); err != nil {
8686
return err
8787
} else if ok {
8888
result.ExpiresAt = value

0 commit comments

Comments
 (0)