Download src/auto-reply/reply/agent-runner-core.test.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 8.77 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/auto-reply/reply/agent-runner-core.test.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/auto-reply/reply/agent-runner-core.test.ts
-
curl -L -o agent-runner-core.test.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/auto-reply/reply/agent-runner-core.test.ts
8.77 kB
| import { describe, expect, it, onTestFinished } from "vitest"; | |
| import { testing as cliBackendsTesting } from "../../agents/cli-backends.test-support.js"; | |
| import { resolveFallbackTransition } from "../fallback-state.js"; | |
| import type { TemplateContext } from "../templating.js"; | |
| import { | |
| buildSilentFallbackFailurePayload, | |
| resolveAdmittedRunSessionFile, | |
| resolveReplyRunDeliveryContext, | |
| } from "./agent-runner-core.js"; | |
| import type { RuntimeFallbackAttempt } from "./agent-runner-execution.types.js"; | |
| describe("resolveAdmittedRunSessionFile", () => { | |
| it("uses the scoped session key when one is available", () => { | |
| expect( | |
| resolveAdmittedRunSessionFile({ | |
| agentId: "main", | |
| sessionId: "session", | |
| sessionFile: "legacy-target", | |
| sessionKey: " agent:main:session ", | |
| storePath: "/tmp/sessions.json", | |
| }), | |
| ).toBe("agent:main:session"); | |
| }); | |
| it("preserves the admitted fallback when a persisted run has no session key", () => { | |
| expect( | |
| resolveAdmittedRunSessionFile({ | |
| agentId: "main", | |
| sessionId: "session", | |
| sessionFile: "legacy-target", | |
| storePath: "/tmp/sessions.json", | |
| }), | |
| ).toBe("legacy-target"); | |
| }); | |
| }); | |
| describe("resolveReplyRunDeliveryContext", () => { | |
| it.each([ | |
| { name: "numeric message topic", messageThreadId: 99, threadId: 99 }, | |
| { name: "numeric transport topic", transportThreadId: 99, threadId: 99 }, | |
| { name: "message topic precedence", messageThreadId: 99, transportThreadId: 77, threadId: 99 }, | |
| { name: "string message topic", messageThreadId: "99", threadId: "99" }, | |
| { name: "session identity fallback", threadId: "12345:99" }, | |
| ])("preserves the $name", ({ messageThreadId, transportThreadId, threadId }) => { | |
| expect( | |
| resolveReplyRunDeliveryContext({ | |
| cfg: {}, | |
| sessionCtx: { | |
| Provider: "telegram", | |
| OriginatingChannel: "telegram", | |
| OriginatingTo: "telegram:12345", | |
| AccountId: "work", | |
| MessageThreadId: messageThreadId, | |
| TransportThreadId: transportThreadId, | |
| SessionKey: "agent:main:telegram:direct:12345:thread:12345:99", | |
| } as TemplateContext, | |
| sessionKey: "agent:main:telegram:direct:12345:thread:12345:99", | |
| }), | |
| ).toEqual({ | |
| channel: "telegram", | |
| to: "telegram:12345", | |
| accountId: "work", | |
| threadId, | |
| }); | |
| }); | |
| }); | |
| describe("buildSilentFallbackFailurePayload", () => { | |
| const selected = { provider: "openrouter", model: "z-ai/glm-5.3" }; | |
| const other = { provider: "amazon-bedrock", model: "claude-haiku" }; | |
| const transition = resolveFallbackTransition({ | |
| selectedProvider: selected.provider, | |
| selectedModel: selected.model, | |
| activeProvider: other.provider, | |
| activeModel: other.model, | |
| attempts: [], | |
| }); | |
| const base = { | |
| fallbackTransition: transition, | |
| fallbackFailureKnown: true, | |
| cfg: {}, | |
| isHeartbeat: false, | |
| hasSuccessfulTerminalDelivery: false, | |
| }; | |
| const attempt = ( | |
| reason: RuntimeFallbackAttempt["reason"], | |
| identity: Partial<RuntimeFallbackAttempt> = {}, | |
| ): RuntimeFallbackAttempt => ({ ...selected, error: "provider failed", reason, ...identity }); | |
| it.each(["timeout", "server_error", "overloaded", "tls_certificate"] as const)( | |
| "uses unreachable wording for selected-backend %s evidence", | |
| (reason) => { | |
| const payload = buildSilentFallbackFailurePayload({ | |
| ...base, | |
| fallbackAttempts: [attempt(reason)], | |
| }); | |
| expect(payload?.text).toContain("couldn't reach the configured model backend"); | |
| expect(payload?.text).toContain(transition.selectedModelRef); | |
| expect(payload?.text).toContain(transition.activeModelRef); | |
| expect(payload?.isError).toBe(true); | |
| }, | |
| ); | |
| it.each(["format", "empty_response"] as const)( | |
| "uses response wording for selected-backend %s evidence", | |
| (reason) => { | |
| const payload = buildSilentFallbackFailurePayload({ | |
| ...base, | |
| fallbackAttempts: [attempt(reason)], | |
| }); | |
| expect(payload?.text).toContain("responded but produced no usable reply"); | |
| expect(payload?.text).not.toContain("couldn't reach"); | |
| }, | |
| ); | |
| it.each([ | |
| { label: "empty evidence", attempts: [] }, | |
| { label: "unknown reason", attempts: [attempt("unknown")] }, | |
| { label: "auth skip", attempts: [attempt("auth")] }, | |
| { label: "auth with synthesized status", attempts: [attempt("auth", { status: 401 })] }, | |
| { label: "permanent auth", attempts: [attempt("auth_permanent")] }, | |
| { label: "billing", attempts: [attempt("billing")] }, | |
| { label: "rate limit", attempts: [attempt("rate_limit")] }, | |
| ...(["timeout", "overloaded", "format", "empty_response"] as const).map((reason) => ({ | |
| label: `local skip retaining ${reason}`, | |
| attempts: [attempt(reason, { code: "MODEL_FALLBACK_SKIPPED" })], | |
| })), | |
| { | |
| label: "local skip beside a response", | |
| attempts: [attempt("format"), attempt("format", { code: "MODEL_FALLBACK_SKIPPED" })], | |
| }, | |
| { label: "transport then response", attempts: [attempt("timeout"), attempt("format")] }, | |
| { label: "response then transport", attempts: [attempt("format"), attempt("timeout")] }, | |
| { label: "other backend only", attempts: [attempt("format", other)] }, | |
| { label: "other model only", attempts: [attempt("format", { model: "different" })] }, | |
| { label: "unattributed response", attempts: [attempt("format", { provider: "", model: "" })] }, | |
| { | |
| label: "unattributed transport", | |
| attempts: [attempt("timeout", { provider: "", model: "" })], | |
| }, | |
| { | |
| label: "incomplete evidence beside response", | |
| attempts: [attempt("format"), attempt("timeout", { provider: "" })], | |
| }, | |
| { | |
| label: "incomplete evidence beside transport", | |
| attempts: [attempt("timeout"), attempt("format", { model: " " })], | |
| }, | |
| ])("keeps $label cause-neutral", ({ attempts }) => { | |
| const payload = buildSilentFallbackFailurePayload({ ...base, fallbackAttempts: attempts }); | |
| expect(payload?.text).toContain("produced no usable reply"); | |
| expect(payload?.text).not.toContain("responded"); | |
| expect(payload?.text).not.toContain("couldn't reach"); | |
| }); | |
| it.each([ | |
| { | |
| selectedReason: "format", | |
| otherReason: "timeout", | |
| expected: "responded but produced no usable reply", | |
| }, | |
| { | |
| selectedReason: "timeout", | |
| otherReason: "format", | |
| expected: "couldn't reach the configured model backend", | |
| }, | |
| ] as const)( | |
| "ignores another backend's $otherReason evidence", | |
| ({ selectedReason, otherReason, expected }) => { | |
| const payload = buildSilentFallbackFailurePayload({ | |
| ...base, | |
| fallbackAttempts: [attempt(otherReason, other), attempt(selectedReason)], | |
| }); | |
| expect(payload?.text).toContain(expected); | |
| }, | |
| ); | |
| it("uses the configured runtime alias when attributing a response", () => { | |
| // Exercise attribution with setup metadata; the plugin registration test owns | |
| // the real Claude CLI descriptor and its canonical provider binding. | |
| onTestFinished(() => cliBackendsTesting.resetDepsForTest()); | |
| cliBackendsTesting.setDepsForTest({ | |
| resolveRuntimeCliBackends: () => [], | |
| resolvePluginSetupCliBackend: ({ backend }) => | |
| backend === "claude-cli" | |
| ? { | |
| pluginId: "anthropic", | |
| backend: { | |
| id: "claude-cli", | |
| modelProvider: "anthropic", | |
| config: { command: "claude" }, | |
| }, | |
| } | |
| : undefined, | |
| }); | |
| const cfg = { plugins: { allow: ["anthropic"], entries: { anthropic: { enabled: true } } } }; | |
| const fallbackTransition = resolveFallbackTransition({ | |
| selectedProvider: "anthropic", | |
| selectedModel: "claude-sonnet-4-6", | |
| activeProvider: "openai", | |
| activeModel: "gpt-5.5", | |
| attempts: [], | |
| cfg, | |
| }); | |
| const payload = buildSilentFallbackFailurePayload({ | |
| ...base, | |
| cfg, | |
| fallbackTransition, | |
| fallbackAttempts: [attempt("format", { provider: "claude-cli", model: "claude-sonnet-4-6" })], | |
| }); | |
| expect(payload?.text).toContain("responded but produced no usable reply"); | |
| }); | |
| it.each([ | |
| { isHeartbeat: true }, | |
| { hasSuccessfulTerminalDelivery: true }, | |
| { allowEmptyAssistantReplyAsSilent: true }, | |
| { silentExpected: true }, | |
| { hasExplicitSilentReply: true }, | |
| { fallbackFailureKnown: false }, | |
| { fallbackTransition: { ...transition, fallbackActive: false } }, | |
| ])("preserves warning suppression %j", (suppression) => { | |
| expect( | |
| buildSilentFallbackFailurePayload({ | |
| ...base, | |
| ...suppression, | |
| fallbackAttempts: [attempt("format")], | |
| }), | |
| ).toBeUndefined(); | |
| }); | |
| }); | |