Skip to content

Commit edcd0df

Browse files
author
SqlRush
committed
Accept nested message parent aliases
1 parent c70a572 commit edcd0df

5 files changed

Lines changed: 45 additions & 9 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
M6 补充:transcript resume 的嵌套 content block 现在接受 `toolUseId`/`toolUseID``isError``cacheControl``cacheReference` 字段别名,并保留 cache edit 的 `cacheReference`
3636

37+
M6 补充:嵌套 contract message 现在接受 `parentUUID``parentId`/`parentID`/`parent_id``parentMessageId`/`parentMessageID`/`parent_message_id` 和 parent-message UUID 别名,transcript/remote history payload 自带 parent alias 时不会丢失嵌套 parent。
38+
3739
M6 补充:remote history GraphQL/connection 分页现在接受 `hasPrevious`/`hasPreviousPage``hasOlder`/`more` 继续分页标记,以及 `previousCursor`/`prevCursor`/`beforeCursor`/`olderCursor` 等 before-id cursor 别名,避免只返回第一页历史。
3840

3941
M6 补充:remote history response parser 现在会递归解包 `data.session.events``data.projectSession.eventConnection``conversation``remoteHistory` 等 GraphQL/session wrapper,继续复用 `nodes`/`edges[].node``pageInfo` pagination 解析。

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ test/parity/ # golden tests against TS/official behavior
196196
- 本轮补充:lightweight transcript metadata loader 在 `system`/`compact_boundary` 后清空旧 `marble-origami-commit`/`marble-origami-snapshot` 状态,和 full loader/官方 sessionStorage compact-boundary 语义一致。
197197
- 本轮补充:transcript metadata loader 接受 `sessionID`/`session` 作为 session-scoped metadata ID 别名,并容忍 `prNumber``timeSavedMs``lastSpawnTokens` 等计数字段使用数字字符串。
198198
- 本轮补充:transcript message 和嵌套 contract message 接受顶层 `sessionID` 作为 session id 别名,`LoadTranscript``LoadTranscriptIndex` 和 indexed resume 会保留该 session id(覆盖测试:`TestLoadTranscriptAcceptsSessionIDUpperAlias`)。
199+
- 本轮补充:嵌套 contract message 接受 `parentUUID``parentId`/`parentID`/`parent_id``parentMessageId`/`parentMessageID`/`parent_message_id` 和 parent-message UUID 别名,transcript/remote history payload 自带 parent alias 时不会丢失嵌套 parent。
199200
- 本轮补充:remote history `SDKEvent` 解码接受顶层 `sessionID` 作为事件 session id 别名,materialize transcript 时会填充 record 与嵌套 message 的 session id(覆盖测试:`TestRemoteHistoryTranscriptMessagesAcceptsSessionIDUpperAlias`)。
200201
- 本轮补充:remote history `SDKEvent` 解码接受 `parentUUID``parentId`/`parentID`/`parent_id``parentMessageId`/`parentMessageID`/`parent_message_id` parent aliases,materialize transcript 时会保留 parent chain(覆盖测试:`TestRemoteHistoryTranscriptMessagesAcceptsParentIDAliases`)。
201202
- 本轮补充:memory 层补齐官方 `memoryAge`/freshness note 语义,`ReadDocumentsWithOptions` 可为超过 1 天的 memory 文档前缀 system-reminder,提示模型把 memory 当作 point-in-time observation 并核对当前代码。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ M6 progress now includes:
130130
- `internal/session`: transcript full loader and line-offset index now accept top-level record UUID aliases such as `messageUuid`, `messageUUID`, `message_id`, `messageId`, and `id`, plus parent message UUID/ID aliases for progress bridge and indexed resume paths.
131131
- `internal/session`: transcript full loader and line-offset index now accept entry type aliases such as `role`, `entry_type`, and `messageType`, plus `createdAt`/`created_at` timestamp aliases.
132132
- `internal/contracts`/`internal/session`: transcript resume now accepts nested content block aliases for `toolUseId`/`toolUseID`, `isError`, `cacheControl`, `cacheReference`, and cache edit `cacheReference`.
133+
- `internal/contracts`/`internal/session`: nested contract messages now accept parent aliases such as `parentUUID`, `parentId`/`parentID`/`parent_id`, `parentMessageId`/`parentMessageID`/`parent_message_id`, and parent-message UUID aliases, preserving payload-supplied parents in transcript and remote-history resume paths.
133134
- `internal/session`: remote-history parsing now also accepts connection-style `history`/`messages` wrappers with `nodes`/`edges[].node` event lists and `pageInfo`/`page_info` `hasNextPage`/`endCursor`/`startCursor` pagination aliases.
134135
- `internal/session`: remote-history connection edges now use `edges[].cursor` as the event cursor when the nested node lacks an event ID, preserving pagination even when pageInfo omits a cursor.
135136
- `internal/session`: remote-history parsing now also accepts `eventList`/`event_list`, `sessionEvents`/`session_events`, and connection aliases such as `connection`, `eventConnection`, and `sessionEventsConnection`.

internal/contracts/messages.go

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,23 @@ func (m *Message) UnmarshalJSON(data []byte) error {
164164
type MessageJSON Message
165165
var aux struct {
166166
*MessageJSON
167-
ParentUUIDSnake *ID `json:"parent_uuid"`
168-
SessionIDUpper ID `json:"sessionID"`
169-
SessionIDSnake ID `json:"session_id"`
170-
SessionUUID ID `json:"sessionUuid"`
171-
SessionUUIDUpper ID `json:"sessionUUID"`
172-
SessionUUIDSnake ID `json:"session_uuid"`
173-
IsMetaSnake *bool `json:"is_meta"`
167+
ParentUUIDUpper *ID `json:"parentUUID"`
168+
ParentUUIDSnake *ID `json:"parent_uuid"`
169+
ParentID *ID `json:"parentId"`
170+
ParentIDUpper *ID `json:"parentID"`
171+
ParentIDSnake *ID `json:"parent_id"`
172+
ParentMessageID *ID `json:"parentMessageId"`
173+
ParentMessageIDUpper *ID `json:"parentMessageID"`
174+
ParentMessageIDSnake *ID `json:"parent_message_id"`
175+
ParentMessageUUID *ID `json:"parentMessageUuid"`
176+
ParentMessageUUIDUpper *ID `json:"parentMessageUUID"`
177+
ParentMessageUUIDSnake *ID `json:"parent_message_uuid"`
178+
SessionIDUpper ID `json:"sessionID"`
179+
SessionIDSnake ID `json:"session_id"`
180+
SessionUUID ID `json:"sessionUuid"`
181+
SessionUUIDUpper ID `json:"sessionUUID"`
182+
SessionUUIDSnake ID `json:"session_uuid"`
183+
IsMetaSnake *bool `json:"is_meta"`
174184
}
175185
base := MessageJSON{}
176186
aux.MessageJSON = &base
@@ -179,7 +189,19 @@ func (m *Message) UnmarshalJSON(data []byte) error {
179189
}
180190
*m = Message(base)
181191
if m.ParentUUID == nil {
182-
m.ParentUUID = aux.ParentUUIDSnake
192+
m.ParentUUID = firstMessageIDPtr(
193+
aux.ParentUUIDUpper,
194+
aux.ParentUUIDSnake,
195+
aux.ParentID,
196+
aux.ParentIDUpper,
197+
aux.ParentIDSnake,
198+
aux.ParentMessageID,
199+
aux.ParentMessageIDUpper,
200+
aux.ParentMessageIDSnake,
201+
aux.ParentMessageUUID,
202+
aux.ParentMessageUUIDUpper,
203+
aux.ParentMessageUUIDSnake,
204+
)
183205
}
184206
if m.SessionID == "" {
185207
m.SessionID = aux.SessionIDUpper
@@ -202,6 +224,16 @@ func (m *Message) UnmarshalJSON(data []byte) error {
202224
return nil
203225
}
204226

227+
func firstMessageIDPtr(values ...*ID) *ID {
228+
for _, value := range values {
229+
if value != nil && *value != "" {
230+
cloned := *value
231+
return &cloned
232+
}
233+
}
234+
return nil
235+
}
236+
205237
type APIMessage struct {
206238
Role string `json:"role"`
207239
Content []ContentBlock `json:"content"`

internal/session/transcript_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestLoadTranscriptAcceptsMessageFieldAliases(t *testing.T) {
3535
path := writeTranscript(t, []string{
3636
`{"type":"user","uuid":"u1","session_id":"sess_1","timestamp":"2026-01-01T00:00:00Z","message":{"type":"user","session_id":"sess_1","content":[{"type":"text","text":"hi"}]}}`,
3737
`{"type":"progress","uuid":"p1","parent_uuid":"u1"}`,
38-
`{"type":"assistant","uuid":"a1","parent_uuid":"p1","logical_parent_uuid":"u1","session_id":"sess_1","is_sidechain":true,"agent_id":"agent_alias","timestamp":"2026-01-01T00:00:01Z","message":{"id":"msg_1","type":"assistant","parent_uuid":"u1","session_id":"sess_1","is_meta":true,"content":[{"type":"text","text":"done"}]}}`,
38+
`{"type":"assistant","uuid":"a1","parent_uuid":"p1","logical_parent_uuid":"u1","session_id":"sess_1","is_sidechain":true,"agent_id":"agent_alias","timestamp":"2026-01-01T00:00:01Z","message":{"id":"msg_1","type":"assistant","parentMessageID":"u1","session_id":"sess_1","is_meta":true,"content":[{"type":"text","text":"done"}]}}`,
3939
})
4040

4141
transcript, err := LoadTranscript(path)

0 commit comments

Comments
 (0)