Skip to content

Commit 3f4dddc

Browse files
author
SqlRush
committed
Accept remote history generic wrappers
1 parent 60d00e9 commit 3f4dddc

5 files changed

Lines changed: 46 additions & 0 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ M6 补充:remote history response parser 现在会递归解包 `data.session.e
7878

7979
M6 补充:remote history event-list 现在接受 `value`/`values`/`resources`/`collection` 别名,connection edge 也接受 `resource`/`value` 作为 node payload,覆盖 OData/HAL/resource collection 风格响应。
8080

81+
M6 补充:remote history response parser 现在会解包 `payload`/`response`/`result`/`body` 等通用响应外壳,外壳内的 event list、pagination、links 会继续递归解析。
82+
8183
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。
8284

8385
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
@@ -198,6 +198,7 @@ test/parity/ # golden tests against TS/official behavior
198198
- 本轮补充:contract `ID` JSON 读取现在接受 JSON number/null,remote history event/message/session/parent ID alias 可继承数字 ID 兼容面并在 transcript materialization 中保留为字符串。
199199
- 本轮补充:remote history response parser 会递归解包 `data.session.events``data.projectSession.eventConnection``conversation``remoteHistory``_embedded` 等 GraphQL/session/HAL wrapper,继续复用 `nodes`/`edges[].node``pageInfo` pagination 解析。
200200
- 本轮补充:remote history event-list 接受 `value`/`values`/`resources`/`collection` 别名,connection edge 也接受 `resource`/`value` 作为 node payload,覆盖 OData/HAL/resource collection 风格响应。
201+
- 本轮补充:remote history response parser 会解包 `payload`/`response`/`result`/`body` 等通用响应外壳,外壳内的 event list、pagination、links 会继续递归解析。
201202
- 本轮补充:transcript resume 的嵌套 content block 接受 `toolUseId`/`toolUseID``isError``cacheControl``cacheReference` 字段别名,并保留 cache edit 的 `cacheReference`
202203
- 本轮补充:transcript resume 的 nested content block `id`/`tool_use_id`/`toolUseId` 现在接受 JSON number,并保留为字符串 tool-use ID。
203204
- 本轮补充: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
@@ -145,6 +145,7 @@ M6 progress now includes:
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`.
147147
- `internal/session`: remote-history parsing now also accepts `value`, `values`, `resources`, and `collection` event-list aliases, plus `edges[].resource`/`edges[].value` node payload aliases.
148+
- `internal/session`: remote-history parsing now unwraps generic response envelopes such as `payload`, `response`, `result`, and `body` when they contain event lists and pagination fields.
148149
- `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`.
149150
- `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.
150151
- `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: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ func (r *sessionEventsResponse) mergeJSON(data []byte) error {
148148
{name: "values", target: &r.Values},
149149
{name: "resources", target: &r.Resources},
150150
{name: "collection", target: &r.Collection},
151+
{name: "payload", target: &r.Events},
152+
{name: "response", target: &r.Events},
153+
{name: "result", target: &r.Results},
154+
{name: "body", target: &r.Events},
151155
{name: "records", target: &r.Records},
152156
{name: "rows", target: &r.Rows},
153157
{name: "entries", target: &r.Entries},

internal/session/remote_history_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,44 @@ func TestFetchRemoteHistoryAcceptsValueAndResourceAliases(t *testing.T) {
718718
}
719719
}
720720

721+
func TestFetchRemoteHistoryAcceptsGenericResponseWrappers(t *testing.T) {
722+
var seen []url.Values
723+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
724+
seen = append(seen, r.URL.Query())
725+
w.Header().Set("Content-Type", "application/json")
726+
switch r.URL.Query().Get("before_id") {
727+
case "":
728+
_, _ = w.Write([]byte(`{"payload":{"events":[{"type":"status","event_id":"evt_payload","session_id":"s","status":"payload"}],"hasMore":true,"nextCursor":"evt_payload"}}`))
729+
case "evt_payload":
730+
_, _ = w.Write([]byte(`{"response":{"items":[{"type":"status","event_id":"evt_response","session_id":"s","status":"response"}],"paging":{"more":true,"olderCursor":"evt_response"}}}`))
731+
case "evt_response":
732+
_, _ = w.Write([]byte(`{"result":{"value":[{"type":"status","event_id":"evt_result","session_id":"s","status":"result"}],"@odata.nextLink":"/v1/sessions/s/events?skipToken=evt_body"}}`))
733+
case "evt_body":
734+
_, _ = w.Write([]byte(`{"body":{"resources":[{"type":"status","event_id":"evt_body","session_id":"s","status":"body"}],"has_more":false}}`))
735+
default:
736+
t.Fatalf("unexpected before_id = %q", r.URL.Query().Get("before_id"))
737+
}
738+
}))
739+
defer server.Close()
740+
741+
authCtx := NewRemoteHistoryAuthContext("s", "token", "", auth.OAuthConfig{BaseAPIURL: server.URL})
742+
events, err := FetchRemoteHistory(context.Background(), server.Client(), authCtx, RemoteHistoryFetchOptions{Limit: 4})
743+
if err != nil {
744+
t.Fatal(err)
745+
}
746+
if !events.Complete || events.Pages != 4 || len(events.Events) != 4 || events.NextBeforeID != "" {
747+
t.Fatalf("events = %#v", events)
748+
}
749+
for index, want := range []string{"payload", "response", "result", "body"} {
750+
if events.Events[index].Status != want {
751+
t.Fatalf("event %d = %#v, want status %q", index, events.Events[index], want)
752+
}
753+
}
754+
if len(seen) != 4 || seen[1].Get("before_id") != "evt_payload" || seen[2].Get("before_id") != "evt_response" || seen[3].Get("before_id") != "evt_body" {
755+
t.Fatalf("queries = %#v", seen)
756+
}
757+
}
758+
721759
func TestFetchRemoteHistoryUsesEdgeCursorWhenNodeIDMissing(t *testing.T) {
722760
var seen []url.Values
723761
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)