Skip to main content

Models

  • Recommended: gpt-4o (latest, best quality)
  • Fast/Cheap: gpt-4o-mini (fast, cost-effective)
  • Reasoning: o1, o1-mini (advanced reasoning)
  • Latest: gpt-4.1, gpt-4.5-preview (newest releases)

Python

With Tools

Multi-Agent

Transparent Responses API routing

For OpenAI models that support the Responses API (gpt-4o, gpt-4.1, gpt-4.5, gpt-5, o1, o3, o4, chatgpt-4o, and their azure/ / openai/ prefixes), PraisonAI uses the Responses endpoint automatically on the native client path โ€” no code change, no flag. Chat Completions is only used when a custom base_url is set or the installed openai SDK does not expose responses.
On the Responses branch, sync callers (agent.chat / agent.start) use the same transparent routing โ€” the client rebinds its async transport across asyncio.run loops, so a sync turn and the next sync turn stay on the Responses endpoint rather than silently swapping to Chat Completions.

Supplying history with tool calls

If you pass conversation history that includes an assistant turn with tool_calls, the content field may be any of:
  • a plain string: "Checking"
  • a list of text parts: [{"type": "text", "text": "Checking"}] (the Chat Completions multimodal shape)
  • empty โ€” "", None, [], or whitespace โ€” in which case only the tool call is emitted
Multimodal list content was fixed in PraisonAI PR #5695 (merged 2026-10-08). On earlier versions the same history raised AttributeError and silently fell back to Chat Completions.

Fallback is quieter now

Two spurious Responses API failed, falling back to Chat Completions: โ€ฆ WARNING lines were fixed in PraisonAI PR #5682 (merged 2026-10-08):
  • Orphan tool outputs no longer 400. If your history contains a role="tool" message whose tool_call_id has no matching assistant function_call in the same payload โ€” e.g. history trimming dropped the assistant turn, or a user turn follows a tool round from an earlier session โ€” the client now drops that function_call_output before sending. Before #5682 the Responses API rejected the payload with No tool call found for function call output with call_id โ€ฆ and the client logged a fallback WARNING for every such turn.
  • Sync callers no longer see โ€œEvent loop is closedโ€. The cached AsyncOpenAI instance is rebuilt whenever the running loop differs from the one it was bound to (the common case for sync agent.chat() / agent.start() which bridge into the async path via a fresh asyncio.run per call). Before #5682 the stale httpx transport raised Event loop is closed on reuse and the client logged a fallback WARNING for every turn.
The fallback mechanism is unchanged โ€” on a real Responses failure the client still falls back to Chat Completions, so answers are not lost. #5682 only stops the two spurious triggers above from firing.
Follow-up in PR #5859 (merged 2026-10-16). After #5682 rebinds the client on each sync turn, the previous loopโ€™s AsyncOpenAI is eventually garbage-collected. Before #5859 that GC fired httpx.AsyncClient.aclose() on whichever loop was running โ€” raising RuntimeError: Event loop is closed and logging Task exception was never retrieved at ERROR level. The cached client is now built with openai.DefaultAsyncHttpxClient() (same timeouts, limits, redirects) so no cross-loop aclose task is scheduled from __del__.Sync OpenAIClient.close() also changed: it used to call AsyncOpenAI.close() without awaiting it (closing nothing). It now closes the sync client and drops the async client reference. Use await client.aclose() or await agent.aclose() for async teardown.
With -W always::ResourceWarning, dropped clients may still print unclosed transport lines. They are cosmetic โ€” asyncioโ€™s transport finaliser releases the sockets, so nothing leaks.
Orphan function_call_output items are dropped while the Responses input is built โ€” the client scans assistant tool_calls first, then keeps only the tool outputs whose call_id matches one it emitted. The cached AsyncOpenAI is rebound whenever the running loop changes, so each sync turn gets a client bound to its own asyncio.run loop.
Reasoning model parameter normalization. Whenever a request goes through Chat Completions (custom base_url, the installed openai SDK has no responses, or a Responses call falls back), PraisonAI omits unset temperature/max_tokens instead of sending null, and for reasoning models (o1, o3, o4, gpt-5.x) maps an explicit max_tokens to max_completion_tokens (PR #5910). See Reasoning Models for the full behaviour table.

CLI

YAML