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
9 changes: 9 additions & 0 deletions .changeset/late-cougars-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@ai-sdk/openai-compatible': patch
'@ai-sdk/provider-utils': patch
'@ai-sdk/alibaba': patch
---

fix(openai-compatible,provider-utils): JSON schema validation

fix(alibaba): await prepareTools call now that it's async
2 changes: 1 addition & 1 deletion packages/alibaba/src/alibaba-chat-language-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export class AlibabaLanguageModel implements LanguageModelV3 {
tools: alibabaTools,
toolChoice: alibabaToolChoice,
toolWarnings,
} = prepareTools({ tools, toolChoice });
} = await prepareTools({ tools, toolChoice });

warnings.push(...cacheControlValidator.getWarnings());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export class OpenAICompatibleChatLanguageModel implements LanguageModelV3 {
tools: openaiTools,
toolChoice: openaiToolChoice,
toolWarnings,
} = prepareTools({
} = await prepareTools({
tools,
toolChoice,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { describe, expect, it } from 'vitest';
import { prepareTools } from './openai-compatible-prepare-tools';

describe('prepareTools', () => {
it('should return undefined tools and toolChoice when tools are null', () => {
const result = prepareTools({
it('should return undefined tools and toolChoice when tools are null', async () => {
const result = await prepareTools({
tools: undefined,
toolChoice: undefined,
});
Expand All @@ -15,8 +15,8 @@ describe('prepareTools', () => {
});
});

it('should return undefined tools and toolChoice when tools are empty', () => {
const result = prepareTools({
it('should return undefined tools and toolChoice when tools are empty', async () => {
const result = await prepareTools({
tools: [],
toolChoice: undefined,
});
Expand All @@ -28,8 +28,8 @@ describe('prepareTools', () => {
});
});

it('should correctly prepare function tools', () => {
const result = prepareTools({
it('should correctly prepare function tools', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand Down Expand Up @@ -62,8 +62,8 @@ describe('prepareTools', () => {
`);
});

it('should add warnings for unsupported provider-defined tools', () => {
const result = prepareTools({
it('should add warnings for unsupported provider-defined tools', async () => {
const result = await prepareTools({
tools: [
{
type: 'provider',
Expand All @@ -87,8 +87,8 @@ describe('prepareTools', () => {
`);
});

it('should handle tool choice "auto"', () => {
const result = prepareTools({
it('should handle tool choice "auto"', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand All @@ -103,8 +103,8 @@ describe('prepareTools', () => {
expect(result.toolChoice).toEqual('auto');
});

it('should handle tool choice "required"', () => {
const result = prepareTools({
it('should handle tool choice "required"', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand All @@ -119,8 +119,8 @@ describe('prepareTools', () => {
expect(result.toolChoice).toEqual('required');
});

it('should handle tool choice "none"', () => {
const result = prepareTools({
it('should handle tool choice "none"', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand All @@ -135,8 +135,8 @@ describe('prepareTools', () => {
expect(result.toolChoice).toEqual('none');
});

it('should handle tool choice "tool"', () => {
const result = prepareTools({
it('should handle tool choice "tool"', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand All @@ -155,8 +155,8 @@ describe('prepareTools', () => {
});

describe('strict mode', () => {
it('should pass through strict mode when strict is true', () => {
const result = prepareTools({
it('should pass through strict mode when strict is true', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand Down Expand Up @@ -191,8 +191,8 @@ describe('prepareTools', () => {
`);
});

it('should pass through strict mode when strict is false', () => {
const result = prepareTools({
it('should pass through strict mode when strict is false', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand Down Expand Up @@ -227,8 +227,8 @@ describe('prepareTools', () => {
`);
});

it('should not include strict mode when strict is undefined', () => {
const result = prepareTools({
it('should not include strict mode when strict is undefined', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand Down Expand Up @@ -261,8 +261,8 @@ describe('prepareTools', () => {
`);
});

it('should pass through strict mode for multiple tools with different strict settings', () => {
const result = prepareTools({
it('should pass through strict mode for multiple tools with different strict settings', async () => {
const result = await prepareTools({
tools: [
{
type: 'function',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import {
SharedV3Warning,
UnsupportedFunctionalityError,
} from '@ai-sdk/provider';
import { jsonSchema } from '@ai-sdk/provider-utils';

export function prepareTools({
export async function prepareTools({
tools,
toolChoice,
}: {
tools: LanguageModelV3CallOptions['tools'];
toolChoice?: LanguageModelV3CallOptions['toolChoice'];
}): {
}): Promise<{
tools:
| undefined
| Array<{
Expand All @@ -29,7 +30,7 @@ export function prepareTools({
| 'required'
| undefined;
toolWarnings: SharedV3Warning[];
} {
}> {
// when the tools array is empty, change it to undefined to prevent errors:
tools = tools?.length ? tools : undefined;

Expand All @@ -56,12 +57,20 @@ export function prepareTools({
feature: `provider-defined tool ${tool.id}`,
});
} else {
const parameters =
tool.inputSchema ??
(await jsonSchema({
type: 'object',
properties: {},
additionalProperties: false,
}).jsonSchema);

openaiCompatTools.push({
type: 'function',
function: {
name: tool.name,
description: tool.description,
parameters: tool.inputSchema,
parameters,
...(tool.strict != null ? { strict: tool.strict } : {}),
},
});
Expand Down
6 changes: 5 additions & 1 deletion packages/provider-utils/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ export function asSchema<OBJECT>(
schema: FlexibleSchema<OBJECT> | undefined,
): Schema<OBJECT> {
return schema == null
? jsonSchema({ properties: {}, additionalProperties: false })
? jsonSchema({
type: 'object',
properties: {},
additionalProperties: false,
})
: isSchema(schema)
? schema
: '~standard' in schema
Expand Down