summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTimo Clasen <[email protected]>2025-07-08 22:37:25 +0200
committerGitHub <[email protected]>2025-07-08 15:37:25 -0500
commit1e07384364d6ec42239f8fdebcffc66f340c3761 (patch)
tree4d90b925f5d2aa5e87fabff0c72cd3a1d67af441
parent4c4739c422edd0b43275b38aa1a031a0626f995d (diff)
downloadopencode-1e07384364d6ec42239f8fdebcffc66f340c3761.tar.gz
opencode-1e07384364d6ec42239f8fdebcffc66f340c3761.zip
fix: make compact command interruptible (#691)
Co-authored-by: GitHub Action <[email protected]>
-rw-r--r--packages/opencode/src/session/index.ts60
-rw-r--r--packages/tui/internal/app/app.go24
2 files changed, 71 insertions, 13 deletions
diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts
index ed9dff24a..a039b42e5 100644
--- a/packages/opencode/src/session/index.ts
+++ b/packages/opencode/src/session/index.ts
@@ -873,20 +873,58 @@ export namespace Session {
},
})
- for await (const value of result.fullStream) {
- switch (value.type) {
- case "text":
- if (!text) {
- text = {
- type: "text",
- text: value.text,
- }
- next.parts.push(text)
- } else text.text += value.text
- await updateMessage(next)
+ try {
+ for await (const value of result.fullStream) {
+ switch (value.type) {
+ case "text":
+ if (!text) {
+ text = {
+ type: "text",
+ text: value.text,
+ }
+ next.parts.push(text)
+ } else text.text += value.text
+ await updateMessage(next)
+ break
+ }
+ }
+ } catch (e: any) {
+ log.error("summarize stream error", {
+ error: e,
+ })
+ switch (true) {
+ case e instanceof DOMException && e.name === "AbortError":
+ next.error = new MessageV2.AbortedError(
+ { message: e.message },
+ {
+ cause: e,
+ },
+ ).toObject()
break
+ case MessageV2.OutputLengthError.isInstance(e):
+ next.error = e
+ break
+ case LoadAPIKeyError.isInstance(e):
+ next.error = new Provider.AuthError(
+ {
+ providerID: input.providerID,
+ message: e.message,
+ },
+ { cause: e },
+ ).toObject()
+ break
+ case e instanceof Error:
+ next.error = new NamedError.Unknown({ message: e.toString() }, { cause: e }).toObject()
+ break
+ default:
+ next.error = new NamedError.Unknown({ message: JSON.stringify(e) }, { cause: e }).toObject()
}
+ Bus.publish(Event.Error, {
+ error: next.error,
+ })
}
+ next.time.completed = Date.now()
+ await updateMessage(next)
}
function lock(sessionID: string) {
diff --git a/packages/tui/internal/app/app.go b/packages/tui/internal/app/app.go
index b7911b56e..83934343e 100644
--- a/packages/tui/internal/app/app.go
+++ b/packages/tui/internal/app/app.go
@@ -35,6 +35,7 @@ type App struct {
Commands commands.CommandRegistry
InitialModel *string
InitialPrompt *string
+ compactCancel context.CancelFunc
}
type SessionSelectedMsg = *opencode.Session
@@ -306,13 +307,26 @@ func (a *App) InitializeProject(ctx context.Context) tea.Cmd {
}
func (a *App) CompactSession(ctx context.Context) tea.Cmd {
+ if a.compactCancel != nil {
+ a.compactCancel()
+ }
+
+ compactCtx, cancel := context.WithCancel(ctx)
+ a.compactCancel = cancel
+
go func() {
- _, err := a.Client.Session.Summarize(ctx, a.Session.ID, opencode.SessionSummarizeParams{
+ defer func() {
+ a.compactCancel = nil
+ }()
+
+ _, err := a.Client.Session.Summarize(compactCtx, a.Session.ID, opencode.SessionSummarizeParams{
ProviderID: opencode.F(a.Provider.ID),
ModelID: opencode.F(a.Model.ID),
})
if err != nil {
- slog.Error("Failed to compact session", "error", err)
+ if compactCtx.Err() != context.Canceled {
+ slog.Error("Failed to compact session", "error", err)
+ }
}
}()
return nil
@@ -415,6 +429,12 @@ func (a *App) SendChatMessage(
}
func (a *App) Cancel(ctx context.Context, sessionID string) error {
+ // Cancel any running compact operation
+ if a.compactCancel != nil {
+ a.compactCancel()
+ a.compactCancel = nil
+ }
+
_, err := a.Client.Session.Abort(ctx, sessionID)
if err != nil {
slog.Error("Failed to cancel session", "error", err)