Skip to content

Commit 2b10adc

Browse files
authored
Fix #393 add domain filtering and sources to web search tool (#398)
1 parent dba4bb6 commit 2b10adc

File tree

8 files changed

+109
-10
lines changed

8 files changed

+109
-10
lines changed

.changeset/two-hotels-do.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@openai/agents-openai': patch
3+
'@openai/agents-core': patch
4+
---
5+
6+
Fix #393 add domain filtering and sources to web search tool & upgrade openai package to the latest version

examples/tools/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"start:computer-use": "tsx computer-use.ts",
1212
"start:file-search": "tsx file-search.ts",
1313
"start:web-search": "tsx web-search.ts",
14+
"start:web-search-filters": "tsx web-search-filters.ts",
1415
"start:code-interpreter": "tsx code-interpreter.ts",
1516
"start:image-generation": "tsx image-generation.ts"
1617
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Agent, run, webSearchTool, withTrace } from '@openai/agents';
2+
3+
async function main() {
4+
const agent = new Agent({
5+
name: 'OAI website searcher',
6+
model: 'gpt-5-nano',
7+
instructions:
8+
'You are a helpful agent that can search openai.com resources.',
9+
tools: [
10+
webSearchTool({
11+
// https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses#domain-filtering
12+
filters: {
13+
allowedDomains: [
14+
'openai.com',
15+
'developer.openai.com',
16+
'platform.openai.com',
17+
'help.openai.com',
18+
],
19+
},
20+
searchContextSize: 'medium',
21+
}),
22+
],
23+
modelSettings: {
24+
providerData: {
25+
reasoning: { effort: 'low' },
26+
text: { verbosity: 'low' },
27+
// https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses#sources
28+
include: ['web_search_call.action.sources'],
29+
},
30+
},
31+
});
32+
33+
await withTrace('OpenAI website search example', async () => {
34+
const today = new Date().toISOString().split('T')[0];
35+
const query = `Write a summary of the latest OpenAI Platform updates for developers in the last few weeks (today is ${today}).`;
36+
const result = await run(agent, query);
37+
console.log('\n----- Sources -----\n');
38+
for (const item of result.history) {
39+
if (
40+
item.type === 'hosted_tool_call' &&
41+
item.name === 'web_search_call' &&
42+
item.providerData?.action?.sources
43+
) {
44+
console.log(
45+
JSON.stringify(
46+
item.providerData.action.sources.map((s: any) => s.url),
47+
null,
48+
2,
49+
),
50+
);
51+
}
52+
}
53+
console.log('\n----- Final Output -----\n');
54+
console.log(result.finalOutput);
55+
});
56+
}
57+
58+
main().catch(console.error);

packages/agents-openai/src/openaiResponsesModel.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,16 @@ import {
3636
import { camelOrSnakeToSnakeCase } from './utils/providerData';
3737
import { ProviderData } from '@openai/agents-core/types';
3838

39-
type ToolChoice = ToolChoiceOptions | ToolChoiceTypes | ToolChoiceFunction;
39+
type ToolChoice =
40+
| ToolChoiceOptions
41+
| ToolChoiceTypes
42+
// TOOD: remove this once the underlying ToolChoiceTypes include this
43+
| { type: 'web_search' }
44+
| ToolChoiceFunction;
4045

4146
const HostedToolChoice = z.enum([
4247
'file_search',
48+
'web_search',
4349
'web_search_preview',
4450
'computer_use_preview',
4551
'code_interpreter',
@@ -137,6 +143,16 @@ function converTool<_TContext = unknown>(
137143
};
138144
} else if (tool.type === 'hosted_tool') {
139145
if (tool.providerData?.type === 'web_search') {
146+
return {
147+
tool: {
148+
type: 'web_search',
149+
user_location: tool.providerData.user_location,
150+
filters: tool.providerData.filters,
151+
search_context_size: tool.providerData.search_context_size,
152+
},
153+
include: undefined,
154+
};
155+
} else if (tool.providerData?.type === 'web_search_preview') {
140156
return {
141157
tool: {
142158
type: 'web_search_preview',

packages/agents-openai/src/tools.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,25 @@ export const ImageGenerationStatus = z
2929

3030
/**
3131
* The built-in Web search tool
32+
*
33+
* see https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses
3234
*/
3335
export type WebSearchTool = {
3436
type: 'web_search';
35-
name?: 'web_search_preview' | string;
37+
name?: 'web_search' | 'web_search_preview' | string;
3638
/**
3739
* Optional location for the search. Lets you customize results to be relevant to a location.
3840
*/
39-
userLocation?: OpenAI.Responses.WebSearchTool.UserLocation;
41+
userLocation?: OpenAI.Responses.Tool.WebSearchTool.UserLocation;
42+
43+
/**
44+
* Optional filters for the search.
45+
*/
46+
filters?: { allowedDomains?: Array<string> | null };
47+
4048
/**
41-
* The amount of context to use for the search.
49+
* High level guidance for the amount of context window space to use for the
50+
* search. One of `low`, `medium`, or `high`. `medium` is the default.
4251
*/
4352
searchContextSize: 'low' | 'medium' | 'high';
4453
};
@@ -53,13 +62,16 @@ export function webSearchTool(
5362
): HostedTool {
5463
const providerData: ProviderData.WebSearchTool = {
5564
type: 'web_search',
56-
name: options.name ?? 'web_search_preview',
65+
name: options.name ?? 'web_search',
5766
user_location: options.userLocation,
67+
filters: options.filters?.allowedDomains
68+
? { allowed_domains: options.filters.allowedDomains }
69+
: undefined,
5870
search_context_size: options.searchContextSize ?? 'medium',
5971
};
6072
return {
6173
type: 'hosted_tool',
62-
name: options.name ?? 'web_search_preview',
74+
name: options.name ?? 'web_search',
6375
providerData,
6476
};
6577
}

packages/agents-openai/src/types/providerData.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import OpenAI from 'openai';
22

3-
export type WebSearchTool = Omit<OpenAI.Responses.WebSearchTool, 'type'> & {
3+
export type WebSearchTool = Omit<
4+
OpenAI.Responses.Tool.WebSearchTool,
5+
'type'
6+
> & {
47
type: 'web_search';
5-
name: 'web_search_preview' | string;
8+
name: 'web_search' | 'web_search_preview' | string;
69
};
710

811
export type FileSearchTool = Omit<OpenAI.Responses.FileSearchTool, 'type'> & {

packages/agents-openai/test/openaiResponsesModel.helpers.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ describe('getToolChoice', () => {
1616

1717
it('handles hosted tool choices', () => {
1818
expect(getToolChoice('file_search')).toEqual({ type: 'file_search' });
19+
expect(getToolChoice('web_search')).toEqual({
20+
type: 'web_search',
21+
});
1922
expect(getToolChoice('web_search_preview')).toEqual({
2023
type: 'web_search_preview',
2124
});
@@ -77,7 +80,7 @@ describe('converTool', () => {
7780
},
7881
} as any);
7982
expect(web.tool).toEqual({
80-
type: 'web_search_preview',
83+
type: 'web_search',
8184
user_location: {},
8285
search_context_size: 'low',
8386
});

packages/agents-openai/test/tools.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ describe('Tool', () => {
88
});
99
expect(t).toBeDefined();
1010
expect(t.type).toBe('hosted_tool');
11-
expect(t.name).toBe('web_search_preview');
11+
expect(t.name).toBe('web_search');
1212
});
1313

1414
it('fileSearchTool', () => {

0 commit comments

Comments
 (0)