From 62c1fe5fb4b30f798c4086d34aa720c4614b0dbd Mon Sep 17 00:00:00 2001 From: "openai-sdks[bot]" <284451331+openai-sdks[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 17:35:40 +0000 Subject: [PATCH 1/9] release: 3.21.0 (#3987) Automated Release PR --- ## [3.21.0](https://github.com/openai/openai-python/compare/v3.20.0...v3.21.0) (2026-09-29) ### Features * **api:** add GPT-6.1 Sol model identifier ([#3986](https://github.com/openai/openai-python/issues/3986)) ([160b2c0](https://github.com/openai/openai-python/commit/160b2c0230b9afac15862dcdf8a764e5bae18eb3)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: openai-sdks[bot] <284451331+openai-sdks[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- uv.lock | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d11c8fc3a0..eba8a04955 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.20.0" + ".": "3.21.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 478a8f81b9..7e34678b8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [3.21.0](https://github.com/openai/openai-python/compare/v3.20.0...v3.21.0) (2026-09-29) + + +### Features + +* **api:** add GPT-6.1 Sol model identifier ([#3986](https://github.com/openai/openai-python/issues/3986)) ([160b2c0](https://github.com/openai/openai-python/commit/160b2c0230b9afac15862dcdf8a764e5bae18eb3)) + ## [3.20.0](https://github.com/openai/openai-python/compare/v3.19.2...v3.20.0) (2026-09-28) diff --git a/pyproject.toml b/pyproject.toml index 8d5cca8ac9..206ba3fca2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "3.20.0" +version = "3.21.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_version.py b/src/openai/_version.py index cf3e8564f3..1a557a7cc8 100644 --- a/src/openai/_version.py +++ b/src/openai/_version.py @@ -1,2 +1,2 @@ __title__ = "openai" -__version__ = "3.20.0" # x-release-please-version +__version__ = "3.21.0" # x-release-please-version diff --git a/uv.lock b/uv.lock index 9e256efd0d..46770cb264 100644 --- a/uv.lock +++ b/uv.lock @@ -1535,7 +1535,7 @@ wheels = [ [[package]] name = "openai" -version = "3.20.0" # x-release-please-version +version = "3.21.0" # x-release-please-version source = { editable = "." } dependencies = [ { name = "anyio" }, From f5dddb5a199f899d9439ac3187c9c0f2d3e4082e Mon Sep 17 00:00:00 2001 From: Marcus Wood Date: Tue, 29 Sep 2026 18:45:39 +0000 Subject: [PATCH 2/9] feat(api): add computer use to beta agents (#3989) ## Summary Adds typed computer-use tools, approval responses, screenshots, and desktop settings to beta.agents. ## Changes - Support computer_use tools and optional screenshots. - Add browser authentication and origin-access approval inputs and required actions. - Expose computer-use calls and credential-free approval history. - Add desktop settings for hosted environments and environment templates. Co-authored-by: marcuswood-oai <323319819+marcuswood-oai@users.noreply.github.com> --- .castiron.stats.yml | 14 +- api.md | 3 + api_reference/openapi.transformed.yml | 706 +++++++++++++++++- .../beta/agents/environments/templates.py | 18 + src/openai/types/beta/__init__.py | 16 + ...ent_browser_authentication_cancel_param.py | 13 + ...owser_authentication_cancel_param_param.py | 13 + ...ent_browser_authentication_submit_param.py | 34 + ...owser_authentication_submit_param_param.py | 34 + .../beta/agent_browser_origin_access_param.py | 19 + ...agent_browser_origin_access_param_param.py | 19 + src/openai/types/beta/agent_output_item.py | 122 ++- src/openai/types/beta/agent_session.py | 105 +++ .../types/beta/agent_session_input_param.py | 28 + src/openai/types/beta/agent_session_item.py | 168 ++++- src/openai/types/beta/agent_tool.py | 12 + src/openai/types/beta/agent_tool_param.py | 12 + .../environments/environment_template.py | 13 +- .../environments/template_create_params.py | 27 +- .../environments/template_update_params.py | 21 +- src/openai/types/beta/environment.py | 15 +- src/openai/types/beta/environment_param.py | 26 +- src/openai/types/beta/persisted_agent_tool.py | 12 + .../types/beta/persisted_agent_tool_param.py | 12 + tests/api_resources/audio/test_speech.py | 16 +- .../agents/environments/test_templates.py | 8 + .../beta/agents/sessions/test_events.py | 244 +++--- 27 files changed, 1579 insertions(+), 151 deletions(-) create mode 100644 src/openai/types/beta/agent_browser_authentication_cancel_param.py create mode 100644 src/openai/types/beta/agent_browser_authentication_cancel_param_param.py create mode 100644 src/openai/types/beta/agent_browser_authentication_submit_param.py create mode 100644 src/openai/types/beta/agent_browser_authentication_submit_param_param.py create mode 100644 src/openai/types/beta/agent_browser_origin_access_param.py create mode 100644 src/openai/types/beta/agent_browser_origin_access_param_param.py diff --git a/.castiron.stats.yml b/.castiron.stats.yml index 006b022221..800f02fe05 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,8 +1,8 @@ schema_version: 1 -generation_id: 0aa9ce13-d80a-4a74-a5a3-a64c06d396bd -openapi_spec_hash: ef23be781aae82cc4aaf121dc1e23c90 -openapi_transformed_spec_hash: 6c58c6858bf78f94b91d1095df3b4523 -config_hash: 38c35bf82be025557d8a7dc727060f2f -codegen_sha: 696f896d9c4820f2118a6b7bd3cba58172677ec1 -codegen_hash: f34dc0b8de3f49538501f94020eae54bbeaf5d813f0af4d4c4d03236d83d57e2 -public_codegen_sha: 20af1d8d59806c56dd7e866ae4cc018d92768a9e +generation_id: 7151c90a-4825-4a4f-b9b1-9e268a95134d +openapi_spec_hash: 982e032cd9bc8921825601fbb36a8a92 +openapi_transformed_spec_hash: 7554bcd8a14262861882411fc4426386 +config_hash: ac46b7ace0a09008785717fbff2f1d19 +codegen_sha: 591413c2ff7e011ff70f92ab58d9a8a4917818ac +codegen_hash: 69df1931f3258b1a5ff25728ac96053783f52b1c94eb5d1c190a520ed699faac +public_codegen_sha: 2fb2f98ab0d132294487c886ebda89a479b41e2e diff --git a/api.md b/api.md index 74b2276e7f..8a4b3d8b03 100644 --- a/api.md +++ b/api.md @@ -491,6 +491,9 @@ Types: ```python from openai.types.beta import ( Agent, + AgentBrowserAuthenticationCancelParam, + AgentBrowserAuthenticationSubmitParam, + AgentBrowserOriginAccessParam, AgentCloseSubagentCallItem, AgentCommandExecutionItem, AgentContent, diff --git a/api_reference/openapi.transformed.yml b/api_reference/openapi.transformed.yml index 73540a551f..4073792f46 100644 --- a/api_reference/openapi.transformed.yml +++ b/api_reference/openapi.transformed.yml @@ -80301,6 +80301,9 @@ components: resume_subagent_call: '#/components/schemas/ResumeSubagentCallItemResource' wait_for_subagents_call: '#/components/schemas/WaitForSubagentsCallItemResource' close_subagent_call: '#/components/schemas/CloseSubagentCallItemResource' + computer_use_approval_request: '#/components/schemas/BrowserAuthenticationRequestItemResource' + computer_use_approval_request_result: '#/components/schemas/ComputerUseApprovalRequestResultItemResource' + computer_use_call: '#/components/schemas/ComputerUseCallItemResource' x-oai-discriminator-values: - message - reasoning @@ -80308,6 +80311,9 @@ components: - function_call_output - agent_message - mcp_call + - computer_use_call + - computer_use_approval_request + - computer_use_approval_request_result - web_search_call - command_execution - create_subagent_call @@ -80323,6 +80329,9 @@ components: - $ref: '#/components/schemas/FunctionCallOutputItemResource' - $ref: '#/components/schemas/AgentMessageItemResource' - $ref: '#/components/schemas/McpCallItemResource' + - $ref: '#/components/schemas/ComputerUseCallItemResource' + - $ref: '#/components/schemas/BrowserAuthenticationRequestItemResource' + - $ref: '#/components/schemas/ComputerUseApprovalRequestResultItemResource' - $ref: '#/components/schemas/WebSearchCallItemResource' - $ref: '#/components/schemas/CommandExecutionItemResource' - $ref: '#/components/schemas/CreateSubagentCallItemResource' @@ -81045,18 +81054,21 @@ components: programmatic_tool_calling: '#/components/schemas/PersistedAgentToolResourceProgrammaticToolCalling' mcp: '#/components/schemas/PersistedAgentToolResourceMcp' web_search: '#/components/schemas/PersistedAgentToolResourceWebSearch' + computer_use: '#/components/schemas/PersistedAgentToolResourceComputerUse' x-oai-discriminator-values: - function - tool_search - programmatic_tool_calling - mcp - web_search + - computer_use anyOf: - $ref: '#/components/schemas/PersistedAgentToolResourceFunction' - $ref: '#/components/schemas/PersistedAgentToolResourceToolSearch' - $ref: '#/components/schemas/PersistedAgentToolResourceProgrammaticToolCalling' - $ref: '#/components/schemas/PersistedAgentToolResourceMcp' - $ref: '#/components/schemas/PersistedAgentToolResourceWebSearch' + - $ref: '#/components/schemas/PersistedAgentToolResourceComputerUse' MultiAgentConfigResource: type: object properties: @@ -81673,18 +81685,21 @@ components: programmatic_tool_calling: '#/components/schemas/PersistedAgentToolConfigParamProgrammaticToolCalling' mcp: '#/components/schemas/PersistedAgentToolConfigParamMcp' web_search: '#/components/schemas/PersistedAgentToolConfigParamWebSearch' + computer_use: '#/components/schemas/PersistedAgentToolConfigParamComputerUse' x-oai-discriminator-values: - function - tool_search - programmatic_tool_calling - mcp - web_search + - computer_use anyOf: - $ref: '#/components/schemas/PersistedAgentToolConfigParamFunction' - $ref: '#/components/schemas/PersistedAgentToolConfigParamToolSearch' - $ref: '#/components/schemas/PersistedAgentToolConfigParamProgrammaticToolCalling' - $ref: '#/components/schemas/PersistedAgentToolConfigParamMcp' - $ref: '#/components/schemas/PersistedAgentToolConfigParamWebSearch' + - $ref: '#/components/schemas/PersistedAgentToolConfigParamComputerUse' MultiAgentConfigCurrentParam: type: object properties: @@ -81907,7 +81922,7 @@ components: x-enumDescriptions: - Allows unrestricted network access. - Disables network access. - - Allows access only to configured domains. + - Applies the configured domain restrictions. description: The network access mode for an OpenAI-hosted environment. NetworkPolicyResource: type: object @@ -82116,6 +82131,9 @@ components: minItems: 0 maxItems: 50 description: Safe file metadata, excluding contents and session-scoped file IDs. + desktop: + $ref: '#/components/schemas/DesktopResource' + description: Desktop configuration for each OpenAI-hosted environment. required: - id - name @@ -82236,7 +82254,7 @@ components: x-enumDescriptions: - Allows unrestricted network access. - Disables network access. - - Allows access only to configured domains. + - Applies the configured domain restrictions. description: The network access mode for an OpenAI-hosted environment. NetworkPolicyParam: type: object @@ -82255,6 +82273,17 @@ components: minItems: 0 maxItems: 16384 description: Domains the environment may access when network access is restricted. + blocked_domains: + type: + - array + - 'null' + items: + type: string + minLength: 0 + maxLength: 1048576 + minItems: 0 + maxItems: 100 + description: 'Domains blocked for both executor and browser when access is restricted. A nonempty list requires `access: restricted` and cannot be combined with nonempty `allowed_domains`. Wildcard domains are not supported.' required: - access additionalProperties: false @@ -82491,6 +82520,11 @@ components: minLength: 1 maxLength: 256 description: An optional human-readable display name for the template. + desktop: + anyOf: + - $ref: '#/components/schemas/DesktopParam' + - type: 'null' + description: Desktop provisioning. Omission or null inherits the template setting, or defaults to disabled. additionalProperties: false description: Parameters for creating a reusable, project-scoped OpenAI-hosted environment template. UpdateEnvironmentTemplateParams: @@ -82575,6 +82609,11 @@ components: minItems: 0 maxItems: 50 description: Replacement file configuration materialized for each new session. + desktop: + anyOf: + - $ref: '#/components/schemas/DesktopParam' + - type: 'null' + description: Replacement desktop configuration, or null to disable the desktop. additionalProperties: false description: Fields to replace on an existing reusable OpenAI-hosted environment template. DeletedEnvironmentTemplateResource: @@ -82671,10 +82710,13 @@ components: mapping: function_call: '#/components/schemas/SessionRequiredActionResourceFunctionCall' environment_connection: '#/components/schemas/SessionRequiredActionResourceEnvironmentConnection' + computer_use_approval_request: '#/components/schemas/SessionRequiredActionResourceComputerUseApprovalRequest' x-oai-discriminator-values: + - computer_use_approval_request - function_call - environment_connection anyOf: + - $ref: '#/components/schemas/SessionRequiredActionResourceComputerUseApprovalRequest' - $ref: '#/components/schemas/SessionRequiredActionResourceFunctionCall' - $ref: '#/components/schemas/SessionRequiredActionResourceEnvironmentConnection' AgentToolResourceFunction: @@ -82912,16 +82954,19 @@ components: programmatic_tool_calling: '#/components/schemas/AgentToolResourceProgrammaticToolCalling' mcp: '#/components/schemas/AgentToolResourceMcp' web_search: '#/components/schemas/AgentToolResourceWebSearch' + computer_use: '#/components/schemas/AgentToolResourceComputerUse' x-oai-discriminator-values: - function - programmatic_tool_calling - mcp - web_search + - computer_use anyOf: - $ref: '#/components/schemas/AgentToolResourceFunction' - $ref: '#/components/schemas/AgentToolResourceProgrammaticToolCalling' - $ref: '#/components/schemas/AgentToolResourceMcp' - $ref: '#/components/schemas/AgentToolResourceWebSearch' + - $ref: '#/components/schemas/AgentToolResourceComputerUse' SessionAgentResource: type: object properties: @@ -83039,6 +83084,9 @@ components: minItems: 0 maxItems: 50 description: Files available in the environment, excluding their contents. + desktop: + $ref: '#/components/schemas/DesktopResource' + description: The effective desktop configuration. required: - type - id @@ -83530,18 +83578,21 @@ components: programmatic_tool_calling: '#/components/schemas/AgentToolConfigParamProgrammaticToolCalling' mcp: '#/components/schemas/AgentToolConfigParamMcp' web_search: '#/components/schemas/AgentToolConfigParamWebSearch' + computer_use: '#/components/schemas/AgentToolConfigParamComputerUse' x-oai-discriminator-values: - function - tool_search - programmatic_tool_calling - mcp - web_search + - computer_use anyOf: - $ref: '#/components/schemas/AgentToolConfigParamFunction' - $ref: '#/components/schemas/AgentToolConfigParamToolSearch' - $ref: '#/components/schemas/AgentToolConfigParamProgrammaticToolCalling' - $ref: '#/components/schemas/AgentToolConfigParamMcp' - $ref: '#/components/schemas/AgentToolConfigParamWebSearch' + - $ref: '#/components/schemas/AgentToolConfigParamComputerUse' SessionAgentConfigParam: type: object properties: @@ -83689,6 +83740,11 @@ components: minLength: 0 maxLength: 64 description: A reusable hosted template applied before inline session configuration. Omitted fields inherit the template; network overrides cannot broaden its policy. + desktop: + anyOf: + - $ref: '#/components/schemas/DesktopParam' + - type: 'null' + description: Desktop provisioning. Omission or null inherits the template setting, or defaults to disabled. required: - type additionalProperties: false @@ -84759,11 +84815,15 @@ components: resume_subagent_call: '#/components/schemas/ResumeSubagentCallItemResource' wait_for_subagents_call: '#/components/schemas/WaitForSubagentsCallItemResource' close_subagent_call: '#/components/schemas/CloseSubagentCallItemResource' + computer_use_approval_request: '#/components/schemas/BrowserAuthenticationRequestItemResource' + computer_use_call: '#/components/schemas/ComputerUseCallItemResource' x-oai-discriminator-values: - message - reasoning - function_call - mcp_call + - computer_use_call + - computer_use_approval_request - web_search_call - command_execution - create_subagent_call @@ -84777,6 +84837,8 @@ components: - $ref: '#/components/schemas/ReasoningItemResource' - $ref: '#/components/schemas/FunctionCallItemResource' - $ref: '#/components/schemas/McpCallItemResource' + - $ref: '#/components/schemas/ComputerUseCallItemResource' + - $ref: '#/components/schemas/BrowserAuthenticationRequestItemResource' - $ref: '#/components/schemas/WebSearchCallItemResource' - $ref: '#/components/schemas/CommandExecutionItemResource' - $ref: '#/components/schemas/CreateSubagentCallItemResource' @@ -85659,11 +85721,14 @@ components: agent.session.input.message: '#/components/schemas/SessionInputParamAgentSessionInputMessage' agent.session.input.cancel: '#/components/schemas/SessionInputParamAgentSessionInputCancel' agent.session.input.tool_result: '#/components/schemas/SessionInputParamAgentSessionInputToolResult' + agent.session.input.computer_use_approval_request_result: '#/components/schemas/SessionInputParamAgentSessionInputComputerUseApprovalRequestResult' x-oai-discriminator-values: + - agent.session.input.computer_use_approval_request_result - agent.session.input.message - agent.session.input.cancel - agent.session.input.tool_result anyOf: + - $ref: '#/components/schemas/SessionInputParamAgentSessionInputComputerUseApprovalRequestResult' - $ref: '#/components/schemas/SessionInputParamAgentSessionInputMessage' - $ref: '#/components/schemas/SessionInputParamAgentSessionInputCancel' - $ref: '#/components/schemas/SessionInputParamAgentSessionInputToolResult' @@ -101185,6 +101250,643 @@ components: - $ref: '#/components/schemas/BetaResponseCustomToolCallInputDoneEvent' discriminator: propertyName: type + AgentToolConfigParamComputerUse: + type: object + properties: + type: + type: string + enum: + - computer_use + default: computer_use + x-stainless-const: true + description: The type of the object. Always `computer_use`. + include_screenshots: + type: boolean + default: false + description: Whether computer tool outputs include screenshots. Defaults to `false`. + required: + - type + additionalProperties: false + description: Browser use in an OpenAI-hosted session. + AgentToolResourceComputerUse: + type: object + properties: + type: + type: string + enum: + - computer_use + default: computer_use + x-stainless-const: true + description: The type of the object. Always `computer_use`. + include_screenshots: + type: boolean + description: Whether computer tool outputs include screenshots. + required: + - type + - include_screenshots + additionalProperties: false + description: Browser use in an OpenAI-hosted session. + BrowserAuthenticationFieldResource: + type: object + properties: + id: + type: string + minLength: 0 + description: The field ID to submit as field_id in a fields entry. + label: + type: string + minLength: 0 + description: The label to display beside the control. + type: + type: string + minLength: 0 + description: The rendering type, such as email, password, or text. + required: + type: boolean + description: Whether this control requires a nonempty value. + required: + - id + - label + - type + - required + additionalProperties: false + description: A control in a registered browser-login form. + BrowserAuthenticationFieldValueParam: + type: object + properties: + field_id: + type: string + minLength: 0 + maxLength: 1048576 + description: The field ID from the required action. + value: + type: string + minLength: 0 + maxLength: 16384 + description: The value to enter into the registered control. + required: + - field_id + - value + additionalProperties: false + description: One user-entered value, including non-password fields such as an email address. + BrowserAuthenticationHistoryRequestKindResource: + x-oai-discriminator-values: + - browser_authentication + discriminator: + propertyName: type + mapping: + browser_authentication: '#/components/schemas/BrowserAuthenticationHistoryRequestKindResourceBrowserAuthentication' + anyOf: + - $ref: '#/components/schemas/BrowserAuthenticationHistoryRequestKindResourceBrowserAuthentication' + BrowserAuthenticationHistoryRequestKindResourceBrowserAuthentication: + type: object + properties: + type: + type: string + enum: + - browser_authentication + default: browser_authentication + x-stainless-const: true + description: The type of the object. Always `browser_authentication`. + reason: + type: + - string + - 'null' + minLength: 0 + description: Why the agent needs the user to sign in. + credential_origin: + type: + - string + - 'null' + minLength: 0 + description: The registered form or frame origin where values will be entered. + fields: + type: array + items: + $ref: '#/components/schemas/BrowserAuthenticationFieldResource' + minItems: 0 + maxItems: 2000 + description: Controls to render. All submitted values are sensitive. + options: + type: array + items: + $ref: '#/components/schemas/BrowserAuthenticationOptionResource' + minItems: 0 + maxItems: 2000 + description: Sign-in methods. Empty for a plain form. + required: + - type + - reason + - credential_origin + - fields + - options + additionalProperties: false + description: A registered form awaiting the application's response. + BrowserAuthenticationOptionResource: + type: object + properties: + id: + type: string + minLength: 0 + description: The option ID to submit as selected_option. + label: + type: string + minLength: 0 + description: The method label to display. + field_ids: + type: array + items: + type: string + minLength: 0 + minItems: 0 + maxItems: 2000 + description: IDs from the registered fields that this method accepts. + required: + - id + - label + - field_ids + additionalProperties: false + description: A sign-in method and the fields that belong to it. + BrowserAuthenticationRequestItemResource: + type: object + properties: + turn_id: + type: string + minLength: 0 + request_id: + type: string + minLength: 0 + request: + $ref: '#/components/schemas/BrowserAuthenticationHistoryRequestKindResource' + id: + type: string + minLength: 0 + description: The stable history item ID. + type: + type: string + enum: + - computer_use_approval_request + default: computer_use_approval_request + x-stainless-const: true + description: The item type. Always computer_use_approval_request. + required: + - turn_id + - request_id + - request + - id + - type + additionalProperties: false + description: A credential-free history record of the emitted login request. + BrowserOriginAccessDecisionParam: + type: string + enum: + - approve + - deny + - cancel + x-enumDescriptions: + - Allow the browser to access this origin. + - Deny access to this origin. + - Dismiss this request without approving access. + description: The user's decision for a browser origin access request. + ComputerScreenshotResource: + type: object + properties: + type: + type: string + enum: + - computer_screenshot + default: computer_screenshot + x-stainless-const: true + description: The content type. Always `computer_screenshot`. + image_url: + type: string + minLength: 0 + description: The complete JPEG image as a base64 data URL. + required: + - type + - image_url + additionalProperties: false + description: A browser screenshot emitted by the model during computer use. + ComputerUseApprovalRequestKindResource: + x-oai-discriminator-values: + - browser_authentication + - browser_origin_access + discriminator: + propertyName: type + mapping: + browser_authentication: '#/components/schemas/ComputerUseApprovalRequestKindResourceBrowserAuthentication' + browser_origin_access: '#/components/schemas/ComputerUseApprovalRequestKindResourceBrowserOriginAccess' + anyOf: + - $ref: '#/components/schemas/ComputerUseApprovalRequestKindResourceBrowserAuthentication' + - $ref: '#/components/schemas/ComputerUseApprovalRequestKindResourceBrowserOriginAccess' + ComputerUseApprovalRequestKindResourceBrowserAuthentication: + type: object + properties: + type: + type: string + enum: + - browser_authentication + default: browser_authentication + x-stainless-const: true + description: The type of the object. Always `browser_authentication`. + reason: + type: + - string + - 'null' + minLength: 0 + description: Why the agent needs the user to sign in. + credential_origin: + type: + - string + - 'null' + minLength: 0 + description: The registered form or frame origin where values will be entered. + fields: + type: array + items: + $ref: '#/components/schemas/BrowserAuthenticationFieldResource' + minItems: 0 + maxItems: 2000 + description: Controls to render. All submitted values are sensitive. + options: + type: array + items: + $ref: '#/components/schemas/BrowserAuthenticationOptionResource' + minItems: 0 + maxItems: 2000 + description: Sign-in methods. Empty for a plain form. + required: + - type + - reason + - credential_origin + - fields + - options + additionalProperties: false + description: A registered form awaiting the application's response. + ComputerUseApprovalRequestKindResourceBrowserOriginAccess: + type: object + properties: + type: + type: string + enum: + - browser_origin_access + default: browser_origin_access + x-stainless-const: true + description: The type of the object. Always `browser_origin_access`. + reason: + type: + - string + - 'null' + minLength: 0 + description: The browser's explanation for this request, or null when unavailable. + origin: + type: string + minLength: 0 + description: The origin the browser needs permission to access. + required: + - type + - reason + - origin + additionalProperties: false + description: A browser origin awaiting the application's approval decision. + ComputerUseApprovalRequestResultItemResource: + type: object + properties: + id: + type: string + minLength: 0 + description: The stable history item ID. + type: + type: string + enum: + - computer_use_approval_request_result + default: computer_use_approval_request_result + x-stainless-const: true + turn_id: + type: string + minLength: 0 + description: The ID of the turn that contains this item. + request_id: + type: string + minLength: 0 + description: The registered request answered by this item. + response: + $ref: '#/components/schemas/ComputerUseApprovalResponseKindResource' + description: The admitted response, without submitted credential values. + required: + - id + - type + - turn_id + - request_id + - response + additionalProperties: false + description: A credential-free record of an admitted response, not proof of completion. + ComputerUseApprovalResponseKindResource: + x-oai-discriminator-values: + - submit + - cancel + discriminator: + propertyName: action + mapping: + submit: '#/components/schemas/ComputerUseApprovalResponseKindResourceBrowserAuthenticationSubmitResource' + cancel: '#/components/schemas/ComputerUseApprovalResponseKindResourceBrowserAuthenticationCancelResource' + anyOf: + - $ref: '#/components/schemas/ComputerUseApprovalResponseKindResourceBrowserAuthenticationSubmitResource' + - $ref: '#/components/schemas/ComputerUseApprovalResponseKindResourceBrowserAuthenticationCancelResource' + ComputerUseApprovalResponseKindResourceBrowserAuthenticationCancelResource: + type: object + properties: + type: + type: string + enum: + - browser_authentication + default: browser_authentication + x-stainless-const: true + action: + type: string + enum: + - cancel + default: cancel + x-stainless-const: true + required: + - type + - action + additionalProperties: false + ComputerUseApprovalResponseKindResourceBrowserAuthenticationSubmitResource: + type: object + properties: + type: + type: string + enum: + - browser_authentication + default: browser_authentication + x-stainless-const: true + action: + type: string + enum: + - submit + default: submit + x-stainless-const: true + selected_option: + type: + - string + - 'null' + minLength: 0 + description: The chosen sign-in method, or null when no options were offered. + required: + - type + - action + - selected_option + additionalProperties: false + ComputerUseApprovalResponseParam: + x-oai-discriminator-values: + - browser_authentication + - browser_origin_access + discriminator: + propertyName: type + mapping: + browser_authentication: '#/components/schemas/ComputerUseApprovalResponseParamBrowserAuthentication' + browser_origin_access: '#/components/schemas/ComputerUseApprovalResponseParamBrowserOriginAccessParam' + anyOf: + - $ref: '#/components/schemas/ComputerUseApprovalResponseParamBrowserAuthentication' + - $ref: '#/components/schemas/ComputerUseApprovalResponseParamBrowserOriginAccessParam' + ComputerUseApprovalResponseParamBrowserAuthentication: + required: + - type + discriminator: + propertyName: action + mapping: + submit: '#/components/schemas/ComputerUseApprovalResponseParamBrowserAuthenticationSubmitParam' + cancel: '#/components/schemas/ComputerUseApprovalResponseParamBrowserAuthenticationCancelParam' + x-oai-discriminator-values: + - submit + - cancel + properties: + type: + type: string + enum: + - browser_authentication + anyOf: + - $ref: '#/components/schemas/ComputerUseApprovalResponseParamBrowserAuthenticationSubmitParam' + - $ref: '#/components/schemas/ComputerUseApprovalResponseParamBrowserAuthenticationCancelParam' + ComputerUseApprovalResponseParamBrowserAuthenticationCancelParam: + type: object + properties: + type: + type: string + enum: + - browser_authentication + default: browser_authentication + x-stainless-const: true + action: + type: string + enum: + - cancel + default: cancel + x-stainless-const: true + required: + - type + - action + additionalProperties: false + ComputerUseApprovalResponseParamBrowserAuthenticationSubmitParam: + type: object + properties: + type: + type: string + enum: + - browser_authentication + default: browser_authentication + x-stainless-const: true + action: + type: string + enum: + - submit + default: submit + x-stainless-const: true + fields: + type: array + items: + $ref: '#/components/schemas/BrowserAuthenticationFieldValueParam' + minItems: 0 + maxItems: 6 + description: Values for up to six active fields in the required action. The submitted field-value mapping and selected option must fit within 120 KiB of JSON. + selected_option: + type: + - string + - 'null' + minLength: 0 + maxLength: 1048576 + description: The chosen method. Required when the required action contains options. + required: + - type + - action + - fields + additionalProperties: false + ComputerUseApprovalResponseParamBrowserOriginAccessParam: + type: object + properties: + type: + type: string + enum: + - browser_origin_access + default: browser_origin_access + x-stainless-const: true + decision: + $ref: '#/components/schemas/BrowserOriginAccessDecisionParam' + description: Whether to allow, deny, or cancel the requested origin access. + required: + - type + - decision + additionalProperties: false + ComputerUseCallItemResource: + type: object + properties: + type: + type: string + enum: + - computer_use_call + default: computer_use_call + x-stainless-const: true + description: The item type. Always `computer_use_call`. + id: + type: string + minLength: 0 + description: The ID of the activity item. + turn_id: + type: string + minLength: 0 + description: The ID of the turn that contains this item. + title: + type: + - string + - 'null' + minLength: 0 + description: A model-generated description of the activity, when available. + status: + $ref: '#/components/schemas/FunctionCallStatusResource' + description: The execution status of the activity. + output: + anyOf: + - $ref: '#/components/schemas/ComputerScreenshotResource' + - type: 'null' + description: The last screenshot emitted by the model. Null when screenshot inclusion is disabled or the call emitted no screenshot. + required: + - type + - id + - turn_id + - title + - status + - output + additionalProperties: false + description: One execution of the platform-provided computer-use capability. + DesktopParam: + type: object + properties: + enabled: + type: boolean + description: Whether to provision the desktop and its browser proxy. + required: + - enabled + additionalProperties: false + description: Desktop configuration for an OpenAI-hosted environment. + DesktopResource: + type: object + properties: + enabled: + type: boolean + description: Whether the environment provisions a desktop and browser proxy. + required: + - enabled + additionalProperties: false + description: The effective desktop configuration for an OpenAI-hosted environment. + PersistedAgentToolConfigParamComputerUse: + type: object + properties: + type: + type: string + enum: + - computer_use + default: computer_use + x-stainless-const: true + description: The type of the object. Always `computer_use`. + include_screenshots: + type: boolean + default: false + description: Whether computer tool outputs include screenshots. Defaults to `false`. + required: + - type + additionalProperties: false + description: Browser use in an OpenAI-hosted session. + PersistedAgentToolResourceComputerUse: + type: object + properties: + type: + type: string + enum: + - computer_use + default: computer_use + x-stainless-const: true + description: The type of the object. Always `computer_use`. + include_screenshots: + type: boolean + description: Whether computer tool outputs include screenshots. + required: + - type + - include_screenshots + additionalProperties: false + description: Browser use in an OpenAI-hosted session. + SessionInputParamAgentSessionInputComputerUseApprovalRequestResult: + type: object + properties: + type: + type: string + enum: + - agent.session.input.computer_use_approval_request_result + default: agent.session.input.computer_use_approval_request_result + x-stainless-const: true + description: The type of the object. Always `agent.session.input.computer_use_approval_request_result`. + request_id: + type: string + minLength: 0 + maxLength: 1048576 + description: The registered request ID from the required action. + response: + $ref: '#/components/schemas/ComputerUseApprovalResponseParam' + description: The response for this request type. + required: + - type + - request_id + - response + additionalProperties: false + description: Responds to a pending Computer Use approval request. + SessionRequiredActionResourceComputerUseApprovalRequest: + type: object + properties: + type: + type: string + enum: + - computer_use_approval_request + default: computer_use_approval_request + x-stainless-const: true + description: The type of the object. Always `computer_use_approval_request`. + turn_id: + type: string + minLength: 0 + description: The turn that requested approval. + request_id: + type: string + minLength: 0 + description: The registered request ID to echo when responding. + request: + $ref: '#/components/schemas/ComputerUseApprovalRequestKindResource' + description: The information needed to render the request. + required: + - type + - turn_id + - request_id + - request + additionalProperties: false + description: Respond to a computer-use request. OAuthErrorCode: anyOf: - enum: diff --git a/src/openai/resources/beta/agents/environments/templates.py b/src/openai/resources/beta/agents/environments/templates.py index fa9a2f3eb6..d71fd24309 100644 --- a/src/openai/resources/beta/agents/environments/templates.py +++ b/src/openai/resources/beta/agents/environments/templates.py @@ -50,6 +50,7 @@ def create( self, *, capability_directories: Optional[SequenceNotStr[str]] | Omit = omit, + desktop: Optional[template_create_params.Desktop] | Omit = omit, env: Optional[Dict[str, str]] | Omit = omit, files: Optional[Iterable[HostedEnvironmentFileParam]] | Omit = omit, name: Optional[str] | Omit = omit, @@ -74,6 +75,9 @@ def create( capability_directories: Directories that contain capabilities exposed to the agent. Defaults to an empty list. + desktop: Desktop provisioning. Omission or null inherits the template setting, or + defaults to disabled. + env: Environment variables made available to the agent. files: Files available before the agent starts. Defaults to an empty list. @@ -106,6 +110,7 @@ def create( body=maybe_transform( { "capability_directories": capability_directories, + "desktop": desktop, "env": env, "files": files, "name": name, @@ -177,6 +182,7 @@ def update( environment_template_id: str, *, capability_directories: Optional[SequenceNotStr[str]] | Omit = omit, + desktop: Optional[template_update_params.Desktop] | Omit = omit, env: Optional[Dict[str, str]] | Omit = omit, files: Optional[Iterable[HostedEnvironmentFileParam]] | Omit = omit, name: Optional[str] | Omit = omit, @@ -200,6 +206,8 @@ def update( Args: capability_directories: Directories that expose capabilities to the agent. + desktop: Replacement desktop configuration, or null to disable the desktop. + env: Replacement confidential environment values. files: Replacement file configuration materialized for each new session. @@ -239,6 +247,7 @@ def update( body=maybe_transform( { "capability_directories": capability_directories, + "desktop": desktop, "env": env, "files": files, "name": name, @@ -388,6 +397,7 @@ async def create( self, *, capability_directories: Optional[SequenceNotStr[str]] | Omit = omit, + desktop: Optional[template_create_params.Desktop] | Omit = omit, env: Optional[Dict[str, str]] | Omit = omit, files: Optional[Iterable[HostedEnvironmentFileParam]] | Omit = omit, name: Optional[str] | Omit = omit, @@ -412,6 +422,9 @@ async def create( capability_directories: Directories that contain capabilities exposed to the agent. Defaults to an empty list. + desktop: Desktop provisioning. Omission or null inherits the template setting, or + defaults to disabled. + env: Environment variables made available to the agent. files: Files available before the agent starts. Defaults to an empty list. @@ -444,6 +457,7 @@ async def create( body=await async_maybe_transform( { "capability_directories": capability_directories, + "desktop": desktop, "env": env, "files": files, "name": name, @@ -515,6 +529,7 @@ async def update( environment_template_id: str, *, capability_directories: Optional[SequenceNotStr[str]] | Omit = omit, + desktop: Optional[template_update_params.Desktop] | Omit = omit, env: Optional[Dict[str, str]] | Omit = omit, files: Optional[Iterable[HostedEnvironmentFileParam]] | Omit = omit, name: Optional[str] | Omit = omit, @@ -538,6 +553,8 @@ async def update( Args: capability_directories: Directories that expose capabilities to the agent. + desktop: Replacement desktop configuration, or null to disable the desktop. + env: Replacement confidential environment values. files: Replacement file configuration materialized for each new session. @@ -577,6 +594,7 @@ async def update( body=await async_maybe_transform( { "capability_directories": capability_directories, + "desktop": desktop, "env": env, "files": files, "name": name, diff --git a/src/openai/types/beta/__init__.py b/src/openai/types/beta/__init__.py index dc935b94d0..9d07d05b25 100644 --- a/src/openai/types/beta/__init__.py +++ b/src/openai/types/beta/__init__.py @@ -224,6 +224,7 @@ from .beta_response_input_text_content import BetaResponseInputTextContent as BetaResponseInputTextContent from .beta_response_refusal_done_event import BetaResponseRefusalDoneEvent as BetaResponseRefusalDoneEvent from .beta_response_steer_failed_event import BetaResponseSteerFailedEvent as BetaResponseSteerFailedEvent +from .agent_browser_origin_access_param import AgentBrowserOriginAccessParam as AgentBrowserOriginAccessParam from .agent_session_input_message_param import AgentSessionInputMessageParam as AgentSessionInputMessageParam from .beta_response_container_reference import BetaResponseContainerReference as BetaResponseContainerReference from .beta_response_function_web_search import BetaResponseFunctionWebSearch as BetaResponseFunctionWebSearch @@ -312,6 +313,9 @@ from .beta_response_mcp_call_completed_event import ( BetaResponseMcpCallCompletedEvent as BetaResponseMcpCallCompletedEvent, ) +from .agent_browser_origin_access_param_param import ( + AgentBrowserOriginAccessParamParam as AgentBrowserOriginAccessParamParam, +) from .agent_session_environment_pending_event import ( AgentSessionEnvironmentPendingEvent as AgentSessionEnvironmentPendingEvent, ) @@ -348,6 +352,12 @@ from .beta_response_reasoning_text_delta_event import ( BetaResponseReasoningTextDeltaEvent as BetaResponseReasoningTextDeltaEvent, ) +from .agent_browser_authentication_cancel_param import ( + AgentBrowserAuthenticationCancelParam as AgentBrowserAuthenticationCancelParam, +) +from .agent_browser_authentication_submit_param import ( + AgentBrowserAuthenticationSubmitParam as AgentBrowserAuthenticationSubmitParam, +) from .agent_session_environment_connected_event import ( AgentSessionEnvironmentConnectedEvent as AgentSessionEnvironmentConnectedEvent, ) @@ -474,6 +484,12 @@ from .beta_response_mcp_list_tools_in_progress_event import ( BetaResponseMcpListToolsInProgressEvent as BetaResponseMcpListToolsInProgressEvent, ) +from .agent_browser_authentication_cancel_param_param import ( + AgentBrowserAuthenticationCancelParamParam as AgentBrowserAuthenticationCancelParamParam, +) +from .agent_browser_authentication_submit_param_param import ( + AgentBrowserAuthenticationSubmitParamParam as AgentBrowserAuthenticationSubmitParamParam, +) from .beta_response_custom_tool_call_input_done_event import ( BetaResponseCustomToolCallInputDoneEvent as BetaResponseCustomToolCallInputDoneEvent, ) diff --git a/src/openai/types/beta/agent_browser_authentication_cancel_param.py b/src/openai/types/beta/agent_browser_authentication_cancel_param.py new file mode 100644 index 0000000000..e9e389b38d --- /dev/null +++ b/src/openai/types/beta/agent_browser_authentication_cancel_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AgentBrowserAuthenticationCancelParam"] + + +class AgentBrowserAuthenticationCancelParam(TypedDict, total=False): + action: Required[Literal["cancel"]] + + type: Required[Literal["browser_authentication"]] diff --git a/src/openai/types/beta/agent_browser_authentication_cancel_param_param.py b/src/openai/types/beta/agent_browser_authentication_cancel_param_param.py new file mode 100644 index 0000000000..704c757130 --- /dev/null +++ b/src/openai/types/beta/agent_browser_authentication_cancel_param_param.py @@ -0,0 +1,13 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AgentBrowserAuthenticationCancelParamParam"] + + +class AgentBrowserAuthenticationCancelParamParam(TypedDict, total=False): + action: Required[Literal["cancel"]] + + type: Required[Literal["browser_authentication"]] diff --git a/src/openai/types/beta/agent_browser_authentication_submit_param.py b/src/openai/types/beta/agent_browser_authentication_submit_param.py new file mode 100644 index 0000000000..d624370078 --- /dev/null +++ b/src/openai/types/beta/agent_browser_authentication_submit_param.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AgentBrowserAuthenticationSubmitParam", "Field"] + + +class Field(TypedDict, total=False): + """One user-entered value, including non-password fields such as an email address.""" + + field_id: Required[str] + """The field ID from the required action.""" + + value: Required[str] + """The value to enter into the registered control.""" + + +class AgentBrowserAuthenticationSubmitParam(TypedDict, total=False): + action: Required[Literal["submit"]] + + fields: Required[Iterable[Field]] + """Values for up to six active fields in the required action. + + The submitted field-value mapping and selected option must fit within 120 KiB of + JSON. + """ + + type: Required[Literal["browser_authentication"]] + + selected_option: Optional[str] + """The chosen method. Required when the required action contains options.""" diff --git a/src/openai/types/beta/agent_browser_authentication_submit_param_param.py b/src/openai/types/beta/agent_browser_authentication_submit_param_param.py new file mode 100644 index 0000000000..7765a3adf0 --- /dev/null +++ b/src/openai/types/beta/agent_browser_authentication_submit_param_param.py @@ -0,0 +1,34 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Iterable, Optional +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AgentBrowserAuthenticationSubmitParamParam", "Field"] + + +class Field(TypedDict, total=False): + """One user-entered value, including non-password fields such as an email address.""" + + field_id: Required[str] + """The field ID from the required action.""" + + value: Required[str] + """The value to enter into the registered control.""" + + +class AgentBrowserAuthenticationSubmitParamParam(TypedDict, total=False): + action: Required[Literal["submit"]] + + fields: Required[Iterable[Field]] + """Values for up to six active fields in the required action. + + The submitted field-value mapping and selected option must fit within 120 KiB of + JSON. + """ + + type: Required[Literal["browser_authentication"]] + + selected_option: Optional[str] + """The chosen method. Required when the required action contains options.""" diff --git a/src/openai/types/beta/agent_browser_origin_access_param.py b/src/openai/types/beta/agent_browser_origin_access_param.py new file mode 100644 index 0000000000..a710d128ce --- /dev/null +++ b/src/openai/types/beta/agent_browser_origin_access_param.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AgentBrowserOriginAccessParam"] + + +class AgentBrowserOriginAccessParam(TypedDict, total=False): + decision: Required[Literal["approve", "deny", "cancel"]] + """Whether to allow, deny, or cancel the requested origin access. + + - `approve` - Allow the browser to access this origin. + - `deny` - Deny access to this origin. + - `cancel` - Dismiss this request without approving access. + """ + + type: Required[Literal["browser_origin_access"]] diff --git a/src/openai/types/beta/agent_browser_origin_access_param_param.py b/src/openai/types/beta/agent_browser_origin_access_param_param.py new file mode 100644 index 0000000000..506cd1d859 --- /dev/null +++ b/src/openai/types/beta/agent_browser_origin_access_param_param.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["AgentBrowserOriginAccessParamParam"] + + +class AgentBrowserOriginAccessParamParam(TypedDict, total=False): + decision: Required[Literal["approve", "deny", "cancel"]] + """Whether to allow, deny, or cancel the requested origin access. + + - `approve` - Allow the browser to access this origin. + - `deny` - Deny access to this origin. + - `cancel` - Dismiss this request without approving access. + """ + + type: Required[Literal["browser_origin_access"]] diff --git a/src/openai/types/beta/agent_output_item.py b/src/openai/types/beta/agent_output_item.py index cfa5d6aba1..3e27f947d9 100644 --- a/src/openai/types/beta/agent_output_item.py +++ b/src/openai/types/beta/agent_output_item.py @@ -1,12 +1,14 @@ # File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. -from typing import Union -from typing_extensions import Annotated, TypeAlias +from typing import List, Union, Optional +from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo +from ..._models import BaseModel from .agent_mcp_call_item import AgentMcpCallItem from .agent_reasoning_item import AgentReasoningItem from .agent_function_call_item import AgentFunctionCallItem +from .agent_function_call_status import AgentFunctionCallStatus from .agent_web_search_call_item import AgentWebSearchCallItem from .agent_command_execution_item import AgentCommandExecutionItem from .agent_close_subagent_call_item import AgentCloseSubagentCallItem @@ -17,7 +19,119 @@ from .agent_wait_for_subagents_call_item import AgentWaitForSubagentsCallItem from .agent_send_subagent_input_call_item import AgentSendSubagentInputCallItem -__all__ = ["AgentOutputItem"] +__all__ = [ + "AgentOutputItem", + "ComputerUseCallItemResource", + "ComputerUseCallItemResourceOutput", + "BrowserAuthenticationRequestItemResource", + "BrowserAuthenticationRequestItemResourceRequest", + "BrowserAuthenticationRequestItemResourceRequestField", + "BrowserAuthenticationRequestItemResourceRequestOption", +] + + +class ComputerUseCallItemResourceOutput(BaseModel): + """The last screenshot emitted by the model. + + Null when screenshot inclusion is disabled or the call emitted no screenshot. + """ + + image_url: str + """The complete JPEG image as a base64 data URL.""" + + type: Literal["computer_screenshot"] + """The content type. Always `computer_screenshot`.""" + + +class ComputerUseCallItemResource(BaseModel): + """One execution of the platform-provided computer-use capability.""" + + id: str + """The ID of the activity item.""" + + output: Optional[ComputerUseCallItemResourceOutput] = None + """The last screenshot emitted by the model. + + Null when screenshot inclusion is disabled or the call emitted no screenshot. + """ + + status: AgentFunctionCallStatus + """The execution status of the activity.""" + + title: Optional[str] = None + """A model-generated description of the activity, when available.""" + + turn_id: str + """The ID of the turn that contains this item.""" + + type: Literal["computer_use_call"] + """The item type. Always `computer_use_call`.""" + + +class BrowserAuthenticationRequestItemResourceRequestField(BaseModel): + """A control in a registered browser-login form.""" + + id: str + """The field ID to submit as field_id in a fields entry.""" + + label: str + """The label to display beside the control.""" + + required: bool + """Whether this control requires a nonempty value.""" + + type: str + """The rendering type, such as email, password, or text.""" + + +class BrowserAuthenticationRequestItemResourceRequestOption(BaseModel): + """A sign-in method and the fields that belong to it.""" + + id: str + """The option ID to submit as selected_option.""" + + field_ids: List[str] + """IDs from the registered fields that this method accepts.""" + + label: str + """The method label to display.""" + + +class BrowserAuthenticationRequestItemResourceRequest(BaseModel): + """A registered form awaiting the application's response.""" + + credential_origin: Optional[str] = None + """The registered form or frame origin where values will be entered.""" + + fields: List[BrowserAuthenticationRequestItemResourceRequestField] + """Controls to render. All submitted values are sensitive.""" + + options: List[BrowserAuthenticationRequestItemResourceRequestOption] + """Sign-in methods. Empty for a plain form.""" + + reason: Optional[str] = None + """Why the agent needs the user to sign in.""" + + type: Literal["browser_authentication"] + """The type of the object. Always `browser_authentication`.""" + + +class BrowserAuthenticationRequestItemResource(BaseModel): + """A credential-free history record of the emitted login request.""" + + id: str + """The stable history item ID.""" + + request: BrowserAuthenticationRequestItemResourceRequest + """A registered form awaiting the application's response.""" + + request_id: str + + turn_id: str + + type: Literal["computer_use_approval_request"] + """The item type. Always computer_use_approval_request.""" + AgentOutputItem: TypeAlias = Annotated[ Union[ @@ -25,6 +139,8 @@ AgentReasoningItem, AgentFunctionCallItem, AgentMcpCallItem, + ComputerUseCallItemResource, + BrowserAuthenticationRequestItemResource, AgentWebSearchCallItem, AgentCommandExecutionItem, AgentCreateSubagentCallItem, diff --git a/src/openai/types/beta/agent_session.py b/src/openai/types/beta/agent_session.py index 3cdce02446..91c27a1c46 100644 --- a/src/openai/types/beta/agent_session.py +++ b/src/openai/types/beta/agent_session.py @@ -16,6 +16,12 @@ "AgentSession", "Agent", "RequiredAction", + "RequiredActionSessionRequiredActionResourceComputerUseApprovalRequest", + "RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequest", + "RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthentication", + "RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthenticationField", + "RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthenticationOption", + "RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserOriginAccess", "RequiredActionSessionRequiredActionResourceFunctionCall", "RequiredActionSessionRequiredActionResourceEnvironmentConnection", ] @@ -55,6 +61,104 @@ class Agent(BaseModel): """Tools available to the agent.""" +class RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthenticationField( + BaseModel +): + """A control in a registered browser-login form.""" + + id: str + """The field ID to submit as field_id in a fields entry.""" + + label: str + """The label to display beside the control.""" + + required: bool + """Whether this control requires a nonempty value.""" + + type: str + """The rendering type, such as email, password, or text.""" + + +class RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthenticationOption( + BaseModel +): + """A sign-in method and the fields that belong to it.""" + + id: str + """The option ID to submit as selected_option.""" + + field_ids: List[str] + """IDs from the registered fields that this method accepts.""" + + label: str + """The method label to display.""" + + +class RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthentication( + BaseModel +): + """A registered form awaiting the application's response.""" + + credential_origin: Optional[str] = None + """The registered form or frame origin where values will be entered.""" + + fields: List[ + RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthenticationField + ] + """Controls to render. All submitted values are sensitive.""" + + options: List[ + RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthenticationOption + ] + """Sign-in methods. Empty for a plain form.""" + + reason: Optional[str] = None + """Why the agent needs the user to sign in.""" + + type: Literal["browser_authentication"] + """The type of the object. Always `browser_authentication`.""" + + +class RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserOriginAccess( + BaseModel +): + """A browser origin awaiting the application's approval decision.""" + + origin: str + """The origin the browser needs permission to access.""" + + reason: Optional[str] = None + """The browser's explanation for this request, or null when unavailable.""" + + type: Literal["browser_origin_access"] + """The type of the object. Always `browser_origin_access`.""" + + +RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequest: TypeAlias = Annotated[ + Union[ + RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserAuthentication, + RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequestComputerUseApprovalRequestKindResourceBrowserOriginAccess, + ], + PropertyInfo(discriminator="type"), +] + + +class RequiredActionSessionRequiredActionResourceComputerUseApprovalRequest(BaseModel): + """Respond to a computer-use request.""" + + request: RequiredActionSessionRequiredActionResourceComputerUseApprovalRequestRequest + """The information needed to render the request.""" + + request_id: str + """The registered request ID to echo when responding.""" + + turn_id: str + """The turn that requested approval.""" + + type: Literal["computer_use_approval_request"] + """The type of the object. Always `computer_use_approval_request`.""" + + class RequiredActionSessionRequiredActionResourceFunctionCall(BaseModel): """Run a function tool and submit its result.""" @@ -86,6 +190,7 @@ class RequiredActionSessionRequiredActionResourceEnvironmentConnection(BaseModel RequiredAction: TypeAlias = Annotated[ Union[ + RequiredActionSessionRequiredActionResourceComputerUseApprovalRequest, RequiredActionSessionRequiredActionResourceFunctionCall, RequiredActionSessionRequiredActionResourceEnvironmentConnection, ], diff --git a/src/openai/types/beta/agent_session_input_param.py b/src/openai/types/beta/agent_session_input_param.py index b7a49bded8..c75f549be0 100644 --- a/src/openai/types/beta/agent_session_input_param.py +++ b/src/openai/types/beta/agent_session_input_param.py @@ -7,14 +7,41 @@ from .agent_function_call_output_param import AgentFunctionCallOutputParam from .agent_session_input_message_param import AgentSessionInputMessageParam +from .agent_browser_origin_access_param_param import AgentBrowserOriginAccessParamParam +from .agent_browser_authentication_cancel_param_param import AgentBrowserAuthenticationCancelParamParam +from .agent_browser_authentication_submit_param_param import AgentBrowserAuthenticationSubmitParamParam __all__ = [ "AgentSessionInputParam", + "SessionInputParamAgentSessionInputComputerUseApprovalRequestResult", + "SessionInputParamAgentSessionInputComputerUseApprovalRequestResultResponse", "SessionInputParamAgentSessionInputMessage", "SessionInputParamAgentSessionInputCancel", "SessionInputParamAgentSessionInputToolResult", ] +SessionInputParamAgentSessionInputComputerUseApprovalRequestResultResponse: TypeAlias = Union[ + AgentBrowserAuthenticationSubmitParamParam, + AgentBrowserAuthenticationCancelParamParam, + AgentBrowserOriginAccessParamParam, +] + + +class SessionInputParamAgentSessionInputComputerUseApprovalRequestResult(TypedDict, total=False): + """Responds to a pending Computer Use approval request.""" + + request_id: Required[str] + """The registered request ID from the required action.""" + + response: Required[SessionInputParamAgentSessionInputComputerUseApprovalRequestResultResponse] + """The response for this request type.""" + + type: Required[Literal["agent.session.input.computer_use_approval_request_result"]] + """The type of the object. + + Always `agent.session.input.computer_use_approval_request_result`. + """ + class SessionInputParamAgentSessionInputMessage(TypedDict, total=False): """Adds one or more user messages and starts a turn.""" @@ -56,6 +83,7 @@ class SessionInputParamAgentSessionInputToolResult(TypedDict, total=False): AgentSessionInputParam: TypeAlias = Union[ + SessionInputParamAgentSessionInputComputerUseApprovalRequestResult, SessionInputParamAgentSessionInputMessage, SessionInputParamAgentSessionInputCancel, SessionInputParamAgentSessionInputToolResult, diff --git a/src/openai/types/beta/agent_session_item.py b/src/openai/types/beta/agent_session_item.py index 75e7df852c..02e17e1c0d 100644 --- a/src/openai/types/beta/agent_session_item.py +++ b/src/openai/types/beta/agent_session_item.py @@ -21,7 +21,21 @@ from .agent_wait_for_subagents_call_item import AgentWaitForSubagentsCallItem from .agent_send_subagent_input_call_item import AgentSendSubagentInputCallItem -__all__ = ["AgentSessionItem", "FunctionCallOutputItemResource", "AgentMessageItemResource"] +__all__ = [ + "AgentSessionItem", + "FunctionCallOutputItemResource", + "AgentMessageItemResource", + "ComputerUseCallItemResource", + "ComputerUseCallItemResourceOutput", + "BrowserAuthenticationRequestItemResource", + "BrowserAuthenticationRequestItemResourceRequest", + "BrowserAuthenticationRequestItemResourceRequestField", + "BrowserAuthenticationRequestItemResourceRequestOption", + "ComputerUseApprovalRequestResultItemResource", + "ComputerUseApprovalRequestResultItemResourceResponse", + "ComputerUseApprovalRequestResultItemResourceResponseComputerUseApprovalResponseKindResourceBrowserAuthenticationSubmitResource", + "ComputerUseApprovalRequestResultItemResourceResponseComputerUseApprovalResponseKindResourceBrowserAuthenticationCancelResource", +] class FunctionCallOutputItemResource(BaseModel): @@ -71,6 +85,155 @@ class AgentMessageItemResource(BaseModel): """The item type. Always `agent_message`.""" +class ComputerUseCallItemResourceOutput(BaseModel): + """The last screenshot emitted by the model. + + Null when screenshot inclusion is disabled or the call emitted no screenshot. + """ + + image_url: str + """The complete JPEG image as a base64 data URL.""" + + type: Literal["computer_screenshot"] + """The content type. Always `computer_screenshot`.""" + + +class ComputerUseCallItemResource(BaseModel): + """One execution of the platform-provided computer-use capability.""" + + id: str + """The ID of the activity item.""" + + output: Optional[ComputerUseCallItemResourceOutput] = None + """The last screenshot emitted by the model. + + Null when screenshot inclusion is disabled or the call emitted no screenshot. + """ + + status: AgentFunctionCallStatus + """The execution status of the activity.""" + + title: Optional[str] = None + """A model-generated description of the activity, when available.""" + + turn_id: str + """The ID of the turn that contains this item.""" + + type: Literal["computer_use_call"] + """The item type. Always `computer_use_call`.""" + + +class BrowserAuthenticationRequestItemResourceRequestField(BaseModel): + """A control in a registered browser-login form.""" + + id: str + """The field ID to submit as field_id in a fields entry.""" + + label: str + """The label to display beside the control.""" + + required: bool + """Whether this control requires a nonempty value.""" + + type: str + """The rendering type, such as email, password, or text.""" + + +class BrowserAuthenticationRequestItemResourceRequestOption(BaseModel): + """A sign-in method and the fields that belong to it.""" + + id: str + """The option ID to submit as selected_option.""" + + field_ids: List[str] + """IDs from the registered fields that this method accepts.""" + + label: str + """The method label to display.""" + + +class BrowserAuthenticationRequestItemResourceRequest(BaseModel): + """A registered form awaiting the application's response.""" + + credential_origin: Optional[str] = None + """The registered form or frame origin where values will be entered.""" + + fields: List[BrowserAuthenticationRequestItemResourceRequestField] + """Controls to render. All submitted values are sensitive.""" + + options: List[BrowserAuthenticationRequestItemResourceRequestOption] + """Sign-in methods. Empty for a plain form.""" + + reason: Optional[str] = None + """Why the agent needs the user to sign in.""" + + type: Literal["browser_authentication"] + """The type of the object. Always `browser_authentication`.""" + + +class BrowserAuthenticationRequestItemResource(BaseModel): + """A credential-free history record of the emitted login request.""" + + id: str + """The stable history item ID.""" + + request: BrowserAuthenticationRequestItemResourceRequest + """A registered form awaiting the application's response.""" + + request_id: str + + turn_id: str + + type: Literal["computer_use_approval_request"] + """The item type. Always computer_use_approval_request.""" + + +class ComputerUseApprovalRequestResultItemResourceResponseComputerUseApprovalResponseKindResourceBrowserAuthenticationSubmitResource( + BaseModel +): + action: Literal["submit"] + + selected_option: Optional[str] = None + """The chosen sign-in method, or null when no options were offered.""" + + type: Literal["browser_authentication"] + + +class ComputerUseApprovalRequestResultItemResourceResponseComputerUseApprovalResponseKindResourceBrowserAuthenticationCancelResource( + BaseModel +): + action: Literal["cancel"] + + type: Literal["browser_authentication"] + + +ComputerUseApprovalRequestResultItemResourceResponse: TypeAlias = Annotated[ + Union[ + ComputerUseApprovalRequestResultItemResourceResponseComputerUseApprovalResponseKindResourceBrowserAuthenticationSubmitResource, + ComputerUseApprovalRequestResultItemResourceResponseComputerUseApprovalResponseKindResourceBrowserAuthenticationCancelResource, + ], + PropertyInfo(discriminator="action"), +] + + +class ComputerUseApprovalRequestResultItemResource(BaseModel): + """A credential-free record of an admitted response, not proof of completion.""" + + id: str + """The stable history item ID.""" + + request_id: str + """The registered request answered by this item.""" + + response: ComputerUseApprovalRequestResultItemResourceResponse + """The admitted response, without submitted credential values.""" + + turn_id: str + """The ID of the turn that contains this item.""" + + type: Literal["computer_use_approval_request_result"] + + AgentSessionItem: TypeAlias = Annotated[ Union[ AgentSessionMessage, @@ -79,6 +242,9 @@ class AgentMessageItemResource(BaseModel): FunctionCallOutputItemResource, AgentMessageItemResource, AgentMcpCallItem, + ComputerUseCallItemResource, + BrowserAuthenticationRequestItemResource, + ComputerUseApprovalRequestResultItemResource, AgentWebSearchCallItem, AgentCommandExecutionItem, AgentCreateSubagentCallItem, diff --git a/src/openai/types/beta/agent_tool.py b/src/openai/types/beta/agent_tool.py index 023fe89c6a..ff4aa6bd2e 100644 --- a/src/openai/types/beta/agent_tool.py +++ b/src/openai/types/beta/agent_tool.py @@ -14,6 +14,7 @@ "AgentToolResourceMcp", "AgentToolResourceWebSearch", "AgentToolResourceWebSearchLocation", + "AgentToolResourceComputerUse", ] @@ -112,12 +113,23 @@ class AgentToolResourceWebSearch(BaseModel): """The type of the object. Always `web_search`.""" +class AgentToolResourceComputerUse(BaseModel): + """Browser use in an OpenAI-hosted session.""" + + include_screenshots: bool + """Whether computer tool outputs include screenshots.""" + + type: Literal["computer_use"] + """The type of the object. Always `computer_use`.""" + + AgentTool: TypeAlias = Annotated[ Union[ AgentToolResourceFunction, AgentToolResourceProgrammaticToolCalling, AgentToolResourceMcp, AgentToolResourceWebSearch, + AgentToolResourceComputerUse, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/beta/agent_tool_param.py b/src/openai/types/beta/agent_tool_param.py index a9e3da4df0..5246817c9f 100644 --- a/src/openai/types/beta/agent_tool_param.py +++ b/src/openai/types/beta/agent_tool_param.py @@ -16,6 +16,7 @@ "AgentToolConfigParamMcp", "AgentToolConfigParamWebSearch", "AgentToolConfigParamWebSearchLocation", + "AgentToolConfigParamComputerUse", ] @@ -139,10 +140,21 @@ class AgentToolConfigParamWebSearch(TypedDict, total=False): """ +class AgentToolConfigParamComputerUse(TypedDict, total=False): + """Browser use in an OpenAI-hosted session.""" + + type: Required[Literal["computer_use"]] + """The type of the object. Always `computer_use`.""" + + include_screenshots: bool + """Whether computer tool outputs include screenshots. Defaults to `false`.""" + + AgentToolParam: TypeAlias = Union[ AgentToolConfigParamFunction, AgentToolConfigParamToolSearch, AgentToolConfigParamProgrammaticToolCalling, AgentToolConfigParamMcp, AgentToolConfigParamWebSearch, + AgentToolConfigParamComputerUse, ] diff --git a/src/openai/types/beta/agents/environments/environment_template.py b/src/openai/types/beta/agents/environments/environment_template.py index 5779f05c46..9af7287d0d 100644 --- a/src/openai/types/beta/agents/environments/environment_template.py +++ b/src/openai/types/beta/agents/environments/environment_template.py @@ -17,6 +17,7 @@ "Skill", "SkillHostedTemplateSkillResourceSkillReference", "SkillHostedTemplateSkillResourceInline", + "Desktop", ] @@ -60,7 +61,7 @@ class Network(BaseModel): - `enabled` - Allows unrestricted network access. - `disabled` - Disables network access. - - `restricted` - Allows access only to configured domains. + - `restricted` - Applies the configured domain restrictions. """ allowed_domains: List[str] @@ -112,6 +113,13 @@ class SkillHostedTemplateSkillResourceInline(BaseModel): ] +class Desktop(BaseModel): + """Desktop configuration for each OpenAI-hosted environment.""" + + enabled: bool + """Whether the environment provisions a desktop and browser proxy.""" + + class EnvironmentTemplate(BaseModel): """ Reusable configuration that provisions a fresh OpenAI-hosted environment for each session. @@ -149,3 +157,6 @@ class EnvironmentTemplate(BaseModel): updated_at: int """The Unix timestamp, in seconds, when the template was last updated.""" + + desktop: Optional[Desktop] = None + """Desktop configuration for each OpenAI-hosted environment.""" diff --git a/src/openai/types/beta/agents/environments/template_create_params.py b/src/openai/types/beta/agents/environments/template_create_params.py index 9fc858120b..19f4dceeb6 100644 --- a/src/openai/types/beta/agents/environments/template_create_params.py +++ b/src/openai/types/beta/agents/environments/template_create_params.py @@ -11,7 +11,7 @@ from ...setup_command_param import SetupCommandParam from ...hosted_environment_file_param import HostedEnvironmentFileParam -__all__ = ["TemplateCreateParams", "Network", "Packages"] +__all__ = ["TemplateCreateParams", "Desktop", "Network", "Packages"] class TemplateCreateParams(TypedDict, total=False): @@ -21,6 +21,12 @@ class TemplateCreateParams(TypedDict, total=False): Defaults to an empty list. """ + desktop: Optional[Desktop] + """Desktop provisioning. + + Omission or null inherits the template setting, or defaults to disabled. + """ + env: Optional[Dict[str, str]] """Environment variables made available to the agent.""" @@ -52,6 +58,16 @@ class TemplateCreateParams(TypedDict, total=False): """ +class Desktop(TypedDict, total=False): + """Desktop provisioning. + + Omission or null inherits the template setting, or defaults to disabled. + """ + + enabled: Required[bool] + """Whether to provision the desktop and its browser proxy.""" + + class Network(TypedDict, total=False): """Network access policy for the environment. @@ -63,12 +79,19 @@ class Network(TypedDict, total=False): - `enabled` - Allows unrestricted network access. - `disabled` - Disables network access. - - `restricted` - Allows access only to configured domains. + - `restricted` - Applies the configured domain restrictions. """ allowed_domains: Optional[SequenceNotStr[str]] """Domains the environment may access when network access is restricted.""" + blocked_domains: Optional[SequenceNotStr[str]] + """Domains blocked for both executor and browser when access is restricted. + + A nonempty list requires `access: restricted` and cannot be combined with + nonempty `allowed_domains`. Wildcard domains are not supported. + """ + class Packages(TypedDict, total=False): """Packages to install in the environment. Defaults to empty package lists.""" diff --git a/src/openai/types/beta/agents/environments/template_update_params.py b/src/openai/types/beta/agents/environments/template_update_params.py index a3a0beda86..eb1b0d9993 100644 --- a/src/openai/types/beta/agents/environments/template_update_params.py +++ b/src/openai/types/beta/agents/environments/template_update_params.py @@ -11,13 +11,16 @@ from ...setup_command_param import SetupCommandParam from ...hosted_environment_file_param import HostedEnvironmentFileParam -__all__ = ["TemplateUpdateParams", "Network", "Packages"] +__all__ = ["TemplateUpdateParams", "Desktop", "Network", "Packages"] class TemplateUpdateParams(TypedDict, total=False): capability_directories: Optional[SequenceNotStr[str]] """Directories that expose capabilities to the agent.""" + desktop: Optional[Desktop] + """Replacement desktop configuration, or null to disable the desktop.""" + env: Optional[Dict[str, str]] """Replacement confidential environment values.""" @@ -47,6 +50,13 @@ class TemplateUpdateParams(TypedDict, total=False): """Replacement skill configuration installed for each new session.""" +class Desktop(TypedDict, total=False): + """Replacement desktop configuration, or null to disable the desktop.""" + + enabled: Required[bool] + """Whether to provision the desktop and its browser proxy.""" + + class Network(TypedDict, total=False): """Network access available after setup completes. @@ -58,12 +68,19 @@ class Network(TypedDict, total=False): - `enabled` - Allows unrestricted network access. - `disabled` - Disables network access. - - `restricted` - Allows access only to configured domains. + - `restricted` - Applies the configured domain restrictions. """ allowed_domains: Optional[SequenceNotStr[str]] """Domains the environment may access when network access is restricted.""" + blocked_domains: Optional[SequenceNotStr[str]] + """Domains blocked for both executor and browser when access is restricted. + + A nonempty list requires `access: restricted` and cannot be combined with + nonempty `allowed_domains`. Wildcard domains are not supported. + """ + class Packages(TypedDict, total=False): """Packages installed before the runtime network policy applies.""" diff --git a/src/openai/types/beta/environment.py b/src/openai/types/beta/environment.py index 508457468c..1897f943cc 100644 --- a/src/openai/types/beta/environment.py +++ b/src/openai/types/beta/environment.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. -from typing import List, Union +from typing import List, Union, Optional from typing_extensions import Literal, Annotated, TypeAlias from ..._utils import PropertyInfo @@ -15,6 +15,7 @@ "EnvironmentResourceOpenAIHosted", "EnvironmentResourceOpenAIHostedNetwork", "EnvironmentResourceOpenAIHostedPackages", + "EnvironmentResourceOpenAIHostedDesktop", "EnvironmentResourceSelfHosted", ] @@ -36,7 +37,7 @@ class EnvironmentResourceOpenAIHostedNetwork(BaseModel): - `enabled` - Allows unrestricted network access. - `disabled` - Disables network access. - - `restricted` - Allows access only to configured domains. + - `restricted` - Applies the configured domain restrictions. """ allowed_domains: List[str] @@ -56,6 +57,13 @@ class EnvironmentResourceOpenAIHostedPackages(BaseModel): """System packages installed in the environment.""" +class EnvironmentResourceOpenAIHostedDesktop(BaseModel): + """The effective desktop configuration.""" + + enabled: bool + """Whether the environment provisions a desktop and browser proxy.""" + + class EnvironmentResourceOpenAIHosted(BaseModel): """An environment hosted by OpenAI.""" @@ -83,6 +91,9 @@ class EnvironmentResourceOpenAIHosted(BaseModel): type: Literal["openai_hosted"] """The type of the object. Always `openai_hosted`.""" + desktop: Optional[EnvironmentResourceOpenAIHostedDesktop] = None + """The effective desktop configuration.""" + class EnvironmentResourceSelfHosted(BaseModel): """An environment hosted by the application.""" diff --git a/src/openai/types/beta/environment_param.py b/src/openai/types/beta/environment_param.py index 43101b23b1..1a646f7a0a 100644 --- a/src/openai/types/beta/environment_param.py +++ b/src/openai/types/beta/environment_param.py @@ -15,6 +15,7 @@ "EnvironmentParam", "EnvironmentParamNone", "EnvironmentParamOpenAIHosted", + "EnvironmentParamOpenAIHostedDesktop", "EnvironmentParamOpenAIHostedNetwork", "EnvironmentParamOpenAIHostedPackages", "EnvironmentParamSelfHosted", @@ -28,6 +29,16 @@ class EnvironmentParamNone(TypedDict, total=False): """The type of the object. Always `none`.""" +class EnvironmentParamOpenAIHostedDesktop(TypedDict, total=False): + """Desktop provisioning. + + Omission or null inherits the template setting, or defaults to disabled. + """ + + enabled: Required[bool] + """Whether to provision the desktop and its browser proxy.""" + + class EnvironmentParamOpenAIHostedNetwork(TypedDict, total=False): """Network access policy for the environment. @@ -39,12 +50,19 @@ class EnvironmentParamOpenAIHostedNetwork(TypedDict, total=False): - `enabled` - Allows unrestricted network access. - `disabled` - Disables network access. - - `restricted` - Allows access only to configured domains. + - `restricted` - Applies the configured domain restrictions. """ allowed_domains: Optional[SequenceNotStr[str]] """Domains the environment may access when network access is restricted.""" + blocked_domains: Optional[SequenceNotStr[str]] + """Domains blocked for both executor and browser when access is restricted. + + A nonempty list requires `access: restricted` and cannot be combined with + nonempty `allowed_domains`. Wildcard domains are not supported. + """ + class EnvironmentParamOpenAIHostedPackages(TypedDict, total=False): """Packages to install in the environment. Defaults to empty package lists.""" @@ -73,6 +91,12 @@ class EnvironmentParamOpenAIHosted(TypedDict, total=False): Defaults to an empty list. """ + desktop: Optional[EnvironmentParamOpenAIHostedDesktop] + """Desktop provisioning. + + Omission or null inherits the template setting, or defaults to disabled. + """ + env: Optional[Dict[str, str]] """Environment variables made available to the agent.""" diff --git a/src/openai/types/beta/persisted_agent_tool.py b/src/openai/types/beta/persisted_agent_tool.py index 69340fb10c..422445d8b5 100644 --- a/src/openai/types/beta/persisted_agent_tool.py +++ b/src/openai/types/beta/persisted_agent_tool.py @@ -15,6 +15,7 @@ "PersistedAgentToolResourceMcp", "PersistedAgentToolResourceWebSearch", "PersistedAgentToolResourceWebSearchLocation", + "PersistedAgentToolResourceComputerUse", ] @@ -117,6 +118,16 @@ class PersistedAgentToolResourceWebSearch(BaseModel): """The type of the object. Always `web_search`.""" +class PersistedAgentToolResourceComputerUse(BaseModel): + """Browser use in an OpenAI-hosted session.""" + + include_screenshots: bool + """Whether computer tool outputs include screenshots.""" + + type: Literal["computer_use"] + """The type of the object. Always `computer_use`.""" + + PersistedAgentTool: TypeAlias = Annotated[ Union[ PersistedAgentToolResourceFunction, @@ -124,6 +135,7 @@ class PersistedAgentToolResourceWebSearch(BaseModel): PersistedAgentToolResourceProgrammaticToolCalling, PersistedAgentToolResourceMcp, PersistedAgentToolResourceWebSearch, + PersistedAgentToolResourceComputerUse, ], PropertyInfo(discriminator="type"), ] diff --git a/src/openai/types/beta/persisted_agent_tool_param.py b/src/openai/types/beta/persisted_agent_tool_param.py index a30719d102..b61830bf73 100644 --- a/src/openai/types/beta/persisted_agent_tool_param.py +++ b/src/openai/types/beta/persisted_agent_tool_param.py @@ -16,6 +16,7 @@ "PersistedAgentToolConfigParamMcp", "PersistedAgentToolConfigParamWebSearch", "PersistedAgentToolConfigParamWebSearchLocation", + "PersistedAgentToolConfigParamComputerUse", ] @@ -136,10 +137,21 @@ class PersistedAgentToolConfigParamWebSearch(TypedDict, total=False): """ +class PersistedAgentToolConfigParamComputerUse(TypedDict, total=False): + """Browser use in an OpenAI-hosted session.""" + + type: Required[Literal["computer_use"]] + """The type of the object. Always `computer_use`.""" + + include_screenshots: bool + """Whether computer tool outputs include screenshots. Defaults to `false`.""" + + PersistedAgentToolParam: TypeAlias = Union[ PersistedAgentToolConfigParamFunction, PersistedAgentToolConfigParamToolSearch, PersistedAgentToolConfigParamProgrammaticToolCalling, PersistedAgentToolConfigParamMcp, PersistedAgentToolConfigParamWebSearch, + PersistedAgentToolConfigParamComputerUse, ] diff --git a/tests/api_resources/audio/test_speech.py b/tests/api_resources/audio/test_speech.py index e1c56b39e8..57985851e8 100644 --- a/tests/api_resources/audio/test_speech.py +++ b/tests/api_resources/audio/test_speech.py @@ -28,7 +28,7 @@ def test_method_create(self, client: OpenAI, respx2_mock: MockRouter) -> None: speech = client.audio.speech.create( input="input", model="tts-1", - voice="alloy", + voice="ash", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -40,7 +40,7 @@ def test_method_create_with_all_params(self, client: OpenAI, respx2_mock: MockRo speech = client.audio.speech.create( input="input", model="tts-1", - voice="alloy", + voice="ash", instructions="instructions", response_format="mp3", speed=0.25, @@ -57,7 +57,7 @@ def test_raw_response_create(self, client: OpenAI, respx2_mock: MockRouter) -> N response = client.audio.speech.with_raw_response.create( input="input", model="tts-1", - voice="alloy", + voice="ash", ) assert response.is_closed is True @@ -72,7 +72,7 @@ def test_streaming_response_create(self, client: OpenAI, respx2_mock: MockRouter with client.audio.speech.with_streaming_response.create( input="input", model="tts-1", - voice="alloy", + voice="ash", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -95,7 +95,7 @@ async def test_method_create(self, async_client: AsyncOpenAI, respx2_mock: MockR speech = await async_client.audio.speech.create( input="input", model="tts-1", - voice="alloy", + voice="ash", ) assert isinstance(speech, _legacy_response.HttpxBinaryResponseContent) assert speech.json() == {"foo": "bar"} @@ -107,7 +107,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI, re speech = await async_client.audio.speech.create( input="input", model="tts-1", - voice="alloy", + voice="ash", instructions="instructions", response_format="mp3", speed=0.25, @@ -124,7 +124,7 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI, respx2_mock: response = await async_client.audio.speech.with_raw_response.create( input="input", model="tts-1", - voice="alloy", + voice="ash", ) assert response.is_closed is True @@ -139,7 +139,7 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI, respx2 async with async_client.audio.speech.with_streaming_response.create( input="input", model="tts-1", - voice="alloy", + voice="ash", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/beta/agents/environments/test_templates.py b/tests/api_resources/beta/agents/environments/test_templates.py index 554e7fb079..457978f52f 100644 --- a/tests/api_resources/beta/agents/environments/test_templates.py +++ b/tests/api_resources/beta/agents/environments/test_templates.py @@ -30,6 +30,7 @@ def test_method_create(self, client: OpenAI) -> None: def test_method_create_with_all_params(self, client: OpenAI) -> None: template = client.beta.agents.environments.templates.create( capability_directories=["string"], + desktop={"enabled": True}, env={"foo": "string"}, files=[ { @@ -42,6 +43,7 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: network={ "access": "enabled", "allowed_domains": ["string"], + "blocked_domains": ["string"], }, packages={ "npm": ["string"], @@ -148,6 +150,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: template = client.beta.agents.environments.templates.update( environment_template_id="environment_template_id", capability_directories=["string"], + desktop={"enabled": True}, env={"foo": "string"}, files=[ { @@ -160,6 +163,7 @@ def test_method_update_with_all_params(self, client: OpenAI) -> None: network={ "access": "enabled", "allowed_domains": ["string"], + "blocked_domains": ["string"], }, packages={ "npm": ["string"], @@ -316,6 +320,7 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> None: template = await async_client.beta.agents.environments.templates.create( capability_directories=["string"], + desktop={"enabled": True}, env={"foo": "string"}, files=[ { @@ -328,6 +333,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> network={ "access": "enabled", "allowed_domains": ["string"], + "blocked_domains": ["string"], }, packages={ "npm": ["string"], @@ -434,6 +440,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> template = await async_client.beta.agents.environments.templates.update( environment_template_id="environment_template_id", capability_directories=["string"], + desktop={"enabled": True}, env={"foo": "string"}, files=[ { @@ -446,6 +453,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncOpenAI) -> network={ "access": "enabled", "allowed_domains": ["string"], + "blocked_domains": ["string"], }, packages={ "npm": ["string"], diff --git a/tests/api_resources/beta/agents/sessions/test_events.py b/tests/api_resources/beta/agents/sessions/test_events.py index 30d4a710bd..057dffe623 100644 --- a/tests/api_resources/beta/agents/sessions/test_events.py +++ b/tests/api_resources/beta/agents/sessions/test_events.py @@ -21,18 +21,18 @@ def test_method_create(self, client: OpenAI) -> None: session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) @@ -44,19 +44,19 @@ def test_method_create_with_all_params(self, client: OpenAI) -> None: session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - "type": "message", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + "selected_option": "selected_option", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], idempotency_key="x", @@ -69,18 +69,18 @@ def test_raw_response_create(self, client: OpenAI) -> None: session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) @@ -96,18 +96,18 @@ def test_streaming_response_create(self, client: OpenAI) -> None: session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) as response: @@ -126,18 +126,18 @@ def test_path_params_create(self, client: OpenAI) -> None: session_id="", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) @@ -191,18 +191,18 @@ async def test_method_create(self, async_client: AsyncOpenAI) -> None: session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) @@ -214,19 +214,19 @@ async def test_method_create_with_all_params(self, async_client: AsyncOpenAI) -> session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - "type": "message", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + "selected_option": "selected_option", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], idempotency_key="x", @@ -239,18 +239,18 @@ async def test_raw_response_create(self, async_client: AsyncOpenAI) -> None: session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) @@ -266,18 +266,18 @@ async def test_streaming_response_create(self, async_client: AsyncOpenAI) -> Non session_id="session_id", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) as response: @@ -296,18 +296,18 @@ async def test_path_params_create(self, async_client: AsyncOpenAI) -> None: session_id="", events=[ { - "input": [ - { - "content": [ - { - "text": "text", - "type": "input_text", - } - ], - "role": "user", - } - ], - "type": "agent.session.input.message", + "request_id": "request_id", + "response": { + "action": "submit", + "fields": [ + { + "field_id": "field_id", + "value": "value", + } + ], + "type": "browser_authentication", + }, + "type": "agent.session.input.computer_use_approval_request_result", } ], ) From 49e4366847516621801ce3d82d7e47b7319c0873 Mon Sep 17 00:00:00 2001 From: "openai-sdks[bot]" <284451331+openai-sdks[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 19:01:43 +0000 Subject: [PATCH 3/9] release: 3.22.0 (#3990) Automated Release PR --- ## [3.22.0](https://github.com/openai/openai-python/compare/v3.21.0...v3.22.0) (2026-09-29) ### Features * **api:** add computer use to beta agents ([#3989](https://github.com/openai/openai-python/issues/3989)) ([f5dddb5](https://github.com/openai/openai-python/commit/f5dddb5a199f899d9439ac3187c9c0f2d3e4082e)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: openai-sdks[bot] <284451331+openai-sdks[bot]@users.noreply.github.com> --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- src/openai/_version.py | 2 +- uv.lock | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index eba8a04955..1887bd54c2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.21.0" + ".": "3.22.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e34678b8f..0914b6b84d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [3.22.0](https://github.com/openai/openai-python/compare/v3.21.0...v3.22.0) (2026-09-29) + + +### Features + +* **api:** add computer use to beta agents ([#3989](https://github.com/openai/openai-python/issues/3989)) ([f5dddb5](https://github.com/openai/openai-python/commit/f5dddb5a199f899d9439ac3187c9c0f2d3e4082e)) + ## [3.21.0](https://github.com/openai/openai-python/compare/v3.20.0...v3.21.0) (2026-09-29) diff --git a/pyproject.toml b/pyproject.toml index 206ba3fca2..6d58e4aae1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openai" -version = "3.21.0" +version = "3.22.0" description = "The official Python library for the openai API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/openai/_version.py b/src/openai/_version.py index 1a557a7cc8..021338e782 100644 --- a/src/openai/_version.py +++ b/src/openai/_version.py @@ -1,2 +1,2 @@ __title__ = "openai" -__version__ = "3.21.0" # x-release-please-version +__version__ = "3.22.0" # x-release-please-version diff --git a/uv.lock b/uv.lock index 46770cb264..92e0325807 100644 --- a/uv.lock +++ b/uv.lock @@ -1535,7 +1535,7 @@ wheels = [ [[package]] name = "openai" -version = "3.21.0" # x-release-please-version +version = "3.22.0" # x-release-please-version source = { editable = "." } dependencies = [ { name = "anyio" }, From 5a4bb9658ddb54f2b4033349ae621d4d879cc40f Mon Sep 17 00:00:00 2001 From: Stefan Wang <1fannnw@gmail.com> Date: Tue, 29 Sep 2026 21:56:50 +0000 Subject: [PATCH 4/9] Fix false results for whitespace-padded true responses (#3854) - [x] I understand that this repository is auto-generated and my pull request may not be merged ## Changes being requested A JSON `true` with a trailing newline is parsed as `False`. Both response parsers now trim whitespace and keep case-insensitive parsing. ## Additional context & links | # | Scenario | Command | Result | | --- | --- | --- | --- | | 1 | Local file download | Program below | `true\n`: `False` before, `True` after |
Reproducer and raw logs ```bash PYTHONPATH=src python - <<'PY' from http import HTTPStatus from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from threading import Thread import httpx2 from openai import OpenAI FILES: dict[str, bytes] = {"file_false": b"false\n", "file_true": b"true\n"} class Handler(BaseHTTPRequestHandler): def do_GET(self) -> None: body = FILES[self.path.split("/")[3]] self.send_response(HTTPStatus.OK) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, format: str, *args: object) -> None: pass server = ThreadingHTTPServer(server_address=("127.0.0.1", 0), RequestHandlerClass=Handler) thread = Thread(target=server.serve_forever) thread.start() try: with OpenAI(api_key="local", base_url=f"http://127.0.0.1:{server.server_port}/v1", http_client=httpx2.Client(trust_env=False)) as client: for file_id in FILES: raw = client.files.with_raw_response.content(file_id=file_id) with client.files.with_streaming_response.content(file_id=file_id) as streamed: values = (raw.parse(to=bool), streamed.parse(to=bool)) print(file_id, raw.status_code, values, flush=True) expected = file_id == "file_true" assert values == (expected, expected), "Incorrect boolean result" finally: server.shutdown() server.server_close() thread.join() PY ``` Before: ```text file_false 200 (False, False) file_true 200 (False, False) Traceback (most recent call last): File "", line 34, in AssertionError: Incorrect boolean result exit=1 ``` After: ```text file_false 200 (False, False) file_true 200 (True, True) exit=0 ```
Both parser modules hit the same existing `AttributeError: module 'rich' has no attribute 'console'` in the display helper before and after this change. Signed-off-by: 1fanwang <1fannnw@gmail.com> Co-authored-by: Marcus Wood --- src/openai/_legacy_response.py | 2 +- src/openai/_response.py | 2 +- tests/test_legacy_response.py | 2 ++ tests/test_response.py | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/openai/_legacy_response.py b/src/openai/_legacy_response.py index a66bca2bce..bfbdcb1ab6 100644 --- a/src/openai/_legacy_response.py +++ b/src/openai/_legacy_response.py @@ -265,7 +265,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast(R, float(response.text)) if cast_to == bool: - return cast(R, response.text.lower() == "true") + return cast(R, response.text.strip().lower() == "true") if inspect.isclass(origin) and issubclass(origin, HttpxBinaryResponseContent): return cast(R, cast_to(response)) # type: ignore diff --git a/src/openai/_response.py b/src/openai/_response.py index e18f927a69..41bddf671a 100644 --- a/src/openai/_response.py +++ b/src/openai/_response.py @@ -199,7 +199,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast(R, float(response.text)) if cast_to == bool: - return cast(R, response.text.lower() == "true") + return cast(R, response.text.strip().lower() == "true") # handle the legacy binary response case if inspect.isclass(cast_to) and cast_to.__name__ == "HttpxBinaryResponseContent": diff --git a/tests/test_legacy_response.py b/tests/test_legacy_response.py index 236c6c259b..b2334a7acb 100644 --- a/tests/test_legacy_response.py +++ b/tests/test_legacy_response.py @@ -43,6 +43,8 @@ def test_response_parse_mismatched_basemodel(client: OpenAI) -> None: ("True", True), ("TrUe", True), ("FalSe", False), + (" \ttrue\r\n", True), + (" \tfalse\r\n", False), ], ) def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> None: diff --git a/tests/test_response.py b/tests/test_response.py index fba775e873..68083c358b 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -246,6 +246,8 @@ async def test_async_response_parse_annotated_type(async_client: AsyncOpenAI) -> ("True", True), ("TrUe", True), ("FalSe", False), + (" \ttrue\r\n", True), + (" \tfalse\r\n", False), ], ) def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> None: @@ -271,6 +273,8 @@ def test_response_parse_bool(client: OpenAI, content: str, expected: bool) -> No ("True", True), ("TrUe", True), ("FalSe", False), + (" \ttrue\r\n", True), + (" \tfalse\r\n", False), ], ) async def test_async_response_parse_bool(client: AsyncOpenAI, content: str, expected: bool) -> None: From 063375b7a12f3f3a0de10aec829c0416651be8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E8=B0=A6?= <89645338+simpleqt@users.noreply.github.com> Date: Tue, 29 Sep 2026 22:13:07 +0000 Subject: [PATCH 5/9] docs(examples): print event.delta in the streaming helpers doc (#3876) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary The streaming snippet in `helpers.md:172` prints `event.content` for `content.delta` events, but `ContentDeltaEvent` only has `delta` and `snapshot` fields (`src/openai/lib/streaming/chat/_events.py`) — running the snippet raises `AttributeError`. Changed to `event.delta`, which the same page already documents at line 199. ## Checklist - [x] I understand that this repository is auto-generated and my pull request may not be merged Co-authored-by: Marcus Wood --- helpers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.md b/helpers.md index 940381dd4d..c6df1faf42 100644 --- a/helpers.md +++ b/helpers.md @@ -169,7 +169,7 @@ async with client.chat.completions.stream( ) as stream: async for event in stream: if event.type == 'content.delta': - print(event.content, flush=True, end='') + print(event.delta, flush=True, end='') ``` When the context manager is entered, a `ChatCompletionStream` / `AsyncChatCompletionStream` instance is returned which, like `.create(stream=True)` is an iterator in the sync client and an async iterator in the async client. The full list of events that are yielded by the iterator are outlined [below](#chat-completions-events). From 51692ed3f9d2b87084801295f824c2202dac3785 Mon Sep 17 00:00:00 2001 From: Marcus Wood Date: Tue, 29 Sep 2026 22:15:47 +0000 Subject: [PATCH 6/9] fix(api): correct the missing authentication error message (#3993) ## Summary Clarifies the error raised when authentication cannot be resolved. ## Changes - List each authentication header once and use the correct singular or plural wording. - Remove stray quotation marks without changing authentication validation or the exception type. Fixes #3962 Co-authored-by: marcuswood-oai <323319819+marcuswood-oai@users.noreply.github.com> --- .castiron.stats.yml | 8 ++++---- src/openai/_client.py | 4 ++-- tests/test_client.py | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.castiron.stats.yml b/.castiron.stats.yml index 800f02fe05..24b9aba1e5 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,8 +1,8 @@ schema_version: 1 -generation_id: 7151c90a-4825-4a4f-b9b1-9e268a95134d +generation_id: 531ae883-4e92-4d68-806a-afa871a99ebf openapi_spec_hash: 982e032cd9bc8921825601fbb36a8a92 openapi_transformed_spec_hash: 7554bcd8a14262861882411fc4426386 config_hash: ac46b7ace0a09008785717fbff2f1d19 -codegen_sha: 591413c2ff7e011ff70f92ab58d9a8a4917818ac -codegen_hash: 69df1931f3258b1a5ff25728ac96053783f52b1c94eb5d1c190a520ed699faac -public_codegen_sha: 2fb2f98ab0d132294487c886ebda89a479b41e2e +codegen_sha: f3f4c861a6667d43481d59bc13ec819aea842424 +codegen_hash: 9a593cdd8f956c8e66684b95d43e866785aa2ddfa5050b37032ddcd86564cd61 +public_codegen_sha: 6c05ca76072a68a16d7a5fccd5b78f648f90c3ba diff --git a/src/openai/_client.py b/src/openai/_client.py index 0a5330a9aa..47ae340317 100644 --- a/src/openai/_client.py +++ b/src/openai/_client.py @@ -662,7 +662,7 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: return raise TypeError( - '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' + "Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for the `Authorization` header to be explicitly omitted." ) @override @@ -1425,7 +1425,7 @@ def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None: return raise TypeError( - '"Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for one of the `Authorization` or `Authorization` headers to be explicitly omitted"' + "Could not resolve authentication method. Expected either api_key or admin_api_key to be set. Or for the `Authorization` header to be explicitly omitted." ) @override diff --git a/tests/test_client.py b/tests/test_client.py index 006fe24d0a..9e86c03c72 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -582,10 +582,7 @@ def test_validate_headers(self) -> None: ) assert admin_only_request.headers.get("Authorization") == f"Bearer {admin_api_key}" - with pytest.raises( - TypeError, - match="Could not resolve authentication method", - ): + with pytest.raises(TypeError) as exc: admin_only._build_request( FinalRequestOptions( method="post", @@ -593,6 +590,10 @@ def test_validate_headers(self) -> None: security={"bearer_auth": True}, ) ) + assert str(exc.value) == ( + "Could not resolve authentication method. Expected either api_key or admin_api_key to be set. " + "Or for the `Authorization` header to be explicitly omitted." + ) with update_env( **{ @@ -2134,10 +2135,7 @@ async def test_validate_headers(self) -> None: ) assert admin_only_request.headers.get("Authorization") == f"Bearer {admin_api_key}" - with pytest.raises( - TypeError, - match="Could not resolve authentication method", - ): + with pytest.raises(TypeError) as exc: admin_only._build_request( FinalRequestOptions( method="post", @@ -2145,6 +2143,10 @@ async def test_validate_headers(self) -> None: security={"bearer_auth": True}, ) ) + assert str(exc.value) == ( + "Could not resolve authentication method. Expected either api_key or admin_api_key to be set. " + "Or for the `Authorization` header to be explicitly omitted." + ) with update_env( **{ From 5559bdb326dcf9b914a142caa8ba426a10df357f Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Tue, 29 Sep 2026 22:43:27 +0000 Subject: [PATCH 7/9] test(api): cover generated WebSocket resources in redirect harness (#3992) ## Summary Connect the WebSocket redirect/reconnect test harness to the generated resource registry so newly generated resource families inherit the existing coverage. The harness supplies synthetic required connection arguments and retains SDK-owned beta Realtime coverage. API definitions and runtime behavior are unchanged. ## Validation - All 99 WebSocket redirect/reconnect tests pass locally. - Ruff formatting and lint pass for the changed test file. - Full SDK, compatibility, and Castiron checks run in CI. Co-authored-by: apcha-oai <228803254+apcha-oai@users.noreply.github.com> --- .castiron.stats.yml | 8 +++--- tests/api_resources/_websocket_resources.py | 11 +++++++++ tests/lib/test_websocket_redirects.py | 27 ++++++++++++++------- 3 files changed, 33 insertions(+), 13 deletions(-) create mode 100644 tests/api_resources/_websocket_resources.py diff --git a/.castiron.stats.yml b/.castiron.stats.yml index 24b9aba1e5..a76b4d2f01 100644 --- a/.castiron.stats.yml +++ b/.castiron.stats.yml @@ -1,8 +1,8 @@ schema_version: 1 -generation_id: 531ae883-4e92-4d68-806a-afa871a99ebf +generation_id: ce06443e-d28b-4283-849b-5a25fd1ad9a9 openapi_spec_hash: 982e032cd9bc8921825601fbb36a8a92 openapi_transformed_spec_hash: 7554bcd8a14262861882411fc4426386 config_hash: ac46b7ace0a09008785717fbff2f1d19 -codegen_sha: f3f4c861a6667d43481d59bc13ec819aea842424 -codegen_hash: 9a593cdd8f956c8e66684b95d43e866785aa2ddfa5050b37032ddcd86564cd61 -public_codegen_sha: 6c05ca76072a68a16d7a5fccd5b78f648f90c3ba +codegen_sha: 0d833f5593b49e59cbc139ebecdabb03dd2e2137 +codegen_hash: 9db992d1159f9180396901efa950985fd0eee02fccb090be17c15d53b9a829c7 +public_codegen_sha: 401db4818440978f47a92ae7535a243934ccea29 diff --git a/tests/api_resources/_websocket_resources.py b/tests/api_resources/_websocket_resources.py new file mode 100644 index 0000000000..8cae7a1155 --- /dev/null +++ b/tests/api_resources/_websocket_resources.py @@ -0,0 +1,11 @@ +# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details. + +# Consumed by the SDK-owned tests/lib/test_websocket_redirects.py harness. +WEBSOCKET_RESOURCES = [ + "beta.responses", + "responses", + "live", + "live.sideband", + "live.forks", + "realtime", +] diff --git a/tests/lib/test_websocket_redirects.py b/tests/lib/test_websocket_redirects.py index 35f48d46c1..3515744ef8 100644 --- a/tests/lib/test_websocket_redirects.py +++ b/tests/lib/test_websocket_redirects.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import inspect from typing import Any, Callable from unittest.mock import Mock, AsyncMock @@ -15,8 +16,10 @@ from openai import OpenAI, AsyncOpenAI, AsyncAzureOpenAI from openai.lib._websocket import _WebSocketConnect from openai.types.websocket_reconnection import ReconnectingEvent +from tests.api_resources._websocket_resources import WEBSOCKET_RESOURCES -RESOURCES = ["realtime", "beta.realtime", "responses", "beta.responses", "live", "live.sideband", "live.forks"] +# Beta Realtime is SDK-owned; all generated resources come from the compiler. +RESOURCES = sorted({*WEBSOCKET_RESOURCES, "beta.realtime"}) RECONNECTING_RESOURCES = [name for name in RESOURCES if name != "beta.realtime"] EXTRA_HEADERS = {"api-key": "fake-key", "Cookie": "fake-cookie", "X-Custom": "fake-private-header"} FOLLOWS_REDIRECTS = hasattr(connect, "process_redirect") @@ -36,11 +39,17 @@ def resource(client: Any, name: str) -> Any: return client -def options(name: str) -> dict[str, Any]: +def options(client: Any, name: str) -> dict[str, Any]: + # The socket-free harness needs only synthetic values for required URL arguments. + parameters = inspect.signature(resource(client, name).connect).parameters return { "extra_headers": EXTRA_HEADERS, - **({"model": "fake-model"} if name.endswith("realtime") else {}), - **({"session_id": "live_fake"} if name in {"live.sideband", "live.forks"} else {}), + **{ + key: "fake-value" + for key, parameter in parameters.items() + if parameter.default is inspect.Parameter.empty + and parameter.kind in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY) + }, } @@ -112,7 +121,7 @@ async def test_async_websocket_redirects( websocket_base_url=base, http_client=async_http_client(), ) as client: - manager = resource(client, name).connect(**options(name)) + manager = resource(client, name).connect(**options(client, name)) if name in RECONNECTING_RESOURCES: manager.send({"type": "response.create"}) if succeeds: @@ -146,7 +155,7 @@ async def test_later_cross_origin_redirect_is_rejected(monkeypatch: pytest.Monke api_key="fake-key", websocket_base_url="wss://origin.test", http_client=async_http_client() ) as client: with pytest.raises(SecurityError): - async with resource(client, name).connect(**options(name)): + async with resource(client, name).connect(**options(client, name)): pytest.fail("Unexpected connection") assert len(handshakes.attempts) == 2 assert all(uri.host == "origin.test" for uri, _ in handshakes.attempts) @@ -164,7 +173,7 @@ async def test_async_websocket_reconnect_redirects(monkeypatch: pytest.MonkeyPat api_key="fake-key", websocket_base_url="wss://origin.test", http_client=async_http_client() ) as client: manager = resource(client, name).connect( - **options(name), on_reconnecting=reconnect, initial_delay=0, max_retries=1 + **options(client, name), on_reconnecting=reconnect, initial_delay=0, max_retries=1 ) async with manager as connection: connection._send_queue.enqueue("fake-queued-message") @@ -212,12 +221,12 @@ def test_sync_websocket_connector_is_unchanged(monkeypatch: pytest.MonkeyPatch, websocket_base_url="wss://origin.test", http_client=httpx2.Client(transport=httpx2.MockTransport(unexpected_http)), ) as client: - with resource(client, name).connect(**options(name)): + with resource(client, name).connect(**options(client, name)): pass error = redirect_error("wss://other.test/final") connect_mock.side_effect = error with pytest.raises(InvalidStatus) as caught: - with resource(client, name).connect(**options(name)): + with resource(client, name).connect(**options(client, name)): pytest.fail("Unexpected connection") assert caught.value is error assert connect_mock.call_count == 2 From fd78a48d2be489fde978696e1ad32032c20f0fab Mon Sep 17 00:00:00 2001 From: Yasser Ameur Date: Tue, 29 Sep 2026 22:57:37 +0000 Subject: [PATCH 8/9] chore(tests): mark sample_file.txt as text with LF line endings (#3879) - [x] I understand that this repository is auto-generated and my pull request may not be merged ## Changes being requested Add a `.gitattributes` marking `tests/sample_file.txt -text`. A default Windows checkout (`core.autocrlf=true`, the setting Git for Windows recommends) converts that fixture to CRLF because nothing tells Git it is a fixed byte fixture. `test_base64_file_input` base64-encodes the file and compares against a fixed LF-based digest, so it fails out of the box on a fresh Windows clone: AssertionError: assert '...IHdvcmxkIQ0K' == '...IHdvcmxkIQo=' With the attribute, `git ls-files --eol tests/sample_file.txt` shows `i/lf w/lf attr/-text` and `pytest tests/test_transform.py -k base64_file_input` goes from 2 failed to 2 passed on the same clone; the rest of `tests/test_transform.py` (60 tests) stays green. The fixture's bytes in the repository are unchanged. ## Additional context & links The file is not generated code, so nothing in the SDK regeneration touches it. Same shape as other repos' fixture handling for byte-exact test inputs. --------- Co-authored-by: Marcus Wood --- tests/.gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/.gitattributes diff --git a/tests/.gitattributes b/tests/.gitattributes new file mode 100644 index 0000000000..9b6b9c516c --- /dev/null +++ b/tests/.gitattributes @@ -0,0 +1 @@ +sample_file.txt -text From 1c4830b6e735d2ca3c4bd95f66467fa007f8b451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E8=B0=A6?= <89645338+simpleqt@users.noreply.github.com> Date: Tue, 29 Sep 2026 23:31:28 +0000 Subject: [PATCH 9/9] docs(examples): fix two stale example comments (#3877) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - `examples/parsing_tools_stream.py:27`: the comment credits `.parse_stream()` for the tool-call deserialization, but no such method exists in the SDK (`grep -rn parse_stream src/openai` → 0) — the wrapping comes from `pydantic_function_tool(...)`. The comment drifted when the example moved from `client.beta.chat.completions.stream`. - `examples/realtime/audio_util.py:16`: `CHUNK_LENGTH_S = 0.05 # 100ms` — 0.05 s is 50 ms (1200 frames at the module's 24 kHz rate). Comment corrected. Comment-only changes in examples/. ## Checklist - [x] I understand that this repository is auto-generated and my pull request may not be merged Co-authored-by: Marcus Wood --- examples/parsing_tools_stream.py | 2 +- examples/realtime/audio_util.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/parsing_tools_stream.py b/examples/parsing_tools_stream.py index b7dcd3d230..fabd56e123 100644 --- a/examples/parsing_tools_stream.py +++ b/examples/parsing_tools_stream.py @@ -24,7 +24,7 @@ class GetWeather(BaseModel): }, ], tools=[ - # because we're using `.parse_stream()`, the returned tool calls + # because the tool is built with `pydantic_function_tool(...)`, the returned tool calls # will be automatically deserialized into this `GetWeather` type openai.pydantic_function_tool(GetWeather, name="get_weather"), ], diff --git a/examples/realtime/audio_util.py b/examples/realtime/audio_util.py index 954a508675..990093505e 100644 --- a/examples/realtime/audio_util.py +++ b/examples/realtime/audio_util.py @@ -13,7 +13,7 @@ from openai.resources.realtime.realtime import AsyncRealtimeConnection -CHUNK_LENGTH_S = 0.05 # 100ms +CHUNK_LENGTH_S = 0.05 # 50ms SAMPLE_RATE = 24000 FORMAT = pyaudio.paInt16 CHANNELS = 1