Skip to content

Commit a9241b6

Browse files
author
SqlRush
committed
Accept remote history HAL links
1 parent 2c0b38b commit a9241b6

5 files changed

Lines changed: 39 additions & 5 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ M6 补充:contract `ID` JSON 读取现在接受 JSON number/null,remote hist
7474

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

77-
M6 补充:remote history REST/link 风格分页现在接受 `links.next`/`links.previous`/`links.prev`/`links.older` 的字符串 URL 或 `{href,url,uri,link}` 对象,并从 `before_id``beforeId``cursor``pageCursor``previousCursor``prevCursor``beforeCursor``olderCursor``startCursor``endCursor` 等 query 参数提取下一页 before-id。
77+
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。
7878

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ test/parity/ # golden tests against TS/official behavior
297297
- 本轮补充:prompt history `LogEntry` 读取接受 `sessionID`/`session`/`sessionUuid`/`sessionUUID`/`session_uuid` 作为 session id 别名,current-session-first 历史排序不会因 session 字段拼写不同而失效。
298298
- 本轮补充:REPL message restore 现在可从用户消息 content blocks、`imagePasteIds` 和 pasted-content metadata 重建 prompt text、`[Image #N]` 引用和 base64 image pasted contents。
299299
- 本轮补充:Ctrl-S prompt stash 现在保存/恢复 prompt text、cursor 和 pasted-content metadata,空 prompt 下再次触发会恢复 stash,贴近官方 `chat:stash`
300-
- 本轮补充:remote history REST/link 风格分页接受 `links.next`/`links.previous`/`links.prev`/`links.older` 的字符串 URL 或 `{href,url,uri,link}` 对象,并从 `before_id``beforeId``cursor``pageCursor``previousCursor``prevCursor``beforeCursor``olderCursor``startCursor``endCursor` 等 query 参数提取续抓 before-id。
300+
- 本轮补充: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。
301301
- 本轮补充:remote history REST/link 风格分页也接受 RFC/JSON:API 风格 `links` 数组,按 `rel`/`relation`/`name`/`type` 中的 `previous`/`prev`/`older`/`next` 选择 continuation URL。
302302
- 本轮补充:remote history HTTP `Link` header 分页接受 `rel="previous"`/`prev`/`older`/`next` URL,并从同一组 before/cursor query 参数提取续抓 before-id。
303303
- 本轮补充:sidechain/subagent state loader 接受 `subagent_start`/`agent_start`/`task_start``sidechain_end`/`subagent_finish`/`agent_finish`/`task_summary` 等 subtype 别名,并归一化 `active`/`success`/`canceled`/`error` 等状态别名。

docs/first-second-parity-audit.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ M6 progress now includes:
150150
- `internal/session`: remote-history pagination now accepts token aliases such as `nextPageToken`, `nextToken`, `pageToken`, and `continuationToken` in response fields and link query parameters.
151151
- `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.
152152
- `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.
153-
- `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.
153+
- `internal/session`: remote-history link pagination now accepts `links`/`_links` `next`/`previous`/`prev`/`older` string URLs or `{href,url,uri,link}` objects and extracts before/cursor query parameters for continuation.
154154
- `internal/session`: remote-history link pagination now also accepts RFC/JSON:API-style `links` arrays with `rel` values such as `previous`, `prev`, `older`, and `next`.
155155
- `internal/session`: remote-history pagination now also accepts HTTP `Link` header URLs with `previous`/`prev`/`older`/`next` rels as continuation cursor fallbacks.
156156
- `internal/session`: sidechain state loading now accepts legacy subagent/agent/task start and finish subtype aliases, broader sidechain/subagent ID and type fields, summary aliases, and common running/completed/cancelled/failed status aliases.

internal/session/remote_history.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,15 @@ func (r *sessionEventsResponse) mergeJSON(data []byte) error {
168168
}
169169
}
170170
for _, name := range []string{
171-
"page", "pagination", "page_info", "pageInfo", "paging", "links", "meta", "metadata",
171+
"page", "pagination", "page_info", "pageInfo", "paging", "links", "_links", "meta", "metadata",
172172
"session", "project_session", "projectSession", "conversation", "remote_history", "remoteHistory",
173173
"event_page", "eventPage", "session_history", "sessionHistory",
174174
} {
175175
value, ok := raw[name]
176176
if !ok {
177177
continue
178178
}
179-
if name == "links" {
179+
if name == "links" || name == "_links" {
180180
if err := r.mergeLinksField(value); err != nil {
181181
return err
182182
}

internal/session/remote_history_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,40 @@ func TestFetchRemoteHistoryAcceptsLinkArrayCursors(t *testing.T) {
432432
}
433433
}
434434

435+
func TestFetchRemoteHistoryAcceptsHALLinkCursors(t *testing.T) {
436+
var seen []url.Values
437+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
438+
seen = append(seen, r.URL.Query())
439+
w.Header().Set("Content-Type", "application/json")
440+
switch r.URL.Query().Get("before_id") {
441+
case "":
442+
_, _ = w.Write([]byte(`{"data":[{"type":"status","session_id":"s","status":"latest"}],"_links":{"self":{"href":"/v1/sessions/s/events?cursor=self"},"prev":{"href":"/v1/sessions/s/events?before_id=evt_hal"}}}`))
443+
case "evt_hal":
444+
_, _ = w.Write([]byte(`{"data":[{"type":"status","session_id":"s","status":"older"}],"_links":{"older":{"href":"/v1/sessions/s/events?pageToken=evt_hal_old"}}}`))
445+
case "evt_hal_old":
446+
_, _ = w.Write([]byte(`{"data":[{"type":"status","session_id":"s","status":"oldest"}],"_links":{}}`))
447+
default:
448+
t.Fatalf("unexpected before_id = %q", r.URL.Query().Get("before_id"))
449+
}
450+
}))
451+
defer server.Close()
452+
453+
authCtx := NewRemoteHistoryAuthContext("s", "token", "", auth.OAuthConfig{BaseAPIURL: server.URL})
454+
events, err := FetchRemoteHistory(context.Background(), server.Client(), authCtx, RemoteHistoryFetchOptions{Limit: 3})
455+
if err != nil {
456+
t.Fatal(err)
457+
}
458+
if !events.Complete || events.Pages != 3 || len(events.Events) != 3 || events.NextBeforeID != "" {
459+
t.Fatalf("events = %#v", events)
460+
}
461+
if events.Events[0].Status != "latest" || events.Events[1].Status != "older" || events.Events[2].Status != "oldest" {
462+
t.Fatalf("events = %#v", events.Events)
463+
}
464+
if len(seen) != 3 || seen[1].Get("before_id") != "evt_hal" || seen[2].Get("before_id") != "evt_hal_old" {
465+
t.Fatalf("queries = %#v", seen)
466+
}
467+
}
468+
435469
func TestFetchRemoteHistoryAcceptsLinkHeaderCursors(t *testing.T) {
436470
var seen []url.Values
437471
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)