diff --git a/extensions/llama-cpp/src/inference-provider.test.ts b/extensions/llama-cpp/src/inference-provider.test.ts index 63bc58a09c21..e35030c26f6b 100644 --- a/extensions/llama-cpp/src/inference-provider.test.ts +++ b/extensions/llama-cpp/src/inference-provider.test.ts @@ -768,11 +768,14 @@ describe("llama.cpp inference provider", () => { rejectCleanup = reject; }); mocks.contextDispose.mockImplementationOnce(async () => await cleanup); - await createTestStream({ prompt: "three" }); + const failedSwitch = await createTestStream({ prompt: "three" }); await vi.waitFor(() => expect(mocks.contextDispose).toHaveBeenCalledTimes(2)); const unavailable = await createTestStream({ selectedModel: otherModel, prompt: "four" }); const disposing = inferenceRuntime.dispose(); rejectCleanup(new Error("context cleanup failed")); + await expect(failedSwitch.result()).resolves.toMatchObject({ + errorMessage: expect.stringContaining("openclaw gateway restart"), + }); await expect(unavailable.result()).resolves.toMatchObject({ errorMessage: expect.stringContaining("openclaw gateway restart"), }); @@ -784,7 +787,10 @@ describe("llama.cpp inference provider", () => { it("records cleanup failure during partial model initialization", async () => { mocks.model.createContext.mockRejectedValueOnce(new Error("context creation failed")); mocks.modelDispose.mockRejectedValueOnce(new Error("model cleanup failed")); - await collectTestEvents(); + const failedInitialization = await createTestStream(); + await expect(failedInitialization.result()).resolves.toMatchObject({ + errorMessage: expect.stringContaining("openclaw gateway restart"), + }); await expect(inferenceRuntime.dispose()).rejects.toThrow("model cleanup failed"); expectDisposeCalls(0, 1, 0); }); diff --git a/extensions/llama-cpp/src/inference-provider.ts b/extensions/llama-cpp/src/inference-provider.ts index 3e295f6fb577..f077aca88deb 100644 --- a/extensions/llama-cpp/src/inference-provider.ts +++ b/extensions/llama-cpp/src/inference-provider.ts @@ -86,6 +86,12 @@ function buildMessage(params: { }; } +function runtimeUnavailableErrorMessage(state: LlamaCppInferenceRuntimeState): string { + return state.cleanupFailure + ? "llama.cpp runtime stopped after cleanup failed. Run `openclaw gateway restart` to recover." + : "llama.cpp runtime is stopping"; +} + function runtimeUnavailableMessage( state: LlamaCppInferenceRuntimeState, model: Parameters[0], @@ -94,9 +100,7 @@ function runtimeUnavailableMessage( model, content: [], stopReason: "error", - errorMessage: state.cleanupFailure - ? "llama.cpp runtime stopped after cleanup failed. Run `openclaw gateway restart` to recover." - : "llama.cpp runtime is stopping", + errorMessage: runtimeUnavailableErrorMessage(state), }); } @@ -682,7 +686,11 @@ function createLlamaCppStreamFnForRuntime( } catch (error) { const aborted = generationAborted || options?.signal?.aborted === true; const reason = aborted ? "aborted" : "error"; - const errorMessage = aborted ? "Request was aborted" : formatLlamaCppSetupError(error); + const errorMessage = aborted + ? "Request was aborted" + : state.cleanupFailure + ? runtimeUnavailableErrorMessage(state) + : formatLlamaCppSetupError(error); stream.push({ type: "error", reason,