Skip to content

Commit 3ec50d9

Browse files
author
SqlRush
committed
Accept remote history event id aliases
1 parent db402f6 commit 3ec50d9

4 files changed

Lines changed: 50 additions & 4 deletions

File tree

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ test/parity/ # golden tests against TS/official behavior
279279
- 本轮补充:content-replacement metadata 接受 `records`/`contentReplacements` 等 record wrapper,以及 record 内 `type`/`content`/`hash` 等字段别名,full loader、metadata loader 和 transcript index 的 replacement 恢复保持一致。
280280
- 本轮补充:remote history `SDKEvent` 解码接受顶层 `sessionID` 作为事件 session id 别名,materialize transcript 时会填充 record 与嵌套 message 的 session id(覆盖测试:`TestRemoteHistoryTranscriptMessagesAcceptsSessionIDUpperAlias`)。
281281
- 本轮补充:remote history `SDKEvent` 解码接受 `parentUUID``parentId`/`parentID`/`parent_id``parentMessageId`/`parentMessageID`/`parent_message_id` parent aliases,materialize transcript 时会保留 parent chain(覆盖测试:`TestRemoteHistoryTranscriptMessagesAcceptsParentIDAliases`)。
282+
- 本轮补充:remote history `SDKEvent` 解码接受 `eventID``messageId`/`messageID`/`message_id``messageUuid`/`messageUUID`/`message_uuid` 作为事件 ID aliases;只有 `uuid` 时也会作为 event ID fallback,materialize transcript 时能稳定生成 message UUID 与 parent chain(覆盖测试:`TestRemoteHistoryTranscriptMessagesAcceptsEventMessageIDAliases`)。
282283
- 本轮补充:memory 层补齐官方 `memoryAge`/freshness note 语义,`ReadDocumentsWithOptions` 可为超过 1 天的 memory 文档前缀 system-reminder,提示模型把 memory 当作 point-in-time observation 并核对当前代码。
283284
- 本轮补充:Read tool 在 metadata 提供 auto-memory 目录时,会为读取旧 auto-memory 文件的 tool result 前缀 freshness system-reminder,和官方 FileReadTool 的 memory freshness prefix 对齐。
284285
- 本轮补充:memory 层补齐官方 `relevant_memories` attachment 基础,包含 stable memory header、system-reminder 渲染、surfaced path/byte 扫描、按 200 行/4096 bytes 读取并附截断提示的 surfacing reader、mark-after-filter 的 duplicate memory attachment 过滤、最后非 meta user prompt/单词 prompt/60KB session cap 的 prefetch gating、多目录结果排除 read-state/surfaced 后取前 5 个候选的选择逻辑,以及 recent successful tools 窗口收集并排除 pending/failed/同名失败工具。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ M6 progress now includes:
227227
- `internal/session` and `internal/contracts`: transcript records and nested contract messages now accept top-level `sessionID` as a session id alias, preserving it through `LoadTranscript`, `LoadTranscriptIndex`, and indexed resume (`TestLoadTranscriptAcceptsSessionIDUpperAlias`).
228228
- `internal/contracts`/`internal/session`: remote-history `SDKEvent` decoding now accepts top-level `sessionID` as an event session id alias and preserves it during transcript materialization (`TestRemoteHistoryTranscriptMessagesAcceptsSessionIDUpperAlias`).
229229
- `internal/contracts`/`internal/session`: remote-history `SDKEvent` decoding now accepts parent aliases such as `parentUUID`, `parentId`/`parentID`/`parent_id`, and `parentMessageId`/`parentMessageID`/`parent_message_id`, preserving parent chains during transcript materialization (`TestRemoteHistoryTranscriptMessagesAcceptsParentIDAliases`).
230+
- `internal/contracts`/`internal/session`: remote-history `SDKEvent` decoding now accepts event/message ID aliases such as `eventID`, `messageId`/`messageID`/`message_id`, and `messageUuid`/`messageUUID`/`message_uuid`, using them as transcript UUID fallbacks during materialization (`TestRemoteHistoryTranscriptMessagesAcceptsEventMessageIDAliases`).
230231
- `internal/contracts`/`internal/session`: remote-history `SDKEvent` type canonicalization now also accepts adjacent stream/provider aliases such as `assistant_delta`, `humanMessage`, `finalResult`, `response.completed`, `failureEvent`, and `statusMessage`, keeping transcript materialization stable across SDK event spellings.
231232
- `internal/memory`: memory age/freshness helpers now match official stale-memory guidance, and document loading can prefix old memory files with a system-reminder that they are point-in-time observations.
232233
- `internal/memory`: relevant-memory attachment primitives now match the official `relevant_memories` shape for stable headers, system-reminder rendering, surfaced path/byte scanning, 200-line/4096-byte surfacing reads with truncation notices, mark-after-filter duplicate attachment handling, last-non-meta-user/single-word/session-byte-cap prefetch gating, top-5 candidate filtering after read-state/surfaced de-dup, and recent successful tools collection excluding pending/failed/same-name-failed tools.

internal/contracts/session.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,13 @@ func (e *SDKEvent) UnmarshalJSON(data []byte) error {
153153
MessageTypeSnake string `json:"message_type"`
154154
EventIDSnake ID `json:"event_id"`
155155
EventIDCamel ID `json:"eventId"`
156+
EventIDUpper ID `json:"eventID"`
157+
MessageID ID `json:"messageId"`
158+
MessageIDUpper ID `json:"messageID"`
159+
MessageIDSnake ID `json:"message_id"`
160+
MessageUUID ID `json:"messageUuid"`
161+
MessageUUIDUpper ID `json:"messageUUID"`
162+
MessageUUIDSnake ID `json:"message_uuid"`
156163
SessionIDUpper ID `json:"sessionID"`
157164
SessionUUID ID `json:"sessionUuid"`
158165
SessionUUIDUpper ID `json:"sessionUUID"`
@@ -190,10 +197,18 @@ func (e *SDKEvent) UnmarshalJSON(data []byte) error {
190197
e.Type = eventType
191198
}
192199
if e.ID == "" {
193-
e.ID = aux.EventIDSnake
194-
}
195-
if e.ID == "" {
196-
e.ID = aux.EventIDCamel
200+
e.ID = firstSDKEventID(
201+
aux.EventIDSnake,
202+
aux.EventIDCamel,
203+
aux.EventIDUpper,
204+
aux.MessageUUID,
205+
aux.MessageUUIDUpper,
206+
aux.MessageUUIDSnake,
207+
aux.MessageID,
208+
aux.MessageIDUpper,
209+
aux.MessageIDSnake,
210+
e.UUID,
211+
)
197212
}
198213
if e.SessionID == "" {
199214
e.SessionID = aux.SessionIDUpper
@@ -298,6 +313,15 @@ func firstSDKEventString(values ...string) string {
298313
return ""
299314
}
300315

316+
func firstSDKEventID(values ...ID) ID {
317+
for _, value := range values {
318+
if value != "" {
319+
return value
320+
}
321+
}
322+
return ""
323+
}
324+
301325
func firstSDKEventIDPtr(values ...*ID) *ID {
302326
for _, value := range values {
303327
if value != nil && *value != "" {

internal/session/remote_history_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,26 @@ func TestRemoteHistoryTranscriptMessagesAcceptsParentIDAliases(t *testing.T) {
19001900
}
19011901
}
19021902

1903+
func TestRemoteHistoryTranscriptMessagesAcceptsEventMessageIDAliases(t *testing.T) {
1904+
var response sessionEventsResponse
1905+
if err := json.Unmarshal([]byte(`{"events":[
1906+
{"type":"user","messageID":"msg_u1","sessionID":"s_msg","timestamp":"2026-01-01T00:00:01Z","message":{"type":"user","content":[{"type":"text","text":"hi"}]}},
1907+
{"type":"assistant","message_uuid":"msg_a1","sessionID":"s_msg","parentMessageId":"msg_u1","timestamp":"2026-01-01T00:00:02Z","message":{"type":"assistant","content":[{"type":"text","text":"hello"}]}}
1908+
]}`), &response); err != nil {
1909+
t.Fatal(err)
1910+
}
1911+
messages := RemoteHistoryTranscriptMessages(response.Events)
1912+
if len(messages) != 2 || messages[0].UUID != "msg_u1" || messages[1].UUID != "msg_a1" {
1913+
t.Fatalf("messages = %#v", messages)
1914+
}
1915+
if messages[1].ParentUUID == nil || *messages[1].ParentUUID != "msg_u1" {
1916+
t.Fatalf("parent alias = %#v", messages[1].ParentUUID)
1917+
}
1918+
if messages[1].Message == nil || messages[1].Message.ParentUUID == nil || *messages[1].Message.ParentUUID != "msg_u1" {
1919+
t.Fatalf("message parent alias = %#v", messages[1].Message)
1920+
}
1921+
}
1922+
19031923
func TestRemoteHistoryTranscriptMessagesAcceptsEventPayloadAliases(t *testing.T) {
19041924
var response sessionEventsResponse
19051925
if err := json.Unmarshal([]byte(`{"events":[

0 commit comments

Comments
 (0)