Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@browserbasehq/stagehand": patch
---

Remove the noisy AI SDK "system message in messages" warning from `act()`, `extract()`, and `observe()` (including when the agent's own tools call them internally).
2 changes: 2 additions & 0 deletions packages/core/lib/v3/external_clients/aisdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export class AISdkClient extends LLMClient {
model: this.model,
messages: formattedMessages,
schema: options.response_model.schema,
allowSystemInMessages: true,
Comment thread
shrey150 marked this conversation as resolved.
});

return {
Expand Down Expand Up @@ -113,6 +114,7 @@ export class AISdkClient extends LLMClient {
model: this.model,
messages: formattedMessages,
tools,
allowSystemInMessages: true,
});

return {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/lib/v3/llm/aisdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ You must respond in JSON format. respond WITH JSON. Do not include any other tex
messages: formattedMessages,
schema: options.response_model.schema,
temperature,
allowSystemInMessages: true,
Comment thread
shrey150 marked this conversation as resolved.
...(Object.keys(providerOptions).length > 0
? { providerOptions }
: {}),
Expand Down Expand Up @@ -383,6 +384,7 @@ You must respond in JSON format. respond WITH JSON. Do not include any other tex
: "auto"
: undefined,
temperature,
allowSystemInMessages: true,
});
} catch (err) {
// Log error response to maintain request/response pairing
Expand Down
76 changes: 75 additions & 1 deletion packages/core/tests/unit/aisdk-clients.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { LanguageModelV2 } from "@ai-sdk/provider";
import { generateObject } from "ai";
import { generateObject, generateText } from "ai";
import { z } from "zod";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { AISdkClient } from "../../lib/v3/llm/aisdk.js";
Expand All @@ -9,10 +9,12 @@ vi.mock("ai", async () => {
return {
...actual,
generateObject: vi.fn(),
generateText: vi.fn(),
};
});

const mockGenerateObject = vi.mocked(generateObject);
const mockGenerateText = vi.mocked(generateText);

function createModel(modelId: string) {
return {
Expand Down Expand Up @@ -99,3 +101,75 @@ describe("AISdkClient structured output provider options", () => {
);
});
});

describe("AISdkClient allowSystemInMessages", () => {
beforeEach(() => {
mockGenerateObject.mockReset();
mockGenerateObject.mockResolvedValue({
object: { ok: true },
usage: {
inputTokens: 1,
outputTokens: 2,
reasoningTokens: 0,
cachedInputTokens: 0,
totalTokens: 3,
},
} as never);

mockGenerateText.mockReset();
mockGenerateText.mockResolvedValue({
text: "done",
toolCalls: [],
finishReason: "stop",
usage: {
inputTokens: 1,
outputTokens: 2,
reasoningTokens: 0,
cachedInputTokens: 0,
totalTokens: 3,
},
} as never);
});

const systemAndUserMessages = [
{ role: "system" as const, content: "you are a helpful assistant" },
{ role: "user" as const, content: "hello" },
];

it("passes allowSystemInMessages: true on the generateObject (response_model) call", async () => {
const client = new AISdkClient({
model: createModel("anthropic/claude-haiku-4-5"),
logger: vi.fn(),
});

await client.createChatCompletion({
options: {
messages: systemAndUserMessages,
response_model: { name: "test", schema: z.object({ ok: z.boolean() }) },
},
logger: vi.fn(),
});

expect(mockGenerateObject).toHaveBeenCalledWith(
expect.objectContaining({ allowSystemInMessages: true }),
);
});

it("passes allowSystemInMessages: true on the generateText (tool-calling) call", async () => {
const client = new AISdkClient({
model: createModel("anthropic/claude-haiku-4-5"),
logger: vi.fn(),
});

await client.createChatCompletion({
options: {
messages: systemAndUserMessages,
},
logger: vi.fn(),
});

expect(mockGenerateText).toHaveBeenCalledWith(
expect.objectContaining({ allowSystemInMessages: true }),
);
});
});
92 changes: 92 additions & 0 deletions packages/core/tests/unit/external-aisdk-client.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import type { LanguageModelV2 } from "@ai-sdk/provider";
import { generateObject, generateText } from "ai";
import { z } from "zod";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { AISdkClient } from "../../lib/v3/external_clients/aisdk.js";

vi.mock("ai", async () => {
const actual = await vi.importActual<typeof import("ai")>("ai");
return {
...actual,
generateObject: vi.fn(),
generateText: vi.fn(),
};
});

const mockGenerateObject = vi.mocked(generateObject);
const mockGenerateText = vi.mocked(generateText);

function createModel(modelId: string) {
return {
modelId,
specificationVersion: "v2",
} as unknown as LanguageModelV2;
}

describe("BYOC AISdkClient allowSystemInMessages", () => {
beforeEach(() => {
mockGenerateObject.mockReset();
mockGenerateObject.mockResolvedValue({
object: { ok: true },
usage: {
inputTokens: 1,
outputTokens: 2,
reasoningTokens: 0,
cachedInputTokens: 0,
totalTokens: 3,
},
} as never);

mockGenerateText.mockReset();
mockGenerateText.mockResolvedValue({
text: "done",
toolCalls: [],
finishReason: "stop",
usage: {
inputTokens: 1,
outputTokens: 2,
reasoningTokens: 0,
cachedInputTokens: 0,
totalTokens: 3,
},
} as never);
});

const systemAndUserMessages = [
{ role: "system" as const, content: "you are a helpful assistant" },
{ role: "user" as const, content: "hello" },
];

it("passes allowSystemInMessages: true on the generateObject (response_model) call", async () => {
const client = new AISdkClient({ model: createModel("openai/gpt-4.1") });

await client.createChatCompletion({
options: {
messages: systemAndUserMessages,
response_model: { name: "test", schema: z.object({ ok: z.boolean() }) },
tools: [],
},
logger: vi.fn(),
});

expect(mockGenerateObject).toHaveBeenCalledWith(
expect.objectContaining({ allowSystemInMessages: true }),
);
});

it("passes allowSystemInMessages: true on the generateText (tool-calling) call", async () => {
const client = new AISdkClient({ model: createModel("openai/gpt-4.1") });

await client.createChatCompletion({
options: {
messages: systemAndUserMessages,
tools: [],
},
logger: vi.fn(),
});

expect(mockGenerateText).toHaveBeenCalledWith(
expect.objectContaining({ allowSystemInMessages: true }),
);
});
});
Loading