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 {