Restart conversation support.
The idea here is to let the user restart the conversation, possibly with
a better prompt. This is a common manual workflow, and I'd like to make
it easier.
I hand wrote the agent.go stuff, but Sketch wrote the rest.
Co-Authored-By: sketch <hello@sketch.dev>
diff --git a/webui/src/web-components/sketch-app-shell.ts b/webui/src/web-components/sketch-app-shell.ts
index 3ee27f6..1cd1a0b 100644
--- a/webui/src/web-components/sketch-app-shell.ts
+++ b/webui/src/web-components/sketch-app-shell.ts
@@ -13,6 +13,7 @@
import "./sketch-terminal";
import "./sketch-timeline";
import "./sketch-view-mode-select";
+import "./sketch-restart-modal";
import { createRef, ref } from "lit/directives/ref.js";
@@ -229,6 +230,27 @@
margin-right: 50px;
}
+ .restart-button {
+ background: #2196f3;
+ color: white;
+ border: none;
+ padding: 4px 10px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 12px;
+ margin-right: 5px;
+ }
+
+ .restart-button:hover {
+ background-color: #0b7dda;
+ }
+
+ .restart-button:disabled {
+ background-color: #ccc;
+ cursor: not-allowed;
+ opacity: 0.6;
+ }
+
.refresh-button {
background: #4caf50;
color: white;
@@ -304,8 +326,14 @@
outstanding_tool_calls: [],
session_id: "",
ssh_available: false,
+ ssh_error: "",
+ in_container: false,
+ first_message_index: 0,
};
+ @state()
+ private restartModalOpen = false;
+
// Mutation observer to detect when new messages are added
private mutationObserver: MutationObserver | null = null;
@@ -706,10 +734,6 @@
this.updateDocumentTitle();
}
- /**
- * Handle stop button click
- * Sends a request to the server to stop the current operation
- */
// Update last commit information when new messages arrive
private updateLastCommitInfo(newMessages: AgentMessage[]): void {
if (!newMessages || newMessages.length === 0) return;
@@ -782,6 +806,14 @@
}
}
+ openRestartModal() {
+ this.restartModalOpen = true;
+ }
+
+ handleRestartModalClose() {
+ this.restartModalOpen = false;
+ }
+
async _sendChat(e: CustomEvent) {
console.log("app shell: _sendChat", e);
const message = e.detail.message?.trim();
@@ -867,10 +899,14 @@
<div class="refresh-control">
<button
- id="stopButton"
- class="refresh-button stop-button"
- @click="${this._handleStopClick}"
+ id="restartButton"
+ class="restart-button"
+ ?disabled=${this.containerState.message_count === 0}
+ @click=${this.openRestartModal}
>
+ Restart
+ </button>
+ <button id="stopButton" class="refresh-button stop-button">
Stop
</button>
@@ -939,6 +975,13 @@
<div id="chat-input">
<sketch-chat-input @send-chat="${this._sendChat}"></sketch-chat-input>
</div>
+
+ <sketch-restart-modal
+ ?open=${this.restartModalOpen}
+ @close=${this.handleRestartModalClose}
+ .containerState=${this.containerState}
+ .messages=${this.messages}
+ ></sketch-restart-modal>
`;
}
@@ -956,6 +999,27 @@
50,
);
+ // Setup stop button
+ const stopButton = this.renderRoot?.querySelector(
+ "#stopButton",
+ ) as HTMLButtonElement;
+ stopButton?.addEventListener("click", async () => {
+ try {
+ const response = await fetch("/cancel", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ reason: "User clicked stop button" }),
+ });
+ if (!response.ok) {
+ console.error("Failed to cancel:", await response.text());
+ }
+ } catch (error) {
+ console.error("Error cancelling operation:", error);
+ }
+ });
+
const pollToggleCheckbox = this.renderRoot?.querySelector(
"#pollToggle",
) as HTMLInputElement;