diff --git a/src/client/src/api.ts b/src/client/src/api.ts index c0a582a..5188e31 100644 --- a/src/client/src/api.ts +++ b/src/client/src/api.ts @@ -108,6 +108,7 @@ export const api = { shell: (sessionId: string, text: string) => request(`/api/sessions/${sessionId}/shell`, parseAccepted, { method: "POST", body: JSON.stringify({ text }) }), runCommand: (sessionId: string, text: string) => request(`/api/sessions/${sessionId}/commands/run`, parseCommandResult, { method: "POST", body: JSON.stringify({ text }) }), respondToCommand: (sessionId: string, requestId: string, value: string) => request(`/api/sessions/${sessionId}/commands/respond`, parseCommandResult, { method: "POST", body: JSON.stringify({ requestId, value }) }), + abort: (sessionId: string) => request(`/api/sessions/${sessionId}/abort`, parseAborted, { method: "POST" }), stop: (sessionId: string) => request(`/api/sessions/${sessionId}/stop`, parseStopped, { method: "POST" }), archive: (sessionId: string) => request(`/api/sessions/${sessionId}/archive`, parseArchived, { method: "POST" }), restore: (sessionId: string) => request(`/api/sessions/${sessionId}/restore`, parseRestored, { method: "POST" }), @@ -300,6 +301,12 @@ function parseAccepted(value: unknown): { accepted: true } { return { accepted: true }; } +function parseAborted(value: unknown): { aborted: true } { + const record = requireRecord(value); + if (record["aborted"] !== true) throw new Error("Expected aborted response"); + return { aborted: true }; +} + function parseStopped(value: unknown): { stopped: true } { const record = requireRecord(value); if (record["stopped"] !== true) throw new Error("Expected stopped response"); diff --git a/src/client/src/components/PiWebApp.ts b/src/client/src/components/PiWebApp.ts index 79b937f..ebcddb1 100644 --- a/src/client/src/components/PiWebApp.ts +++ b/src/client/src/components/PiWebApp.ts @@ -115,7 +115,7 @@ export class PiWebApp extends LitElement { ${state.error ? html`
${state.error}
` : null} ${state.selectedSession ? html` 0} .loadingMore=${state.isLoadingEarlierMessages} .isCompacting=${state.status?.isCompacting === true} .pendingMessageCount=${state.status?.pendingMessageCount ?? 0} .onLoadMore=${() => this.withChatPrependTransition(() => this.sessions.loadEarlierMessages())}> - this.sessions.send(text, streamingBehavior)} .onStopSession=${() => this.sessions.stopSession()}> + this.sessions.send(text, streamingBehavior)} .onStop=${() => this.sessions.stopActiveWork()}> ${state.commandDialog !== undefined ? html` this.sessions.respondToCommand(state.commandDialog?.requestId ?? "", value)} .onCancel=${() => { this.sessions.cancelCommand(); }}>` : null} ` : html`
Select or start a session.
`} diff --git a/src/client/src/components/PromptEditor.ts b/src/client/src/components/PromptEditor.ts index 01041b7..a17ee7f 100644 --- a/src/client/src/components/PromptEditor.ts +++ b/src/client/src/components/PromptEditor.ts @@ -12,8 +12,9 @@ export class PromptEditor extends LitElement { @property() cwd?: string; @property({ type: Boolean }) canSteer = false; @property({ type: Boolean }) isCompacting = false; + @property({ type: Boolean }) canStop = false; @property({ attribute: false }) onSend?: (text: string, streamingBehavior?: "steer" | "followUp") => void; - @property({ attribute: false }) onStopSession?: () => void; + @property({ attribute: false }) onStop?: () => void; @query("textarea") private textarea?: HTMLTextAreaElement; @state() private draft = ""; @state() private completions: CompletionItem[] = []; @@ -56,7 +57,7 @@ export class PromptEditor extends LitElement {
${this.canSteer && !this.isCompacting ? html`` : null} - +
`; diff --git a/src/client/src/controllers/sessionController.ts b/src/client/src/controllers/sessionController.ts index dfdb32e..9e40b86 100644 --- a/src/client/src/controllers/sessionController.ts +++ b/src/client/src/controllers/sessionController.ts @@ -167,16 +167,13 @@ export class SessionController { } } - async stopSession() { + async stopActiveWork() { const session = this.getState().selectedSession; if (!session) return; try { - await api.stop(session.id); + await api.abort(session.id); } catch (error) { this.setState({ error: String(error) }); - } finally { - this.clearActiveSession(); - this.updateUrl(); } } diff --git a/src/server/sessions/piSessionService.ts b/src/server/sessions/piSessionService.ts index f42617e..a2edc95 100644 --- a/src/server/sessions/piSessionService.ts +++ b/src/server/sessions/piSessionService.ts @@ -180,7 +180,10 @@ export class PiSessionService { async abort(sessionId: string): Promise { const active = this.active.get(sessionId); - if (active) await active.runtime.session.abort(); + if (!active) return; + await active.runtime.session.abort(); + this.publishActivity(active.runtime.session, "stopped", "idle"); + this.publishStatus(active.runtime.session); } stop(sessionId: string): void {