mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-22 18:24:21 +01:00
fix session performance issue from large diffs
This commit is contained in:
@@ -758,6 +758,34 @@ export namespace Server {
|
|||||||
return c.json(messages)
|
return c.json(messages)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
.get(
|
||||||
|
"/session/:id/diff",
|
||||||
|
describeRoute({
|
||||||
|
description: "Get the diff for this session",
|
||||||
|
operationId: "session.diff",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "List of diffs",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(Snapshot.FileDiff.array()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...errors(400, 404),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
validator(
|
||||||
|
"param",
|
||||||
|
z.object({
|
||||||
|
id: z.string().meta({ description: "Session ID" }),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
async (c) => {
|
||||||
|
const diff = await Session.diff(c.req.valid("param").id)
|
||||||
|
return c.json(diff)
|
||||||
|
},
|
||||||
|
)
|
||||||
.get(
|
.get(
|
||||||
"/session/:id/message/:messageID",
|
"/session/:id/message/:messageID",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import { MessageV2 } from "./message-v2"
|
|||||||
import { Instance } from "../project/instance"
|
import { Instance } from "../project/instance"
|
||||||
import { SessionPrompt } from "./prompt"
|
import { SessionPrompt } from "./prompt"
|
||||||
import { fn } from "@/util/fn"
|
import { fn } from "@/util/fn"
|
||||||
import { Snapshot } from "@/snapshot"
|
|
||||||
import { Command } from "../command"
|
import { Command } from "../command"
|
||||||
|
import { Snapshot } from "@/snapshot"
|
||||||
|
|
||||||
export namespace Session {
|
export namespace Session {
|
||||||
const log = Log.create({ service: "session" })
|
const log = Log.create({ service: "session" })
|
||||||
@@ -42,7 +42,9 @@ export namespace Session {
|
|||||||
parentID: Identifier.schema("session").optional(),
|
parentID: Identifier.schema("session").optional(),
|
||||||
summary: z
|
summary: z
|
||||||
.object({
|
.object({
|
||||||
diffs: Snapshot.FileDiff.array(),
|
additions: z.number(),
|
||||||
|
deletions: z.number(),
|
||||||
|
diffs: Snapshot.FileDiff.array().optional(),
|
||||||
})
|
})
|
||||||
.optional(),
|
.optional(),
|
||||||
share: z
|
share: z
|
||||||
@@ -258,6 +260,11 @@ export namespace Session {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const diff = fn(Identifier.schema("session"), async (sessionID) => {
|
||||||
|
const diffs = await Storage.read<Snapshot.FileDiff[]>(["session_diff", sessionID])
|
||||||
|
return diffs ?? []
|
||||||
|
})
|
||||||
|
|
||||||
export const messages = fn(Identifier.schema("session"), async (sessionID) => {
|
export const messages = fn(Identifier.schema("session"), async (sessionID) => {
|
||||||
const result = [] as MessageV2.WithParts[]
|
const result = [] as MessageV2.WithParts[]
|
||||||
for (const p of await Storage.list(["message", sessionID])) {
|
for (const p of await Storage.list(["message", sessionID])) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { SystemPrompt } from "./system"
|
|||||||
import { Log } from "@/util/log"
|
import { Log } from "@/util/log"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Instance } from "@/project/instance"
|
import { Instance } from "@/project/instance"
|
||||||
|
import { Storage } from "@/storage/storage"
|
||||||
|
|
||||||
export namespace SessionSummary {
|
export namespace SessionSummary {
|
||||||
const log = Log.create({ service: "session.summary" })
|
const log = Log.create({ service: "session.summary" })
|
||||||
@@ -44,9 +45,11 @@ export namespace SessionSummary {
|
|||||||
)
|
)
|
||||||
await Session.update(input.sessionID, (draft) => {
|
await Session.update(input.sessionID, (draft) => {
|
||||||
draft.summary = {
|
draft.summary = {
|
||||||
diffs,
|
additions: diffs.reduce((sum, x) => sum + x.additions, 0),
|
||||||
|
deletions: diffs.reduce((sum, x) => sum + x.deletions, 0),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
await Storage.write(["session_diff", input.sessionID], diffs)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function summarizeMessage(input: { messageID: string; messages: MessageV2.WithParts[] }) {
|
async function summarizeMessage(input: { messageID: string; messages: MessageV2.WithParts[] }) {
|
||||||
|
|||||||
@@ -85,7 +85,9 @@ export namespace Storage {
|
|||||||
const session = await Bun.file(sessionFile).json()
|
const session = await Bun.file(sessionFile).json()
|
||||||
await Bun.write(dest, JSON.stringify(session))
|
await Bun.write(dest, JSON.stringify(session))
|
||||||
log.info(`migrating messages for session ${session.id}`)
|
log.info(`migrating messages for session ${session.id}`)
|
||||||
for await (const msgFile of new Bun.Glob(`storage/session/message/${session.id}/*.json`).scan({
|
for await (const msgFile of new Bun.Glob(
|
||||||
|
`storage/session/message/${session.id}/*.json`,
|
||||||
|
).scan({
|
||||||
cwd: fullProjectDir,
|
cwd: fullProjectDir,
|
||||||
absolute: true,
|
absolute: true,
|
||||||
})) {
|
})) {
|
||||||
@@ -98,12 +100,12 @@ export namespace Storage {
|
|||||||
await Bun.write(dest, JSON.stringify(message))
|
await Bun.write(dest, JSON.stringify(message))
|
||||||
|
|
||||||
log.info(`migrating parts for message ${message.id}`)
|
log.info(`migrating parts for message ${message.id}`)
|
||||||
for await (const partFile of new Bun.Glob(`storage/session/part/${session.id}/${message.id}/*.json`).scan(
|
for await (const partFile of new Bun.Glob(
|
||||||
{
|
`storage/session/part/${session.id}/${message.id}/*.json`,
|
||||||
cwd: fullProjectDir,
|
).scan({
|
||||||
absolute: true,
|
cwd: fullProjectDir,
|
||||||
},
|
absolute: true,
|
||||||
)) {
|
})) {
|
||||||
const dest = path.join(dir, "part", message.id, path.basename(partFile))
|
const dest = path.join(dir, "part", message.id, path.basename(partFile))
|
||||||
const part = await Bun.file(partFile).json()
|
const part = await Bun.file(partFile).json()
|
||||||
log.info("copying", {
|
log.info("copying", {
|
||||||
@@ -117,6 +119,29 @@ export namespace Storage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async (dir) => {
|
||||||
|
for await (const item of new Bun.Glob("session/*/*.json").scan({
|
||||||
|
cwd: dir,
|
||||||
|
absolute: true,
|
||||||
|
})) {
|
||||||
|
const session = await Bun.file(item).json()
|
||||||
|
if (!session.projectID) continue
|
||||||
|
if (!session.summary?.diffs) continue
|
||||||
|
const { diffs } = session.summary
|
||||||
|
await Bun.file(path.join(dir, "session_diff", session.id + ".json")).write(
|
||||||
|
JSON.stringify(diffs),
|
||||||
|
)
|
||||||
|
await Bun.file(path.join(dir, "session", session.projectID, session.id + ".json")).write(
|
||||||
|
JSON.stringify({
|
||||||
|
...session,
|
||||||
|
summary: {
|
||||||
|
additions: diffs.reduce((sum: any, x: any) => sum + x.additions, 0),
|
||||||
|
deletions: diffs.reduce((sum: any, x: any) => sum + x.deletions, 0),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const state = lazy(async () => {
|
const state = lazy(async () => {
|
||||||
@@ -128,9 +153,7 @@ export namespace Storage {
|
|||||||
for (let index = migration; index < MIGRATIONS.length; index++) {
|
for (let index = migration; index < MIGRATIONS.length; index++) {
|
||||||
log.info("running migration", { index })
|
log.info("running migration", { index })
|
||||||
const migration = MIGRATIONS[index]
|
const migration = MIGRATIONS[index]
|
||||||
await migration(dir).catch((e) => {
|
await migration(dir).catch(() => log.error("failed to run migration", { index }))
|
||||||
log.error("failed to run migration", { error: e, index })
|
|
||||||
})
|
|
||||||
await Bun.write(path.join(dir, "migration"), (index + 1).toString())
|
await Bun.write(path.join(dir, "migration"), (index + 1).toString())
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import type {
|
|||||||
SessionShareErrors,
|
SessionShareErrors,
|
||||||
SessionDiffData,
|
SessionDiffData,
|
||||||
SessionDiffResponses,
|
SessionDiffResponses,
|
||||||
|
SessionDiffErrors,
|
||||||
SessionSummarizeData,
|
SessionSummarizeData,
|
||||||
SessionSummarizeResponses,
|
SessionSummarizeResponses,
|
||||||
SessionSummarizeErrors,
|
SessionSummarizeErrors,
|
||||||
@@ -475,12 +476,16 @@ class Session extends _HeyApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the diff that resulted from this user message
|
* Get the diff for this session
|
||||||
*/
|
*/
|
||||||
public diff<ThrowOnError extends boolean = false>(
|
public diff<ThrowOnError extends boolean = false>(
|
||||||
options: Options<SessionDiffData, ThrowOnError>,
|
options: Options<SessionDiffData, ThrowOnError>,
|
||||||
) {
|
) {
|
||||||
return (options.client ?? this._client).get<SessionDiffResponses, unknown, ThrowOnError>({
|
return (options.client ?? this._client).get<
|
||||||
|
SessionDiffResponses,
|
||||||
|
SessionDiffErrors,
|
||||||
|
ThrowOnError
|
||||||
|
>({
|
||||||
url: "/session/{id}/diff",
|
url: "/session/{id}/diff",
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -527,7 +527,9 @@ export type Session = {
|
|||||||
directory: string
|
directory: string
|
||||||
parentID?: string
|
parentID?: string
|
||||||
summary?: {
|
summary?: {
|
||||||
diffs: Array<FileDiff>
|
additions: number
|
||||||
|
deletions: number
|
||||||
|
diffs?: Array<FileDiff>
|
||||||
}
|
}
|
||||||
share?: {
|
share?: {
|
||||||
url: string
|
url: string
|
||||||
@@ -1882,6 +1884,9 @@ export type SessionShareResponse = SessionShareResponses[keyof SessionShareRespo
|
|||||||
export type SessionDiffData = {
|
export type SessionDiffData = {
|
||||||
body?: never
|
body?: never
|
||||||
path: {
|
path: {
|
||||||
|
/**
|
||||||
|
* Session ID
|
||||||
|
*/
|
||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
query?: {
|
query?: {
|
||||||
@@ -1891,9 +1896,22 @@ export type SessionDiffData = {
|
|||||||
url: "/session/{id}/diff"
|
url: "/session/{id}/diff"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SessionDiffErrors = {
|
||||||
|
/**
|
||||||
|
* Bad request
|
||||||
|
*/
|
||||||
|
400: BadRequestError
|
||||||
|
/**
|
||||||
|
* Not found
|
||||||
|
*/
|
||||||
|
404: NotFoundError
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SessionDiffError = SessionDiffErrors[keyof SessionDiffErrors]
|
||||||
|
|
||||||
export type SessionDiffResponses = {
|
export type SessionDiffResponses = {
|
||||||
/**
|
/**
|
||||||
* Successfully retrieved diff
|
* List of diffs
|
||||||
*/
|
*/
|
||||||
200: Array<FileDiff>
|
200: Array<FileDiff>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user