rapidagent 0.3.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.
- rapidagent/__init__.py +4 -0
- rapidagent/backends/__init__.py +16 -0
- rapidagent/backends/base.py +193 -0
- rapidagent/backends/direct.py +1018 -0
- rapidagent/backends/langgraph.py +185 -0
- rapidagent/blueprints/__init__.py +5 -0
- rapidagent/blueprints/rag.py +62 -0
- rapidagent/blueprints/research.py +91 -0
- rapidagent/blueprints/support.py +95 -0
- rapidagent/cli/__init__.py +0 -0
- rapidagent/cli/main.py +309 -0
- rapidagent/config/__init__.py +5 -0
- rapidagent/config/defaults.py +42 -0
- rapidagent/config/loader.py +46 -0
- rapidagent/config/schema.py +58 -0
- rapidagent/core/__init__.py +5 -0
- rapidagent/core/base.py +255 -0
- rapidagent/core/state.py +45 -0
- rapidagent/core/types.py +19 -0
- rapidagent/graphs/__init__.py +6 -0
- rapidagent/graphs/react.py +66 -0
- rapidagent/graphs/sequential.py +54 -0
- rapidagent/graphs/supervisor.py +116 -0
- rapidagent/graphs/swarm.py +98 -0
- rapidagent/guardrails/__init__.py +22 -0
- rapidagent/guardrails/base.py +199 -0
- rapidagent/guardrails/builtins.py +318 -0
- rapidagent/guardrails/config.py +97 -0
- rapidagent/memory/__init__.py +5 -0
- rapidagent/memory/base.py +34 -0
- rapidagent/memory/file_store.py +47 -0
- rapidagent/memory/in_memory.py +29 -0
- rapidagent/models/__init__.py +3 -0
- rapidagent/models/config.py +547 -0
- rapidagent/nodes/__init__.py +7 -0
- rapidagent/nodes/human.py +45 -0
- rapidagent/nodes/llm.py +44 -0
- rapidagent/nodes/memory.py +48 -0
- rapidagent/nodes/router.py +42 -0
- rapidagent/nodes/tool_executor.py +49 -0
- rapidagent/tools/__init__.py +5 -0
- rapidagent/tools/builtins.py +32 -0
- rapidagent/tools/decorator.py +80 -0
- rapidagent/tools/registry.py +51 -0
- rapidagent-0.3.0.dist-info/METADATA +394 -0
- rapidagent-0.3.0.dist-info/RECORD +50 -0
- rapidagent-0.3.0.dist-info/WHEEL +5 -0
- rapidagent-0.3.0.dist-info/entry_points.txt +2 -0
- rapidagent-0.3.0.dist-info/licenses/LICENSE +21 -0
- rapidagent-0.3.0.dist-info/top_level.txt +1 -0
rapidagent/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Lazy imports — backends may have optional dependencies
|
|
2
|
+
from rapidagent.backends.base import Backend, BackendResult
|
|
3
|
+
|
|
4
|
+
__all__ = ["Backend", "BackendResult"]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def LangGraphBackend(*args, **kwargs):
|
|
8
|
+
"""Lazy loader — langgraph is an optional dependency."""
|
|
9
|
+
from rapidagent.backends.langgraph import LangGraphBackend as _LB
|
|
10
|
+
return _LB(*args, **kwargs)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def DirectBackend(*args, **kwargs):
|
|
14
|
+
"""Lazy loader — pure Python, no extra deps."""
|
|
15
|
+
from rapidagent.backends.direct import DirectBackend as _DB
|
|
16
|
+
return _DB(*args, **kwargs)
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"""Abstract backend interface for agent execution."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import abc
|
|
6
|
+
import sys
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
|
+
from typing import Any, Generator
|
|
9
|
+
|
|
10
|
+
from rapidagent.models.config import ModelConfig
|
|
11
|
+
from rapidagent.tools.registry import ToolRegistry
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Token / cost tracking
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class TokenUsage:
|
|
20
|
+
"""Token and cost tracking from an LLM response."""
|
|
21
|
+
|
|
22
|
+
prompt_tokens: int = 0
|
|
23
|
+
completion_tokens: int = 0
|
|
24
|
+
total_tokens: int = 0
|
|
25
|
+
cost_usd: float = 0.0
|
|
26
|
+
|
|
27
|
+
def add(self, other: TokenUsage) -> None:
|
|
28
|
+
self.prompt_tokens += other.prompt_tokens
|
|
29
|
+
self.completion_tokens += other.completion_tokens
|
|
30
|
+
self.total_tokens += other.total_tokens
|
|
31
|
+
self.cost_usd += other.cost_usd
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def from_openai_response(cls, response: Any, model: str = "gpt-4o-mini") -> TokenUsage:
|
|
35
|
+
"""Parse token usage from an OpenAI chat completion response."""
|
|
36
|
+
rates = {
|
|
37
|
+
"gpt-4o-mini": (0.00015, 0.00060),
|
|
38
|
+
"gpt-4o": (0.00250, 0.01000),
|
|
39
|
+
"gpt-5": (0.00500, 0.02000),
|
|
40
|
+
}
|
|
41
|
+
usage = getattr(response, "usage", None) or getattr(response, "usage_metadata", None)
|
|
42
|
+
if usage is None:
|
|
43
|
+
return cls()
|
|
44
|
+
|
|
45
|
+
pt = getattr(usage, "prompt_tokens", getattr(usage, "input_tokens", 0)) or 0
|
|
46
|
+
ct = getattr(usage, "completion_tokens", getattr(usage, "output_tokens", 0)) or 0
|
|
47
|
+
r = rates.get(model, (0.0, 0.0))
|
|
48
|
+
cost = (pt / 1_000_000) * r[0] + (ct / 1_000_000) * r[1]
|
|
49
|
+
return cls(prompt_tokens=pt, completion_tokens=ct, total_tokens=pt + ct, cost_usd=cost)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# Result
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class BackendResult:
|
|
58
|
+
"""Standard result returned by any backend's ``invoke`` / ``stream``."""
|
|
59
|
+
|
|
60
|
+
messages: list[Any] = field(default_factory=list)
|
|
61
|
+
content: str = ""
|
|
62
|
+
error: str | None = None
|
|
63
|
+
raw: dict[str, Any] = field(default_factory=dict)
|
|
64
|
+
usage: TokenUsage = field(default_factory=TokenUsage)
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def from_content(cls, content: str) -> "BackendResult":
|
|
68
|
+
return cls(content=content, messages=[{"role": "assistant", "content": content}])
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ---------------------------------------------------------------------------
|
|
72
|
+
# Backend
|
|
73
|
+
# ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
class Backend(abc.ABC):
|
|
76
|
+
"""Abstract base for agent execution backends."""
|
|
77
|
+
|
|
78
|
+
name: str = ""
|
|
79
|
+
|
|
80
|
+
def __init__(self, checkpoint_dir: str | None = None) -> None:
|
|
81
|
+
self._checkpoint_dir = checkpoint_dir
|
|
82
|
+
self._guardrail_pipeline: Any = None
|
|
83
|
+
|
|
84
|
+
def set_guardrails(self, pipeline: Any) -> None:
|
|
85
|
+
self._guardrail_pipeline = pipeline
|
|
86
|
+
|
|
87
|
+
# -- Single agent --
|
|
88
|
+
|
|
89
|
+
@abc.abstractmethod
|
|
90
|
+
def build_react(
|
|
91
|
+
self,
|
|
92
|
+
llm_config: ModelConfig,
|
|
93
|
+
tools: ToolRegistry,
|
|
94
|
+
system_prompt: str,
|
|
95
|
+
max_iterations: int = 10,
|
|
96
|
+
response_format: type | None = None,
|
|
97
|
+
) -> Any:
|
|
98
|
+
"""Build a compiled ReAct agent.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
llm_config: Model configuration (provider, model, auth, etc.).
|
|
102
|
+
tools: Registered tools.
|
|
103
|
+
system_prompt: System prompt for the LLM.
|
|
104
|
+
max_iterations: Max ReAct loop iterations.
|
|
105
|
+
response_format: Optional Pydantic model for structured output.
|
|
106
|
+
Returns:
|
|
107
|
+
An opaque compiled object for ``invoke`` / ``stream``.
|
|
108
|
+
"""
|
|
109
|
+
...
|
|
110
|
+
|
|
111
|
+
@abc.abstractmethod
|
|
112
|
+
def invoke(
|
|
113
|
+
self,
|
|
114
|
+
compiled: Any,
|
|
115
|
+
message: str,
|
|
116
|
+
thread_id: str | None = None,
|
|
117
|
+
stream: bool = False,
|
|
118
|
+
) -> BackendResult:
|
|
119
|
+
"""Run the agent with a message.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
compiled: Compiled agent from ``build_react``.
|
|
123
|
+
message: User input.
|
|
124
|
+
thread_id: Conversation thread ID (for checkpointing).
|
|
125
|
+
stream: If True, ``result.content`` is updated progressively.
|
|
126
|
+
"""
|
|
127
|
+
...
|
|
128
|
+
|
|
129
|
+
@abc.abstractmethod
|
|
130
|
+
def stream(
|
|
131
|
+
self,
|
|
132
|
+
compiled: Any,
|
|
133
|
+
message: str,
|
|
134
|
+
thread_id: str | None = None,
|
|
135
|
+
) -> Any:
|
|
136
|
+
"""Stream agent execution events."""
|
|
137
|
+
...
|
|
138
|
+
|
|
139
|
+
# -- Multi-agent --
|
|
140
|
+
|
|
141
|
+
def build_supervisor(
|
|
142
|
+
self,
|
|
143
|
+
supervisor_config: ModelConfig,
|
|
144
|
+
workers: dict[str, Any],
|
|
145
|
+
supervisor_prompt: str | None = None,
|
|
146
|
+
) -> Any:
|
|
147
|
+
"""Build a supervisor/worker multi-agent system.
|
|
148
|
+
|
|
149
|
+
Falls back to ``DirectSupervisorGraph`` by default.
|
|
150
|
+
Override in backend-specific subclasses for deeper integration.
|
|
151
|
+
"""
|
|
152
|
+
from rapidagent.backends.direct import DirectSupervisorGraph
|
|
153
|
+
|
|
154
|
+
return DirectSupervisorGraph(
|
|
155
|
+
supervisor_config=supervisor_config,
|
|
156
|
+
workers=workers,
|
|
157
|
+
supervisor_prompt=supervisor_prompt,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ---------------------------------------------------------------------------
|
|
162
|
+
# Helpers
|
|
163
|
+
# ---------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
def get_default_backend() -> str:
|
|
166
|
+
if sys.version_info >= (3, 14):
|
|
167
|
+
return "direct"
|
|
168
|
+
return "langgraph"
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def create_backend(name: str | None = None, checkpoint_dir: str | None = None) -> Backend:
|
|
172
|
+
import warnings
|
|
173
|
+
|
|
174
|
+
name = name or get_default_backend()
|
|
175
|
+
|
|
176
|
+
if name == "langgraph":
|
|
177
|
+
try:
|
|
178
|
+
from rapidagent.backends.langgraph import LangGraphBackend
|
|
179
|
+
|
|
180
|
+
return LangGraphBackend(checkpoint_dir=checkpoint_dir)
|
|
181
|
+
except ImportError:
|
|
182
|
+
warnings.warn(
|
|
183
|
+
"LangGraph not installed. Falling back to 'direct'. "
|
|
184
|
+
"Install: pip install rapidagent[langgraph]",
|
|
185
|
+
stacklevel=2,
|
|
186
|
+
)
|
|
187
|
+
from rapidagent.backends.direct import DirectBackend
|
|
188
|
+
return DirectBackend(checkpoint_dir=checkpoint_dir)
|
|
189
|
+
elif name == "direct":
|
|
190
|
+
from rapidagent.backends.direct import DirectBackend
|
|
191
|
+
return DirectBackend(checkpoint_dir=checkpoint_dir)
|
|
192
|
+
else:
|
|
193
|
+
raise ValueError(f"Unknown backend: '{name}'. Supported: 'langgraph', 'direct'.")
|