Catalog PyPI
Back to packageRELEASE DETAILS

0.6.0

PyPI

agent-event-protocol

Python SDK for the Agent Event Protocol (AEP) — structured observability for multi-agent AI systems

agentautogencrewailanggraphllmmulti-agentobservabilityopentelemetrytelemetrytracing
Published29 Jul 2026
Direct dependencies15
Transitive dependenciesNot calculated

README

Version 0.6.0 documentation

AEP Python SDK

Python client library for the Agent Event Protocol — an observability framework for agent workflows.

Version: 0.6.0 · Python: ≥ 3.10 · Schema: AEP v0.2.0

📍 Project direction (2026-06): AEP is converging on OpenTelemetry rather than continuing as a standalone protocol. This SDK remains published and usable, and is the carry-forward / reference SDK — its framework auto-instrumentation, OTEL bridge, and signing feed contributions to the OTel GenAI semantic conventions.


Installation

From PyPI:

pip install agent-event-protocol

The PyPI distribution name is agent-event-protocol (the bare aep name was already taken on PyPI), but the import name is unchanged — you still write import aep.

From the repo root (development):

pip install -e "sdks/python[dev]"

Quick start

from aep import create_event, AEPClient

# Build a spec-compliant event
event = create_event(
    source="agent://my-agent",
    type="task.created",
    session_id="ses_001",
    trace_id="trc_001",
    payload={"task": "summarise document"},
)

# Emit to the AEP ingest server
with AEPClient(server_url="http://localhost:8787", api_key="aep_...") as client:
    result = client.emit(event)
    # {"accepted": True, "duplicate": False, "id": "evt_..."}

Environment variables are read automatically:

VariablePurposeDefault
AEP_INGEST_URLServer base URLhttp://localhost:8787
AEP_API_KEYBearer token—

Async client

import asyncio
from aep import create_event, AsyncAEPClient

async def main():
    event = create_event(
        source="agent://my-agent",
        type="task.completed",
        session_id="ses_001",
        trace_id="trc_001",
        payload={"result": "done"},
    )
    async with AsyncAEPClient() as client:
        result = await client.emit(event)

asyncio.run(main())

Event types

from aep import CORE_EVENT_TYPES, EventType

# String constants
print(CORE_EVENT_TYPES)
# ['task.created', 'task.updated', ..., 'error.raised']

# Enum access
EventType.TOOL_CALLED.value  # 'tool.called'

The 12 core types: task.created, task.updated, task.completed, task.failed, tool.called, tool.result, memory.read, memory.write, handoff.started, handoff.completed, policy.blocked, error.raised.


Multi-agent / sub-agent workflows

from aep import create_event, AEPClient

trace_id = "trc_workflow_001"
orch_session = "ses_orchestrator_001"
sub_session = "ses_subagent_001"

orch_event = create_event(
    source="agent://orchestrator",
    type="task.created",
    session_id=orch_session,
    trace_id=trace_id,
    payload={"goal": "research AI observability"},
    agent_role="orchestrator",
)

sub_event = create_event(
    source="agent://subagent",
    type="task.created",
    session_id=sub_session,
    trace_id=trace_id,       # same trace_id ties sessions together
    parent_session_id=orch_session,  # links to parent
    payload={"subtask": "web search"},
    agent_role="subagent",
)

with AEPClient() as client:
    client.emit_batch([orch_event, sub_event])
    tree = client.get_session_tree(orch_session)
    workflow = client.get_workflow(trace_id)

Auto-instrumentation (LangGraph, CrewAI, AutoGen, OpenAI Agents SDK & Claude Agent SDK)

Emit the full multi-agent DAG from a LangGraph, CrewAI, AutoGen AgentChat, OpenAI Agents SDK, or Anthropic Claude Agent SDK workflow with no changes to your code — one aep.instrument() call wires AEP events to the run, every sub-agent, each tool call, and the handoffs between them. Only the frameworks you actually use need be installed; instrumenting CrewAI, AutoGen, the OpenAI Agents SDK, or the Claude Agent SDK does not require LangChain.

pip install -e "sdks/python[langgraph]"   # adds langgraph + langchain-core
import aep
aep.instrument()          # reads AEP_INGEST_URL / AEP_API_KEY (or pass them in)

# ... build and run your StateGraph exactly as usual ...
app = graph.compile()
app.invoke({"topic": "AI agent observability"})

aep.flush()               # block until buffered telemetry is sent (see below)
# aep.uninstrument()      # optional: restore original behavior (also flushes)

What gets emitted, with causation preserved (trace_id, session_id, parent_session_id, causation_id):

LangGraph eventAEP event(s)Role
graph run (root)task.created → task.completed/failedorchestrator
node runtask.created → task.completed/failedsubagent
orchestrator → nodehandoff.started → handoff.completedorchestrator
tool calltool.called → tool.result(caller)
tool / node errorerror.raised / task.failed(caller)

Notes:

  • Tested against langgraph>=0.1. Internals vary across versions; if the expected hook isn't found, instrument() logs a warning and is a no-op — it never crashes your app, and it won't falsely report success.
  • Configuration: aep.instrument(server_url=..., api_key=...), or AEP_INGEST_URL / AEP_API_KEY env vars.
  • Implemented as a LangChain BaseCallbackHandler injected via RunnableConfig (the supported extension point), so it survives parallel node fan-out.
  • Emission is non-blocking — events are sent on a background worker so they never add network latency to your graph. Call aep.flush() before a short-lived process exits (or rely on the atexit flush / uninstrument()) to be sure they were delivered. The buffer is bounded and drops with a warning under sustained overload rather than blocking your workflow.
  • See demos/langgraph_multiagent.py for a runnable 10-node example.

CrewAI

pip install -e "sdks/python[crewai]"   # adds crewai (no LangChain needed)
import aep
aep.instrument()          # or aep.instrument(frameworks=["crewai"])

# ... build and kick off your Crew exactly as usual ...
crew.kickoff()

aep.flush()
CrewAI eventAEP event(s)Role
Crew.kickoff() (root)task.created → task.completed/failedorchestrator
each task (named for its agent)task.created → task.completed/failedsubagent
crew → agent dispatchhandoff.started → handoff.completedorchestrator
tool usagetool.called → tool.result(agent)
tool failureerror.raised(agent)
failed guardrail validationpolicy.blocked(task)

Notes:

  • Tested against crewai>=1.0. Implemented by subscribing to CrewAI's own event bus (crewai.events), the supported extension point — not by wrapping Crew/Agent internals. If the event API has drifted, instrument() warns and is a no-op (never crashes your app).
  • CrewAI runs each task through its assigned agent, so a task is the sub-agent session (named for that agent's role); an agent that runs outside any task (e.g. a hierarchical manager) gets its own sub-agent session.
  • Tool-call attribution is exact for sequential crews; with concurrent agents running tools at once, pairing a tool.result to its tool.called is best-effort (the events don't always carry a per-call id).
  • Guardrail failures map to policy.blocked (v0.6.0): a guardrail validation that fails (LLMGuardrailCompletedEvent with success=False) emits policy.blocked on the guarded task's session with the guardrail's name and error text plus retry_count (CrewAI retries failed validations — each failed attempt is one event). Passed validations emit nothing. On a CrewAI without guardrail events, everything else still instruments.
  • See demos/crewai_multiagent.py for a runnable 3-agent example that works offline with no LLM API key.

AutoGen AgentChat

pip install -e "sdks/python[autogen]"   # adds autogen-agentchat + autogen-ext (no LangChain needed)
import aep
aep.instrument()          # or aep.instrument(frameworks=["autogen"])

# ... build and run your team exactly as usual ...
await team.run(task="research and write a report")   # or team.run_stream(...)

aep.flush()
AutoGen eventAEP event(s)Role
team run / run_stream (root)task.created → task.completed/failedorchestrator
each agent (by message source)task.created → task.completedsubagent
team → agent dispatchhandoff.started → handoff.completedorchestrator
ToolCallRequestEvent → …ExecutionEventtool.called → tool.result(agent)
tool execution error (is_error)error.raised(agent)

Notes:

  • Tested against autogen-agentchat>=0.4 (developed on 0.7.x). AutoGen AgentChat has no callback registry or event bus, so the tracer taps the async event stream BaseGroupChat.run_stream yields (which team.run() consumes internally — so both entry points are covered). If the team base class has drifted, instrument() warns and is a no-op (never crashes your app).
  • Teams are the instrumented surface. A team is the orchestrator; each agent that speaks becomes a sub-agent session. In-team agents run through the AgentChat runtime, so they're captured once with no double-counting. A standalone single AssistantAgent run with no team is not instrumented — wrap it in a team.
  • Tool pairing is exact, even for parallel tool calls returned out of order: AutoGen tags each result with the call_id of its request, so no LIFO guessing is needed (unlike CrewAI).
  • Agent boundaries are inferred from message source (AutoGen emits no per-agent start/stop event), so a run-level failure marks only the orchestrator task.failed; observed sub-agents close task.completed.
  • See demos/autogen_multiagent.py for a runnable 2-agent team example that works offline with no LLM API key (via autogen-ext's ReplayChatCompletionClient).

OpenAI Agents SDK

pip install -e "sdks/python[openai-agents]"   # adds openai-agents (no LangChain needed)
import aep
aep.instrument()          # or aep.instrument(frameworks=["openai-agents"])

# ... build and run your agents exactly as usual ...
from agents import Runner
await Runner.run(triage_agent, "help me in Spanish")   # or Runner.run_sync(...)

aep.flush()
OpenAI Agents SDK trace/spanAEP event(s)Role
Runner.run trace (root)task.created → task.completedorchestrator
agent spantask.created → task.completed/failedsubagent
workflow → agent dispatchhandoff.started → handoff.completedorchestrator
function spantool.called → tool.result(agent)
function span error (span.error)error.raised(agent)

Notes:

  • Tested against openai-agents>=0.1 (developed on 0.17.x). Implemented by registering a tracing processor via agents.tracing.add_trace_processor — the SDK's supported, global, zero-code observation surface — alongside (not replacing) the SDK's own exporter. If the tracing API has drifted, instrument() warns and is a no-op (never crashes your app).
  • The run's trace is the orchestrator, and every agent is a sub-agent of it — matching how the SDK itself trees agents as siblings under the workflow. The real from_agent of a handoff is recorded on the handed-to agent's task.created payload as handoff_from, so the actual flow is preserved even though the parent edge is the workflow root.
  • Tool pairing is exact: a tool is a single function span carrying both its start and end, so tool.called → tool.result pair by span_id — no LIFO guessing. A tool nests on its owning agent's session (resolved by walking the span tree to the nearest enclosing agent).
  • Agents-as-tools (agent.as_tool(...)) produce both a tool.called / tool.result pair (for the as_tool function span) and a nested sub-agent task.* for the inner agent (parented to the calling agent) — a faithful double-representation of "the outer agent called a tool that was itself an agent", not a duplicate. The DAG stays a single trace with no dangling links.
  • Caveat — uncaught run errors aren't marked failed. The tracing surface only reports failures the SDK records on a span (e.g. a tool error). An uncaught exception from Runner.run is not delivered to processors — the spans and trace still close cleanly and the exception propagates to your caller — so such a run is recorded completed here. The exception itself remains your source of truth; AEP deliberately doesn't add a separate failure path that would race the SDK's own span/trace close.
  • Guardrail tripwires map to policy.blocked (v0.6.0): a guardrail span that ends with its tripwire triggered emits policy.blocked on the owning agent's session (policy = the guardrail's name, action_blocked = agent/<agent name> or workflow/<workflow name> — the gated run's identity), chained to that run via causation_id. Untriggered guardrails emit nothing (blocked-only semantics).
  • See demos/openai_agents_multiagent.py for a runnable handoff + tool example that works offline with no LLM API key (via a scripted Model).

Anthropic Claude Agent SDK

pip install -e "sdks/python[claude-agent]"   # adds claude-agent-sdk (no LangChain needed)
import aep
aep.instrument()          # or aep.instrument(frameworks=["claude-agent"])

# ... run your agent exactly as usual ...
from claude_agent_sdk import query
async for message in query(prompt="review the repo"):   # or ClaudeSDKClient(...)
    ...

aep.flush()
Claude Agent SDK hookAEP event(s)Role
top-level agent (per session_id)task.created → task.completedorchestrator
SubagentStart / SubagentStoptask.created / task.completedsubagent
top-level → sub-agent (Task)handoff.started → handoff.completedorchestrator
PreToolUse → PostToolUsetool.called → tool.result(agent)
PostToolUseFailureerror.raised(agent)
can_use_tool deny (wrapped)policy.blocked(agent)

Notes:

  • Permission denials map to policy.blocked (v0.6.0): when your app supplies a can_use_tool handler, AEP wraps it observationally — the handler's result passes through unchanged, and a deny additionally emits policy.blocked (policy: "can_use_tool", the deny message as reason, action_blocked: "tool.called/<tool_name>"). Attribution: the denial's context carries no session identifier, so the event lands on the denied tool's run (when PreToolUse fired first), else the single open session's root; with several sessions open and no correlation it is dropped rather than mislabeled. Runs without a can_use_tool handler have no in-process denial surface — interactive prompts and permission-rule denials happen inside the CLI and are not observable here.
  • Tested against claude-agent-sdk>=0.2 (developed on 0.2.x). Implemented by injecting observer hooks into ClaudeAgentOptions.hooks — the SDK's supported observation surface — at the two methods both entry points consume (InternalClient.process_query for query(), ClaudeSDKClient.connect for the streaming client). If the hooks API has drifted, instrument() warns and is a no-op (never crashes your app). Call aep.instrument() once at startup.
  • The top-level agent is the orchestrator (one per session_id); each Task sub-agent is a sub-agent of it. Every tool/sub-agent hook carries an agent_id and tool_use_id, so attribution and pairing are exact — a tool nests on its owning agent's session (the sub-agent named by agent_id if one is open, else the root), and tool.called/tool.result pair by tool_use_id. No inference, no LIFO guessing.
  • The injected hooks are pure observers — each returns {} (proceed, no decision) and swallows its own errors, so AEP can never alter or break your agent run. They coexist with any hooks you configure yourself.
  • Caveat — the top-level run is closed by the Stop hook (fired at the end of each turn). A multi-turn ClaudeSDKClient session therefore records one trace per turn (the root reopens on the next turn's first hook). Sub-agents still open/close within their turn.
  • See demos/claude_agent_multiagent.py for a runnable orchestrator + sub-agent + tools example that works offline with no API key and no claude binary (it replays scripted hooks through a real query() via a control-protocol fake transport).

Client API

AEPClient (sync) / AsyncAEPClient (async)

MethodAEPClient (sync)AsyncAEPClient (async)
emit(event)POST /events — returns response bodysame, await-able
emit_batch(events)Sequential; raises on first error, prior events already sentConcurrent (asyncio.gather); all complete before raising
get_sessions(*, limit, cursor)GET /sessions — paginated listsame, await-able
get_session_events(session_id, *, type, q, limit, cursor)GET /sessions/{id}/eventssame, await-able
get_session_tree(session_id)GET /sessions/{id}/treesame, await-able
get_session_export(session_id, *, format)GET /sessions/{id}/exportsame, await-able
get_workflow(trace_id)GET /workflows/{traceId}same, await-able
get_metrics()GET /metricssame, await-able
health()GET /healthsame, await-able
ready()GET /readysame, await-able

Retries (v0.5.0+)

Both clients automatically retry transient failures — connection/timeout errors, HTTP 429 and HTTP 5xx (honouring Retry-After on any retryable status, per RFC 7231) — with full-jitter exponential backoff. Other 4xx responses, and deterministic local errors (e.g. an unsupported URL scheme), are never retried. Retrying POST /events is safe because events carry a client-generated id and the server deduplicates on it (a replay returns "duplicate": true).

AEPClient(
    max_retries=3,            # retries after the initial attempt; 0 disables
    retry_backoff_base=0.5,   # seconds; delay ceiling is base * 2**attempt
    retry_backoff_max=30.0,   # hard cap per delay, also caps Retry-After
)

Since v0.5.0 every transport-level failure (including timeouts, previously a raw httpx.TimeoutException) is raised as AEPConnectionError after retries are exhausted.


HMAC signing

from aep import create_event, sign_event

event = create_event(source="agent://test", type="task.created",
                     session_id="ses_1", trace_id="trc_1", payload={})
sign_event(event, secret="my-hmac-secret")  # v2 (deep) by default
# event["signature"] == {"alg": "hmac-sha256", "value": "<base64>", "canon": "v2"}

# Or let the client sign automatically:
from aep import AEPClient
with AEPClient(hmac_secret="my-hmac-secret") as client:
    client.emit(event)  # signs (v2) before sending

Canonicalization versions (canon) — issue #59

The default canonical form is now v2 (deep): it recursively key-sorts the whole event including nested payloads, so the signature covers payload contents and carries a signature.canon: "v2" marker — payload tamper-evidence is on without opt-in. canonicalize_v2(event) exposes the deep form directly. It is byte-identical to the server and the Node and Go SDKs for JSON values shared across runtimes (locked by a server-derived known-answer test).

v1 is now legacy but still supported — pass canon="v1" for the envelope-only form, which sorts only top-level keys and drops nested object contents (covers the envelope but not nested payloads):

sign_event(event, secret="my-hmac-secret", canon="v1")  # legacy envelope-only

verify_signature is version-aware (honours canon; an absent marker accepts either form).

Compatibility: the v2 default requires a v2-aware server (one that includes server PR #60+). The current AEP server requires v2 and rejects legacy v1 with 401 — the v1 retirement is complete (issue #65, the successor to the #59 unification). canon="v1" is retained only for talking to an older self-hosted server that predates signature.canon support; a current server rejects it.


Offline audit-bundle verification

Verify a tamper-evident audit bundle (from GET /sessions/:id/audit-bundle, GET /workflows/:traceId/audit-bundle, or aep audit export) entirely offline — no server, no database — with just the bundle JSON and the audit signing secret:

import json
from aep import verify_audit_bundle

with open("bundle.json", encoding="utf-8") as fh:
    bundle = json.load(fh)

result = verify_audit_bundle(bundle, secret="my-audit-signing-secret")
# {"valid": True, "content_digest_match": True, "manifest_signature_valid": True,
#  "errors": [], "per_event": [...]}

if not result["valid"]:
    raise SystemExit(f"bundle failed verification: {result['errors']}")

It recomputes the content digest over the bundle's events and the HMAC signature over its manifest — both byte-identical to the server (and the Go/Node SDKs; locked by a shared known-answer fixture). Any post-hoc change — a mutated payload field, reordered/added/dropped events, an edited manifest, or the wrong secret — makes valid false. (Building/signing bundles stays server-side, where the signing secret lives.)


Validation

from aep import create_event, validate_event

event = create_event(...)
result = validate_event(event)
# {"valid": True, "errors": []}

# Errors include warnings prefixed with [warn] which don't affect validity

Exceptions

ExceptionWhen raised
AEPValidationErrorHTTP 400 — schema validation failed; has .errors: list[str]
AEPAuthErrorHTTP 401/403 — bad API key or insufficient scope
AEPRateLimitErrorHTTP 429 — rate limit hit; has .retry_after: int
AEPNotFoundErrorHTTP 404 — session or workflow not found
AEPServerErrorHTTP 5xx — server-side error; has .status_code: int
AEPConnectionErrorNetwork error reaching the server

Demo

A complete multi-agent research demo is in demos/subagent_research.py. It mirrors the JS demo and exercises the session tree and workflow APIs.

# Start the server first
npm run ingest   # from repo root

# Run the demo
cd sdks/python
python demos/subagent_research.py

Tests

cd sdks/python
pip install -e ".[dev]"

# Unit tests (no server needed)
pytest tests/unit/

# Integration tests (requires running server)
AEP_INGEST_URL=http://localhost:8787 pytest tests/integration/

Publishing / Releases

The SDK is published to PyPI as agent-event-protocol (import name stays aep) by the Release Python SDK workflow, which is triggered only by pushing a python-sdk-v* tag — never on a branch push or PR. Publishing uses PyPI Trusted Publishing (OIDC), so there is no API token to store or leak.

Like tags in general, python-sdk-v* tags are not branch-protected, so the release is gated twice and independently:

  1. verify — fails fast unless the tagged commit is an ancestor of origin/main (i.e. it landed via the PR-protected merge path), then builds the sdist + wheel and runs pytest. The approver sees a green pre-flight.
  2. publish — runs in the pypi-publish GitHub Environment, which has required reviewers. The upload to PyPI only happens after a human approves the deployment, and it ships the exact artifacts verify built and tested.

Maintainer setup (one-time)

Before the first release, configure the publisher side (cannot be done from code):

  • PyPI Trusted Publisher — on PyPI, add a GitHub Actions trusted publisher (use the pending publisher flow for the first-ever release, since the project doesn't exist on PyPI yet) with exactly:
    • Project name: agent-event-protocol
    • Owner: surpradhan · Repository: agent-event-protocol
    • Workflow: release-python-sdk.yml · Environment: pypi-publish
  • GitHub Environment — create an Environment named pypi-publish under Settings → Environments and add the release owners as Required reviewers. No secrets are stored (OIDC replaces the API token).

Cutting a release

# 1. Bump sdks/python/pyproject.toml `version` AND aep/__init__.py `__version__`
#    (keep them in sync) on a PR; squash-merge to main.
# 2. From main, tag the release commit and push the tag:
git tag python-sdk-v0.6.0
git push origin python-sdk-v0.6.0
# 3. Approve the `pypi-publish` deployment in the Actions UI once `verify` is green.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 15

Native requirements
15 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
httpx
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
httpx<1.0,>=0.27runtime
jsonschema
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
jsonschema<5.0,>=4.20runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest>=8; extra == "dev"runtime
pytest-asyncio
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest-asyncio>=0.23; extra == "dev"runtime
respx
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
respx>=0.21; extra == "dev"runtime
ruff
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
ruff==0.16.0; extra == "dev"runtime
langgraph
Environment
{
  "extras": "",
  "marker": "extra == \"langgraph\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
langgraph>=0.1.0; extra == "langgraph"runtime
langchain-core
Environment
{
  "extras": "",
  "marker": "extra == \"langgraph\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
langchain-core>=0.1.0; extra == "langgraph"runtime
crewai
Environment
{
  "extras": "",
  "marker": "extra == \"crewai\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
crewai>=1.0.0; extra == "crewai"runtime
autogen-agentchat
Environment
{
  "extras": "",
  "marker": "extra == \"autogen\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
autogen-agentchat>=0.4; extra == "autogen"runtime
autogen-ext
Environment
{
  "extras": "",
  "marker": "extra == \"autogen\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
autogen-ext>=0.4; extra == "autogen"runtime
openai-agents
Environment
{
  "extras": "",
  "marker": "extra == \"openai-agents\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
openai-agents>=0.1; extra == "openai-agents"runtime
claude-agent-sdk
Environment
{
  "extras": "",
  "marker": "extra == \"claude-agent\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
claude-agent-sdk>=0.2; extra == "claude-agent"runtime
opentelemetry-api
Environment
{
  "extras": "",
  "marker": "extra == \"otel\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
opentelemetry-api>=1.20.0; extra == "otel"runtime
opentelemetry-sdk
Environment
{
  "extras": "",
  "marker": "extra == \"otel\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
opentelemetry-sdk>=1.20.0; extra == "otel"runtime

Distribution files

2 collected
agent_event_protocol-0.6.0-py3-none-any.whl

bdist_wheel · 62.72 KB · Python py3

Source file
agent_event_protocol-0.6.0.tar.gz

sdist · 66.53 KB · Python source

Source file

Repository

PENDING
surpradhan/agent-event-protocol

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 21:53 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:47a647b87120b00a1259ef5562b299bdadef10f809496578ea3ac3101e902a05

Other collected versions

View all collected versions →