agentsdiagram 0.1.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.
Files changed (64) hide show
  1. agentsdiagram-0.1.0/.gitignore +20 -0
  2. agentsdiagram-0.1.0/CHANGELOG.md +12 -0
  3. agentsdiagram-0.1.0/LICENSE +21 -0
  4. agentsdiagram-0.1.0/PKG-INFO +131 -0
  5. agentsdiagram-0.1.0/README.md +100 -0
  6. agentsdiagram-0.1.0/docs/adapters/pydantic_ai.md +38 -0
  7. agentsdiagram-0.1.0/docs/adapters/smolagents.md +28 -0
  8. agentsdiagram-0.1.0/docs/adding-a-framework.md +18 -0
  9. agentsdiagram-0.1.0/docs/architecture.md +82 -0
  10. agentsdiagram-0.1.0/docs/images/viewer.png +0 -0
  11. agentsdiagram-0.1.0/docs/ir.md +63 -0
  12. agentsdiagram-0.1.0/docs/releasing.md +36 -0
  13. agentsdiagram-0.1.0/package.json +14 -0
  14. agentsdiagram-0.1.0/pnpm-lock.yaml +4777 -0
  15. agentsdiagram-0.1.0/pnpm-workspace.yaml +7 -0
  16. agentsdiagram-0.1.0/pyproject.toml +99 -0
  17. agentsdiagram-0.1.0/src/agentsdiagram/__init__.py +1 -0
  18. agentsdiagram-0.1.0/src/agentsdiagram/_static/viewer.css +1 -0
  19. agentsdiagram-0.1.0/src/agentsdiagram/_static/viewer.js +16 -0
  20. agentsdiagram-0.1.0/src/agentsdiagram/adapters/__init__.py +12 -0
  21. agentsdiagram-0.1.0/src/agentsdiagram/adapters/base.py +159 -0
  22. agentsdiagram-0.1.0/src/agentsdiagram/adapters/pydantic_ai/__init__.py +0 -0
  23. agentsdiagram-0.1.0/src/agentsdiagram/adapters/pydantic_ai/extract.py +464 -0
  24. agentsdiagram-0.1.0/src/agentsdiagram/adapters/pydantic_ai/graph.py +314 -0
  25. agentsdiagram-0.1.0/src/agentsdiagram/adapters/pydantic_ai/symbols.py +145 -0
  26. agentsdiagram-0.1.0/src/agentsdiagram/adapters/smolagents/__init__.py +0 -0
  27. agentsdiagram-0.1.0/src/agentsdiagram/adapters/smolagents/extract.py +345 -0
  28. agentsdiagram-0.1.0/src/agentsdiagram/adapters/smolagents/symbols.py +54 -0
  29. agentsdiagram-0.1.0/src/agentsdiagram/analyze.py +668 -0
  30. agentsdiagram-0.1.0/src/agentsdiagram/cli.py +129 -0
  31. agentsdiagram-0.1.0/src/agentsdiagram/facts.py +101 -0
  32. agentsdiagram-0.1.0/src/agentsdiagram/ir.py +171 -0
  33. agentsdiagram-0.1.0/src/agentsdiagram/lsp.py +276 -0
  34. agentsdiagram-0.1.0/src/agentsdiagram/project.py +427 -0
  35. agentsdiagram-0.1.0/src/agentsdiagram/render/__init__.py +0 -0
  36. agentsdiagram-0.1.0/src/agentsdiagram/render/html.py +66 -0
  37. agentsdiagram-0.1.0/src/agentsdiagram/render/mermaid.py +145 -0
  38. agentsdiagram-0.1.0/tests/__snapshots__/test_render_cli.ambr +4330 -0
  39. agentsdiagram-0.1.0/tests/conftest.py +28 -0
  40. agentsdiagram-0.1.0/tests/fixtures/pai/agent.yaml +8 -0
  41. agentsdiagram-0.1.0/tests/fixtures/pai/base_nodes.py +21 -0
  42. agentsdiagram-0.1.0/tests/fixtures/pai/basic_tools.py +47 -0
  43. agentsdiagram-0.1.0/tests/fixtures/pai/dynamic.py +10 -0
  44. agentsdiagram-0.1.0/tests/fixtures/pai/fastmcp_server.py +10 -0
  45. agentsdiagram-0.1.0/tests/fixtures/pai/graph_builder.py +42 -0
  46. agentsdiagram-0.1.0/tests/fixtures/pai/multi/__init__.py +0 -0
  47. agentsdiagram-0.1.0/tests/fixtures/pai/multi/agents.py +6 -0
  48. agentsdiagram-0.1.0/tests/fixtures/pai/multi/orchestrator.py +33 -0
  49. agentsdiagram-0.1.0/tests/fixtures/pai/spec.py +5 -0
  50. agentsdiagram-0.1.0/tests/fixtures/pai/syntax_error.py +3 -0
  51. agentsdiagram-0.1.0/tests/fixtures/pai/toolsets_mcp.py +48 -0
  52. agentsdiagram-0.1.0/tests/fixtures/pai/v1_api.py +7 -0
  53. agentsdiagram-0.1.0/tests/fixtures/pyproject.toml +4 -0
  54. agentsdiagram-0.1.0/tests/fixtures/smol/managed.py +32 -0
  55. agentsdiagram-0.1.0/tests/fixtures/smol/managed_without_name.py +14 -0
  56. agentsdiagram-0.1.0/tests/fixtures/smol/mcp.py +12 -0
  57. agentsdiagram-0.1.0/tests/fixtures/smol/tool_class.py +20 -0
  58. agentsdiagram-0.1.0/tests/test_lsp.py +91 -0
  59. agentsdiagram-0.1.0/tests/test_oracle.py +81 -0
  60. agentsdiagram-0.1.0/tests/test_pydantic_ai.py +126 -0
  61. agentsdiagram-0.1.0/tests/test_render_cli.py +78 -0
  62. agentsdiagram-0.1.0/tests/test_smolagents.py +41 -0
  63. agentsdiagram-0.1.0/tests/test_symbols_drift.py +80 -0
  64. agentsdiagram-0.1.0/uv.lock +3374 -0
@@ -0,0 +1,20 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ # viewer bundle (built by pnpm, shipped via hatch `artifacts`)
11
+ src/agentsdiagram/_static/
12
+ # Node
13
+ node_modules/
14
+ packages/*/dist/
15
+ packages/vscode/out/
16
+ *.vsix
17
+ # local
18
+ .DS_Store
19
+ CLAUDE.md
20
+ .claude/
@@ -0,0 +1,12 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-10-22
4
+
5
+ First release.
6
+
7
+ - Static analysis of PydanticAI 2.x (agents, tools, toolsets, MCP, capabilities, SubAgents,
8
+ delegation, hand-off workflows, pydantic-graph, Agent Specs) and smolagents 1.x (CodeAgent,
9
+ ToolCallingAgent, tools, managed agents, MCP).
10
+ - CLI: `scan` (Mermaid, JSON, Markdown, self-contained interactive HTML), `check`, `schema`, `lsp`.
11
+ - Interactive viewer (React Flow) and VS Code / Open VSX extension with live diagram, code lenses
12
+ and diagnostics.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alex Ojeda Copa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,131 @@
1
+ Metadata-Version: 2.5
2
+ Name: agentsdiagram
3
+ Version: 0.1.0
4
+ Summary: See your AI agents: static diagrams of agents, tools and flows for PydanticAI and smolagents — CLI and VS Code extension.
5
+ Project-URL: Homepage, https://github.com/alex-roc/agentsdiagram
6
+ Project-URL: Repository, https://github.com/alex-roc/agentsdiagram
7
+ Project-URL: Issues, https://github.com/alex-roc/agentsdiagram/issues
8
+ Project-URL: Changelog, https://github.com/alex-roc/agentsdiagram/blob/main/CHANGELOG.md
9
+ Author: Alex Ojeda Copa
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,diagram,llm,mermaid,pydantic-ai,smolagents,static-analysis,visualization
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Software Development :: Documentation
23
+ Classifier: Topic :: Software Development :: Quality Assurance
24
+ Requires-Python: >=3.11
25
+ Requires-Dist: libcst>=1.9
26
+ Requires-Dist: pydantic>=2.7
27
+ Requires-Dist: pyyaml>=6
28
+ Provides-Extra: lsp
29
+ Requires-Dist: pygls>=2.1; extra == 'lsp'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # agentsdiagram
33
+
34
+ **See your AI agents.** `agentsdiagram` reads the code of your [PydanticAI](https://ai.pydantic.dev)
35
+ and [smolagents](https://huggingface.co/docs/smolagents) agents and draws them: agents, tools,
36
+ toolsets, MCP servers, capabilities, delegation between agents, hand-off workflows and
37
+ pydantic-graph flows.
38
+
39
+ It is **static analysis**: your code is parsed, never imported or executed. No API keys, no
40
+ dependencies of your project, no network.
41
+
42
+ ![The interactive viewer](docs/images/viewer.png)
43
+
44
+ - **CLI**: Mermaid, JSON or a self-contained interactive HTML page.
45
+ - **VS Code extension** (also on Open VSX for Cursor, Windsurf and Positron): a live diagram next to
46
+ your code that follows your edits, "Show in diagram" code lenses and diagnostics.
47
+
48
+ ## Quick start
49
+
50
+ ```bash
51
+ uvx agentsdiagram scan path/to/project # Mermaid to stdout
52
+ uvx agentsdiagram scan . -f html -o agents.html # interactive page, open it in any browser
53
+ uvx agentsdiagram scan . -f markdown -o AGENTS-DIAGRAM.md # renders on GitHub
54
+ uvx agentsdiagram check . # diagnostics; exit 1 on errors (CI, pre-commit)
55
+ ```
56
+
57
+ Or install it: `uv tool install agentsdiagram` / `pip install agentsdiagram`.
58
+
59
+ ```
60
+ agentsdiagram scan [PATH] [-f mermaid|json|html|markdown] [-o FILE] [--framework pydantic_ai|smolagents]
61
+ [--include GLOB] [--exclude GLOB] [--title TEXT]
62
+ agentsdiagram check [PATH] [--strict] [--json]
63
+ agentsdiagram schema # JSON Schema of the IR
64
+ agentsdiagram lsp # language server (needs agentsdiagram[lsp]); used by the extension
65
+ ```
66
+
67
+ Project-wide settings go in `pyproject.toml`:
68
+
69
+ ```toml
70
+ [tool.agentsdiagram]
71
+ include = ["src/**"]
72
+ exclude = ["tests/**", "notebooks/**"]
73
+ ```
74
+
75
+ ## What it understands
76
+
77
+ | | PydanticAI 2.x | smolagents 1.x |
78
+ |---|---|---|
79
+ | Agents | `Agent(...)`, `Agent.from_file("spec.yaml")`, factories (`make_agent()`) | `CodeAgent`, `ToolCallingAgent` |
80
+ | Tools | `@agent.tool`, `@agent.tool_plain`, `tools=[f, Tool(...)]` | `@tool`, `Tool` subclasses, default tools, `add_base_tools` |
81
+ | Toolsets | `FunctionToolset`, wrappers (`.prefixed()`, `.filtered()`…), `@agent.toolset` | `ToolCollection`, Hub/Space/LangChain sources |
82
+ | MCP | `MCPToolset(...)`, `load_mcp_toolsets("mcp.json")`, `MCP(url=...)` | `ToolCollection.from_mcp`, `MCPClient` |
83
+ | Multi-agent | agent run inside a tool, `SubAgents`, hand-off functions | `managed_agents=[...]` |
84
+ | Flows | pydantic-graph `GraphBuilder` (steps, decisions, joins) and `BaseNode` | — |
85
+ | Checks | v1 API still in use | managed agents without name/description, `@tool` without hints, name clashes |
86
+
87
+ Anything that only exists at runtime (lists built in a loop, tools fetched from a server) shows up
88
+ as a dashed **dynamic** node instead of silently disappearing. Full coverage matrices:
89
+ [PydanticAI](docs/adapters/pydantic_ai.md) · [smolagents](docs/adapters/smolagents.md).
90
+
91
+ ## VS Code extension
92
+
93
+ Install **Agents Diagram** from the Marketplace or Open VSX. It needs either
94
+ [uv](https://docs.astral.sh/uv/) (the extension runs `uvx agentsdiagram[lsp]`) or your own command
95
+ in `agentsdiagram.server.command`. The Python extension is not required. See
96
+ [packages/vscode/README.md](packages/vscode/README.md).
97
+
98
+ ## How it works
99
+
100
+ ```
101
+ your code ──LibCST──▶ adapters (pydantic_ai, smolagents) ──▶ facts ──link──▶ IR (JSON)
102
+ ├─▶ Mermaid
103
+ ├─▶ HTML viewer (React Flow)
104
+ └─▶ LSP ─▶ VS Code panel
105
+ ```
106
+
107
+ The IR is a small, versioned JSON format ([docs/ir.md](docs/ir.md)); the viewer and the
108
+ extension use TypeScript types generated from its JSON Schema. Architecture and design
109
+ decisions: [docs/architecture.md](docs/architecture.md).
110
+
111
+ ## Roadmap
112
+
113
+ - **Plan** (v0.3): draw agents and tools that do not exist yet; agentsdiagram writes the stubs.
114
+ - **Edit** (v0.4): connect, add and remove tools and agents in the diagram; the change is written
115
+ to your code with LibCST, preserving formatting. The code stays the single source of truth.
116
+ - More frameworks through adapters ([docs/adding-a-framework.md](docs/adding-a-framework.md)).
117
+
118
+ ## Development
119
+
120
+ ```bash
121
+ uv sync # Python 3.11+, includes pydantic-ai and smolagents for the oracle tests
122
+ pnpm install && pnpm build # viewer + extension (pnpm 11, Node 22+)
123
+ uv run pytest # unit, snapshot, oracle, drift and LSP tests
124
+ pnpm test # viewer (vitest) + extension smoke test
125
+ ```
126
+
127
+ More in [docs/architecture.md](docs/architecture.md#development) and [docs/releasing.md](docs/releasing.md).
128
+
129
+ ## License
130
+
131
+ MIT © 2026 Alex Ojeda Copa
@@ -0,0 +1,100 @@
1
+ # agentsdiagram
2
+
3
+ **See your AI agents.** `agentsdiagram` reads the code of your [PydanticAI](https://ai.pydantic.dev)
4
+ and [smolagents](https://huggingface.co/docs/smolagents) agents and draws them: agents, tools,
5
+ toolsets, MCP servers, capabilities, delegation between agents, hand-off workflows and
6
+ pydantic-graph flows.
7
+
8
+ It is **static analysis**: your code is parsed, never imported or executed. No API keys, no
9
+ dependencies of your project, no network.
10
+
11
+ ![The interactive viewer](docs/images/viewer.png)
12
+
13
+ - **CLI**: Mermaid, JSON or a self-contained interactive HTML page.
14
+ - **VS Code extension** (also on Open VSX for Cursor, Windsurf and Positron): a live diagram next to
15
+ your code that follows your edits, "Show in diagram" code lenses and diagnostics.
16
+
17
+ ## Quick start
18
+
19
+ ```bash
20
+ uvx agentsdiagram scan path/to/project # Mermaid to stdout
21
+ uvx agentsdiagram scan . -f html -o agents.html # interactive page, open it in any browser
22
+ uvx agentsdiagram scan . -f markdown -o AGENTS-DIAGRAM.md # renders on GitHub
23
+ uvx agentsdiagram check . # diagnostics; exit 1 on errors (CI, pre-commit)
24
+ ```
25
+
26
+ Or install it: `uv tool install agentsdiagram` / `pip install agentsdiagram`.
27
+
28
+ ```
29
+ agentsdiagram scan [PATH] [-f mermaid|json|html|markdown] [-o FILE] [--framework pydantic_ai|smolagents]
30
+ [--include GLOB] [--exclude GLOB] [--title TEXT]
31
+ agentsdiagram check [PATH] [--strict] [--json]
32
+ agentsdiagram schema # JSON Schema of the IR
33
+ agentsdiagram lsp # language server (needs agentsdiagram[lsp]); used by the extension
34
+ ```
35
+
36
+ Project-wide settings go in `pyproject.toml`:
37
+
38
+ ```toml
39
+ [tool.agentsdiagram]
40
+ include = ["src/**"]
41
+ exclude = ["tests/**", "notebooks/**"]
42
+ ```
43
+
44
+ ## What it understands
45
+
46
+ | | PydanticAI 2.x | smolagents 1.x |
47
+ |---|---|---|
48
+ | Agents | `Agent(...)`, `Agent.from_file("spec.yaml")`, factories (`make_agent()`) | `CodeAgent`, `ToolCallingAgent` |
49
+ | Tools | `@agent.tool`, `@agent.tool_plain`, `tools=[f, Tool(...)]` | `@tool`, `Tool` subclasses, default tools, `add_base_tools` |
50
+ | Toolsets | `FunctionToolset`, wrappers (`.prefixed()`, `.filtered()`…), `@agent.toolset` | `ToolCollection`, Hub/Space/LangChain sources |
51
+ | MCP | `MCPToolset(...)`, `load_mcp_toolsets("mcp.json")`, `MCP(url=...)` | `ToolCollection.from_mcp`, `MCPClient` |
52
+ | Multi-agent | agent run inside a tool, `SubAgents`, hand-off functions | `managed_agents=[...]` |
53
+ | Flows | pydantic-graph `GraphBuilder` (steps, decisions, joins) and `BaseNode` | — |
54
+ | Checks | v1 API still in use | managed agents without name/description, `@tool` without hints, name clashes |
55
+
56
+ Anything that only exists at runtime (lists built in a loop, tools fetched from a server) shows up
57
+ as a dashed **dynamic** node instead of silently disappearing. Full coverage matrices:
58
+ [PydanticAI](docs/adapters/pydantic_ai.md) · [smolagents](docs/adapters/smolagents.md).
59
+
60
+ ## VS Code extension
61
+
62
+ Install **Agents Diagram** from the Marketplace or Open VSX. It needs either
63
+ [uv](https://docs.astral.sh/uv/) (the extension runs `uvx agentsdiagram[lsp]`) or your own command
64
+ in `agentsdiagram.server.command`. The Python extension is not required. See
65
+ [packages/vscode/README.md](packages/vscode/README.md).
66
+
67
+ ## How it works
68
+
69
+ ```
70
+ your code ──LibCST──▶ adapters (pydantic_ai, smolagents) ──▶ facts ──link──▶ IR (JSON)
71
+ ├─▶ Mermaid
72
+ ├─▶ HTML viewer (React Flow)
73
+ └─▶ LSP ─▶ VS Code panel
74
+ ```
75
+
76
+ The IR is a small, versioned JSON format ([docs/ir.md](docs/ir.md)); the viewer and the
77
+ extension use TypeScript types generated from its JSON Schema. Architecture and design
78
+ decisions: [docs/architecture.md](docs/architecture.md).
79
+
80
+ ## Roadmap
81
+
82
+ - **Plan** (v0.3): draw agents and tools that do not exist yet; agentsdiagram writes the stubs.
83
+ - **Edit** (v0.4): connect, add and remove tools and agents in the diagram; the change is written
84
+ to your code with LibCST, preserving formatting. The code stays the single source of truth.
85
+ - More frameworks through adapters ([docs/adding-a-framework.md](docs/adding-a-framework.md)).
86
+
87
+ ## Development
88
+
89
+ ```bash
90
+ uv sync # Python 3.11+, includes pydantic-ai and smolagents for the oracle tests
91
+ pnpm install && pnpm build # viewer + extension (pnpm 11, Node 22+)
92
+ uv run pytest # unit, snapshot, oracle, drift and LSP tests
93
+ pnpm test # viewer (vitest) + extension smoke test
94
+ ```
95
+
96
+ More in [docs/architecture.md](docs/architecture.md#development) and [docs/releasing.md](docs/releasing.md).
97
+
98
+ ## License
99
+
100
+ MIT © 2026 Alex Ojeda Copa
@@ -0,0 +1,38 @@
1
+ # PydanticAI adapter
2
+
3
+ Verified against **pydantic-ai 2.59.0**, **pydantic-ai-harness 0.59.0** and **pydantic-graph 2.59.0**
4
+ (October 2026). Symbols: [`adapters/pydantic_ai/symbols.py`](../../src/agentsdiagram/adapters/pydantic_ai/symbols.py).
5
+
6
+ | Construct | Result |
7
+ |---|---|
8
+ | `Agent(model, name=, instructions=/system_prompt=, deps_type=, output_type=, description=)` | `agent` node (name from `name=` or the variable) |
9
+ | `Agent(...)` inside a function | `partial` agent; `x = factory(...)` gets its own node |
10
+ | `Agent.from_file("x.yaml")` (literal path) | agent from the Agent Spec: model, instructions, capabilities, MCP |
11
+ | `@agent.tool`, `@agent.tool_plain` (`name=`, `requires_approval=`) | `tool` with docstring, signature, `takes_ctx` |
12
+ | `tools=[f, Tool(f, ...), Tool.from_schema(...)]` | `uses` → `tool` |
13
+ | `@agent.instructions`, `@agent.system_prompt` | `attrs.dynamic_instructions` |
14
+ | `@agent.output_validator`, `@agent.on_event` | badges |
15
+ | `@agent.toolset` | `dynamic` toolset |
16
+ | `FunctionToolset(tools=[...])`, `@ts.tool`, `@ts.tool_plain`, `ts.add_function(f)` | `toolset` → `provides` → tools |
17
+ | `PrefixedToolset`, `FilteredToolset`, `RenamedToolset`, `ApprovalRequiredToolset`… / `CombinedToolset` | `toolset` → `wraps` |
18
+ | `.prefixed()`, `.filtered()`, `.renamed()`, `.approval_required()`… | edge `wrappers` |
19
+ | `ExternalToolset` | `partial` toolset |
20
+ | `MCPToolset("https://…")`, `MCPToolset(StdioTransport(command, args))`, `MCPToolset(Client(...))` | `mcp_server` with url/command |
21
+ | `load_mcp_toolsets("mcp.json")` (literal path) | toolset → one `mcp_server` per entry |
22
+ | `capabilities=[NativeTool(WebSearchTool())]`, `WebSearch()`, `WebFetch()`… | `native_tool` |
23
+ | `capabilities=[MCP(url=...)]` | `mcp_server` |
24
+ | `capabilities=[Capability(id=, tools=, toolsets=)]`, `@cap.tool` | `capability` → `provides` |
25
+ | `capabilities=[Toolset(ts)]` | `uses` → toolset |
26
+ | `SubAgents(agents=[SubAgent(a, name=)])` (harness) | `capability` → `delegates_to` → agent |
27
+ | `DynamicWorkflow(agents=[...])` (harness) | `dynamic` capability → `delegates_to` |
28
+ | any other capability (`Thinking`, `Caching`, `TemporalDurability`…) | badge on the agent |
29
+ | `other.run/run_sync/run_stream/iter(...)` inside a tool | tool → `delegates_to` → agent |
30
+ | function running ≥ 2 agents | `workflow` → ordered `runs` |
31
+ | `GraphBuilder`: `@g.step`, `g.join(...)`, `edge_from(...).to(...)`, `.map()`, `.label()`, `decision().branch(match(T).label().to())` | `graph` with `graph_step`s and `transitions` |
32
+ | `BaseNode` subclasses (`run()` return annotation, `End[T]`) | `graph` with `transitions` |
33
+ | v1: `MCPServerStdio/SSE/StreamableHTTP/HTTP`, `mcp_servers=`, `builtin_tools=`, `load_mcp_servers`, `UrlContextTool` | recognised + AD101 |
34
+
35
+ Not detected (shown as `dynamic` when referenced): toolsets/tools built at runtime, agents
36
+ passed as parameters, output functions that hand off (planned).
37
+
38
+ FastMCP servers (`@server.tool()`) are deliberately **not** treated as agent tools.
@@ -0,0 +1,28 @@
1
+ # smolagents adapter
2
+
3
+ Verified against **smolagents 1.26.0** (October 2026). Symbols:
4
+ [`adapters/smolagents/symbols.py`](../../src/agentsdiagram/adapters/smolagents/symbols.py).
5
+
6
+ | Construct | Result |
7
+ |---|---|
8
+ | `CodeAgent(...)`, `ToolCallingAgent(...)` | `agent`: `name`, `description`, `instructions`, model (`Class('model_id')`, aliases like `OpenAIServerModel` → `OpenAIModel`), `planning_interval`, `max_steps`, `executor_type`, `additional_authorized_imports` |
9
+ | `tools=[...]` | `uses` → tool / MCP / external source |
10
+ | `managed_agents=[...]` | `manages` → agent |
11
+ | `add_base_tools=True` | implicit `web_search`, `visit_webpage` (+ `python_interpreter` on `ToolCallingAgent`), as in `agents.py::_setup_tools` |
12
+ | `@tool` functions | `tool` with docstring and signature |
13
+ | `class X(Tool)` with `name`, `description`, `inputs`, `output_type`, `forward` | `tool` |
14
+ | default tools (`WebSearchTool()`, `DuckDuckGoSearchTool()`, `VisitWebpageTool()`…) | `tool` with the name the library exposes |
15
+ | `Tool.from_space/from_langchain/from_gradio/from_code` | `partial` tool |
16
+ | `Tool.from_hub`, `load_tool`, `ToolCollection.from_hub` | `external_tool_source` |
17
+ | `with ToolCollection.from_mcp(params) as tc: ... tools=[*tc.tools]` | `mcp_server` (command or URL) |
18
+ | `with MCPClient(params) as tools: ... tools=tools` | `mcp_server` |
19
+ | `managed.run(...)` inside a `@tool` | `delegates_to` |
20
+
21
+ Diagnostics: AD201 (managed agent without `name`/`description`), AD202 (two tools/agents with the
22
+ same name — several default tools are all called `web_search`), AD203 (`@tool` without type hints
23
+ or `Args:`), AD204 (`executor_type="wasm"`, removed in 1.26).
24
+
25
+ `final_answer` is added by smolagents to every agent and is not drawn.
26
+
27
+ Note: in 1.26 `agent.to_dict()` returns `tools` and `managed_agents` as lists of dicts (with
28
+ code), not names; the oracle tests use it as ground truth.
@@ -0,0 +1,18 @@
1
+ # Adding a framework
2
+
3
+ 1. Create `src/agentsdiagram/adapters/<framework>/` with:
4
+ - `symbols.py`: tables of `root.LastName` symbols, with the library version you verified
5
+ against, and `all_symbols()`.
6
+ - `extract.py`: a class with `framework`, `markers` (bytes for the prefilter),
7
+ `run_methods`, `extract(module, facts)` and `check(project)`.
8
+ 2. In `extract`, iterate `module.calls` (source order; reverse it for post-order) and
9
+ `module.bindings`. Register nodes with `facts.add(Def(...), call)` and relations with
10
+ `facts.edge(source_key, kind, module, target_expression)`. Let the linker resolve the
11
+ targets; do not resolve names yourself. Use `adapters/base.py` helpers (`arg`,
12
+ `string_value`, `describe_model`, `elements`, `value_of`…).
13
+ 3. Add the framework to `Framework` in `ir.py`, run `pnpm schema`, and register the adapter in
14
+ `adapters/__init__.py`.
15
+ 4. Add fixtures under `tests/fixtures/<short>/`, unit tests, oracle tests (import the fixtures
16
+ with the real library) and the symbol drift test, and add the library to the `oracle`
17
+ dependency group and to `.github/workflows/drift.yml`.
18
+ 5. Document coverage in `docs/adapters/<framework>.md` and the README table.
@@ -0,0 +1,82 @@
1
+ # Architecture
2
+
3
+ `agentsdiagram` turns agent code into a graph without running it. One Python core feeds three
4
+ front ends (CLI, HTML viewer, VS Code extension) through one JSON format (the IR).
5
+
6
+ ```
7
+ src/agentsdiagram/
8
+ project.py file discovery (git ls-files), module index, one-pass LibCST collector
9
+ facts.py per-module facts recorded by adapters (Defs + pending edges)
10
+ adapters/ one package per framework: symbols.py (data) + extract.py (logic)
11
+ analyze.py lazy loading, name resolution across modules, linking, IR build
12
+ ir.py the IR (pydantic) and its JSON Schema
13
+ render/ mermaid.py, html.py (inlines the viewer bundle from _static/)
14
+ lsp.py pygls 2 language server for the extension
15
+ cli.py argparse CLI
16
+ packages/
17
+ protocol/ TS types generated from the IR schema + viewer/extension messages
18
+ viewer/ React Flow viewer, one IIFE bundle (viewer.js + viewer.css)
19
+ vscode/ the extension (LanguageClient + webview panel)
20
+ ```
21
+
22
+ ## Pipeline
23
+
24
+ 1. **Collect.** `project.collect()` lists Python files (honouring `.gitignore` via
25
+ `git ls-files`), builds a module index for cross-module resolution and selects the *seed*
26
+ files to analyse (`[tool.agentsdiagram]` include/exclude apply).
27
+ 2. **Prefilter.** A seed is parsed only if its bytes mention a framework (`pydantic_ai`,
28
+ `smolagents`…) or an agent run method (`.run(`), so large repos stay fast.
29
+ 3. **Parse.** LibCST parses each file once. A single custom visitor computes parents,
30
+ scopes, bindings, qualified names and the list of calls. It replaces LibCST's
31
+ Scope/QualifiedName providers, which were 3–4x slower. It follows Python's LEGB
32
+ lookup for module, function and class scopes.
33
+ 4. **Extract.** Each adapter records `Def`s (things that may become nodes) and pending
34
+ edges whose target is still an expression. Plain functions and classes are registered
35
+ too, so they become tools only when something uses them.
36
+ 5. **Resolve and link.** `Analyzer.resolve()` follows names through assignments, imports and
37
+ re-exports across modules, factory functions (`return Agent(...)`), list literals, `+`
38
+ concatenation and method calls (`ts.prefixed("x")` becomes an edge wrapper). Modules
39
+ are loaded lazily. Unresolvable expressions become `dynamic` nodes. Library objects
40
+ with no structural meaning (e.g. `Thinking()`) become badges.
41
+ 6. **Implicit relations.** Function bodies of visible tools and graph steps are scanned for
42
+ `agent.run(...)` calls, which produce `delegates_to` and `runs` edges. A plain function
43
+ that runs two or more agents becomes a `workflow` node with ordered `runs` edges.
44
+ 7. **Build.** Visible defs (explicit ones in seed files, plus everything reachable) become
45
+ nodes with stable ids. Adapters then run whole-graph checks (`check()`).
46
+
47
+ ## Key decisions
48
+
49
+ - **Static only.** It never imports user code. This keeps it safe and independent of the user's
50
+ environment, and makes it work on broken projects.
51
+ - **The code is the single source of truth.** Planning and editing (roadmap) will write code
52
+ with LibCST. The diagram never stores state of its own.
53
+ - **Data-driven adapters.** Library symbols live in `symbols.py` tables matched by root
54
+ package and last name (`pydantic_ai.Agent` also matches `pydantic_ai.agent.Agent`).
55
+ `tests/test_symbols_drift.py` imports every entry, and a weekly workflow runs it against the
56
+ latest releases.
57
+ - **Factory instances.** `planner = make_agent(...)` creates its own node, a copy of the
58
+ factory's product, and the factory's template node is hidden. Without this, every agent
59
+ built by one factory would collapse into a single node.
60
+ - **Tolerant to broken code.** A file with a syntax error keeps its last valid version, marked
61
+ `stale`, plus diagnostic AD000. Each adapter runs isolated, and a crash becomes AD900.
62
+ - **Stable ids.** Ids are `framework:kind:module.qualname`. Unnamed constructs use an ordinal
63
+ within their scope, never line numbers. Every node and edge also carries a `SourceRef` (range
64
+ plus name range), which future edits will use as anchors.
65
+ - **LSP for the editor.** pygls gives us unsaved buffers, lifecycle, cancellation and the
66
+ Problems panel. IR columns are code points and are converted to UTF-16 at the LSP boundary.
67
+ - **The extension does not embed Python.** It runs `uvx agentsdiagram[lsp]==<its version>`, or a
68
+ user-configured command (machine scope, restricted in untrusted workspaces).
69
+
70
+ ## Development
71
+
72
+ ```bash
73
+ uv sync && pnpm install
74
+ uv run pytest # Python: unit, snapshots (syrupy), oracles, drift, LSP (pytest-lsp)
75
+ uv run pytest --snapshot-update # after an intended output change
76
+ pnpm build # viewer -> src/agentsdiagram/_static and packages/vscode/media
77
+ pnpm schema # after changing ir.py: regenerate the schema and TS types
78
+ pnpm --filter agentsdiagram test:e2e # extension + real language server (needs uv)
79
+ ```
80
+
81
+ Fixtures live in `tests/fixtures` (their own project root). Oracle tests import them with the
82
+ real libraries, so a fixture that stops importing is also a failing test.
@@ -0,0 +1,63 @@
1
+ # The IR (intermediate representation)
2
+
3
+ JSON produced by `agentsdiagram scan -f json` and by the language server (`agentsdiagram/graph`).
4
+ Schema: `agentsdiagram schema` / [`packages/protocol/ir.schema.json`](../packages/protocol/ir.schema.json).
5
+ Current version: `ir_version: "1"`.
6
+
7
+ ```jsonc
8
+ {
9
+ "ir_version": "1", "tool_version": "0.1.0", "root": "/abs/project",
10
+ "frameworks": ["pydantic_ai"],
11
+ "files": [{ "path": "app/agents.py", "module": "app.agents", "frameworks": ["pydantic_ai"], "status": "ok", "sha256": "…" }],
12
+ "nodes": [{ "id": "pydantic_ai:agent:app.agents.lead", "kind": "agent", "framework": "pydantic_ai",
13
+ "name": "lead", "status": "resolved", "source": { "file": "app/agents.py", "range": {…}, "name_range": {…} },
14
+ "attrs": { "model": "openai:gpt-5", "instructions": "…", "badges": ["Thinking"], "extra": {} } }],
15
+ "edges": [{ "id": "uses:…->…", "kind": "uses", "source": "…", "target": "…", "label": null, "order": null,
16
+ "wrappers": ["prefixed(\"math\")"], "ref": { … } }],
17
+ "diagnostics": [{ "code": "AD201", "severity": "error", "message": "…", "ref": { … }, "node_id": "…" }]
18
+ }
19
+ ```
20
+
21
+ Positions: `line` is 1-based, `column` is 0-based and counted in code points.
22
+
23
+ ## Node kinds
24
+
25
+ | kind | meaning |
26
+ |---|---|
27
+ | `agent` | an agent (`Agent`, `CodeAgent`, `ToolCallingAgent`, an Agent Spec) |
28
+ | `tool` | a function or `Tool` the model can call |
29
+ | `toolset` | a group of tools (`FunctionToolset`, wrappers, MCP config files, dynamic toolsets) |
30
+ | `mcp_server` | an MCP server (stdio command or URL) |
31
+ | `native_tool` | a provider-side tool (`WebSearchTool`, `WebFetch`…) |
32
+ | `capability` | a PydanticAI capability with structure (`Capability`, `SubAgents`, `DynamicWorkflow`) |
33
+ | `workflow` | a plain function that runs several agents in sequence (hand-off) |
34
+ | `external_tool_source` | tools loaded from the Hub, a Space, LangChain… |
35
+ | `graph` / `graph_step` | pydantic-graph graphs and their steps (incl. `start`, `end`, `decision`, joins) |
36
+ | `dynamic` | an expression that cannot be resolved statically |
37
+
38
+ ## Edge kinds
39
+
40
+ `uses` (agent → tool/toolset/mcp/native/capability) · `provides` (toolset/capability → tool) ·
41
+ `wraps` (wrapper toolset → inner) · `delegates_to` (tool/capability → agent) ·
42
+ `manages` (smolagents manager → managed agent) · `runs` (workflow/graph step → agent, ordered) ·
43
+ `contains` (graph → step) · `transitions` (step → step).
44
+
45
+ ## Status
46
+
47
+ `resolved` · `partial` (built in a function / factory, arguments may vary) · `dynamic` ·
48
+ `planned` (roadmap: stubs written by the planner) · `stale` (file has a syntax error; last valid version).
49
+
50
+ ## Diagnostic codes
51
+
52
+ | code | severity | meaning |
53
+ |---|---|---|
54
+ | AD000 | error / warning | syntax error (warning when a previous valid version is shown) |
55
+ | AD001 | info | expression cannot be resolved statically (dynamic node) |
56
+ | AD002 | info | referenced config/spec file not found |
57
+ | AD101 | warning | PydanticAI v1 API (`MCPServerStdio`, `mcp_servers=`, `builtin_tools=`…) |
58
+ | AD201 | error | smolagents managed agent without `name` and `description` |
59
+ | AD202 | warning | smolagents agent with two tools/agents of the same name |
60
+ | AD203 | warning | smolagents `@tool` without type hints or `Args:` docstring |
61
+ | AD204 | error | smolagents `executor_type` that no longer exists |
62
+ | AD301 | info | agent created inside a function |
63
+ | AD900 | error | an adapter crashed on a file (please report it) |
@@ -0,0 +1,36 @@
1
+ # Releasing
2
+
3
+ Versions are kept in lockstep: `src/agentsdiagram/__init__.py` and `packages/vscode/package.json`
4
+ must match the tag. The extension runs `uvx agentsdiagram[lsp]==<its version>`, so PyPI is
5
+ published first.
6
+
7
+ ```bash
8
+ # bump both versions, update CHANGELOG.md, commit
9
+ git tag v0.1.0 && git push origin v0.1.0
10
+ ```
11
+
12
+ `.github/workflows/release.yml` builds the viewer, the wheel/sdist (checking `_static/` is inside)
13
+ and the `.vsix`, then publishes PyPI → Open VSX + Marketplace → GitHub release.
14
+
15
+ ## One-time setup
16
+
17
+ - **PyPI**: on pypi.org (account `alex-roc`), *Publishing → Add a pending publisher*:
18
+ project `agentsdiagram`, owner `alex-roc`, repo `agentsdiagram`, workflow `release.yml`,
19
+ environment `release`. Create the `release` environment in the GitHub repo.
20
+ - **Open VSX**: sign in at open-vsx.org with GitHub `alex-roc`, sign the Publisher Agreement,
21
+ create a token, run `npx ovsx create-namespace alex-roc -p <token>`, then claim the namespace
22
+ (issue in EclipseFdn/open-vsx.org, "Namespace access"). Store the token as secret `OVSX_PAT`.
23
+ - **VS Code Marketplace**: create publisher `alex-roc` at marketplace.visualstudio.com/manage.
24
+ Global Azure DevOps PATs are retired on **2026-12-01**, so use Microsoft Entra ID: an app
25
+ registration with a federated credential for `repo:alex-roc/agentsdiagram:environment:release`,
26
+ added as a member of the publisher; set repository variables `AZURE_CLIENT_ID` and
27
+ `AZURE_TENANT_ID`. (Until then a `VSCE_PAT` secret also works.)
28
+
29
+ ## Manual publish (fallback)
30
+
31
+ ```bash
32
+ pnpm build && uv build && uv publish # PyPI
33
+ pnpm --filter agentsdiagram run package # packages/vscode/agentsdiagram-X.Y.Z.vsix
34
+ npx ovsx publish packages/vscode/*.vsix -p $OVSX_PAT
35
+ npx @vscode/vsce publish --packagePath packages/vscode/*.vsix --azure-credential
36
+ ```
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "agentsdiagram-monorepo",
3
+ "private": true,
4
+ "packageManager": "pnpm@11.17.0",
5
+ "scripts": {
6
+ "build": "pnpm --filter @agentsdiagram/viewer run build && pnpm --filter agentsdiagram run build",
7
+ "test": "pnpm -r --if-present run test",
8
+ "lint": "pnpm -r --if-present run lint",
9
+ "schema": "uv run agentsdiagram schema > packages/protocol/ir.schema.json && pnpm --filter @agentsdiagram/protocol run generate"
10
+ },
11
+ "engines": {
12
+ "node": ">=22"
13
+ }
14
+ }