complete and stream, with loader-owned retries and heuristic token estimates for countTokens.
Why
Use OpenAI when you need GPT-family models in the same app as Claude or Gemini. Enable theopenai block in tools.ai and route with model ids such as gpt-4o — no separate client enum like mailer.
Setup
- Confirm
apps/backend/package.jsonincludes"tooling-ai-openai": "workspace:*". - Run
make deps-installafter dependency changes. - Add
openaiundertools.aiinapps/backend/src/configuration/development.ts:
anthropic and google blocks in the same tools.ai object — see AI tooling overview.
- No
compose.ymlchanges are required for OpenAI. - Add to
.env.development:
- Verify:
Local observability
OpenAI requests surface through Refract’sai logger feature and ai.request.* metrics, not the OpenAI dashboard from this stack. Check backend logs for tokenEstimate: true on count operations.
Adding a new model id
- Add the model id to
tools.ai.openai.modelsin environment config. - Update
defaultModelif it should become the OpenAI default whenparams.modelis omitted and OpenAI is the primary provider. - Expose the id to callers only after it appears in
getAvailableModelsoutput. - Run
make test module=tooling-ai-openai.
Gotchas
countTokensignores the chat tokenizer API — estimates use joined message length ÷ 4; do not use for production billing without replacing the adapter.- Unknown
params.modelvalues throwAiValidationErrorbefore OpenAI is called. - Streaming chunks may report zero usage until the final yield; instrumentation picks up usage from the last chunk that includes token counts.
What’s next?
- AI tooling overview — multi-provider routing and timeouts
- Anthropic · Google Gemini
- Configuration
- Tooling system
