RouteKitAI 0.2.0__tar.gz → 0.2.1__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 (114) hide show
  1. {routekitai-0.2.0/src/RouteKitAI.egg-info → routekitai-0.2.1}/PKG-INFO +30 -3
  2. {routekitai-0.2.0 → routekitai-0.2.1}/README.md +26 -2
  3. {routekitai-0.2.0 → routekitai-0.2.1}/docs/api-reference.md +1 -1
  4. {routekitai-0.2.0 → routekitai-0.2.1}/docs/guides/providers.md +11 -4
  5. routekitai-0.2.1/examples/anthropic_agent.py +107 -0
  6. {routekitai-0.2.0 → routekitai-0.2.1}/pyproject.toml +4 -0
  7. {routekitai-0.2.0 → routekitai-0.2.1/src/RouteKitAI.egg-info}/PKG-INFO +30 -3
  8. {routekitai-0.2.0 → routekitai-0.2.1}/src/RouteKitAI.egg-info/SOURCES.txt +1 -0
  9. {routekitai-0.2.0 → routekitai-0.2.1}/src/RouteKitAI.egg-info/requires.txt +4 -0
  10. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/__init__.py +1 -1
  11. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/policies.py +2 -1
  12. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/runtime.py +8 -0
  13. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/providers/__init__.py +2 -0
  14. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/providers/anthropic.py +25 -9
  15. {routekitai-0.2.0 → routekitai-0.2.1}/CHANGELOG.md +0 -0
  16. {routekitai-0.2.0 → routekitai-0.2.1}/LICENSE +0 -0
  17. {routekitai-0.2.0 → routekitai-0.2.1}/MANIFEST.in +0 -0
  18. {routekitai-0.2.0 → routekitai-0.2.1}/docs/architecture.md +0 -0
  19. {routekitai-0.2.0 → routekitai-0.2.1}/docs/getting-started.md +0 -0
  20. {routekitai-0.2.0 → routekitai-0.2.1}/docs/guides/cli-reference.md +0 -0
  21. {routekitai-0.2.0 → routekitai-0.2.1}/docs/guides/creating-tools.md +0 -0
  22. {routekitai-0.2.0 → routekitai-0.2.1}/docs/guides/graph-workflows.md +0 -0
  23. {routekitai-0.2.0 → routekitai-0.2.1}/docs/guides/running-agents.md +0 -0
  24. {routekitai-0.2.0 → routekitai-0.2.1}/docs/guides/tracing-and-replay.md +0 -0
  25. {routekitai-0.2.0 → routekitai-0.2.1}/docs/index.md +0 -0
  26. {routekitai-0.2.0 → routekitai-0.2.1}/docs/security-and-governance.md +0 -0
  27. {routekitai-0.2.0 → routekitai-0.2.1}/examples/__init__.py +0 -0
  28. {routekitai-0.2.0 → routekitai-0.2.1}/examples/basic.py +0 -0
  29. {routekitai-0.2.0 → routekitai-0.2.1}/examples/eval_regression.py +0 -0
  30. {routekitai-0.2.0 → routekitai-0.2.1}/examples/function_calling_policy.py +0 -0
  31. {routekitai-0.2.0 → routekitai-0.2.1}/examples/graph_agent.py +0 -0
  32. {routekitai-0.2.0 → routekitai-0.2.1}/examples/graph_agent_real.py +0 -0
  33. {routekitai-0.2.0 → routekitai-0.2.1}/examples/graph_policy.py +0 -0
  34. {routekitai-0.2.0 → routekitai-0.2.1}/examples/hello_routekit.py +0 -0
  35. {routekitai-0.2.0 → routekitai-0.2.1}/examples/plan_execute_policy.py +0 -0
  36. {routekitai-0.2.0 → routekitai-0.2.1}/examples/react_policy.py +0 -0
  37. {routekitai-0.2.0 → routekitai-0.2.1}/examples/supervisor_agent.py +0 -0
  38. {routekitai-0.2.0 → routekitai-0.2.1}/examples/supervisor_policy.py +0 -0
  39. {routekitai-0.2.0 → routekitai-0.2.1}/setup.cfg +0 -0
  40. {routekitai-0.2.0 → routekitai-0.2.1}/src/RouteKitAI.egg-info/dependency_links.txt +0 -0
  41. {routekitai-0.2.0 → routekitai-0.2.1}/src/RouteKitAI.egg-info/entry_points.txt +0 -0
  42. {routekitai-0.2.0 → routekitai-0.2.1}/src/RouteKitAI.egg-info/top_level.txt +0 -0
  43. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/__init__.py +0 -0
  44. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/main.py +0 -0
  45. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/replay.py +0 -0
  46. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/run.py +0 -0
  47. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/serve.py +0 -0
  48. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/test_agent.py +0 -0
  49. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/trace.py +0 -0
  50. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/trace_analyze.py +0 -0
  51. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/cli/trace_search.py +0 -0
  52. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/__init__.py +0 -0
  53. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/agent.py +0 -0
  54. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/errors.py +0 -0
  55. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/hooks.py +0 -0
  56. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/memory.py +0 -0
  57. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/message.py +0 -0
  58. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/model.py +0 -0
  59. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/policy.py +0 -0
  60. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/policy_adapter.py +0 -0
  61. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/tool.py +0 -0
  62. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/core/tools.py +0 -0
  63. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/evals/__init__.py +0 -0
  64. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/evals/dataset.py +0 -0
  65. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/evals/metrics.py +0 -0
  66. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/evals/runner.py +0 -0
  67. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/graphs/__init__.py +0 -0
  68. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/graphs/executors.py +0 -0
  69. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/graphs/graph.py +0 -0
  70. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/memory/__init__.py +0 -0
  71. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/memory/episodic.py +0 -0
  72. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/memory/kv.py +0 -0
  73. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/memory/retrieval.py +0 -0
  74. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/memory/vector.py +0 -0
  75. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/memory/working.py +0 -0
  76. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/message.py +0 -0
  77. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/model.py +0 -0
  78. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/__init__.py +0 -0
  79. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/analyzer.py +0 -0
  80. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/exporters/__init__.py +0 -0
  81. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/exporters/base.py +0 -0
  82. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/exporters/jsonl.py +0 -0
  83. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/exporters/otel.py +0 -0
  84. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/spans.py +0 -0
  85. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/streaming.py +0 -0
  86. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/observability/trace.py +0 -0
  87. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/providers/azure_openai.py +0 -0
  88. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/providers/local.py +0 -0
  89. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/providers/openai.py +0 -0
  90. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/py.typed +0 -0
  91. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/sandbox/__init__.py +0 -0
  92. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/sandbox/filesystem.py +0 -0
  93. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/sandbox/network.py +0 -0
  94. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/sandbox/permissions.py +0 -0
  95. {routekitai-0.2.0 → routekitai-0.2.1}/src/routekitai/tool.py +0 -0
  96. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_evals.py +0 -0
  97. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_graphs.py +0 -0
  98. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_graphs_subgraph.py +0 -0
  99. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_hooks.py +0 -0
  100. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_integration.py +0 -0
  101. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_memory.py +0 -0
  102. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_memory_kv.py +0 -0
  103. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_memory_vector.py +0 -0
  104. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_message.py +0 -0
  105. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_otel_exporter.py +0 -0
  106. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_runtime.py +0 -0
  107. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_sandbox_filesystem.py +0 -0
  108. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_sandbox_network.py +0 -0
  109. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_streaming.py +0 -0
  110. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_streaming_serve.py +0 -0
  111. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_tool.py +0 -0
  112. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_tools.py +0 -0
  113. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_trace_analyzer.py +0 -0
  114. {routekitai-0.2.0 → routekitai-0.2.1}/tests/test_trace_analyzer_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RouteKitAI
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: An agent development + orchestration framework
5
5
  Author: Mohamed Ghassen Brahim
6
6
  License: MIT
@@ -41,6 +41,9 @@ Requires-Dist: sentence-transformers>=2.2.0; extra == "optional"
41
41
  Requires-Dist: faiss-cpu>=1.7.4; extra == "optional"
42
42
  Requires-Dist: openai>=1.0.0; extra == "optional"
43
43
  Requires-Dist: nest-asyncio>=1.5.0; extra == "optional"
44
+ Provides-Extra: docs
45
+ Requires-Dist: mkdocs>=1.5.0; extra == "docs"
46
+ Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
44
47
  Dynamic: license-file
45
48
 
46
49
  # RouteKitAI
@@ -60,6 +63,8 @@ Dynamic: license-file
60
63
 
61
64
  ---
62
65
 
66
+ > **⚠️ Early stage**: RouteKitAI is still in very early development. APIs may change, and some features are experimental. Use with caution in production.
67
+
63
68
  RouteKitAI is a Python framework for building AI agents with **graph-based orchestration**, **built-in tracing**, and **deterministic replay**. Unlike other frameworks, RouteKitAI treats observability and testability as first-class features from day one.
64
69
 
65
70
  ## ✨ Features
@@ -202,6 +207,7 @@ asyncio.run(main())
202
207
  Check out the [`examples/`](examples/) directory for complete examples:
203
208
 
204
209
  - **[Basic Agent](examples/basic.py)** / **[Hello RouteKit](examples/hello_routekit.py)**: Simple agent with tools
210
+ - **[Real agent with Anthropic](examples/anthropic_agent.py)**: Live Claude agent with tool use (requires `ANTHROPIC_API_KEY`)
205
211
  - **[Graph Orchestration](examples/graph_agent.py)** / **[Graph Policy](examples/graph_policy.py)**: Multi-agent workflows
206
212
  - **[Supervisor Pattern](examples/supervisor_agent.py)** / **[Supervisor Policy](examples/supervisor_policy.py)**: Supervisor delegating to sub-agents
207
213
  - **[ReAct / Plan–Execute / Function Calling](examples/react_policy.py)**, **[Plan–Execute](examples/plan_execute_policy.py)**, **[Function Calling](examples/function_calling_policy.py)**: Policy examples
@@ -305,8 +311,29 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) and:
305
311
 
306
312
  ## 📋 Requirements
307
313
 
308
- - Python 3.11 or higher
309
- - Pydantic 2.0+
314
+ **Core (always installed):**
315
+
316
+ - Python 3.11+
317
+ - [Pydantic](https://docs.pydantic.dev/) 2.x
318
+ - [NumPy](https://numpy.org/) 1.24+
319
+ - [httpx](https://www.python-httpx.org/) 0.24+
320
+
321
+ **Optional extras:**
322
+
323
+ | Extra | Purpose |
324
+ |-------|---------|
325
+ | `[dev]` | CLI, tests, linting, type checking (pytest, mypy, ruff, rich, typer, safety, bandit) |
326
+ | `[ui]` | Web UI for traces: `routekitai serve` (FastAPI, Uvicorn) |
327
+ | `[optional]` | Vector memory, OpenAI adapter (sentence-transformers, faiss, openai, nest-asyncio) |
328
+ | `[docs]` | Build documentation locally (MkDocs, MkDocs Material) |
329
+
330
+ Examples:
331
+
332
+ ```bash
333
+ pip install "RouteKitAI[dev]" # development + CLI
334
+ pip install "RouteKitAI[dev,ui]" # + trace web UI
335
+ pip install "RouteKitAI[docs]" # build docs: mkdocs build / mkdocs serve
336
+ ```
310
337
 
311
338
  ## 📄 License
312
339
 
@@ -15,6 +15,8 @@
15
15
 
16
16
  ---
17
17
 
18
+ > **⚠️ Early stage**: RouteKitAI is still in very early development. APIs may change, and some features are experimental. Use with caution in production.
19
+
18
20
  RouteKitAI is a Python framework for building AI agents with **graph-based orchestration**, **built-in tracing**, and **deterministic replay**. Unlike other frameworks, RouteKitAI treats observability and testability as first-class features from day one.
19
21
 
20
22
  ## ✨ Features
@@ -157,6 +159,7 @@ asyncio.run(main())
157
159
  Check out the [`examples/`](examples/) directory for complete examples:
158
160
 
159
161
  - **[Basic Agent](examples/basic.py)** / **[Hello RouteKit](examples/hello_routekit.py)**: Simple agent with tools
162
+ - **[Real agent with Anthropic](examples/anthropic_agent.py)**: Live Claude agent with tool use (requires `ANTHROPIC_API_KEY`)
160
163
  - **[Graph Orchestration](examples/graph_agent.py)** / **[Graph Policy](examples/graph_policy.py)**: Multi-agent workflows
161
164
  - **[Supervisor Pattern](examples/supervisor_agent.py)** / **[Supervisor Policy](examples/supervisor_policy.py)**: Supervisor delegating to sub-agents
162
165
  - **[ReAct / Plan–Execute / Function Calling](examples/react_policy.py)**, **[Plan–Execute](examples/plan_execute_policy.py)**, **[Function Calling](examples/function_calling_policy.py)**: Policy examples
@@ -260,8 +263,29 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) and:
260
263
 
261
264
  ## 📋 Requirements
262
265
 
263
- - Python 3.11 or higher
264
- - Pydantic 2.0+
266
+ **Core (always installed):**
267
+
268
+ - Python 3.11+
269
+ - [Pydantic](https://docs.pydantic.dev/) 2.x
270
+ - [NumPy](https://numpy.org/) 1.24+
271
+ - [httpx](https://www.python-httpx.org/) 0.24+
272
+
273
+ **Optional extras:**
274
+
275
+ | Extra | Purpose |
276
+ |-------|---------|
277
+ | `[dev]` | CLI, tests, linting, type checking (pytest, mypy, ruff, rich, typer, safety, bandit) |
278
+ | `[ui]` | Web UI for traces: `routekitai serve` (FastAPI, Uvicorn) |
279
+ | `[optional]` | Vector memory, OpenAI adapter (sentence-transformers, faiss, openai, nest-asyncio) |
280
+ | `[docs]` | Build documentation locally (MkDocs, MkDocs Material) |
281
+
282
+ Examples:
283
+
284
+ ```bash
285
+ pip install "RouteKitAI[dev]" # development + CLI
286
+ pip install "RouteKitAI[dev,ui]" # + trace web UI
287
+ pip install "RouteKitAI[docs]" # build docs: mkdocs build / mkdocs serve
288
+ ```
265
289
 
266
290
  ## 📄 License
267
291
 
@@ -105,7 +105,7 @@ Overview of the main public APIs in RouteKitAI. For full signatures and docstrin
105
105
  |--------|-------------|
106
106
  | **FakeModel** | Local model with preloaded responses (no API key). |
107
107
  | **OpenAIChatModel** | OpenAI chat API. |
108
- | **AnthropicChatModel** | Anthropic API (if installed). |
108
+ | **AnthropicModel** | Anthropic Claude (Messages API). |
109
109
  | **AzureOpenAIChatModel** | Azure OpenAI (if installed). |
110
110
 
111
111
  ---
@@ -58,14 +58,21 @@ model = OpenAIChatModel(
58
58
 
59
59
  ## Anthropic
60
60
 
61
- Uses the Anthropic API. Install the optional dependency and use the provider (if exposed in the package):
61
+ Uses the Anthropic Messages API (Claude). No extra install beyond RouteKitAI; the provider uses `httpx` (already a dependency).
62
62
 
63
63
  ```python
64
- # Check routekitai.providers for exact import
65
- from routekitai.providers.anthropic import AnthropicChatModel # if available
64
+ import os
65
+ from routekitai.providers import AnthropicModel
66
+
67
+ model = AnthropicModel(
68
+ name="claude-3-5-sonnet-20241022",
69
+ api_key=os.environ.get("ANTHROPIC_API_KEY"),
70
+ )
66
71
  ```
67
72
 
68
- Configure with `ANTHROPIC_API_KEY` and the desired model name.
73
+ - **api_key** — Prefer `ANTHROPIC_API_KEY` environment variable.
74
+ - **name** — Model name (e.g. `claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`).
75
+ - **base_url** — Optional; defaults to `https://api.anthropic.com/v1`.
69
76
 
70
77
  ## Azure OpenAI
71
78
 
@@ -0,0 +1,107 @@
1
+ """Example: Real agent with Anthropic Claude.
2
+
3
+ This example runs a live agent using Anthropic's Claude model with tool use.
4
+ The agent can answer questions and call tools (e.g. echo) in a ReAct loop.
5
+
6
+ To run this example:
7
+ 1. Set your Anthropic API key: export ANTHROPIC_API_KEY='your-api-key-here'
8
+ 2. (Optional) Set model: export ANTHROPIC_MODEL='claude-sonnet-4-5-20250929'
9
+ If you get a 404 "model not found", list models at https://docs.anthropic.com/en/api/models
10
+ and set ANTHROPIC_MODEL to a model ID available in your account.
11
+ 3. Install httpx (required by Anthropic provider): pip install httpx
12
+ 4. Run: python examples/anthropic_agent.py
13
+
14
+ Note: This example uses real Anthropic API calls and will consume API credits.
15
+ Ensure your Anthropic account has sufficient credits (Plans & Billing).
16
+ """
17
+
18
+ import asyncio
19
+ import os
20
+ from pathlib import Path
21
+
22
+ from routekitai import Agent
23
+ from routekitai.core.message import MessageRole
24
+ from routekitai.core.policies import ReActPolicy
25
+ from routekitai.core.tools import EchoTool
26
+ from routekitai.providers.anthropic import AnthropicModel
27
+
28
+
29
+ async def main() -> None:
30
+ """Run a real agent with Anthropic Claude."""
31
+ print("Running real agent example with Anthropic Claude...")
32
+ print("=" * 60)
33
+
34
+ api_key = os.getenv("ANTHROPIC_API_KEY")
35
+ if not api_key:
36
+ raise ValueError(
37
+ "ANTHROPIC_API_KEY environment variable not set. "
38
+ "Please set it with: export ANTHROPIC_API_KEY='your-api-key-here'"
39
+ )
40
+
41
+ # Model: use ANTHROPIC_MODEL env var or a default (see https://docs.anthropic.com/en/api/models)
42
+ model_id = os.getenv("ANTHROPIC_MODEL", "claude-sonnet-4-5-20250929")
43
+ model = AnthropicModel(
44
+ name=model_id,
45
+ api_key=api_key,
46
+ provider="anthropic",
47
+ )
48
+
49
+ agent = Agent(
50
+ name="claude_agent",
51
+ model=model,
52
+ tools=[EchoTool()],
53
+ policy=ReActPolicy(max_iterations=25),
54
+ )
55
+
56
+ print(f"✓ Using Anthropic API (model: {model_id})")
57
+ print("✓ Agent has echo tool available")
58
+ print()
59
+
60
+ # Run the agent with a prompt that may trigger tool use
61
+ prompt = (
62
+ "What is 2 + 2? Give the number only. "
63
+ "Then use the echo tool to echo the word 'done' so I know you finished."
64
+ )
65
+ print("Prompt:", prompt)
66
+ print("-" * 60)
67
+
68
+ async with model:
69
+ result = await agent.run(prompt)
70
+
71
+ print()
72
+ print("=" * 60)
73
+ print("Agent run completed!")
74
+ print("=" * 60)
75
+ print("\nOutput:")
76
+ output_text = (result.output.content or "").strip()
77
+ if output_text:
78
+ print(output_text)
79
+ else:
80
+ # Fallback when model returned no final text (e.g. after tool use)
81
+ last_with_content = None
82
+ for msg in reversed(result.messages):
83
+ if msg.role == MessageRole.ASSISTANT and (msg.content or "").strip():
84
+ last_with_content = msg.content.strip()
85
+ break
86
+ if last_with_content:
87
+ print(last_with_content)
88
+ else:
89
+ # Show tool results if any
90
+ tool_results = [
91
+ str(msg.tool_result.get("result", msg.content))
92
+ for msg in result.messages
93
+ if msg.role == MessageRole.TOOL and msg.tool_result
94
+ ]
95
+ if tool_results:
96
+ print("(no final text; tool results: ", ", ".join(tool_results), ")")
97
+ else:
98
+ print("(no text output)")
99
+
100
+ trace_path = Path(".routekit") / "traces" / f"{result.trace_id}.jsonl"
101
+ print(f"\nTrace ID: {result.trace_id}")
102
+ if trace_path.exists():
103
+ print(f"Trace saved to: {trace_path}")
104
+
105
+
106
+ if __name__ == "__main__":
107
+ asyncio.run(main())
@@ -55,6 +55,10 @@ optional = [
55
55
  "openai>=1.0.0",
56
56
  "nest-asyncio>=1.5.0",
57
57
  ]
58
+ docs = [
59
+ "mkdocs>=1.5.0",
60
+ "mkdocs-material>=9.0.0",
61
+ ]
58
62
 
59
63
  [project.urls]
60
64
  Homepage = "https://github.com/MedGhassen/RouteKit"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RouteKitAI
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: An agent development + orchestration framework
5
5
  Author: Mohamed Ghassen Brahim
6
6
  License: MIT
@@ -41,6 +41,9 @@ Requires-Dist: sentence-transformers>=2.2.0; extra == "optional"
41
41
  Requires-Dist: faiss-cpu>=1.7.4; extra == "optional"
42
42
  Requires-Dist: openai>=1.0.0; extra == "optional"
43
43
  Requires-Dist: nest-asyncio>=1.5.0; extra == "optional"
44
+ Provides-Extra: docs
45
+ Requires-Dist: mkdocs>=1.5.0; extra == "docs"
46
+ Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
44
47
  Dynamic: license-file
45
48
 
46
49
  # RouteKitAI
@@ -60,6 +63,8 @@ Dynamic: license-file
60
63
 
61
64
  ---
62
65
 
66
+ > **⚠️ Early stage**: RouteKitAI is still in very early development. APIs may change, and some features are experimental. Use with caution in production.
67
+
63
68
  RouteKitAI is a Python framework for building AI agents with **graph-based orchestration**, **built-in tracing**, and **deterministic replay**. Unlike other frameworks, RouteKitAI treats observability and testability as first-class features from day one.
64
69
 
65
70
  ## ✨ Features
@@ -202,6 +207,7 @@ asyncio.run(main())
202
207
  Check out the [`examples/`](examples/) directory for complete examples:
203
208
 
204
209
  - **[Basic Agent](examples/basic.py)** / **[Hello RouteKit](examples/hello_routekit.py)**: Simple agent with tools
210
+ - **[Real agent with Anthropic](examples/anthropic_agent.py)**: Live Claude agent with tool use (requires `ANTHROPIC_API_KEY`)
205
211
  - **[Graph Orchestration](examples/graph_agent.py)** / **[Graph Policy](examples/graph_policy.py)**: Multi-agent workflows
206
212
  - **[Supervisor Pattern](examples/supervisor_agent.py)** / **[Supervisor Policy](examples/supervisor_policy.py)**: Supervisor delegating to sub-agents
207
213
  - **[ReAct / Plan–Execute / Function Calling](examples/react_policy.py)**, **[Plan–Execute](examples/plan_execute_policy.py)**, **[Function Calling](examples/function_calling_policy.py)**: Policy examples
@@ -305,8 +311,29 @@ Contributions are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) and:
305
311
 
306
312
  ## 📋 Requirements
307
313
 
308
- - Python 3.11 or higher
309
- - Pydantic 2.0+
314
+ **Core (always installed):**
315
+
316
+ - Python 3.11+
317
+ - [Pydantic](https://docs.pydantic.dev/) 2.x
318
+ - [NumPy](https://numpy.org/) 1.24+
319
+ - [httpx](https://www.python-httpx.org/) 0.24+
320
+
321
+ **Optional extras:**
322
+
323
+ | Extra | Purpose |
324
+ |-------|---------|
325
+ | `[dev]` | CLI, tests, linting, type checking (pytest, mypy, ruff, rich, typer, safety, bandit) |
326
+ | `[ui]` | Web UI for traces: `routekitai serve` (FastAPI, Uvicorn) |
327
+ | `[optional]` | Vector memory, OpenAI adapter (sentence-transformers, faiss, openai, nest-asyncio) |
328
+ | `[docs]` | Build documentation locally (MkDocs, MkDocs Material) |
329
+
330
+ Examples:
331
+
332
+ ```bash
333
+ pip install "RouteKitAI[dev]" # development + CLI
334
+ pip install "RouteKitAI[dev,ui]" # + trace web UI
335
+ pip install "RouteKitAI[docs]" # build docs: mkdocs build / mkdocs serve
336
+ ```
310
337
 
311
338
  ## 📄 License
312
339
 
@@ -15,6 +15,7 @@ docs/guides/providers.md
15
15
  docs/guides/running-agents.md
16
16
  docs/guides/tracing-and-replay.md
17
17
  examples/__init__.py
18
+ examples/anthropic_agent.py
18
19
  examples/basic.py
19
20
  examples/eval_regression.py
20
21
  examples/function_calling_policy.py
@@ -13,6 +13,10 @@ typer>=0.9.0
13
13
  safety>=2.0.0
14
14
  bandit>=1.7.0
15
15
 
16
+ [docs]
17
+ mkdocs>=1.5.0
18
+ mkdocs-material>=9.0.0
19
+
16
20
  [optional]
17
21
  sentence-transformers>=2.2.0
18
22
  faiss-cpu>=1.7.4
@@ -1,6 +1,6 @@
1
1
  """RouteKitAI: An agent development + orchestration framework."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.2.1"
4
4
 
5
5
  # Import hooks first to ensure ToolFilter is defined before Agent
6
6
  from routekitai.core import (
@@ -25,7 +25,8 @@ class ReActPolicy(Policy):
25
25
  Simple loop: model -> decide tool -> tool -> model -> final
26
26
  """
27
27
 
28
- max_iterations: int = 10
28
+ def __init__(self, max_iterations: int = 10) -> None:
29
+ self.max_iterations = max_iterations
29
30
 
30
31
  async def plan(self, state: dict[str, Any]) -> list[Action]:
31
32
  """Plan next action in ReAct loop.
@@ -543,6 +543,14 @@ class Runtime(BaseModel):
543
543
  output_message = Message.assistant(final_response.content)
544
544
  messages.append(output_message)
545
545
 
546
+ # If final output has no content (e.g. model returned empty after tool use),
547
+ # use the last assistant message that had content so the run result is useful.
548
+ if not (output_message.content or "").strip() and messages:
549
+ for msg in reversed(messages):
550
+ if msg.role == MessageRole.ASSISTANT and (msg.content or "").strip():
551
+ output_message = msg
552
+ break
553
+
546
554
  # Import here to avoid circular import
547
555
  from routekitai.core.agent import RunResult
548
556
 
@@ -1,9 +1,11 @@
1
1
  """Model providers for RouteKit."""
2
2
 
3
+ from routekitai.providers.anthropic import AnthropicModel
3
4
  from routekitai.providers.local import FakeModel
4
5
  from routekitai.providers.openai import OpenAIChatModel
5
6
 
6
7
  __all__ = [
8
+ "AnthropicModel",
7
9
  "OpenAIChatModel",
8
10
  "FakeModel",
9
11
  ]
@@ -75,7 +75,11 @@ class AnthropicModel(Model):
75
75
  return self._client
76
76
 
77
77
  def _message_to_anthropic(self, message: Message) -> dict[str, Any]:
78
- """Convert routkitai Message to Anthropic format."""
78
+ """Convert routkitai Message to Anthropic format.
79
+
80
+ Anthropic requires all messages to have non-empty content except the
81
+ optional final assistant message. We ensure content is never empty.
82
+ """
79
83
  role_map = {
80
84
  MessageRole.SYSTEM: "system",
81
85
  MessageRole.USER: "user",
@@ -84,13 +88,15 @@ class AnthropicModel(Model):
84
88
  # Anthropic doesn't support tool role messages directly
85
89
  if message.role == MessageRole.TOOL:
86
90
  # Convert tool messages to user messages with tool result
87
- return {
88
- "role": "user",
89
- "content": f"Tool result: {message.content}",
90
- }
91
+ content = (
92
+ f"Tool result: {message.content}" if message.content else "Tool result: (no output)"
93
+ )
94
+ return {"role": "user", "content": content}
95
+ # API rejects empty or whitespace-only content; use a non-whitespace placeholder
96
+ content = message.content if (message.content and message.content.strip()) else "(no text)"
91
97
  return {
92
98
  "role": role_map.get(message.role, "user"),
93
- "content": message.content,
99
+ "content": content,
94
100
  }
95
101
 
96
102
  def _tools_to_anthropic(self, tools: list[Tool]) -> list[dict[str, Any]]:
@@ -208,9 +214,19 @@ class AnthropicModel(Model):
208
214
  )
209
215
 
210
216
  except httpx.HTTPStatusError as e:
211
- raise ModelError(
212
- f"Anthropic API error: {e.response.status_code} - {e.response.text}"
213
- ) from e
217
+ msg = f"Anthropic API error: {e.response.status_code}"
218
+ try:
219
+ body = e.response.json()
220
+ err = body.get("error") or {}
221
+ if isinstance(err, dict) and err.get("message"):
222
+ msg = f"{msg} - {err['message']}"
223
+ else:
224
+ msg = f"{msg} - {e.response.text}"
225
+ except Exception:
226
+ msg = f"{msg} - {e.response.text}"
227
+ if e.response.status_code == 404 and "model" in msg.lower():
228
+ msg += " Use a model ID from https://docs.anthropic.com/en/api/models or set ANTHROPIC_MODEL."
229
+ raise ModelError(msg) from e
214
230
  except Exception as e:
215
231
  raise ModelError(f"Failed to call Anthropic API: {e}") from e
216
232
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes