diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index ed9dff24..a039b42e 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) - break + 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 b7911b56..83934343 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)