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: 81 additions & 47 deletions agentops/instrumentation/crewai/instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
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 @@ -410,58 +411,91 @@
def wrap_llm_call(
tracer, duration_histogram, token_histogram, environment, application_name, wrapped, instance, args, kwargs
):
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)
try:
llm = instance.model if hasattr(instance, "model") else "llm"

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L414-L415

Added lines #L414 - L415 were not covered by tests
# 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]

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L417

Added line #L417 was not covered by tests

provider_instrumentor = {

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#L419

Added line #L419 was not covered by tests
"gpt": "OpenAIInstrumentor",
"openai": "OpenAIInstrumentor",
"claude": "AnthropicInstrumentor",
"anthropic": "AnthropicInstrumentor",
"google": "GoogleGenerativeAIInstrumentor",
"gemini": "GoogleGenerativeAIInstrumentor",
"ibm": "IBMWatsonXInstrumentor",
"watsonx": "IBMWatsonXInstrumentor",
"agents": "OpenAIAgentsInstrumentor",
}

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

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L431

Added line #L431 was not covered by tests

if instrumentor:
logger.debug(f"Skipping instrumentation for CrewAI LLM call for {provider} and using {instrumentor}")
result = wrapped(*args, **kwargs)
return result

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L433-L436

Added lines #L433 - L436 were not covered by tests
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)

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L438-L444

Added lines #L438 - L444 were not covered by tests

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

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L446

Added line #L446 was not covered by tests

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

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L448

Added line #L448 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 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 457 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

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

Added lines #L451 - L457 were not covered by tests

# 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 462 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L460-L462

Added lines #L460 - L462 were not covered by tests

# Set token usage attributes from callbacks
if (

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L465

Added line #L465 was not covered by tests
"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(

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L470-L472

Added lines #L470 - L472 were not covered by tests
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 478 in agentops/instrumentation/crewai/instrumentation.py

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L475-L478

Added lines #L475 - L478 were not covered by tests

# 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)

if duration_histogram:
duration = time.time() - start_time
duration_histogram.record(
duration,
attributes={
SpanAttributes.LLM_SYSTEM: "crewai",
SpanAttributes.LLM_RESPONSE_MODEL: str(instance.model),
},
)
if duration_histogram:
duration = time.time() - start_time
duration_histogram.record(

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L480-L482

Added lines #L480 - L482 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 ex:
span.set_status(Status(StatusCode.ERROR, str(ex)))
logger.error("Error in trace creation: %s", ex)
raise
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

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

View check run for this annotation

Codecov / codecov/patch

agentops/instrumentation/crewai/instrumentation.py#L490-L498

Added lines #L490 - L498 were not covered by tests


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