Skip to content

Commit 2c0b38b

Browse files
author
SqlRush
committed
Accept remote history pagination token aliases
1 parent 14b4cac commit 2c0b38b

5 files changed

Lines changed: 54 additions & 0 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ M6 补充:remote history pagination bool 字段现在除 JSON bool 和 `true`/
6868

6969
M6 补充:remote history pagination cursor/id 字段现在接受 JSON number 并原样转成字符串,覆盖 `next_cursor` 等 page 字段和 `edges[].cursor` 的数字形态。
7070

71+
M6 补充:remote history pagination 现在接受 `nextPageToken`/`nextToken`/`pageToken`/`continuationToken` 及 snake_case 形式,响应字段和 link URL query 参数都会归一到续抓 before-id。
72+
7173
M6 补充:contract `ID` JSON 读取现在接受 JSON number/null,remote history event/message/session/parent ID alias 可继承数字 ID 兼容面并在 transcript materialization 中保留为字符串。
7274

7375
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
@@ -193,6 +193,7 @@ test/parity/ # golden tests against TS/official behavior
193193
- 本轮补充:remote history connection/pageInfo 解析接受 `hasPrevious`/`hasPreviousPage``hasOlder`/`more` 继续分页标记,以及 `previousCursor`/`prevCursor`/`beforeCursor`/`olderCursor` before-id cursor 别名,覆盖 GraphQL 向更旧事件翻页的响应形态。
194194
- 本轮补充:remote history pagination bool 字段除 JSON bool 和 `true`/`false` 字符串外,也接受 `1`/`0``yes`/`no``on`/`off` 等数值/字符串布尔形态,避免 wrapper/pageInfo 中的非严格布尔值中断分页。
195195
- 本轮补充:remote history pagination cursor/id 字段现在接受 JSON number 并原样转成字符串,覆盖 `next_cursor` 等 page 字段和 `edges[].cursor` 的数字形态。
196+
- 本轮补充:remote history pagination 现在接受 `nextPageToken`/`nextToken`/`pageToken`/`continuationToken` 及 snake_case 形式,响应字段和 link URL query 参数都会归一到续抓 before-id。
196197
- 本轮补充:contract `ID` JSON 读取现在接受 JSON number/null,remote history event/message/session/parent ID alias 可继承数字 ID 兼容面并在 transcript materialization 中保留为字符串。
197198
- 本轮补充:remote history response parser 会递归解包 `data.session.events``data.projectSession.eventConnection``conversation``remoteHistory` 等 GraphQL/session wrapper,继续复用 `nodes`/`edges[].node``pageInfo` pagination 解析。
198199
- 本轮补充:transcript resume 的嵌套 content block 接受 `toolUseId`/`toolUseID``isError``cacheControl``cacheReference` 字段别名,并保留 cache edit 的 `cacheReference`

docs/first-second-parity-audit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ M6 progress now includes:
147147
- `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`.
148148
- `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.
149149
- `internal/session`: remote-history pagination cursor/id parsing now accepts JSON numbers and preserves them as string cursors for page fields and `edges[].cursor`.
150+
- `internal/session`: remote-history pagination now accepts token aliases such as `nextPageToken`, `nextToken`, `pageToken`, and `continuationToken` in response fields and link query parameters.
150151
- `internal/contracts`: ID JSON decoding now accepts JSON numbers/null so remote-history event, message, session, and parent ID aliases can preserve numeric IDs as strings during transcript materialization.
151152
- `internal/session`: remote-history response parsing now recursively unwraps GraphQL/session containers such as `data.session.events`, `data.projectSession.eventConnection`, `conversation`, and `remoteHistory` before applying `nodes`/`edges[].node` event-list and `pageInfo` pagination parsing.
152153
- `internal/session`: remote-history link pagination now accepts `links.next`/`links.previous`/`links.prev`/`links.older` string URLs or `{href,url,uri,link}` objects and extracts before/cursor query parameters for continuation.

internal/session/remote_history.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,14 @@ func (r *sessionEventsResponse) mergeScalarFields(raw map[string]json.RawMessage
239239
{name: "nextBeforeId", target: &r.NextBeforeIDCamel},
240240
{name: "next_cursor", target: &r.NextCursor},
241241
{name: "nextCursor", target: &r.NextCursorCamel},
242+
{name: "next_page_token", target: &r.NextCursor},
243+
{name: "nextPageToken", target: &r.NextCursorCamel},
244+
{name: "next_token", target: &r.NextCursor},
245+
{name: "nextToken", target: &r.NextCursorCamel},
246+
{name: "page_token", target: &r.Cursor},
247+
{name: "pageToken", target: &r.CursorCamel},
248+
{name: "continuation_token", target: &r.Cursor},
249+
{name: "continuationToken", target: &r.CursorCamel},
242250
{name: "end_cursor", target: &r.EndCursor},
243251
{name: "endCursor", target: &r.EndCursorCamel},
244252
{name: "start_cursor", target: &r.StartCursor},
@@ -927,6 +935,14 @@ func remoteHistoryLinkCursor(link string) string {
927935
query.Get("nextBeforeId"),
928936
query.Get("cursor"),
929937
query.Get("pageCursor"),
938+
query.Get("next_page_token"),
939+
query.Get("nextPageToken"),
940+
query.Get("next_token"),
941+
query.Get("nextToken"),
942+
query.Get("page_token"),
943+
query.Get("pageToken"),
944+
query.Get("continuation_token"),
945+
query.Get("continuationToken"),
930946
query.Get("previous_cursor"),
931947
query.Get("previousCursor"),
932948
query.Get("prev_cursor"),

internal/session/remote_history_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,40 @@ func TestFetchRemoteHistoryAcceptsNumericCursorFields(t *testing.T) {
266266
}
267267
}
268268

269+
func TestFetchRemoteHistoryAcceptsPaginationTokenAliases(t *testing.T) {
270+
var seen []url.Values
271+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
272+
seen = append(seen, r.URL.Query())
273+
w.Header().Set("Content-Type", "application/json")
274+
switch r.URL.Query().Get("before_id") {
275+
case "":
276+
_, _ = w.Write([]byte(`{"data":[{"type":"status","session_id":"s","status":"latest"}],"hasNext":true,"nextPageToken":"evt_token"}`))
277+
case "evt_token":
278+
_, _ = w.Write([]byte(`{"data":[{"type":"status","session_id":"s","status":"older"}],"links":{"older":"/v1/sessions/s/events?continuationToken=evt_continuation"}}`))
279+
case "evt_continuation":
280+
_, _ = w.Write([]byte(`{"data":[{"type":"status","session_id":"s","status":"oldest"}],"has_more":false,"pageToken":"ignored_when_complete"}`))
281+
default:
282+
t.Fatalf("unexpected before_id = %q", r.URL.Query().Get("before_id"))
283+
}
284+
}))
285+
defer server.Close()
286+
287+
authCtx := NewRemoteHistoryAuthContext("s", "token", "", auth.OAuthConfig{BaseAPIURL: server.URL})
288+
events, err := FetchRemoteHistory(context.Background(), server.Client(), authCtx, RemoteHistoryFetchOptions{Limit: 3})
289+
if err != nil {
290+
t.Fatal(err)
291+
}
292+
if !events.Complete || events.Pages != 3 || len(events.Events) != 3 || events.NextBeforeID != "" {
293+
t.Fatalf("events = %#v", events)
294+
}
295+
if events.Events[0].Status != "latest" || events.Events[1].Status != "older" || events.Events[2].Status != "oldest" {
296+
t.Fatalf("events = %#v", events.Events)
297+
}
298+
if len(seen) != 3 || seen[1].Get("before_id") != "evt_token" || seen[2].Get("before_id") != "evt_continuation" {
299+
t.Fatalf("queries = %#v", seen)
300+
}
301+
}
302+
269303
func TestFetchRemoteHistoryAcceptsWrappedDataPageFields(t *testing.T) {
270304
var seen []url.Values
271305
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)