























@@ -63,6 +63,118 @@ describe("proxy stream wrappers", () => {
6363]);
6464});
656566+it("adds opt-in OpenRouter response caching headers", () => {
67+const calls: Array<{ headers?: Record<string, string> }> = [];
68+const baseStreamFn: StreamFn = (_model, _context, options) => {
69+calls.push({ headers: options?.headers });
70+return createAssistantMessageEventStream();
71+};
72+73+const wrapped = createOpenRouterWrapper(baseStreamFn, undefined, {
74+responseCache: true,
75+responseCacheTtlSeconds: 900,
76+});
77+78+void wrapped(
79+{
80+api: "openai-completions",
81+provider: "openrouter",
82+id: "openrouter/auto",
83+baseUrl: "https://openrouter.ai/api/v1",
84+} as Model<"openai-completions">,
85+{ messages: [] },
86+{},
87+);
88+89+expect(calls[0]?.headers).toMatchObject({
90+"HTTP-Referer": "https://openclaw.ai",
91+"X-OpenRouter-Cache": "true",
92+"X-OpenRouter-Cache-TTL": "900",
93+});
94+});
95+96+it("sends OpenRouter response cache disables for preset opt-outs", () => {
97+const calls: Array<{ headers?: Record<string, string> }> = [];
98+const baseStreamFn: StreamFn = (_model, _context, options) => {
99+calls.push({ headers: options?.headers });
100+return createAssistantMessageEventStream();
101+};
102+103+const wrapped = createOpenRouterWrapper(baseStreamFn, undefined, {
104+response_cache: false,
105+response_cache_ttl_seconds: 600,
106+});
107+108+void wrapped(
109+{
110+api: "openai-completions",
111+provider: "openrouter",
112+id: "openrouter/@preset/cached-tests",
113+} as Model<"openai-completions">,
114+{ messages: [] },
115+{},
116+);
117+118+expect(calls[0]?.headers).toMatchObject({
119+"X-OpenRouter-Cache": "false",
120+});
121+expect(calls[0]?.headers).not.toHaveProperty("X-OpenRouter-Cache-TTL");
122+});
123+124+it("supports OpenRouter response cache refresh and TTL clamping", () => {
125+const calls: Array<{ headers?: Record<string, string> }> = [];
126+const baseStreamFn: StreamFn = (_model, _context, options) => {
127+calls.push({ headers: options?.headers });
128+return createAssistantMessageEventStream();
129+};
130+131+const wrapped = createOpenRouterWrapper(baseStreamFn, undefined, {
132+response_cache_clear: "true",
133+response_cache_ttl: 999999,
134+});
135+136+void wrapped(
137+{
138+api: "openai-completions",
139+provider: "openrouter",
140+id: "openrouter/auto",
141+} as Model<"openai-completions">,
142+{ messages: [] },
143+{},
144+);
145+146+expect(calls[0]?.headers).toMatchObject({
147+"X-OpenRouter-Cache": "true",
148+"X-OpenRouter-Cache-Clear": "true",
149+"X-OpenRouter-Cache-TTL": "86400",
150+});
151+});
152+153+it("does not add OpenRouter response caching headers to custom proxy routes", () => {
154+const calls: Array<{ headers?: Record<string, string> }> = [];
155+const baseStreamFn: StreamFn = (_model, _context, options) => {
156+calls.push({ headers: options?.headers });
157+return createAssistantMessageEventStream();
158+};
159+160+const wrapped = createOpenRouterWrapper(baseStreamFn, undefined, {
161+responseCache: true,
162+});
163+164+void wrapped(
165+{
166+api: "openai-completions",
167+provider: "openrouter",
168+id: "openrouter/auto",
169+baseUrl: "https://proxy.example.com/v1",
170+} as Model<"openai-completions">,
171+{ messages: [] },
172+{},
173+);
174+175+expect(calls[0]?.headers).toBeUndefined();
176+});
177+66178it("injects cache_control markers for declared OpenRouter Anthropic models on the default route", () => {
67179const payload = runSystemCacheWrapper({});
68180此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。