SpyBara
Go Premium

Documentation 2026-07-20 21:59 UTC to 2026-07-21 15:00 UTC

60 files changed +1,294 −1,227. View all changes and history on the product overview
2026
Thu 23 03:02 Wed 22 20:02 Tue 21 15:00 Mon 20 21:59 Sat 18 22:00 Fri 17 19:58 Thu 16 17:00 Wed 15 16:58 Tue 14 21:58 Mon 13 21:58 Sat 11 07:01 Fri 10 23:02 Thu 9 17:03 Wed 8 22:02 Mon 6 22:58 Sat 4 16:59
Details

156Create a project spend limit alert156Create a project spend limit alert

157 157 

158```javascript158```javascript

159const spendAlert =159const spendAlert = await client.admin.organization.projects.spendAlerts.create(

160 await client.admin.organization.projects.spendAlerts.create("proj_abc", {160 "proj_abc",

161 {

161 currency: "USD",162 currency: "USD",

162 interval: "month",163 interval: "month",

163 notification_channel: {164 notification_channel: {


166 subject_prefix: "[OpenAI spend]",167 subject_prefix: "[OpenAI spend]",

167 },168 },

168 threshold_amount: 50000,169 threshold_amount: 50000,

169 });170 }

171);

170 172 

171console.log(spendAlert.id);173console.log(spendAlert.id);

172```174```

Details

91 outputType: calendarEvent,91 outputType: calendarEvent,

92});92});

93 93 

94const result = await run(94const result = await run(agent, "Dinner with Priya and Sam on Friday.");

95 agent,

96 "Dinner with Priya and Sam on Friday.",

97);

98 95 

99console.log(result.finalOutput);96console.log(result.finalOutput);

100```97```

Details

21Block a request with an input guardrail21Block a request with an input guardrail

22 22 

23```typescript23```typescript

24import {24import { Agent, InputGuardrailTripwireTriggered, run } from "@openai/agents";

25 Agent,

26 InputGuardrailTripwireTriggered,

27 run,

28} from "@openai/agents";

29import { z } from "zod";25import { z } from "zod";

30 26 

31const guardrailAgent = new Agent({27const guardrailAgent = new Agent({

Details

62 62 

63const server = new MCPServerStdio({63const server = new MCPServerStdio({

64 name: "Filesystem MCP Server",64 name: "Filesystem MCP Server",

65 fullCommand: "npx -y @modelcontextprotocol/server-filesystem ./sample_files",65 fullCommand:

66 "npx -y @modelcontextprotocol/server-filesystem fixtures/sample_files",

66});67});

67 68 

68await server.connect();69await server.connect();

Details

33await runner.run(fastAgent, "Summarize ticket 123.");33await runner.run(fastAgent, "Summarize ticket 123.");

34const result = await runner.run(34const result = await runner.run(

35 generalAgent,35 generalAgent,

36 "Investigate the billing issue on account 456.",36 "Investigate the billing issue on account 456."

37);37);

38 38 

39console.log(result.finalOutput);39console.log(result.finalOutput);

Details

34 34 

35const agent = new Agent({35const agent = new Agent({

36 name: "History tutor",36 name: "History tutor",

37 instructions:37 instructions: "You answer history questions clearly and concisely.",

38 "You answer history questions clearly and concisely.",

39 model: "gpt-5.6",38 model: "gpt-5.6",

40});39});

41 40 


108 107 

109const result = await run(108const result = await run(

110 agent,109 agent,

111 "Tell me something surprising about ancient life on Earth.",110 "Tell me something surprising about ancient life on Earth."

112);111);

113 112 

114console.log(result.finalOutput);113console.log(result.finalOutput);


175 174 

176const result = await run(175const result = await run(

177 triageAgent,176 triageAgent,

178 "Who was the first president of the United States?",177 "Who was the first president of the United States?"

179);178);

180 179 

181console.log(result.finalOutput);180console.log(result.finalOutput);

Details

39 39 

40const session = new MemorySession();40const session = new MemorySession();

41 41 

42const firstTurn = await run(42const firstTurn = await run(agent, "What city is the Golden Gate Bridge in?", {

43 agent,43 session,

44 "What city is the Golden Gate Bridge in?",44});

45 { session },

46);

47console.log(firstTurn.finalOutput);45console.log(firstTurn.finalOutput);

48 46 

49const secondTurn = await run(agent, "What state is it in?", { session });47const secondTurn = await run(agent, "What state is it in?", { session });


165for await (const event of stream) {163for await (const event of stream) {

166 if (164 if (

167 event.type === "raw_model_stream_event" &&165 event.type === "raw_model_stream_event" &&

168 event.data.type === "response.output_text.delta"166 event.data.type === "output_text_delta"

169 ) {167 ) {

170 process.stdout.write(event.data.delta);168 process.stdout.write(event.data.delta);

171 }169 }

Details

267 267 

268```typescript268```typescript

269import { run } from "@openai/agents";269import { run } from "@openai/agents";

270import {270import { Manifest, SandboxAgent, file, shell } from "@openai/agents/sandbox";

271 Manifest,

272 SandboxAgent,

273 file,

274 shell,

275} from "@openai/agents/sandbox";

276import { UnixLocalSandboxClient } from "@openai/agents/sandbox/local";271import { UnixLocalSandboxClient } from "@openai/agents/sandbox/local";

277 272 

278const manifest = new Manifest({273const manifest = new Manifest({


309 sandbox: {304 sandbox: {

310 client: new UnixLocalSandboxClient(),305 client: new UnixLocalSandboxClient(),

311 },306 },

312 },307 }

313);308);

314 309 

315console.log(result.finalOutput);310console.log(result.finalOutput);


512}507}

513 508 

514const resumedSession = await client.resume(509const resumedSession = await client.resume(

515 await client.deserializeSessionState(frozenSessionState),510 await client.deserializeSessionState(frozenSessionState)

516);511);

517 512 

518try {513try {

Details

155residency jurisdictions. Teams with residency requirements should evaluate the155residency jurisdictions. Teams with residency requirements should evaluate the

156Bedrock Region itself and the corresponding AWS terms.156Bedrock Region itself and the corresponding AWS terms.

157 157 

158## Data access and retention

159 

160Amazon Bedrock uses separate controls for operator access and data retention:

161 

162- **[Zero operator access (ZOA)](https://aws.amazon.com/blogs/machine-learning/exploring-the-zero-operator-access-design-of-mantle/)**

163 prevents service operators from accessing model inputs and outputs processed

164 by Mantle.

165- **[Zero data retention (ZDR)](https://docs.aws.amazon.com/bedrock/latest/userguide/data-retention.html)**

166 means AWS does not write model inputs or outputs to durable storage or share

167 them with OpenAI when the effective retention mode is `none`.

168 

169[Configure Bedrock data

170retention](https://docs.aws.amazon.com/bedrock/latest/userguide/data-retention.html#data-retention-configuration)

171for your AWS account or project. For requests sent directly to the OpenAI API,

172use the separate [OpenAI Zero Data Retention

173controls](https://developers.openai.com/api/docs/guides/your-data#zero-data-retention).

174 

175Under the `default` retention mode, retention depends on the model and request

176settings. For specific OpenAI GPT models, AWS retains classifier-flagged traffic

177for up to 30 days for automated offline abuse detection. AWS stores and

178processes this data and does not share it with OpenAI. On the Responses API,

179`store` defaults to `true`, so AWS may store response data beyond abuse

180detection. See [Amazon Bedrock abuse

181detection](https://docs.aws.amazon.com/bedrock/latest/userguide/abuse-detection.html)

182for the current model list and retention details.

183 

184If you need full ZDR for a model that requires retention, [contact your AWS

185account

186manager](https://docs.aws.amazon.com/bedrock/latest/userguide/data-retention.html#data-retention-zdr)

187to discuss eligibility. AWS evaluates ZDR access for each account and model. If

188AWS approves access, confirm that `none` appears in the model's `allowed_modes`,

189then set the account or project retention mode to `none`. Setting `store: false`

190does not guarantee ZDR. When the effective retention mode is `none`, AWS rejects

191`store: true`, and background mode is unavailable.

192 

193If AWS detects apparent CSAM in an image input, AWS may store and review the

194 flagged input or output only to determine whether it is CSAM. AWS may also

195 file a report with national authorities.

196 

158## Responses API feature availability197## Responses API feature availability

159 198 

160Amazon Bedrock supports a subset of Responses API capabilities available199Amazon Bedrock supports a subset of Responses API capabilities available

guides/audio.md +9 −6

Details

95 messages: [95 messages: [

96 {96 {

97 role: "user",97 role: "user",

98 content: "Is a golden retriever a good family dog?"98 content: "Is a golden retriever a good family dog?",

99 }99 },

100 ],100 ],

101 store: true,101 store: true,

102});102});


107// Write audio data to a file107// Write audio data to a file

108writeFileSync(108writeFileSync(

109 "dog.wav",109 "dog.wav",

110 Buffer.from(response.choices[0].message.audio.data, 'base64'),110 Buffer.from(response.choices[0].message.audio.data, "base64"),

111 { encoding: "utf-8" }111 { encoding: "utf-8" }

112);112);

113```113```


178 role: "user",178 role: "user",

179 content: [179 content: [

180 { type: "text", text: "What is in this recording?" },180 { type: "text", text: "What is in this recording?" },

181 { type: "input_audio", input_audio: { data: base64str, format: "wav" }}181 {

182 ]182 type: "input_audio",

183 }183 input_audio: { data: base64str, format: "wav" },

184 },

185 ],

186 },

184 ],187 ],

185 store: true,188 store: true,

186});189});

Details

66const client = new OpenAI();66const client = new OpenAI();

67 67 

68let resp = await client.responses.create({68let resp = await client.responses.create({

69model: "gpt-5.6",69 model: "gpt-5.6",

70input: "Write a very long novel about otters in space.",70 input: "Write a very long novel about otters in space.",

71background: true,71 background: true,

72});72});

73 73 

74while (resp.status === "queued" || resp.status === "in_progress") {74while (resp.status === "queued" || resp.status === "in_progress") {

75console.log("Current status: " + resp.status);75 console.log("Current status: " + resp.status);

76await new Promise(resolve => setTimeout(resolve, 2000)); // wait 2 seconds76 await new Promise((resolve) => setTimeout(resolve, 2000)); // wait 2 seconds

77resp = await client.responses.retrieve(resp.id);77 resp = await client.responses.retrieve(resp.id);

78}78}

79 79 

80console.log("Final status: " + resp.status + "\nOutput:\n" + resp.output_text);80console.log("Final status: " + resp.status + "\nOutput:\n" + resp.output_text);

guides/batch.md +2 −2

Details

109const openai = new OpenAI();109const openai = new OpenAI();

110 110 

111const file = await openai.files.create({111const file = await openai.files.create({

112 file: fs.createReadStream("batchinput.jsonl"),112 file: fs.createReadStream("fixtures/batchinput.jsonl"),

113 purpose: "batch",113 purpose: "batch",

114});114});

115 115 


155const batch = await openai.batches.create({155const batch = await openai.batches.create({

156 input_file_id: "file-abc123",156 input_file_id: "file-abc123",

157 endpoint: "/v1/chat/completions",157 endpoint: "/v1/chat/completions",

158 completion_window: "24h"158 completion_window: "24h",

159});159});

160 160 

161console.log(batch);161console.log(batch);

guides/chatkit.md +43 −20

Details

78 78 

79```typescript79```typescript

80export default async function getChatKitSessionToken(80export default async function getChatKitSessionToken(

81deviceId: string81 deviceId: string

82): Promise<string> {82): Promise<string> {

83const response = await fetch("https://api.openai.com/v1/chatkit/sessions", {83 const apiKey = process.env.OPENAI_API_KEY;

84 if (!apiKey) {

85 throw new Error("OPENAI_API_KEY is required");

86 }

87 

88 const response = await fetch("https://api.openai.com/v1/chatkit/sessions", {

84 method: "POST",89 method: "POST",

85 headers: {90 headers: {

86 "Content-Type": "application/json",91 "Content-Type": "application/json",

87 "OpenAI-Beta": "chatkit_beta=v1",92 "OpenAI-Beta": "chatkit_beta=v1",

88 Authorization: "Bearer " + process.env.VITE_OPENAI_API_SECRET_KEY,93 Authorization: `Bearer ${apiKey}`,

89 },94 },

90 body: JSON.stringify({95 body: JSON.stringify({

91 workflow: { id: "wf_68df4b13b3588190a09d19288d4610ec0df388c3983f58d1" },96 workflow: { id: "wf_68df4b13b3588190a09d19288d4610ec0df388c3983f58d1" },

92 user: deviceId,97 user: deviceId,

93 }),98 }),

94});99 });

95 100 

96const { client_secret } = await response.json();101 if (!response.ok) {

102 throw new Error(

103 `Failed to create a ChatKit session: ${response.status} ${await response.text()}`

104 );

105 }

97 106 

98return client_secret;107 const { client_secret } = (await response.json()) as {

108 client_secret?: string;

109 };

110 if (!client_secret) {

111 throw new Error("ChatKit session response did not include client_secret");

112 }

113 

114 return client_secret;

99}115}

100```116```

101 117 


150```166```

151 167 

152```javascript168```javascript

153const chatkit = document.getElementById('my-chat');169const chatkit = document.getElementById("my-chat");

170if (

171 !chatkit ||

172 !("setOptions" in chatkit) ||

173 typeof chatkit.setOptions !== "function"

174) {

175 throw new Error("ChatKit element not found.");

176}

154 177 

155 chatkit.setOptions({178chatkit.setOptions({

156 api: {179 api: {

157 getClientSecret(currentClientSecret) {180 async getClientSecret(currentClientSecret) {

158 if (!currentClientSecret) {181 if (!currentClientSecret) {

159 const res = await fetch('/api/chatkit/start', { method: 'POST' })182 const res = await fetch("/api/chatkit/start", { method: "POST" });

160 const {client_secret} = await res.json();183 const { client_secret } = await res.json();

161 return client_secret184 return client_secret;

162 }185 }

163 const res = await fetch('/api/chatkit/refresh', {186 const res = await fetch("/api/chatkit/refresh", {

164 method: 'POST',187 method: "POST",

165 body: JSON.stringify({ currentClientSecret })188 body: JSON.stringify({ currentClientSecret }),

166 headers: {189 headers: {

167 'Content-Type': 'application/json',190 "Content-Type": "application/json",

168 },191 },

169 });192 });

170 const {client_secret} = await res.json();193 const { client_secret } = await res.json();

171 return client_secret194 return client_secret;

172 }

173 },195 },

174 });196 },

197});

175```198```

176 199 

177 200 

Details

71 71 

72const openai = new OpenAI();72const openai = new OpenAI();

73 73 

74/** @type {OpenAI.Responses.ResponseInput} */

74let history = [75let history = [

75 {76 {

76 role: "user",77 role: "user",


87console.log(response.output_text);88console.log(response.output_text);

88 89 

89// Add all response output items, including reasoning items, to the history90// Add all response output items, including reasoning items, to the history

90history = [...history, ...response.output];91history.push(...response.output);

91 92 

92history.push({93history.push({

93 role: "user",94 role: "user",


195const secondResponse = await openai.responses.create({196const secondResponse = await openai.responses.create({

196 model: "gpt-5.6",197 model: "gpt-5.6",

197 previous_response_id: response.id,198 previous_response_id: response.id,

198 input: [{"role": "user", "content": "explain why this is funny."}],199 input: [{ role: "user", content: "explain why this is funny." }],

199 store: true,200 store: true,

200});201});

201 202 


242const secondResponse = await openai.responses.create({243const secondResponse = await openai.responses.create({

243 model: "gpt-5.6",244 model: "gpt-5.6",

244 previous_response_id: response.id,245 previous_response_id: response.id,

245 input: [{"role": "user", "content": "explain why this is funny."}],246 input: [{ role: "user", content: "explain why this is funny." }],

246 store: true,247 store: true,

247});248});

248 249 

Details

79 type: "file_search",78 type: "file_search",

80 vector_store_ids: [79 vector_store_ids: [

81 "vs_68870b8868b88191894165101435eef6",80 "vs_68870b8868b88191894165101435eef6",

82 "vs_12345abcde6789fghijk101112131415"81 "vs_12345abcde6789fghijk101112131415",

83 ],82 ],

84 },83 },

85 { type: "code_interpreter", container: { type: "auto" } },84 { type: "code_interpreter", container: { type: "auto" } },


232const input = "Research surfboards for me. I'm interested in ...";231const input = "Research surfboards for me. I'm interested in ...";

233 232 

234const response = await openai.responses.create({233const response = await openai.responses.create({

235model: "gpt-5.6",234 model: "gpt-5.6",

236input,235 input,

237instructions,236 instructions,

238});237});

239 238 

240console.log(response.output_text);239console.log(response.output_text);


503 },502 },

504 ],503 ],

505 instructions,504 instructions,

506 input: "What similarities are in the notes for our closed/lost Salesforce opportunities?",505 input:

506 "What similarities are in the notes for our closed/lost Salesforce opportunities?",

507});507});

508 508 

509console.log(resp.output_text);509console.log(resp.output_text);

Details

253 253 

254const openai = new OpenAI();254const openai = new OpenAI();

255 255 

256/** @type {OpenAI.Responses.Tool} */

256const billingNamespace = {257const billingNamespace = {

257 type: "namespace",258 type: "namespace",

258 name: "billing",259 name: "billing",


261 {262 {

262 type: "function",263 type: "function",

263 name: "lookup_invoice",264 name: "lookup_invoice",

264 description: "Look up invoice state, taxes, credits, and payment attempts.",265 description:

266 "Look up invoice state, taxes, credits, and payment attempts.",

265 parameters: {267 parameters: {

266 type: "object",268 type: "object",

267 properties: {269 properties: {


276 ],278 ],

277};279};

278 280 

281/** @type {OpenAI.Responses.Tool} */

279const crmNamespace = {282const crmNamespace = {

280 type: "namespace",283 type: "namespace",

281 name: "crm",284 name: "crm",

282 description: "CRM tools for account ownership, plans, health, and payment history.",285 description:

286 "CRM tools for account ownership, plans, health, and payment history.",

283 tools: [287 tools: [

284 {288 {

285 type: "function",289 type: "function",


654 658 

655const openai = new OpenAI();659const openai = new OpenAI();

656 660 

661/** @type {OpenAI.Responses.ResponseInput} */

657const history = [662const history = [

658 {663 {

659 role: "user",664 role: "user",

guides/evals.md +7 −3

Details

150 type: "object",150 type: "object",

151 properties: {151 properties: {

152 ticket_text: { type: "string" },152 ticket_text: { type: "string" },

153 correct_label: { type: "string" }153 correct_label: { type: "string" },

154 },154 },

155 required: ["ticket_text", "correct_label"],155 required: ["ticket_text", "correct_label"],

156 },156 },


308const openai = new OpenAI();308const openai = new OpenAI();

309 309 

310const file = await openai.files.create({310const file = await openai.files.create({

311 file: fs.createReadStream("tickets.jsonl"),311 file: fs.createReadStream("fixtures/tickets.jsonl"),

312 purpose: "evals",312 purpose: "evals",

313});313});

314 314 


386 input_messages: {386 input_messages: {

387 type: "template",387 type: "template",

388 template: [388 template: [

389 { role: "developer", content: "You are an expert in categorizing IT support tickets. Given the support ticket below, categorize the request into one of 'Hardware', 'Software', or 'Other'. Respond with only one of those words." },389 {

390 role: "developer",

391 content:

392 "You are an expert in categorizing IT support tickets. Given the support ticket below, categorize the request into one of 'Hardware', 'Software', or 'Other'. Respond with only one of those words.",

393 },

390 { role: "user", content: "{{ item.ticket_text }}" },394 { role: "user", content: "{{ item.ticket_text }}" },

391 ],395 ],

392 },396 },

Details

263const client = new OpenAI();263const client = new OpenAI();

264 264 

265const file = await client.files.create({265const file = await client.files.create({

266 file: fs.createReadStream("draconomicon.pdf"),266 file: fs.createReadStream("fixtures/draconomicon.pdf"),

267 purpose: "user_data",267 purpose: "user_data",

268});268});

269 269 


409import OpenAI from "openai";409import OpenAI from "openai";

410const client = new OpenAI();410const client = new OpenAI();

411 411 

412const data = fs.readFileSync("draconomicon.pdf");412const data = fs.readFileSync("fixtures/draconomicon.pdf");

413const base64String = data.toString("base64");413const base64String = data.toString("base64");

414 414 

415const response = await client.responses.create({415const response = await client.responses.create({

Details

20 timeout: 15 * 1000 * 60, // Increase default timeout to 15 minutes20 timeout: 15 * 1000 * 60, // Increase default timeout to 15 minutes

21});21});

22 22 

23const response = await client.responses.create({23const response = await client.responses.create(

24 {

24 model: "gpt-5.6",25 model: "gpt-5.6",

25 instructions: "List and describe all the metaphors used in this book.",26 instructions: "List and describe all the metaphors used in this book.",

26 input: "<very long text of book here>",27 input: "<very long text of book here>",

27 service_tier: "flex",28 service_tier: "flex",

28}, { timeout: 15 * 1000 * 60 });29 },

30 { timeout: 15 * 1000 * 60 }

31);

29 32 

30console.log(response.output_text);33console.log(response.output_text);

31```34```

Details

150const openai = new OpenAI();150const openai = new OpenAI();

151 151 

152// 1. Define a list of callable tools for the model152// 1. Define a list of callable tools for the model

153/** @type {OpenAI.Responses.Tool[]} */

153const tools = [154const tools = [

154 {155 {

155 type: "function",156 type: "function",


175}176}

176 177 

177// Create a running input list we will add to over time178// Create a running input list we will add to over time

179/** @type {OpenAI.Responses.ResponseInput} */

178let input = [180let input = [

179 { role: "user", content: "What is my horoscope? I am an Aquarius." },181 { role: "user", content: "What is my horoscope? I am an Aquarius." },

180];182];


413 const name = toolCall.name;415 const name = toolCall.name;

414 const args = JSON.parse(toolCall.arguments);416 const args = JSON.parse(toolCall.arguments);

415 417 

416 const result = callFunction(name, args);418 const result = await callFunction(name, args);

417 input.push({419 input.push({

418 type: "function_call_output",420 type: "function_call_output",

419 call_id: toolCall.call_id,421 call_id: toolCall.call_id,

420 output: result.toString()422 output: result.toString(),

421 });423 });

422}424}

423```425```


691 693 

692const openai = new OpenAI();694const openai = new OpenAI();

693 695 

694const tools = [{696/** @type {OpenAI.Responses.Tool[]} */

697const tools = [

698 {

695 type: "function",699 type: "function",

696 name: "get_weather",700 name: "get_weather",

697 description: "Get current temperature for provided coordinates in celsius.",701 description: "Get current temperature for provided coordinates in celsius.",


699 type: "object",703 type: "object",

700 properties: {704 properties: {

701 latitude: { type: "number" },705 latitude: { type: "number" },

702 longitude: { type: "number" }706 longitude: { type: "number" },

703 },707 },

704 required: ["latitude", "longitude"],708 required: ["latitude", "longitude"],

705 additionalProperties: false709 additionalProperties: false,

706 },710 },

707 strict: true711 strict: true,

708}];712 },

713];

709 714 

710const stream = await openai.responses.create({715const stream = await openai.responses.create({

711 model: "gpt-5.6",716 model: "gpt-5.6",


716});721});

717 722 

718for await (const event of stream) {723for await (const event of stream) {

719 console.log(event)724 console.log(event);

720}725}

721```726```

722 727 


777const finalToolCalls = {};782const finalToolCalls = {};

778 783 

779for await (const event of stream) {784for await (const event of stream) {

780 if (event.type === 'response.output_item.added') {785 if (event.type === "response.output_item.added") {

781 finalToolCalls[event.output_index] = event.item;786 finalToolCalls[event.output_index] = event.item;

782 } else if (event.type === 'response.function_call_arguments.delta') {787 } else if (event.type === "response.function_call_arguments.delta") {

783 const index = event.output_index;788 const index = event.output_index;

784 789 

785 if (finalToolCalls[index]) {790 if (finalToolCalls[index]) {


1106import OpenAI from "openai";1111import OpenAI from "openai";

1107const client = new OpenAI();1112const client = new OpenAI();

1108 1113 

1109const grammar = "^(?P<month>January|February|March|April|May|June|July|August|September|October|November|December)\s+(?P<day>\d{1,2})(?:st|nd|rd|th)?\s+(?P<year>\d{4})\s+at\s+(?P<hour>0?[1-9]|1[0-2])(?P<ampm>AM|PM)$";1114const grammar =

1115 "^(?P<month>January|February|March|April|May|June|July|August|September|October|November|December)\\s+(?P<day>\\d{1,2})(?:st|nd|rd|th)?\\s+(?P<year>\\d{4})\\s+at\\s+(?P<hour>0?[1-9]|1[0-2])(?P<ampm>AM|PM)$";

1110 1116 

1111const response = await client.responses.create({1117const response = await client.responses.create({

1112 model: "gpt-5.6",1118 model: "gpt-5.6",

1113 input: "Use the timestamp tool to save a timestamp for August 7th 2025 at 10AM.",1119 input:

1120 "Use the timestamp tool to save a timestamp for August 7th 2025 at 10AM.",

1114 tools: [1121 tools: [

1115 {1122 {

1116 type: "custom",1123 type: "custom",

Details

140 140 

141const response = await openai.responses.create({141const response = await openai.responses.create({

142 model: "gpt-5.6",142 model: "gpt-5.6",

143 input: "Generate an image of gray tabby cat hugging an otter with an orange scarf",143 input:

144 tools: [{type: "image_generation"}],144 "Generate an image of gray tabby cat hugging an otter with an orange scarf",

145 tools: [{ type: "image_generation" }],

145});146});

146 147 

147// Save the image to a file148// Save the image to a file


200 201 

201const response = await openai.responses.create({202const response = await openai.responses.create({

202 model: "gpt-5.6",203 model: "gpt-5.6",

203 input: "Generate an image of gray tabby cat hugging an otter with an orange scarf",204 input:

204 tools: [{type: "image_generation", action: "generate"}],205 "Generate an image of gray tabby cat hugging an otter with an orange scarf",

206 tools: [{ type: "image_generation", action: "generate" }],

205});207});

206 208 

207// Save the image to a file209// Save the image to a file


731`;733`;

732 734 

733const imageFiles = [735const imageFiles = [

734 "bath-bomb.png",736 "fixtures/bath-bomb.png",

735 "body-lotion.png",737 "fixtures/body-lotion.png",

736 "incense-kit.png",738 "fixtures/incense-kit.png",

737 "soap.png",739 "fixtures/soap.png",

738];740];

739 741 

740const images = await Promise.all(742const images = await Promise.all(

741 imageFiles.map(async (file) =>743 imageFiles.map(

744 async (file) =>

742 await toFile(fs.createReadStream(file), null, {745 await toFile(fs.createReadStream(file), null, {

743 type: "image/png",746 type: "image/png",

744 })747 })

745 ),748 )

746);749);

747 750 

748const response = await client.images.edit({751const response = await client.images.edit({


871 return result.id;874 return result.id;

872}875}

873 876 

874const fileId = await createFile("sunlit_lounge.png");877const fileId = await createFile("fixtures/sunlit_lounge.png");

875const maskId = await createFile("mask.png");878const maskId = await createFile("fixtures/mask.png");

876 879 

877const response = await openai.responses.create({880const response = await openai.responses.create({

878 model: "gpt-5.6",881 model: "gpt-5.6",


887 {890 {

888 type: "input_image",891 type: "input_image",

889 file_id: fileId,892 file_id: fileId,

890 }893 detail: "auto",

894 },

891 ],895 ],

892 },896 },

893 ],897 ],


897 quality: "high",901 quality: "high",

898 input_image_mask: {902 input_image_mask: {

899 file_id: maskId,903 file_id: maskId,

900 }904 },

901 },905 },

902 ],906 ],

903});907});


946 950 

947const rsp = await client.images.edit({951const rsp = await client.images.edit({

948 model: "gpt-image-2",952 model: "gpt-image-2",

949 image: await toFile(fs.createReadStream("sunlit_lounge.png"), null, {953 image: await toFile(fs.createReadStream("fixtures/sunlit_lounge.png"), null, {

950 type: "image/png",954 type: "image/png",

951 }),955 }),

952 mask: await toFile(fs.createReadStream("mask.png"), null, {956 mask: await toFile(fs.createReadStream("fixtures/mask.png"), null, {

953 type: "image/png",957 type: "image/png",

954 }),958 }),

955 prompt: "A sunlit indoor lounge area with a pool containing a flamingo",959 prompt: "A sunlit indoor lounge area with a pool containing a flamingo",


1238 hint =1242 hint =

1239 "Try removing abusive or targeting language and focus on neutral visual details instead.";1243 "Try removing abusive or targeting language and focus on neutral visual details instead.";

1240 } else if (stage === "input") {1244 } else if (stage === "input") {

1241 hint = "Try revising the prompt or input images and submit the request again.";1245 hint =

1246 "Try revising the prompt or input images and submit the request again.";

1242 } else if (stage === "output") {1247 } else if (stage === "output") {

1243 hint = "The generated result was blocked by a safety check. Try changing the prompt and generating again.";1248 hint =

1249 "The generated result was blocked by a safety check. Try changing the prompt and generating again.";

1244 }1250 }

1245 1251 

1246 console.error("Image generation blocked", {1252 console.error("Image generation blocked", {

Details

38 38 

39const response = await openai.responses.create({39const response = await openai.responses.create({

40 model: "gpt-5.6",40 model: "gpt-5.6",

41 input: "Generate an image of gray tabby cat hugging an otter with an orange scarf",41 input:

42 tools: [{type: "image_generation"}],42 "Generate an image of gray tabby cat hugging an otter with an orange scarf",

43 tools: [{ type: "image_generation" }],

43});44});

44 45 

45// Save the image to a file46// Save the image to a file


133 134 

134const response = await openai.responses.create({135const response = await openai.responses.create({

135 model: "gpt-5.6",136 model: "gpt-5.6",

136 input: [{137 input: [

138 {

137 role: "user",139 role: "user",

138 content: [140 content: [

139 { type: "input_text", text: "what's in this image?" },141 { type: "input_text", text: "what's in this image?" },

140 {142 {

141 type: "input_image",143 type: "input_image",

142 image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",144 image_url:

145 "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",

146 detail: "auto",

147 },

148 ],

143 },149 },

144 ],150 ],

145 }],

146});151});

147 152 

148console.log(response.output_text);153console.log(response.output_text);


235 240 

236const openai = new OpenAI();241const openai = new OpenAI();

237 242 

238const imagePath = "path_to_your_image.jpg";243const imagePath = "fixtures/example.jpg";

239const base64Image = fs.readFileSync(imagePath, "base64");244const base64Image = fs.readFileSync(imagePath, "base64");

240 245 

241const response = await openai.responses.create({246const response = await openai.responses.create({


248 {253 {

249 type: "input_image",254 type: "input_image",

250 image_url: `data:image/jpeg;base64,${base64Image}`,255 image_url: `data:image/jpeg;base64,${base64Image}`,

256 detail: "auto",

251 },257 },

252 ],258 ],

253 },259 },


351}357}

352 358 

353// Getting the file ID359// Getting the file ID

354const fileId = await createFile("path_to_your_image.jpg");360const fileId = await createFile("fixtures/example.jpg");

355 361 

356const response = await openai.responses.create({362const response = await openai.responses.create({

357 model: "gpt-5.6",363 model: "gpt-5.6",


363 {369 {

364 type: "input_image",370 type: "input_image",

365 file_id: fileId,371 file_id: fileId,

372 detail: "auto",

366 },373 },

367 ],374 ],

368 },375 },

Details

74 74 

75const response = await openai.responses.create({75const response = await openai.responses.create({

76 model: "gpt-5.2",76 model: "gpt-5.2",

77 input: "Think carefully and outline your steps before answering. How much gold would it take to coat the Statue of Liberty in a 1mm layer?",77 input:

78 "Think carefully and outline your steps before answering. How much gold would it take to coat the Statue of Liberty in a 1mm layer?",

78 reasoning: {79 reasoning: {

79 effort: "none"80 effort: "none",

80 }81 },

81});82});

82 83 

83console.log(response);84console.log(response);


132 133 

133const response = await openai.responses.create({134const response = await openai.responses.create({

134 model: "gpt-5.2",135 model: "gpt-5.2",

135 input: "What is the answer to the ultimate question of life, the universe, and everything?",136 input:

137 "What is the answer to the ultimate question of life, the universe, and everything?",

136 text: {138 text: {

137 verbosity: "low"139 verbosity: "low",

138 }140 },

139});141});

140 142 

141console.log(response);143console.log(response);

Details

77 77 

78const response = await openai.responses.create({78const response = await openai.responses.create({

79 model: "gpt-5.4",79 model: "gpt-5.4",

80 input: "Think carefully and outline your steps before answering. How much gold would it take to coat the Statue of Liberty in a 1mm layer?",80 input:

81 "Think carefully and outline your steps before answering. How much gold would it take to coat the Statue of Liberty in a 1mm layer?",

81 reasoning: {82 reasoning: {

82 effort: "none"83 effort: "none",

83 }84 },

84});85});

85 86 

86console.log(response);87console.log(response);


135 136 

136const response = await openai.responses.create({137const response = await openai.responses.create({

137 model: "gpt-5.4",138 model: "gpt-5.4",

138 input: "What is the answer to the ultimate question of life, the universe, and everything?",139 input:

140 "What is the answer to the ultimate question of life, the universe, and everything?",

139 text: {141 text: {

140 verbosity: "low"142 verbosity: "low",

141 }143 },

142});144});

143 145 

144console.log(response);146console.log(response);

Details

109```109```

110 110 

111```javascript111```javascript

112/** @type {OpenAI.ChatCompletionMessageParam[] & OpenAI.Responses.ResponseInput} */

112const context = [113const context = [

113 { role: 'system', content: 'You are a helpful assistant.' },114 { role: "system", content: "You are a helpful assistant." },

114 { role: 'user', content: 'Hello!' }115 { role: "user", content: "Hello!" },

115];116];

116 117 

117const completion = await client.chat.completions.create({118const completion = await client.chat.completions.create({

118 model: 'gpt-5.6',119 model: "gpt-5.6",

119 messages: context120 messages: context,

120});121});

121 122 

122const response = await client.responses.create({123const response = await client.responses.create({

123 model: "gpt-5.6",124 model: "gpt-5.6",

124 input: context125 input: context,

125});126});

126```127```

127 128 


152 Generate text from a model153 Generate text from a model

153 154 

154```javascript155```javascript

155import OpenAI from 'openai';156import OpenAI from "openai";

156const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });157const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

157 158 

158const completion = await client.chat.completions.create({159const completion = await client.chat.completions.create({

159 model: 'gpt-5.6',160 model: "gpt-5.6",

160 messages: [161 messages: [

161 { 'role': 'system', 'content': 'You are a helpful assistant.' },162 { role: "system", content: "You are a helpful assistant." },

162 { 'role': 'user', 'content': 'Hello!' }163 { role: "user", content: "Hello!" },

163 ]164 ],

164});165});

165console.log(completion.choices[0].message.content);166console.log(completion.choices[0].message.content);

166```167```


201 Generate text from a model202 Generate text from a model

202 203 

203```javascript204```javascript

204import OpenAI from 'openai';205import OpenAI from "openai";

205const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });206const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

206 207 

207const response = await client.responses.create({208const response = await client.responses.create({

208 model: 'gpt-5.6',209 model: "gpt-5.6",

209 instructions: 'You are a helpful assistant.',210 instructions: "You are a helpful assistant.",

210 input: 'Hello!'211 input: "Hello!",

211});212});

212 213 

213console.log(response.output_text);214console.log(response.output_text);


274 Multi-turn conversation275 Multi-turn conversation

275 276 

276```javascript277```javascript

278/** @type {OpenAI.ChatCompletionMessageParam[]} */

277let messages = [279let messages = [

278 { 'role': 'system', 'content': 'You are a helpful assistant.' },280 { role: "system", content: "You are a helpful assistant." },

279 { 'role': 'user', 'content': 'What is the capital of France?' }281 { role: "user", content: "What is the capital of France?" },

280 ];282];

281const res1 = await client.chat.completions.create({283const res1 = await client.chat.completions.create({

282 model: 'gpt-5.6',284 model: "gpt-5.6",

283 messages285 messages,

284});286});

285 287 

286messages = messages.concat([res1.choices[0].message]);288messages = messages.concat([res1.choices[0].message]);

287messages.push({ 'role': 'user', 'content': 'And its population?' });289messages.push({ role: "user", content: "And its population?" });

288 290 

289const res2 = await client.chat.completions.create({291const res2 = await client.chat.completions.create({

290 model: 'gpt-5.6',292 model: "gpt-5.6",

291 messages293 messages,

292});294});

293```295```

294 296 


337```339```

338 340 

339```javascript341```javascript

340let context = [342/** @type {OpenAI.Responses.ResponseInput} */

341 { role: "user", content: "What is the capital of France?" }343let context = [{ role: "user", content: "What is the capital of France?" }];

342];

343 344 

344const res1 = await client.responses.create({345const res1 = await client.responses.create({

345 model: "gpt-5.6",346 model: "gpt-5.6",


364 365 

365```javascript366```javascript

366const res1 = await client.responses.create({367const res1 = await client.responses.create({

367 model: 'gpt-5.6',368 model: "gpt-5.6",

368 input: 'What is the capital of France?',369 input: "What is the capital of France?",

369 store: true370 store: true,

370});371});

371 372 

372const res2 = await client.responses.create({373const res2 = await client.responses.create({

373 model: 'gpt-5.6',374 model: "gpt-5.6",

374 input: 'And its population?',375 input: "And its population?",

375 previous_response_id: res1.id,376 previous_response_id: res1.id,

376 store: true377 store: true,

377});378});

378```379```

379 380 


526 model: "gpt-5.6",527 model: "gpt-5.6",

527 messages: [528 messages: [

528 {529 {

529 "role": "user",530 role: "user",

530 "content": "Jane, 54 years old",531 content: "Jane, 54 years old",

531 }532 },

532 ],533 ],

533 response_format: {534 response_format: {

534 type: "json_schema",535 type: "json_schema",


540 properties: {541 properties: {

541 name: {542 name: {

542 type: "string",543 type: "string",

543 minLength: 1544 minLength: 1,

544 },545 },

545 age: {546 age: {

546 type: "number",547 type: "number",

547 minimum: 0,548 minimum: 0,

548 maximum: 130549 maximum: 130,

549 }

550 },550 },

551 required: [

552 "name",

553 "age"

554 ],

555 additionalProperties: false

556 }

557 }

558 },551 },

559 reasoning_effort: "medium"552 required: ["name", "age"],

553 additionalProperties: false,

554 },

555 },

556 },

557 reasoning_effort: "medium",

560});558});

561```559```

562 560 


648 properties: {646 properties: {

649 name: {647 name: {

650 type: "string",648 type: "string",

651 minLength: 1649 minLength: 1,

652 },650 },

653 age: {651 age: {

654 type: "number",652 type: "number",

655 minimum: 0,653 minimum: 0,

656 maximum: 130654 maximum: 130,

657 }655 },

656 },

657 required: ["name", "age"],

658 additionalProperties: false,

659 },

658 },660 },

659 required: [

660 "name",

661 "age"

662 ],

663 additionalProperties: false

664 }

665 },661 },

666 }

667});662});

668```663```

669 664 


698 693 

699```javascript694```javascript

700async function web_search(query) {695async function web_search(query) {

701 const fetch = (await import('node-fetch')).default;

702 const res = await fetch(`https://api.example.com/search?q=${query}`);696 const res = await fetch(`https://api.example.com/search?q=${query}`);

703 const data = await res.json();697 const data = await res.json();

704 return data.results;698 return data.results;

705}699}

706 700 

707const completion = await client.chat.completions.create({701const completion = await client.chat.completions.create({

708 model: 'gpt-5.6',702 model: "gpt-5.6",

709 messages: [703 messages: [

710 { role: 'system', content: 'You are a helpful assistant.' },704 { role: "system", content: "You are a helpful assistant." },

711 { role: 'user', content: 'Who is the current president of France?' }705 { role: "user", content: "Who is the current president of France?" },

712 ],706 ],

713 functions: [707 functions: [

714 {708 {

715 name: 'web_search',709 name: "web_search",

716 description: 'Search the web for information',710 description: "Search the web for information",

717 parameters: {711 parameters: {

718 type: 'object',712 type: "object",

719 properties: { query: { type: 'string' } },713 properties: { query: { type: "string" } },

720 required: ['query']714 required: ["query"],

721 }715 },

722 }716 },

723 ]717 ],

724});718});

725```719```

726 720 


766 760 

767```javascript761```javascript

768const answer = await client.responses.create({762const answer = await client.responses.create({

769 model: 'gpt-5.6',763 model: "gpt-5.6",

770 input: 'Who is the current president of France?',764 input: "Who is the current president of France?",

771 tools: [{ type: 'web_search' }]765 tools: [{ type: "web_search" }],

772});766});

773 767 

774console.log(answer.output_text);768console.log(answer.output_text);

Details

69 69 

70const inputModeration = response.moderation.input;70const inputModeration = response.moderation.input;

71const outputModeration = response.moderation.output;71const outputModeration = response.moderation.output;

72if (inputModeration.type === "error") {

73 throw new Error(inputModeration.message);

74}

75if (outputModeration.type === "error") {

76 throw new Error(outputModeration.message);

77}

72 78 

73console.log(inputModeration.flagged);79console.log(inputModeration.flagged);

74console.log(outputModeration.flagged);80console.log(outputModeration.flagged);

Details

49 messages: [49 messages: [

50 {50 {

51 role: "user",51 role: "user",

52 content: refactorPrompt52 content: refactorPrompt,

53 },53 },

54 {54 {

55 role: "user",55 role: "user",

56 content: code56 content: code,

57 }57 },

58 ],58 ],

59 store: true,59 store: true,

60 prediction: {60 prediction: {

61 type: "content",61 type: "content",

62 content: code62 content: code,

63 }63 },

64});64});

65 65 

66// Inspect returned data66// Inspect returned data


196 messages: [196 messages: [

197 {197 {

198 role: "user",198 role: "user",

199 content: refactorPrompt199 content: refactorPrompt,

200 },200 },

201 {201 {

202 role: "user",202 role: "user",

203 content: code203 content: code,

204 }204 },

205 ],205 ],

206 store: true,206 store: true,

207 prediction: {207 prediction: {

208 type: "content",208 type: "content",

209 content: code209 content: code,

210 },210 },

211 stream: true211 stream: true,

212});212});

213 213 

214// Inspect returned data214// Inspect returned data

215for await (const chunk of stream) {215for await (const chunk of completion) {

216 process.stdout.write(chunk.choices[0]?.delta?.content || "");216 process.stdout.write(chunk.choices[0]?.delta?.content || "");

217}217}

218```218```

Details

31const response = await openai.responses.create({31const response = await openai.responses.create({

32 model: "gpt-5.6",32 model: "gpt-5.6",

33 input: "What does 'fit check for my napalm era' mean?",33 input: "What does 'fit check for my napalm era' mean?",

34 service_tier: "priority"34 service_tier: "priority",

35});35});

36 36 

37console.log(response);37console.log(response);

Details

14 14 

15const response = await client.responses.create({15const response = await client.responses.create({

16 model: "gpt-5.6",16 model: "gpt-5.6",

17 input: "Write a one-sentence bedtime story about a unicorn."17 input: "Write a one-sentence bedtime story about a unicorn.",

18});18});

19 19 

20console.log(response.output_text);20console.log(response.output_text);


209const response = await client.responses.create({209const response = await client.responses.create({

210 model: "gpt-5.6",210 model: "gpt-5.6",

211 reasoning: { effort: "low" },211 reasoning: { effort: "low" },

212 instructions: "${semicolonsDevMsg}",212 instructions: "Talk like a pirate.",

213 input: "${semicolonsPrompt}",213 input: "Are semicolons optional in JavaScript?",

214});214});

215 215 

216console.log(response.output_text);216console.log(response.output_text);


257 input: [257 input: [

258 {258 {

259 role: "developer",259 role: "developer",

260 content: "${semicolonsDevMsg}"260 content: "Talk like a pirate.",

261 },261 },

262 {262 {

263 role: "user",263 role: "user",

264 content: "${semicolonsPrompt}",264 content: "Are semicolons optional in JavaScript?",

265 },265 },

266 ],266 ],

267});267});


409import OpenAI from "openai";409import OpenAI from "openai";

410const client = new OpenAI();410const client = new OpenAI();

411 411 

412const instructions = await fs.readFile("prompt.txt", "utf-8");412const instructions = await fs.readFile("fixtures/prompt.txt", "utf-8");

413 413 

414const response = await client.responses.create({414const response = await client.responses.create({

415 model: "gpt-5.6",415 model: "gpt-5.6",

Details

19 19 

20const response = await client.responses.create({20const response = await client.responses.create({

21 prompt: {21 prompt: {

22 prompt_id: "pmpt_123",22 id: "pmpt_123",

23 version: "1",23 version: "1",

24 variables: {24 variables: {

25 customer_name: "Acme",25 customer_name: "Acme",


160 160 

161const client = new OpenAI();161const client = new OpenAI();

162 162 

163/** @returns {OpenAI.Responses.ResponseInput} */

163function buildSupportPrompt({ customerName, issue }) {164function buildSupportPrompt({ customerName, issue }) {

164 return [165 return [

165 {166 {

Details

50 rate: 24000,50 rate: 24000,

51 },51 },

52 turn_detection: {52 turn_detection: {

53 type: "semantic_vad"53 type: "semantic_vad",

54 }54 },

55 },55 },

56 output: {56 output: {

57 format: {57 format: {

58 type: "audio/pcm",58 type: "audio/pcm",

59 },59 },

60 voice: "marin",60 voice: "marin",

61 }61 },

62 },62 },

63 // Use a server-stored prompt by ID. Optionally pin a version and pass variables.63 // Use a server-stored prompt by ID. Optionally pin a version and pass variables.

64 prompt: {64 prompt: {

65 id: "pmpt_123", // your stored prompt ID65 id: "pmpt_123", // your stored prompt ID

66 version: "89", // optional: pin a specific version66 version: "89", // optional: pin a specific version

67 variables: {67 variables: {

68 city: "Paris" // example variable used by your prompt68 city: "Paris", // example variable used by your prompt

69 }69 },

70 },70 },

71 // You can still set direct session fields; these override prompt fields if they overlap:71 // You can still set direct session fields; these override prompt fields if they overlap:

72 instructions: "Speak clearly and briefly. Confirm understanding before taking actions."72 instructions:

73 "Speak clearly and briefly. Confirm understanding before taking actions.",

73 },74 },

74};75};

75 76 


155 {156 {

156 type: "input_text",157 type: "input_text",

157 text: "What Prince album sold the most copies?",158 text: "What Prince album sold the most copies?",

158 }159 },

159 ]160 ],

160 },161 },

161};162};

162 163 


190const event = {191const event = {

191 type: "response.create",192 type: "response.create",

192 response: {193 response: {

193 output_modalities: [ "text" ]194 output_modalities: ["text"],

194 },195 },

195};196};

196 197 


214Listen for response.done to see the final results215Listen for response.done to see the final results

215 216 

216```javascript217```javascript

217function handleEvent(e) {218function handleEvent(message) {

218 const serverEvent = JSON.parse(e.data);219 const data = "data" in message ? message.data : message.toString();

220 const serverEvent = JSON.parse(data);

219 if (serverEvent.type === "response.done") {221 if (serverEvent.type === "response.done") {

220 console.log(serverEvent.response.output[0]);222 console.log(serverEvent.response.output[0]);

221 }223 }


426Append audio input bytes to the conversation428Append audio input bytes to the conversation

427 429 

428```javascript430```javascript

429import fs from 'fs';431import fs from "fs";

430import decodeAudio from 'audio-decode';432import decodeAudio from "audio-decode";

431 433 

432// Converts Float32Array of audio data to PCM16 ArrayBuffer434// Converts Float32Array of audio data to PCM16 ArrayBuffer

433function floatTo16BitPCM(float32Array) {435function floatTo16BitPCM(float32Array) {


442}444}

443 445 

444// Converts a Float32Array to base64-encoded PCM16 data446// Converts a Float32Array to base64-encoded PCM16 data

445base64EncodeAudio(float32Array) {447function base64EncodeAudio(float32Array) {

446 const arrayBuffer = floatTo16BitPCM(float32Array);448 const arrayBuffer = floatTo16BitPCM(float32Array);

447 let binary = '';449 let binary = "";

448 let bytes = new Uint8Array(arrayBuffer);450 let bytes = new Uint8Array(arrayBuffer);

449 const chunkSize = 0x8000; // 32KB chunk size451 const chunkSize = 0x8000; // 32KB chunk size

450 for (let i = 0; i < bytes.length; i += chunkSize) {452 for (let i = 0; i < bytes.length; i += chunkSize) {


457// Fills the audio buffer with the contents of three files,459// Fills the audio buffer with the contents of three files,

458// then asks the model to generate a response.460// then asks the model to generate a response.

459const files = [461const files = [

460 './path/to/sample1.wav',462 "fixtures/sample1.wav",

461 './path/to/sample2.wav',463 "fixtures/sample2.wav",

462 './path/to/sample3.wav'464 "fixtures/sample3.wav",

463];465];

464 466 

465for (const filename of files) {467for (const filename of files) {

466 const audioFile = fs.readFileSync(filename);468 const audioFile = fs.readFileSync(filename);

467 const audioBuffer = await decodeAudio(audioFile);469 const audioBuffer = await decodeAudio(audioFile);

468 const channelData = audioBuffer.getChannelData(0);470 const channelData = audioBuffer.channelData[0];

469 const base64Chunk = base64EncodeAudio(channelData);471 const base64Chunk = base64EncodeAudio(channelData);

470 ws.send(JSON.stringify({472 ws.send(

471 type: 'input_audio_buffer.append',473 JSON.stringify({

472 audio: base64Chunk474 type: "input_audio_buffer.append",

473 }));475 audio: base64Chunk,

474});476 })

477 );

478}

475 479 

476ws.send(JSON.stringify({type: 'input_audio_buffer.commit'}));480ws.send(JSON.stringify({ type: "input_audio_buffer.commit" }));

477ws.send(JSON.stringify({type: 'response.create'}));481ws.send(JSON.stringify({ type: "response.create" }));

478```482```

479 483 

480```python484```python


580Listen for response.output_audio.delta events584Listen for response.output_audio.delta events

581 585 

582```javascript586```javascript

583function handleEvent(e) {587function handleEvent(message) {

584 const serverEvent = JSON.parse(e.data);588 const serverEvent = JSON.parse(message.toString());

585 if (serverEvent.type === "response.audio.delta") {589 if (serverEvent.type === "response.output_audio.delta") {

586 // Access Base64-encoded audio chunks590 // Access Base64-encoded audio chunks

587 // console.log(serverEvent.delta);591 // console.log(serverEvent.delta);

588 }592 }


595```python599```python

596def on_message(ws, message):600def on_message(ws, message):

597 server_event = json.loads(message)601 server_event = json.loads(message)

598 if server_event.type == "response.audio.delta":602 if server_event["type"] == "response.output_audio.delta":

599 # Access Base64-encoded audio chunks:603 # Access Base64-encoded audio chunks:

600 # print(server_event.delta)604 # print(server_event["delta"])

601```605```

602 606 

603 607 


678 metadata: { topic: "classification" },682 metadata: { topic: "classification" },

679 683 

680 // Set any other available response fields684 // Set any other available response fields

681 output_modalities: [ "text" ],685 output_modalities: ["text"],

682 instructions: prompt,686 instructions: prompt,

683 },687 },

684};688};


718Create an out-of-band model response722Create an out-of-band model response

719 723 

720```javascript724```javascript

721function handleEvent(e) {725function handleEvent(message) {

722 const serverEvent = JSON.parse(e.data);726 const data = "data" in message ? message.data : message.toString();

727 const serverEvent = JSON.parse(data);

723 if (728 if (

724 serverEvent.type === "response.done" &&729 serverEvent.type === "response.done" &&

725 serverEvent.response.metadata?.topic === "classification"730 serverEvent.response.metadata?.topic === "classification"


765 response: {770 response: {

766 conversation: "none",771 conversation: "none",

767 metadata: { topic: "pizza" },772 metadata: { topic: "pizza" },

768 output_modalities: [ "text" ],773 output_modalities: ["text"],

769 774 

770 // Create a custom input array for this request with whatever context775 // Create a custom input array for this request with whatever context

771 // is appropriate776 // is appropriate


773 // potentially include existing conversation items:778 // potentially include existing conversation items:

774 {779 {

775 type: "item_reference",780 type: "item_reference",

776 id: "some_conversation_item_id"781 id: "some_conversation_item_id",

777 },782 },

778 {783 {

779 type: "message",784 type: "message",

Details

315 }315 }

316 316 

317 if (event.item.type === "mcp_approval_request") {317 if (event.item.type === "mcp_approval_request") {

318 console.log("Approval required for:", event.item.name, event.item.arguments);318 console.log(

319 "Approval required for:",

320 event.item.name,

321 event.item.arguments

322 );

319 }323 }

320 break;324 break;

321 325 

Details

96 "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1",96 "wss://api.openai.com/v1/realtime?model=gpt-realtime-2.1",

97 [97 [

98 "realtime",98 "realtime",

99 // Auth99 // Use a short-lived token fetched from your application server.

100 "openai-insecure-api-key." + OPENAI_API_KEY,100 "openai-insecure-api-key." + OPENAI_REALTIME_EPHEMERAL_KEY,

101 // Optional101 // Optional

102 "openai-organization." + OPENAI_ORG_ID,102 "openai-organization." + OPENAI_ORG_ID,

103 "openai-project." + OPENAI_PROJECT_ID,103 "openai-project." + OPENAI_PROJECT_ID,

104 ]104 ]

105);105);

106 106 

107ws.on("open", function open() {107ws.addEventListener("open", function open() {

108 console.log("Connected to server.");108 console.log("Connected to server.");

109});109});

110 110 

111ws.on("message", function incoming(message) {111ws.addEventListener("message", function incoming(event) {

112 console.log(message.data);112 console.log(event.data);

113});113});

114```114```

115 115 

Details

354 354 

355const client = new OpenAI();355const client = new OpenAI();

356 356 

357/** @type {OpenAI.Responses.ResponseInput} */

357const history = [358const history = [

358 {359 {

359 role: "user",360 role: "user",

Details

108 item.agent?.agent_name === "/root" &&108 item.agent?.agent_name === "/root" &&

109 item.phase === "final_answer"109 item.phase === "final_answer"

110 ? item.content110 ? item.content

111 : [],111 : []

112 )112 )

113 .filter((part) => part.type === "output_text")113 .filter((part) => part.type === "output_text")

114 .map((part) => part.text)114 .map((part) => part.text)

Details

42const openai = new OpenAI();42const openai = new OpenAI();

43 43 

44const transcription = await openai.audio.transcriptions.create({44const transcription = await openai.audio.transcriptions.create({

45 file: fs.createReadStream("/path/to/file/audio.mp3"),45 file: fs.createReadStream("fixtures/audio.wav"),

46 model: "gpt-4o-transcribe",46 model: "gpt-4o-transcribe",

47});47});

48 48 


101const openai = new OpenAI();101const openai = new OpenAI();

102 102 

103const transcription = await openai.audio.transcriptions.create({103const transcription = await openai.audio.transcriptions.create({

104 file: fs.createReadStream("/path/to/file/speech.mp3"),104 file: fs.createReadStream("fixtures/speech.wav"),

105 model: "gpt-4o-transcribe",105 model: "gpt-4o-transcribe",

106 response_format: "text",106 response_format: "text",

107});107});

108 108 

109console.log(transcription.text);109console.log(transcription);

110```110```

111 111 

112```python112```python


157 157 

158const openai = new OpenAI();158const openai = new OpenAI();

159 159 

160const agentRef = fs.readFileSync("agent.wav").toString("base64");160const agentRef = fs.readFileSync("fixtures/agent.wav").toString("base64");

161 161 

162const transcript = await openai.audio.transcriptions.create({162const transcript = /** @type {OpenAI.Audio.TranscriptionDiarized} */ (

163 file: fs.createReadStream("meeting.wav"),163 await openai.audio.transcriptions.create({

164 file: fs.createReadStream("fixtures/meeting.wav"),

164 model: "gpt-4o-transcribe-diarize",165 model: "gpt-4o-transcribe-diarize",

165 response_format: "diarized_json",166 response_format: "diarized_json",

166 chunking_strategy: "auto",167 chunking_strategy: "auto",

167 extra_body: {

168 known_speaker_names: ["agent"],168 known_speaker_names: ["agent"],

169 known_speaker_references: ["data:audio/wav;base64," + agentRef],169 known_speaker_references: ["data:audio/wav;base64," + agentRef],

170 },170 })

171});171);

172 172 

173for (const segment of transcript.segments) {173for (const segment of transcript.segments) {

174 console.log(`${segment.speaker}: ${segment.text}`, segment.start, segment.end);174 if (!("speaker" in segment)) continue;

175 

176 console.log(

177 `${segment.speaker}: ${segment.text}`,

178 segment.start,

179 segment.end

180 );

175}181}

176```182```

177 183 


233const openai = new OpenAI();239const openai = new OpenAI();

234 240 

235const translation = await openai.audio.translations.create({241const translation = await openai.audio.translations.create({

236 file: fs.createReadStream("/path/to/file/german.mp3"),242 file: fs.createReadStream("fixtures/german.wav"),

237 model: "whisper-1",243 model: "whisper-1",

238});244});

239 245 


295const openai = new OpenAI();301const openai = new OpenAI();

296 302 

297const transcription = await openai.audio.transcriptions.create({303const transcription = await openai.audio.transcriptions.create({

298 file: fs.createReadStream("audio.mp3"),304 file: fs.createReadStream("fixtures/audio.wav"),

299 model: "whisper-1",305 model: "whisper-1",

300 response_format: "verbose_json",306 response_format: "verbose_json",

301 timestamp_granularities: ["word"]307 timestamp_granularities: ["word"],

302});308});

303 309 

304console.log(transcription.words);310console.log(transcription.words);


367const openai = new OpenAI();373const openai = new OpenAI();

368 374 

369const transcription = await openai.audio.transcriptions.create({375const transcription = await openai.audio.transcriptions.create({

370 file: fs.createReadStream("/path/to/file/speech.mp3"),376 file: fs.createReadStream("fixtures/speech.wav"),

371 model: "gpt-4o-transcribe",377 model: "gpt-4o-transcribe",

372 response_format: "text",378 response_format: "text",

373 prompt:"The following conversation is a lecture about the recent developments around OpenAI, GPT-4.5 and the future of AI.",379 prompt:

380 "The following conversation is a lecture about the recent developments around OpenAI, GPT-4.5 and the future of AI.",

374});381});

375 382 

376console.log(transcription.text);383console.log(transcription);

377```384```

378 385 

379```python386```python


438const openai = new OpenAI();445const openai = new OpenAI();

439 446 

440const stream = await openai.audio.transcriptions.create({447const stream = await openai.audio.transcriptions.create({

441 file: fs.createReadStream("/path/to/file/speech.mp3"),448 file: fs.createReadStream("fixtures/speech.wav"),

442 model: "gpt-4o-mini-transcribe",449 model: "gpt-4o-mini-transcribe",

443 response_format: "text",450 response_format: "text",

444 // highlight-start451 // highlight-start


515const openai = new OpenAI();522const openai = new OpenAI();

516 523 

517const transcription = await openai.audio.transcriptions.create({524const transcription = await openai.audio.transcriptions.create({

518 file: fs.createReadStream("/path/to/file/speech.mp3"),525 file: fs.createReadStream("fixtures/speech.wav"),

519 model: "whisper-1",526 model: "whisper-1",

520 response_format: "text",527 response_format: "text",

521 prompt:"ZyntriQix, Digique Plus, CynapseFive, VortiQore V8, EchoNix Array, OrbitalLink Seven, DigiFractal Matrix, PULSE, RAPT, B.R.I.C.K., Q.U.A.R.T.Z., F.L.I.N.T.",528 prompt:

529 "ZyntriQix, Digique Plus, CynapseFive, VortiQore V8, EchoNix Array, OrbitalLink Seven, DigiFractal Matrix, PULSE, RAPT, B.R.I.C.K., Q.U.A.R.T.Z., F.L.I.N.T.",

522});530});

523 531 

524console.log(transcription.text);532console.log(transcription);

525```533```

526 534 

527```python535```python


574 582 

575const transcript = await transcribe(audioFile);583const transcript = await transcribe(audioFile);

576const completion = await openai.chat.completions.create({584const completion = await openai.chat.completions.create({

577model: "gpt-4.1",585 model: "gpt-4.1",

578temperature: temperature,586 temperature: temperature,

579messages: [587 messages: [

580 {588 {

581 role: "system",589 role: "system",

582 content: systemPrompt590 content: systemPrompt,

583 },591 },

584 {592 {

585 role: "user",593 role: "user",

586 content: transcript594 content: transcript,

587 }595 },

588],596 ],

589store: true,597 store: true,

590});598});

591 599 

592console.log(completion.choices[0].message.content);600console.log(completion.choices[0].message.content);

Details

166const response = await openai.responses.parse({166const response = await openai.responses.parse({

167 model: "gpt-5.6",167 model: "gpt-5.6",

168 input: [168 input: [

169 { role: "system", content: "You are a helpful math tutor. Guide the user through the solution step by step." },169 {

170 role: "system",

171 content:

172 "You are a helpful math tutor. Guide the user through the solution step by step.",

173 },

170 { role: "user", content: "how can I solve 8x + 7 = -23" },174 { role: "user", content: "how can I solve 8x + 7 = -23" },

171 ],175 ],

172 text: {176 text: {

guides/text.md +5 −5

Details

12 12 

13const response = await client.responses.create({13const response = await client.responses.create({

14 model: "gpt-5.6",14 model: "gpt-5.6",

15 input: "Write a one-sentence bedtime story about a unicorn."15 input: "Write a one-sentence bedtime story about a unicorn.",

16});16});

17 17 

18console.log(response.output_text);18console.log(response.output_text);


197const response = await client.responses.create({197const response = await client.responses.create({

198 model: "gpt-5.6",198 model: "gpt-5.6",

199 reasoning: { effort: "low" },199 reasoning: { effort: "low" },

200 instructions: "${semicolonsDevMsg}",200 instructions: "Talk like a pirate.",

201 input: "${semicolonsPrompt}",201 input: "Are semicolons optional in JavaScript?",

202});202});

203 203 

204console.log(response.output_text);204console.log(response.output_text);


245 input: [245 input: [

246 {246 {

247 role: "developer",247 role: "developer",

248 content: "${semicolonsDevMsg}"248 content: "Talk like a pirate.",

249 },249 },

250 {250 {

251 role: "user",251 role: "user",

252 content: "${semicolonsPrompt}",252 content: "Are semicolons optional in JavaScript?",

253 },253 },

254 ],254 ],

255});255});

Details

42 42 

43const client = new OpenAI();43const client = new OpenAI();

44 44 

45const response = await client.responses.input_tokens.count({45const response = await client.responses.inputTokens.count({

46 model: "gpt-5.6",46 model: "gpt-5.6",

47 input: "Tell me a joke.",47 input: "Tell me a joke.",

48});48});


94 94 

95const client = new OpenAI();95const client = new OpenAI();

96 96 

97const response = await client.responses.input_tokens.count({97const response = await client.responses.inputTokens.count({

98 model: "gpt-5.6",98 model: "gpt-5.6",

99 input: [99 input: [

100 { role: "user", content: "What is 2 + 2?" },100 { role: "user", content: "What is 2 + 2?" },


158 158 

159const client = new OpenAI();159const client = new OpenAI();

160 160 

161const response = await client.responses.input_tokens.count({161const response = await client.responses.inputTokens.count({

162 model: "gpt-5.6",162 model: "gpt-5.6",

163 instructions:163 instructions: "You are a helpful assistant that explains concepts simply.",

164 "You are a helpful assistant that explains concepts simply.",

165 input: "Explain quantum computing in one sentence.",164 input: "Explain quantum computing in one sentence.",

166});165});

167 166 


222 221 

223const client = new OpenAI();222const client = new OpenAI();

224 223 

225const response = await client.responses.input_tokens.count({224const response = await client.responses.inputTokens.count({

226 model: "gpt-5.6",225 model: "gpt-5.6",

227 input: [226 input: [

228 {227 {


231 {230 {

232 type: "input_image",231 type: "input_image",

233 image_url: "https://example.com/chart.png",232 image_url: "https://example.com/chart.png",

233 detail: "auto",

234 },234 },

235 { type: "input_text", text: "Summarize this chart." },235 { type: "input_text", text: "Summarize this chart." },

236 ],236 ],


310 310 

311const client = new OpenAI();311const client = new OpenAI();

312 312 

313const response = await client.responses.input_tokens.count({313const response = await client.responses.inputTokens.count({

314 model: "gpt-5.6",314 model: "gpt-5.6",

315 tools: [315 tools: [

316 {316 {

317 type: "function",317 type: "function",

318 name: "get_weather",318 name: "get_weather",

319 description: "Get the current weather in a location",319 description: "Get the current weather in a location",

320 strict: true,

320 parameters: {321 parameters: {

321 type: "object",322 type: "object",

322 properties: { location: { type: "string" } },323 properties: { location: { type: "string" } },

323 required: ["location"],324 required: ["location"],

325 additionalProperties: false,

324 },326 },

325 },327 },

326 ],328 ],

guides/tools.md +6 −5

Details

14 14 

15const response = await client.responses.create({15const response = await client.responses.create({

16 model: "gpt-5.6",16 model: "gpt-5.6",

17 tools: [17 tools: [{ type: "web_search" }],

18 { type: "web_search" },

19 ],

20 input: "What was a positive news story from today?",18 input: "What was a positive news story from today?",

21});19});

22 20 


231 229 

232const client = new OpenAI();230const client = new OpenAI();

233 231 

232/** @type {OpenAI.Responses.NamespaceTool} */

234const crmNamespace = {233const crmNamespace = {

235 type: "namespace",234 type: "namespace",

236 name: "crm",235 name: "crm",


289import OpenAI from "openai";288import OpenAI from "openai";

290const client = new OpenAI();289const client = new OpenAI();

291 290 

291/** @type {OpenAI.Responses.Tool[]} */

292const tools = [292const tools = [

293 {293 {

294 type: "function",294 type: "function",


317 tools,317 tools,

318});318});

319 319 

320console.log(response.output[0].to_json());320console.log(response.output[0]);

321```321```

322 322 

323```python323```python


495 {495 {

496 type: "mcp",496 type: "mcp",

497 server_label: "dmcp",497 server_label: "dmcp",

498 server_description: "A Dungeons and Dragons MCP server to assist with dice rolling.",498 server_description:

499 "A Dungeons and Dragons MCP server to assist with dice rolling.",

499 server_url: "https://dmcp-server.deno.dev/mcp",500 server_url: "https://dmcp-server.deno.dev/mcp",

500 require_approval: "never",501 require_approval: "never",

501 },502 },

Details

197Use the apply patch tool with the Agents SDK197Use the apply patch tool with the Agents SDK

198 198 

199```javascript199```javascript

200import { applyDiff, Agent, run, applyPatchTool, Editor } from "@openai/agents";200import {

201 applyDiff,

202 Agent,

203 run,

204 applyPatchTool,

205 type ApplyPatchOperation,

206 type ApplyPatchResult,

207 type Editor,

208} from "@openai/agents";

201 209 

202class WorkspaceEditor implements Editor {210class WorkspaceEditor implements Editor {

203 async createFile(operation) {211 async createFile(

212 operation: Extract<ApplyPatchOperation, { type: "create_file" }>

213 ): Promise<ApplyPatchResult> {

204 // convert the diff to the file content214 // convert the diff to the file content

205 const content = applyDiff("", operation.diff, "create");215 const content = applyDiff("", operation.diff, "create");

206 // write the file content to the file system216 // write the file content to the file system

207 return { status: "completed", output: `Created ${operation.path}` };217 return { status: "completed", output: `Created ${operation.path}` };

208 }218 }

209 219 

210 async updateFile(operation) {220 async updateFile(

221 operation: Extract<ApplyPatchOperation, { type: "update_file" }>

222 ): Promise<ApplyPatchResult> {

211 // read the file content from the file system223 // read the file content from the file system

212 const current = "";224 const current = "";

213 // convert the diff to the new file content225 // convert the diff to the new file content


216 return { status: "completed", output: `Updated ${operation.path}` };228 return { status: "completed", output: `Updated ${operation.path}` };

217 }229 }

218 230 

219 async deleteFile(operation) {231 async deleteFile(

232 operation: Extract<ApplyPatchOperation, { type: "delete_file" }>

233 ): Promise<ApplyPatchResult> {

220 // delete the file from the file system234 // delete the file from the file system

221 return { status: "completed", output: `Deleted ${operation.path}` };235 return { status: "completed", output: `Deleted ${operation.path}` };

222 }236 }


227const agent = new Agent({241const agent = new Agent({

228 name: "Patch Assistant",242 name: "Patch Assistant",

229 model: "gpt-5.6",243 model: "gpt-5.6",

230 instructions: "You can edit files inside the /tmp directory using the apply_patch tool.",244 instructions:

245 "You can edit files inside the /tmp directory using the apply_patch tool.",

231 tools: [246 tools: [

232 applyPatchTool({247 applyPatchTool({

233 editor,248 editor,

Details

139import OpenAI from "openai";139import OpenAI from "openai";

140const client = new OpenAI();140const client = new OpenAI();

141 141 

142const container = await client.containers.create({ name: "test-container", memory_limit: "4g" });142const container = await client.containers.create({

143 name: "test-container",

144 memory_limit: "4g",

145});

143 146 

144const resp = await client.responses.create({147const resp = await client.responses.create({

145 model: "gpt-5.6",148 model: "gpt-5.6",

146 tools: [149 tools: [

147 {150 {

148 type: "code_interpreter",151 type: "code_interpreter",

149 container: container.id152 container: container.id,

150 }153 },

151 ],154 ],

152 tool_choice: "required",155 tool_choice: "required",

153 input: "use the python tool to calculate what is 4 * 3.82. and then find its square root and then find the square root of that result"156 input:

157 "use the python tool to calculate what is 4 * 3.82. and then find its square root and then find the square root of that result",

154});158});

155 159 

156console.log(resp.output_text);160console.log(resp.output_text);

Details

146```146```

147 147 

148```javascript148```javascript

149import { exec } from "node:child_process";149import { execFile } from "node:child_process";

150import { promisify } from "node:util";150import { promisify } from "node:util";

151 151 

152const execAsync = promisify(exec);152const execFileAsync = promisify(execFile);

153 153 

154async function dockerExec(cmd, containerName, decode = true) {154async function dockerExec(

155 const safeCmd = cmd.replace(/"/g, '\\"');155 containerName,

156 const dockerCmd = `docker exec ${containerName} sh -c "${safeCmd}"`;156 executable,

157 const output = await execAsync(dockerCmd, {157 args = [],

158 { decode = true, env = {} } = {}

159) {

160 const environmentArgs = Object.entries(env).flatMap(([name, value]) => [

161 "--env",

162 `${name}=${value}`,

163 ]);

164 const output = await execFileAsync(

165 "docker",

166 [

167 "exec",

168 ...environmentArgs,

169 containerName,

170 executable,

171 ...args.map(String),

172 ],

173 {

158 encoding: decode ? "utf8" : "buffer",174 encoding: decode ? "utf8" : "buffer",

159 });175 maxBuffer: 10 * 1024 * 1024,

176 }

177 );

160 return output.stdout;178 return output.stdout;

161}179}

162 180 


325 }343 }

326};344};

327 345 

346// Translate API button names to Playwright's supported button names.

347const normalizePlaywrightButton = (button = "left") => {

348 const buttons = {

349 left: "left",

350 right: "right",

351 wheel: "middle",

352 };

353 const normalized = buttons[button];

354 if (!normalized) {

355 throw new Error(

356 `Unsupported Playwright mouse button: ${button}. The back and forward buttons are not supported.`

357 );

358 }

359 return normalized;

360};

361 

328// Accept drag paths as either [x, y] pairs or {x, y} objects.362// Accept drag paths as either [x, y] pairs or {x, y} objects.

329const normalizeDragPath = (path) => {363const normalizeDragPath = (path) => {

330 if (!Array.isArray(path)) {364 if (!Array.isArray(path)) {


338 if (point && typeof point === "object" && "x" in point && "y" in point) {372 if (point && typeof point === "object" && "x" in point && "y" in point) {

339 return [point.x, point.y];373 return [point.x, point.y];

340 }374 }

341 throw new Error("drag path entries must be coordinate pairs or {x, y} objects");375 throw new Error(

376 "drag path entries must be coordinate pairs or {x, y} objects"

377 );

342 });378 });

343};379};

344```380```


380 return key_map.get(key, key)416 return key_map.get(key, key)

381 417 

382 418 

419def normalize_playwright_button(button="left"):

420 """Translate API button names to Playwright's supported button names."""

421 button_map = {

422 "left": "left",

423 "right": "right",

424 "wheel": "middle",

425 }

426 if button not in button_map:

427 raise ValueError(

428 f"Unsupported Playwright mouse button: {button}. "

429 "The back and forward buttons are not supported."

430 )

431 return button_map[button]

432 

433 

383def normalize_drag_path(path):434def normalize_drag_path(path):

384 """Accept drag paths as either [x, y] pairs or {x, y} objects."""435 """Accept drag paths as either [x, y] pairs or {x, y} objects."""

385 if not isinstance(path, list):436 if not isinstance(path, list):


459 }510 }

460};511};

461 512 

513// Translate API button names to X11 button numbers.

514const normalizeXdotoolButton = (button = "left") => {

515 const buttons = {

516 left: 1,

517 wheel: 2,

518 right: 3,

519 back: 8,

520 forward: 9,

521 };

522 const normalized = buttons[button];

523 if (!normalized) {

524 throw new Error(`Unsupported xdotool mouse button: ${button}`);

525 }

526 return normalized;

527};

528 

529// Translate API scroll deltas to vertical and horizontal X11 wheel clicks.

530const getXdotoolScrollButtons = (scrollX, scrollY) => {

531 const scrollButtons = [];

532 const appendClicks = (delta, negativeButton, positiveButton) => {

533 if (!delta) {

534 return;

535 }

536 const button = delta < 0 ? negativeButton : positiveButton;

537 const clicks = Math.max(1, Math.abs(Math.round(delta / 100)));

538 scrollButtons.push(...Array(clicks).fill(button));

539 };

540 

541 appendClicks(scrollY, 4, 5);

542 appendClicks(scrollX, 6, 7);

543 return scrollButtons;

544};

545 

462// Accept drag paths as either [x, y] pairs or {x, y} objects.546// Accept drag paths as either [x, y] pairs or {x, y} objects.

463const normalizeDragPath = (path) => {547const normalizeDragPath = (path) => {

464 if (!Array.isArray(path)) {548 if (!Array.isArray(path)) {


472 if (point && typeof point === "object" && "x" in point && "y" in point) {556 if (point && typeof point === "object" && "x" in point && "y" in point) {

473 return [point.x, point.y];557 return [point.x, point.y];

474 }558 }

475 throw new Error("drag path entries must be coordinate pairs or {x, y} objects");559 throw new Error(

560 "drag path entries must be coordinate pairs or {x, y} objects"

561 );

476 });562 });

477};563};

478```564```


514 return key_map.get(key, key)600 return key_map.get(key, key)

515 601 

516 602 

603def normalize_xdotool_button(button="left"):

604 """Translate API button names to X11 button numbers."""

605 button_map = {

606 "left": 1,

607 "wheel": 2,

608 "right": 3,

609 "back": 8,

610 "forward": 9,

611 }

612 if button not in button_map:

613 raise ValueError(f"Unsupported xdotool mouse button: {button}")

614 return button_map[button]

615 

616 

617def get_xdotool_scroll_buttons(scroll_x, scroll_y):

618 """Translate API scroll deltas to vertical and horizontal X11 wheel clicks."""

619 buttons = []

620 for delta, negative_button, positive_button in (

621 (scroll_y, 4, 5),

622 (scroll_x, 6, 7),

623 ):

624 if not delta:

625 continue

626 button = negative_button if delta < 0 else positive_button

627 clicks = max(1, abs(round(delta / 100)))

628 buttons.extend([button] * clicks)

629 return buttons

630 

631 

517def normalize_drag_path(path):632def normalize_drag_path(path):

518 """Accept drag paths as either [x, y] pairs or {x, y} objects."""633 """Accept drag paths as either [x, y] pairs or {x, y} objects."""

519 if not isinstance(path, list):634 if not isinstance(path, list):


565 680 

566```javascript681```javascript

567// Reuse normalizeKey from the helper above.682// Reuse normalizeKey from the helper above.

683// Reuse normalizePlaywrightButton from the helper above.

568// Reuse normalizeDragPath from the helper above.684// Reuse normalizeDragPath from the helper above.

569 685 

686function rejectModifiers(action) {

687 if (action.keys?.length) {

688 throw new Error(

689 "This handler does not support modifier keys. Use the modifier-aware handler below."

690 );

691 }

692}

693 

570async function handleComputerActions(page, actions) {694async function handleComputerActions(page, actions) {

571 for (const action of actions) {695 for (const action of actions) {

572 switch (action.type) {696 switch (action.type) {

573 case "click":697 case "click": {

698 rejectModifiers(action);

574 await page.mouse.click(action.x, action.y, {699 await page.mouse.click(action.x, action.y, {

575 button: action.button ?? "left",700 button: normalizePlaywrightButton(action.button),

576 });701 });

577 break;702 break;

703 }

578 case "double_click":704 case "double_click":

579 await page.mouse.dblclick(action.x, action.y, {705 rejectModifiers(action);

580 button: action.button ?? "left",706 await page.mouse.dblclick(action.x, action.y);

581 });

582 break;707 break;

583 case "drag": {708 case "drag": {

709 rejectModifiers(action);

584 const path = normalizeDragPath(action.path);710 const path = normalizeDragPath(action.path);

585 if (path.length < 2) {711 if (path.length < 2) {

586 throw new Error("drag action requires at least two path points");712 throw new Error("drag action requires at least two path points");


595 break;721 break;

596 }722 }

597 case "move":723 case "move":

724 rejectModifiers(action);

598 await page.mouse.move(action.x, action.y);725 await page.mouse.move(action.x, action.y);

599 break;726 break;

600 case "scroll":727 case "scroll":

728 rejectModifiers(action);

601 await page.mouse.move(action.x, action.y);729 await page.mouse.move(action.x, action.y);

602 await page.mouse.wheel(action.scrollX ?? 0, action.scrollY ?? 0);730 await page.mouse.wheel(action.scroll_x, action.scroll_y);

603 break;731 break;

604 case "keypress":732 case "keypress":

605 for (const key of action.keys) {733 for (const key of action.keys) {


610 await page.keyboard.type(action.text);738 await page.keyboard.type(action.text);

611 break;739 break;

612 case "wait":740 case "wait":

741 await page.waitForTimeout(2000);

742 break;

613 case "screenshot":743 case "screenshot":

614 break;744 break;

615 default:745 default:


623import time753import time

624 754 

625# Reuse normalize_key from the helper above.755# Reuse normalize_key from the helper above.

756# Reuse normalize_playwright_button from the helper above.

626# Reuse normalize_drag_path from the helper above.757# Reuse normalize_drag_path from the helper above.

627 758 

628 759 

760def reject_modifiers(action):

761 if getattr(action, "keys", None):

762 raise ValueError(

763 "This handler does not support modifier keys. "

764 "Use the modifier-aware handler below."

765 )

766 

767 

629def handle_computer_actions(page, actions):768def handle_computer_actions(page, actions):

630 for action in actions:769 for action in actions:

631 match action.type:770 match action.type:

632 case "click":771 case "click":

772 reject_modifiers(action)

633 page.mouse.click(773 page.mouse.click(

634 action.x,774 action.x,

635 action.y,775 action.y,

636 button=getattr(action, "button", "left"),776 button=normalize_playwright_button(

777 getattr(action, "button", "left")

778 ),

637 )779 )

638 case "double_click":780 case "double_click":

639 page.mouse.dblclick(781 reject_modifiers(action)

640 action.x,782 page.mouse.dblclick(action.x, action.y)

641 action.y,

642 button=getattr(action, "button", "left"),

643 )

644 case "drag":783 case "drag":

784 reject_modifiers(action)

645 path = normalize_drag_path(action.path)785 path = normalize_drag_path(action.path)

646 if len(path) < 2:786 if len(path) < 2:

647 raise ValueError("drag action requires at least two path points")787 raise ValueError("drag action requires at least two path points")


652 page.mouse.move(x, y)792 page.mouse.move(x, y)

653 page.mouse.up()793 page.mouse.up()

654 case "move":794 case "move":

795 reject_modifiers(action)

655 page.mouse.move(action.x, action.y)796 page.mouse.move(action.x, action.y)

656 case "scroll":797 case "scroll":

798 reject_modifiers(action)

657 page.mouse.move(action.x, action.y)799 page.mouse.move(action.x, action.y)

658 page.mouse.wheel(800 page.mouse.wheel(

659 getattr(action, "scrollX", 0),801 action.scroll_x,

660 getattr(action, "scrollY", 0),802 action.scroll_y,

661 )803 )

662 case "keypress":804 case "keypress":

663 for key in action.keys:805 for key in action.keys:


679 821 

680```javascript822```javascript

681// Reuse normalizeXdotoolKey from the helper above.823// Reuse normalizeXdotoolKey from the helper above.

824// Reuse normalizeXdotoolButton and getXdotoolScrollButtons from the helper above.

682// Reuse normalizeDragPath from the helper above.825// Reuse normalizeDragPath from the helper above.

683 826 

684async function handleComputerActions(vm, actions) {827function rejectModifiers(action) {

685 const buttonMap = { left: 1, middle: 2, right: 3 };828 if (action.keys?.length) {

829 throw new Error(

830 "This handler does not support modifier keys. Use the modifier-aware handler below."

831 );

832 }

833}

686 834 

835async function handleComputerActions(vm, actions) {

687 for (const action of actions) {836 for (const action of actions) {

688 switch (action.type) {837 switch (action.type) {

689 case "click": {838 case "click": {

690 const button = buttonMap[action.button ?? "left"] ?? 1;839 rejectModifiers(action);

840 const button = normalizeXdotoolButton(action.button);

691 await dockerExec(841 await dockerExec(

692 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y} click ${button}`,842 vm.containerName,

693 vm.containerName843 "xdotool",

844 ["mousemove", action.x, action.y, "click", button],

845 { env: { DISPLAY: vm.display } }

694 );846 );

695 break;847 break;

696 }848 }

697 case "double_click": {849 case "double_click": {

698 const button = buttonMap[action.button ?? "left"] ?? 1;850 rejectModifiers(action);

699 await dockerExec(851 await dockerExec(

700 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y} click --repeat 2 ${button}`,852 vm.containerName,

701 vm.containerName853 "xdotool",

854 ["mousemove", action.x, action.y, "click", "--repeat", 2, 1],

855 { env: { DISPLAY: vm.display } }

702 );856 );

703 break;857 break;

704 }858 }

705 case "drag": {859 case "drag": {

860 rejectModifiers(action);

706 const path = normalizeDragPath(action.path);861 const path = normalizeDragPath(action.path);

707 if (path.length < 2) {862 if (path.length < 2) {

708 throw new Error("drag action requires at least two path points");863 throw new Error("drag action requires at least two path points");

709 }864 }

710 const [[startX, startY], ...rest] = path;865 const [[startX, startY], ...rest] = path;

711 await dockerExec(866 await dockerExec(

712 `DISPLAY=${vm.display} xdotool mousemove ${startX} ${startY} mousedown 1`,867 vm.containerName,

713 vm.containerName868 "xdotool",

869 ["mousemove", startX, startY, "mousedown", 1],

870 { env: { DISPLAY: vm.display } }

714 );871 );

715 for (const [x, y] of rest) {872 for (const [x, y] of rest) {

716 await dockerExec(873 await dockerExec(vm.containerName, "xdotool", ["mousemove", x, y], {

717 `DISPLAY=${vm.display} xdotool mousemove ${x} ${y}`,874 env: { DISPLAY: vm.display },

718 vm.containerName875 });

719 );

720 }876 }

721 await dockerExec(877 await dockerExec(vm.containerName, "xdotool", ["mouseup", 1], {

722 `DISPLAY=${vm.display} xdotool mouseup 1`,878 env: { DISPLAY: vm.display },

723 vm.containerName879 });

724 );

725 break;880 break;

726 }881 }

727 case "move":882 case "move":

883 rejectModifiers(action);

728 await dockerExec(884 await dockerExec(

729 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y}`,885 vm.containerName,

730 vm.containerName886 "xdotool",

887 ["mousemove", action.x, action.y],

888 { env: { DISPLAY: vm.display } }

731 );889 );

732 break;890 break;

733 case "scroll": {891 case "scroll": {

734 const button = action.scrollY < 0 ? 4 : 5;892 rejectModifiers(action);

735 const clicks = Math.max(1, Math.abs(Math.round(action.scrollY / 100)));893 const buttons = getXdotoolScrollButtons(

736 await dockerExec(894 action.scroll_x,

737 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y}`,895 action.scroll_y

738 vm.containerName

739 );896 );

740 for (let i = 0; i < clicks; i += 1) {

741 await dockerExec(897 await dockerExec(

742 `DISPLAY=${vm.display} xdotool click ${button}`,898 vm.containerName,

743 vm.containerName899 "xdotool",

900 ["mousemove", action.x, action.y],

901 { env: { DISPLAY: vm.display } }

744 );902 );

903 for (const button of buttons) {

904 await dockerExec(vm.containerName, "xdotool", ["click", button], {

905 env: { DISPLAY: vm.display },

906 });

745 }907 }

746 break;908 break;

747 }909 }

748 case "keypress":910 case "keypress":

749 for (const key of action.keys) {911 for (const key of action.keys) {

750 await dockerExec(912 await dockerExec(

751 `DISPLAY=${vm.display} xdotool key '${normalizeXdotoolKey(key)}'`,913 vm.containerName,

752 vm.containerName914 "xdotool",

915 ["key", normalizeXdotoolKey(key)],

916 { env: { DISPLAY: vm.display } }

753 );917 );

754 }918 }

755 break;919 break;

756 case "type":920 case "type":

757 await dockerExec(921 await dockerExec(

758 `DISPLAY=${vm.display} xdotool type --delay 0 '${action.text}'`,922 vm.containerName,

759 vm.containerName923 "xdotool",

924 ["type", "--delay", 0, action.text],

925 { env: { DISPLAY: vm.display } }

760 );926 );

761 break;927 break;

762 case "wait":928 case "wait":

929 await new Promise((resolve) => setTimeout(resolve, 2000));

930 break;

763 case "screenshot":931 case "screenshot":

764 break;932 break;

765 default:933 default:


773import time941import time

774 942 

775# Reuse normalize_xdotool_key from the helper above.943# Reuse normalize_xdotool_key from the helper above.

944# Reuse normalize_xdotool_button and get_xdotool_scroll_buttons from the helper above.

776# Reuse normalize_drag_path from the helper above.945# Reuse normalize_drag_path from the helper above.

777 946 

778 947 

779def handle_computer_actions(vm, actions):948def reject_modifiers(action):

780 button_map = {"left": 1, "middle": 2, "right": 3}949 if getattr(action, "keys", None):

950 raise ValueError(

951 "This handler does not support modifier keys. "

952 "Use the modifier-aware handler below."

953 )

954 

781 955 

956def handle_computer_actions(vm, actions):

782 for action in actions:957 for action in actions:

783 match action.type:958 match action.type:

784 case "click":959 case "click":

785 button = button_map.get(getattr(action, "button", "left"), 1)960 reject_modifiers(action)

961 button = normalize_xdotool_button(

962 getattr(action, "button", "left")

963 )

786 docker_exec(964 docker_exec(

787 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y} click {button}",965 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y} click {button}",

788 vm.container_name,966 vm.container_name,

789 )967 )

790 case "double_click":968 case "double_click":

791 button = button_map.get(getattr(action, "button", "left"), 1)969 reject_modifiers(action)

792 docker_exec(970 docker_exec(

793 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y} click --repeat 2 {button}",971 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y} click --repeat 2 1",

794 vm.container_name,972 vm.container_name,

795 )973 )

796 case "drag":974 case "drag":

975 reject_modifiers(action)

797 path = normalize_drag_path(action.path)976 path = normalize_drag_path(action.path)

798 if len(path) < 2:977 if len(path) < 2:

799 raise ValueError("drag action requires at least two path points")978 raise ValueError("drag action requires at least two path points")


812 vm.container_name,991 vm.container_name,

813 )992 )

814 case "move":993 case "move":

994 reject_modifiers(action)

815 docker_exec(995 docker_exec(

816 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y}",996 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y}",

817 vm.container_name,997 vm.container_name,

818 )998 )

819 case "scroll":999 case "scroll":

820 button = 4 if getattr(action, "scrollY", 0) < 0 else 51000 reject_modifiers(action)

821 clicks = max(1, abs(round(getattr(action, "scrollY", 0) / 100)))1001 buttons = get_xdotool_scroll_buttons(

1002 action.scroll_x,

1003 action.scroll_y,

1004 )

822 1005 

823 docker_exec(1006 docker_exec(

824 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y}",1007 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y}",

825 vm.container_name,1008 vm.container_name,

826 )1009 )

827 for _ in range(clicks):1010 for button in buttons:

828 docker_exec(1011 docker_exec(

829 f"DISPLAY={vm.display} xdotool click {button}",1012 f"DISPLAY={vm.display} xdotool click {button}",

830 vm.container_name,1013 vm.container_name,


892 1075 

893```javascript1076```javascript

894// Reuse normalizeKey from the helper above.1077// Reuse normalizeKey from the helper above.

1078// Reuse normalizePlaywrightButton from the helper above.

895// Reuse normalizeDragPath from the helper above.1079// Reuse normalizeDragPath from the helper above.

896 1080 

897async function withModifiers(page, keys, callback) {1081async function withModifiers(page, keys, callback) {


918 case "click":1102 case "click":

919 await withModifiers(page, action.keys, async () => {1103 await withModifiers(page, action.keys, async () => {

920 await page.mouse.click(action.x, action.y, {1104 await page.mouse.click(action.x, action.y, {

921 button: action.button ?? "left",1105 button: normalizePlaywrightButton(action.button),

922 });1106 });

923 });1107 });

924 break;1108 break;

925 case "double_click":1109 case "double_click":

926 await withModifiers(page, action.keys, async () => {1110 await withModifiers(page, action.keys, async () => {

927 await page.mouse.dblclick(action.x, action.y, {1111 await page.mouse.dblclick(action.x, action.y);

928 button: action.button ?? "left",

929 });

930 });1112 });

931 break;1113 break;

932 case "drag": {1114 case "drag": {


953 case "scroll":1135 case "scroll":

954 await withModifiers(page, action.keys, async () => {1136 await withModifiers(page, action.keys, async () => {

955 await page.mouse.move(action.x, action.y);1137 await page.mouse.move(action.x, action.y);

956 await page.mouse.wheel(action.scrollX ?? 0, action.scrollY ?? 0);1138 await page.mouse.wheel(action.scroll_x, action.scroll_y);

957 });1139 });

958 break;1140 break;

959 case "keypress":1141 case "keypress":


965 await page.keyboard.type(action.text);1147 await page.keyboard.type(action.text);

966 break;1148 break;

967 case "wait":1149 case "wait":

1150 await page.waitForTimeout(2000);

1151 break;

968 case "screenshot":1152 case "screenshot":

969 break;1153 break;

970 default:1154 default:


978import time1162import time

979 1163 

980# Reuse normalize_key from the helper above.1164# Reuse normalize_key from the helper above.

1165# Reuse normalize_playwright_button from the helper above.

981# Reuse normalize_drag_path from the helper above.1166# Reuse normalize_drag_path from the helper above.

982 1167 

983 1168 


1006 lambda: page.mouse.click(1191 lambda: page.mouse.click(

1007 action.x,1192 action.x,

1008 action.y,1193 action.y,

1009 button=getattr(action, "button", "left"),1194 button=normalize_playwright_button(

1195 getattr(action, "button", "left")

1196 ),

1010 ),1197 ),

1011 )1198 )

1012 case "double_click":1199 case "double_click":

1013 with_modifiers(1200 with_modifiers(

1014 page,1201 page,

1015 getattr(action, "keys", None),1202 getattr(action, "keys", None),

1016 lambda: page.mouse.dblclick(1203 lambda: page.mouse.dblclick(action.x, action.y),

1017 action.x,

1018 action.y,

1019 button=getattr(action, "button", "left"),

1020 ),

1021 )1204 )

1022 case "drag":1205 case "drag":

1023 path = normalize_drag_path(action.path)1206 path = normalize_drag_path(action.path)


1050 lambda: (1233 lambda: (

1051 page.mouse.move(action.x, action.y),1234 page.mouse.move(action.x, action.y),

1052 page.mouse.wheel(1235 page.mouse.wheel(

1053 getattr(action, "scrollX", 0),1236 action.scroll_x,

1054 getattr(action, "scrollY", 0),1237 action.scroll_y,

1055 ),1238 ),

1056 ),1239 ),

1057 )1240 )


1075 1258 

1076```javascript1259```javascript

1077// Reuse normalizeXdotoolKey from the helper above.1260// Reuse normalizeXdotoolKey from the helper above.

1261// Reuse normalizeXdotoolButton and getXdotoolScrollButtons from the helper above.

1078// Reuse normalizeDragPath from the helper above.1262// Reuse normalizeDragPath from the helper above.

1079 1263 

1080async function withModifiers(vm, keys, callback) {1264async function withModifiers(vm, keys, callback) {


1083 1267 

1084 try {1268 try {

1085 for (const key of normalizedKeys) {1269 for (const key of normalizedKeys) {

1086 await dockerExec(1270 await dockerExec(vm.containerName, "xdotool", ["keydown", key], {

1087 `DISPLAY=${vm.display} xdotool keydown '${key}'`,1271 env: { DISPLAY: vm.display },

1088 vm.containerName1272 });

1089 );

1090 pressedKeys.push(key);1273 pressedKeys.push(key);

1091 }1274 }

1092 1275 

1093 await callback();1276 await callback();

1094 } finally {1277 } finally {

1095 for (const key of [...pressedKeys].reverse()) {1278 for (const key of [...pressedKeys].reverse()) {

1096 await dockerExec(1279 await dockerExec(vm.containerName, "xdotool", ["keyup", key], {

1097 `DISPLAY=${vm.display} xdotool keyup '${key}'`,1280 env: { DISPLAY: vm.display },

1098 vm.containerName1281 });

1099 );

1100 }1282 }

1101 }1283 }

1102}1284}

1103 1285 

1104async function handleComputerActions(vm, actions) {1286async function handleComputerActions(vm, actions) {

1105 const buttonMap = { left: 1, middle: 2, right: 3 };

1106 

1107 for (const action of actions) {1287 for (const action of actions) {

1108 switch (action.type) {1288 switch (action.type) {

1109 case "click": {1289 case "click": {

1110 const button = buttonMap[action.button ?? "left"] ?? 1;1290 const button = normalizeXdotoolButton(action.button);

1111 await withModifiers(vm, action.keys, async () => {1291 await withModifiers(vm, action.keys, async () => {

1112 await dockerExec(1292 await dockerExec(

1113 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y} click ${button}`,1293 vm.containerName,

1114 vm.containerName1294 "xdotool",

1295 ["mousemove", action.x, action.y, "click", button],

1296 { env: { DISPLAY: vm.display } }

1115 );1297 );

1116 });1298 });

1117 break;1299 break;

1118 }1300 }

1119 case "double_click": {1301 case "double_click": {

1120 const button = buttonMap[action.button ?? "left"] ?? 1;

1121 await withModifiers(vm, action.keys, async () => {1302 await withModifiers(vm, action.keys, async () => {

1122 await dockerExec(1303 await dockerExec(

1123 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y} click --repeat 2 ${button}`,1304 vm.containerName,

1124 vm.containerName1305 "xdotool",

1306 ["mousemove", action.x, action.y, "click", "--repeat", 2, 1],

1307 { env: { DISPLAY: vm.display } }

1125 );1308 );

1126 });1309 });

1127 break;1310 break;


1134 await withModifiers(vm, action.keys, async () => {1317 await withModifiers(vm, action.keys, async () => {

1135 const [[startX, startY], ...rest] = path;1318 const [[startX, startY], ...rest] = path;

1136 await dockerExec(1319 await dockerExec(

1137 `DISPLAY=${vm.display} xdotool mousemove ${startX} ${startY} mousedown 1`,1320 vm.containerName,

1138 vm.containerName1321 "xdotool",

1322 ["mousemove", startX, startY, "mousedown", 1],

1323 { env: { DISPLAY: vm.display } }

1139 );1324 );

1140 for (const [x, y] of rest) {1325 for (const [x, y] of rest) {

1141 await dockerExec(1326 await dockerExec(vm.containerName, "xdotool", ["mousemove", x, y], {

1142 `DISPLAY=${vm.display} xdotool mousemove ${x} ${y}`,1327 env: { DISPLAY: vm.display },

1143 vm.containerName1328 });

1144 );

1145 }1329 }

1146 await dockerExec(1330 await dockerExec(vm.containerName, "xdotool", ["mouseup", 1], {

1147 `DISPLAY=${vm.display} xdotool mouseup 1`,1331 env: { DISPLAY: vm.display },

1148 vm.containerName1332 });

1149 );

1150 });1333 });

1151 break;1334 break;

1152 }1335 }

1153 case "move": {1336 case "move": {

1154 await withModifiers(vm, action.keys, async () => {1337 await withModifiers(vm, action.keys, async () => {

1155 await dockerExec(1338 await dockerExec(

1156 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y}`,1339 vm.containerName,

1157 vm.containerName1340 "xdotool",

1341 ["mousemove", action.x, action.y],

1342 { env: { DISPLAY: vm.display } }

1158 );1343 );

1159 });1344 });

1160 break;1345 break;

1161 }1346 }

1162 case "scroll": {1347 case "scroll": {

1163 const button = action.scrollY < 0 ? 4 : 5;1348 const buttons = getXdotoolScrollButtons(

1164 const clicks = Math.max(1, Math.abs(Math.round(action.scrollY / 100)));1349 action.scroll_x,

1165 await withModifiers(vm, action.keys, async () => {1350 action.scroll_y

1166 await dockerExec(

1167 `DISPLAY=${vm.display} xdotool mousemove ${action.x} ${action.y}`,

1168 vm.containerName

1169 );1351 );

1170 for (let i = 0; i < clicks; i += 1) {1352 await withModifiers(vm, action.keys, async () => {

1171 await dockerExec(1353 await dockerExec(

1172 `DISPLAY=${vm.display} xdotool click ${button}`,1354 vm.containerName,

1173 vm.containerName1355 "xdotool",

1356 ["mousemove", action.x, action.y],

1357 { env: { DISPLAY: vm.display } }

1174 );1358 );

1359 for (const button of buttons) {

1360 await dockerExec(vm.containerName, "xdotool", ["click", button], {

1361 env: { DISPLAY: vm.display },

1362 });

1175 }1363 }

1176 });1364 });

1177 break;1365 break;


1179 case "keypress":1367 case "keypress":

1180 for (const key of action.keys) {1368 for (const key of action.keys) {

1181 await dockerExec(1369 await dockerExec(

1182 `DISPLAY=${vm.display} xdotool key '${normalizeXdotoolKey(key)}'`,1370 vm.containerName,

1183 vm.containerName1371 "xdotool",

1372 ["key", normalizeXdotoolKey(key)],

1373 { env: { DISPLAY: vm.display } }

1184 );1374 );

1185 }1375 }

1186 break;1376 break;

1187 case "type":1377 case "type":

1188 await dockerExec(1378 await dockerExec(

1189 `DISPLAY=${vm.display} xdotool type --delay 0 '${action.text}'`,1379 vm.containerName,

1190 vm.containerName1380 "xdotool",

1381 ["type", "--delay", 0, action.text],

1382 { env: { DISPLAY: vm.display } }

1191 );1383 );

1192 break;1384 break;

1193 case "wait":1385 case "wait":

1386 await new Promise((resolve) => setTimeout(resolve, 2000));

1387 break;

1194 case "screenshot":1388 case "screenshot":

1195 break;1389 break;

1196 default:1390 default:


1204import time1398import time

1205 1399 

1206# Reuse normalize_xdotool_key from the helper above.1400# Reuse normalize_xdotool_key from the helper above.

1401# Reuse normalize_xdotool_button and get_xdotool_scroll_buttons from the helper above.

1207# Reuse normalize_drag_path from the helper above.1402# Reuse normalize_drag_path from the helper above.

1208 1403 

1209 1404 


1229 1424 

1230 1425 

1231def handle_computer_actions(vm, actions):1426def handle_computer_actions(vm, actions):

1232 button_map = {"left": 1, "middle": 2, "right": 3}

1233 

1234 for action in actions:1427 for action in actions:

1235 match action.type:1428 match action.type:

1236 case "click":1429 case "click":

1237 button = button_map.get(getattr(action, "button", "left"), 1)1430 button = normalize_xdotool_button(

1431 getattr(action, "button", "left")

1432 )

1238 with_modifiers(1433 with_modifiers(

1239 vm,1434 vm,

1240 getattr(action, "keys", None),1435 getattr(action, "keys", None),


1244 ),1439 ),

1245 )1440 )

1246 case "double_click":1441 case "double_click":

1247 button = button_map.get(getattr(action, "button", "left"), 1)

1248 with_modifiers(1442 with_modifiers(

1249 vm,1443 vm,

1250 getattr(action, "keys", None),1444 getattr(action, "keys", None),

1251 lambda: docker_exec(1445 lambda: docker_exec(

1252 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y} click --repeat 2 {button}",1446 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y} click --repeat 2 1",

1253 vm.container_name,1447 vm.container_name,

1254 ),1448 ),

1255 )1449 )


1285 ),1479 ),

1286 )1480 )

1287 case "scroll":1481 case "scroll":

1288 button = 4 if getattr(action, "scrollY", 0) < 0 else 51482 buttons = get_xdotool_scroll_buttons(

1289 clicks = max(1, abs(round(getattr(action, "scrollY", 0) / 100)))1483 action.scroll_x,

1484 action.scroll_y,

1485 )

1290 1486 

1291 def do_scroll():1487 def do_scroll():

1292 docker_exec(1488 docker_exec(

1293 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y}",1489 f"DISPLAY={vm.display} xdotool mousemove {action.x} {action.y}",

1294 vm.container_name,1490 vm.container_name,

1295 )1491 )

1296 for _ in range(clicks):1492 for button in buttons:

1297 docker_exec(1493 docker_exec(

1298 f"DISPLAY={vm.display} xdotool click {button}",1494 f"DISPLAY={vm.display} xdotool click {button}",

1299 vm.container_name,1495 vm.container_name,


1352```javascript1548```javascript

1353async function captureScreenshot(vm) {1549async function captureScreenshot(vm) {

1354 return await dockerExec(1550 return await dockerExec(

1355 `export DISPLAY=${vm.display} && import -window root png:-`,

1356 vm.containerName,1551 vm.containerName,

1357 false1552 "import",

1553 ["-window", "root", "png:-"],

1554 { decode: false, env: { DISPLAY: vm.display } }

1358 );1555 );

1359}1556}

1360```1557```


1384const client = new OpenAI();1581const client = new OpenAI();

1385 1582 

1386async function sendComputerScreenshot(response, callId, screenshotBase64) {1583async function sendComputerScreenshot(response, callId, screenshotBase64) {

1584 const output = /** @type {const} */ ({

1585 type: "computer_screenshot",

1586 image_url: `data:image/png;base64,${screenshotBase64}`,

1587 detail: "original",

1588 });

1589 

1387 return await client.responses.create({1590 return await client.responses.create({

1388 model: "gpt-5.6",1591 model: "gpt-5.6",

1389 tools: [{ type: "computer" }],1592 tools: [{ type: "computer" }],


1392 {1595 {

1393 type: "computer_call_output",1596 type: "computer_call_output",

1394 call_id: callId,1597 call_id: callId,

1395 output: {1598 output,

1396 type: "computer_screenshot",

1397 image_url: `data:image/png;base64,${screenshotBase64}`,

1398 detail: "original",

1399 },

1400 },1599 },

1401 ],1600 ],

1402 });1601 });


1442 1641 

1443async function computerUseLoop(target, response) {1642async function computerUseLoop(target, response) {

1444 while (true) {1643 while (true) {

1445 const computerCall = response.output.find((item) => item.type === "computer_call");1644 const computerCall = response.output.find(

1645 (item) => item.type === "computer_call"

1646 );

1446 if (!computerCall) {1647 if (!computerCall) {

1447 return response;1648 return response;

1448 }1649 }


1451 1652 

1452 const screenshot = await captureScreenshot(target);1653 const screenshot = await captureScreenshot(target);

1453 const screenshotBase64 = Buffer.from(screenshot).toString("base64");1654 const screenshotBase64 = Buffer.from(screenshot).toString("base64");

1655 const output = /** @type {const} */ ({

1656 type: "computer_screenshot",

1657 image_url: `data:image/png;base64,${screenshotBase64}`,

1658 detail: "original",

1659 });

1454 1660 

1455 response = await client.responses.create({1661 response = await client.responses.create({

1456 model: "gpt-5.6",1662 model: "gpt-5.6",


1460 {1666 {

1461 type: "computer_call_output",1667 type: "computer_call_output",

1462 call_id: computerCall.call_id,1668 call_id: computerCall.call_id,

1463 output: {1669 output,

1464 type: "computer_screenshot",

1465 image_url: `data:image/png;base64,${screenshotBase64}`,

1466 detail: "original",

1467 },

1468 },1670 },

1469 ],1671 ],

1470 });1672 });


1565 1767 

1566These minimal JavaScript and Python implementations demonstrate a code-execution harness. They give the model a code-execution tool, keep Playwright objects available to the runtime, return text and screenshots back to the model, and let the model ask the user clarifying questions when it gets blocked.1768These minimal JavaScript and Python implementations demonstrate a code-execution harness. They give the model a code-execution tool, keep Playwright objects available to the runtime, return text and screenshots back to the model, and let the model ask the user clarifying questions when it gets blocked.

1567 1769 

1770Run model-generated code only inside a disposable, least-privilege container or VM with resource and network limits. Language-level sandboxes such as Node.js `vm` and restricted Python global variables are not security boundaries. Keep the sandbox in a separate process and security boundary from the API client, with no shared credentials or host mounts. Enforce time and resource limits inside the sandbox, and terminate the runtime when it exceeds them.

1771 

1772The examples below do not run generated code in the API client. They send each approved snippet to the separately isolated service configured by `OPENAI_EXAMPLE_CODE_EXECUTION_URL`, with an optional `OPENAI_EXAMPLE_CODE_EXECUTION_TOKEN`. The service accepts `{ session_id, language, code }` and returns `{ output }`, where `output` contains Responses API `input_text` or `input_image` items. It owns the persistent Playwright objects and must validate requests, authenticate callers, enforce its own execution deadline, and return only validated output. The client-side timeout only limits how long the example waits for a response.

1773 

1568 1774 

1569 1775 

1570<div data-content-switcher-pane data-value="javascript">1776<div data-content-switcher-pane data-value="javascript">


1573 1779 

1574```javascript1780```javascript

1575// Run with:1781// Run with:

1576// bun run -i cua_code_mode.ts1782// pnpm example -- tools/cua/015-code-execution-harness-example.ts

1577// Override the user prompt with:1783// Override the user prompt with:

1578// bun run -i cua_code_mode.ts --prompt "Go to example.com and summarize the page."1784// pnpm example -- tools/cua/015-code-execution-harness-example.ts --prompt "Go to example.com and summarize the page."

1579// Note: this script intentionally leaves the Playwright browser open after the1785//

1580// model reaches a final answer. Because the browser/context are not closed,1786// Requires OPENAI_EXAMPLE_CODE_EXECUTION_URL to point to a separately isolated

1581// Bun stays alive until you close the browser or stop the process manually.1787// sandbox service. The service keeps a browser, context, and page alive for each

1788// session and returns text or image outputs. Do not run model-generated code in

1789// this API client process.

1790 

1791import { randomUUID } from "node:crypto";

1792import readline from "node:readline/promises";

1582 1793 

1583import OpenAI from "openai";1794import OpenAI from "openai";

1584import readline from "node:readline/promises";1795 

1585import vm from "node:vm";1796const EXECUTION_TIMEOUT_MS = 30_000;

1586import { chromium } from "playwright";1797 

1587import util from "node:util";1798type ExecutionOutput =

1799 | { type: "input_text"; text: string }

1800 | {

1801 type: "input_image";

1802 image_url: string;

1803 detail: "original";

1804 };

1805 

1806function isExecutionOutput(value: unknown): value is ExecutionOutput {

1807 if (typeof value !== "object" || value === null || !("type" in value)) {

1808 return false;

1809 }

1810 if (

1811 value.type === "input_text" &&

1812 "text" in value &&

1813 typeof value.text === "string"

1814 ) {

1815 return true;

1816 }

1817 return (

1818 value.type === "input_image" &&

1819 "image_url" in value &&

1820 typeof value.image_url === "string" &&

1821 "detail" in value &&

1822 value.detail === "original"

1823 );

1824}

1825 

1826async function executeInSandbox(

1827 code: string,

1828 sessionId: string

1829): Promise<ExecutionOutput[]> {

1830 const endpoint = process.env.OPENAI_EXAMPLE_CODE_EXECUTION_URL;

1831 if (!endpoint) {

1832 return [

1833 {

1834 type: "input_text",

1835 text: "Execution blocked. Configure OPENAI_EXAMPLE_CODE_EXECUTION_URL with a separately isolated sandbox service.",

1836 },

1837 ];

1838 }

1839 

1840 const headers: Record<string, string> = {

1841 "content-type": "application/json",

1842 };

1843 const token = process.env.OPENAI_EXAMPLE_CODE_EXECUTION_TOKEN;

1844 if (token) headers.authorization = `Bearer ${token}`;

1845 

1846 const response = await fetch(endpoint, {

1847 method: "POST",

1848 headers,

1849 body: JSON.stringify({

1850 session_id: sessionId,

1851 language: "javascript",

1852 code,

1853 }),

1854 signal: AbortSignal.timeout(EXECUTION_TIMEOUT_MS),

1855 });

1856 if (!response.ok) {

1857 throw new Error(

1858 `Sandbox request failed with ${response.status} ${response.statusText}`

1859 );

1860 }

1861 

1862 const payload: unknown = await response.json();

1863 if (

1864 typeof payload !== "object" ||

1865 payload === null ||

1866 !("output" in payload) ||

1867 !Array.isArray(payload.output) ||

1868 !payload.output.every(isExecutionOutput)

1869 ) {

1870 throw new Error("Sandbox returned an invalid output payload.");

1871 }

1872 return payload.output;

1873}

1588 1874 

1589async function main(1875async function main(

1590 prompt: string = "Go to Hacker News, click on the most interesting link (be prepared to justify your choice), take a screenshot, and give me a critique of the visual layout.",1876 prompt: string = "Go to Hacker News, click on the most interesting link (be prepared to justify your choice), take a screenshot, and give me a critique of the visual layout.",

1591 max_steps: number = 50,1877 maxSteps: number = 50,

1592 model: string = "gpt-5.6"1878 model: string = "gpt-5.6"

1593) {1879) {

1594 type Phase = null | "commentary" | "final_answer";1880 type Phase = null | "commentary" | "final_answer";


1597 input: process.stdin,1883 input: process.stdin,

1598 output: process.stdout,1884 output: process.stdout,

1599 });1885 });

1600 const browser = await chromium.launch({1886 const sessionId = randomUUID();

1601 headless: false,1887 const conversation: any[] = [{ role: "user", content: prompt }];

1602 args: ["--window-size=1440,900"],

1603 });

1604 const context = await browser.newContext({

1605 viewport: { width: 1440, height: 900 },

1606 });

1607 const page = await context.newPage();

1608 

1609 const conversation: any[] = [];

1610 const js_output: any[] = [];

1611 const sandbox: Record<string, any> = {

1612 console: {

1613 log: (...xs: any[]) => {

1614 js_output.push({

1615 type: "input_text",

1616 text: util.formatWithOptions(

1617 { showHidden: false, getters: false, maxStringLength: 2000 },

1618 ...xs

1619 ),

1620 });

1621 },

1622 },

1623 browser: browser,

1624 context: context,

1625 page: page,

1626 display: (base64_image: string) => {

1627 js_output.push({

1628 type: "input_image",

1629 image_url: `data:image/png;base64,${base64_image}`,

1630 detail: "original",

1631 });

1632 },

1633 };

1634 const ctx = vm.createContext(sandbox);

1635 

1636 conversation.push({

1637 role: "user",

1638 content: prompt,

1639 });

1640 1888 

1641 for (let i = 0; i < max_steps; i++) {1889 try {

1642 const resp = await client.responses.create({1890 for (let i = 0; i < maxSteps; i++) {

1891 const response = await client.responses.create({

1643 model,1892 model,

1644 tools: [1893 tools: [

1645 {1894 {

1646 type: "function" as const,1895 type: "function" as const,

1647 name: "exec_js",1896 name: "exec_js",

1648 description:1897 description:

1649 "Execute provided interactive JavaScript in a persistent REPL context.",1898 "Execute provided interactive JavaScript in a persistent, isolated browser runtime.",

1650 parameters: {1899 parameters: {

1651 type: "object",1900 type: "object",

1652 properties: {1901 properties: {

1653 code: {1902 code: {

1654 type: "string",1903 type: "string",

1655 description: `1904 description: `

1656JavaScript to execute. Write small snippets of interactive code. To persist variables or functions across tool calls, you must save them to globalThis. Code is executed in an async node:vm context, so you can use await. You have access to ONLY the following:1905JavaScript to execute. Write small snippets of interactive code. To persist variables or functions across tool calls, save them to globalThis. The isolated runtime supports await and provides only these helpers and Playwright objects:

1657- console.log(x): Use this to read contents back to you. But be minimal: otherwise the output may be too long. Avoid using console.log() for large base64 payloads like screenshots or buffer. If you create an image or screenshot, pass the base64 string to display().1906- console.log(x): Return concise text. Do not log large base64 payloads, screenshots, buffers, page HTML, or other large blobs.

1658- display(base64_image_string): Use this to view a base64-encoded image.1907- display(base64_image_string): Return a base64-encoded image.

1659- Do not write screenshots or image data to temporary files or disk just to pass them back. Keep image data in memory and send it directly to display().1908- browser: A Playwright Chromium browser instance.

1660- Do not assume package globals like Bun.file are available unless they are explicitly provided.1909- context: A Playwright browser context with viewport 1440x900.

1661- browser: A playwright chromium browser instance.1910- page: A Playwright page already created in that context.

1662- context: A playwright browser context with viewport 1440x900.1911Keep screenshots and image data in memory and pass them directly to display(). Do not assume other globals or packages are available.

1663- page: A playwright page already created in that context.

1664`,1912`,

1665 },1913 },

1666 },1914 },

1667 required: ["code"],1915 required: ["code"],

1668 additionalProperties: false,1916 additionalProperties: false,

1669 },1917 },

1918 strict: true,

1670 },1919 },

1671 {1920 {

1672 type: "function" as const,1921 type: "function" as const,


1685 required: ["question"],1934 required: ["question"],

1686 additionalProperties: false,1935 additionalProperties: false,

1687 },1936 },

1937 strict: true,

1688 },1938 },

1689 ],1939 ],

1690 input: conversation,1940 input: conversation,


1693 },1943 },

1694 });1944 });

1695 1945 

1696 // Save model outputs into the running conversation1946 conversation.push(...response.output);

1697 conversation.push(...resp.output);

1698 

1699 let hadToolCall = false;1947 let hadToolCall = false;

1700 let latestPhase: Phase = null;1948 let latestPhase: Phase = null;

1701 1949 

1702 // Handle tool calls1950 for (const item of response.output) {

1703 for (const item of resp.output) {

1704 if (item.type === "function_call" && item.name === "exec_js") {1951 if (item.type === "function_call" && item.name === "exec_js") {

1705 hadToolCall = true;1952 hadToolCall = true;

1706 const parsed = JSON.parse(item.arguments ?? "{}") as {1953 const parsed = JSON.parse(item.arguments ?? "{}") as {


1709 const code = parsed.code ?? "";1956 const code = parsed.code ?? "";

1710 console.log(code);1957 console.log(code);

1711 console.log("----");1958 console.log("----");

1712 const wrappedCode = `

1713 (async () => {

1714 ${code}

1715 })();

1716 `;

1717 1959 

1960 let executionOutput: ExecutionOutput[];

1961 const endpoint = process.env.OPENAI_EXAMPLE_CODE_EXECUTION_URL;

1962 if (!endpoint) {

1963 executionOutput = await executeInSandbox(code, sessionId);

1964 } else {

1965 const approval = await rl.question(

1966 "Send this generated JavaScript to the isolated runtime? Type yes to continue: "

1967 );

1968 if (approval.trim().toLowerCase() !== "yes") {

1969 executionOutput = [

1970 {

1971 type: "input_text",

1972 text: "The user declined this code execution.",

1973 },

1974 ];

1975 } else {

1718 try {1976 try {

1719 await new vm.Script(wrappedCode, {1977 executionOutput = await executeInSandbox(code, sessionId);

1720 filename: "exec_js.js",1978 } catch (error) {

1721 }).runInContext(ctx);1979 executionOutput = [

1722 } catch (e: any) {1980 {

1723 sandbox.console.log(e, e?.message, e?.stack);1981 type: "input_text",

1982 text:

1983 error instanceof Error ? error.message : String(error),

1984 },

1985 ];

1986 }

1987 }

1724 }1988 }

1725 1989 

1726 // Send tool output back to the model, keyed by call_id

1727 conversation.push({1990 conversation.push({

1728 type: "function_call_output",1991 type: "function_call_output",

1729 call_id: item.call_id,1992 call_id: item.call_id,

1730 output: js_output.slice(),1993 output: executionOutput,

1731 });1994 });

1732 1995 

1733 for (const out of js_output) {1996 for (const output of executionOutput) {

1734 if (out.type === "input_text") {1997 if (output.type === "input_text") {

1735 console.log("JS LOG:", out.text);1998 console.log("JS LOG:", output.text);

1736 } else if (out.type === "input_image") {1999 } else {

1737 console.log("JS IMAGE: [base64 string omitted]");2000 console.log("JS IMAGE: [base64 string omitted]");

1738 }2001 }

1739 }2002 }

1740 console.log("=====");2003 console.log("=====");

1741 

1742 js_output.length = 0;

1743 } else if (item.type === "function_call" && item.name === "ask_user") {2004 } else if (item.type === "function_call" && item.name === "ask_user") {

1744 hadToolCall = true;2005 hadToolCall = true;

1745 const parsed = JSON.parse(item.arguments ?? "{}") as {2006 const parsed = JSON.parse(item.arguments ?? "{}") as {

1746 question?: string;2007 question?: string;

1747 };2008 };

1748 const question = parsed.question ?? "Please provide more information.";2009 const question =

2010 parsed.question ?? "Please provide more information.";

1749 console.log(`MODEL QUESTION: ${question}`);2011 console.log(`MODEL QUESTION: ${question}`);

1750 const answer = await rl.question("> ");2012 const answer = await rl.question("> ");

1751 conversation.push({2013 conversation.push({


1754 output: answer,2016 output: answer,

1755 });2017 });

1756 } else if (item.type === "message") {2018 } else if (item.type === "message") {

1757 console.log(item.content[0]?.text ?? item.content);2019 const text = item.content.find((part) => part.type === "output_text");

2020 console.log(text?.text ?? item.content);

1758 if ("phase" in item) {2021 if ("phase" in item) {

1759 latestPhase = (item.phase as Phase) ?? null;2022 latestPhase = (item.phase as Phase) ?? null;

1760 }2023 }

1761 } else if (item.type === "output_item.done" && "phase" in item) {

1762 latestPhase = (item.phase as Phase) ?? null;

1763 }2024 }

1764 }2025 }

1765 2026 

1766 // Stop only when the model explicitly marks the turn as a final answer

1767 // and there were no tool calls in the same turn.

1768 if (!hadToolCall && latestPhase === "final_answer") return;2027 if (!hadToolCall && latestPhase === "final_answer") return;

1769 }2028 }

2029 } finally {

2030 rl.close();

2031 }

1770}2032}

1771 2033 

1772function getCliPrompt(): string | undefined {2034function getCliPrompt(): string | undefined {

1773 const args = Bun.argv.slice(2);2035 const args = process.argv.slice(2);

1774 for (let i = 0; i < args.length; i++) {2036 for (let i = 0; i < args.length; i++) {

1775 if (args[i] === "--prompt") {2037 if (args[i] === "--prompt") return args[i + 1];

1776 return args[i + 1];

1777 }

1778 }2038 }

1779 return undefined;2039 return undefined;

1780}2040}

1781 2041 

1782main(getCliPrompt());2042await main(getCliPrompt());

1783```2043```

1784 2044 

2045 </div>

2046 <div data-content-switcher-pane data-value="python" hidden>

2047 <div class="hidden">Python</div>

2048 Code-execution harness

2049 

1785```python2050```python

1786# /// script2051# /// script

1787# requires-python = ">=3.10"2052# requires-python = ">=3.10"

1788# dependencies = [2053# dependencies = [

1789# "openai",2054# "openai",

1790# "playwright",

1791# ]2055# ]

1792# ///2056# ///

1793# Run with: `uv run cua_code_mode_py_async.py`2057# Run with: `uv run cua_code_mode_py_async.py`

1794# Override the user prompt with:2058# Override the user prompt with:

1795# `uv run cua_code_mode_py_async.py --prompt "Go to example.com and summarize the page."`2059# `uv run cua_code_mode_py_async.py --prompt "Go to example.com and summarize the page."`

1796# Install Chromium once first: `uv run --with playwright python -m playwright install chromium`2060# Requires `OPENAI_API_KEY` and `OPENAI_EXAMPLE_CODE_EXECUTION_URL`.

1797# Requires `OPENAI_API_KEY` in the environment.

1798 2061 

1799"""Async Python analogue of cua_code_mode.ts.2062"""Async Python analogue of cua_code_mode.ts.

1800 2063 

1801Runs a Responses API loop with one persistent Playwright browser/context/page,2064The API client sends approved snippets to a separately isolated sandbox service.

1802and tools that let the model execute short async Python snippets and ask the2065The sandbox keeps a Playwright browser, context, and page alive for each session

1803user clarifying questions.2066and returns text or image outputs. Never run model-generated code in this API

1804 2067client process.

1805The model can return visual observations by calling:

1806 display(base64_png_string)

1807"""2068"""

1808 2069 

1809from __future__ import annotations2070from __future__ import annotations


1811import argparse2072import argparse

1812import asyncio2073import asyncio

1813import json2074import json

1814import traceback2075import os

2076import uuid

1815from typing import Any2077from typing import Any

2078from urllib import request

1816 2079 

1817from openai import OpenAI2080from openai import OpenAI

1818from playwright.async_api import async_playwright

1819 2081 

1820Phase = str | None2082Phase = str | None

2083EXECUTION_TIMEOUT_SECONDS = 30

1821 2084 

1822 2085 

1823def _message_text(item: Any) -> str:2086def _message_text(item: Any) -> str:


1840 return await asyncio.to_thread(input, prompt)2103 return await asyncio.to_thread(input, prompt)

1841 2104 

1842 2105 

2106def _is_execution_output(value: Any) -> bool:

2107 if not isinstance(value, dict):

2108 return False

2109 if value.get("type") == "input_text":

2110 return isinstance(value.get("text"), str)

2111 return (

2112 value.get("type") == "input_image"

2113 and isinstance(value.get("image_url"), str)

2114 and value.get("detail") == "original"

2115 )

2116 

2117 

2118def _execute_in_sandbox(code: str, session_id: str) -> list[dict[str, Any]]:

2119 endpoint = os.environ.get("OPENAI_EXAMPLE_CODE_EXECUTION_URL")

2120 if not endpoint:

2121 return [

2122 {

2123 "type": "input_text",

2124 "text": (

2125 "Execution blocked. Configure OPENAI_EXAMPLE_CODE_EXECUTION_URL "

2126 "with a separately isolated sandbox service."

2127 ),

2128 }

2129 ]

2130 

2131 headers = {"Content-Type": "application/json"}

2132 token = os.environ.get("OPENAI_EXAMPLE_CODE_EXECUTION_TOKEN")

2133 if token:

2134 headers["Authorization"] = f"Bearer {token}"

2135 

2136 body = json.dumps(

2137 {

2138 "session_id": session_id,

2139 "language": "python",

2140 "code": code,

2141 }

2142 ).encode()

2143 sandbox_request = request.Request(

2144 endpoint,

2145 data=body,

2146 headers=headers,

2147 method="POST",

2148 )

2149 with request.urlopen(

2150 sandbox_request,

2151 timeout=EXECUTION_TIMEOUT_SECONDS,

2152 ) as response:

2153 payload = json.loads(response.read())

2154 

2155 output = payload.get("output") if isinstance(payload, dict) else None

2156 if not isinstance(output, list) or not all(

2157 _is_execution_output(item) for item in output

2158 ):

2159 raise ValueError("Sandbox returned an invalid output payload.")

2160 return output

2161 

2162 

1843async def main(2163async def main(

1844 prompt: str = "Go to Hacker News, click on the most interesting link (be prepared to justify your choice), take a screenshot, and give me a critique of the visual layout.",2164 prompt: str = "Go to Hacker News, click on the most interesting link (be prepared to justify your choice), take a screenshot, and give me a critique of the visual layout.",

1845 max_steps: int = 20,2165 max_steps: int = 20,

1846 model: str = "gpt-5.6",2166 model: str = "gpt-5.6",

1847) -> None:2167) -> None:

1848 client = OpenAI()2168 client = OpenAI()

2169 session_id = str(uuid.uuid4())

1849 2170 

1850 async with async_playwright() as p:2171 async def run_loop() -> None:

1851 browser = await p.chromium.launch(

1852 headless=False,

1853 args=["--window-size=1440,900"],

1854 )

1855 context = await browser.new_context(viewport={"width": 1440, "height": 900})

1856 page = await context.new_page()

1857 

1858 conversation: list[dict[str, Any]] = [{"role": "user", "content": prompt}]2172 conversation: list[dict[str, Any]] = [{"role": "user", "content": prompt}]

1859 py_output: list[dict[str, Any]] = []

1860 

1861 def log(*xs: Any) -> None:

1862 text = " ".join(str(x) for x in xs)

1863 py_output.append({"type": "input_text", "text": text[:5000]})

1864 

1865 def display(base64_image: str) -> None:

1866 py_output.append(

1867 {

1868 "type": "input_image",

1869 "image_url": f"data:image/png;base64,{base64_image}",

1870 "detail": "original",

1871 }

1872 )

1873 

1874 runtime_globals: dict[str, Any] = {

1875 "__builtins__": __builtins__,

1876 "asyncio": asyncio,

1877 "browser": browser,

1878 "context": context,

1879 "page": page,

1880 "display": display,

1881 "log": log,

1882 }

1883 2173 

1884 for _ in range(max_steps):2174 for _ in range(max_steps):

1885 resp = client.responses.create(2175 resp = client.responses.create(


1888 {2178 {

1889 "type": "function",2179 "type": "function",

1890 "name": "exec_py",2180 "name": "exec_py",

1891 "description": "Execute provided interactive async Python in a persistent runtime context.",2181 "description": "Execute provided interactive async Python in a persistent, isolated browser runtime.",

1892 "parameters": {2182 "parameters": {

1893 "type": "object",2183 "type": "object",

1894 "properties": {2184 "properties": {


1897 "description": (2187 "description": (

1898 "Python code to execute. Write small snippets. "2188 "Python code to execute. Write small snippets. "

1899 "State persists across tool calls via globals(). "2189 "State persists across tool calls via globals(). "

1900 "This runtime uses Playwright's async Python API, so you may use await directly. "2190 "The isolated runtime supports await and provides only these helpers and Playwright objects: "

1901 "Do not call asyncio.run(...), loop.run_until_complete(...), or manage the event loop yourself. "2191 "log(x) for concise text output, display(base64_png_string) for image output, "

1902 "You can use ONLY these prebound objects/helpers: "2192 "browser (async Playwright browser), context (viewport 1440x900), and page. "

1903 "log(x) for text output, display(base64_png_string) for image output, "2193 "Keep screenshots and image data in memory and pass them directly to display(). "

1904 "browser (async Playwright browser), context (viewport 1440x900), page (already created), "2194 "Do not assume other globals or packages are available."

1905 "asyncio (module). "

1906 "Be concise with log(x): do not send large base64 payloads, screenshots, buffers, page HTML, "

1907 "or other large blobs through log(). If you create an image or screenshot, pass the base64 PNG "

1908 "string to display(). Do not write screenshots or image data to temporary files or disk just "

1909 "to pass them back; keep image data in memory and send it directly to display(). "

1910 "Do not assume extra globals or helpers are available unless they are explicitly listed here. "

1911 "Do not close browser/context/page unless explicitly asked."

1912 ),2195 ),

1913 }2196 }

1914 },2197 },

1915 "required": ["code"],2198 "required": ["code"],

1916 "additionalProperties": False,2199 "additionalProperties": False,

1917 },2200 },

2201 "strict": True,

1918 },2202 },

1919 {2203 {

1920 "type": "function",2204 "type": "function",


1931 "required": ["question"],2215 "required": ["question"],

1932 "additionalProperties": False,2216 "additionalProperties": False,

1933 },2217 },

2218 "strict": True,

1934 },2219 },

1935 ],2220 ],

1936 input=conversation,2221 input=conversation,


1956 print(code)2241 print(code)

1957 print("----")2242 print("----")

1958 2243 

1959 wrapped = (2244 if not os.environ.get("OPENAI_EXAMPLE_CODE_EXECUTION_URL"):

1960 "async def __codex_exec__():\n"2245 py_output = _execute_in_sandbox(code, session_id)

1961 + "".join(2246 else:

1962 f" {line}\n" if line else " \n"2247 approval = await _ainput(

1963 for line in (code or "pass").splitlines()2248 "Send this generated Python to the isolated runtime? "

1964 )2249 "Type yes to continue: "

1965 )2250 )

1966 2251 if approval.strip().lower() != "yes":

2252 py_output = [

2253 {

2254 "type": "input_text",

2255 "text": "The user declined this code execution.",

2256 }

2257 ]

2258 else:

1967 try:2259 try:

1968 exec(wrapped, runtime_globals, runtime_globals)2260 py_output = await asyncio.wait_for(

1969 await runtime_globals["__codex_exec__"]()2261 asyncio.to_thread(

1970 except Exception:2262 _execute_in_sandbox,

1971 log(traceback.format_exc())2263 code,

2264 session_id,

2265 ),

2266 timeout=EXECUTION_TIMEOUT_SECONDS,

2267 )

2268 except Exception as exc:

2269 py_output = [

2270 {

2271 "type": "input_text",

2272 "text": str(exc),

2273 }

2274 ]

1972 2275 

1973 conversation.append(2276 conversation.append(

1974 {2277 {

1975 "type": "function_call_output",2278 "type": "function_call_output",

1976 "call_id": getattr(item, "call_id", None),2279 "call_id": getattr(item, "call_id", None),

1977 "output": py_output[:],2280 "output": py_output,

1978 }2281 }

1979 )2282 )

1980 2283 


1985 print("PY IMAGE: [base64 string omitted]")2288 print("PY IMAGE: [base64 string omitted]")

1986 print("=====")2289 print("=====")

1987 2290 

1988 py_output.clear()

1989 

1990 elif item_type == "function_call" and getattr(item, "name", None) == "ask_user":2291 elif item_type == "function_call" and getattr(item, "name", None) == "ask_user":

1991 had_tool_call = True2292 had_tool_call = True

1992 raw_args = getattr(item, "arguments", "{}") or "{}"2293 raw_args = getattr(item, "arguments", "{}") or "{}"


2024 if not had_tool_call and latest_phase == "final_answer":2325 if not had_tool_call and latest_phase == "final_answer":

2025 return2326 return

2026 2327 

2027 2328 await run_loop()

2028if __name__ == "__main__":

2029 parser = argparse.ArgumentParser()

2030 parser.add_argument("--prompt", help="Override the default user prompt.")

2031 args = parser.parse_args()

2032 asyncio.run(main(prompt=args.prompt) if args.prompt is not None else main())

2033```

2034 

2035 </div>

2036 <div data-content-switcher-pane data-value="python" hidden>

2037 <div class="hidden">Python</div>

2038 Code-execution harness

2039 

2040```javascript

2041// Run with:

2042// bun run -i cua_code_mode.ts

2043// Override the user prompt with:

2044// bun run -i cua_code_mode.ts --prompt "Go to example.com and summarize the page."

2045// Note: this script intentionally leaves the Playwright browser open after the

2046// model reaches a final answer. Because the browser/context are not closed,

2047// Bun stays alive until you close the browser or stop the process manually.

2048 

2049import OpenAI from "openai";

2050import readline from "node:readline/promises";

2051import vm from "node:vm";

2052import { chromium } from "playwright";

2053import util from "node:util";

2054 

2055async function main(

2056 prompt: string = "Go to Hacker News, click on the most interesting link (be prepared to justify your choice), take a screenshot, and give me a critique of the visual layout.",

2057 max_steps: number = 50,

2058 model: string = "gpt-5.6"

2059) {

2060 type Phase = null | "commentary" | "final_answer";

2061 const client = new OpenAI();

2062 const rl = readline.createInterface({

2063 input: process.stdin,

2064 output: process.stdout,

2065 });

2066 const browser = await chromium.launch({

2067 headless: false,

2068 args: ["--window-size=1440,900"],

2069 });

2070 const context = await browser.newContext({

2071 viewport: { width: 1440, height: 900 },

2072 });

2073 const page = await context.newPage();

2074 

2075 const conversation: any[] = [];

2076 const js_output: any[] = [];

2077 const sandbox: Record<string, any> = {

2078 console: {

2079 log: (...xs: any[]) => {

2080 js_output.push({

2081 type: "input_text",

2082 text: util.formatWithOptions(

2083 { showHidden: false, getters: false, maxStringLength: 2000 },

2084 ...xs

2085 ),

2086 });

2087 },

2088 },

2089 browser: browser,

2090 context: context,

2091 page: page,

2092 display: (base64_image: string) => {

2093 js_output.push({

2094 type: "input_image",

2095 image_url: `data:image/png;base64,${base64_image}`,

2096 detail: "original",

2097 });

2098 },

2099 };

2100 const ctx = vm.createContext(sandbox);

2101 

2102 conversation.push({

2103 role: "user",

2104 content: prompt,

2105 });

2106 

2107 for (let i = 0; i < max_steps; i++) {

2108 const resp = await client.responses.create({

2109 model,

2110 tools: [

2111 {

2112 type: "function" as const,

2113 name: "exec_js",

2114 description:

2115 "Execute provided interactive JavaScript in a persistent REPL context.",

2116 parameters: {

2117 type: "object",

2118 properties: {

2119 code: {

2120 type: "string",

2121 description: `

2122JavaScript to execute. Write small snippets of interactive code. To persist variables or functions across tool calls, you must save them to globalThis. Code is executed in an async node:vm context, so you can use await. You have access to ONLY the following:

2123- console.log(x): Use this to read contents back to you. But be minimal: otherwise the output may be too long. Avoid using console.log() for large base64 payloads like screenshots or buffer. If you create an image or screenshot, pass the base64 string to display().

2124- display(base64_image_string): Use this to view a base64-encoded image.

2125- Do not write screenshots or image data to temporary files or disk just to pass them back. Keep image data in memory and send it directly to display().

2126- Do not assume package globals like Bun.file are available unless they are explicitly provided.

2127- browser: A playwright chromium browser instance.

2128- context: A playwright browser context with viewport 1440x900.

2129- page: A playwright page already created in that context.

2130`,

2131 },

2132 },

2133 required: ["code"],

2134 additionalProperties: false,

2135 },

2136 },

2137 {

2138 type: "function" as const,

2139 name: "ask_user",

2140 description:

2141 "Ask the user a clarification question and wait for their response.",

2142 parameters: {

2143 type: "object",

2144 properties: {

2145 question: {

2146 type: "string",

2147 description:

2148 "The exact question to show the human. Use this instead of answering with a freeform clarifying question in a final answer.",

2149 },

2150 },

2151 required: ["question"],

2152 additionalProperties: false,

2153 },

2154 },

2155 ],

2156 input: conversation,

2157 reasoning: {

2158 effort: "low",

2159 },

2160 });

2161 

2162 // Save model outputs into the running conversation

2163 conversation.push(...resp.output);

2164 

2165 let hadToolCall = false;

2166 let latestPhase: Phase = null;

2167 

2168 // Handle tool calls

2169 for (const item of resp.output) {

2170 if (item.type === "function_call" && item.name === "exec_js") {

2171 hadToolCall = true;

2172 const parsed = JSON.parse(item.arguments ?? "{}") as {

2173 code?: string;

2174 };

2175 const code = parsed.code ?? "";

2176 console.log(code);

2177 console.log("----");

2178 const wrappedCode = `

2179 (async () => {

2180 ${code}

2181 })();

2182 `;

2183 

2184 try {

2185 await new vm.Script(wrappedCode, {

2186 filename: "exec_js.js",

2187 }).runInContext(ctx);

2188 } catch (e: any) {

2189 sandbox.console.log(e, e?.message, e?.stack);

2190 }

2191 

2192 // Send tool output back to the model, keyed by call_id

2193 conversation.push({

2194 type: "function_call_output",

2195 call_id: item.call_id,

2196 output: js_output.slice(),

2197 });

2198 

2199 for (const out of js_output) {

2200 if (out.type === "input_text") {

2201 console.log("JS LOG:", out.text);

2202 } else if (out.type === "input_image") {

2203 console.log("JS IMAGE: [base64 string omitted]");

2204 }

2205 }

2206 console.log("=====");

2207 

2208 js_output.length = 0;

2209 } else if (item.type === "function_call" && item.name === "ask_user") {

2210 hadToolCall = true;

2211 const parsed = JSON.parse(item.arguments ?? "{}") as {

2212 question?: string;

2213 };

2214 const question = parsed.question ?? "Please provide more information.";

2215 console.log(`MODEL QUESTION: ${question}`);

2216 const answer = await rl.question("> ");

2217 conversation.push({

2218 type: "function_call_output",

2219 call_id: item.call_id,

2220 output: answer,

2221 });

2222 } else if (item.type === "message") {

2223 console.log(item.content[0]?.text ?? item.content);

2224 if ("phase" in item) {

2225 latestPhase = (item.phase as Phase) ?? null;

2226 }

2227 } else if (item.type === "output_item.done" && "phase" in item) {

2228 latestPhase = (item.phase as Phase) ?? null;

2229 }

2230 }

2231 

2232 // Stop only when the model explicitly marks the turn as a final answer

2233 // and there were no tool calls in the same turn.

2234 if (!hadToolCall && latestPhase === "final_answer") return;

2235 }

2236}

2237 

2238function getCliPrompt(): string | undefined {

2239 const args = Bun.argv.slice(2);

2240 for (let i = 0; i < args.length; i++) {

2241 if (args[i] === "--prompt") {

2242 return args[i + 1];

2243 }

2244 }

2245 return undefined;

2246}

2247 

2248main(getCliPrompt());

2249```

2250 

2251```python

2252# /// script

2253# requires-python = ">=3.10"

2254# dependencies = [

2255# "openai",

2256# "playwright",

2257# ]

2258# ///

2259# Run with: `uv run cua_code_mode_py_async.py`

2260# Override the user prompt with:

2261# `uv run cua_code_mode_py_async.py --prompt "Go to example.com and summarize the page."`

2262# Install Chromium once first: `uv run --with playwright python -m playwright install chromium`

2263# Requires `OPENAI_API_KEY` in the environment.

2264 

2265"""Async Python analogue of cua_code_mode.ts.

2266 

2267Runs a Responses API loop with one persistent Playwright browser/context/page,

2268and tools that let the model execute short async Python snippets and ask the

2269user clarifying questions.

2270 

2271The model can return visual observations by calling:

2272 display(base64_png_string)

2273"""

2274 

2275from __future__ import annotations

2276 

2277import argparse

2278import asyncio

2279import json

2280import traceback

2281from typing import Any

2282 

2283from openai import OpenAI

2284from playwright.async_api import async_playwright

2285 

2286Phase = str | None

2287 

2288 

2289def _message_text(item: Any) -> str:

2290 try:

2291 parts = getattr(item, "content", None)

2292 if isinstance(parts, list) and parts:

2293 out: list[str] = []

2294 for p in parts:

2295 t = getattr(p, "text", None)

2296 if isinstance(t, str) and t:

2297 out.append(t)

2298 if out:

2299 return "\n".join(out)

2300 except Exception:

2301 pass

2302 return str(item)

2303 

2304 

2305async def _ainput(prompt: str) -> str:

2306 return await asyncio.to_thread(input, prompt)

2307 

2308 

2309async def main(

2310 prompt: str = "Go to Hacker News, click on the most interesting link (be prepared to justify your choice), take a screenshot, and give me a critique of the visual layout.",

2311 max_steps: int = 20,

2312 model: str = "gpt-5.6",

2313) -> None:

2314 client = OpenAI()

2315 

2316 async with async_playwright() as p:

2317 browser = await p.chromium.launch(

2318 headless=False,

2319 args=["--window-size=1440,900"],

2320 )

2321 context = await browser.new_context(viewport={"width": 1440, "height": 900})

2322 page = await context.new_page()

2323 

2324 conversation: list[dict[str, Any]] = [{"role": "user", "content": prompt}]

2325 py_output: list[dict[str, Any]] = []

2326 

2327 def log(*xs: Any) -> None:

2328 text = " ".join(str(x) for x in xs)

2329 py_output.append({"type": "input_text", "text": text[:5000]})

2330 

2331 def display(base64_image: str) -> None:

2332 py_output.append(

2333 {

2334 "type": "input_image",

2335 "image_url": f"data:image/png;base64,{base64_image}",

2336 "detail": "original",

2337 }

2338 )

2339 

2340 runtime_globals: dict[str, Any] = {

2341 "__builtins__": __builtins__,

2342 "asyncio": asyncio,

2343 "browser": browser,

2344 "context": context,

2345 "page": page,

2346 "display": display,

2347 "log": log,

2348 }

2349 

2350 for _ in range(max_steps):

2351 resp = client.responses.create(

2352 model=model,

2353 tools=[

2354 {

2355 "type": "function",

2356 "name": "exec_py",

2357 "description": "Execute provided interactive async Python in a persistent runtime context.",

2358 "parameters": {

2359 "type": "object",

2360 "properties": {

2361 "code": {

2362 "type": "string",

2363 "description": (

2364 "Python code to execute. Write small snippets. "

2365 "State persists across tool calls via globals(). "

2366 "This runtime uses Playwright's async Python API, so you may use await directly. "

2367 "Do not call asyncio.run(...), loop.run_until_complete(...), or manage the event loop yourself. "

2368 "You can use ONLY these prebound objects/helpers: "

2369 "log(x) for text output, display(base64_png_string) for image output, "

2370 "browser (async Playwright browser), context (viewport 1440x900), page (already created), "

2371 "asyncio (module). "

2372 "Be concise with log(x): do not send large base64 payloads, screenshots, buffers, page HTML, "

2373 "or other large blobs through log(). If you create an image or screenshot, pass the base64 PNG "

2374 "string to display(). Do not write screenshots or image data to temporary files or disk just "

2375 "to pass them back; keep image data in memory and send it directly to display(). "

2376 "Do not assume extra globals or helpers are available unless they are explicitly listed here. "

2377 "Do not close browser/context/page unless explicitly asked."

2378 ),

2379 }

2380 },

2381 "required": ["code"],

2382 "additionalProperties": False,

2383 },

2384 },

2385 {

2386 "type": "function",

2387 "name": "ask_user",

2388 "description": "Ask the user a clarification question and wait for their response.",

2389 "parameters": {

2390 "type": "object",

2391 "properties": {

2392 "question": {

2393 "type": "string",

2394 "description": "The exact question to show the user. Use this instead of asking a freeform clarifying question in a final answer.",

2395 }

2396 },

2397 "required": ["question"],

2398 "additionalProperties": False,

2399 },

2400 },

2401 ],

2402 input=conversation,

2403 )

2404 

2405 conversation.extend(resp.output)

2406 

2407 had_tool_call = False

2408 latest_phase: Phase = None

2409 

2410 for item in resp.output:

2411 item_type = getattr(item, "type", None)

2412 

2413 if item_type == "function_call" and getattr(item, "name", None) == "exec_py":

2414 had_tool_call = True

2415 raw_args = getattr(item, "arguments", "{}") or "{}"

2416 try:

2417 args = json.loads(raw_args)

2418 except json.JSONDecodeError:

2419 args = {}

2420 code = args.get("code", "") if isinstance(args, dict) else ""

2421 

2422 print(code)

2423 print("----")

2424 

2425 wrapped = (

2426 "async def __codex_exec__():\n"

2427 + "".join(

2428 f" {line}\n" if line else " \n"

2429 for line in (code or "pass").splitlines()

2430 )

2431 )

2432 

2433 try:

2434 exec(wrapped, runtime_globals, runtime_globals)

2435 await runtime_globals["__codex_exec__"]()

2436 except Exception:

2437 log(traceback.format_exc())

2438 

2439 conversation.append(

2440 {

2441 "type": "function_call_output",

2442 "call_id": getattr(item, "call_id", None),

2443 "output": py_output[:],

2444 }

2445 )

2446 

2447 for out in py_output:

2448 if out.get("type") == "input_text":

2449 print("PY LOG:", out.get("text", ""))

2450 elif out.get("type") == "input_image":

2451 print("PY IMAGE: [base64 string omitted]")

2452 print("=====")

2453 

2454 py_output.clear()

2455 

2456 elif item_type == "function_call" and getattr(item, "name", None) == "ask_user":

2457 had_tool_call = True

2458 raw_args = getattr(item, "arguments", "{}") or "{}"

2459 try:

2460 args = json.loads(raw_args)

2461 except json.JSONDecodeError:

2462 args = {}

2463 question = (

2464 args.get("question", "Please provide more information.")

2465 if isinstance(args, dict)

2466 else "Please provide more information."

2467 )

2468 

2469 print(f"MODEL QUESTION: {question}")

2470 answer = await _ainput("> ")

2471 

2472 conversation.append(

2473 {

2474 "type": "function_call_output",

2475 "call_id": getattr(item, "call_id", None),

2476 "output": answer,

2477 }

2478 )

2479 

2480 elif item_type == "message":

2481 print(_message_text(item))

2482 phase = getattr(item, "phase", None)

2483 if isinstance(phase, str) or phase is None:

2484 latest_phase = phase

2485 elif item_type == "output_item.done":

2486 phase = getattr(item, "phase", None)

2487 if isinstance(phase, str) or phase is None:

2488 latest_phase = phase

2489 

2490 if not had_tool_call and latest_phase == "final_answer":

2491 return

2492 2329 

2493 2330 

2494if __name__ == "__main__":2331if __name__ == "__main__":

Details

56 {56 {

57 type: "mcp",57 type: "mcp",

58 server_label: "dmcp",58 server_label: "dmcp",

59 server_description: "A Dungeons and Dragons MCP server to assist with dice rolling.",59 server_description:

60 "A Dungeons and Dragons MCP server to assist with dice rolling.",

60 server_url: "https://dmcp-server.deno.dev/mcp",61 server_url: "https://dmcp-server.deno.dev/mcp",

61 require_approval: "never",62 require_approval: "never",

62 },63 },


361 362 

362const resp = await client.responses.create({363const resp = await client.responses.create({

363 model: "gpt-5.6",364 model: "gpt-5.6",

364 tools: [{365 tools: [

366 {

365 type: "mcp",367 type: "mcp",

366 server_label: "dmcp",368 server_label: "dmcp",

367 server_description: "A Dungeons and Dragons MCP server to assist with dice rolling.",369 server_description:

370 "A Dungeons and Dragons MCP server to assist with dice rolling.",

368 server_url: "https://dmcp-server.deno.dev/mcp",371 server_url: "https://dmcp-server.deno.dev/mcp",

369 require_approval: "never",372 require_approval: "never",

370 allowed_tools: ["roll"],373 allowed_tools: ["roll"],

371 }],374 },

375 ],

372 input: "Roll 2d4+1",376 input: "Roll 2d4+1",

373});377});

374 378 


489 493 

490const resp = await client.responses.create({494const resp = await client.responses.create({

491 model: "gpt-5.6",495 model: "gpt-5.6",

492 tools: [{496 tools: [

497 {

493 type: "mcp",498 type: "mcp",

494 server_label: "dmcp",499 server_label: "dmcp",

495 server_description: "A Dungeons and Dragons MCP server to assist with dice rolling.",500 server_description:

501 "A Dungeons and Dragons MCP server to assist with dice rolling.",

496 server_url: "https://dmcp-server.deno.dev/mcp",502 server_url: "https://dmcp-server.deno.dev/mcp",

497 require_approval: "always",503 require_approval: "always",

498 }],504 },

505 ],

499 previous_response_id: "resp_682d498bdefc81918b4a6aa477bfafd904ad1e533afccbfa",506 previous_response_id: "resp_682d498bdefc81918b4a6aa477bfafd904ad1e533afccbfa",

500 input: [{507 input: [

508 {

501 type: "mcp_approval_response",509 type: "mcp_approval_response",

502 approve: true,510 approve: true,

503 approval_request_id: "mcpr_682d498e3bd4819196a0ce1664f8e77b04ad1e533afccbfa"511 approval_request_id:

504 }],512 "mcpr_682d498e3bd4819196a0ce1664f8e77b04ad1e533afccbfa",

513 },

514 ],

505});515});

506 516 

507console.log(resp.output_text);517console.log(resp.output_text);


605 server_url: "https://mcp.deepwiki.com/mcp",615 server_url: "https://mcp.deepwiki.com/mcp",

606 require_approval: {616 require_approval: {

607 never: {617 never: {

608 tool_names: ["ask_question", "read_wiki_structure"]618 tool_names: ["ask_question", "read_wiki_structure"],

609 }619 },

610 }620 },

611 },621 },

612 ],622 ],

613 input: "What transport protocols does the 2025-03-26 version of the MCP spec (modelcontextprotocol/modelcontextprotocol) support?",623 input:

624 "What transport protocols does the 2025-03-26 version of the MCP spec (modelcontextprotocol/modelcontextprotocol) support?",

614});625});

615 626 

616console.log(resp.output_text);627console.log(resp.output_text);


701 type: "mcp",712 type: "mcp",

702 server_label: "stripe",713 server_label: "stripe",

703 server_url: "https://mcp.stripe.com",714 server_url: "https://mcp.stripe.com",

704 authorization: "$STRIPE_OAUTH_ACCESS_TOKEN"715 authorization: "$STRIPE_OAUTH_ACCESS_TOKEN",

705 }716 },

706 ]717 ],

707});718});

708 719 

709console.log(resp.output_text);720console.log(resp.output_text);

Details

19 19 

20const response = await openai.responses.create({20const response = await openai.responses.create({

21 model: "gpt-5.6",21 model: "gpt-5.6",

22 input: "Generate an image of gray tabby cat hugging an otter with an orange scarf",22 input:

23 tools: [{type: "image_generation"}],23 "Generate an image of gray tabby cat hugging an otter with an orange scarf",

24 tools: [{ type: "image_generation" }],

24});25});

25 26 

26// Save the image to a file27// Save the image to a file

Details

231 get_demand: async ({ sku }) => ({ sku, requested_units: 31 }),231 get_demand: async ({ sku }) => ({ sku, requested_units: 31 }),

232};232};

233 233 

234/** @type {OpenAI.Responses.Tool[]} */

234const tools = [235const tools = [

235 {236 {

236 type: "function",237 type: "function",


253 additionalProperties: false,254 additionalProperties: false,

254 },255 },

255 allowed_callers: ["programmatic"],256 allowed_callers: ["programmatic"],

257 strict: true,

256 },258 },

257 {259 {

258 type: "function",260 type: "function",


275 additionalProperties: false,277 additionalProperties: false,

276 },278 },

277 allowed_callers: ["programmatic"],279 allowed_callers: ["programmatic"],

280 strict: true,

278 },281 },

279 { type: "programmatic_tool_calling" },282 { type: "programmatic_tool_calling" },

280];283];

281 284 

285/** @type {OpenAI.Responses.ResponseInput} */

282const input = [286const input = [

283 {287 {

284 role: "user",288 role: "user",


301 // Preserve every output item, including program and reasoning items.305 // Preserve every output item, including program and reasoning items.

302 input.push(...response.output);306 input.push(...response.output);

303 307 

304 const calls = response.output.filter(308 const calls = response.output.filter((item) => item.type === "function_call");

305 (item) => item.type === "function_call",

306 );

307 309 

308 if (calls.length === 0) {310 if (calls.length === 0) {

309 const message = response.output.find((item) => item.type === "message");311 const message = response.output.find((item) => item.type === "message");


321 if (!run) throw new Error(`Unknown tool: ${call.name}`);323 if (!run) throw new Error(`Unknown tool: ${call.name}`);

322 324 

323 const result = await run(JSON.parse(call.arguments));325 const result = await run(JSON.parse(call.arguments));

324 return {326 return /** @type {const} */ ({

325 type: "function_call_output",327 type: "function_call_output",

326 call_id: call.call_id,328 call_id: call.call_id,

327 output: JSON.stringify(result),329 output: JSON.stringify(result),

328 // Preserve caller so the runtime can resume the correct program.330 // Preserve caller so the runtime can resume the correct program.

329 caller: call.caller,331 caller: call.caller,

330 };332 });

331 }),333 })

332 );334 );

333 335 

334 input.push(...outputs);336 input.push(...outputs);

Details

259const container = await client.containers.create({259const container = await client.containers.create({

260 name: "skill-container",260 name: "skill-container",

261 skills: [261 skills: [

262 { type: "skill_reference", skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f" },262 {

263 { type: "skill_reference", skill_id: "openai-spreadsheets", version: "latest" },263 type: "skill_reference",

264 skill_id: "skill_4db6f1a2c9e73508b41f9da06e2c7b5f",

265 },

266 {

267 type: "skill_reference",

268 skill_id: "openai-spreadsheets",

269 version: "latest",

270 },

264 ],271 ],

265});272});

266 273 


480 487 

481const client = new OpenAI();488const client = new OpenAI();

482 489 

483const inlineZip = fs.readFileSync("csv_insights.zip").toString("base64");490const inlineZip = fs

484const reportCsv = fs.readFileSync("report.csv").toString("base64");491 .readFileSync("fixtures/csv_insights.zip")

492 .toString("base64");

493const reportCsv = fs.readFileSync("fixtures/report.csv").toString("base64");

485 494 

486const container = await client.containers.create({495const container = await client.containers.create({

487 name: "inline-skill-container",496 name: "inline-skill-container",


792 801 

793const response = await client.responses.create({802const response = await client.responses.create({

794 model: "gpt-5.6",803 model: "gpt-5.6",

795 previous_response_id: "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",804 previous_response_id:

805 "resp_2a8e5c9174d63b0f18a4c572de9f64a1b3c76d508e12f9ab47",

796 tools: [806 tools: [

797 {807 {

798 type: "shell",808 type: "shell",


945```955```

946 956 

947```javascript957```javascript

948import { exec } from "node:child_process/promises";958import { exec as execCallback } from "node:child_process";

959import { promisify } from "node:util";

960 

961const exec = promisify(execCallback);

949 962 

950class ShellExecutor {963class ShellExecutor {

951 constructor(defaultTimeoutMs = 60_000) {964 constructor(defaultTimeoutMs = 60_000) {


960 return { stdout, stderr, exitCode: 0, timedOut: false };973 return { stdout, stderr, exitCode: 0, timedOut: false };

961 } catch (error) {974 } catch (error) {

962 const timedOut = Boolean(error?.killed) && error?.signal === "SIGTERM";975 const timedOut = Boolean(error?.killed) && error?.signal === "SIGTERM";

963 const exitCode = timedOut ? null : error?.code ?? null;976 const exitCode = timedOut ? null : (error?.code ?? null);

964 return {977 return {

965 stdout: error?.stdout ?? "",978 stdout: error?.stdout ?? "",

966 stderr: error?.stderr ?? String(error),979 stderr: error?.stderr ?? String(error),

Details

97 type: "container_auto",97 type: "container_auto",

98 skills: [98 skills: [

99 { type: "skill_reference", skill_id: "<skill_id>" },99 { type: "skill_reference", skill_id: "<skill_id>" },

100 { type: "skill_reference", skill_id: "<skill_id>", version: 2 },100 { type: "skill_reference", skill_id: "<skill_id>", version: "2" },

101 ],101 ],

102 },102 },

103 },103 },

104 ],104 ],

105 input: "Use the skills to add 144 and 377, then compute triangle area with base 9 height 13.",105 input:

106 "Use the skills to add 144 and 377, then compute triangle area with base 9 height 13.",

106});107});

107 108 

108console.log(response.output_text);109console.log(response.output_text);


196 },197 },

197 },198 },

198 ],199 ],

199 input: "Use the csv-insights skill and run locally to summarize today's CSV reports in this repo.",200 input:

201 "Use the csv-insights skill and run locally to summarize today's CSV reports in this repo.",

200});202});

201 203 

202console.log(response.output_text);204console.log(response.output_text);

Details

55 55 

56Create a video56Create a video

57 57 

58```javascript

59import OpenAI from "openai";

60 

61const openai = new OpenAI();

62 

63let video = await openai.videos.create({

64 model: "sora-2",

65 prompt: "A video of the words 'Thank you' in sparkling letters",

66});

67 

68console.log("Video generation started: ", video);

69```

70 

58```python71```python

59from openai import OpenAI72from openai import OpenAI

60 73 


140Poll the status endpoint153Poll the status endpoint

141 154 

142```javascript155```javascript

143import OpenAI from 'openai';156import OpenAI from "openai";

157import { setTimeout as sleep } from "node:timers/promises";

144 158 

145const openai = new OpenAI();159const openai = new OpenAI();

146 160 

147async function main() {161async function main() {

148 const video = await openai.videos.createAndPoll({162 let video = await openai.videos.create({

149 model: 'sora-2',163 model: "sora-2",

150 prompt: "A video of the words 'Thank you' in sparkling letters",164 prompt: "A video of the words 'Thank you' in sparkling letters",

151 });165 });

152 166 

153 if (video.status === 'completed') {167 while (video.status === "queued" || video.status === "in_progress") {

154 console.log('Video successfully completed: ', video);168 await sleep(2000);

169 video = await openai.videos.retrieve(video.id);

170 }

171 

172 if (video.status === "completed") {

173 console.log("Video successfully completed: ", video);

155 } else {174 } else {

156 console.log('Video creation failed. Status: ', video.status);175 console.log("Video creation failed. Status: ", video.status);

157 }176 }

158}177}

159 178 


228Download the MP4247Download the MP4

229 248 

230```javascript249```javascript

231import OpenAI from 'openai';250import { writeFileSync } from "node:fs";

251 

252import OpenAI from "openai";

232 253 

233const openai = new OpenAI();254const openai = new OpenAI();

234 255 

235let video = await openai.videos.create({256let video = await openai.videos.create({

236 model: 'sora-2',257 model: "sora-2",

237 prompt: "A video of the words 'Thank you' in sparkling letters",258 prompt: "A video of the words 'Thank you' in sparkling letters",

238});259});

239 260 

240console.log('Video generation started: ', video);261console.log("Video generation started: ", video);

241let progress = video.progress ?? 0;262let progress = video.progress ?? 0;

242 263 

243while (video.status === 'in_progress' || video.status === 'queued') {264while (video.status === "in_progress" || video.status === "queued") {

244 video = await openai.videos.retrieve(video.id);265 video = await openai.videos.retrieve(video.id);

245 progress = video.progress ?? 0;266 progress = video.progress ?? 0;

246 267 


248 const barLength = 30;269 const barLength = 30;

249 const filledLength = Math.floor((progress / 100) * barLength);270 const filledLength = Math.floor((progress / 100) * barLength);

250 // Simple ASCII progress visualization for terminal output271 // Simple ASCII progress visualization for terminal output

251 const bar = '='.repeat(filledLength) + '-'.repeat(barLength - filledLength);272 const bar = "=".repeat(filledLength) + "-".repeat(barLength - filledLength);

252 const statusText = video.status === 'queued' ? 'Queued' : 'Processing';273 const statusText = video.status === "queued" ? "Queued" : "Processing";

253 274 

254 process.stdout.write(`${statusText}: [${bar}] ${progress.toFixed(1)}%`);275 process.stdout.write(`${statusText}: [${bar}] ${progress.toFixed(1)}%`);

255 276 


257}278}

258 279 

259// Clear the progress line and show completion280// Clear the progress line and show completion

260process.stdout.write('\n');281process.stdout.write("\n");

261 282 

262if (video.status === 'failed') {283if (video.status === "failed") {

263 console.error('Video generation failed');284 throw new Error("Video generation failed");

264 return;

265}285}

266 286 

267console.log('Video generation completed: ', video);287console.log("Video generation completed: ", video);

268 288 

269console.log('Downloading video content...');289console.log("Downloading video content...");

270 290 

271const content = await openai.videos.downloadContent(video.id);291const content = await openai.videos.downloadContent(video.id);

272 292 

273const body = content.arrayBuffer();293const body = content.arrayBuffer();

274const buffer = Buffer.from(await body);294const buffer = Buffer.from(await body);

275 295 

276require('fs').writeFileSync('video.mp4', buffer);296writeFileSync("video.mp4", buffer);

277 297 

278console.log('Wrote video.mp4');298console.log("Wrote video.mp4");

279```299```

280 300 

281```bash301```bash

Details

209```javascript209```javascript

210const client = new OpenAI();210const client = new OpenAI();

211const webhook_secret = process.env.OPENAI_WEBHOOK_SECRET;211const webhook_secret = process.env.OPENAI_WEBHOOK_SECRET;

212if (!webhook_secret) throw new Error("Set OPENAI_WEBHOOK_SECRET.");

212 213 

213// will throw if the signature is invalid214// will throw if the signature is invalid

214const event = client.webhooks.unwrap(req.body, req.headers, { secret: webhook_secret });215const event = await client.webhooks.unwrap(

216 req.body,

217 req.headers,

218 webhook_secret

219);

215```220```

216 221 

217 222 

Details

160```typescript160```typescript

161import { GetWebIdentityTokenCommand, STSClient } from "@aws-sdk/client-sts";161import { GetWebIdentityTokenCommand, STSClient } from "@aws-sdk/client-sts";

162import OpenAI from "openai";162import OpenAI from "openai";

163import type { SubjectTokenProvider } from "openai/auth";163import type { SubjectTokenProvider } from "openai/auth/index";

164 164 

165const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;165const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

166const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;166const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;


172 "Set OPENAI_IDENTITY_PROVIDER_ID, OPENAI_SERVICE_ACCOUNT_ID, OPENAI_WIF_AUDIENCE, and AWS_REGION"172 "Set OPENAI_IDENTITY_PROVIDER_ID, OPENAI_SERVICE_ACCOUNT_ID, OPENAI_WIF_AUDIENCE, and AWS_REGION"

173 );173 );

174}174}

175const wifAudience = audience;

175 176 

176const sts = new STSClient({ region: awsRegion });177const sts = new STSClient({ region: awsRegion });

177 178 


181 getToken: async () => {182 getToken: async () => {

182 const response = await sts.send(183 const response = await sts.send(

183 new GetWebIdentityTokenCommand({184 new GetWebIdentityTokenCommand({

184 Audience: [audience],185 Audience: [wifAudience],

185 SigningAlgorithm: "ES384",186 SigningAlgorithm: "ES384",

186 DurationSeconds: 300,187 DurationSeconds: 300,

187 })188 })


644```typescript645```typescript

645import { readFile } from "node:fs/promises";646import { readFile } from "node:fs/promises";

646import OpenAI from "openai";647import OpenAI from "openai";

647import type { SubjectTokenProvider } from "openai/auth";648import type { SubjectTokenProvider } from "openai/auth/index";

648 649 

649const tokenPath = "/var/run/secrets/tokens/token";650const tokenPath = "/var/run/secrets/tokens/token";

650const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;651const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

651const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;652const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

652 653 

653if (!identityProviderId || !serviceAccountId) {654if (!identityProviderId || !serviceAccountId) {

654 throw new Error("Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID");655 throw new Error(

656 "Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID"

657 );

655}658}

656 659 

657function mountedEksServiceAccountTokenProvider(path: string): SubjectTokenProvider {660function mountedEksServiceAccountTokenProvider(

661 path: string

662): SubjectTokenProvider {

658 return {663 return {

659 tokenType: "jwt",664 tokenType: "jwt",

660 getToken: async () => {665 getToken: async () => {

Details

163 163 

164```typescript164```typescript

165import OpenAI from "openai";165import OpenAI from "openai";

166import type { SubjectTokenProvider } from "openai/auth";166import type { SubjectTokenProvider } from "openai/auth/index";

167 167 

168const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;168const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

169const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;169const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;


218 workloadIdentity: {218 workloadIdentity: {

219 identityProviderId,219 identityProviderId,

220 serviceAccountId,220 serviceAccountId,

221 provider: githubActionsOIDCTokenProvider(requestURL, requestToken, audience),221 provider: githubActionsOIDCTokenProvider(

222 requestURL,

223 requestToken,

224 audience

225 ),

222 },226 },

223});227});

224 228 

Details

114 114 

115```typescript115```typescript

116import OpenAI from "openai";116import OpenAI from "openai";

117import type { SubjectTokenProvider } from "openai/auth";117import type { SubjectTokenProvider } from "openai/auth/index";

118 118 

119const metadataEndpoint =119const metadataEndpoint =

120 "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity";120 "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity";


129 );129 );

130}130}

131 131 

132function googleMetadataIdentityTokenProvider(audience: string): SubjectTokenProvider {132function googleMetadataIdentityTokenProvider(

133 audience: string

134): SubjectTokenProvider {

133 return {135 return {

134 tokenType: "jwt",136 tokenType: "jwt",

135 getToken: async () => {137 getToken: async () => {


149 151 

150 const token = (await response.text()).trim();152 const token = (await response.text()).trim();

151 if (!token) {153 if (!token) {

152 throw new Error("Google metadata server did not return an identity token.");154 throw new Error(

155 "Google metadata server did not return an identity token."

156 );

153 }157 }

154 158 

155 return token;159 return token;


665```typescript669```typescript

666import { readFile } from "node:fs/promises";670import { readFile } from "node:fs/promises";

667import OpenAI from "openai";671import OpenAI from "openai";

668import type { SubjectTokenProvider } from "openai/auth";672import type { SubjectTokenProvider } from "openai/auth/index";

669 673 

670const tokenPath = "/var/run/secrets/tokens/token";674const tokenPath = "/var/run/secrets/tokens/token";

671const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;675const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

672const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;676const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

673 677 

674if (!identityProviderId || !serviceAccountId) {678if (!identityProviderId || !serviceAccountId) {

675 throw new Error("Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID");679 throw new Error(

680 "Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID"

681 );

676}682}

677 683 

678function mountedGkeServiceAccountTokenProvider(path: string): SubjectTokenProvider {684function mountedGkeServiceAccountTokenProvider(

685 path: string

686): SubjectTokenProvider {

679 return {687 return {

680 tokenType: "jwt",688 tokenType: "jwt",

681 getToken: async () => {689 getToken: async () => {

Details

137```typescript137```typescript

138import { readFile } from "node:fs/promises";138import { readFile } from "node:fs/promises";

139import OpenAI from "openai";139import OpenAI from "openai";

140import type { SubjectTokenProvider } from "openai/auth";140import type { SubjectTokenProvider } from "openai/auth/index";

141 141 

142const tokenPath = "/var/run/secrets/tokens/token";142const tokenPath = "/var/run/secrets/tokens/token";

143const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;143const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

144const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;144const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

145 145 

146if (!identityProviderId || !serviceAccountId) {146if (!identityProviderId || !serviceAccountId) {

147 throw new Error("Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID");147 throw new Error(

148 "Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID"

149 );

148}150}

149 151 

150function mountedServiceAccountTokenProvider(path: string): SubjectTokenProvider {152function mountedServiceAccountTokenProvider(

153 path: string

154): SubjectTokenProvider {

151 return {155 return {

152 tokenType: "jwt",156 tokenType: "jwt",

153 getToken: async () => {157 getToken: async () => {

Details

120 120 

121```typescript121```typescript

122import OpenAI from "openai";122import OpenAI from "openai";

123import type { SubjectTokenProvider } from "openai/auth";123import type { SubjectTokenProvider } from "openai/auth/index";

124 124 

125const imdsEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token";125const imdsEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token";

126 126 


134 );134 );

135}135}

136 136 

137function azureManagedIdentityTokenProvider(resource: string): SubjectTokenProvider {137function azureManagedIdentityTokenProvider(

138 resource: string

139): SubjectTokenProvider {

138 return {140 return {

139 tokenType: "jwt",141 tokenType: "jwt",

140 getToken: async () => {142 getToken: async () => {


703```typescript705```typescript

704import { readFile } from "node:fs/promises";706import { readFile } from "node:fs/promises";

705import OpenAI from "openai";707import OpenAI from "openai";

706import type { SubjectTokenProvider } from "openai/auth";708import type { SubjectTokenProvider } from "openai/auth/index";

707 709 

708const tokenPath = "/var/run/secrets/tokens/token";710const tokenPath = "/var/run/secrets/tokens/token";

709const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;711const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

710const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;712const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

711 713 

712if (!identityProviderId || !serviceAccountId) {714if (!identityProviderId || !serviceAccountId) {

713 throw new Error("Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID");715 throw new Error(

716 "Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID"

717 );

714}718}

715 719 

716function mountedAksServiceAccountTokenProvider(path: string): SubjectTokenProvider {720function mountedAksServiceAccountTokenProvider(

721 path: string

722): SubjectTokenProvider {

717 return {723 return {

718 tokenType: "jwt",724 tokenType: "jwt",

719 getToken: async () => {725 getToken: async () => {

Details

166```typescript166```typescript

167import { readFile } from "node:fs/promises";167import { readFile } from "node:fs/promises";

168import OpenAI from "openai";168import OpenAI from "openai";

169import type { SubjectTokenProvider } from "openai/auth";169import type { SubjectTokenProvider } from "openai/auth/index";

170 170 

171const tokenPath = "/var/run/spiffe/openai.jwt";171const tokenPath = "/var/run/spiffe/openai.jwt";

172const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;172const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;

173const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;173const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

174 174 

175if (!identityProviderId || !serviceAccountId) {175if (!identityProviderId || !serviceAccountId) {

176 throw new Error("Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID");176 throw new Error(

177 "Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID"

178 );

177}179}

178 180 

179function spiffeJwtSvidProvider(path: string): SubjectTokenProvider {181function spiffeJwtSvidProvider(path: string): SubjectTokenProvider {

quickstart.md +19 −16

Details

162 },162 },

163 {163 {

164 type: "input_image",164 type: "input_image",

165 image_url: "https://openai-documentation.vercel.app/images/cat_and_otter.png",165 image_url:

166 "https://openai-documentation.vercel.app/images/cat_and_otter.png",

167 detail: "auto",

166 },168 },

167 ],169 ],

168 },170 },


450const client = new OpenAI();452const client = new OpenAI();

451 453 

452const file = await client.files.create({454const file = await client.files.create({

453 file: fs.createReadStream("draconomicon.pdf"),455 file: fs.createReadStream("fixtures/draconomicon.pdf"),

454 purpose: "user_data",456 purpose: "user_data",

455});457});

456 458 


589 591 

590const response = await client.responses.create({592const response = await client.responses.create({

591 model: "gpt-5.6",593 model: "gpt-5.6",

592 tools: [594 tools: [{ type: "web_search" }],

593 { type: "web_search" },

594 ],

595 input: "What was a positive news story from today?",595 input: "What was a positive news story from today?",

596});596});

597 597 


750 750 

751const response = await client.responses.create({751const response = await client.responses.create({

752 model: "gpt-5.6",752 model: "gpt-5.6",

753 instructions: "You are a personal math tutor. When asked a math question, write and run code to answer the question.",753 instructions:

754 "You are a personal math tutor. When asked a math question, write and run code to answer the question.",

754 tools: [755 tools: [

755 {756 {

756 type: "code_interpreter",757 type: "code_interpreter",


826import OpenAI from "openai";827import OpenAI from "openai";

827const client = new OpenAI();828const client = new OpenAI();

828 829 

830/** @type {OpenAI.Responses.Tool[]} */

829const tools = [831const tools = [

830 {832 {

831 type: "function",833 type: "function",


854 tools,856 tools,

855});857});

856 858 

857console.log(response.output[0].to_json());859console.log(response.output[0]);

858```860```

859 861 

860```python862```python


1032 {1034 {

1033 type: "mcp",1035 type: "mcp",

1034 server_label: "dmcp",1036 server_label: "dmcp",

1035 server_description: "A Dungeons and Dragons MCP server to assist with dice rolling.",1037 server_description:

1038 "A Dungeons and Dragons MCP server to assist with dice rolling.",

1036 server_url: "https://dmcp-server.deno.dev/mcp",1039 server_url: "https://dmcp-server.deno.dev/mcp",

1037 require_approval: "never",1040 require_approval: "never",

1038 },1041 },


1239Build a language triage agent1242Build a language triage agent

1240 1243 

1241```javascript1244```javascript

1242import { Agent, run } from '@openai/agents';1245import { Agent, run } from "@openai/agents";

1243 1246 

1244const spanishAgent = new Agent({1247const spanishAgent = new Agent({

1245 name: 'Spanish agent',1248 name: "Spanish agent",

1246 instructions: 'You only speak Spanish.',1249 instructions: "You only speak Spanish.",

1247});1250});

1248 1251 

1249const englishAgent = new Agent({1252const englishAgent = new Agent({

1250 name: 'English agent',1253 name: "English agent",

1251 instructions: 'You only speak English',1254 instructions: "You only speak English",

1252});1255});

1253 1256 

1254const triageAgent = new Agent({1257const triageAgent = new Agent({

1255 name: 'Triage agent',1258 name: "Triage agent",

1256 instructions:1259 instructions:

1257 'Handoff to the appropriate agent based on the language of the request.',1260 "Handoff to the appropriate agent based on the language of the request.",

1258 handoffs: [spanishAgent, englishAgent],1261 handoffs: [spanishAgent, englishAgent],

1259});1262});

1260 1263 

1261const result = await run(triageAgent, 'Hola, ¿cómo estás?');1264const result = await run(triageAgent, "Hola, ¿cómo estás?");

1262console.log(result.finalOutput);1265console.log(result.finalOutput);

1263```1266```

1264 1267