mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 08:20:43 +00:00
fix(hooks): honor configured ollama slug timeout (#66455)
This commit is contained in:
@@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Browser: keep loopback CDP readiness checks reachable under strict SSRF defaults so OpenClaw can reconnect to locally started managed Chrome. (#66354) Thanks @hxy91819.
|
||||
- Agents/context engine: compact engine-owned sessions from the first tool-loop delta and preserve ingest fallback when `afterTurn` is absent, so long-running tool loops can stay bounded without dropping engine state. (#63555) Thanks @Bikkies.
|
||||
- Discord/native commands: return the real status card for native `/status` interactions instead of falling through to the synthetic `✅ Done.` ack when the generic dispatcher produces no visible reply. (#54629) Thanks @tkozzer and @vincentkoc.
|
||||
- Hooks/Ollama: let LLM-backed session-memory slug generation honor an explicit `agents.defaults.timeoutSeconds` override instead of always aborting after 15 seconds, so slow local Ollama runs stop silently dropping back to generic filenames. (#66237) Thanks @dmak and @vincentkoc.
|
||||
|
||||
## 2026.4.14-beta.1
|
||||
|
||||
|
||||
60
src/hooks/llm-slug-generator.test.ts
Normal file
60
src/hooks/llm-slug-generator.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
|
||||
const runEmbeddedPiAgentMock = vi.fn();
|
||||
|
||||
vi.mock("../agents/agent-scope.js", () => ({
|
||||
resolveDefaultAgentId: vi.fn(() => "main"),
|
||||
resolveAgentWorkspaceDir: vi.fn(() => "/tmp/openclaw-agent"),
|
||||
resolveAgentDir: vi.fn(() => "/tmp/openclaw-agent/.openclaw-agent"),
|
||||
resolveAgentEffectiveModelPrimary: vi.fn(() => null),
|
||||
}));
|
||||
|
||||
vi.mock("../agents/pi-embedded.js", () => ({
|
||||
runEmbeddedPiAgent: (...args: unknown[]) => runEmbeddedPiAgentMock(...args),
|
||||
}));
|
||||
|
||||
import { generateSlugViaLLM } from "./llm-slug-generator.js";
|
||||
|
||||
describe("generateSlugViaLLM", () => {
|
||||
beforeEach(() => {
|
||||
runEmbeddedPiAgentMock.mockReset();
|
||||
runEmbeddedPiAgentMock.mockResolvedValue({
|
||||
payloads: [{ text: "test-slug" }],
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the helper default timeout when no agent timeout is configured", async () => {
|
||||
await generateSlugViaLLM({
|
||||
sessionContent: "hello",
|
||||
cfg: {} as OpenClawConfig,
|
||||
});
|
||||
|
||||
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
|
||||
expect(runEmbeddedPiAgentMock.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
timeoutMs: 15_000,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("honors configured agent timeoutSeconds for slow local providers", async () => {
|
||||
await generateSlugViaLLM({
|
||||
sessionContent: "hello",
|
||||
cfg: {
|
||||
agents: {
|
||||
defaults: {
|
||||
timeoutSeconds: 500,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
});
|
||||
|
||||
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
|
||||
expect(runEmbeddedPiAgentMock.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
timeoutMs: 500_000,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -14,11 +14,21 @@ import {
|
||||
import { DEFAULT_PROVIDER, DEFAULT_MODEL } from "../agents/defaults.js";
|
||||
import { parseModelRef } from "../agents/model-selection.js";
|
||||
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
|
||||
import { resolveAgentTimeoutMs } from "../agents/timeout.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
const log = createSubsystemLogger("llm-slug-generator");
|
||||
const DEFAULT_SLUG_GENERATOR_TIMEOUT_MS = 15_000;
|
||||
|
||||
function resolveSlugGeneratorTimeoutMs(cfg: OpenClawConfig): number {
|
||||
const configuredTimeoutSeconds = cfg.agents?.defaults?.timeoutSeconds;
|
||||
if (typeof configuredTimeoutSeconds !== "number" || !Number.isFinite(configuredTimeoutSeconds)) {
|
||||
return DEFAULT_SLUG_GENERATOR_TIMEOUT_MS;
|
||||
}
|
||||
return resolveAgentTimeoutMs({ cfg });
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a short 1-2 word filename slug from session content using LLM
|
||||
@@ -50,6 +60,7 @@ Reply with ONLY the slug, nothing else. Examples: "vendor-pitch", "api-design",
|
||||
const parsed = modelRef ? parseModelRef(modelRef, DEFAULT_PROVIDER) : null;
|
||||
const provider = parsed?.provider ?? DEFAULT_PROVIDER;
|
||||
const model = parsed?.model ?? DEFAULT_MODEL;
|
||||
const timeoutMs = resolveSlugGeneratorTimeoutMs(params.cfg);
|
||||
|
||||
const result = await runEmbeddedPiAgent({
|
||||
sessionId: `slug-generator-${Date.now()}`,
|
||||
@@ -62,7 +73,7 @@ Reply with ONLY the slug, nothing else. Examples: "vendor-pitch", "api-design",
|
||||
prompt,
|
||||
provider,
|
||||
model,
|
||||
timeoutMs: 15_000, // 15 second timeout
|
||||
timeoutMs,
|
||||
runId: `slug-gen-${Date.now()}`,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user