Skip to content

Commit 3976f4e

Browse files
test: add OrcaRouter unit tests
core/llm/llms/OrcaRouter.vitest.ts — seven cases covering provider name, default options, attribution header injection, user header override, and Anthropic prompt-caching pass-through (patterned on OpenRouter.vitest.ts). packages/openai-adapters/src/apis/OrcaRouter.test.ts — four cases covering default apiBase, custom apiBase override, attribution headers, and standard OpenAI headers (patterned on ClawRouter.test.ts).
1 parent 722c4cb commit 3976f4e

2 files changed

Lines changed: 220 additions & 0 deletions

File tree

core/llm/llms/OrcaRouter.vitest.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import { ChatCompletionCreateParams } from "openai/resources/index";
2+
import { describe, expect, it } from "vitest";
3+
4+
import OrcaRouter from "./OrcaRouter";
5+
6+
describe("OrcaRouter", () => {
7+
it("uses the correct providerName and default apiBase", () => {
8+
expect(OrcaRouter.providerName).toBe("orcarouter");
9+
expect(OrcaRouter.defaultOptions?.apiBase).toBe(
10+
"https://api.orcarouter.ai/v1/",
11+
);
12+
expect(OrcaRouter.defaultOptions?.model).toBe("orcarouter/auto");
13+
});
14+
15+
it("injects OrcaRouter attribution headers", () => {
16+
const orcaRouter = new OrcaRouter({
17+
model: "orcarouter/auto",
18+
apiKey: "sk-orca-test",
19+
});
20+
21+
const headers = (orcaRouter as any).requestOptions?.headers ?? {};
22+
expect(headers["HTTP-Referer"]).toBe("https://www.continue.dev/");
23+
expect(headers["X-Title"]).toBe("Continue");
24+
expect(headers["X-Continue-Provider"]).toBe("orcarouter");
25+
});
26+
27+
it("allows user-provided headers to override defaults", () => {
28+
const orcaRouter = new OrcaRouter({
29+
model: "orcarouter/auto",
30+
apiKey: "sk-orca-test",
31+
requestOptions: {
32+
headers: { "X-Title": "MyApp" },
33+
},
34+
});
35+
36+
const headers = (orcaRouter as any).requestOptions?.headers ?? {};
37+
expect(headers["X-Title"]).toBe("MyApp");
38+
});
39+
});
40+
41+
describe("OrcaRouter Anthropic Caching", () => {
42+
it("does not throw for Anthropic models without cacheBehavior", () => {
43+
const orcaRouter = new OrcaRouter({
44+
model: "anthropic/claude-opus-4.7",
45+
apiKey: "sk-orca-test",
46+
});
47+
48+
const body: ChatCompletionCreateParams = {
49+
model: "anthropic/claude-opus-4.7",
50+
messages: [],
51+
};
52+
53+
expect(() => orcaRouter["modifyChatBody"](body)).not.toThrow();
54+
});
55+
56+
it("adds cache_control to last two user messages when caching is enabled", () => {
57+
const orcaRouter = new OrcaRouter({
58+
model: "anthropic/claude-opus-4.7",
59+
apiKey: "sk-orca-test",
60+
cacheBehavior: {
61+
cacheConversation: true,
62+
cacheSystemMessage: false,
63+
},
64+
});
65+
66+
const body: ChatCompletionCreateParams = {
67+
model: "anthropic/claude-opus-4.7",
68+
messages: [
69+
{ role: "user", content: "First message" },
70+
{ role: "assistant", content: "Response" },
71+
{ role: "user", content: "Second message" },
72+
{ role: "assistant", content: "Another response" },
73+
{ role: "user", content: "Third message" },
74+
],
75+
};
76+
77+
const modifiedBody = orcaRouter["modifyChatBody"](body);
78+
const userMessages = modifiedBody.messages.filter(
79+
(msg: any) => msg.role === "user",
80+
);
81+
82+
expect(userMessages[0].content).toBe("First message");
83+
expect(userMessages[1].content).toEqual([
84+
{
85+
type: "text",
86+
text: "Second message",
87+
cache_control: { type: "ephemeral" },
88+
},
89+
]);
90+
expect(userMessages[2].content).toEqual([
91+
{
92+
type: "text",
93+
text: "Third message",
94+
cache_control: { type: "ephemeral" },
95+
},
96+
]);
97+
});
98+
99+
it("adds cache_control to system message when caching is enabled", () => {
100+
const orcaRouter = new OrcaRouter({
101+
model: "anthropic/claude-opus-4.7",
102+
apiKey: "sk-orca-test",
103+
cacheBehavior: {
104+
cacheConversation: false,
105+
cacheSystemMessage: true,
106+
},
107+
});
108+
109+
const body: ChatCompletionCreateParams = {
110+
model: "anthropic/claude-opus-4.7",
111+
messages: [
112+
{ role: "system", content: "You are a helpful assistant" },
113+
{ role: "user", content: "Hello" },
114+
],
115+
};
116+
117+
const modifiedBody = orcaRouter["modifyChatBody"](body);
118+
119+
expect(modifiedBody.messages[0]).toEqual({
120+
role: "system",
121+
content: [
122+
{
123+
type: "text",
124+
text: "You are a helpful assistant",
125+
cache_control: { type: "ephemeral" },
126+
},
127+
],
128+
});
129+
expect(modifiedBody.messages[1]).toEqual({
130+
role: "user",
131+
content: "Hello",
132+
});
133+
});
134+
135+
it("does not modify messages for non-Anthropic models", () => {
136+
const orcaRouter = new OrcaRouter({
137+
model: "openai/gpt-5.5",
138+
apiKey: "sk-orca-test",
139+
cacheBehavior: {
140+
cacheConversation: true,
141+
cacheSystemMessage: true,
142+
},
143+
});
144+
145+
const body: ChatCompletionCreateParams = {
146+
model: "openai/gpt-5.5",
147+
messages: [
148+
{ role: "system", content: "System message" },
149+
{ role: "user", content: "User message" },
150+
],
151+
};
152+
153+
const modifiedBody = orcaRouter["modifyChatBody"](body);
154+
expect(modifiedBody.messages).toEqual(body.messages);
155+
});
156+
157+
it("does not modify messages when no caching is enabled", () => {
158+
const orcaRouter = new OrcaRouter({
159+
model: "anthropic/claude-opus-4.7",
160+
apiKey: "sk-orca-test",
161+
});
162+
163+
const body: ChatCompletionCreateParams = {
164+
model: "anthropic/claude-opus-4.7",
165+
messages: [
166+
{ role: "system", content: "System message" },
167+
{ role: "user", content: "User message" },
168+
],
169+
};
170+
171+
const modifiedBody = orcaRouter["modifyChatBody"](body);
172+
expect(modifiedBody.messages).toEqual(body.messages);
173+
});
174+
});
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { OrcaRouterApi } from "./OrcaRouter.js";
4+
5+
describe("OrcaRouterApi", () => {
6+
const baseConfig = {
7+
provider: "orcarouter" as const,
8+
};
9+
10+
it("should use default apiBase when not provided", () => {
11+
const api = new OrcaRouterApi(baseConfig);
12+
expect(api["config"].apiBase).toBe("https://api.orcarouter.ai/v1/");
13+
});
14+
15+
it("should allow custom apiBase", () => {
16+
const api = new OrcaRouterApi({
17+
...baseConfig,
18+
apiBase: "https://api.custom-orca.example.com/v1/",
19+
});
20+
expect(api["config"].apiBase).toBe(
21+
"https://api.custom-orca.example.com/v1/",
22+
);
23+
});
24+
25+
it("should include Continue attribution headers", () => {
26+
const api = new OrcaRouterApi(baseConfig);
27+
const headers = api["getHeaders"]();
28+
29+
expect(headers["HTTP-Referer"]).toBe("https://www.continue.dev/");
30+
expect(headers["X-Title"]).toBe("Continue");
31+
expect(headers["User-Agent"]).toBe("Continue/IDE");
32+
expect(headers["X-Continue-Provider"]).toBe("orcarouter");
33+
});
34+
35+
it("should include standard OpenAI headers", () => {
36+
const api = new OrcaRouterApi({
37+
...baseConfig,
38+
apiKey: "sk-orca-test",
39+
});
40+
const headers = api["getHeaders"]();
41+
42+
expect(headers["Content-Type"]).toBe("application/json");
43+
expect(headers["Accept"]).toBe("application/json");
44+
expect(headers["Authorization"]).toBe("Bearer sk-orca-test");
45+
});
46+
});

0 commit comments

Comments
 (0)