RouteKitAI 0.1.0__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 +53 -0
- routekitai/cli/__init__.py +18 -0
- routekitai/cli/main.py +40 -0
- routekitai/cli/replay.py +80 -0
- routekitai/cli/run.py +95 -0
- routekitai/cli/serve.py +966 -0
- routekitai/cli/test_agent.py +178 -0
- routekitai/cli/trace.py +209 -0
- routekitai/cli/trace_analyze.py +120 -0
- routekitai/cli/trace_search.py +126 -0
- routekitai/core/__init__.py +58 -0
- routekitai/core/agent.py +325 -0
- routekitai/core/errors.py +49 -0
- routekitai/core/hooks.py +174 -0
- routekitai/core/memory.py +54 -0
- routekitai/core/message.py +132 -0
- routekitai/core/model.py +91 -0
- routekitai/core/policies.py +373 -0
- routekitai/core/policy.py +85 -0
- routekitai/core/policy_adapter.py +133 -0
- routekitai/core/runtime.py +1403 -0
- routekitai/core/tool.py +148 -0
- routekitai/core/tools.py +180 -0
- routekitai/evals/__init__.py +13 -0
- routekitai/evals/dataset.py +75 -0
- routekitai/evals/metrics.py +101 -0
- routekitai/evals/runner.py +184 -0
- routekitai/graphs/__init__.py +12 -0
- routekitai/graphs/executors.py +457 -0
- routekitai/graphs/graph.py +164 -0
- routekitai/memory/__init__.py +13 -0
- routekitai/memory/episodic.py +242 -0
- routekitai/memory/kv.py +34 -0
- routekitai/memory/retrieval.py +192 -0
- routekitai/memory/vector.py +700 -0
- routekitai/memory/working.py +66 -0
- routekitai/message.py +29 -0
- routekitai/model.py +48 -0
- routekitai/observability/__init__.py +21 -0
- routekitai/observability/analyzer.py +314 -0
- routekitai/observability/exporters/__init__.py +10 -0
- routekitai/observability/exporters/base.py +30 -0
- routekitai/observability/exporters/jsonl.py +81 -0
- routekitai/observability/exporters/otel.py +119 -0
- routekitai/observability/spans.py +111 -0
- routekitai/observability/streaming.py +117 -0
- routekitai/observability/trace.py +144 -0
- routekitai/providers/__init__.py +9 -0
- routekitai/providers/anthropic.py +227 -0
- routekitai/providers/azure_openai.py +243 -0
- routekitai/providers/local.py +196 -0
- routekitai/providers/openai.py +321 -0
- routekitai/py.typed +0 -0
- routekitai/sandbox/__init__.py +12 -0
- routekitai/sandbox/filesystem.py +131 -0
- routekitai/sandbox/network.py +142 -0
- routekitai/sandbox/permissions.py +70 -0
- routekitai/tool.py +33 -0
- routekitai-0.1.0.dist-info/METADATA +328 -0
- routekitai-0.1.0.dist-info/RECORD +64 -0
- routekitai-0.1.0.dist-info/WHEEL +5 -0
- routekitai-0.1.0.dist-info/entry_points.txt +2 -0
- routekitai-0.1.0.dist-info/licenses/LICENSE +21 -0
- routekitai-0.1.0.dist-info/top_level.txt +1 -0
routekitai/__init__.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""RouteKitAI: An agent development + orchestration framework."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.1.0"
|
|
4
|
+
|
|
5
|
+
# Import hooks first to ensure ToolFilter is defined before Agent
|
|
6
|
+
from routekitai.core import (
|
|
7
|
+
Agent,
|
|
8
|
+
Message,
|
|
9
|
+
MessageRole,
|
|
10
|
+
Model,
|
|
11
|
+
ModelError,
|
|
12
|
+
ModelResponse,
|
|
13
|
+
PolicyError,
|
|
14
|
+
RouteKitError,
|
|
15
|
+
RunResult,
|
|
16
|
+
Runtime,
|
|
17
|
+
StreamEvent,
|
|
18
|
+
Tool,
|
|
19
|
+
ToolCall,
|
|
20
|
+
ToolError,
|
|
21
|
+
Usage,
|
|
22
|
+
)
|
|
23
|
+
from routekitai.core import (
|
|
24
|
+
RuntimeError as RouteKitRuntimeError,
|
|
25
|
+
)
|
|
26
|
+
from routekitai.core.hooks import ToolFilter
|
|
27
|
+
from routekitai.core.policies import SupervisorPolicy
|
|
28
|
+
|
|
29
|
+
# Rebuild models to resolve forward references
|
|
30
|
+
# Runtime needs Agent, Agent needs ToolFilter, SupervisorPolicy needs Agent
|
|
31
|
+
Agent.model_rebuild()
|
|
32
|
+
Runtime.model_rebuild()
|
|
33
|
+
SupervisorPolicy.model_rebuild()
|
|
34
|
+
|
|
35
|
+
__all__ = [
|
|
36
|
+
"Agent",
|
|
37
|
+
"Message",
|
|
38
|
+
"MessageRole",
|
|
39
|
+
"Model",
|
|
40
|
+
"ModelResponse",
|
|
41
|
+
"RouteKitError",
|
|
42
|
+
"ModelError",
|
|
43
|
+
"ToolError",
|
|
44
|
+
"PolicyError",
|
|
45
|
+
"RouteKitRuntimeError",
|
|
46
|
+
"RunResult",
|
|
47
|
+
"Runtime",
|
|
48
|
+
"StreamEvent",
|
|
49
|
+
"Tool",
|
|
50
|
+
"ToolCall",
|
|
51
|
+
"ToolFilter",
|
|
52
|
+
"Usage",
|
|
53
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""CLI tools for RouteKit."""
|
|
2
|
+
|
|
3
|
+
# TODO: Implement CLI commands
|
|
4
|
+
try:
|
|
5
|
+
from routekitai.cli.replay import replay_command
|
|
6
|
+
from routekitai.cli.run import run as run_command
|
|
7
|
+
from routekitai.cli.test_agent import test_command
|
|
8
|
+
from routekitai.cli.trace import trace_command
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"run_command",
|
|
12
|
+
"trace_command",
|
|
13
|
+
"replay_command",
|
|
14
|
+
"test_command",
|
|
15
|
+
]
|
|
16
|
+
except ImportError:
|
|
17
|
+
# Typer not installed, CLI not available
|
|
18
|
+
__all__ = []
|
routekitai/cli/main.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Main CLI entry point for RouteKit."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
import typer
|
|
7
|
+
except ImportError:
|
|
8
|
+
print("Error: Typer and Rich are required for CLI. Install with: pip install 'routekit[dev]'")
|
|
9
|
+
sys.exit(1)
|
|
10
|
+
|
|
11
|
+
from routekitai.cli.replay import replay_command
|
|
12
|
+
from routekitai.cli.run import run as run_command
|
|
13
|
+
from routekitai.cli.serve import serve_command
|
|
14
|
+
from routekitai.cli.test_agent import test_command
|
|
15
|
+
from routekitai.cli.trace import trace_command
|
|
16
|
+
from routekitai.cli.trace_analyze import analyze_command
|
|
17
|
+
from routekitai.cli.trace_search import search_command
|
|
18
|
+
|
|
19
|
+
app = typer.Typer(
|
|
20
|
+
name="routekit",
|
|
21
|
+
help="RouteKit: An agent development + orchestration framework",
|
|
22
|
+
add_completion=False,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
app.command(name="run")(run_command)
|
|
26
|
+
app.command(name="trace")(trace_command)
|
|
27
|
+
app.command(name="trace-analyze")(analyze_command)
|
|
28
|
+
app.command(name="trace-search")(search_command)
|
|
29
|
+
app.command(name="serve")(serve_command)
|
|
30
|
+
app.command(name="replay")(replay_command)
|
|
31
|
+
app.command(name="test-agent")(test_command)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def main() -> None:
|
|
35
|
+
"""Main CLI entry point."""
|
|
36
|
+
app()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if __name__ == "__main__":
|
|
40
|
+
main()
|
routekitai/cli/replay.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""CLI command for replaying traces."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
except ImportError as e:
|
|
10
|
+
raise ImportError("CLI dependencies not installed. Install with: pip install typer rich") from e
|
|
11
|
+
|
|
12
|
+
from routekitai.core.runtime import Runtime
|
|
13
|
+
from routekitai.observability.exporters.jsonl import JSONLExporter
|
|
14
|
+
|
|
15
|
+
app = typer.Typer(name="replay", help="Replay agent execution traces")
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def replay_command(
|
|
20
|
+
trace_id: str = typer.Argument(..., help="Trace ID to replay"),
|
|
21
|
+
agent_name: str = typer.Option(..., "--agent", "-a", help="Agent name to use for replay"),
|
|
22
|
+
trace_dir: str | None = typer.Option(
|
|
23
|
+
None, "--trace-dir", "-t", help="Directory containing trace files"
|
|
24
|
+
),
|
|
25
|
+
verify: bool = typer.Option(
|
|
26
|
+
True, "--verify/--no-verify", help="Verify outputs match original trace"
|
|
27
|
+
),
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Replay a trace with deterministic execution.
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
routkitai replay abc123 --agent my_agent
|
|
33
|
+
routkitai replay abc123 --agent my_agent --no-verify
|
|
34
|
+
routkitai replay abc123 --agent my_agent --trace-dir ./custom_traces
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
async def _replay() -> None:
|
|
38
|
+
# Determine trace directory
|
|
39
|
+
if trace_dir is None:
|
|
40
|
+
trace_dir_path = Path(".routekit") / "traces"
|
|
41
|
+
else:
|
|
42
|
+
trace_dir_path = Path(trace_dir)
|
|
43
|
+
|
|
44
|
+
if not trace_dir_path.exists():
|
|
45
|
+
console.print(f"[red]Error: Trace directory not found: {trace_dir_path}[/red]")
|
|
46
|
+
raise typer.Exit(1)
|
|
47
|
+
|
|
48
|
+
console.print(f"[green]Replaying trace: {trace_id}[/green]")
|
|
49
|
+
console.print(f"[dim]Agent: {agent_name}[/dim]")
|
|
50
|
+
console.print(f"[dim]Trace dir: {trace_dir_path}[/dim]\n")
|
|
51
|
+
|
|
52
|
+
# Create runtime and replay
|
|
53
|
+
runtime = Runtime(trace_dir=trace_dir_path)
|
|
54
|
+
result = await runtime.replay(trace_id, agent_name, verify_output=verify)
|
|
55
|
+
|
|
56
|
+
console.print("\n[bold]Replay completed[/bold]")
|
|
57
|
+
console.print(f"[green]Output:[/green] {result.output.content}")
|
|
58
|
+
console.print(f"[dim]Trace ID: {result.trace_id}[/dim]")
|
|
59
|
+
|
|
60
|
+
if verify:
|
|
61
|
+
# Load original trace for comparison
|
|
62
|
+
exporter = JSONLExporter(output_dir=trace_dir_path)
|
|
63
|
+
original_trace = await exporter.load(trace_id)
|
|
64
|
+
if original_trace:
|
|
65
|
+
original_completed = original_trace.get_events_by_type("run_completed")
|
|
66
|
+
if original_completed:
|
|
67
|
+
original_result = original_completed[0].data.get("result", {})
|
|
68
|
+
original_output = original_result.get("output", {}).get("content", "")
|
|
69
|
+
if original_output != result.output.content:
|
|
70
|
+
console.print("\n[yellow]⚠ Warning: Output mismatch![/yellow]")
|
|
71
|
+
console.print(f"[dim] Original: {original_output}[/dim]")
|
|
72
|
+
console.print(f"[dim] Replay: {result.output.content}[/dim]")
|
|
73
|
+
else:
|
|
74
|
+
console.print("\n[green]✓ Output matches original trace[/green]")
|
|
75
|
+
|
|
76
|
+
asyncio.run(_replay())
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__" and app is not None:
|
|
80
|
+
app()
|
routekitai/cli/run.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""CLI command for running agents."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
import typer
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.markdown import Markdown
|
|
10
|
+
except ImportError as e:
|
|
11
|
+
raise ImportError("CLI dependencies not installed. Install with: pip install typer rich") from e
|
|
12
|
+
|
|
13
|
+
app = typer.Typer(name="run", help="Run an agent with a prompt or script")
|
|
14
|
+
console = Console()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
async def _run_agent_from_script(script_path: Path) -> None:
|
|
18
|
+
"""Run an agent from a Python script.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
script_path: Path to Python script
|
|
22
|
+
"""
|
|
23
|
+
import importlib.util
|
|
24
|
+
import sys
|
|
25
|
+
|
|
26
|
+
spec = importlib.util.spec_from_file_location("agent_script", script_path)
|
|
27
|
+
if spec is None or spec.loader is None:
|
|
28
|
+
console.print(f"[red]Error: Could not load script from {script_path}[/red]")
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
module = importlib.util.module_from_spec(spec)
|
|
32
|
+
sys.modules["agent_script"] = module
|
|
33
|
+
spec.loader.exec_module(module)
|
|
34
|
+
|
|
35
|
+
# Look for a main() function or agent definition
|
|
36
|
+
if hasattr(module, "main"):
|
|
37
|
+
if asyncio.iscoroutinefunction(module.main):
|
|
38
|
+
await module.main()
|
|
39
|
+
else:
|
|
40
|
+
module.main()
|
|
41
|
+
else:
|
|
42
|
+
console.print("[yellow]Warning: No main() function found in script[/yellow]")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@app.command()
|
|
46
|
+
def run(
|
|
47
|
+
prompt_or_script: str = typer.Argument(..., help="Prompt string or path to Python script"),
|
|
48
|
+
agent_name: str = typer.Option("default", "--agent", "-a", help="Agent name (if using script)"),
|
|
49
|
+
trace_dir: str | None = typer.Option(
|
|
50
|
+
None, "--trace-dir", "-t", help="Directory for trace files"
|
|
51
|
+
),
|
|
52
|
+
output_format: str = typer.Option("text", "--format", "-f", help="Output format: text, json"),
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Run an agent with a prompt or execute a Python script.
|
|
55
|
+
|
|
56
|
+
Examples:
|
|
57
|
+
routkitai run "What is 2+2?"
|
|
58
|
+
routkitai run agent_script.py
|
|
59
|
+
routkitai run "Hello" --agent my_agent --format json
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
script_path = Path(prompt_or_script)
|
|
63
|
+
is_script = script_path.exists() and script_path.suffix == ".py"
|
|
64
|
+
|
|
65
|
+
if is_script:
|
|
66
|
+
# Run as script
|
|
67
|
+
console.print(f"[green]Running script: {script_path}[/green]")
|
|
68
|
+
asyncio.run(_run_agent_from_script(script_path))
|
|
69
|
+
else:
|
|
70
|
+
# Run as prompt (requires agent to be registered)
|
|
71
|
+
console.print("[yellow]Note: Direct prompt execution requires a registered agent.[/yellow]")
|
|
72
|
+
console.print("[yellow]Consider using a script or the Python API instead.[/yellow]")
|
|
73
|
+
console.print(f"\n[dim]Prompt: {prompt_or_script}[/dim]")
|
|
74
|
+
console.print("[dim]Agent: {agent_name}[/dim]")
|
|
75
|
+
console.print("\n[blue]Example Python usage:[/blue]")
|
|
76
|
+
console.print(
|
|
77
|
+
Markdown(
|
|
78
|
+
f"""
|
|
79
|
+
```python
|
|
80
|
+
from routkitai import Agent, Runtime
|
|
81
|
+
from routekitai.providers.local import FakeModel
|
|
82
|
+
|
|
83
|
+
model = FakeModel(name="test")
|
|
84
|
+
agent = Agent(name="my_agent", model=model)
|
|
85
|
+
|
|
86
|
+
result = await agent.run("{prompt_or_script}")
|
|
87
|
+
print(result.output.content)
|
|
88
|
+
```
|
|
89
|
+
"""
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__" and app is not None:
|
|
95
|
+
app()
|