fix(openrouter): bound generation-cost JSON response reads (#97490)

(cherry picked from commit c0883a531d)
This commit is contained in:
NIO
2026-06-29 01:44:36 +08:00
committed by Dallin Romney
parent 619d50888a
commit da7a0da19a
2 changed files with 58 additions and 1 deletions
+51
View File
@@ -791,6 +791,57 @@ describe("openrouter provider hooks", () => {
}
});
it("falls back to streamed cost estimate when generation metadata response is oversized", async () => {
const provider = await registerSingleProviderPlugin(openrouterPlugin);
// Body exceeds the 16 MiB cap; readProviderJsonResponse must reject it and
// applyOpenRouterBilledCost must fall back to the streamed estimate.
const oversizedBody = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array(16 * 1024 * 1024 + 1).fill(0x78));
controller.close();
},
});
const fetchMock = vi.fn(async (url: string) => {
expect(url).toBe("https://openrouter.ai/api/v1/generation?id=gen-oversized-1");
return new Response(oversizedBody, {
headers: { "Content-Type": "application/json" },
status: 200,
});
});
vi.stubGlobal("fetch", fetchMock);
const baseStreamFn = vi.fn(() =>
createOpenRouterDoneStream({ responseId: "gen-oversized-1", totalCost: 0.001 }),
);
try {
const wrapped = provider.wrapStreamFn?.({
provider: "openrouter",
modelId: "openrouter/auto",
streamFn: baseStreamFn,
} as never);
if (!wrapped) {
throw new Error("expected OpenRouter wrapper");
}
const stream = await wrapped(
{
provider: "openrouter",
api: "openai-completions",
id: "openrouter/auto",
baseUrl: "https://openrouter.ai/api/v1",
compat: {},
} as never,
{ messages: [] } as never,
{ apiKey: "or-test-key" } as never,
);
const message = await stream.result();
expect(fetchMock).toHaveBeenCalledOnce();
expect(message.usage.cost.total).toBe(0.001);
} finally {
vi.unstubAllGlobals();
}
});
it("does not fetch generation metadata for custom OpenRouter-compatible routes", async () => {
const provider = await registerSingleProviderPlugin(openrouterPlugin);
const fetchMock = vi.fn();
+7 -1
View File
@@ -9,6 +9,7 @@ import type { ProviderWrapStreamFnContext } from "openclaw/plugin-sdk/plugin-ent
import {
assertOkOrThrowHttpError,
fetchWithTimeoutGuarded,
readProviderJsonResponse,
} from "openclaw/plugin-sdk/provider-http";
import { OPENROUTER_THINKING_STREAM_HOOKS } from "openclaw/plugin-sdk/provider-stream-family";
import {
@@ -124,7 +125,12 @@ async function fetchOpenRouterGenerationTotalCost(params: {
);
try {
await assertOkOrThrowHttpError(response, "OpenRouter generation metadata request failed");
return readOpenRouterTotalCost((await response.json()) as OpenRouterGenerationResponse);
return readOpenRouterTotalCost(
await readProviderJsonResponse<OpenRouterGenerationResponse>(
response,
"openrouter.generation-cost",
),
);
} finally {
await release();
}