Skip to content

Commit fd6b657

Browse files
author
SqlRush
committed
Accept remote history resource aliases
1 parent 17777be commit fd6b657

5 files changed

Lines changed: 60 additions & 2 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ M6 补充:contract `ID` JSON 读取现在接受 JSON number/null,remote hist
7474

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

77+
M6 补充:remote history event-list 现在接受 `value`/`values`/`resources`/`collection` 别名,connection edge 也接受 `resource`/`value` 作为 node payload,覆盖 OData/HAL/resource collection 风格响应。
78+
7779
M6 补充:remote history REST/link 风格分页现在接受 `links`/`_links``next`/`previous`/`prev`/`older` 字符串 URL 或 `{href,url,uri,link}` 对象,并从 `before_id``beforeId``cursor``pageCursor``previousCursor``prevCursor``beforeCursor``olderCursor``startCursor``endCursor` 等 query 参数提取下一页 before-id。
7880

7981
M6 补充:remote history REST/link 风格分页现在也接受 RFC/JSON:API 风格的 `links` 数组,按 `rel`/`relation`/`name`/`type` 中的 `previous`/`prev`/`older`/`next` 选择续抓 URL,并从同一组 before/cursor query 参数提取 before-id。

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
- 本轮补充:remote history pagination 现在接受 `nextPageToken`/`nextToken`/`pageToken`/`continuationToken` 及 snake_case 形式,响应字段和 link URL query 参数都会归一到续抓 before-id。
197197
- 本轮补充:contract `ID` JSON 读取现在接受 JSON number/null,remote history event/message/session/parent ID alias 可继承数字 ID 兼容面并在 transcript materialization 中保留为字符串。
198198
- 本轮补充:remote history response parser 会递归解包 `data.session.events``data.projectSession.eventConnection``conversation``remoteHistory``_embedded` 等 GraphQL/session/HAL wrapper,继续复用 `nodes`/`edges[].node``pageInfo` pagination 解析。
199+
- 本轮补充:remote history event-list 接受 `value`/`values`/`resources`/`collection` 别名,connection edge 也接受 `resource`/`value` 作为 node payload,覆盖 OData/HAL/resource collection 风格响应。
199200
- 本轮补充:transcript resume 的嵌套 content block 接受 `toolUseId`/`toolUseID``isError``cacheControl``cacheReference` 字段别名,并保留 cache edit 的 `cacheReference`
200201
- 本轮补充:transcript resume 的 nested content block `id`/`tool_use_id`/`toolUseId` 现在接受 JSON number,并保留为字符串 tool-use ID。
201202
- 本轮补充:lightweight transcript metadata loader 在 `system`/`compact_boundary` 后清空旧 `marble-origami-commit`/`marble-origami-snapshot` 状态,和 full loader/官方 sessionStorage compact-boundary 语义一致。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ M6 progress now includes:
144144
- `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.
145145
- `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.
146146
- `internal/session`: remote-history parsing now also accepts `eventList`/`event_list`, `sessionEvents`/`session_events`, and connection aliases such as `connection`, `eventConnection`, and `sessionEventsConnection`.
147+
- `internal/session`: remote-history parsing now also accepts `value`, `values`, `resources`, and `collection` event-list aliases, plus `edges[].resource`/`edges[].value` node payload aliases.
147148
- `internal/session`: remote-history pageInfo parsing now accepts previous/older pagination signals such as `hasPrevious`/`hasPreviousPage`, `hasOlder`/`more`, and before-id cursors such as `previousCursor`/`prevCursor`/`beforeCursor`/`olderCursor`.
148149
- `internal/session`: remote-history pagination bool parsing now accepts numeric and yes/no-style bool values in addition to JSON bools and true/false strings.
149150
- `internal/session`: remote-history pagination cursor/id parsing now accepts JSON numbers and preserves them as string cursors for page fields and `edges[].cursor`.

internal/session/remote_history.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ type sessionEventsResponse struct {
5252
Events []contracts.SDKEvent `json:"events"`
5353
Items []contracts.SDKEvent `json:"items"`
5454
Results []contracts.SDKEvent `json:"results"`
55+
Value []contracts.SDKEvent `json:"value"`
56+
Values []contracts.SDKEvent `json:"values"`
57+
Resources []contracts.SDKEvent `json:"resources"`
58+
Collection []contracts.SDKEvent `json:"collection"`
5559
Records []contracts.SDKEvent `json:"records"`
5660
Rows []contracts.SDKEvent `json:"rows"`
5761
Entries []contracts.SDKEvent `json:"entries"`
@@ -140,6 +144,10 @@ func (r *sessionEventsResponse) mergeJSON(data []byte) error {
140144
{name: "events", target: &r.Events},
141145
{name: "items", target: &r.Items},
142146
{name: "results", target: &r.Results},
147+
{name: "value", target: &r.Value},
148+
{name: "values", target: &r.Values},
149+
{name: "resources", target: &r.Resources},
150+
{name: "collection", target: &r.Collection},
143151
{name: "records", target: &r.Records},
144152
{name: "rows", target: &r.Rows},
145153
{name: "entries", target: &r.Entries},
@@ -380,6 +388,18 @@ func (r *sessionEventsResponse) mergeFrom(other sessionEventsResponse) {
380388
if r.Results == nil {
381389
r.Results = other.Results
382390
}
391+
if r.Value == nil {
392+
r.Value = other.Value
393+
}
394+
if r.Values == nil {
395+
r.Values = other.Values
396+
}
397+
if r.Resources == nil {
398+
r.Resources = other.Resources
399+
}
400+
if r.Collection == nil {
401+
r.Collection = other.Collection
402+
}
383403
if r.Records == nil {
384404
r.Records = other.Records
385405
}
@@ -558,7 +578,7 @@ func decodeRemoteHistoryEventArray(name string, data json.RawMessage) ([]contrac
558578
events := make([]contracts.SDKEvent, 0, len(rawEdges))
559579
for index, edge := range rawEdges {
560580
cursor := remoteHistoryStringField(edge, "cursor")
561-
rawEvent := firstRawField(edge, "node", "event", "record", "item")
581+
rawEvent := firstRawField(edge, "node", "event", "record", "item", "resource", "value")
562582
if rawEvent == nil {
563583
rawEvent = edgeJSON(edge)
564584
}
@@ -1038,7 +1058,7 @@ func firstEventList(values ...[]contracts.SDKEvent) []contracts.SDKEvent {
10381058
}
10391059

10401060
func responseEventList(response sessionEventsResponse) []contracts.SDKEvent {
1041-
return firstEventList(response.Data, response.Events, response.Items, response.Results, response.Records, response.Rows, response.Entries, response.Messages, response.History, response.Nodes, response.Edges)
1061+
return firstEventList(response.Data, response.Events, response.Items, response.Results, response.Value, response.Values, response.Resources, response.Collection, response.Records, response.Rows, response.Entries, response.Messages, response.History, response.Nodes, response.Edges)
10421062
}
10431063

10441064
func cloneHeader(header http.Header) http.Header {

internal/session/remote_history_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,40 @@ func TestFetchRemoteHistoryAcceptsConnectionWrappers(t *testing.T) {
650650
}
651651
}
652652

653+
func TestFetchRemoteHistoryAcceptsValueAndResourceAliases(t *testing.T) {
654+
var seen []url.Values
655+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
656+
seen = append(seen, r.URL.Query())
657+
w.Header().Set("Content-Type", "application/json")
658+
switch r.URL.Query().Get("before_id") {
659+
case "":
660+
_, _ = w.Write([]byte(`{"value":[{"type":"status","eventId":"evt_value","session_id":"s","status":"latest"}],"hasNext":true,"nextPageToken":"evt_value"}`))
661+
case "evt_value":
662+
_, _ = w.Write([]byte(`{"history":{"edges":[{"cursor":"evt_resource","resource":{"type":"status","session_id":"s","status":"resource"}}],"pageInfo":{"hasNextPage":true}}}`))
663+
case "evt_resource":
664+
_, _ = w.Write([]byte(`{"resources":[{"type":"status","event_id":"evt_old","session_id":"s","status":"oldest"}],"has_more":false}`))
665+
default:
666+
t.Fatalf("unexpected before_id = %q", r.URL.Query().Get("before_id"))
667+
}
668+
}))
669+
defer server.Close()
670+
671+
authCtx := NewRemoteHistoryAuthContext("s", "token", "", auth.OAuthConfig{BaseAPIURL: server.URL})
672+
events, err := FetchRemoteHistory(context.Background(), server.Client(), authCtx, RemoteHistoryFetchOptions{Limit: 3})
673+
if err != nil {
674+
t.Fatal(err)
675+
}
676+
if !events.Complete || events.Pages != 3 || len(events.Events) != 3 || events.NextBeforeID != "" {
677+
t.Fatalf("events = %#v", events)
678+
}
679+
if events.Events[0].ID != "evt_value" || events.Events[0].Status != "latest" || events.Events[1].ID != "evt_resource" || events.Events[1].Status != "resource" || events.Events[2].ID != "evt_old" || events.Events[2].Status != "oldest" {
680+
t.Fatalf("events = %#v", events.Events)
681+
}
682+
if len(seen) != 3 || seen[1].Get("before_id") != "evt_value" || seen[2].Get("before_id") != "evt_resource" {
683+
t.Fatalf("queries = %#v", seen)
684+
}
685+
}
686+
653687
func TestFetchRemoteHistoryUsesEdgeCursorWhenNodeIDMissing(t *testing.T) {
654688
var seen []url.Values
655689
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)