fix(quick-pane): recover catalog after bridge restarts
Treat missing stale runtimes as already closed and defer thinking reconciliation until the refreshed model catalog is ready.
This commit is contained in:
@@ -459,6 +459,52 @@ describe("QuickPane", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("recovers a stale Quick runtime and keeps persisted thinking after bridge restart", async () => {
|
||||||
|
const thinkingModels: Model[] = [
|
||||||
|
{
|
||||||
|
provider: "provider",
|
||||||
|
id: "quick/model",
|
||||||
|
reasoning: true,
|
||||||
|
thinkingLevelMap: { high: "high" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const persistedSettings = {
|
||||||
|
...settings,
|
||||||
|
defaultThinkingLevel: "high",
|
||||||
|
};
|
||||||
|
const tracker = bridgeMock([thinkingModels, thinkingModels], undefined, {
|
||||||
|
...uiState,
|
||||||
|
quickPane: persistedSettings,
|
||||||
|
});
|
||||||
|
const invoke = mocks.invoke.getMockImplementation();
|
||||||
|
mocks.invoke.mockImplementation(
|
||||||
|
(command: string, payload?: { runtimeId?: string }) => {
|
||||||
|
if (
|
||||||
|
command === "close_quick_runtime" &&
|
||||||
|
payload?.runtimeId === "runtime-1"
|
||||||
|
)
|
||||||
|
return Promise.reject(
|
||||||
|
new Error("unknown session runtime: stale-runtime-id"),
|
||||||
|
);
|
||||||
|
return invoke?.(command, payload);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
render(<QuickPane />);
|
||||||
|
await preparedTrigger();
|
||||||
|
const settingsListener = mocks.listen.mock.calls.find(
|
||||||
|
([event]) => event === "quick-pane-settings-saved",
|
||||||
|
)?.[1] as ((event: { payload: QuickPaneSettings }) => void) | undefined;
|
||||||
|
expect(settingsListener).toBeTypeOf("function");
|
||||||
|
|
||||||
|
await act(async () => settingsListener?.({ payload: persistedSettings }));
|
||||||
|
|
||||||
|
await waitFor(() => expect(tracker.runtimeCount()).toBe(2));
|
||||||
|
expect(screen.queryByText(/unknown session runtime/)).toBeNull();
|
||||||
|
expect(screen.getByRole("combobox", { name: "Thinking" })).toHaveValue(
|
||||||
|
"high",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("derives thinking choices from selected model metadata and falls back to Off", async () => {
|
it("derives thinking choices from selected model metadata and falls back to Off", async () => {
|
||||||
const thinkingModels: Model[] = [
|
const thinkingModels: Model[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -341,10 +341,11 @@ export default function QuickPane() {
|
|||||||
!!extension;
|
!!extension;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (catalogStatus !== "ready") return;
|
||||||
setThinkingLevel((current) =>
|
setThinkingLevel((current) =>
|
||||||
reconcileThinkingLevel(selectedCatalogModel, current),
|
reconcileThinkingLevel(selectedCatalogModel, current),
|
||||||
);
|
);
|
||||||
}, [selectedCatalogModel]);
|
}, [catalogStatus, selectedCatalogModel]);
|
||||||
|
|
||||||
const recordInputSelection = (input: HTMLTextAreaElement) => {
|
const recordInputSelection = (input: HTMLTextAreaElement) => {
|
||||||
if (
|
if (
|
||||||
@@ -468,6 +469,9 @@ export default function QuickPane() {
|
|||||||
|
|
||||||
cleanupQueueRef.current.add(runtimeId);
|
cleanupQueueRef.current.add(runtimeId);
|
||||||
const cleanup = invoke("close_quick_runtime", { runtimeId })
|
const cleanup = invoke("close_quick_runtime", { runtimeId })
|
||||||
|
.catch((reason) => {
|
||||||
|
if (!String(reason).includes("unknown session runtime:")) throw reason;
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
cleanupQueueRef.current.delete(runtimeId);
|
cleanupQueueRef.current.delete(runtimeId);
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user