OpenAI
Factories for the OpenAI Responses API and the OpenAI Agents SDK - same eight operations, Zod-validated, approval-gated by default.
The files-sdk/openai subpath ships two factories targeting OpenAI directly - one for the native Responses API and one for the OpenAI Agents SDK (@openai/agents). Both wrap the same eight file operations as the Vercel subpath, with the same approval-gating defaults.
openai and @openai/agents are optional peer dependencies - install only the one(s) you use. The subpath requires Zod 4: @openai/agents peer-requires it, and Zod 4’s built-in toJSONSchema powers the Responses tool definitions.
Responses API
createResponsesFileTools returns { definitions, execute, needsApproval }. Pass definitions straight to openai.responses.create({ tools }), then call execute(call) on each function_call item in the response output to get a function_call_output ready to push into the next turn’s input.
npm install openai zodpnpm add openai zodyarn add openai zodbun add openai zodnub add openai zodaube add openai zodimport OpenAI from "openai";
import { Files } from "files-sdk";
import { s3 } from "files-sdk/s3";
import { createResponsesFileTools } from "files-sdk/openai";
const client = new OpenAI();
const files = new Files({ adapter: s3({ bucket: "uploads" }) });
const ft = createResponsesFileTools({ files });
const input: any[] = [{ role: "user", content: "List my files." }];
while (true) {
const res = await client.responses.create({
model: "gpt-4.1",
input,
tools: ft.definitions,
});
const calls = res.output.filter((o) => o.type === "function_call");
if (calls.length === 0) {
console.log(res.output_text);
break;
}
for (const call of calls) {
let approved = false;
if (ft.needsApproval(call.name)) {
// surface approval UX for this exact call
approved = true;
}
input.push(call, await ft.execute(call, { approved }));
}
}
execute returns JSON parse failures, Zod validation errors, and unapproved write attempts as the tool’s output, so the model can self-correct on the next turn. For write tools whose needsApproval(name) is true, call execute(call, { approved: true }) only after your approval UX approves that exact function call. FilesError from the underlying SDK is rethrown - you decide how to surface it.
Agents SDK
createAgentsFileTools returns a record of tool() outputs keyed by tool name - spread Object.values() into new Agent({ tools }). Write tools default to needsApproval: true; the Agents SDK runner surfaces an interruption that your program resolves by approving or rejecting the call.
npm install @openai/agents zodpnpm add @openai/agents zodyarn add @openai/agents zodbun add @openai/agents zodnub add @openai/agents zodaube add @openai/agents zodimport { Agent, run } from "@openai/agents";
import { Files } from "files-sdk";
import { s3 } from "files-sdk/s3";
import { createAgentsFileTools } from "files-sdk/openai";
const files = new Files({ adapter: s3({ bucket: "uploads" }) });
const tools = createAgentsFileTools({ files });
const agent = new Agent({
instructions: "Help the user manage their files.",
name: "Files agent",
tools: Object.values(tools),
});
const result = await run(agent, "List my files.");
The Agents SDK runs Zod-typed tools in OpenAI strict mode, so each tool’s parameter schema is strict-valid: optional arguments are sent as null and read as absent, and uploadFile takes no metadata argument (strict mode can’t express a free-form map). Attach metadata from your own code, or use the Responses factory without strict, if the model needs to set it.
Errors thrown from execute() are wrapped by the Agents SDK’s default errorFunction into a model-visible string - the model sees the message and can self-correct on the next turn. This is the standard Agents-SDK pattern, and differs from the Responses flow where FilesError rethrows.
Approval, read-only, overrides
Both factories accept the same options shape as the Vercel createFileTools: requireApproval (boolean or per-tool record), readOnly (strips writes entirely), and overrides (description, plus strict for Responses or needsApproval for Agents).
Setting strict: true on a Responses tool reshapes its parameters to what OpenAI strict mode accepts: every property is listed in required, optional ones become nullable (execute treats null as “absent”), and free-form maps are dropped, so uploadFile has no metadata field under strict mode.
// Same shape across both factories.
createResponsesFileTools({ files }); // all writes gated (default)
createResponsesFileTools({ files, requireApproval: false }); // disabled
createResponsesFileTools({
files,
requireApproval: { deleteFile: true, uploadFile: false },
});
createAgentsFileTools({ files, readOnly: true });
// → only listFiles, getFileMetadata, downloadFile, getFileUrl