flightdeck-sensor 0.10.0__tar.gz → 0.11.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/PKG-INFO +12 -10
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/README.md +9 -9
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/__init__.py +35 -4
- flightdeck_sensor-0.11.0/flightdeck_sensor/interceptor/langgraph.py +1299 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/pyproject.toml +9 -1
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/_lazy_patch_child.py +23 -0
- flightdeck_sensor-0.11.0/tests/unit/test_interceptor_langgraph.py +1433 -0
- flightdeck_sensor-0.11.0/tests/unit/test_interceptor_langgraph_runs.py +1420 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_lazy_patch.py +8 -4
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/uv.lock +107 -6
- flightdeck_sensor-0.10.0/flightdeck_sensor/interceptor/langgraph.py +0 -347
- flightdeck_sensor-0.10.0/tests/unit/test_interceptor_langgraph.py +0 -383
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/.gitignore +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/CLAUDE.md +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/Makefile +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/compat/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/compat/crewai_mcp.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/config.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/agent_id.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/context.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/errors.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/exceptions.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/import_hook.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/mcp_policy.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/policy.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/schemas.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/session.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/tool_capture.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/core/types.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/anthropic.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/base.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/claude_agent_sdk.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/crewai.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/litellm.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/llama_index.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/mcp.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/mcp_identity.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/openai.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/openai_agents.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/platform.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/interceptor/raw_views.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/provider.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/providers/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/providers/_access.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/providers/anthropic.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/providers/litellm.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/providers/openai.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/providers/protocol.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/py.typed +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/transport/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/transport/body_limit.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/transport/client.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/flightdeck_sensor/transport/retry.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/conftest.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/__init__.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/_child_process.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/_signal_child.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_agent_handoff.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_agent_id.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_agent_type_validation.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_anthropic_resource_patch.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_body_limit.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_compat_crewai_mcp.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_context.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_cross_agent_messages.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_custom_directives.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_deferred_stream_unread.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_egress_url_validation.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_errors.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_framework_attribution.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_identity_vectors.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_import_hook.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_init_defaults.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor_claude_agent_sdk.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor_crewai.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor_litellm.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor_litellm_routes.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor_llama_index.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_interceptor_openai_agents.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_llm_event_enrichment.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_2x_paths.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_availability.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_identity.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_interceptor.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_policy_emission_enriched.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_policy_enforcement.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_mcp_policy_enforcement_all_paths.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_openai_beta_chat.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_openai_constructed_resources.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_openai_parse_responses.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_originating_event_id.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_patch.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_policy.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_policy_decision_summary.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_policy_directive_events.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_policy_emission_enriched.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_policy_events.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_prompt_capture.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_provider_enum.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_providers.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_raw_stream_capture.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_session.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_session_lifecycle_enrichment.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_signal_shutdown.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_stop_reason_errors.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_streaming_usage.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_token_cost_fields.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_tool_capture_destination.py +0 -0
- {flightdeck_sensor-0.10.0 → flightdeck_sensor-0.11.0}/tests/unit/test_transport.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flightdeck-sensor
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: In-process agent observability sensor for Flightdeck
|
|
5
5
|
Project-URL: Repository, https://github.com/flightdeckhq/flightdeck
|
|
6
6
|
Author-email: Omri Arnon <omri.arnon@gmail.com>
|
|
@@ -24,6 +24,7 @@ Provides-Extra: dev
|
|
|
24
24
|
Requires-Dist: anthropic>=0.86; extra == 'dev'
|
|
25
25
|
Requires-Dist: claude-agent-sdk<0.3,>=0.2.168; extra == 'dev'
|
|
26
26
|
Requires-Dist: crewai>=1.14; (python_version < '3.14') and extra == 'dev'
|
|
27
|
+
Requires-Dist: deepagents<0.8,>=0.7; extra == 'dev'
|
|
27
28
|
Requires-Dist: httpx>=0.25; extra == 'dev'
|
|
28
29
|
Requires-Dist: langchain-anthropic<2,>=1; extra == 'dev'
|
|
29
30
|
Requires-Dist: langchain-mcp-adapters<0.4,>=0.3; extra == 'dev'
|
|
@@ -37,6 +38,7 @@ Requires-Dist: llama-index-tools-mcp>=0.1; extra == 'dev'
|
|
|
37
38
|
Requires-Dist: mcp<2,>=1.28; extra == 'dev'
|
|
38
39
|
Requires-Dist: mcpadapt>=0.0.6; extra == 'dev'
|
|
39
40
|
Requires-Dist: mypy>=2.4; extra == 'dev'
|
|
41
|
+
Requires-Dist: nest-asyncio>=1.6; extra == 'dev'
|
|
40
42
|
Requires-Dist: openai-agents<0.21,>=0.20; extra == 'dev'
|
|
41
43
|
Requires-Dist: openai>=1.26; extra == 'dev'
|
|
42
44
|
Requires-Dist: pytest-asyncio>=1.0; extra == 'dev'
|
|
@@ -317,7 +319,7 @@ is imported) only if your application imports it. `unpatch()` (and
|
|
|
317
319
|
| litellm (router that aggregates many providers behind one function surface) | `patch_litellm_functions` | `litellm.completion`, `litellm.acompletion`, `litellm.text_completion`, `litellm.atext_completion`, `litellm.responses`, `litellm.aresponses` (each with `stream=True`), `litellm.embedding`, `litellm.aembedding` |
|
|
318
320
|
| MCP (official Python `mcp` SDK, reached transitively by `langchain-mcp-adapters`, `llama-index-tools-mcp` and `mcpadapt`) | `patch_mcp_classes` | `mcp.client.session.ClientSession.initialize` on mcp 1.x / `.adopt` on mcp 2.x (server fingerprint capture, every 2.x handshake path), `.list_tools`, `.call_tool`, `.list_resources`, `.read_resource`, `.list_prompts`, `.get_prompt` (one `mcp_*` event type each), plus the stdio / SSE / streamable-HTTP / websocket transport client factories and mcp 2.x's `Client._build_session` for transport attribution. `call_tool` also enforces the MCP Protection Policy. Supported SDK range: `mcp>=1.28,<3`. |
|
|
319
321
|
| CrewAI (sub-agent sessions) | `patch_crewai_classes` | `crewai.Agent.execute_task` / `.aexecute_task` — each Crew member's turn lands as a child session (`session_start` / `session_end`) with `parent_session_id`, `agent_role` taken from `Agent.role`, and incoming / outgoing message capture gated on `capture_prompts` |
|
|
320
|
-
| LangGraph (sub-agent sessions) | `patch_langgraph_classes` | `langgraph.graph.StateGraph.add_node` —
|
|
322
|
+
| LangGraph and Deep Agents (sub-agent sessions) | `patch_langgraph_classes` (`patch_langgraph_runs` patches the graph runs alone; `patch()` applies it on the import of `langgraph.pregel`, so a functional-API application is covered) | `langgraph.graph.StateGraph.add_node` — each node of a graph you build, a function or a Runnable (`RunnableLambda`, `RunnableCallable`, an LCEL pipe, your own `ToolNode`), lands as a child session per run with `agent_role` taken from the node name; every such node is treated as agent-bearing unless narrowed with `init(langgraph_agent_node_pattern=...)`. The nodes `create_agent` and `create_react_agent` register (model, tools, middleware and model hooks) and generator nodes are not wrapped. `langgraph.pregel.Pregel.stream` / `astream` — a graph run started inside another graph run or a child (a compiled graph used as a node, a graph or an agent invoked from a node or a tool, each Deep Agents `task` sub-agent) lands as one child session, `agent_role` the run's name (`create_agent(name=...)`, the Deep Agents sub-agent's name), else the node it runs in (unless that node is one of `create_agent`'s own steps), else `subgraph`; a top-level run opens none. Each child nests under the child it runs in. An interrupt closes the child normally; async runs post their child's start and end off the event loop |
|
|
321
323
|
| LlamaIndex agent workflows (sub-agent sessions, `llama-index-core>=0.14`) | `patch_llama_index` | A span handler on LlamaIndex's root instrumentation dispatcher (no LlamaIndex method is replaced): each agent of a `FunctionAgent`, `ReActAgent`, `CodeActAgent` or `AgentWorkflow` run lands as a child session with `agent_role` the agent's name (the agent's model, tool and MCP calls stay on the sensor's session, as for CrewAI and LangGraph); an `AgentWorkflow` hand-off ends one child, records an `agent_handoff` signal on it and opens the next; a tool call the model wrote as text (ReAct, CodeAct) is reported once as a `tool_call`, its arguments and output under `capture_prompts` |
|
|
322
324
|
| Claude Agent SDK (`claude-agent-sdk>=0.2.168,<0.3`) | `patch_claude_agent_sdk` | `query()` (however it was imported) and `ClaudeSDKClient` — each run lands as its own `claude_agent_sdk` session keyed by the Claude Code session id, with a `post_call` per assistant message (tokens, cache split, billing mode) and a `tool_call` per tool use, read from the SDK's message stream; a Claude Code plugin loaded into the run stays silent. `PreToolUse` and `UserPromptSubmit` callbacks added after the caller's hooks apply the run's directives (a stop denies the next tool call and blocks prompts; budget warnings reach the run) and the MCP Protection Policy. Install with `pip install flightdeck-sensor[claude-agent-sdk]`. |
|
|
323
325
|
| OpenAI Agents SDK (`openai-agents>=0.6`, sub-agent sessions) | `patch_openai_agents` | `AgentRunner.run` / `.run_streamed` (so `Runner.run`, `run_sync` and `run_streamed`) and the `run` of the four guardrail classes — each agent that runs lands as a child session with `agent_role` taken from `Agent.name`, an agent used as a tool nests under the agent that called it, a hand-off posts `agent_handoff` on the agent handing off, a guardrail that fires posts `guardrail_tripwire` (names only), and the run's conversation id lands in the child's context as `gen_ai_conversation_id`. Model, tool and MCP calls stay on the sensor's session (the OpenAI and MCP interceptors meter them); a shutdown also stops the run when the next agent starts or hands off. Patched only when `agents` comes from the `openai-agents` distribution. Install with `pip install flightdeck-sensor[openai-agents]`. |
|
|
@@ -326,7 +328,7 @@ is imported) only if your application imports it. `unpatch()` (and
|
|
|
326
328
|
|
|
327
329
|
Any framework that calls a model through the Anthropic or OpenAI SDK or
|
|
328
330
|
litellm is metered and enforced through the interceptors above, with no
|
|
329
|
-
wrap of its own:
|
|
331
|
+
wrap of its own: Microsoft Agent Framework,
|
|
330
332
|
Google ADK (on `LiteLlm`, Anthropic or OpenAI models), Pydantic AI and
|
|
331
333
|
Strands Agents (on their Anthropic, OpenAI and LiteLLM models), Agno,
|
|
332
334
|
Haystack, smolagents, Semantic Kernel, AutoGen, AG2 and DSPy on its
|
|
@@ -335,17 +337,17 @@ litellm engine. Each event names the framework in
|
|
|
335
337
|
|
|
336
338
|
- **Sub-agent sessions planned**
|
|
337
339
|
([#185](https://github.com/flightdeckhq/flightdeck/issues/185)): Google
|
|
338
|
-
ADK
|
|
339
|
-
`task` sub-agent).
|
|
340
|
+
ADK and Microsoft Agent Framework.
|
|
340
341
|
- **LLM calls planned**
|
|
341
342
|
([#185](https://github.com/flightdeckhq/flightdeck/issues/185)): a DSPy
|
|
342
343
|
callback adapter for its default engine, which has its own HTTP
|
|
343
344
|
transport and bypasses the SDKs and litellm.
|
|
344
|
-
- **No sub-agent sessions from `create_agent
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
345
|
+
- **No sub-agent sessions from `create_agent`'s steps**: its model, tool
|
|
346
|
+
and middleware nodes are the agent's own steps, not sub-agents, so the
|
|
347
|
+
LangGraph interceptor leaves them alone. A top-level `create_agent`
|
|
348
|
+
run is one session (its LLM calls are still metered); a Deep Agents
|
|
349
|
+
run adds one child per `task` sub-agent run, and an agent run inside
|
|
350
|
+
another graph run is a child of its own.
|
|
349
351
|
- **Structure through OpenTelemetry instead**: Pydantic AI and Strands
|
|
350
352
|
Agents export GenAI spans that Flightdeck's OTLP receiver maps into
|
|
351
353
|
observe-only child sessions. The sensor does not wrap them. Report a
|
|
@@ -251,7 +251,7 @@ is imported) only if your application imports it. `unpatch()` (and
|
|
|
251
251
|
| litellm (router that aggregates many providers behind one function surface) | `patch_litellm_functions` | `litellm.completion`, `litellm.acompletion`, `litellm.text_completion`, `litellm.atext_completion`, `litellm.responses`, `litellm.aresponses` (each with `stream=True`), `litellm.embedding`, `litellm.aembedding` |
|
|
252
252
|
| MCP (official Python `mcp` SDK, reached transitively by `langchain-mcp-adapters`, `llama-index-tools-mcp` and `mcpadapt`) | `patch_mcp_classes` | `mcp.client.session.ClientSession.initialize` on mcp 1.x / `.adopt` on mcp 2.x (server fingerprint capture, every 2.x handshake path), `.list_tools`, `.call_tool`, `.list_resources`, `.read_resource`, `.list_prompts`, `.get_prompt` (one `mcp_*` event type each), plus the stdio / SSE / streamable-HTTP / websocket transport client factories and mcp 2.x's `Client._build_session` for transport attribution. `call_tool` also enforces the MCP Protection Policy. Supported SDK range: `mcp>=1.28,<3`. |
|
|
253
253
|
| CrewAI (sub-agent sessions) | `patch_crewai_classes` | `crewai.Agent.execute_task` / `.aexecute_task` — each Crew member's turn lands as a child session (`session_start` / `session_end`) with `parent_session_id`, `agent_role` taken from `Agent.role`, and incoming / outgoing message capture gated on `capture_prompts` |
|
|
254
|
-
| LangGraph (sub-agent sessions) | `patch_langgraph_classes` | `langgraph.graph.StateGraph.add_node` —
|
|
254
|
+
| LangGraph and Deep Agents (sub-agent sessions) | `patch_langgraph_classes` (`patch_langgraph_runs` patches the graph runs alone; `patch()` applies it on the import of `langgraph.pregel`, so a functional-API application is covered) | `langgraph.graph.StateGraph.add_node` — each node of a graph you build, a function or a Runnable (`RunnableLambda`, `RunnableCallable`, an LCEL pipe, your own `ToolNode`), lands as a child session per run with `agent_role` taken from the node name; every such node is treated as agent-bearing unless narrowed with `init(langgraph_agent_node_pattern=...)`. The nodes `create_agent` and `create_react_agent` register (model, tools, middleware and model hooks) and generator nodes are not wrapped. `langgraph.pregel.Pregel.stream` / `astream` — a graph run started inside another graph run or a child (a compiled graph used as a node, a graph or an agent invoked from a node or a tool, each Deep Agents `task` sub-agent) lands as one child session, `agent_role` the run's name (`create_agent(name=...)`, the Deep Agents sub-agent's name), else the node it runs in (unless that node is one of `create_agent`'s own steps), else `subgraph`; a top-level run opens none. Each child nests under the child it runs in. An interrupt closes the child normally; async runs post their child's start and end off the event loop |
|
|
255
255
|
| LlamaIndex agent workflows (sub-agent sessions, `llama-index-core>=0.14`) | `patch_llama_index` | A span handler on LlamaIndex's root instrumentation dispatcher (no LlamaIndex method is replaced): each agent of a `FunctionAgent`, `ReActAgent`, `CodeActAgent` or `AgentWorkflow` run lands as a child session with `agent_role` the agent's name (the agent's model, tool and MCP calls stay on the sensor's session, as for CrewAI and LangGraph); an `AgentWorkflow` hand-off ends one child, records an `agent_handoff` signal on it and opens the next; a tool call the model wrote as text (ReAct, CodeAct) is reported once as a `tool_call`, its arguments and output under `capture_prompts` |
|
|
256
256
|
| Claude Agent SDK (`claude-agent-sdk>=0.2.168,<0.3`) | `patch_claude_agent_sdk` | `query()` (however it was imported) and `ClaudeSDKClient` — each run lands as its own `claude_agent_sdk` session keyed by the Claude Code session id, with a `post_call` per assistant message (tokens, cache split, billing mode) and a `tool_call` per tool use, read from the SDK's message stream; a Claude Code plugin loaded into the run stays silent. `PreToolUse` and `UserPromptSubmit` callbacks added after the caller's hooks apply the run's directives (a stop denies the next tool call and blocks prompts; budget warnings reach the run) and the MCP Protection Policy. Install with `pip install flightdeck-sensor[claude-agent-sdk]`. |
|
|
257
257
|
| OpenAI Agents SDK (`openai-agents>=0.6`, sub-agent sessions) | `patch_openai_agents` | `AgentRunner.run` / `.run_streamed` (so `Runner.run`, `run_sync` and `run_streamed`) and the `run` of the four guardrail classes — each agent that runs lands as a child session with `agent_role` taken from `Agent.name`, an agent used as a tool nests under the agent that called it, a hand-off posts `agent_handoff` on the agent handing off, a guardrail that fires posts `guardrail_tripwire` (names only), and the run's conversation id lands in the child's context as `gen_ai_conversation_id`. Model, tool and MCP calls stay on the sensor's session (the OpenAI and MCP interceptors meter them); a shutdown also stops the run when the next agent starts or hands off. Patched only when `agents` comes from the `openai-agents` distribution. Install with `pip install flightdeck-sensor[openai-agents]`. |
|
|
@@ -260,7 +260,7 @@ is imported) only if your application imports it. `unpatch()` (and
|
|
|
260
260
|
|
|
261
261
|
Any framework that calls a model through the Anthropic or OpenAI SDK or
|
|
262
262
|
litellm is metered and enforced through the interceptors above, with no
|
|
263
|
-
wrap of its own:
|
|
263
|
+
wrap of its own: Microsoft Agent Framework,
|
|
264
264
|
Google ADK (on `LiteLlm`, Anthropic or OpenAI models), Pydantic AI and
|
|
265
265
|
Strands Agents (on their Anthropic, OpenAI and LiteLLM models), Agno,
|
|
266
266
|
Haystack, smolagents, Semantic Kernel, AutoGen, AG2 and DSPy on its
|
|
@@ -269,17 +269,17 @@ litellm engine. Each event names the framework in
|
|
|
269
269
|
|
|
270
270
|
- **Sub-agent sessions planned**
|
|
271
271
|
([#185](https://github.com/flightdeckhq/flightdeck/issues/185)): Google
|
|
272
|
-
ADK
|
|
273
|
-
`task` sub-agent).
|
|
272
|
+
ADK and Microsoft Agent Framework.
|
|
274
273
|
- **LLM calls planned**
|
|
275
274
|
([#185](https://github.com/flightdeckhq/flightdeck/issues/185)): a DSPy
|
|
276
275
|
callback adapter for its default engine, which has its own HTTP
|
|
277
276
|
transport and bypasses the SDKs and litellm.
|
|
278
|
-
- **No sub-agent sessions from `create_agent
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
277
|
+
- **No sub-agent sessions from `create_agent`'s steps**: its model, tool
|
|
278
|
+
and middleware nodes are the agent's own steps, not sub-agents, so the
|
|
279
|
+
LangGraph interceptor leaves them alone. A top-level `create_agent`
|
|
280
|
+
run is one session (its LLM calls are still metered); a Deep Agents
|
|
281
|
+
run adds one child per `task` sub-agent run, and an agent run inside
|
|
282
|
+
another graph run is a child of its own.
|
|
283
283
|
- **Structure through OpenTelemetry instead**: Pydantic AI and Strands
|
|
284
284
|
Agents export GenAI spans that Flightdeck's OTLP receiver maps into
|
|
285
285
|
observe-only child sessions. The sensor does not wrap them. Report a
|
|
@@ -78,9 +78,15 @@ if TYPE_CHECKING:
|
|
|
78
78
|
from flightdeck_sensor.interceptor.langgraph import (
|
|
79
79
|
patch_langgraph_classes as patch_langgraph_classes,
|
|
80
80
|
)
|
|
81
|
+
from flightdeck_sensor.interceptor.langgraph import (
|
|
82
|
+
patch_langgraph_runs as patch_langgraph_runs,
|
|
83
|
+
)
|
|
81
84
|
from flightdeck_sensor.interceptor.langgraph import (
|
|
82
85
|
unpatch_langgraph_classes as unpatch_langgraph_classes,
|
|
83
86
|
)
|
|
87
|
+
from flightdeck_sensor.interceptor.langgraph import (
|
|
88
|
+
unpatch_langgraph_runs as unpatch_langgraph_runs,
|
|
89
|
+
)
|
|
84
90
|
from flightdeck_sensor.interceptor.litellm import SensorLitellm as SensorLitellm
|
|
85
91
|
from flightdeck_sensor.interceptor.litellm import (
|
|
86
92
|
patch_litellm_functions as patch_litellm_functions,
|
|
@@ -211,8 +217,12 @@ class _SDKTarget:
|
|
|
211
217
|
# keyed on ``langgraph.graph``, the package StateGraph comes from:
|
|
212
218
|
# ``langgraph`` itself is a namespace package shared with LangGraph's other
|
|
213
219
|
# distributions, and a namespace package runs no code for the hook to see.
|
|
214
|
-
#
|
|
215
|
-
#
|
|
220
|
+
# It has a second target, ``langgraph.pregel``, which patches the graph runs
|
|
221
|
+
# alone: an application on LangGraph's functional API imports only that,
|
|
222
|
+
# and the import of ``langgraph.graph`` imports it first, so its patch
|
|
223
|
+
# imports nothing from ``langgraph.graph``. LlamaIndex is keyed on
|
|
224
|
+
# ``llama_index.core`` for the same reason as LangGraph (``llama_index`` is
|
|
225
|
+
# a namespace package).
|
|
216
226
|
_SDK_TARGETS: tuple[_SDKTarget, ...] = (
|
|
217
227
|
_SDKTarget(
|
|
218
228
|
Provider.ANTHROPIC,
|
|
@@ -239,6 +249,13 @@ _SDK_TARGETS: tuple[_SDKTarget, ...] = (
|
|
|
239
249
|
"patch_crewai_classes",
|
|
240
250
|
"unpatch_crewai_classes",
|
|
241
251
|
),
|
|
252
|
+
_SDKTarget(
|
|
253
|
+
Provider.LANGGRAPH,
|
|
254
|
+
"langgraph.pregel",
|
|
255
|
+
"langgraph",
|
|
256
|
+
"patch_langgraph_runs",
|
|
257
|
+
"unpatch_langgraph_runs",
|
|
258
|
+
),
|
|
242
259
|
_SDKTarget(
|
|
243
260
|
Provider.LANGGRAPH,
|
|
244
261
|
"langgraph.graph",
|
|
@@ -969,8 +986,12 @@ def patch(
|
|
|
969
986
|
callbacks: dict[str, Callable[[str], None]] = {}
|
|
970
987
|
for t in selected:
|
|
971
988
|
callbacks[t.module] = functools.partial(_patch_on_import, t, quiet)
|
|
972
|
-
|
|
973
|
-
|
|
989
|
+
# Two targets can share an interceptor module (LangGraph's):
|
|
990
|
+
# its import then patches both.
|
|
991
|
+
on_interceptor = functools.partial(_patch_on_interceptor_import, t, quiet)
|
|
992
|
+
earlier = callbacks.get(t.interceptor_module)
|
|
993
|
+
callbacks[t.interceptor_module] = (
|
|
994
|
+
on_interceptor if earlier is None else _both(earlier, on_interceptor)
|
|
974
995
|
)
|
|
975
996
|
_import_hook.watch(callbacks)
|
|
976
997
|
for target in selected:
|
|
@@ -1236,6 +1257,16 @@ def _patch_on_import(target: _SDKTarget, quiet: bool, _module: str) -> None:
|
|
|
1236
1257
|
_patch_pending()
|
|
1237
1258
|
|
|
1238
1259
|
|
|
1260
|
+
def _both(first: Callable[[str], None], second: Callable[[str], None]) -> Callable[[str], None]:
|
|
1261
|
+
"""An import-hook callback that runs ``first``, then ``second``."""
|
|
1262
|
+
|
|
1263
|
+
def both(module: str) -> None:
|
|
1264
|
+
first(module)
|
|
1265
|
+
second(module)
|
|
1266
|
+
|
|
1267
|
+
return both
|
|
1268
|
+
|
|
1269
|
+
|
|
1239
1270
|
def _patch_on_interceptor_import(target: _SDKTarget, quiet: bool, _module: str) -> None:
|
|
1240
1271
|
"""The import hook's callback for the interceptor module of
|
|
1241
1272
|
``target``, whose code has just finished: patch the SDK if the
|