Skip to Content
AdaptersOpenAI / Codex Adapter

OpenAI / Codex Adapter

Overview

Mechanism: HTTP POST to OpenAI REST API (/v1/chat/completions) with stream: true.

Why OpenAI as secondary cloud provider:

  • Tenant choice: some tenants may have existing OpenAI contracts or preferences
  • GPT-4o is a capable alternative to Claude Sonnet for most copywriting tasks
  • Codex / o1 models are purpose-built for code generation — useful if agents need to write scripts or automation code
  • Fallback when Claude API has outages

When to use:

  • Any creative or analysis task as an alternative to Claude (tenant-configured)
  • Code generation tasks (Codex/o1 models)
  • Tenants who have opted for OpenAI-primary

Configuration

interface OpenAIAdapterConfig { model: string; // e.g. 'gpt-4o', 'gpt-4o-mini', 'o1', 'codex' baseUrl?: string; // default: https://api.openai.com/v1 env: { OPENAI_API_KEY: string }; timeoutMs: number; }

How Data Flows IN

POST https://api.openai.com/v1/chat/completions Content-Type: application/json { "model": "gpt-4o", "stream": true, "messages": [ { "role": "system", "content": "<system prompt + injected skills>" }, { "role": "user", "content": "<task prompt>" }, // ... prior conversation turns (for session continuity) { "role": "assistant", "content": "<prior assistant reply>" }, { "role": "user", "content": "<next task>" } ], "max_tokens": 8000 }

The full assembled system prompt (with tenant settings, RAG context, etc.) goes in messages[0]. Skills are prepended to the system message as plain Markdown. Prior conversation turns are appended as user/assistant pairs from sessions.messageHistory.


How Data Flows OUT — SSE Streaming

data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Why "},"index":0}]} data: {"id":"chatcmpl-abc","choices":[{"delta":{"content":"Your "},"index":0}]} data: {"id":"chatcmpl-abc","choices":[{"delta":{},"finish_reason":"stop"},"index":0}],"usage":{"prompt_tokens":4200,"completion_tokens":1800}} data: [DONE]

The adapter reads the response body as a stream, splits on \n, filters for data: lines, parses each JSON chunk, and accumulates delta.content. Each chunk emits a text_delta event for live UI streaming. [DONE] signals completion.


Session Handling

OpenAI has no native session resumption. Conversation history is maintained manually:

  • Stored as messageHistory: Message[] in the PostgreSQL sessions table
  • Each new task appends { role: 'user', content: taskPrompt } to the array
  • After completion, the assistant reply is appended as { role: 'assistant', content: result }
  • When approaching the context limit: older turns are summarised using a cheap model and replaced with the summary

Skills Injection

There is no --add-dir equivalent for OpenAI. Skills content is injected into the prompt directly:

  • Skills Markdown content is retrieved from MongoDB
  • Full text is concatenated and prepended to the system message: skillsContent + '\n\n---\n\n' + systemPrompt
  • All skills content is sent upfront with every request (unlike Claude’s --add-dir which is lazy)

Cost Source

Token counts come from the usage field in the final streaming chunk → MODEL_PRICING[model] × tokens.


Timeout

HTTP fetch with AbortController at timeoutMs. The activity run is marked failed with error: 'timeout' and BullMQ retry policy picks it up.

© 2026 Leadmetrics — Internal use only