Skip to Content
ExecutorsOpenAI Responses Executor

OpenAI Responses Executor

Executor for Ark agents backed by the OpenAI Responses API . Supports built-in tools (web search, code interpreter, file search), CFG/Lark grammar-constrained output, structured JSON output, MCP function tools, and stateless multi-turn threading via previous_response_id.

Overview

  • Built-in Toolsweb_search_preview, file_search, code_interpreter, computer_use configured via annotations
  • CFG/Grammar Output — Lark grammar constraints enforced at token level (not by prompt) via custom tool type
  • Structured Output — JSON schema enforcement via text.format annotation; response is a valid JSON object
  • Multi-turn Threading — Conversations thread via previous_response_id — no full history resent each turn
  • MCP Tools — Custom function tools from spec.tools wired through Ark’s tool infrastructure
  • GPT-5 Support — Reasoning parameter (effort) for gpt-5 models; temperature disabled automatically
  • OTEL Tracing — Optional observability via openinference-instrumentation-openai
  • A2A Protocol — Compliant with the Agent-to-Agent protocol for seamless Ark integration

Conversation Threading

Each request carries an A2A context_id → mapped to conversationId in the executor → used as a key to look up the last response_id on disk (/data/sessions/<conversationId>/response_id). Subsequent turns pass previous_response_id to the API instead of resending history — keeping payloads small and preserving server-side context.

Query CR A2A layer Executor OpenAI API ───────────────────── ────────────────── ──────────────────── ────────────────── conversationId: "abc" → context_id: "abc" → lookup session file → previous_response_id: "resp_xyz" save response.id ← response.id: "resp_xyz2"

Install

ark install marketplace/executors/executor-openai-responses

Or with DevSpace:

cd executors/openai-responses devspace deploy

Or with Helm:

helm install executor-openai-responses ./chart -n default --create-namespace

Prerequisites

Model CRD (Required)

apiVersion: ark.mckinsey.com/v1alpha1 kind: Model metadata: name: openai-gpt-4o spec: provider: openai type: completions model: value: gpt-4o config: openai: apiKey: valueFrom: secretKeyRef: name: openai-credentials key: api-key

For GPT-5 models, include baseUrl:

baseUrl: valueFrom: secretKeyRef: name: openai-credentials key: base-url

OpenAI Credentials Secret

kubectl create secret generic openai-credentials \ --from-literal=api-key=sk-... \ --from-literal=base-url=https://your-endpoint # optional

Annotations

All configuration uses annotations with cascade: ExecutionEngine → Agent → Query (highest priority wins, merged by type key).

Built-in Tools

annotations: executor-openai-responses.ark.mckinsey.com/tools: | [ { "type": "web_search_preview", "user_location": {"type": "approximate", "country": "GB", "city": "London", "region": "London"} } ]

Available types: web_search_preview, file_search, code_interpreter, computer_use.

MCP Tools

The executor runs an MCP client for tools declared on the Agent via spec.tools (type: mcp). The ARK SDK resolves those to request.mcpServers; the executor connects (streamable-HTTP or SSE), lists the allow-listed tools, and exposes each to the model as an OpenAI function tool. When the model calls one, the executor dispatches tools/call to the MCP server and feeds the result back into the tool loop.

spec: tools: - type: mcp name: tavily-search # Tool CR → MCPServer + toolName

The synthesized function name is <mcpServer>__<toolName>. Tool-name matching is hyphen/underscore-insensitive; if none of an agent’s declared tools match what the server exposes, the executor logs the available names.

Deterministic prefetch (MCP chain)

For latency-sensitive agents, mcp-prefetch runs a chain of MCP tool calls before the model, injects the results into the prompt, and lets the model answer in a single no-tool turn — removing the model’s decide-to-call round-trip. Each step may bind its result so later steps template it in with {<bind>.<field>}; {input} is the cleaned user input.

annotations: executor-openai-responses.ark.mckinsey.com/mcp-prefetch: | [ {"tool": "companies-house__resolve_uk_company", "args": {"company_name": "{input}"}, "bind": "ch", "label": "Companies House"}, {"tool": "tavily-search-mcp__tavily_search", "args": {"query": "{ch.company_name} {ch.locality} official website UK"}, "label": "Web search results"} ]

Each step: tool (a discovered <server>__<toolName>), args (string values are templated), optional bind (name for {bind.field} references), label (heading for the injected block), inject (default true). A single step object is also accepted. Domain logic lives in the agent config + the MCP servers — the executor stays generic. This is how a UK-company website-discovery agent hits ~2–4s while staying accurate: step 1 anchors the registered entity, step 2 searches biased by its town.

Reasoning (GPT-5 only)

annotations: executor-openai-responses.ark.mckinsey.com/reasoning: '{"effort": "low"}'

Effort values: "low", "medium", "high". Omitting the annotation defaults to "medium".

Use "low" for focused single-task agents (e.g. find one URL). Use "medium" or higher for agents that must gather multiple pieces of information (e.g. structured lookup with web search across several fields) — lower effort may not perform enough searches to find all required data.

File Attachments

Attach OpenAI file IDs to a query; the executor passes each as an input_file content part. File IDs come from the executor’s /v1/files API (below) or direct upload to the OpenAI Files API with the same credentials the agent’s Model uses.

annotations: executor-openai-responses.ark.mckinsey.com/file-ids: '["file-abc123"]'

Files attach on the turn they are new to the conversation: already-attached IDs are tracked per conversation and not re-sent (the threaded response state retains them).

Structured Output

Constrains the response to a JSON object matching the schema — enforced at token level:

annotations: executor-openai-responses.ark.mckinsey.com/output-schema: | { "type": "object", "properties": { "company_name": {"type": "string"}, "website_url": {"type": "string"} }, "required": ["company_name", "website_url"], "additionalProperties": false }

Files API and UI

The executor serves an OpenAI-compatible Files API and a chat + upload UI at GET / on the pod:

  • POST /v1/files — multipart upload (file, purpose); proxied to the OpenAI Files API
  • GET /v1/files — list; DELETE /v1/files/{id} — delete
  • POST /chat — SSE chat with optional file_ids selection (UI shortcut, bypasses the Ark control plane)

All endpoints accept ?agent=<namespace>/<name>: credentials resolve from that agent’s Model CRD, so uploads land in the OpenAI project the agent’s Responses calls use, and listings are scoped to that agent’s uploads (UPLOADED_FILES_ONLY, see the README ).

Note: conversation threading uses previous_response_id, which OpenAI does not support for Zero Data Retention organizations. On ZDR orgs each turn runs fresh — the executor detects the provider error, resets the stored conversation state, and returns a clear message telling the caller to retry.

Examples

See examples/ for ready-to-use YAML manifests and demo scripts.

Running the demo

Against a live cluster:

# Apply all CRDs and run each example, printing prompt, input and response examples/demo.sh

Locally without Kubernetes:

export OPENAI_API_KEY=sk-... export OPENAI_BASE_URL=https://your-endpoint # optional export MODEL_NAME=gpt-5.2-2025-12-11 # optional python3 examples/demo_local.py

Example manifests

ExampleWhat it shows
website-search-agent.yamlweb_search_preview with UK location context
company-lookup-agent.yamlWeb search + structured JSON output (company data)
sql-generator-agent.yamlCFG/Lark grammar-constrained SQL generation
dsl-generator-agent.yamlCFG/Lark grammar for a functional pipeline DSL
companies-house-agent.yamlMCP function tools via spec.tools

Configuration

Env VarDefaultDescription
SESSIONS_DIR/data/sessionsDirectory for persisting response_id per conversation
MAX_TOOL_ITERATIONS10Max function-call loop iterations before returning
OTEL_INSTRUMENTATION_ENABLEDfalseEnable OpenAI OTEL instrumentation
PORT8000HTTP server port

Data Flow and Encryption

This section covers data surfaces specific to the OpenAI Responses executor. For platform-level surfaces (etcd, Kubernetes Secrets, broker, OTel collector, pod logs), see the Data Flow and Encryption  operations guide.

Data at rest

SurfaceWhat lands thereEncrypted by default?How to protect
Session response IDs (/data/sessions/<conversationId>/response_id)A single OpenAI response UUID per conversation. No message content — just the ID used for previous_response_id threading.No. Plaintext file on the PVC.Use an encrypted PersistentVolume. Note: response IDs alone do not contain message content, but they can be used to retrieve conversation history from the OpenAI API.
OpenAI server-side stateFull conversation history, tool outputs, file search indexes, code interpreter state. Retained server-side by OpenAI and linked by response_id.Managed by OpenAI.Review OpenAI’s data retention and encryption policies. The executor does not control server-side storage.

Data in transit

HopProtocolTLS by default?Notes
Executor → OpenAI APIHTTPSYes. The OpenAI Python SDK enforces HTTPS by default.Custom baseUrl from the Model CRD can override — ensure any proxy or Azure endpoint uses HTTPS.
Executor → OpenAI built-in toolsHTTPSYes. Tool execution (web search, code interpreter, file search) happens server-side within OpenAI’s infrastructure.User location data (country, city, region) is sent to OpenAI for web_search_preview context.
Controller → executor (A2A)HTTPNo.Deploy a service mesh for mTLS between pods.

Logging

  • The executor logs agent name, model name, conversation ID, and tool types at info level.
  • Function tool arguments are logged unmasked at info level when tool calls are executed. If tools receive sensitive inputs, configure your log aggregator to filter these entries.
  • API keys are retrieved at runtime from Model CRDs and passed directly to the SDK client — they are not logged except in unhandled error tracebacks.

Data retention and disposal

The executor does not manage data lifecycle — retention and cleanup are deployment configuration.

  • Session response IDs: Files in /data/sessions/ accumulate indefinitely on the PVC. Schedule a CronJob to prune entries older than your retention window. The PVC survives helm uninstall — delete it explicitly when decommissioning.
  • OpenAI server-side state: Conversation history linked by response_id is retained by OpenAI according to their data retention policies. The executor has no mechanism to request deletion. Deleting the local response_id file breaks the threading link but does not remove data from OpenAI’s servers. Review OpenAI’s data retention terms for your usage tier.
Last updated on