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
9 changes: 9 additions & 0 deletions .changeset/goofy-llamas-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@openai/agents-extensions': minor
Copy link
Member Author

Choose a reason for hiding this comment

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

intentionally minor; also when we release this, we will update the documents too (currently we're asking users to use zod@3)

'@openai/agents-realtime': minor
'@openai/agents-openai': minor
'@openai/agents-core': minor
'@openai/agents': minor
---

feat: #561 support both zod3 and zod4
2 changes: 1 addition & 1 deletion integration-tests/deno.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('Deno', () => {
await execa`deno install`;
}, 60000);

test('should be able to run', async () => {
test('should be able to run', { timeout: 60000 }, async () => {
Copy link
Member Author

Choose a reason for hiding this comment

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

unrelated improvement

const { stdout } = await execa`deno --allow-net --allow-env main.ts`;
expect(stdout).toContain('[RESPONSE]Hello there![/RESPONSE]');
});
Expand Down
32 changes: 32 additions & 0 deletions integration-tests/node-zod3.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, test, expect, beforeAll } from 'vitest';
import { execa as execaBase } from 'execa';

const execa = execaBase({
cwd: './integration-tests/node-zod3',
env: {
...process.env,
NODE_OPTIONS: '',
TS_NODE_PROJECT: '',
TS_NODE_COMPILER_OPTIONS: '',
},
});

describe('Node.js', () => {
beforeAll(async () => {
// remove lock file to avoid errors
console.log('[node] Removing node_modules');
await execa`rm -rf node_modules`;
console.log('[node] Installing dependencies');
await execa`npm install`;
}, 60000);

test('should be able to run using CommonJS', async () => {
const { stdout } = await execa`npm run start:cjs`;
expect(stdout).toContain('[RESPONSE]Hello there![/RESPONSE]');
});

test('should be able to run using ESM', async () => {
const { stdout } = await execa`npm run start:esm`;
expect(stdout).toContain('[RESPONSE]Hello there![/RESPONSE]');
});
});
2 changes: 2 additions & 0 deletions integration-tests/node-zod3/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@openai:registry=http://localhost:4873
package-lock=false
37 changes: 37 additions & 0 deletions integration-tests/node-zod3/index.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// @ts-check

const {
Agent,
run,
tool,
setTraceProcessors,
ConsoleSpanExporter,
BatchTraceProcessor,
} = require('@openai/agents');

const { z } = require('zod');

setTraceProcessors([new BatchTraceProcessor(new ConsoleSpanExporter())]);

const getWeatherTool = tool({
name: 'get_weather',
description: 'Get the weather for a given city',
parameters: z.object({ city: z.string() }),
execute: async (input) => {
return `The weather in ${input.city} is sunny`;
},
});

const agent = new Agent({
name: 'Test Agent',
instructions:
'You will always only respond with "Hello there!". Not more not less.',
tools: [getWeatherTool],
});

async function main() {
const result = await run(agent, 'Hey there!');
console.log(`[RESPONSE]${result.finalOutput}[/RESPONSE]`);
}

main().catch(console.error);
33 changes: 33 additions & 0 deletions integration-tests/node-zod3/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// @ts-check

import { z } from 'zod';

import {
Agent,
run,
tool,
setTraceProcessors,
ConsoleSpanExporter,
BatchTraceProcessor,
} from '@openai/agents';

setTraceProcessors([new BatchTraceProcessor(new ConsoleSpanExporter())]);

const getWeatherTool = tool({
name: 'get_weather',
description: 'Get the weather for a given city',
parameters: z.object({ city: z.string() }),
execute: async (input) => {
return `The weather in ${input.city} is sunny`;
},
});

const agent = new Agent({
name: 'Test Agent',
instructions:
'You will always only respond with "Hello there!". Not more not less.',
tools: [getWeatherTool],
});

const result = await run(agent, 'What is the weather in San Francisco?');
console.log(`[RESPONSE]${result.finalOutput}[/RESPONSE]`);
13 changes: 13 additions & 0 deletions integration-tests/node-zod3/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"type": "commonjs",
"scripts": {
"start:cjs": "node --no-experimental-require-module index.cjs",
"start:esm": "node --no-experimental-require-module index.mjs"
},
"dependencies": {
"@openai/agents": "latest",
"typescript": "^5.9.3",
"zod": "^3.25.40"
}
}
32 changes: 32 additions & 0 deletions integration-tests/node-zod4.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, test, expect, beforeAll } from 'vitest';
import { execa as execaBase } from 'execa';

const execa = execaBase({
cwd: './integration-tests/node-zod4',
env: {
...process.env,
NODE_OPTIONS: '',
TS_NODE_PROJECT: '',
TS_NODE_COMPILER_OPTIONS: '',
},
});

describe('Node.js', () => {
beforeAll(async () => {
// remove lock file to avoid errors
console.log('[node] Removing node_modules');
await execa`rm -rf node_modules`;
console.log('[node] Installing dependencies');
await execa`npm install`;
}, 60000);

test('should be able to run using CommonJS', async () => {
const { stdout } = await execa`npm run start:cjs`;
expect(stdout).toContain('[RESPONSE]Hello there![/RESPONSE]');
});

test('should be able to run using ESM', async () => {
const { stdout } = await execa`npm run start:esm`;
expect(stdout).toContain('[RESPONSE]Hello there![/RESPONSE]');
});
});
2 changes: 2 additions & 0 deletions integration-tests/node-zod4/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@openai:registry=http://localhost:4873
package-lock=false
37 changes: 37 additions & 0 deletions integration-tests/node-zod4/index.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// @ts-check

const {
Agent,
run,
tool,
setTraceProcessors,
ConsoleSpanExporter,
BatchTraceProcessor,
} = require('@openai/agents');

const { z } = require('zod');

setTraceProcessors([new BatchTraceProcessor(new ConsoleSpanExporter())]);

const getWeatherTool = tool({
name: 'get_weather',
description: 'Get the weather for a given city',
parameters: z.object({ city: z.string() }),
execute: async (input) => {
return `The weather in ${input.city} is sunny`;
},
});

const agent = new Agent({
name: 'Test Agent',
instructions:
'You will always only respond with "Hello there!". Not more not less.',
tools: [getWeatherTool],
});

async function main() {
const result = await run(agent, 'Hey there!');
console.log(`[RESPONSE]${result.finalOutput}[/RESPONSE]`);
}

main().catch(console.error);
33 changes: 33 additions & 0 deletions integration-tests/node-zod4/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// @ts-check

import { z } from 'zod';

import {
Agent,
run,
tool,
setTraceProcessors,
ConsoleSpanExporter,
BatchTraceProcessor,
} from '@openai/agents';

setTraceProcessors([new BatchTraceProcessor(new ConsoleSpanExporter())]);

const getWeatherTool = tool({
name: 'get_weather',
description: 'Get the weather for a given city',
parameters: z.object({ city: z.string() }),
execute: async (input) => {
return `The weather in ${input.city} is sunny`;
},
});

const agent = new Agent({
name: 'Test Agent',
instructions:
'You will always only respond with "Hello there!". Not more not less.',
tools: [getWeatherTool],
});

const result = await run(agent, 'What is the weather in San Francisco?');
console.log(`[RESPONSE]${result.finalOutput}[/RESPONSE]`);
13 changes: 13 additions & 0 deletions integration-tests/node-zod4/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"private": true,
"type": "commonjs",
"scripts": {
"start:cjs": "node --no-experimental-require-module index.cjs",
"start:esm": "node --no-experimental-require-module index.mjs"
},
"dependencies": {
"@openai/agents": "latest",
"typescript": "^5.9.3",
"zod": "^4"
}
}
1 change: 0 additions & 1 deletion integration-tests/node/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const {
ConsoleSpanExporter,
BatchTraceProcessor,
} = require('@openai/agents');
const { assert } = require('node:console');
Copy link
Member Author

Choose a reason for hiding this comment

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

this is unused


setTraceProcessors([new BatchTraceProcessor(new ConsoleSpanExporter())]);

Expand Down
2 changes: 1 addition & 1 deletion integration-tests/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
},
"dependencies": {
"@openai/agents": "latest",
"typescript": "^5.9.2"
"typescript": "^5.9.3"
}
}
24 changes: 24 additions & 0 deletions integration-tests/vite-react.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { describe, test, expect, beforeAll, afterAll } from 'vitest';
import { chromium } from 'playwright';
import { execa as execaBase, ResultPromise } from 'execa';
import { writeFile, unlink } from 'node:fs/promises';
import path from 'node:path';

const execa = execaBase({
cwd: './integration-tests/vite-react',
});

let server: ResultPromise;
const envPath = path.join(
process.cwd(),
'integration-tests',
'vite-react',
'.env',
);
let wroteEnvFile = false;

describe('Vite React', () => {
beforeAll(async () => {
Expand All @@ -16,10 +25,21 @@ describe('Vite React', () => {
await execa`rm -rf node_modules`;
console.log('[vite-react] Installing dependencies');
await execa`npm install`;

const apiKey = process.env.OPENAI_API_KEY;
Copy link
Member Author

Choose a reason for hiding this comment

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

unrelated improvement; easier to run this test

if (!apiKey) {
throw new Error(
'OPENAI_API_KEY must be set to run the Vite React integration test.',
);
}
await writeFile(envPath, `VITE_OPENAI_API_KEY=${apiKey}\n`, 'utf8');
wroteEnvFile = true;

console.log('[vite-react] Building');
await execa`npm run build`;
console.log('[vite-react] Starting server');
server = execa`npm run preview -- --port 9999`;
server.catch(() => {});
await new Promise((resolve) => {
server.stdout?.on('data', (data) => {
if (data.toString().includes('http://localhost')) {
Expand All @@ -41,6 +61,7 @@ describe('Vite React', () => {
const root = await page.$('#root');
const span = await root?.waitForSelector('span[data-testid="response"]', {
state: 'attached',
timeout: 60000,
});
expect(await span?.textContent()).toBe('[RESPONSE]Hello there![/RESPONSE]');
await browser.close();
Expand All @@ -50,5 +71,8 @@ describe('Vite React', () => {
if (server) {
server.kill();
}
if (wroteEnvFile) {
await unlink(envPath).catch(() => {});
}
});
});
4 changes: 2 additions & 2 deletions packages/agents-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"debug": "^4.4.0"
},
"peerDependencies": {
"zod": "^3.25.40"
"zod": "^3.25.40 || ^4.0"
},
"peerDependenciesMeta": {
"zod": {
Expand Down Expand Up @@ -102,7 +102,7 @@
},
"devDependencies": {
"@types/debug": "^4.1.12",
"zod": "^3.25.40"
"zod": "^3.25.40 || ^4.0"
Copy link
Member Author

Choose a reason for hiding this comment

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

align with underlying openai package

},
"files": [
"dist"
Expand Down
Loading