Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions python/packages/core/agent_framework/openai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
"RawOpenAIChatClient": ("agent_framework_openai", "agent-framework-openai"),
"OpenAIChatCompletionClient": ("agent_framework_openai", "agent-framework-openai"),
"OpenAIChatCompletionOptions": ("agent_framework_openai", "agent-framework-openai"),
"OpenAIChatMessagePreparer": ("agent_framework_openai", "agent-framework-openai"),
"OpenAIChatResponseContentsParser": ("agent_framework_openai", "agent-framework-openai"),
"RawOpenAIChatCompletionClient": ("agent_framework_openai", "agent-framework-openai"),
"OpenAIEmbeddingClient": ("agent_framework_openai", "agent-framework-openai"),
"OpenAIEmbeddingOptions": ("agent_framework_openai", "agent-framework-openai"),
Expand Down
4 changes: 4 additions & 0 deletions python/packages/core/agent_framework/openai/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ from agent_framework_openai import (
OpenAIChatClient,
OpenAIChatCompletionClient,
OpenAIChatCompletionOptions,
OpenAIChatMessagePreparer,
OpenAIChatOptions,
OpenAIChatResponseContentsParser,
OpenAIContentFilterException,
OpenAIContinuationToken,
OpenAIEmbeddingClient,
Expand All @@ -23,7 +25,9 @@ __all__ = [
"OpenAIChatClient",
"OpenAIChatCompletionClient",
"OpenAIChatCompletionOptions",
"OpenAIChatMessagePreparer",
"OpenAIChatOptions",
"OpenAIChatResponseContentsParser",
"OpenAIContentFilterException",
"OpenAIContinuationToken",
"OpenAIEmbeddingClient",
Expand Down
25 changes: 25 additions & 0 deletions python/packages/openai/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@ The generic OpenAI clients support both OpenAI and Azure OpenAI routing. Precede
explicit Azure inputs (`credential`, `azure_endpoint`, `api_version`) → OpenAI API key
(`OPENAI_API_KEY`) → Azure environment fallback (`AZURE_OPENAI_*`).

## Adapting the Chat Completions client to OpenAI-compatible endpoints

`OpenAIChatCompletionClient` targets the OpenAI Chat Completions wire format and is intentionally
kept free of provider-specific quirks. Many "OpenAI-compatible" providers (OpenRouter, vLLM,
Mistral, DeepSeek, Ollama, …) diverge on the edges — e.g. returning reasoning under
`reasoning` / `reasoning_content` / `reasoning_details`, or `content` as a list of chunks. Rather
than branching in core, the client exposes two optional callables so callers adapt it themselves:

- `response_parser: OpenAIChatResponseContentsParser` — `(message_or_delta, default_contents) -> contents`.
Post-processes the `Content` items parsed from each response choice. Receives the already-selected
`ChatCompletionMessage` (non-streaming) or `ChoiceDelta` (streaming) — the client resolves the
dispatch — so a parser reads provider fields directly (e.g. `getattr(msg, "reasoning", None)`) without
branching. Use it to surface non-standard fields for display. Applied per choice in both paths.
- `message_preparer: OpenAIChatMessagePreparer` — `(message, default_dicts) -> dicts`. Post-processes
the outgoing request message dicts built from each framework `Message` (called once per `Message`, for
every role including `system`/`developer`). Use it to echo provider-specific fields (e.g. vLLM
`reasoning`) back on later turns for multi-turn continuity. To correlate a surfaced-reasoning `Content`
with the dict the default serializer emitted for it, tag the `Content` via `additional_properties` in
the parser and match against `message.contents` rather than raw request-string matching.

Both default to `None` (no-op → byte-identical stock OpenAI behavior) and are constructor args on
`RawOpenAIChatCompletionClient` / `OpenAIChatCompletionClient`. Provider round-trips generally need
**both**: the parser surfaces the field for display, the preparer sends it back. Prefer a dedicated
client (e.g. `agent-framework-mistral`) when an endpoint diverges substantially.

## Dependencies

- `agent-framework-core` — core abstractions
Expand Down
4 changes: 4 additions & 0 deletions python/packages/openai/agent_framework_openai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from ._chat_completion_client import (
OpenAIChatCompletionClient,
OpenAIChatCompletionOptions,
OpenAIChatMessagePreparer,
OpenAIChatResponseContentsParser,
RawOpenAIChatCompletionClient,
)
from ._embedding_client import OpenAIEmbeddingClient, OpenAIEmbeddingOptions
Expand All @@ -33,7 +35,9 @@
"OpenAIChatClient",
"OpenAIChatCompletionClient",
"OpenAIChatCompletionOptions",
"OpenAIChatMessagePreparer",
"OpenAIChatOptions",
"OpenAIChatResponseContentsParser",
"OpenAIContentFilterException",
"OpenAIContinuationToken",
"OpenAIEmbeddingClient",
Expand Down
Loading
Loading