mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(anthropic): restore subscription OAuth billing routing
This commit is contained in:
@@ -149,6 +149,37 @@ describe("Anthropic provider", () => {
|
||||
expect(config.authToken).toBeNull();
|
||||
});
|
||||
|
||||
it("puts Claude subscription billing identity first for OAuth requests", async () => {
|
||||
let capturedPayload: unknown;
|
||||
const stream = streamSimpleAnthropic(
|
||||
makeAnthropicModel(),
|
||||
{
|
||||
messages: [{ role: "user", content: "hello", timestamp: 1 }],
|
||||
},
|
||||
{
|
||||
apiKey: "sk-ant-oat01-test-token",
|
||||
onPayload: (payload) => {
|
||||
capturedPayload = payload;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const result = await stream.result();
|
||||
|
||||
expect(result.stopReason).toBe("error");
|
||||
expect((capturedPayload as { system?: unknown }).system).toEqual([
|
||||
{
|
||||
type: "text",
|
||||
text: "x-anthropic-billing-header: cc_version=2.1.75; cc_entrypoint=sdk-cli;",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
||||
cache_control: { type: "ephemeral" },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps aggregate cache billing buckets out of the context total", async () => {
|
||||
const client = {
|
||||
messages: {
|
||||
|
||||
@@ -109,6 +109,7 @@ function getCacheControl(
|
||||
|
||||
// Stealth mode: Mimic Claude Code's tool naming exactly
|
||||
const claudeCodeVersion = "2.1.75";
|
||||
const claudeCodeBillingSystemBlock = `x-anthropic-billing-header: cc_version=${claudeCodeVersion}; cc_entrypoint=sdk-cli;`;
|
||||
|
||||
// Claude Code 2.x tool names (canonical casing)
|
||||
// Source: https://cchistory.mariozechner.at/data/prompts-2.1.11.md
|
||||
@@ -1564,6 +1565,11 @@ function buildAnthropicSystemBlocks(
|
||||
): TextBlockParam[] | undefined {
|
||||
const blocks: TextBlockParam[] = [];
|
||||
if (isOAuthTokenResult) {
|
||||
// Anthropic uses this first system block to route Claude subscription OAuth billing.
|
||||
blocks.push({
|
||||
type: "text",
|
||||
text: claudeCodeBillingSystemBlock,
|
||||
});
|
||||
blocks.push({
|
||||
type: "text",
|
||||
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
||||
|
||||
@@ -1618,6 +1618,9 @@ describe("anthropic transport stream", () => {
|
||||
expect(headers.get("user-agent")).toContain("claude-cli/");
|
||||
const firstCallParams = latestAnthropicRequest().payload;
|
||||
const system = requireArray(firstCallParams.system, "system");
|
||||
expect(requireRecord(system[0], "billing system item").text).toBe(
|
||||
"x-anthropic-billing-header: cc_version=2.1.75; cc_entrypoint=sdk-cli;",
|
||||
);
|
||||
expect(
|
||||
system.some(
|
||||
(item) =>
|
||||
|
||||
@@ -82,6 +82,7 @@ import {
|
||||
import type { ContextUsage } from "./usage.js";
|
||||
|
||||
const CLAUDE_CODE_VERSION = "2.1.75";
|
||||
const CLAUDE_CODE_BILLING_SYSTEM_BLOCK = `x-anthropic-billing-header: cc_version=${CLAUDE_CODE_VERSION}; cc_entrypoint=sdk-cli;`;
|
||||
const ANTHROPIC_MESSAGES_ERROR_BODY_MAX_BYTES = 8 * 1024;
|
||||
const ANTHROPIC_MESSAGES_ERROR_BODY_MAX_CHARS = 400;
|
||||
const ANTHROPIC_MESSAGES_ERROR_BODY_READ_IDLE_TIMEOUT_MS = 10_000;
|
||||
@@ -1006,6 +1007,11 @@ function buildAnthropicParams(
|
||||
}
|
||||
if (isOAuthToken) {
|
||||
params.system = [
|
||||
// Anthropic requires this first block to route Claude subscription OAuth billing.
|
||||
{
|
||||
type: "text",
|
||||
text: CLAUDE_CODE_BILLING_SYSTEM_BLOCK,
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
||||
|
||||
Reference in New Issue
Block a user