Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions packages/core/lib/v3/agent/AnthropicCUAClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,9 +554,16 @@ export class AnthropicCUAClient extends AgentClient {
];
}

// Add system parameter if provided
// Add system parameter if provided, with cache control so the
// tools + system prefix is cached across agent steps
if (this.userProvidedInstructions) {
requestParams.system = this.userProvidedInstructions;
requestParams.system = [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new system content-block array with cache_control is not verified by any unit test, even though the codebase already mocks getAction's Anthropic SDK call and asserts on request parameters. Because the API call is typed as Record<string, unknown> and uses @ts-expect-error, a regression in this shape would compile cleanly but fail at Anthropic at runtime. Adding a focused test that instantiates AnthropicCUAClient with non-empty userProvidedInstructions and asserts on the system field passed to mockCreate would be straightforward given the existing test infrastructure.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/lib/v3/agent/AnthropicCUAClient.ts, line 560:

<comment>The new `system` content-block array with `cache_control` is not verified by any unit test, even though the codebase already mocks `getAction`'s Anthropic SDK call and asserts on request parameters. Because the API call is typed as `Record<string, unknown>` and uses `@ts-expect-error`, a regression in this shape would compile cleanly but fail at Anthropic at runtime. Adding a focused test that instantiates `AnthropicCUAClient` with non-empty `userProvidedInstructions` and asserts on the `system` field passed to `mockCreate` would be straightforward given the existing test infrastructure.</comment>

<file context>
@@ -554,9 +554,16 @@ export class AnthropicCUAClient extends AgentClient {
+      // tools + system prefix is cached across agent steps
       if (this.userProvidedInstructions) {
-        requestParams.system = this.userProvidedInstructions;
+        requestParams.system = [
+          {
+            type: "text",
</file context>

{
type: "text",
text: this.userProvidedInstructions,
cache_control: { type: "ephemeral" },
},
];
}

// Add thinking parameter if available
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { describe, expect, it, vi, beforeEach } from "vitest";
import { AnthropicCUAClient } from "../../lib/v3/agent/AnthropicCUAClient.js";
import Anthropic from "@anthropic-ai/sdk";

// Mock the Anthropic SDK's beta.messages.create method
vi.mock("@anthropic-ai/sdk", () => {
const mockCreate = vi.fn().mockResolvedValue({
id: "test-id",
content: [{ type: "text", text: "test response" }],
usage: { input_tokens: 10, output_tokens: 20 },
});

return {
default: class MockAnthropic {
beta = {
messages: {
create: mockCreate,
},
};
},
};
});

describe("AnthropicCUAClient system prompt caching", () => {
let mockCreate: ReturnType<typeof vi.fn>;

beforeEach(() => {
vi.clearAllMocks();
// Get the mock create function from a new instance
const anthropic = new Anthropic({ apiKey: "test" });
mockCreate = anthropic.beta.messages.create as ReturnType<typeof vi.fn>;
mockCreate.mockResolvedValue({
id: "test-id",
content: [{ type: "text", text: "test response" }],
usage: { input_tokens: 10, output_tokens: 20 },
});
});

it("should send the system prompt as a content block array with cache_control", async () => {
const instructions = "You are a helpful browser automation assistant.";
const client = new AnthropicCUAClient(
"anthropic",
"claude-opus-4-6",
instructions,
{
apiKey: "test-key",
},
);
client.setViewport(1280, 720);

await client.getAction([{ role: "user", content: "test" }]);

expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
system: [
{
type: "text",
text: instructions,
cache_control: { type: "ephemeral" },
},
],
}),
);
});

it("should not set the system parameter when no instructions are provided", async () => {
const client = new AnthropicCUAClient(
"anthropic",
"claude-opus-4-6",
undefined,
{
apiKey: "test-key",
},
);
client.setViewport(1280, 720);

await client.getAction([{ role: "user", content: "test" }]);

const callArgs = mockCreate.mock.calls[0][0];
expect(callArgs.system).toBeUndefined();
});
});
Loading