mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
fix(auto-reply): harden fallback lifecycle formatting
This commit is contained in:
committed by
joshavant
parent
9baae38704
commit
241d39daea
@@ -66,6 +66,19 @@ describe("fallback-state", () => {
|
||||
expect(resolved.nextState.activeModel).toBe("deepinfra/moonshotai/Kimi-K2.5");
|
||||
});
|
||||
|
||||
it("normalizes fallback reason whitespace for summaries", () => {
|
||||
const resolved = resolveFallbackTransition({
|
||||
selectedProvider: "fireworks",
|
||||
selectedModel: "fireworks/minimax-m2p5",
|
||||
activeProvider: "deepinfra",
|
||||
activeModel: "moonshotai/Kimi-K2.5",
|
||||
attempts: [{ ...baseAttempt, reason: "rate_limit\n\tburst" }],
|
||||
state: {},
|
||||
});
|
||||
|
||||
expect(resolved.reasonSummary).toBe("rate limit burst");
|
||||
});
|
||||
|
||||
it("refreshes reason when fallback remains active with same model pair", () => {
|
||||
const resolved = resolveFallbackTransition({
|
||||
selectedProvider: "fireworks",
|
||||
|
||||
@@ -15,7 +15,9 @@ export function normalizeFallbackModelRef(value?: string): string | undefined {
|
||||
}
|
||||
|
||||
function truncateFallbackReasonPart(value: string, max = FALLBACK_REASON_PART_MAX): string {
|
||||
const text = String(value ?? "").trim();
|
||||
const text = String(value ?? "")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
if (text.length <= max) {
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -509,6 +509,30 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
||||
expect(onToolResult).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("retries transient HTTP failures once with timer-driven backoff", async () => {
|
||||
vi.useFakeTimers();
|
||||
let calls = 0;
|
||||
state.runEmbeddedPiAgentMock.mockImplementation(async () => {
|
||||
calls += 1;
|
||||
if (calls === 1) {
|
||||
throw new Error("502 Bad Gateway");
|
||||
}
|
||||
return { payloads: [{ text: "final" }], meta: {} };
|
||||
});
|
||||
|
||||
const { run } = createMinimalRun({
|
||||
typingMode: "message",
|
||||
});
|
||||
const runPromise = run();
|
||||
|
||||
await vi.advanceTimersByTimeAsync(2_499);
|
||||
expect(calls).toBe(1);
|
||||
await vi.advanceTimersByTimeAsync(1);
|
||||
await runPromise;
|
||||
expect(calls).toBe(2);
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("announces auto-compaction in verbose mode and tracks count", async () => {
|
||||
await withTempStateDir(async (stateDir) => {
|
||||
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
||||
|
||||
@@ -83,4 +83,57 @@ describe("app-tool-stream fallback lifecycle handling", () => {
|
||||
expect(host.fallbackStatus).toBeNull();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("auto-clears fallback status after toast duration", () => {
|
||||
vi.useFakeTimers();
|
||||
const host = createHost();
|
||||
|
||||
handleAgentEvent(host, {
|
||||
runId: "run-1",
|
||||
seq: 1,
|
||||
stream: "lifecycle",
|
||||
ts: Date.now(),
|
||||
sessionKey: "main",
|
||||
data: {
|
||||
phase: "fallback",
|
||||
selectedProvider: "fireworks",
|
||||
selectedModel: "fireworks/minimax-m2p5",
|
||||
activeProvider: "deepinfra",
|
||||
activeModel: "moonshotai/Kimi-K2.5",
|
||||
},
|
||||
});
|
||||
|
||||
expect(host.fallbackStatus).not.toBeNull();
|
||||
vi.advanceTimersByTime(7_999);
|
||||
expect(host.fallbackStatus).not.toBeNull();
|
||||
vi.advanceTimersByTime(1);
|
||||
expect(host.fallbackStatus).toBeNull();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("builds previous fallback label from provider + model on fallback_cleared", () => {
|
||||
vi.useFakeTimers();
|
||||
const host = createHost();
|
||||
|
||||
handleAgentEvent(host, {
|
||||
runId: "run-1",
|
||||
seq: 1,
|
||||
stream: "lifecycle",
|
||||
ts: Date.now(),
|
||||
sessionKey: "main",
|
||||
data: {
|
||||
phase: "fallback_cleared",
|
||||
selectedProvider: "fireworks",
|
||||
selectedModel: "fireworks/minimax-m2p5",
|
||||
activeProvider: "fireworks",
|
||||
activeModel: "fireworks/minimax-m2p5",
|
||||
previousActiveProvider: "deepinfra",
|
||||
previousActiveModel: "moonshotai/Kimi-K2.5",
|
||||
},
|
||||
});
|
||||
|
||||
expect(host.fallbackStatus?.phase).toBe("cleared");
|
||||
expect(host.fallbackStatus?.previous).toBe("deepinfra/moonshotai/Kimi-K2.5");
|
||||
vi.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -339,8 +339,8 @@ function handleLifecycleFallbackEvent(host: CompactionHost, payload: AgentEventP
|
||||
resolveModelLabel(data.activeProvider, data.activeModel) ??
|
||||
resolveModelLabel(data.toProvider, data.toModel);
|
||||
const previous =
|
||||
toTrimmedString(data.previousActiveModel) ??
|
||||
resolveModelLabel(data.previousActiveProvider, data.previousActiveModel);
|
||||
resolveModelLabel(data.previousActiveProvider, data.previousActiveModel) ??
|
||||
toTrimmedString(data.previousActiveModel);
|
||||
if (!selected || !active) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user