Skip to content
Merged
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
128 changes: 47 additions & 81 deletions agentops/instrumentation/crewai/instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from agentops.semconv import SpanAttributes, AgentOpsSpanKindValues, Meters, ToolAttributes, MessageAttributes
from .crewai_span_attributes import CrewAISpanAttributes, set_span_attribute


# Initialize logger
logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -411,91 +410,58 @@
def wrap_llm_call(
tracer, duration_histogram, token_histogram, environment, application_name, wrapped, instance, args, kwargs
):
try:
llm = instance.model if hasattr(instance, "model") else "llm"
# To get the model provider (e.g. "openai") or the model name (e.g. "gpt-4o-mini")
provider = llm.split("/")[0] if "/" in llm else llm.split("-")[0]

provider_instrumentor = {
"gpt": "OpenAIInstrumentor",
"openai": "OpenAIInstrumentor",
"claude": "AnthropicInstrumentor",
"anthropic": "AnthropicInstrumentor",
"google": "GoogleGenerativeAIInstrumentor",
"gemini": "GoogleGenerativeAIInstrumentor",
"ibm": "IBMWatsonXInstrumentor",
"watsonx": "IBMWatsonXInstrumentor",
"agents": "OpenAIAgentsInstrumentor",
}

instrumentor = provider_instrumentor.get(provider.lower())

if instrumentor:
logger.debug(f"Skipping instrumentation for CrewAI LLM call for {provider} and using {instrumentor}")
result = wrapped(*args, **kwargs)
return result
else:
logger.debug(f"Instrumenting CrewAI LLM call for provider: {provider}")
with tracer.start_as_current_span(f"{llm}.llm", kind=SpanKind.CLIENT, attributes={}) as span:
start_time = time.time()
try:
span.set_attribute(TELEMETRY_SDK_NAME, "agentops")
span.set_attribute(SERVICE_NAME, application_name)
span.set_attribute(DEPLOYMENT_ENVIRONMENT, environment)
llm = instance.model if hasattr(instance, "model") else "llm"
with tracer.start_as_current_span(f"{llm}.llm", kind=SpanKind.CLIENT, attributes={}) as span:
start_time = time.time()
try:
span.set_attribute(TELEMETRY_SDK_NAME, "agentops")
span.set_attribute(SERVICE_NAME, application_name)
span.set_attribute(DEPLOYMENT_ENVIRONMENT, environment)

Check warning on line 419 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L413-L419

Added lines #L413 - L419 were not covered by tests

CrewAISpanAttributes(span=span, instance=instance)
CrewAISpanAttributes(span=span, instance=instance)

Check warning on line 421 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L421

Added line #L421 was not covered by tests

result = wrapped(*args, **kwargs)
result = wrapped(*args, **kwargs)

Check warning on line 423 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L423

Added line #L423 was not covered by tests

# Set prompt attributes from args
if args and isinstance(args[0], list):
for i, message in enumerate(args[0]):
if isinstance(message, dict):
if "role" in message:
span.set_attribute(MessageAttributes.PROMPT_ROLE.format(i=i), message["role"])
if "content" in message:
span.set_attribute(MessageAttributes.PROMPT_CONTENT.format(i=i), message["content"])

# Set completion attributes from result
if result:
span.set_attribute(MessageAttributes.COMPLETION_CONTENT.format(i=0), str(result))
span.set_attribute(MessageAttributes.COMPLETION_ROLE.format(i=0), "assistant")

# Set token usage attributes from callbacks
if (
"callbacks" in kwargs
and kwargs["callbacks"]
and hasattr(kwargs["callbacks"][0], "token_cost_process")
):
token_process = kwargs["callbacks"][0].token_cost_process
if hasattr(token_process, "completion_tokens"):
span.set_attribute(
SpanAttributes.LLM_USAGE_COMPLETION_TOKENS, token_process.completion_tokens
)
if hasattr(token_process, "prompt_tokens"):
span.set_attribute(SpanAttributes.LLM_USAGE_PROMPT_TOKENS, token_process.prompt_tokens)
if hasattr(token_process, "total_tokens"):
span.set_attribute(SpanAttributes.LLM_USAGE_TOTAL_TOKENS, token_process.total_tokens)
# Set prompt attributes from args
if args and isinstance(args[0], list):
for i, message in enumerate(args[0]):
if isinstance(message, dict):
if "role" in message:
span.set_attribute(MessageAttributes.PROMPT_ROLE.format(i=i), message["role"])
if "content" in message:
span.set_attribute(MessageAttributes.PROMPT_CONTENT.format(i=i), message["content"])

Check warning on line 432 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L426-L432

Added lines #L426 - L432 were not covered by tests

if duration_histogram:
duration = time.time() - start_time
duration_histogram.record(
duration,
attributes={
SpanAttributes.LLM_SYSTEM: "crewai",
SpanAttributes.LLM_RESPONSE_MODEL: str(instance.model),
},
)
# Set completion attributes from result
if result:
span.set_attribute(MessageAttributes.COMPLETION_CONTENT.format(i=0), str(result))
span.set_attribute(MessageAttributes.COMPLETION_ROLE.format(i=0), "assistant")

Check warning on line 437 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L435-L437

Added lines #L435 - L437 were not covered by tests

# Set token usage attributes from callbacks
if "callbacks" in kwargs and kwargs["callbacks"] and hasattr(kwargs["callbacks"][0], "token_cost_process"):
token_process = kwargs["callbacks"][0].token_cost_process
if hasattr(token_process, "completion_tokens"):
span.set_attribute(SpanAttributes.LLM_USAGE_COMPLETION_TOKENS, token_process.completion_tokens)
if hasattr(token_process, "prompt_tokens"):
span.set_attribute(SpanAttributes.LLM_USAGE_PROMPT_TOKENS, token_process.prompt_tokens)
if hasattr(token_process, "total_tokens"):
span.set_attribute(SpanAttributes.LLM_USAGE_TOTAL_TOKENS, token_process.total_tokens)

Check warning on line 447 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L440-L447

Added lines #L440 - L447 were not covered by tests

if duration_histogram:
duration = time.time() - start_time
duration_histogram.record(

Check warning on line 451 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L449-L451

Added lines #L449 - L451 were not covered by tests
duration,
attributes={
SpanAttributes.LLM_SYSTEM: "crewai",
SpanAttributes.LLM_RESPONSE_MODEL: str(instance.model),
},
)

span.set_status(Status(StatusCode.OK))
return result
except Exception as e:
span.set_status(Status(StatusCode.ERROR, str(e)))
logger.error("Error in trace creation: %s", e)
raise e
except Exception as e:
logger.error(f"Error in provider detection: {e}")
raise e
span.set_status(Status(StatusCode.OK))
return result
except Exception as ex:
span.set_status(Status(StatusCode.ERROR, str(ex)))
logger.error("Error in trace creation: %s", ex)
raise

Check warning on line 464 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L459-L464

Added lines #L459 - L464 were not covered by tests


def wrap_tool_execution(tracer, duration_histogram, environment, application_name):
Expand Down
Loading