Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 7a7060e

Browse files
committed
fix session performance issue from large diffs
1 parent f9af9fc commit 7a7060e

6 files changed

Lines changed: 101 additions & 17 deletions

File tree

packages/opencode/src/server/server.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,34 @@ export namespace Server {
758758
return c.json(messages)
759759
},
760760
)
761+
.get(
762+
"/session/:id/diff",
763+
describeRoute({
764+
description: "Get the diff for this session",
765+
operationId: "session.diff",
766+
responses: {
767+
200: {
768+
description: "List of diffs",
769+
content: {
770+
"application/json": {
771+
schema: resolver(Snapshot.FileDiff.array()),
772+
},
773+
},
774+
},
775+
...errors(400, 404),
776+
},
777+
}),
778+
validator(
779+
"param",
780+
z.object({
781+
id: z.string().meta({ description: "Session ID" }),
782+
}),
783+
),
784+
async (c) => {
785+
const diff = await Session.diff(c.req.valid("param").id)
786+
return c.json(diff)
787+
},
788+
)
761789
.get(
762790
"/session/:id/message/:messageID",
763791
describeRoute({

packages/opencode/src/session/index.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import { MessageV2 } from "./message-v2"
1515
import { Instance } from "../project/instance"
1616
import { SessionPrompt } from "./prompt"
1717
import { fn } from "@/util/fn"
18-
import { Snapshot } from "@/snapshot"
1918
import { Command } from "../command"
19+
import { Snapshot } from "@/snapshot"
2020

2121
export namespace Session {
2222
const log = Log.create({ service: "session" })
@@ -42,7 +42,9 @@ export namespace Session {
4242
parentID: Identifier.schema("session").optional(),
4343
summary: z
4444
.object({
45-
diffs: Snapshot.FileDiff.array(),
45+
additions: z.number(),
46+
deletions: z.number(),
47+
diffs: Snapshot.FileDiff.array().optional(),
4648
})
4749
.optional(),
4850
share: z
@@ -258,6 +260,11 @@ export namespace Session {
258260
return result
259261
}
260262

263+
export const diff = fn(Identifier.schema("session"), async (sessionID) => {
264+
const diffs = await Storage.read<Snapshot.FileDiff[]>(["session_diff", sessionID])
265+
return diffs ?? []
266+
})
267+
261268
export const messages = fn(Identifier.schema("session"), async (sessionID) => {
262269
const result = [] as MessageV2.WithParts[]
263270
for (const p of await Storage.list(["message", sessionID])) {

packages/opencode/src/session/summary.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SystemPrompt } from "./system"
1111
import { Log } from "@/util/log"
1212
import path from "path"
1313
import { Instance } from "@/project/instance"
14+
import { Storage } from "@/storage/storage"
1415

1516
export namespace SessionSummary {
1617
const log = Log.create({ service: "session.summary" })
@@ -44,9 +45,11 @@ export namespace SessionSummary {
4445
)
4546
await Session.update(input.sessionID, (draft) => {
4647
draft.summary = {
47-
diffs,
48+
additions: diffs.reduce((sum, x) => sum + x.additions, 0),
49+
deletions: diffs.reduce((sum, x) => sum + x.deletions, 0),
4850
}
4951
})
52+
await Storage.write(["session_diff", input.sessionID], diffs)
5053
}
5154

5255
async function summarizeMessage(input: { messageID: string; messages: MessageV2.WithParts[] }) {

packages/opencode/src/storage/storage.ts

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ export namespace Storage {
8585
const session = await Bun.file(sessionFile).json()
8686
await Bun.write(dest, JSON.stringify(session))
8787
log.info(`migrating messages for session ${session.id}`)
88-
for await (const msgFile of new Bun.Glob(`storage/session/message/${session.id}/*.json`).scan({
88+
for await (const msgFile of new Bun.Glob(
89+
`storage/session/message/${session.id}/*.json`,
90+
).scan({
8991
cwd: fullProjectDir,
9092
absolute: true,
9193
})) {
@@ -98,12 +100,12 @@ export namespace Storage {
98100
await Bun.write(dest, JSON.stringify(message))
99101

100102
log.info(`migrating parts for message ${message.id}`)
101-
for await (const partFile of new Bun.Glob(`storage/session/part/${session.id}/${message.id}/*.json`).scan(
102-
{
103-
cwd: fullProjectDir,
104-
absolute: true,
105-
},
106-
)) {
103+
for await (const partFile of new Bun.Glob(
104+
`storage/session/part/${session.id}/${message.id}/*.json`,
105+
).scan({
106+
cwd: fullProjectDir,
107+
absolute: true,
108+
})) {
107109
const dest = path.join(dir, "part", message.id, path.basename(partFile))
108110
const part = await Bun.file(partFile).json()
109111
log.info("copying", {
@@ -117,6 +119,29 @@ export namespace Storage {
117119
}
118120
}
119121
},
122+
async (dir) => {
123+
for await (const item of new Bun.Glob("session/*/*.json").scan({
124+
cwd: dir,
125+
absolute: true,
126+
})) {
127+
const session = await Bun.file(item).json()
128+
if (!session.projectID) continue
129+
if (!session.summary?.diffs) continue
130+
const { diffs } = session.summary
131+
await Bun.file(path.join(dir, "session_diff", session.id + ".json")).write(
132+
JSON.stringify(diffs),
133+
)
134+
await Bun.file(path.join(dir, "session", session.projectID, session.id + ".json")).write(
135+
JSON.stringify({
136+
...session,
137+
summary: {
138+
additions: diffs.reduce((sum: any, x: any) => sum + x.additions, 0),
139+
deletions: diffs.reduce((sum: any, x: any) => sum + x.deletions, 0),
140+
},
141+
}),
142+
)
143+
}
144+
},
120145
]
121146

122147
const state = lazy(async () => {
@@ -128,9 +153,7 @@ export namespace Storage {
128153
for (let index = migration; index < MIGRATIONS.length; index++) {
129154
log.info("running migration", { index })
130155
const migration = MIGRATIONS[index]
131-
await migration(dir).catch((e) => {
132-
log.error("failed to run migration", { error: e, index })
133-
})
156+
await migration(dir).catch(() => log.error("failed to run migration", { index }))
134157
await Bun.write(path.join(dir, "migration"), (index + 1).toString())
135158
}
136159
return {

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import type {
5555
SessionShareErrors,
5656
SessionDiffData,
5757
SessionDiffResponses,
58+
SessionDiffErrors,
5859
SessionSummarizeData,
5960
SessionSummarizeResponses,
6061
SessionSummarizeErrors,
@@ -475,12 +476,16 @@ class Session extends _HeyApiClient {
475476
}
476477

477478
/**
478-
* Get the diff that resulted from this user message
479+
* Get the diff for this session
479480
*/
480481
public diff<ThrowOnError extends boolean = false>(
481482
options: Options<SessionDiffData, ThrowOnError>,
482483
) {
483-
return (options.client ?? this._client).get<SessionDiffResponses, unknown, ThrowOnError>({
484+
return (options.client ?? this._client).get<
485+
SessionDiffResponses,
486+
SessionDiffErrors,
487+
ThrowOnError
488+
>({
484489
url: "/session/{id}/diff",
485490
...options,
486491
})

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

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,9 @@ export type Session = {
527527
directory: string
528528
parentID?: string
529529
summary?: {
530-
diffs: Array<FileDiff>
530+
additions: number
531+
deletions: number
532+
diffs?: Array<FileDiff>
531533
}
532534
share?: {
533535
url: string
@@ -1882,6 +1884,9 @@ export type SessionShareResponse = SessionShareResponses[keyof SessionShareRespo
18821884
export type SessionDiffData = {
18831885
body?: never
18841886
path: {
1887+
/**
1888+
* Session ID
1889+
*/
18851890
id: string
18861891
}
18871892
query?: {
@@ -1891,9 +1896,22 @@ export type SessionDiffData = {
18911896
url: "/session/{id}/diff"
18921897
}
18931898

1899+
export type SessionDiffErrors = {
1900+
/**
1901+
* Bad request
1902+
*/
1903+
400: BadRequestError
1904+
/**
1905+
* Not found
1906+
*/
1907+
404: NotFoundError
1908+
}
1909+
1910+
export type SessionDiffError = SessionDiffErrors[keyof SessionDiffErrors]
1911+
18941912
export type SessionDiffResponses = {
18951913
/**
1896-
* Successfully retrieved diff
1914+
* List of diffs
18971915
*/
18981916
200: Array<FileDiff>
18991917
}

0 commit comments

Comments
 (0)