Skip to content

feat: add Cerebras integration to the Python SDK#7342

Open
NishchayMahor wants to merge 1 commit into
comet-ml:mainfrom
NishchayMahor:feat/cerebras-integration
Open

feat: add Cerebras integration to the Python SDK#7342
NishchayMahor wants to merge 1 commit into
comet-ml:mainfrom
NishchayMahor:feat/cerebras-integration

Conversation

@NishchayMahor

Copy link
Copy Markdown
Contributor

Summary

Adds a Cerebras integration to the Opik Python SDK, so calls made with the native cerebras-cloud-sdk client are automatically logged as Opik LLM spans:

from cerebras.cloud.sdk import Cerebras
from opik.integrations.cerebras import track_cerebras

client = track_cerebras(Cerebras())
client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[{"role": "user", "content": "Why is the sky blue?"}],
)

Cerebras (very fast inference for Llama and other open models) has a distinct native SDK, so the OpenAI wrapper (track_openai) can't instrument it — this adds first-class support, matching the existing standalone integrations.

Details

track_cerebras() follows the existing OpenAI/Anthropic pattern:

  • Wraps chat.completions.create() on both Cerebras and AsyncCerebras, including stream=True (sync + async streaming via aggregated chunks).
  • Records the span provider as "cerebras"; Cerebras returns OpenAI-shaped usage, so token usage is parsed with the OpenAI converter (the comment notes this denotes payload format, not the span provider).
  • Graceful span/trace finalization with error_info on failures.

Files:

  • src/opik/integrations/cerebras/track_cerebras, decorator, chunk aggregator, stream patchers.
  • tests/library_integration/cerebras/ — mock-based unit tests + requirements.txt.
  • CI: lib-cerebras-tests.yml + registration in lib-integration-tests-runner.yml.

Testing

pytest tests/library_integration/cerebras/4 passed (sync happy-path with full trace-tree assertion, async, and error handling), using the fake_backend fixture and a mocked transport so no Cerebras API key is required. ruff and mypy clean.

Happy to add a documentation/cookbook page as a follow-up if preferred.

Add track_cerebras() to wrap Cerebras / AsyncCerebras clients so calls to
chat.completions.create() (including stream=True) are logged as Opik LLM
spans, following the existing OpenAI/Anthropic integration pattern. Cerebras
returns OpenAI-shaped payloads, so usage is parsed with the OpenAI converter
while the span provider is recorded as 'cerebras'. Adds mock-based unit tests
and wires the cerebras suite into the integration runner.
@NishchayMahor NishchayMahor requested review from a team as code owners July 5, 2026 06:33
@github-actions github-actions Bot added dependencies Pull requests that update a dependency file python Pull requests that update Python code Infrastructure tests Including test files, or tests related like configuration. Python SDK labels Jul 5, 2026
Comment on lines +26 to +30
aggregated_response = {
"choices": [{"index": 0, "message": {"role": "", "content": ""}}],
"created": first_chunk.created,
"id": first_chunk.id,
"model": first_chunk.model,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate chunk aggregation

aggregate() is a near copy of opik/integrations/openai/chat_completion_chunks_aggregator.py:22-63, so OpenAI and Cerebras chunk stitching will drift if this logic changes; should we extract it into a reusable helper?

Severity

Want Baz to fix this for you? Activate Fixer

Comment on lines +48 to +49
if delta.content:
text_chunks.append(delta.content)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drops streamed reasoning output

delta.reasoning is dropped when the reducer aggregates streamed choices, so reasoning-enabled completions log a synthetic choices[0].message without the reasoning text and the span output is incomplete — should we preserve it too, as Cerebras’ official reasoning docs say it’s delivered in delta.reasoning?

Severity web_search

Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
sdks/python/src/opik/integrations/cerebras/chat_completion_chunks_aggregator.py around
lines 48-49 inside the `aggregate` function’s loop, the code currently appends only
`delta.content` into `text_chunks` and never copies `delta.reasoning` from the streamed
chunks. Refactor the aggregation to also collect `delta.reasoning` tokens (e.g., a
separate buffer) and set them onto the synthetic
`aggregated_response['choices'][0]['message']` in the appropriate field so downstream
span/log output includes reasoning-enabled text. Ensure this works when reasoning is
present across multiple streamed chunks by concatenating all reasoning tokens in order,
similar to how `content` is concatenated.

Comment on lines +33 to +37
def Stream__iter__decorator(dunder_iter_func: Callable) -> Callable:
@functools.wraps(dunder_iter_func)
def wrapper(self: cerebras.Stream) -> Iterator[StreamItem]:
try:
accumulated_items: List[StreamItem] = []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate stream patching

patch_sync_stream/patch_async_stream duplicate the opik/integrations/openai/stream_patchers.py:30‑157 logic almost verbatim for cerebras.Stream, so any fix to generations_aggregator or finally_callback has to be mirrored in both places and can drift — should we parameterize the shared patcher instead?

Severity

Want Baz to fix this for you? Activate Fixer

Comment on lines +43 to +47
LOGGER.debug(
"Exception raised from cerebras.Stream.",
str(exception),
exc_info=True,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging call raises formatting error

In both the sync and async stream wrappers, LOGGER.debug("Exception raised from cerebras.Stream.", str(exception), exc_info=True) passes str(exception) to a message with no %s, so logging raises a TypeError before the debug line is emitted and can interrupt exception handling while the span is still open — should we change it to LOGGER.debug("Exception raised from cerebras.Stream: %s", exception, exc_info=True)?

Severity

Want Baz to fix this for you? Activate Fixer

Other fix methods

Fix in Cursor

Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
sdks/python/src/opik/integrations/cerebras/stream_patchers.py around lines 43-47 in
patch_sync_stream’s Stream__iter__decorator exception handler, the LOGGER.debug call
passes str(exception) as a positional arg to a message string with no formatting
placeholders, which can raise TypeError during logging and prevent cleanup. Refactor
that logging line to use standard logging formatting with a “%s” placeholder (e.g.,
append “: %s” to the message and pass the exception as the corresponding argument)
while keeping exc_info=True. Do the same for the analogous LOGGER.debug call in
patch_async_stream around lines 96-100 inside AsyncStream__aiter__decorator.

Comment on lines +4 to +8
import cerebras.cloud.sdk as cerebras

from opik.types import LLMProvider

from . import cerebras_chat_completions_decorator, chat_completion_chunks_aggregator

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional import crashes package load

sdks/python/src/opik/integrations/cerebras/__init__.py imports cerebras.cloud.sdk and the decorator helpers at module load, so import opik.integrations.cerebras raises ModuleNotFoundError in environments without cerebras-cloud-sdk before track_cerebras() is reached — should we move those imports behind the public function boundary or guard them like the other optional integrations, as .agents/skills/python-sdk/SKILL.md requires?

Severity

Want Baz to fix this for you? Activate Fixer You can also update your AI coding guidelines based on this comment by apply pr to [branch name]

Other fix methods

Fix in Cursor

Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
sdks/python/src/opik/integrations/cerebras/opik_tracker.py around lines 1-70,
`track_cerebras()` relies on `import cerebras.cloud.sdk as cerebras` and module-scope
imports of the Cerebras decorator modules, which execute during package import and can
raise ModuleNotFoundError when the optional `cerebras-cloud-sdk` isn’t installed.
Refactor by removing the top-level Cerebras SDK import and any other Cerebras-runtime
imports from module scope; instead, perform them inside `track_cerebras()` (and
`_extract_metadata_from_client` if needed) with a clear error message if Cerebras
isn’t installed. Keep typing aliases (e.g., `TypeVar`) behind `typing.TYPE_CHECKING`
or adjust them so they don’t require the Cerebras SDK at import time.

@NishchayMahor

Copy link
Copy Markdown
Contributor Author

Same as #7341 (Groq) — these three points are intentional consistency with the existing OpenAI/Anthropic integrations:

  1. The aggregator's try/except → None mirrors integrations/openai/chat_completion_chunks_aggregator.py.
  2. stream_patchers deliberately follows the OpenAI integration's structure (Cerebras's SDK is OpenAI-shaped; only Stream/AsyncStream, a subset). A shared base for OpenAI/Groq/Cerebras would be a separate refactor.
  3. import cerebras.cloud.sdk at module top matches import anthropic in the anthropic integration; it's opt-in, so import opik doesn't pull it. Happy to adjust any of these.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file Infrastructure Python SDK python Pull requests that update Python code tests Including test files, or tests related like configuration.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant