chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
@@ -1,8 +1,7 @@
|
||||
import type Anthropic from "@anthropic-ai/sdk";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { stream as streamAnthropic } from "../src/api/anthropic-messages.ts";
|
||||
import { getModel } from "../src/compat.ts";
|
||||
import type { Context } from "../src/types.ts";
|
||||
import { getModel, normalizeContext } from "../src/compat.ts";
|
||||
|
||||
function createSseResponse(events: Array<{ event: string; data: string }>): Response {
|
||||
const body = events.map(({ event, data }) => `event: ${event}\ndata: ${data}\n`).join("\n");
|
||||
@@ -57,7 +56,7 @@ function eventsWithCacheCreation(
|
||||
}
|
||||
|
||||
// claude-opus-4-8: input 5, cacheWrite (5m) 6.25 per Mtok. 1h write = 2x input = 10.
|
||||
const context: Context = { messages: [{ role: "user", content: "hi", timestamp: Date.now() }] };
|
||||
const context = normalizeContext({ messages: [{ role: "user", content: "hi", timestamp: Date.now() }] });
|
||||
|
||||
describe("Anthropic 1h cache write cost", () => {
|
||||
it("prices the 1h portion at 2x input and the rest at the 5m rate", async () => {
|
||||
@@ -65,7 +64,9 @@ describe("Anthropic 1h cache write cost", () => {
|
||||
const response = createSseResponse(
|
||||
eventsWithCacheCreation({ ephemeral_5m_input_tokens: 600_000, ephemeral_1h_input_tokens: 400_000 }),
|
||||
);
|
||||
const result = await streamAnthropic(model, context, { client: createFakeAnthropicClient(response) }).result();
|
||||
const result = await streamAnthropic(model, context, {
|
||||
client: createFakeAnthropicClient(response),
|
||||
}).result();
|
||||
|
||||
expect(result.usage.cacheWrite).toBe(1_000_000);
|
||||
expect(result.usage.cacheWrite1h).toBe(400_000);
|
||||
@@ -73,10 +74,47 @@ describe("Anthropic 1h cache write cost", () => {
|
||||
expect(result.usage.cost.cacheWrite).toBeCloseTo(7.75, 10);
|
||||
});
|
||||
|
||||
// Regression for #9210: Vercel AI Gateway sends cache usage in message_delta, not message_start.
|
||||
it("prices 1h cache writes reported only in message_delta", async () => {
|
||||
const model = getModel("vercel-ai-gateway", "anthropic/claude-haiku-4.5");
|
||||
const response = createSseResponse([
|
||||
{
|
||||
event: "message_start",
|
||||
data: JSON.stringify({
|
||||
type: "message_start",
|
||||
message: { id: "msg_test", usage: { input_tokens: 0, output_tokens: 0 } },
|
||||
}),
|
||||
},
|
||||
{
|
||||
event: "message_delta",
|
||||
data: JSON.stringify({
|
||||
type: "message_delta",
|
||||
delta: { stop_reason: "end_turn" },
|
||||
usage: {
|
||||
input_tokens: 3,
|
||||
output_tokens: 4,
|
||||
cache_creation_input_tokens: 6535,
|
||||
cache_creation: { ephemeral_5m_input_tokens: 0, ephemeral_1h_input_tokens: 6535 },
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ event: "message_stop", data: JSON.stringify({ type: "message_stop" }) },
|
||||
]);
|
||||
const result = await streamAnthropic(model, context, {
|
||||
client: createFakeAnthropicClient(response),
|
||||
}).result();
|
||||
|
||||
expect(result.usage.cacheWrite).toBe(6535);
|
||||
expect(result.usage.cacheWrite1h).toBe(6535);
|
||||
expect(result.usage.cost.cacheWrite).toBeCloseTo((6535 * model.cost.input * 2) / 1_000_000, 10);
|
||||
});
|
||||
|
||||
it("falls back to the 5m rate when no breakdown is reported", async () => {
|
||||
const model = getModel("anthropic", "claude-opus-4-8");
|
||||
const response = createSseResponse(eventsWithCacheCreation(undefined));
|
||||
const result = await streamAnthropic(model, context, { client: createFakeAnthropicClient(response) }).result();
|
||||
const result = await streamAnthropic(model, context, {
|
||||
client: createFakeAnthropicClient(response),
|
||||
}).result();
|
||||
|
||||
expect(result.usage.cacheWrite).toBe(1_000_000);
|
||||
expect(result.usage.cacheWrite1h ?? 0).toBe(0);
|
||||
|
||||
Reference in new issue
Block a user