6ExampleClient — deterministic stub that satisfies :class:`BaseClient`.
10SDK-free and network-free. ``stream_chat`` and ``one_shot`` build a
11fake response from the last user message ("echo: <text>"). Useful as
12a template for new provider clients and as a test harness for code
13that needs a working :class:`BaseClient` without hitting a real API.
14``oc_diagnostics`` is the only external import — it's first-party
15Option C tooling, not a foreign SDK.
17When porting this file to a real provider:
19 1. Replace the constructor body with the SDK client construction
20 (e.g. ``self._sdk = OpenAI(api_key=..., base_url=...)``).
21 2. Replace ``stream_chat`` with a real streaming loop that yields
22 ``("reasoning", str)``, ``("content", str)``,
23 ``("tool_call", dict)``, and ``("usage", dict)`` chunks as the
24 SDK produces them. See ``providers/deepseek/client.py`` for the
26 3. Replace ``one_shot`` with a non-streaming completion call.
27 4. Replace ``list_models`` with a real API call returning model ids.
31- :class:`ExampleClient` — :class:`BaseClient` stub with no I/O.
32- :func:`_last_user_text` — pluck the most recent user message
33 content from the messages list.
34- Deterministic fake usage block (constant token counts) so tests
47- ``stream_chat`` always yields exactly one ``("content", str)``
48 chunk and one ``("usage", dict)`` chunk — no reasoning, no tool
50- ``one_shot`` returns a plain ``str`` — never ``None``.
51- ``list_models`` returns the static :data:`MODELS` keys.
52- No exceptions are raised under normal use; the stub is meant to
57- oc_diagnostics (structured debug logging via _dbg)
58- providers.example.models (MODELS registry whose keys list_models returns)
59- option_c_agent_contracts (lazy; SupportsCancellation type of the stream_chat cancellation token)
61from __future__
import annotations
63from typing
import Any, Iterator, TYPE_CHECKING
65from oc_diagnostics
import _dbg
68 from option_c_agent_contracts
import SupportsCancellation
70from .models
import MODELS
74 """Return the most recent user message's content, or empty string."""
75 for msg
in reversed(messages):
76 if msg.get(
"role") ==
"user":
77 content = msg.get(
"content")
78 if isinstance(content, str):
84 """Stub :class:`BaseClient` for the example provider.
86 Stores the constructor arguments so tests can assert on them, but
87 does nothing with them otherwise.
91 def __init__(self, api_key: str =
"", base_url: str =
"") ->
None:
95 _dbg(
"OC_CHAT.CLIENT", func, f
"ExampleClient base_url={base_url!r}", 4)
101 messages: list[dict],
104 effort: str |
None =
None,
105 extra_body: dict |
None =
None,
106 tools: list[dict] |
None =
None,
107 max_tokens: int |
None =
None,
108 cancellation:
"SupportsCancellation | None" =
None,
109 ) -> Iterator[tuple[str, Any]]:
110 """Yield a fixed sequence: one ``content`` chunk, then ``usage``.
112 Real providers stream multiple ``content`` chunks plus optional
113 ``reasoning`` and ``tool_call`` chunks before the final
114 ``usage`` chunk. See ``providers/deepseek/client.py``.
116 If *cancellation* is provided, the token is polled before each
117 yield; a cancelled token raises :class:`CancellationError` and
118 no further chunks are produced (Phase O3c).
120 text = f
"echo: {_last_user_text(messages)}"
121 if cancellation
is not None:
122 cancellation.raise_if_cancelled()
123 yield (
"content", text)
124 if cancellation
is not None:
125 cancellation.raise_if_cancelled()
128 "completion_tokens": len(text),
136 messages: list[dict],
139 effort: str |
None =
None,
140 extra_body: dict |
None =
None,
141 max_tokens: int |
None =
None,
143 """Return ``"echo: <last user msg>"`` synchronously."""
144 return f
"echo: {_last_user_text(messages)}"
149 """Return the curated example model ids (no network call)."""
150 return list(MODELS.keys())
str one_shot(self, list[dict] messages, str model, *, str|None effort=None, dict|None extra_body=None, int|None max_tokens=None)
Iterator[tuple[str, Any]] stream_chat(self, list[dict] messages, str model, *, str|None effort=None, dict|None extra_body=None, list[dict]|None tools=None, int|None max_tokens=None, "SupportsCancellation | None" cancellation=None)
list[str] list_models(self)
None __init__(self, str api_key="", str base_url="")
str _last_user_text(list[dict] messages)