fix(web-inspector): drop stale Try from here results

This commit is contained in:
Alem Tuzlak
2026-08-28 15:01:06 +02:00
parent c71dcfbb12
commit ec146f6721
3 changed files with 75 additions and 5 deletions
@@ -625,6 +625,67 @@ test("Try from here copies a stored thread into Playground without changing the
}
});
test("Try from here discards a stale copy after leaving Threads", async () => {
const context = await setup({
agent: true,
agentIds: ["default"],
threads: [SAVED_THREAD],
});
try {
await context.open();
await context.selectLeaf("threads");
await selectSavedThread(context.inspector);
const pendingFetch = globalThis.fetch;
let releaseMessages!: () => void;
let messagesResolved = false;
const messagesGate = new Promise<void>((resolve) => {
releaseMessages = resolve;
});
vi.stubGlobal(
"fetch",
async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input instanceof Request ? input.url : String(input);
const isMessages = url.endsWith("/threads/thread-1/messages");
if (isMessages) {
await messagesGate;
}
const response = await pendingFetch(input, init);
if (isMessages) {
messagesResolved = true;
}
return response;
},
);
const root = requireElement(
context.inspector.shadowRoot,
"Web Inspector shadow root was not rendered",
);
const button = requireElement(
tryFromHereButton(root),
"Try from here was not rendered",
);
button.click();
await context.selectLeaf("home");
expectCurrentNavigation(root, "home", "home");
releaseMessages();
await waitFor(() => messagesResolved, "stale Try from here load");
await context.inspector.updateComplete;
expectCurrentNavigation(root, "home", "home");
await context.selectLeaf("playground");
expect(root.textContent).not.toContain("Earlier answer");
expect(
root.querySelector<HTMLSelectElement>("#cpk-playground-thread-source")
?.value ?? "",
).not.toBe("thread-1");
} finally {
context.teardown();
}
});
test("Try from here stays on Threads when messages fail", async () => {
const context = await setup({
agent: true,
+13 -4
View File
@@ -14779,19 +14779,28 @@ export class WebInspectorElement extends LitElement {
this.tryFromHereError = null;
this.requestUpdate();
const isCurrentTryFromHereRequest = (): boolean =>
this.selectedThreadId === threadId && this.selectedMenu === "threads";
try {
const snapshot = await this.loadThreadSnapshot(thread);
this.applyThreadSnapshotToPlayground(thread, snapshot);
// A later thread or pane change owns the UI. Keep the fetch outcome
// for telemetry, but do not replace Playground or leave Threads.
if (isCurrentTryFromHereRequest()) {
this.applyThreadSnapshotToPlayground(thread, snapshot);
this.handleMenuSelect("playground");
}
if (!this.core?.telemetryDisabled) {
trackThreadsTryFromHereClicked({
...this.getThreadsTelemetryProps(),
outcome: "success",
});
}
this.handleMenuSelect("playground");
} catch (error) {
this.tryFromHereError =
error instanceof Error ? error.message : "Failed to load thread.";
if (isCurrentTryFromHereRequest()) {
this.tryFromHereError =
error instanceof Error ? error.message : "Failed to load thread.";
}
if (!this.core?.telemetryDisabled) {
trackThreadsTryFromHereClicked({
...this.getThreadsTelemetryProps(),
+1 -1
View File
@@ -82,7 +82,7 @@ The button is hidden on example tour threads and when thread inspect cannot load
- Map stored thread messages onto Playground agent messages (user, assistant, tool), then `clone()` the source agent, assign a new Playground thread id, `setMessages`, `setState`.
- Fetch the snapshot first. Replace the scratch session only after a successful messages load. This is the control flow from the grill (not a demo):
```
```text
snapshot = loadThread(threadId)
if snapshot.messagesFailed:
showErrorOnThreads(error)