RouteKitAI 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- routekitai/__init__.py +1 -1
- routekitai/core/policies.py +2 -1
- routekitai/core/runtime.py +8 -0
- routekitai/providers/__init__.py +2 -0
- routekitai/providers/anthropic.py +25 -9
- {routekitai-0.2.0.dist-info → routekitai-0.2.1.dist-info}/METADATA +30 -3
- {routekitai-0.2.0.dist-info → routekitai-0.2.1.dist-info}/RECORD +11 -11
- {routekitai-0.2.0.dist-info → routekitai-0.2.1.dist-info}/WHEEL +0 -0
- {routekitai-0.2.0.dist-info → routekitai-0.2.1.dist-info}/entry_points.txt +0 -0
- {routekitai-0.2.0.dist-info → routekitai-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {routekitai-0.2.0.dist-info → routekitai-0.2.1.dist-info}/top_level.txt +0 -0
routekitai/__init__.py
CHANGED
routekitai/core/policies.py
CHANGED
|
@@ -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.
|
routekitai/core/runtime.py
CHANGED
|
@@ -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
|
|
routekitai/providers/__init__.py
CHANGED
|
@@ -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
|
-
|
|
88
|
-
"
|
|
89
|
-
|
|
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":
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: RouteKitAI
|
|
3
|
-
Version: 0.2.
|
|
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
|
-
|
|
309
|
-
|
|
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
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
routekitai/__init__.py,sha256=
|
|
1
|
+
routekitai/__init__.py,sha256=155KUL2u8F-wn5wV7oT4bwzpJ84l2OWhmsU-hk-MM3A,1091
|
|
2
2
|
routekitai/message.py,sha256=owTgRvHctqquWROng2w06c6sMrarKlB6avxHoPhuC3k,830
|
|
3
3
|
routekitai/model.py,sha256=FfGla6Hep-L1bz-rC89leGdbtQed433FZ1yz4eF0wko,1357
|
|
4
4
|
routekitai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -19,10 +19,10 @@ routekitai/core/hooks.py,sha256=lnp5tK_amFDUbkYWxvWnIDwQ2uI4em2Go0KLb1QtD7c,5644
|
|
|
19
19
|
routekitai/core/memory.py,sha256=szDTIr3tCgM4aeFO19tOlGj6a8lLPBHTv4KByeUxC2k,1429
|
|
20
20
|
routekitai/core/message.py,sha256=-nc3rPahQFADkeoA_Ipaq4ELPI14e23JAPIskIvM7js,3471
|
|
21
21
|
routekitai/core/model.py,sha256=vghe66IRXmRO5vNtxQl_L2aVrODE_5Fyj0g_BLCaSMQ,3158
|
|
22
|
-
routekitai/core/policies.py,sha256=
|
|
22
|
+
routekitai/core/policies.py,sha256=uNkeArb__aJdNCmdwVa8gWDZVTbSxW-MJHFgBInQFUw,13946
|
|
23
23
|
routekitai/core/policy.py,sha256=CscLNg2Z4U_XV-xC0mf7QlZN-QCJ3zewSz8uPE5NIR8,2814
|
|
24
24
|
routekitai/core/policy_adapter.py,sha256=GeVVQBfd4Bo3Ijzgcq8fdn1CRtC9XOVwb7f4SkfylYY,5887
|
|
25
|
-
routekitai/core/runtime.py,sha256=
|
|
25
|
+
routekitai/core/runtime.py,sha256=vOngcUlpJWq2t1ZgdJqQV2gChmlZBQtg9or6Frg3Bkk,61839
|
|
26
26
|
routekitai/core/tool.py,sha256=96zHRidFV8NX9x8fWvbNyT3Up2UL-0BjaNLBl_P79_o,4959
|
|
27
27
|
routekitai/core/tools.py,sha256=9jye7xa1NcJnSARRarRAIMsbF6gmyI4DlyCCv7HuRYM,5215
|
|
28
28
|
routekitai/evals/__init__.py,sha256=9J7kySk46qCOApOlIMvOsPSjc3_NzvxCSuZ8-OejBNU,336
|
|
@@ -47,8 +47,8 @@ routekitai/observability/exporters/__init__.py,sha256=g_YIeoJ_YWANEtETQgF7zEBNtW
|
|
|
47
47
|
routekitai/observability/exporters/base.py,sha256=zhkCem3xXqKmrB38QsFaM1HAbxECPOyLoPuO5Jbd-nA,672
|
|
48
48
|
routekitai/observability/exporters/jsonl.py,sha256=wBHgzfvBSksQQ_WLYXnPF9OH6_a7ldgbTlTUzTs0U7E,2621
|
|
49
49
|
routekitai/observability/exporters/otel.py,sha256=Cl25rA1robwJVaOtoHRT2W3VTGvY3ibJ0eoqXQwbsb8,4249
|
|
50
|
-
routekitai/providers/__init__.py,sha256
|
|
51
|
-
routekitai/providers/anthropic.py,sha256=
|
|
50
|
+
routekitai/providers/__init__.py,sha256=-43vXwysU7NNuluD2QcmNFNmlfKMgOq_5uCnWm6ptyY,277
|
|
51
|
+
routekitai/providers/anthropic.py,sha256=v8aSHz4zvCYW958tV-VjGN5joya8U4LCtSUJ86pNBfs,8634
|
|
52
52
|
routekitai/providers/azure_openai.py,sha256=2iTvaLFKTseKy41E4D1EOT4NvwsxK5BSo5G0xaJjd7Y,8312
|
|
53
53
|
routekitai/providers/local.py,sha256=Ii959ycdAOhnUucAlaBPCNP5YOxgFgRmuCbu_XibQwY,7693
|
|
54
54
|
routekitai/providers/openai.py,sha256=ImTGXOiHyNtXUNF2tzBF4Dkv8r_aPrmQDUH6Cu7-zi4,12641
|
|
@@ -56,9 +56,9 @@ routekitai/sandbox/__init__.py,sha256=erkRO6xnq7NcOmv_rV444IRJl0WmhRWoVX1Sx8XiqX
|
|
|
56
56
|
routekitai/sandbox/filesystem.py,sha256=5bLMhrutoJQVfOM49v1L1ykVpjFee50dERdyY4VaiGM,4744
|
|
57
57
|
routekitai/sandbox/network.py,sha256=cFK--kZ88irTREWgTWhXDBDvynzq9XdHjFn_jGcF3HI,4668
|
|
58
58
|
routekitai/sandbox/permissions.py,sha256=5rGeF_4JcpetrsVYZuAw-S-rV5vsic1OSJAh0we-uDs,2094
|
|
59
|
-
routekitai-0.2.
|
|
60
|
-
routekitai-0.2.
|
|
61
|
-
routekitai-0.2.
|
|
62
|
-
routekitai-0.2.
|
|
63
|
-
routekitai-0.2.
|
|
64
|
-
routekitai-0.2.
|
|
59
|
+
routekitai-0.2.1.dist-info/licenses/LICENSE,sha256=TftL8ryIHKESApEmr5TBlRg5mengWfrzzjlr7nz46iE,1079
|
|
60
|
+
routekitai-0.2.1.dist-info/METADATA,sha256=goTgbouS7za77-MZnmXGGZWc4bSh_tmAIbzATdBbi24,11747
|
|
61
|
+
routekitai-0.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
62
|
+
routekitai-0.2.1.dist-info/entry_points.txt,sha256=pHUdSYPaXtmUY5LmHWKcgh2dR-t0DRrgUZ3AO0Pk9L0,56
|
|
63
|
+
routekitai-0.2.1.dist-info/top_level.txt,sha256=lbYswJspf7-baehrsDZboTTxhrabTTPf4mGYC_jXKaY,11
|
|
64
|
+
routekitai-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|