diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx index d19e93188b2..b1fdcda69d0 100644 --- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx @@ -56,10 +56,10 @@ function init() { }) const result = { - trigger(name: string, source?: "prompt") { + trigger(name: string, source?: "prompt", data?: any) { for (const option of options()) { if (option.value === name) { - option.onSelect?.(dialog, source) + option.onSelect?.(dialog, source, data) return } } diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx index 4f8f979d536..b186a63f222 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/autocomplete.tsx @@ -76,7 +76,7 @@ export function Autocomplete(props: { }) { const sdk = useSDK() const sync = useSync() - const command = useCommandDialog() + const dialog = useCommandDialog() const { theme } = useTheme() const dimensions = useTerminalDimensions() const frecency = useFrecency() @@ -317,17 +317,31 @@ export function Autocomplete(props: { const results: AutocompleteOption[] = [] const s = session() for (const command of sync.data.command) { - results.push({ - display: "/" + command.name + (command.mcp ? " (MCP)" : ""), - description: command.description, - onSelect: () => { - const newText = "/" + command.name + " " - const cursor = props.input().logicalCursor - props.input().deleteRange(0, 0, cursor.row, cursor.col) - props.input().insertText(newText) - props.input().cursorOffset = Bun.stringWidth(newText) - }, - }) + if (command.compact && s) { + results.push({ + display: "/" + command.name + (command.mcp ? " (MCP)" : ""), + description: command.description ?? "compact the session", + aliases: command.name === "compact" ? ["/summarize"] : undefined, + onSelect: () => { + dialog.trigger("session.compact", "prompt", { + commandName: command.name, + template: command.template, + }) + }, + }) + } else if (!command.compact) { + results.push({ + display: "/" + command.name + (command.mcp ? " (MCP)" : ""), + description: command.description, + onSelect: () => { + const newText = "/" + command.name + " " + const cursor = props.input().logicalCursor + props.input().deleteRange(0, 0, cursor.row, cursor.col) + props.input().insertText(newText) + props.input().cursorOffset = Bun.stringWidth(newText) + }, + }) + } } if (s) { results.push( @@ -335,55 +349,49 @@ export function Autocomplete(props: { display: "/undo", description: "undo the last message", onSelect: () => { - command.trigger("session.undo") + dialog.trigger("session.undo") }, }, { display: "/redo", description: "redo the last message", - onSelect: () => command.trigger("session.redo"), - }, - { - display: "/compact", - aliases: ["/summarize"], - description: "compact the session", - onSelect: () => command.trigger("session.compact"), + onSelect: () => dialog.trigger("session.redo"), }, { display: "/unshare", disabled: !s.share, description: "unshare a session", - onSelect: () => command.trigger("session.unshare"), + onSelect: () => dialog.trigger("session.unshare"), }, { display: "/rename", description: "rename session", - onSelect: () => command.trigger("session.rename"), + onSelect: () => dialog.trigger("session.rename"), }, { display: "/copy", description: "copy session transcript to clipboard", - onSelect: () => command.trigger("session.copy"), + onSelect: () => dialog.trigger("session.copy"), }, { display: "/export", description: "export session transcript to file", - onSelect: () => command.trigger("session.export"), + onSelect: () => dialog.trigger("session.export"), }, { display: "/timeline", description: "jump to message", - onSelect: () => command.trigger("session.timeline"), + onSelect: () => dialog.trigger("session.timeline"), }, { display: "/fork", description: "fork from message", - onSelect: () => command.trigger("session.fork"), + onSelect: () => dialog.trigger("session.fork"), }, { display: "/thinking", description: "toggle thinking visibility", - onSelect: () => command.trigger("session.toggle.thinking"), + onSelect: () => dialog.trigger("session.toggle.thinking"), }, ) if (sync.data.config.share !== "disabled") { @@ -391,7 +399,7 @@ export function Autocomplete(props: { display: "/share", disabled: !!s.share?.url, description: "share a session", - onSelect: () => command.trigger("session.share"), + onSelect: () => dialog.trigger("session.share"), }) } } @@ -401,64 +409,64 @@ export function Autocomplete(props: { display: "/new", aliases: ["/clear"], description: "create a new session", - onSelect: () => command.trigger("session.new"), + onSelect: () => dialog.trigger("session.new"), }, { display: "/models", description: "list models", - onSelect: () => command.trigger("model.list"), + onSelect: () => dialog.trigger("model.list"), }, { display: "/agents", description: "list agents", - onSelect: () => command.trigger("agent.list"), + onSelect: () => dialog.trigger("agent.list"), }, { display: "/session", aliases: ["/resume", "/continue"], description: "list sessions", - onSelect: () => command.trigger("session.list"), + onSelect: () => dialog.trigger("session.list"), }, { display: "/status", description: "show status", - onSelect: () => command.trigger("opencode.status"), + onSelect: () => dialog.trigger("opencode.status"), }, { display: "/mcp", description: "toggle MCPs", - onSelect: () => command.trigger("mcp.list"), + onSelect: () => dialog.trigger("mcp.list"), }, { display: "/theme", description: "toggle theme", - onSelect: () => command.trigger("theme.switch"), + onSelect: () => dialog.trigger("theme.switch"), }, { display: "/editor", description: "open editor", - onSelect: () => command.trigger("prompt.editor", "prompt"), + onSelect: () => dialog.trigger("prompt.editor", "prompt"), }, { display: "/connect", description: "connect to a provider", - onSelect: () => command.trigger("provider.connect"), + onSelect: () => dialog.trigger("provider.connect"), }, { display: "/help", description: "show help", - onSelect: () => command.trigger("help.show"), + onSelect: () => dialog.trigger("help.show"), }, { display: "/commands", description: "show all commands", - onSelect: () => command.show(), + onSelect: () => dialog.show(), }, { display: "/exit", aliases: ["/quit", "/q"], description: "exit the app", - onSelect: () => command.trigger("app.exit"), + onSelect: () => dialog.trigger("app.exit"), }, ) const max = firstBy(results, [(x) => x.display.length, "desc"])?.display.length @@ -564,7 +572,7 @@ export function Autocomplete(props: { } function show(mode: "@" | "/") { - command.keybinds(false) + dialog.keybinds(false) setStore({ visible: mode, index: props.input().cursorOffset, @@ -581,7 +589,7 @@ export function Autocomplete(props: { draft.input = props.input().plainText }) } - command.keybinds(true) + dialog.keybinds(true) setStore("visible", false) } diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index b6916bc5a58..4b8e7caa7dd 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -374,7 +374,7 @@ export function Session() { value: "session.compact", keybind: "session_compact", category: "Session", - onSelect: (dialog) => { + onSelect: async (dialog, trigger, data) => { const selectedModel = local.model.current() if (!selectedModel) { toast.show({ @@ -384,11 +384,29 @@ export function Session() { }) return } - sdk.client.session.summarize({ + // If no template provided (e.g., via keybind), use the default /compact command + const prompt = data?.template ?? sync.data.command.find((c) => c.name === "compact")?.template + if (!prompt) { + toast.show({ + variant: "warning", + message: "No compact command configured", + duration: 3000, + }) + return + } + const result = await sdk.client.session.summarize({ sessionID: route.sessionID, - modelID: selectedModel.modelID, providerID: selectedModel.providerID, + modelID: selectedModel.modelID, + prompt, }) + if (result.error) { + toast.show({ + variant: "error", + message: "Summarize failed: " + JSON.stringify(result.error), + duration: 5000, + }) + } dialog.clear() }, }, @@ -933,11 +951,11 @@ export function Session() { {(function () { const command = useCommandDialog() const [hover, setHover] = createSignal(false) - const dialog = useDialog() + const modal = useDialog() const handleUnrevert = async () => { const confirmed = await DialogConfirm.show( - dialog, + modal, "Confirm Redo", "Are you sure you want to restore the reverted messages?", ) diff --git a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx index 98adcdeb135..11154a5dc85 100644 --- a/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx +++ b/packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx @@ -38,7 +38,7 @@ export interface DialogSelectOption { disabled?: boolean bg?: RGBA gutter?: JSX.Element - onSelect?: (ctx: DialogContext, trigger?: "prompt") => void + onSelect?: (ctx: DialogContext, trigger?: "prompt", data?: any) => void } export type DialogSelectRef = { diff --git a/packages/opencode/src/command/index.ts b/packages/opencode/src/command/index.ts index 976f1cd51e9..efe9a50629e 100644 --- a/packages/opencode/src/command/index.ts +++ b/packages/opencode/src/command/index.ts @@ -5,6 +5,7 @@ import { Instance } from "../project/instance" import { Identifier } from "../id/id" import PROMPT_INITIALIZE from "./template/initialize.txt" import PROMPT_REVIEW from "./template/review.txt" +import PROMPT_COMPACT from "./template/compact.txt" import { MCP } from "../mcp" export namespace Command { @@ -31,6 +32,7 @@ export namespace Command { // https://zod.dev/v4/changelog?id=zfunction template: z.promise(z.string()).or(z.string()), subtask: z.boolean().optional(), + compact: z.boolean().optional(), hints: z.array(z.string()), }) .meta({ @@ -53,6 +55,7 @@ export namespace Command { export const Default = { INIT: "init", REVIEW: "review", + COMPACT: "compact", } as const const state = Instance.state(async () => { @@ -76,6 +79,13 @@ export namespace Command { subtask: true, hints: hints(PROMPT_REVIEW), }, + [Default.COMPACT]: { + name: Default.COMPACT, + description: "summarize session for compaction", + template: PROMPT_COMPACT, + compact: true, + hints: hints(PROMPT_COMPACT), + }, } for (const [name, command] of Object.entries(cfg.command ?? {})) { @@ -88,6 +98,7 @@ export namespace Command { return command.template }, subtask: command.subtask, + compact: command.compact, hints: hints(command.template), } } diff --git a/packages/opencode/src/command/template/compact.txt b/packages/opencode/src/command/template/compact.txt new file mode 100644 index 00000000000..186244aa708 --- /dev/null +++ b/packages/opencode/src/command/template/compact.txt @@ -0,0 +1 @@ +Provide a detailed prompt for continuing our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next considering new session will not have access to our conversation. \ No newline at end of file diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index bf4a6035bd8..66a69c34014 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -521,6 +521,7 @@ export namespace Config { agent: z.string().optional(), model: z.string().optional(), subtask: z.boolean().optional(), + compact: z.boolean().optional(), }) export type Command = z.infer @@ -997,6 +998,10 @@ export namespace Config { .object({ auto: z.boolean().optional().describe("Enable automatic compaction when context is full (default: true)"), prune: z.boolean().optional().describe("Enable pruning of old tool outputs (default: true)"), + command: z + .string() + .optional() + .describe("Command to use for automatic compaction when context limit is reached. Defaults to 'compact'"), }) .optional(), experimental: z diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts index 52457515b8e..e737d1fd59b 100644 --- a/packages/opencode/src/server/server.ts +++ b/packages/opencode/src/server/server.ts @@ -1189,6 +1189,7 @@ export namespace Server { z.object({ providerID: z.string(), modelID: z.string(), + prompt: z.string().describe("Prompt to use for compaction"), auto: z.boolean().optional().default(false), }), ), @@ -1214,6 +1215,7 @@ export namespace Server { modelID: body.modelID, }, auto: body.auto, + prompt: body.prompt, }) await SessionPrompt.loop(sessionID) return c.json(true) diff --git a/packages/opencode/src/session/compaction.ts b/packages/opencode/src/session/compaction.ts index 42bab2eb975..0932a688cc9 100644 --- a/packages/opencode/src/session/compaction.ts +++ b/packages/opencode/src/session/compaction.ts @@ -12,12 +12,15 @@ import { Log } from "../util/log" import { SessionProcessor } from "./processor" import { fn } from "@/util/fn" import { Agent } from "@/agent/agent" +import PROMPT_COMPACT from "../command/template/compact.txt" import { Plugin } from "@/plugin" import { Config } from "@/config/config" export namespace SessionCompaction { const log = Log.create({ service: "session.compaction" }) + export const DEFAULT_PROMPT = PROMPT_COMPACT + export const Event = { Compacted: BusEvent.define( "session.compacted", @@ -95,6 +98,7 @@ export namespace SessionCompaction { sessionID: string abort: AbortSignal auto: boolean + prompt: string }) { const userMessage = input.messages.findLast((m) => m.info.id === input.parentID)!.info as MessageV2.User const agent = await Agent.get("compaction") @@ -132,15 +136,12 @@ export namespace SessionCompaction { model, abort: input.abort, }) - // Allow plugins to inject context or replace compaction prompt + // Allow plugins to inject additional context for compaction const compacting = await Plugin.trigger( "experimental.session.compacting", { sessionID: input.sessionID }, - { context: [], prompt: undefined }, + { context: [] }, ) - const defaultPrompt = - "Provide a detailed prompt for continuing our conversation above. Focus on information that would be helpful for continuing the conversation, including what we did, what we're doing, which files we're working on, and what we're going to do next considering new session will not have access to our conversation." - const promptText = compacting.prompt ?? [defaultPrompt, ...compacting.context].join("\n\n") const result = await processor.process({ user: userMessage, agent, @@ -155,7 +156,7 @@ export namespace SessionCompaction { content: [ { type: "text", - text: promptText, + text: [input.prompt, ...compacting.context].join("\n\n"), }, ], }, @@ -201,6 +202,7 @@ export namespace SessionCompaction { modelID: z.string(), }), auto: z.boolean(), + prompt: z.string(), }), async (input) => { const msg = await Session.updateMessage({ @@ -219,6 +221,7 @@ export namespace SessionCompaction { sessionID: msg.sessionID, type: "compaction", auto: input.auto, + prompt: input.prompt, }) }, ) diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index c1d4015f6d3..0d9f8bf673b 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -158,6 +158,7 @@ export namespace MessageV2 { export const CompactionPart = PartBase.extend({ type: z.literal("compaction"), auto: z.boolean(), + prompt: z.string(), }).meta({ ref: "CompactionPart", }) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 5036d3a6964..79692da2f5d 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -33,6 +33,7 @@ import { spawn } from "child_process" import { Command } from "../command" import { $, fileURLToPath } from "bun" import { ConfigMarkdown } from "../config/markdown" +import { Config } from "../config/config" import { SessionSummary } from "./summary" import { NamedError } from "@opencode-ai/util/error" import { fn } from "@/util/fn" @@ -480,12 +481,16 @@ export namespace SessionPrompt { // pending compaction if (task?.type === "compaction") { + if (!task.prompt) { + throw new Error("Compaction task missing required prompt") + } const result = await SessionCompaction.process({ messages: msgs, parentID: lastUser.id, abort, sessionID, auto: task.auto, + prompt: task.prompt, }) if (result === "stop") break continue @@ -497,11 +502,26 @@ export namespace SessionPrompt { lastFinished.summary !== true && (await SessionCompaction.isOverflow({ tokens: lastFinished.tokens, model })) ) { + const cfg = await Config.get() + const compactCommandName = cfg.compaction?.command ?? "compact" + const compactCommand = await Command.get(compactCommandName) + + if (!compactCommand) { + const errorMsg = + `Auto-compaction command "${compactCommandName}" not found. ` + + `Please ensure the command exists or update the "compaction.command" config setting.` + log.error("auto-compaction command not found", { + compactCommandName, + }) + throw new Error(errorMsg) + } + await SessionCompaction.create({ sessionID, agent: lastUser.agent, model: lastUser.model, auto: true, + prompt: await compactCommand.template, }) continue } @@ -611,11 +631,14 @@ export namespace SessionPrompt { }) if (result === "stop") break if (result === "compact") { + const cfg = await Config.get() + const compactCmd = await Command.get(cfg.compaction?.command ?? Command.Default.COMPACT) await SessionCompaction.create({ sessionID, agent: lastUser.agent, model: lastUser.model, auto: true, + prompt: await compactCmd.template, }) } continue diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 32f33f66219..c5eb47319e8 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -1443,6 +1443,7 @@ export type Command = { model?: string template: string subtask?: boolean + compact?: boolean } export type Model = { @@ -2499,6 +2500,7 @@ export type SessionSummarizeData = { body?: { providerID: string modelID: string + prompt?: string } path: { /** diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index f83913ea5e1..a5afc5297e9 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -1237,6 +1237,7 @@ export class Session extends HeyApiClient { directory?: string providerID?: string modelID?: string + prompt?: string auto?: boolean }, options?: Options, @@ -1250,6 +1251,7 @@ export class Session extends HeyApiClient { { in: "query", key: "directory" }, { in: "body", key: "providerID" }, { in: "body", key: "modelID" }, + { in: "body", key: "prompt" }, { in: "body", key: "auto" }, ], }, diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index acc29d9b43e..5993ccc7c07 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -417,6 +417,7 @@ export type CompactionPart = { messageID: string type: "compaction" auto: boolean + prompt: string } export type Part = @@ -1580,6 +1581,7 @@ export type Config = { agent?: string model?: string subtask?: boolean + compact?: boolean } } watcher?: { @@ -1716,6 +1718,10 @@ export type Config = { * Enable pruning of old tool outputs (default: true) */ prune?: boolean + /** + * Command to use for automatic compaction when context limit is reached. Defaults to 'compact' + */ + command?: string } experimental?: { hook?: { @@ -1847,6 +1853,7 @@ export type Command = { mcp?: boolean template: string subtask?: boolean + compact?: boolean hints: Array } @@ -3050,6 +3057,10 @@ export type SessionSummarizeData = { body?: { providerID: string modelID: string + /** + * Prompt to use for compaction + */ + prompt: string auto?: boolean } path: { diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index a31f0d67ab2..21fbda34490 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -27,7 +27,10 @@ "type": "string" } }, - "required": ["healthy", "version"] + "required": [ + "healthy", + "version" + ] } } } @@ -476,7 +479,10 @@ "type": "number" } }, - "required": ["rows", "cols"] + "required": [ + "rows", + "cols" + ] } } } @@ -1169,7 +1175,9 @@ ], "summary": "Get session", "description": "Retrieve detailed information about a specific OpenCode session.", - "tags": ["Session"], + "tags": [ + "Session" + ], "responses": { "200": { "description": "Get session", @@ -1375,7 +1383,9 @@ } ], "summary": "Get session children", - "tags": ["Session"], + "tags": [ + "Session" + ], "description": "Retrieve all child sessions that were forked from the specified parent session.", "responses": { "200": { @@ -1558,7 +1568,11 @@ "pattern": "^msg.*" } }, - "required": ["modelID", "providerID", "messageID"] + "required": [ + "modelID", + "providerID", + "messageID" + ] } } } @@ -1955,12 +1969,20 @@ "modelID": { "type": "string" }, + "prompt": { + "description": "Prompt to use for compaction", + "type": "string" + }, "auto": { "default": false, "type": "boolean" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID", + "prompt" + ] } } } @@ -2023,7 +2045,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2097,7 +2122,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2143,7 +2171,10 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "agent": { "type": "string" @@ -2187,7 +2218,9 @@ } } }, - "required": ["parts"] + "required": [ + "parts" + ] } } } @@ -2250,7 +2283,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2519,7 +2555,10 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "agent": { "type": "string" @@ -2563,7 +2602,9 @@ } } }, - "required": ["parts"] + "required": [ + "parts" + ] } } } @@ -2617,7 +2658,10 @@ } } }, - "required": ["info", "parts"] + "required": [ + "info", + "parts" + ] } } } @@ -2695,13 +2739,20 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": ["type", "mime", "url"] + "required": [ + "type", + "mime", + "url" + ] } ] } } }, - "required": ["arguments", "command"] + "required": [ + "arguments", + "command" + ] } } } @@ -2788,13 +2839,19 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "command": { "type": "string" } }, - "required": ["agent", "command"] + "required": [ + "agent", + "command" + ] } } } @@ -2876,7 +2933,9 @@ "pattern": "^prt.*" } }, - "required": ["messageID"] + "required": [ + "messageID" + ] } } } @@ -3022,10 +3081,16 @@ "properties": { "response": { "type": "string", - "enum": ["once", "always", "reject"] + "enum": [ + "once", + "always", + "reject" + ] } }, - "required": ["response"] + "required": [ + "response" + ] } } } @@ -3100,13 +3165,19 @@ "properties": { "reply": { "type": "string", - "enum": ["once", "always", "reject"] + "enum": [ + "once", + "always", + "reject" + ] }, "message": { "type": "string" } }, - "required": ["reply"] + "required": [ + "reply" + ] } } } @@ -3261,7 +3332,9 @@ } } }, - "required": ["answers"] + "required": [ + "answers" + ] } } } @@ -3411,7 +3484,10 @@ } } }, - "required": ["providers", "default"] + "required": [ + "providers", + "default" + ] } } } @@ -3513,10 +3589,15 @@ "properties": { "field": { "type": "string", - "enum": ["reasoning_content", "reasoning_details"] + "enum": [ + "reasoning_content", + "reasoning_details" + ] } }, - "required": ["field"], + "required": [ + "field" + ], "additionalProperties": false } ] @@ -3552,10 +3633,16 @@ "type": "number" } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "limit": { "type": "object", @@ -3567,7 +3654,10 @@ "type": "number" } }, - "required": ["context", "output"] + "required": [ + "context", + "output" + ] }, "modalities": { "type": "object", @@ -3576,25 +3666,44 @@ "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } }, "output": { "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "experimental": { "type": "boolean" }, "status": { "type": "string", - "enum": ["alpha", "beta", "deprecated"] + "enum": [ + "alpha", + "beta", + "deprecated" + ] }, "options": { "type": "object", @@ -3619,7 +3728,9 @@ "type": "string" } }, - "required": ["npm"] + "required": [ + "npm" + ] }, "variants": { "type": "object", @@ -3649,7 +3760,12 @@ } } }, - "required": ["name", "env", "id", "models"] + "required": [ + "name", + "env", + "id", + "models" + ] } }, "default": { @@ -3668,7 +3784,11 @@ } } }, - "required": ["all", "default", "connected"] + "required": [ + "all", + "default", + "connected" + ] } } } @@ -3781,7 +3901,9 @@ "type": "number" } }, - "required": ["method"] + "required": [ + "method" + ] } } } @@ -3854,7 +3976,9 @@ "type": "string" } }, - "required": ["method"] + "required": [ + "method" + ] } } } @@ -3906,7 +4030,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] }, "lines": { "type": "object", @@ -3915,7 +4041,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] }, "line_number": { "type": "number" @@ -3935,7 +4063,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] }, "start": { "type": "number" @@ -3944,11 +4074,21 @@ "type": "number" } }, - "required": ["match", "start", "end"] + "required": [ + "match", + "start", + "end" + ] } } }, - "required": ["path", "lines", "line_number", "absolute_offset", "submatches"] + "required": [ + "path", + "lines", + "line_number", + "absolute_offset", + "submatches" + ] } } } @@ -3987,7 +4127,10 @@ "name": "dirs", "schema": { "type": "string", - "enum": ["true", "false"] + "enum": [ + "true", + "false" + ] } }, { @@ -3995,7 +4138,10 @@ "name": "type", "schema": { "type": "string", - "enum": ["file", "directory"] + "enum": [ + "file", + "directory" + ] } }, { @@ -4251,7 +4397,12 @@ "level": { "description": "Log level", "type": "string", - "enum": ["debug", "info", "error", "warn"] + "enum": [ + "debug", + "info", + "error", + "warn" + ] }, "message": { "description": "Log message", @@ -4266,7 +4417,11 @@ "additionalProperties": {} } }, - "required": ["service", "level", "message"] + "required": [ + "service", + "level", + "message" + ] } } } @@ -4416,7 +4571,10 @@ ] } }, - "required": ["name", "config"] + "required": [ + "name", + "config" + ] } } } @@ -4464,7 +4622,9 @@ "type": "string" } }, - "required": ["authorizationUrl"] + "required": [ + "authorizationUrl" + ] } } } @@ -4531,7 +4691,9 @@ "const": true } }, - "required": ["success"] + "required": [ + "success" + ] } } } @@ -4620,7 +4782,9 @@ "type": "string" } }, - "required": ["code"] + "required": [ + "code" + ] } } } @@ -4937,7 +5101,9 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] } } } @@ -5200,7 +5366,9 @@ "type": "string" } }, - "required": ["command"] + "required": [ + "command" + ] } } } @@ -5253,7 +5421,12 @@ }, "variant": { "type": "string", - "enum": ["info", "success", "warning", "error"] + "enum": [ + "info", + "success", + "warning", + "error" + ] }, "duration": { "description": "Duration in milliseconds", @@ -5261,7 +5434,10 @@ "type": "number" } }, - "required": ["message", "variant"] + "required": [ + "message", + "variant" + ] } } } @@ -5398,7 +5574,9 @@ "pattern": "^ses" } }, - "required": ["sessionID"] + "required": [ + "sessionID" + ] } } } @@ -5438,7 +5616,10 @@ }, "body": {} }, - "required": ["path", "body"] + "required": [ + "path", + "body" + ] } } } @@ -5605,10 +5786,15 @@ "type": "string" } }, - "required": ["version"] + "required": [ + "version" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.installation.update-available": { "type": "object", @@ -5624,10 +5810,15 @@ "type": "string" } }, - "required": ["version"] + "required": [ + "version" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Project": { "type": "object", @@ -5669,7 +5860,10 @@ "type": "number" } }, - "required": ["created", "updated"] + "required": [ + "created", + "updated" + ] }, "sandboxes": { "type": "array", @@ -5678,7 +5872,12 @@ } } }, - "required": ["id", "worktree", "time", "sandboxes"] + "required": [ + "id", + "worktree", + "time", + "sandboxes" + ] }, "Event.project.updated": { "type": "object", @@ -5691,7 +5890,10 @@ "$ref": "#/components/schemas/Project" } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.server.instance.disposed": { "type": "object", @@ -5707,10 +5909,15 @@ "type": "string" } }, - "required": ["directory"] + "required": [ + "directory" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.lsp.client.diagnostics": { "type": "object", @@ -5729,10 +5936,16 @@ "type": "string" } }, - "required": ["serverID", "path"] + "required": [ + "serverID", + "path" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.lsp.updated": { "type": "object", @@ -5746,7 +5959,10 @@ "properties": {} } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "FileDiff": { "type": "object", @@ -5767,7 +5983,13 @@ "type": "number" } }, - "required": ["file", "before", "after", "additions", "deletions"] + "required": [ + "file", + "before", + "after", + "additions", + "deletions" + ] }, "UserMessage": { "type": "object", @@ -5789,7 +6011,9 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] }, "summary": { "type": "object", @@ -5807,7 +6031,9 @@ } } }, - "required": ["diffs"] + "required": [ + "diffs" + ] }, "agent": { "type": "string" @@ -5822,7 +6048,10 @@ "type": "string" } }, - "required": ["providerID", "modelID"] + "required": [ + "providerID", + "modelID" + ] }, "system": { "type": "string" @@ -5840,7 +6069,14 @@ "type": "string" } }, - "required": ["id", "sessionID", "role", "time", "agent", "model"] + "required": [ + "id", + "sessionID", + "role", + "time", + "agent", + "model" + ] }, "ProviderAuthError": { "type": "object", @@ -5859,10 +6095,16 @@ "type": "string" } }, - "required": ["providerID", "message"] + "required": [ + "providerID", + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "UnknownError": { "type": "object", @@ -5878,10 +6120,15 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "MessageOutputLengthError": { "type": "object", @@ -5895,7 +6142,10 @@ "properties": {} } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "MessageAbortedError": { "type": "object", @@ -5911,10 +6161,15 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "APIError": { "type": "object", @@ -5957,10 +6212,16 @@ } } }, - "required": ["message", "isRetryable"] + "required": [ + "message", + "isRetryable" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "AssistantMessage": { "type": "object", @@ -5985,7 +6246,9 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] }, "error": { "anyOf": [ @@ -6031,7 +6294,10 @@ "type": "string" } }, - "required": ["cwd", "root"] + "required": [ + "cwd", + "root" + ] }, "summary": { "type": "boolean" @@ -6061,10 +6327,18 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] } }, - "required": ["input", "output", "reasoning", "cache"] + "required": [ + "input", + "output", + "reasoning", + "cache" + ] }, "finish": { "type": "string" @@ -6109,10 +6383,15 @@ "$ref": "#/components/schemas/Message" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.message.removed": { "type": "object", @@ -6131,10 +6410,16 @@ "type": "string" } }, - "required": ["sessionID", "messageID"] + "required": [ + "sessionID", + "messageID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "TextPart": { "type": "object", @@ -6171,7 +6456,9 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] }, "metadata": { "type": "object", @@ -6181,7 +6468,13 @@ "additionalProperties": {} } }, - "required": ["id", "sessionID", "messageID", "type", "text"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "text" + ] }, "ReasoningPart": { "type": "object", @@ -6219,10 +6512,19 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "text", "time"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "text", + "time" + ] }, "FilePartSourceText": { "type": "object", @@ -6241,7 +6543,11 @@ "maximum": 9007199254740991 } }, - "required": ["value", "start", "end"] + "required": [ + "value", + "start", + "end" + ] }, "FileSource": { "type": "object", @@ -6257,7 +6563,11 @@ "type": "string" } }, - "required": ["text", "type", "path"] + "required": [ + "text", + "type", + "path" + ] }, "Range": { "type": "object", @@ -6272,7 +6582,10 @@ "type": "number" } }, - "required": ["line", "character"] + "required": [ + "line", + "character" + ] }, "end": { "type": "object", @@ -6284,10 +6597,16 @@ "type": "number" } }, - "required": ["line", "character"] + "required": [ + "line", + "character" + ] } }, - "required": ["start", "end"] + "required": [ + "start", + "end" + ] }, "SymbolSource": { "type": "object", @@ -6314,7 +6633,14 @@ "maximum": 9007199254740991 } }, - "required": ["text", "type", "path", "range", "name", "kind"] + "required": [ + "text", + "type", + "path", + "range", + "name", + "kind" + ] }, "ResourceSource": { "type": "object", @@ -6333,7 +6659,12 @@ "type": "string" } }, - "required": ["text", "type", "clientName", "uri"] + "required": [ + "text", + "type", + "clientName", + "uri" + ] }, "FilePartSource": { "anyOf": [ @@ -6377,7 +6708,14 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": ["id", "sessionID", "messageID", "type", "mime", "url"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "mime", + "url" + ] }, "ToolStatePending": { "type": "object", @@ -6397,7 +6735,11 @@ "type": "string" } }, - "required": ["status", "input", "raw"] + "required": [ + "status", + "input", + "raw" + ] }, "ToolStateRunning": { "type": "object", @@ -6430,10 +6772,16 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] } }, - "required": ["status", "input", "time"] + "required": [ + "status", + "input", + "time" + ] }, "ToolStateCompleted": { "type": "object", @@ -6475,7 +6823,10 @@ "type": "number" } }, - "required": ["start", "end"] + "required": [ + "start", + "end" + ] }, "attachments": { "type": "array", @@ -6484,7 +6835,14 @@ } } }, - "required": ["status", "input", "output", "title", "metadata", "time"] + "required": [ + "status", + "input", + "output", + "title", + "metadata", + "time" + ] }, "ToolStateError": { "type": "object", @@ -6520,10 +6878,18 @@ "type": "number" } }, - "required": ["start", "end"] + "required": [ + "start", + "end" + ] } }, - "required": ["status", "input", "error", "time"] + "required": [ + "status", + "input", + "error", + "time" + ] }, "ToolState": { "anyOf": [ @@ -6574,7 +6940,15 @@ "additionalProperties": {} } }, - "required": ["id", "sessionID", "messageID", "type", "callID", "tool", "state"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "callID", + "tool", + "state" + ] }, "StepStartPart": { "type": "object", @@ -6596,7 +6970,12 @@ "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type"] + "required": [ + "id", + "sessionID", + "messageID", + "type" + ] }, "StepFinishPart": { "type": "object", @@ -6645,13 +7024,29 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] } }, - "required": ["input", "output", "reasoning", "cache"] + "required": [ + "input", + "output", + "reasoning", + "cache" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "reason", "cost", "tokens"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "reason", + "cost", + "tokens" + ] }, "SnapshotPart": { "type": "object", @@ -6673,7 +7068,13 @@ "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type", "snapshot"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "snapshot" + ] }, "PatchPart": { "type": "object", @@ -6701,7 +7102,14 @@ } } }, - "required": ["id", "sessionID", "messageID", "type", "hash", "files"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "hash", + "files" + ] }, "AgentPart": { "type": "object", @@ -6739,10 +7147,20 @@ "maximum": 9007199254740991 } }, - "required": ["value", "start", "end"] + "required": [ + "value", + "start", + "end" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "name"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "name" + ] }, "RetryPart": { "type": "object", @@ -6773,10 +7191,20 @@ "type": "number" } }, - "required": ["created"] + "required": [ + "created" + ] } }, - "required": ["id", "sessionID", "messageID", "type", "attempt", "error", "time"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "attempt", + "error", + "time" + ] }, "CompactionPart": { "type": "object", @@ -6796,9 +7224,19 @@ }, "auto": { "type": "boolean" + }, + "prompt": { + "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type", "auto"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "auto", + "prompt" + ] }, "Part": { "anyOf": [ @@ -6834,7 +7272,15 @@ "type": "string" } }, - "required": ["id", "sessionID", "messageID", "type", "prompt", "description", "agent"] + "required": [ + "id", + "sessionID", + "messageID", + "type", + "prompt", + "description", + "agent" + ] }, { "$ref": "#/components/schemas/ReasoningPart" @@ -6885,10 +7331,15 @@ "type": "string" } }, - "required": ["part"] + "required": [ + "part" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.message.part.removed": { "type": "object", @@ -6910,10 +7361,17 @@ "type": "string" } }, - "required": ["sessionID", "messageID", "partID"] + "required": [ + "sessionID", + "messageID", + "partID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "PermissionRequest": { "type": "object", @@ -6958,10 +7416,20 @@ "type": "string" } }, - "required": ["messageID", "callID"] + "required": [ + "messageID", + "callID" + ] } }, - "required": ["id", "sessionID", "permission", "patterns", "metadata", "always"] + "required": [ + "id", + "sessionID", + "permission", + "patterns", + "metadata", + "always" + ] }, "Event.permission.asked": { "type": "object", @@ -6974,7 +7442,10 @@ "$ref": "#/components/schemas/PermissionRequest" } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.permission.replied": { "type": "object", @@ -6994,13 +7465,24 @@ }, "reply": { "type": "string", - "enum": ["once", "always", "reject"] + "enum": [ + "once", + "always", + "reject" + ] } }, - "required": ["sessionID", "requestID", "reply"] + "required": [ + "sessionID", + "requestID", + "reply" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "SessionStatus": { "anyOf": [ @@ -7012,7 +7494,9 @@ "const": "idle" } }, - "required": ["type"] + "required": [ + "type" + ] }, { "type": "object", @@ -7031,7 +7515,12 @@ "type": "number" } }, - "required": ["type", "attempt", "message", "next"] + "required": [ + "type", + "attempt", + "message", + "next" + ] }, { "type": "object", @@ -7041,7 +7530,9 @@ "const": "busy" } }, - "required": ["type"] + "required": [ + "type" + ] } ] }, @@ -7062,10 +7553,16 @@ "$ref": "#/components/schemas/SessionStatus" } }, - "required": ["sessionID", "status"] + "required": [ + "sessionID", + "status" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.idle": { "type": "object", @@ -7081,10 +7578,15 @@ "type": "string" } }, - "required": ["sessionID"] + "required": [ + "sessionID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "QuestionOption": { "type": "object", @@ -7098,7 +7600,10 @@ "type": "string" } }, - "required": ["label", "description"] + "required": [ + "label", + "description" + ] }, "QuestionInfo": { "type": "object", @@ -7128,7 +7633,11 @@ "type": "boolean" } }, - "required": ["question", "header", "options"] + "required": [ + "question", + "header", + "options" + ] }, "QuestionRequest": { "type": "object", @@ -7158,10 +7667,17 @@ "type": "string" } }, - "required": ["messageID", "callID"] + "required": [ + "messageID", + "callID" + ] } }, - "required": ["id", "sessionID", "questions"] + "required": [ + "id", + "sessionID", + "questions" + ] }, "Event.question.asked": { "type": "object", @@ -7174,7 +7690,10 @@ "$ref": "#/components/schemas/QuestionRequest" } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "QuestionAnswer": { "type": "array", @@ -7205,10 +7724,17 @@ } } }, - "required": ["sessionID", "requestID", "answers"] + "required": [ + "sessionID", + "requestID", + "answers" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.question.rejected": { "type": "object", @@ -7227,10 +7753,16 @@ "type": "string" } }, - "required": ["sessionID", "requestID"] + "required": [ + "sessionID", + "requestID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.compacted": { "type": "object", @@ -7246,10 +7778,15 @@ "type": "string" } }, - "required": ["sessionID"] + "required": [ + "sessionID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.file.edited": { "type": "object", @@ -7265,10 +7802,15 @@ "type": "string" } }, - "required": ["file"] + "required": [ + "file" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Todo": { "type": "object", @@ -7290,7 +7832,12 @@ "type": "string" } }, - "required": ["content", "status", "priority", "id"] + "required": [ + "content", + "status", + "priority", + "id" + ] }, "Event.todo.updated": { "type": "object", @@ -7312,10 +7859,16 @@ } } }, - "required": ["sessionID", "todos"] + "required": [ + "sessionID", + "todos" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.prompt.append": { "type": "object", @@ -7331,10 +7884,15 @@ "type": "string" } }, - "required": ["text"] + "required": [ + "text" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.command.execute": { "type": "object", @@ -7373,10 +7931,15 @@ ] } }, - "required": ["command"] + "required": [ + "command" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.toast.show": { "type": "object", @@ -7396,7 +7959,12 @@ }, "variant": { "type": "string", - "enum": ["info", "success", "warning", "error"] + "enum": [ + "info", + "success", + "warning", + "error" + ] }, "duration": { "description": "Duration in milliseconds", @@ -7404,10 +7972,16 @@ "type": "number" } }, - "required": ["message", "variant"] + "required": [ + "message", + "variant" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.tui.session.select": { "type": "object", @@ -7425,10 +7999,15 @@ "pattern": "^ses" } }, - "required": ["sessionID"] + "required": [ + "sessionID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.mcp.tools.changed": { "type": "object", @@ -7444,10 +8023,15 @@ "type": "string" } }, - "required": ["server"] + "required": [ + "server" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.command.executed": { "type": "object", @@ -7474,14 +8058,26 @@ "pattern": "^msg.*" } }, - "required": ["name", "sessionID", "arguments", "messageID"] + "required": [ + "name", + "sessionID", + "arguments", + "messageID" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "PermissionAction": { "type": "string", - "enum": ["allow", "deny", "ask"] + "enum": [ + "allow", + "deny", + "ask" + ] }, "PermissionRule": { "type": "object", @@ -7496,7 +8092,11 @@ "$ref": "#/components/schemas/PermissionAction" } }, - "required": ["permission", "pattern", "action"] + "required": [ + "permission", + "pattern", + "action" + ] }, "PermissionRuleset": { "type": "array", @@ -7543,7 +8143,11 @@ } } }, - "required": ["additions", "deletions", "files"] + "required": [ + "additions", + "deletions", + "files" + ] }, "share": { "type": "object", @@ -7552,7 +8156,9 @@ "type": "string" } }, - "required": ["url"] + "required": [ + "url" + ] }, "title": { "type": "string" @@ -7576,7 +8182,10 @@ "type": "number" } }, - "required": ["created", "updated"] + "required": [ + "created", + "updated" + ] }, "permission": { "$ref": "#/components/schemas/PermissionRuleset" @@ -7597,10 +8206,20 @@ "type": "string" } }, - "required": ["messageID"] + "required": [ + "messageID" + ] } }, - "required": ["id", "slug", "projectID", "directory", "title", "version", "time"] + "required": [ + "id", + "slug", + "projectID", + "directory", + "title", + "version", + "time" + ] }, "Event.session.created": { "type": "object", @@ -7616,10 +8235,15 @@ "$ref": "#/components/schemas/Session" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.updated": { "type": "object", @@ -7635,10 +8259,15 @@ "$ref": "#/components/schemas/Session" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.deleted": { "type": "object", @@ -7654,10 +8283,15 @@ "$ref": "#/components/schemas/Session" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.diff": { "type": "object", @@ -7679,10 +8313,16 @@ } } }, - "required": ["sessionID", "diff"] + "required": [ + "sessionID", + "diff" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.session.error": { "type": "object", @@ -7719,7 +8359,10 @@ } } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.file.watcher.updated": { "type": "object", @@ -7751,10 +8394,16 @@ ] } }, - "required": ["file", "event"] + "required": [ + "file", + "event" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.vcs.branch.updated": { "type": "object", @@ -7772,7 +8421,10 @@ } } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Pty": { "type": "object", @@ -7798,13 +8450,24 @@ }, "status": { "type": "string", - "enum": ["running", "exited"] + "enum": [ + "running", + "exited" + ] }, "pid": { "type": "number" } }, - "required": ["id", "title", "command", "args", "cwd", "status", "pid"] + "required": [ + "id", + "title", + "command", + "args", + "cwd", + "status", + "pid" + ] }, "Event.pty.created": { "type": "object", @@ -7820,10 +8483,15 @@ "$ref": "#/components/schemas/Pty" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.pty.updated": { "type": "object", @@ -7839,10 +8507,15 @@ "$ref": "#/components/schemas/Pty" } }, - "required": ["info"] + "required": [ + "info" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.pty.exited": { "type": "object", @@ -7862,10 +8535,16 @@ "type": "number" } }, - "required": ["id", "exitCode"] + "required": [ + "id", + "exitCode" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.pty.deleted": { "type": "object", @@ -7882,10 +8561,15 @@ "pattern": "^pty.*" } }, - "required": ["id"] + "required": [ + "id" + ] } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.server.connected": { "type": "object", @@ -7899,7 +8583,10 @@ "properties": {} } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event.global.disposed": { "type": "object", @@ -7913,7 +8600,10 @@ "properties": {} } }, - "required": ["type", "properties"] + "required": [ + "type", + "properties" + ] }, "Event": { "anyOf": [ @@ -8046,7 +8736,10 @@ "$ref": "#/components/schemas/Event" } }, - "required": ["directory", "payload"] + "required": [ + "directory", + "payload" + ] }, "BadRequestError": { "type": "object", @@ -8067,7 +8760,11 @@ "const": false } }, - "required": ["data", "errors", "success"] + "required": [ + "data", + "errors", + "success" + ] }, "NotFoundError": { "type": "object", @@ -8083,10 +8780,15 @@ "type": "string" } }, - "required": ["message"] + "required": [ + "message" + ] } }, - "required": ["name", "data"] + "required": [ + "name", + "data" + ] }, "KeybindsConfig": { "description": "Custom keybind configurations", @@ -8533,7 +9235,12 @@ "LogLevel": { "description": "Log level", "type": "string", - "enum": ["DEBUG", "INFO", "WARN", "ERROR"] + "enum": [ + "DEBUG", + "INFO", + "WARN", + "ERROR" + ] }, "ServerConfig": { "description": "Server configuration for opencode serve and web commands", @@ -8565,7 +9272,11 @@ }, "PermissionActionConfig": { "type": "string", - "enum": ["ask", "allow", "deny"] + "enum": [ + "ask", + "allow", + "deny" + ] }, "PermissionObjectConfig": { "type": "object", @@ -8689,7 +9400,11 @@ }, "mode": { "type": "string", - "enum": ["subagent", "primary", "all"] + "enum": [ + "subagent", + "primary", + "all" + ] }, "hidden": { "description": "Hide this subagent from the @ autocomplete menu (default: false, only applies to mode: subagent)", @@ -8789,10 +9504,15 @@ "properties": { "field": { "type": "string", - "enum": ["reasoning_content", "reasoning_details"] + "enum": [ + "reasoning_content", + "reasoning_details" + ] } }, - "required": ["field"], + "required": [ + "field" + ], "additionalProperties": false } ] @@ -8828,10 +9548,16 @@ "type": "number" } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "limit": { "type": "object", @@ -8843,7 +9569,10 @@ "type": "number" } }, - "required": ["context", "output"] + "required": [ + "context", + "output" + ] }, "modalities": { "type": "object", @@ -8852,25 +9581,44 @@ "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } }, "output": { "type": "array", "items": { "type": "string", - "enum": ["text", "audio", "image", "video", "pdf"] + "enum": [ + "text", + "audio", + "image", + "video", + "pdf" + ] } } }, - "required": ["input", "output"] + "required": [ + "input", + "output" + ] }, "experimental": { "type": "boolean" }, "status": { "type": "string", - "enum": ["alpha", "beta", "deprecated"] + "enum": [ + "alpha", + "beta", + "deprecated" + ] }, "options": { "type": "object", @@ -8895,7 +9643,9 @@ "type": "string" } }, - "required": ["npm"] + "required": [ + "npm" + ] }, "variants": { "description": "Variant-specific configuration", @@ -9004,7 +9754,10 @@ "maximum": 9007199254740991 } }, - "required": ["type", "command"], + "required": [ + "type", + "command" + ], "additionalProperties": false }, "McpOAuthConfig": { @@ -9070,13 +9823,19 @@ "maximum": 9007199254740991 } }, - "required": ["type", "url"], + "required": [ + "type", + "url" + ], "additionalProperties": false }, "LayoutConfig": { "description": "@deprecated Always uses stretch layout.", "type": "string", - "enum": ["auto", "stretch"] + "enum": [ + "auto", + "stretch" + ] }, "Config": { "type": "object", @@ -9113,12 +9872,17 @@ "type": "boolean" } }, - "required": ["enabled"] + "required": [ + "enabled" + ] }, "diff_style": { "description": "Control diff rendering style: 'auto' adapts to terminal width, 'stacked' always shows single column", "type": "string", - "enum": ["auto", "stacked"] + "enum": [ + "auto", + "stacked" + ] } } }, @@ -9148,9 +9912,14 @@ }, "subtask": { "type": "boolean" + }, + "compact": { + "type": "boolean" } }, - "required": ["template"] + "required": [ + "template" + ] } }, "watcher": { @@ -9176,7 +9945,11 @@ "share": { "description": "Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing", "type": "string", - "enum": ["manual", "auto", "disabled"] + "enum": [ + "manual", + "auto", + "disabled" + ] }, "autoshare": { "description": "@deprecated Use 'share' field instead. Share newly created sessions automatically", @@ -9224,6 +9997,10 @@ "description": "Custom username to display in conversations instead of system username", "type": "string" }, + "auto_compact_command": { + "description": "Command to use for automatic compaction when context limit is reached. Defaults to 'compact'", + "type": "string" + }, "mode": { "description": "@deprecated Use `agent` field instead.", "type": "object", @@ -9304,7 +10081,9 @@ "type": "boolean" } }, - "required": ["enabled"], + "required": [ + "enabled" + ], "additionalProperties": false } ] @@ -9374,7 +10153,9 @@ "const": true } }, - "required": ["disabled"] + "required": [ + "disabled" + ] }, { "type": "object", @@ -9411,7 +10192,9 @@ "additionalProperties": {} } }, - "required": ["command"] + "required": [ + "command" + ] } ] } @@ -9494,7 +10277,9 @@ } } }, - "required": ["command"] + "required": [ + "command" + ] } } }, @@ -9519,7 +10304,9 @@ } } }, - "required": ["command"] + "required": [ + "command" + ] } } } @@ -9578,7 +10365,11 @@ }, "parameters": {} }, - "required": ["id", "description", "parameters"] + "required": [ + "id", + "description", + "parameters" + ] }, "ToolList": { "type": "array", @@ -9605,7 +10396,13 @@ "type": "string" } }, - "required": ["home", "state", "config", "worktree", "directory"] + "required": [ + "home", + "state", + "config", + "worktree", + "directory" + ] }, "Worktree": { "type": "object", @@ -9620,7 +10417,11 @@ "type": "string" } }, - "required": ["name", "branch", "directory"] + "required": [ + "name", + "branch", + "directory" + ] }, "WorktreeCreateInput": { "type": "object", @@ -9640,7 +10441,9 @@ "type": "string" } }, - "required": ["branch"] + "required": [ + "branch" + ] }, "TextPartInput": { "type": "object", @@ -9671,7 +10474,9 @@ "type": "number" } }, - "required": ["start"] + "required": [ + "start" + ] }, "metadata": { "type": "object", @@ -9681,7 +10486,10 @@ "additionalProperties": {} } }, - "required": ["type", "text"] + "required": [ + "type", + "text" + ] }, "FilePartInput": { "type": "object", @@ -9706,7 +10514,11 @@ "$ref": "#/components/schemas/FilePartSource" } }, - "required": ["type", "mime", "url"] + "required": [ + "type", + "mime", + "url" + ] }, "AgentPartInput": { "type": "object", @@ -9738,10 +10550,17 @@ "maximum": 9007199254740991 } }, - "required": ["value", "start", "end"] + "required": [ + "value", + "start", + "end" + ] } }, - "required": ["type", "name"] + "required": [ + "type", + "name" + ] }, "SubtaskPartInput": { "type": "object", @@ -9766,7 +10585,12 @@ "type": "string" } }, - "required": ["type", "prompt", "description", "agent"] + "required": [ + "type", + "prompt", + "description", + "agent" + ] }, "Command": { "type": "object", @@ -9799,6 +10623,9 @@ "subtask": { "type": "boolean" }, + "compact": { + "type": "boolean" + }, "hints": { "type": "array", "items": { @@ -9806,7 +10633,11 @@ } } }, - "required": ["name", "template", "hints"] + "required": [ + "name", + "template", + "hints" + ] }, "Model": { "type": "object", @@ -9830,7 +10661,11 @@ "type": "string" } }, - "required": ["id", "url", "npm"] + "required": [ + "id", + "url", + "npm" + ] }, "name": { "type": "string" @@ -9872,7 +10707,13 @@ "type": "boolean" } }, - "required": ["text", "audio", "image", "video", "pdf"] + "required": [ + "text", + "audio", + "image", + "video", + "pdf" + ] }, "output": { "type": "object", @@ -9893,7 +10734,13 @@ "type": "boolean" } }, - "required": ["text", "audio", "image", "video", "pdf"] + "required": [ + "text", + "audio", + "image", + "video", + "pdf" + ] }, "interleaved": { "anyOf": [ @@ -9905,15 +10752,28 @@ "properties": { "field": { "type": "string", - "enum": ["reasoning_content", "reasoning_details"] + "enum": [ + "reasoning_content", + "reasoning_details" + ] } }, - "required": ["field"] + "required": [ + "field" + ] } ] } }, - "required": ["temperature", "reasoning", "attachment", "toolcall", "input", "output", "interleaved"] + "required": [ + "temperature", + "reasoning", + "attachment", + "toolcall", + "input", + "output", + "interleaved" + ] }, "cost": { "type": "object", @@ -9934,7 +10794,10 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] }, "experimentalOver200K": { "type": "object", @@ -9955,13 +10818,24 @@ "type": "number" } }, - "required": ["read", "write"] + "required": [ + "read", + "write" + ] } }, - "required": ["input", "output", "cache"] + "required": [ + "input", + "output", + "cache" + ] } }, - "required": ["input", "output", "cache"] + "required": [ + "input", + "output", + "cache" + ] }, "limit": { "type": "object", @@ -9973,11 +10847,19 @@ "type": "number" } }, - "required": ["context", "output"] + "required": [ + "context", + "output" + ] }, "status": { "type": "string", - "enum": ["alpha", "beta", "deprecated", "active"] + "enum": [ + "alpha", + "beta", + "deprecated", + "active" + ] }, "options": { "type": "object", @@ -10037,7 +10919,12 @@ }, "source": { "type": "string", - "enum": ["env", "config", "custom", "api"] + "enum": [ + "env", + "config", + "custom", + "api" + ] }, "env": { "type": "array", @@ -10065,7 +10952,14 @@ } } }, - "required": ["id", "name", "source", "env", "options", "models"] + "required": [ + "id", + "name", + "source", + "env", + "options", + "models" + ] }, "ProviderAuthMethod": { "type": "object", @@ -10086,7 +10980,10 @@ "type": "string" } }, - "required": ["type", "label"] + "required": [ + "type", + "label" + ] }, "ProviderAuthAuthorization": { "type": "object", @@ -10110,7 +11007,11 @@ "type": "string" } }, - "required": ["url", "method", "instructions"] + "required": [ + "url", + "method", + "instructions" + ] }, "Symbol": { "type": "object", @@ -10131,10 +11032,17 @@ "$ref": "#/components/schemas/Range" } }, - "required": ["uri", "range"] + "required": [ + "uri", + "range" + ] } }, - "required": ["name", "kind", "location"] + "required": [ + "name", + "kind", + "location" + ] }, "FileNode": { "type": "object", @@ -10150,13 +11058,22 @@ }, "type": { "type": "string", - "enum": ["file", "directory"] + "enum": [ + "file", + "directory" + ] }, "ignored": { "type": "boolean" } }, - "required": ["name", "path", "absolute", "type", "ignored"] + "required": [ + "name", + "path", + "absolute", + "type", + "ignored" + ] }, "FileContent": { "type": "object", @@ -10210,14 +11127,24 @@ } } }, - "required": ["oldStart", "oldLines", "newStart", "newLines", "lines"] + "required": [ + "oldStart", + "oldLines", + "newStart", + "newLines", + "lines" + ] } }, "index": { "type": "string" } }, - "required": ["oldFileName", "newFileName", "hunks"] + "required": [ + "oldFileName", + "newFileName", + "hunks" + ] }, "encoding": { "type": "string", @@ -10227,7 +11154,10 @@ "type": "string" } }, - "required": ["type", "content"] + "required": [ + "type", + "content" + ] }, "File": { "type": "object", @@ -10247,10 +11177,19 @@ }, "status": { "type": "string", - "enum": ["added", "deleted", "modified"] + "enum": [ + "added", + "deleted", + "modified" + ] } }, - "required": ["path", "added", "removed", "status"] + "required": [ + "path", + "added", + "removed", + "status" + ] }, "Agent": { "type": "object", @@ -10263,7 +11202,11 @@ }, "mode": { "type": "string", - "enum": ["subagent", "primary", "all"] + "enum": [ + "subagent", + "primary", + "all" + ] }, "native": { "type": "boolean" @@ -10293,7 +11236,10 @@ "type": "string" } }, - "required": ["modelID", "providerID"] + "required": [ + "modelID", + "providerID" + ] }, "prompt": { "type": "string" @@ -10311,7 +11257,12 @@ "maximum": 9007199254740991 } }, - "required": ["name", "mode", "permission", "options"] + "required": [ + "name", + "mode", + "permission", + "options" + ] }, "MCPStatusConnected": { "type": "object", @@ -10321,7 +11272,9 @@ "const": "connected" } }, - "required": ["status"] + "required": [ + "status" + ] }, "MCPStatusDisabled": { "type": "object", @@ -10331,7 +11284,9 @@ "const": "disabled" } }, - "required": ["status"] + "required": [ + "status" + ] }, "MCPStatusFailed": { "type": "object", @@ -10344,7 +11299,10 @@ "type": "string" } }, - "required": ["status", "error"] + "required": [ + "status", + "error" + ] }, "MCPStatusNeedsAuth": { "type": "object", @@ -10354,7 +11312,9 @@ "const": "needs_auth" } }, - "required": ["status"] + "required": [ + "status" + ] }, "MCPStatusNeedsClientRegistration": { "type": "object", @@ -10367,7 +11327,10 @@ "type": "string" } }, - "required": ["status", "error"] + "required": [ + "status", + "error" + ] }, "MCPStatus": { "anyOf": [ @@ -10407,7 +11370,11 @@ "type": "string" } }, - "required": ["name", "uri", "client"] + "required": [ + "name", + "uri", + "client" + ] }, "LSPStatus": { "type": "object", @@ -10434,7 +11401,12 @@ ] } }, - "required": ["id", "name", "root", "status"] + "required": [ + "id", + "name", + "root", + "status" + ] }, "FormatterStatus": { "type": "object", @@ -10452,7 +11424,11 @@ "type": "boolean" } }, - "required": ["name", "extensions", "enabled"] + "required": [ + "name", + "extensions", + "enabled" + ] }, "OAuth": { "type": "object", @@ -10477,7 +11453,12 @@ "type": "string" } }, - "required": ["type", "refresh", "access", "expires"] + "required": [ + "type", + "refresh", + "access", + "expires" + ] }, "ApiAuth": { "type": "object", @@ -10490,7 +11471,10 @@ "type": "string" } }, - "required": ["type", "key"] + "required": [ + "type", + "key" + ] }, "WellKnownAuth": { "type": "object", @@ -10506,7 +11490,11 @@ "type": "string" } }, - "required": ["type", "key", "token"] + "required": [ + "type", + "key", + "token" + ] }, "Auth": { "anyOf": [ @@ -10523,4 +11511,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/web/src/content/docs/commands.mdx b/packages/web/src/content/docs/commands.mdx index 2e7db2bcf0a..3bfcc756fd2 100644 --- a/packages/web/src/content/docs/commands.mdx +++ b/packages/web/src/content/docs/commands.mdx @@ -312,6 +312,31 @@ This is an **optional** config option. --- +### Compact + +The `/compact` command performs **session compaction** - summarizing conversation history and removing all previous messages from context, replacing them with the summary. This reduces context size while preserving important information about what happened in the session. + +This command is called automatically when OpenCode reaches its token limit threshold (see [`compaction.auto`](/docs/config#compaction)). You can also run it manually at any time. + +To customize compaction: + +1. **Override the built-in command** - Create a custom `/compact` command using the patterns described above +2. **Create a new compact command** - Mark any command with `compact: true` and configure [`compaction.command`](/docs/config#compaction) to specify which command is used for automatic compaction + +The command body will be used as the summary prompt. + +```md title=".opencode/command/handover.md" +--- +description: Hand over session to next developer +compact: true +--- + +Summarize this session for the next developer. +Include key decisions and next steps. +``` + +--- + ## Built-in opencode includes several built-in commands like `/init`, `/undo`, `/redo`, `/share`, `/help`; [learn more](/docs/tui#commands). diff --git a/packages/web/src/content/docs/config.mdx b/packages/web/src/content/docs/config.mdx index 30edbbd2146..d7457c5a7ae 100644 --- a/packages/web/src/content/docs/config.mdx +++ b/packages/web/src/content/docs/config.mdx @@ -483,13 +483,17 @@ You can control context compaction behavior through the `compaction` option. "$schema": "https://opencode.ai/config.json", "compaction": { "auto": true, - "prune": true + "prune": true, + "command": "compact" } } ``` - `auto` - Automatically compact the session when context is full (default: `true`). - `prune` - Remove old tool outputs to save tokens (default: `true`). +- `command` - Command to use for automatic compaction when context limit is reached (default: `"compact"`). + +[Learn more about compaction](/docs/commands#compact). ---