Skip to content

Commit ff8c4f8

Browse files
feat: /prune
1 parent 09fa84c commit ff8c4f8

File tree

6 files changed

+58
-4
lines changed

6 files changed

+58
-4
lines changed

packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ export function Autocomplete(props: {
219219
description: "compact the session",
220220
onSelect: () => command.trigger("session.compact"),
221221
},
222+
{
223+
display: "/prune",
224+
description: "prune all tool call outputs",
225+
onSelect: () => command.trigger("session.prune"),
226+
},
222227
{
223228
display: "/unshare",
224229
disabled: !s.share,

packages/opencode/src/cli/cmd/tui/event.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const TuiEvent = {
1313
"session.share",
1414
"session.interrupt",
1515
"session.compact",
16+
"session.prune",
1617
"session.page.up",
1718
"session.page.down",
1819
"session.half.page.up",

packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,23 @@ export function Session() {
217217
dialog.clear()
218218
},
219219
},
220+
{
221+
title: "Prune session",
222+
value: "session.prune",
223+
keybind: "session_prune",
224+
category: "Session",
225+
onSelect: (dialog) => {
226+
sdk.client.session
227+
.prune({
228+
path: {
229+
id: route.sessionID,
230+
},
231+
})
232+
.then(() => toast.show({ message: "Session pruned successfully!", variant: "success" }))
233+
.catch(() => toast.show({ message: "Failed to prune session", variant: "error" }))
234+
dialog.clear()
235+
},
236+
},
220237
...(sync.data.config.share !== "disabled"
221238
? [
222239
{

packages/opencode/src/config/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,7 @@ export namespace Config {
396396
session_unshare: z.string().optional().default("none").describe("Unshare current session"),
397397
session_interrupt: z.string().optional().default("escape").describe("Interrupt current session"),
398398
session_compact: z.string().optional().default("<leader>c").describe("Compact the session"),
399+
session_prune: z.string().optional().default("none").describe("Prune all tool call outputs from the session"),
399400
messages_page_up: z.string().optional().default("pageup").describe("Scroll messages up by one page"),
400401
messages_page_down: z.string().optional().default("pagedown").describe("Scroll messages down by one page"),
401402
messages_half_page_up: z.string().optional().default("ctrl+alt+u").describe("Scroll messages up by half page"),

packages/opencode/src/server/server.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,35 @@ export namespace Server {
724724
return c.json(true)
725725
},
726726
)
727+
.post(
728+
"/session/:id/prune",
729+
describeRoute({
730+
description: "Prune all tool call outputs from the session",
731+
operationId: "session.prune",
732+
responses: {
733+
200: {
734+
description: "Pruned session",
735+
content: {
736+
"application/json": {
737+
schema: resolver(z.boolean()),
738+
},
739+
},
740+
},
741+
...errors(400, 404),
742+
},
743+
}),
744+
validator(
745+
"param",
746+
z.object({
747+
id: z.string().meta({ description: "Session ID" }),
748+
}),
749+
),
750+
async (c) => {
751+
const id = c.req.valid("param").id
752+
await SessionCompaction.prune({ sessionID: id, force: true })
753+
return c.json(true)
754+
},
755+
)
727756
.get(
728757
"/session/:id/message",
729758
describeRoute({
@@ -1607,6 +1636,7 @@ export namespace Server {
16071636
session_share: "session.share",
16081637
session_interrupt: "session.interrupt",
16091638
session_compact: "session.compact",
1639+
session_prune: "session.prune",
16101640
messages_page_up: "session.page.up",
16111641
messages_page_down: "session.page.down",
16121642
messages_half_page_up: "session.half.page.up",

packages/opencode/src/session/compaction.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ export namespace SessionCompaction {
4747
// goes backwards through parts until there are 40_000 tokens worth of tool
4848
// calls. then erases output of previous tool calls. idea is to throw away old
4949
// tool calls that are no longer relevant.
50-
export async function prune(input: { sessionID: string }) {
50+
export async function prune(input: { sessionID: string; force?: boolean }) {
5151
if (Flag.OPENCODE_DISABLE_PRUNE) return
52-
log.info("pruning")
52+
log.info("pruning", { force: input.force })
5353
const msgs = await Session.messages({ sessionID: input.sessionID })
5454
let total = 0
5555
let pruned = 0
@@ -68,15 +68,15 @@ export namespace SessionCompaction {
6868
if (part.state.time.compacted) break loop
6969
const estimate = Token.estimate(part.state.output)
7070
total += estimate
71-
if (total > PRUNE_PROTECT) {
71+
if (input.force || total > PRUNE_PROTECT) {
7272
pruned += estimate
7373
toPrune.push(part)
7474
}
7575
}
7676
}
7777
}
7878
log.info("found", { pruned, total })
79-
if (pruned > PRUNE_MINIMUM) {
79+
if (input.force || pruned > PRUNE_MINIMUM) {
8080
for (const part of toPrune) {
8181
if (part.state.status === "completed") {
8282
part.state.time.compacted = Date.now()

0 commit comments

Comments
 (0)