WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
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
5 changes: 5 additions & 0 deletions .changeset/kind-birds-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'ai': patch
---

feat(ai): support SystemModelMessage[] in system and instructions properties
6 changes: 3 additions & 3 deletions content/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ To see `generateText` in action, check out [these examples](#examples).
},
{
name: 'system',
type: 'string | SystemModelMessage',
type: 'string | SystemModelMessage | SystemModelMessage[]',
description:
'The system prompt to use that specifies the behavior of the model.',
},
Expand Down Expand Up @@ -581,7 +581,7 @@ To see `generateText` in action, check out [these examples](#examples).
description: 'Change which tools are active for this step.',
},
{
name: 'system | SystemModelMessage',
name: 'system | SystemModelMessage | SystemModelMessage[]',
type: 'string',
isOptional: true,
description: 'Change the system prompt for this step.',
Expand Down Expand Up @@ -622,7 +622,7 @@ To see `generateText` in action, check out [these examples](#examples).
parameters: [
{
name: 'system',
type: 'string | SystemModelMessage | undefined',
type: 'string | SystemModelMessage | SystemModelMessage[] | undefined',
description: 'The system prompt.',
},
{
Expand Down
6 changes: 3 additions & 3 deletions content/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ To see `streamText` in action, check out [these examples](#examples).
},
{
name: 'system',
type: 'string | SystemModelMessage',
type: 'string | SystemModelMessage | SystemModelMessage[]',
description:
'The system prompt to use that specifies the behavior of the model.',
},
Expand Down Expand Up @@ -633,7 +633,7 @@ To see `streamText` in action, check out [these examples](#examples).
},
{
name: 'system',
type: 'string | SystemModelMessage',
type: 'string | SystemModelMessage | SystemModelMessage[]',
isOptional: true,
description: 'Change the system prompt for this step.',
},
Expand Down Expand Up @@ -673,7 +673,7 @@ To see `streamText` in action, check out [these examples](#examples).
parameters: [
{
name: 'system',
type: 'string | SystemModelMessage | undefined',
type: 'string | SystemModelMessage | SystemModelMessage[] | undefined',
description: 'The system prompt.',
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ To see `generateObject` in action, check out the [additional examples](#more-exa
},
{
name: 'system',
type: 'string | SystemModelMessage',
type: 'string | SystemModelMessage | SystemModelMessage[]',
description:
'The system prompt to use that specifies the behavior of the model.',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ To see `streamObject` in action, check out the [additional examples](#more-examp
Not available with 'no-schema' or 'enum' output.",
},
{
name: 'system | SystemModelMessage',
name: 'system | SystemModelMessage | SystemModelMessage[]',
type: 'string',
description:
'The system prompt to use that specifies the behavior of the model.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ To see `ToolLoopAgent` in action, check out [these examples](#examples).
},
{
name: 'instructions',
type: 'string | SystemModelMessage',
type: 'string | SystemModelMessage | SystemModelMessage[]',
isOptional: true,
description:
'Instructions for the agent, usually used for system prompt/context.',
Expand Down
2 changes: 1 addition & 1 deletion content/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ To see `streamUI` in action, check out [these examples](#examples).
},
{
name: 'system',
type: 'string | SystemModelMessage',
type: 'string | SystemModelMessage | SystemModelMessage[]',
description:
'The system prompt to use that specifies the behavior of the model.',
},
Expand Down
23 changes: 15 additions & 8 deletions examples/ai-core/src/agent/anthropic-cache-instruction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,21 @@ const errorMessage = fs.readFileSync('data/error-message.txt', 'utf8');

const agent = new ToolLoopAgent({
model: anthropic('claude-sonnet-4-5'),
instructions: {
role: 'system',
content: `You are a JavaScript expert that knows everything about the following error message: ${errorMessage}`,
providerOptions: {
anthropic: {
cacheControl: { type: 'ephemeral' },
} satisfies AnthropicProviderOptions,
instructions: [
{
role: 'system',
content: `You are a JavaScript expert that knows everything about the following error message: ${errorMessage}`,
providerOptions: {
anthropic: {
cacheControl: { type: 'ephemeral', ttl: '1h' },
} satisfies AnthropicProviderOptions,
},
},
},
{
role: 'system',
content: 'You pay special attention to the error message.',
},
],
});

run(async () => {
Expand All @@ -26,4 +32,5 @@ run(async () => {

print('Result:', result.content);
print('Metadata:', result.providerMetadata?.anthropic);
print('Request:', result.request.body);
});
2 changes: 1 addition & 1 deletion packages/ai/src/agent/tool-loop-agent-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type ToolLoopAgentSettings<
*
* It can be a string, or, if you need to pass additional provider options (e.g. for caching), a `SystemModelMessage`.
*/
instructions?: string | SystemModelMessage;
instructions?: string | SystemModelMessage | Array<SystemModelMessage>;

/**
The language model to use.
Expand Down
55 changes: 55 additions & 0 deletions packages/ai/src/agent/tool-loop-agent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,61 @@ describe('ToolLoopAgent', () => {
]
`);
});

it('should pass array of system message instructions', async () => {
const agent = new ToolLoopAgent({
model: mockModel,
instructions: [
{
role: 'system',
content: 'INSTRUCTIONS',
providerOptions: { test: { value: 'test' } },
},
{
role: 'system',
content: 'INSTRUCTIONS 2',
providerOptions: { test: { value: 'test 2' } },
},
],
});

await agent.generate({
prompt: 'Hello, world!',
});

expect(doGenerateOptions?.prompt).toMatchInlineSnapshot(`
[
{
"content": "INSTRUCTIONS",
"providerOptions": {
"test": {
"value": "test",
},
},
"role": "system",
},
{
"content": "INSTRUCTIONS 2",
"providerOptions": {
"test": {
"value": "test 2",
},
},
"role": "system",
},
{
"content": [
{
"text": "Hello, world!",
"type": "text",
},
],
"providerOptions": undefined,
"role": "user",
},
]
`);
});
});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/ai/src/generate-text/parse-tool-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export async function parseToolCall<TOOLS extends ToolSet>({
toolCall: LanguageModelV3ToolCall;
tools: TOOLS | undefined;
repairToolCall: ToolCallRepairFunction<TOOLS> | undefined;
system: string | SystemModelMessage | undefined;
system: string | SystemModelMessage | Array<SystemModelMessage> | undefined;
messages: ModelMessage[];
}): Promise<TypedToolCall<TOOLS>> {
try {
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/src/generate-text/prepare-step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type PrepareStepResult<
model?: LanguageModel;
toolChoice?: ToolChoice<NoInfer<TOOLS>>;
activeTools?: Array<keyof NoInfer<TOOLS>>;
system?: string | SystemModelMessage;
system?: string | SystemModelMessage | Array<SystemModelMessage>;
messages?: Array<ModelMessage>;
}
| undefined;
2 changes: 1 addition & 1 deletion packages/ai/src/generate-text/run-tools-transformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export function runToolsTransformation<TOOLS extends ToolSet>({
generatorStream: ReadableStream<LanguageModelV3StreamPart>;
tracer: Tracer;
telemetry: TelemetrySettings | undefined;
system: string | SystemModelMessage | undefined;
system: string | SystemModelMessage | Array<SystemModelMessage> | undefined;
messages: ModelMessage[];
abortSignal: AbortSignal | undefined;
repairToolCall: ToolCallRepairFunction<TOOLS> | undefined;
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/src/generate-text/tool-call-repair-function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { ToolSet } from './tool-set';
* @param options.error - The error that occurred while parsing the tool call.
*/
export type ToolCallRepairFunction<TOOLS extends ToolSet> = (options: {
system: string | SystemModelMessage | undefined;
system: string | SystemModelMessage | Array<SystemModelMessage> | undefined;
messages: ModelMessage[];
toolCall: LanguageModelV3ToolCall;
tools: TOOLS;
Expand Down
39 changes: 39 additions & 0 deletions packages/ai/src/prompt/convert-to-language-model-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,45 @@ describe('convertToLanguageModelPrompt', () => {
]
`);
});

it('should convert an array of SystemModelMessage system messages', async () => {
const result = await convertToLanguageModelPrompt({
prompt: {
system: [
{ role: 'system', content: 'INSTRUCTIONS' },
{ role: 'system', content: 'INSTRUCTIONS 2' },
],
messages: [{ role: 'user', content: 'Hello, world!' }],
},
supportedUrls: {},
download: undefined,
});

expect(result).toMatchInlineSnapshot(`
[
{
"content": "INSTRUCTIONS",
"providerOptions": undefined,
"role": "system",
},
{
"content": "INSTRUCTIONS 2",
"providerOptions": undefined,
"role": "system",
},
{
"content": [
{
"text": "Hello, world!",
"type": "text",
},
],
"providerOptions": undefined,
"role": "user",
},
]
`);
});
});

describe('user message', () => {
Expand Down
13 changes: 6 additions & 7 deletions packages/ai/src/prompt/convert-to-language-model-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
import { convertToLanguageModelV3DataContent } from './data-content';
import { InvalidMessageRoleError } from './invalid-message-role-error';
import { StandardizedPrompt } from './standardize-prompt';
import { asArray } from '../util/as-array';

export async function convertToLanguageModelPrompt({
prompt,
Expand All @@ -48,13 +49,11 @@ export async function convertToLanguageModelPrompt({
...(prompt.system != null
? typeof prompt.system === 'string'
? [{ role: 'system' as const, content: prompt.system }]
: [
{
role: 'system' as const,
content: prompt.system.content,
providerOptions: prompt.system.providerOptions,
},
]
: asArray(prompt.system).map(message => ({
role: 'system' as const,
content: message.content,
providerOptions: message.providerOptions,
}))
: []),
...prompt.messages.map(message =>
convertToLanguageModelMessage({ message, downloadedAssets }),
Expand Down
2 changes: 1 addition & 1 deletion packages/ai/src/prompt/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type Prompt = {
/**
System message to include in the prompt. Can be used with `prompt` or `messages`.
*/
system?: string | SystemModelMessage;
system?: string | SystemModelMessage | Array<SystemModelMessage>;
} & (
| {
/**
Expand Down
31 changes: 31 additions & 0 deletions packages/ai/src/prompt/standardize-prompt.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,35 @@ describe('standardizePrompt', () => {
}
`);
});

it('should support array of SystemModelMessage system messages', async () => {
const result = await standardizePrompt({
system: [
{ role: 'system', content: 'INSTRUCTIONS' },
{ role: 'system', content: 'INSTRUCTIONS 2' },
],
prompt: 'Hello, world!',
});

expect(result).toMatchInlineSnapshot(`
{
"messages": [
{
"content": "Hello, world!",
"role": "user",
},
],
"system": [
{
"content": "INSTRUCTIONS",
"role": "system",
},
{
"content": "INSTRUCTIONS 2",
"role": "system",
},
],
}
`);
});
});
15 changes: 11 additions & 4 deletions packages/ai/src/prompt/standardize-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import {
import { z } from 'zod/v4';
import { modelMessageSchema } from './message';
import { Prompt } from './prompt';
import { asArray } from '../util/as-array';

export type StandardizedPrompt = {
/**
* System message.
*/
system?: string | SystemModelMessage;
system?: string | SystemModelMessage | Array<SystemModelMessage>;

/**
* Messages.
Expand Down Expand Up @@ -41,12 +42,18 @@ export async function standardizePrompt(
if (
prompt.system != null &&
typeof prompt.system !== 'string' &&
'role' in prompt.system &&
prompt.system.role !== 'system'
!asArray(prompt.system).every(
message =>
typeof message === 'object' &&
message !== null &&
'role' in message &&
message.role === 'system',
)
) {
throw new InvalidPromptError({
prompt,
message: 'system must be a string',
message:
'system must be a string, SystemModelMessage, or array of SystemModelMessage',
});
}

Expand Down
Loading