Metadata-Version: 2.5
Name: huaweicloud-opentelemetry-instrumentation-crewai
Version: 1.0.0
Summary: Huawei Cloud standalone instrumentation for CrewAI (crewai)
License-Expression: Apache-2.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.9
Requires-Dist: crewai-core>=1.15.0
Requires-Dist: crewai>=1.15.0
Requires-Dist: opentelemetry-api>=1.42.0
Requires-Dist: opentelemetry-exporter-otlp>=1.42.0
Requires-Dist: opentelemetry-instrumentation>=0.60b1
Requires-Dist: opentelemetry-sdk>=1.42.0
Requires-Dist: opentelemetry-semantic-conventions-ai>=0.5.0
Requires-Dist: wrapt<2.0.0,>=1.0.0
Description-Content-Type: text/x-rst

Huawei Cloud OpenTelemetry Instrumentation — CrewAI
====================================================

Standalone OpenTelemetry instrumentation for `crewai`
(https://github.com/crewAIInc/crewAI), reporting to Huawei Cloud
AgentArts (APM / AOM). Fully isolated from the main probe package
(huaweicloud-opentelemetry-instrumentation), so it can be installed and
iterated independently.

Why standalone
--------------

- crewai 1.15+ (via crewai-core 1.15.24) hard-requires
  ``opentelemetry-api >= 1.42`` (the GenAI semantic conventions GA
  release). The main probe package pins OTel to ``1.39.1`` for its
  LangChain / AgentScope baselines. Mixing the two in one environment
  forces a single OTel version, so crewai is shipped as a separate
  wheel that declares ``>= 1.42`` independently.
- This package subscribes to crewai's own event bus
  (``crewai_event_bus``) to produce the span tree, so it does **not**
  depend on ``opentelemetry-instrumentation-langchain``.

Installation
------------

.. code-block:: bash

   pip install huaweicloud-opentelemetry-instrumentation-crewai

Quick start
-----------

1. Configure Huawei Cloud AgentArts environment variables:

.. code-block:: bash

   export agentarts_agentops_otel_agent_apm_enable=true
   export agentarts_agentops_otel_agent_aom_enable=true
   export agentarts_project_id=<project-id>
   export agentarts_agentops_apm_token=<apm-token>
   export agentarts_agentops_apm_exporter_endpoint=<endpoint>
   export agentarts_agentops_aom_access_code=<access-code>
   export agentarts_agentops_aom_exporter_endpoint=<endpoint>
   export agentarts_agentops_aom_prometheus_id=<prometheus-id>
   # optional agent metadata injected into every span
   export agent_domain_id=<domain-id>
   export agent_resource_id=<resource-id>
   export resource_type=agent

2. Start the application with the CLI wrapper (zero code change):

.. code-block:: bash

   opentelemetry-instrument python app.py

3. View the trace tree and metrics on AgentArts APM / AOM.

Span tree produced
------------------

::

   invoke_agent crew                              (AGENT, root)
   ├─ execute_task <task_name>                    (WORKFLOW)
   │  └─ chat <model>                            (LLM)
   ├─ execute_task <task_name>                    (WORKFLOW)
   │  └─ chat <model>                            (LLM)
   └─ execute_task <task_name>                    (WORKFLOW)
      └─ chat <model>                            (LLM)

A2A (Agent-to-Agent) delegation
--------------------------------

When the application delegates to a remote agent over the A2A protocol
(crewAI's optional ``a2a`` extra), the probe adds two more span kinds
under the ``execute_task`` span that runs the delegation:

::

   invoke_agent crew                              (AGENT, root)
   └─ execute_task research                       (WORKFLOW)
      └─ a2a.delegate <remote_agent_name>         (AGENT, local client side)
         └─ a2a.message turn=<n>                 (AGENT)

The remote agent runs in another process, so no span is created for it.
It is recorded as attributes on the ``a2a.delegate`` span instead:

===============================  ==========================================
Attribute                       Source
===============================  ==========================================
``a2a.endpoint``                remote agent URL
``a2a.remote.agent.name``       remote agent name
``a2a.protocol.version``        negotiated protocol version
``a2a.skill.id``                delegated skill
``a2a.turn.number``             conversation turn
``a2a.is_multiturn``            multi-turn conversation flag
``a2a.status``                  final delegation status
``a2a.context.id``              A2A protocol ``context_id``
===============================  ==========================================

``gen_ai.agent.name`` keeps meaning the *local* agent — the remote agent
name is deliberately written to ``a2a.remote.agent.name`` instead.

Likewise ``gen_ai.conversation.id`` keeps meaning the *local* session
(the ``session_id`` baggage, shared by every span of one user
conversation). The A2A ``context_id`` identifies the remote agent's own
conversation and is written to ``a2a.context.id``, so that the APM does
not split a single user conversation into several sessions.

For the trace to continue into the remote agent, the probe injects the
W3C ``traceparent`` into the outgoing A2A HTTP request. The peer needs
its own instrumentation to pick it up and open a matching server span.

The A2A support is entirely optional: when crewAI is installed without
the ``a2a`` extra, the probe registers no A2A handlers and patches
nothing.

Development
-----------

Run tests:

.. code-block:: bash

   pip install -e .[dev]
   python -m pytest test/
