Skip to content

Commit a44b069

Browse files
committed
feat(session): add ts_before and breakpoint params to Session.messages API
Add optional parameters to Session.messages() for loading older messages: - ts_before: filter to messages created before this timestamp - breakpoint: stop at first compaction summary when true This is a foundational API enhancement that enables clients to implement pagination and history loading without breaking existing functionality.
1 parent e8357a8 commit a44b069

File tree

7 files changed

+96
-166
lines changed

7 files changed

+96
-166
lines changed

packages/opencode/src/server/routes/session.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,13 +567,17 @@ export const SessionRoutes = lazy(() =>
567567
"query",
568568
z.object({
569569
limit: z.coerce.number().optional(),
570+
ts_before: z.coerce.number().optional(),
571+
breakpoint: z.coerce.boolean().optional(),
570572
}),
571573
),
572574
async (c) => {
573575
const query = c.req.valid("query")
574576
const messages = await Session.messages({
575577
sessionID: c.req.valid("param").sessionID,
576578
limit: query.limit,
579+
ts_before: query.ts_before,
580+
breakpoint: query.breakpoint,
577581
})
578582
return c.json(messages)
579583
},

packages/opencode/src/session/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,16 @@ export namespace Session {
293293
z.object({
294294
sessionID: Identifier.schema("session"),
295295
limit: z.number().optional(),
296+
ts_before: z.number().optional(),
297+
breakpoint: z.boolean().optional(),
296298
}),
297299
async (input) => {
298300
const result = [] as MessageV2.WithParts[]
299301
for await (const msg of MessageV2.stream(input.sessionID)) {
302+
if (input.ts_before && msg.info.time.created >= input.ts_before) continue
300303
if (input.limit && result.length >= input.limit) break
301304
result.push(msg)
305+
if (input.ts_before && input.breakpoint && msg.parts.some((p) => p.type === "compaction")) break
302306
}
303307
result.reverse()
304308
return result

packages/sdk/js/src/v2/gen/client/client.gen.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,10 @@ export const createClient = (config: Config = {}): Client => {
162162
case "arrayBuffer":
163163
case "blob":
164164
case "formData":
165+
case "json":
165166
case "text":
166167
data = await response[parseAs]()
167168
break
168-
case "json": {
169-
// Some servers return 200 with no Content-Length and empty body.
170-
// response.json() would throw; read as text and parse if non-empty.
171-
const text = await response.text()
172-
data = text ? JSON.parse(text) : {}
173-
break
174-
}
175169
case "stream":
176170
return opts.responseStyle === "data"
177171
? response.body
@@ -250,7 +244,6 @@ export const createClient = (config: Config = {}): Client => {
250244
}
251245
return request
252246
},
253-
serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined,
254247
url,
255248
})
256249
}

packages/sdk/js/src/v2/gen/core/serverSentEvents.gen.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,6 @@ export const createSseClient = <TData = unknown>({
151151
const { done, value } = await reader.read()
152152
if (done) break
153153
buffer += value
154-
// Normalize line endings: CRLF -> LF, then CR -> LF
155-
buffer = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n")
156154

157155
const chunks = buffer.split("\n\n")
158156
buffer = chunks.pop() ?? ""

packages/sdk/js/src/v2/gen/sdk.gen.ts

Lines changed: 71 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
AppLogErrors,
99
AppLogResponses,
1010
AppSkillsResponses,
11-
Auth as Auth3,
11+
Auth as Auth2,
1212
AuthSetErrors,
1313
AuthSetResponses,
1414
CommandListResponses,
@@ -731,10 +731,7 @@ export class Resource extends HeyApiClient {
731731
}
732732

733733
export class Experimental extends HeyApiClient {
734-
private _resource?: Resource
735-
get resource(): Resource {
736-
return (this._resource ??= new Resource({ client: this.client }))
737-
}
734+
resource = new Resource({ client: this.client })
738735
}
739736

740737
export class Session extends HeyApiClient {
@@ -1244,6 +1241,8 @@ export class Session extends HeyApiClient {
12441241
sessionID: string
12451242
directory?: string
12461243
limit?: number
1244+
ts_before?: number
1245+
breakpoint?: boolean
12471246
},
12481247
options?: Options<never, ThrowOnError>,
12491248
) {
@@ -1255,6 +1254,8 @@ export class Session extends HeyApiClient {
12551254
{ in: "path", key: "sessionID" },
12561255
{ in: "query", key: "directory" },
12571256
{ in: "query", key: "limit" },
1257+
{ in: "query", key: "ts_before" },
1258+
{ in: "query", key: "breakpoint" },
12581259
],
12591260
},
12601261
],
@@ -1967,10 +1968,7 @@ export class Provider extends HeyApiClient {
19671968
})
19681969
}
19691970

1970-
private _oauth?: Oauth
1971-
get oauth(): Oauth {
1972-
return (this._oauth ??= new Oauth({ client: this.client }))
1973-
}
1971+
oauth = new Oauth({ client: this.client })
19741972
}
19751973

19761974
export class Find extends HeyApiClient {
@@ -2281,6 +2279,43 @@ export class Auth extends HeyApiClient {
22812279
},
22822280
)
22832281
}
2282+
2283+
/**
2284+
* Set auth credentials
2285+
*
2286+
* Set authentication credentials
2287+
*/
2288+
public set<ThrowOnError extends boolean = false>(
2289+
parameters: {
2290+
providerID: string
2291+
directory?: string
2292+
auth?: Auth2
2293+
},
2294+
options?: Options<never, ThrowOnError>,
2295+
) {
2296+
const params = buildClientParams(
2297+
[parameters],
2298+
[
2299+
{
2300+
args: [
2301+
{ in: "path", key: "providerID" },
2302+
{ in: "query", key: "directory" },
2303+
{ key: "auth", map: "body" },
2304+
],
2305+
},
2306+
],
2307+
)
2308+
return (options?.client ?? this.client).put<AuthSetResponses, AuthSetErrors, ThrowOnError>({
2309+
url: "/auth/{providerID}",
2310+
...options,
2311+
...params,
2312+
headers: {
2313+
"Content-Type": "application/json",
2314+
...options?.headers,
2315+
...params.headers,
2316+
},
2317+
})
2318+
}
22842319
}
22852320

22862321
export class Mcp extends HeyApiClient {
@@ -2396,10 +2431,7 @@ export class Mcp extends HeyApiClient {
23962431
})
23972432
}
23982433

2399-
private _auth?: Auth
2400-
get auth(): Auth {
2401-
return (this._auth ??= new Auth({ client: this.client }))
2402-
}
2434+
auth = new Auth({ client: this.client })
24032435
}
24042436

24052437
export class Control extends HeyApiClient {
@@ -2734,10 +2766,7 @@ export class Tui extends HeyApiClient {
27342766
})
27352767
}
27362768

2737-
private _control?: Control
2738-
get control(): Control {
2739-
return (this._control ??= new Control({ client: this.client }))
2740-
}
2769+
control = new Control({ client: this.client })
27412770
}
27422771

27432772
export class Instance extends HeyApiClient {
@@ -2949,45 +2978,6 @@ export class Formatter extends HeyApiClient {
29492978
}
29502979
}
29512980

2952-
export class Auth2 extends HeyApiClient {
2953-
/**
2954-
* Set auth credentials
2955-
*
2956-
* Set authentication credentials
2957-
*/
2958-
public set<ThrowOnError extends boolean = false>(
2959-
parameters: {
2960-
providerID: string
2961-
directory?: string
2962-
auth?: Auth3
2963-
},
2964-
options?: Options<never, ThrowOnError>,
2965-
) {
2966-
const params = buildClientParams(
2967-
[parameters],
2968-
[
2969-
{
2970-
args: [
2971-
{ in: "path", key: "providerID" },
2972-
{ in: "query", key: "directory" },
2973-
{ key: "auth", map: "body" },
2974-
],
2975-
},
2976-
],
2977-
)
2978-
return (options?.client ?? this.client).put<AuthSetResponses, AuthSetErrors, ThrowOnError>({
2979-
url: "/auth/{providerID}",
2980-
...options,
2981-
...params,
2982-
headers: {
2983-
"Content-Type": "application/json",
2984-
...options?.headers,
2985-
...params.headers,
2986-
},
2987-
})
2988-
}
2989-
}
2990-
29912981
export class Event extends HeyApiClient {
29922982
/**
29932983
* Subscribe to events
@@ -3017,128 +3007,53 @@ export class OpencodeClient extends HeyApiClient {
30173007
OpencodeClient.__registry.set(this, args?.key)
30183008
}
30193009

3020-
private _global?: Global
3021-
get global(): Global {
3022-
return (this._global ??= new Global({ client: this.client }))
3023-
}
3010+
global = new Global({ client: this.client })
30243011

3025-
private _project?: Project
3026-
get project(): Project {
3027-
return (this._project ??= new Project({ client: this.client }))
3028-
}
3012+
project = new Project({ client: this.client })
30293013

3030-
private _pty?: Pty
3031-
get pty(): Pty {
3032-
return (this._pty ??= new Pty({ client: this.client }))
3033-
}
3014+
pty = new Pty({ client: this.client })
30343015

3035-
private _config?: Config
3036-
get config(): Config {
3037-
return (this._config ??= new Config({ client: this.client }))
3038-
}
3016+
config = new Config({ client: this.client })
30393017

3040-
private _tool?: Tool
3041-
get tool(): Tool {
3042-
return (this._tool ??= new Tool({ client: this.client }))
3043-
}
3018+
tool = new Tool({ client: this.client })
30443019

3045-
private _worktree?: Worktree
3046-
get worktree(): Worktree {
3047-
return (this._worktree ??= new Worktree({ client: this.client }))
3048-
}
3020+
worktree = new Worktree({ client: this.client })
30493021

3050-
private _experimental?: Experimental
3051-
get experimental(): Experimental {
3052-
return (this._experimental ??= new Experimental({ client: this.client }))
3053-
}
3022+
experimental = new Experimental({ client: this.client })
30543023

3055-
private _session?: Session
3056-
get session(): Session {
3057-
return (this._session ??= new Session({ client: this.client }))
3058-
}
3024+
session = new Session({ client: this.client })
30593025

3060-
private _part?: Part
3061-
get part(): Part {
3062-
return (this._part ??= new Part({ client: this.client }))
3063-
}
3026+
part = new Part({ client: this.client })
30643027

3065-
private _permission?: Permission
3066-
get permission(): Permission {
3067-
return (this._permission ??= new Permission({ client: this.client }))
3068-
}
3028+
permission = new Permission({ client: this.client })
30693029

3070-
private _question?: Question
3071-
get question(): Question {
3072-
return (this._question ??= new Question({ client: this.client }))
3073-
}
3030+
question = new Question({ client: this.client })
30743031

3075-
private _provider?: Provider
3076-
get provider(): Provider {
3077-
return (this._provider ??= new Provider({ client: this.client }))
3078-
}
3032+
provider = new Provider({ client: this.client })
30793033

3080-
private _find?: Find
3081-
get find(): Find {
3082-
return (this._find ??= new Find({ client: this.client }))
3083-
}
3034+
find = new Find({ client: this.client })
30843035

3085-
private _file?: File
3086-
get file(): File {
3087-
return (this._file ??= new File({ client: this.client }))
3088-
}
3036+
file = new File({ client: this.client })
30893037

3090-
private _mcp?: Mcp
3091-
get mcp(): Mcp {
3092-
return (this._mcp ??= new Mcp({ client: this.client }))
3093-
}
3038+
mcp = new Mcp({ client: this.client })
30943039

3095-
private _tui?: Tui
3096-
get tui(): Tui {
3097-
return (this._tui ??= new Tui({ client: this.client }))
3098-
}
3040+
tui = new Tui({ client: this.client })
30993041

3100-
private _instance?: Instance
3101-
get instance(): Instance {
3102-
return (this._instance ??= new Instance({ client: this.client }))
3103-
}
3042+
instance = new Instance({ client: this.client })
31043043

3105-
private _path?: Path
3106-
get path(): Path {
3107-
return (this._path ??= new Path({ client: this.client }))
3108-
}
3044+
path = new Path({ client: this.client })
31093045

3110-
private _vcs?: Vcs
3111-
get vcs(): Vcs {
3112-
return (this._vcs ??= new Vcs({ client: this.client }))
3113-
}
3046+
vcs = new Vcs({ client: this.client })
31143047

3115-
private _command?: Command
3116-
get command(): Command {
3117-
return (this._command ??= new Command({ client: this.client }))
3118-
}
3048+
command = new Command({ client: this.client })
31193049

3120-
private _app?: App
3121-
get app(): App {
3122-
return (this._app ??= new App({ client: this.client }))
3123-
}
3050+
app = new App({ client: this.client })
31243051

3125-
private _lsp?: Lsp
3126-
get lsp(): Lsp {
3127-
return (this._lsp ??= new Lsp({ client: this.client }))
3128-
}
3052+
lsp = new Lsp({ client: this.client })
31293053

3130-
private _formatter?: Formatter
3131-
get formatter(): Formatter {
3132-
return (this._formatter ??= new Formatter({ client: this.client }))
3133-
}
3054+
formatter = new Formatter({ client: this.client })
31343055

3135-
private _auth?: Auth2
3136-
get auth(): Auth2 {
3137-
return (this._auth ??= new Auth2({ client: this.client }))
3138-
}
3056+
auth = new Auth({ client: this.client })
31393057

3140-
private _event?: Event
3141-
get event(): Event {
3142-
return (this._event ??= new Event({ client: this.client }))
3143-
}
3058+
event = new Event({ client: this.client })
31443059
}

packages/sdk/js/src/v2/gen/types.gen.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3117,6 +3117,8 @@ export type SessionMessagesData = {
31173117
query?: {
31183118
directory?: string
31193119
limit?: number
3120+
ts_before?: number
3121+
breakpoint?: boolean
31203122
}
31213123
url: "/session/{sessionID}/message"
31223124
}

0 commit comments

Comments
 (0)