Bug Report: CrewAI: LLM.call wrap never fires on crewai >= 1.x native providers, so no LLM span is emitted

Author: IdoGol24Created Sep 1, 2026Updated Sep 3, 2026

Which component is this bug for?

All Packages

Description

Component: CrewAI Instrumentation — not in the dropdown, so "All Packages."

_instrument wraps crewai.llm LLM.call (instrumentation.py#L93-L94), but on crewai 1.15.18 that wrap can never be reached on the native-provider path, so wrap_llm_call never runs — no {model}.llm span, and the duration histogram in _record_duration never records.

crewai.llm.LLM.__new__ is a factory that routes to native provider classes rather than returning an LLM:

def __new__(cls, model: str, is_litellm: bool = False, **kwargs) -> LLM:
    """Factory method that routes to native SDK or falls back to LiteLLM."""

The resulting object is not in LLM's hierarchy at all:

>>> a = Agent(role='r', goal='g', backstory='b')
>>> type(a.llm)
crewai.llms.providers.openai.completion.OpenAICompletion
>>> isinstance(a.llm, crewai.llm.LLM)
False
>>> [c.__name__ for c in OpenAICompletion.__mro__]
['OpenAICompletion', 'BaseLLM', 'BaseModel', 'ABC', 'object']

So patching crewai.llm.LLM.call patches a class the agent never instantiates.

Reproduction steps

  1. pip install crewai==1.15.18 traceloop-sdk==0.62.3 opentelemetry-instrumentation-crewai==0.62.3
  2. Traceloop.init(...), build a crew with a default Agent (no explicit LLM), run Crew.kickoff().
  3. Inventory the exported span names.

Expected behavior

A {model}.llm span per LLM call, as wrap_llm_call is written to produce, plus the gen_ai.client.operation.duration recording.

Actual Behavior with Screenshots

No {model}.llm span. Full inventory from a real run:

   3  openai.chat
   1  Support Responder.agent
   1  <task description>.task
   1  crewai.workflow

Python Version

3.12.3

Provide any additional context for the Bug.

Scope: I verified the native OpenAI provider route only. LLM.__new__ also has a LiteLLM fallback (is_litellm=True), and I haven't checked whether that path yields a real crewai.llm.LLM instance where the existing wrap would still fire. So this may be "dead for native providers" rather than "dead everywhere" — worth confirming on your side.

On the fix: BaseLLM is the common ancestor and does define call, but OpenAICompletion overrides it, so wrapping BaseLLM.call wouldn't intercept either. The right seam is probably the provider classes, or whatever single funnel exists upstream of them — you'll know that better than I do. Happy to send a PR once you've picked one.

Related: #4452 covers the missing tool-execution span in the same package. (The one I previously opened)

Have you spent some time to check if this bug has been raised before?

  • I checked and didn't find similar issue

Are you willing to submit PR?

Yes I am willing to submit a PR!