remdb 0.3.118__py3-none-any.whl → 0.3.141__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.
Potentially problematic release.
This version of remdb might be problematic. Click here for more details.
- rem/agentic/agents/sse_simulator.py +2 -0
- rem/agentic/context.py +23 -3
- rem/agentic/mcp/tool_wrapper.py +126 -15
- rem/agentic/otel/setup.py +1 -0
- rem/agentic/providers/phoenix.py +371 -108
- rem/agentic/providers/pydantic_ai.py +122 -43
- rem/agentic/schema.py +4 -1
- rem/api/mcp_router/tools.py +13 -2
- rem/api/routers/chat/completions.py +250 -4
- rem/api/routers/chat/models.py +81 -7
- rem/api/routers/chat/otel_utils.py +33 -0
- rem/api/routers/chat/sse_events.py +17 -1
- rem/api/routers/chat/streaming.py +35 -1
- rem/api/routers/feedback.py +134 -14
- rem/cli/commands/cluster.py +590 -82
- rem/cli/commands/configure.py +3 -4
- rem/cli/commands/experiments.py +436 -30
- rem/cli/commands/session.py +336 -0
- rem/cli/dreaming.py +2 -2
- rem/cli/main.py +2 -0
- rem/config.py +8 -1
- rem/models/core/experiment.py +54 -0
- rem/models/entities/ontology.py +1 -1
- rem/models/entities/ontology_config.py +1 -1
- rem/schemas/agents/examples/contract-analyzer.yaml +1 -1
- rem/schemas/agents/examples/contract-extractor.yaml +1 -1
- rem/schemas/agents/examples/cv-parser.yaml +1 -1
- rem/services/phoenix/client.py +59 -18
- rem/services/session/compression.py +7 -0
- rem/settings.py +236 -13
- rem/sql/migrations/002_install_models.sql +91 -91
- rem/sql/migrations/004_cache_system.sql +1 -1
- rem/utils/schema_loader.py +94 -3
- rem/utils/vision.py +1 -1
- rem/workers/__init__.py +2 -1
- rem/workers/db_listener.py +579 -0
- {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/METADATA +156 -144
- {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/RECORD +40 -37
- {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/WHEEL +0 -0
- {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/entry_points.txt +0 -0
|
@@ -265,6 +265,8 @@ async def stream_simulator_events(
|
|
|
265
265
|
message_id=message_id,
|
|
266
266
|
in_reply_to=in_reply_to,
|
|
267
267
|
session_id=session_id,
|
|
268
|
+
# Session info
|
|
269
|
+
session_name="SSE Demo Session",
|
|
268
270
|
# Quality indicators
|
|
269
271
|
confidence=0.95,
|
|
270
272
|
sources=["rem/api/routers/chat/sse_events.py", "rem/agentic/agents/sse_simulator.py"],
|
rem/agentic/context.py
CHANGED
|
@@ -2,10 +2,18 @@
|
|
|
2
2
|
Agent execution context and configuration.
|
|
3
3
|
|
|
4
4
|
Design pattern for session context that can be constructed from:
|
|
5
|
-
- HTTP headers (X-User-Id, X-Session-Id, X-Model-Name)
|
|
5
|
+
- HTTP headers (X-User-Id, X-Session-Id, X-Model-Name, X-Is-Eval, etc.)
|
|
6
6
|
- Direct instantiation for testing/CLI
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Headers Mapping:
|
|
9
|
+
X-User-Id → context.user_id
|
|
10
|
+
X-Tenant-Id → context.tenant_id (default: "default")
|
|
11
|
+
X-Session-Id → context.session_id
|
|
12
|
+
X-Agent-Schema → context.agent_schema_uri (default: "rem")
|
|
13
|
+
X-Model-Name → context.default_model
|
|
14
|
+
X-Is-Eval → context.is_eval (marks session as evaluation)
|
|
15
|
+
|
|
16
|
+
Key Design Pattern:
|
|
9
17
|
- AgentContext is passed to agent factory, not stored in agents
|
|
10
18
|
- Enables session tracking across API, CLI, and test execution
|
|
11
19
|
- Supports header-based configuration override (model, schema URI)
|
|
@@ -66,6 +74,11 @@ class AgentContext(BaseModel):
|
|
|
66
74
|
description="Agent schema URI (e.g., 'rem-agents-query-agent')",
|
|
67
75
|
)
|
|
68
76
|
|
|
77
|
+
is_eval: bool = Field(
|
|
78
|
+
default=False,
|
|
79
|
+
description="Whether this is an evaluation session (set via X-Is-Eval header)",
|
|
80
|
+
)
|
|
81
|
+
|
|
69
82
|
model_config = {"populate_by_name": True}
|
|
70
83
|
|
|
71
84
|
@staticmethod
|
|
@@ -126,6 +139,7 @@ class AgentContext(BaseModel):
|
|
|
126
139
|
- X-Session-Id: Session identifier
|
|
127
140
|
- X-Model-Name: Model override
|
|
128
141
|
- X-Agent-Schema: Agent schema URI
|
|
142
|
+
- X-Is-Eval: Whether this is an evaluation session (true/false)
|
|
129
143
|
|
|
130
144
|
Args:
|
|
131
145
|
headers: Dictionary of HTTP headers (case-insensitive)
|
|
@@ -138,17 +152,23 @@ class AgentContext(BaseModel):
|
|
|
138
152
|
"X-User-Id": "user123",
|
|
139
153
|
"X-Tenant-Id": "acme-corp",
|
|
140
154
|
"X-Session-Id": "sess-456",
|
|
141
|
-
"X-Model-Name": "anthropic:claude-opus-4-20250514"
|
|
155
|
+
"X-Model-Name": "anthropic:claude-opus-4-20250514",
|
|
156
|
+
"X-Is-Eval": "true"
|
|
142
157
|
}
|
|
143
158
|
context = AgentContext.from_headers(headers)
|
|
144
159
|
"""
|
|
145
160
|
# Normalize header keys to lowercase for case-insensitive lookup
|
|
146
161
|
normalized = {k.lower(): v for k, v in headers.items()}
|
|
147
162
|
|
|
163
|
+
# Parse X-Is-Eval header (accepts "true", "1", "yes" as truthy)
|
|
164
|
+
is_eval_str = normalized.get("x-is-eval", "").lower()
|
|
165
|
+
is_eval = is_eval_str in ("true", "1", "yes")
|
|
166
|
+
|
|
148
167
|
return cls(
|
|
149
168
|
user_id=normalized.get("x-user-id"),
|
|
150
169
|
tenant_id=normalized.get("x-tenant-id", "default"),
|
|
151
170
|
session_id=normalized.get("x-session-id"),
|
|
152
171
|
default_model=normalized.get("x-model-name") or settings.llm.default_model,
|
|
153
172
|
agent_schema_uri=normalized.get("x-agent-schema"),
|
|
173
|
+
is_eval=is_eval,
|
|
154
174
|
)
|
rem/agentic/mcp/tool_wrapper.py
CHANGED
|
@@ -107,27 +107,138 @@ def create_mcp_tool_wrapper(
|
|
|
107
107
|
return Tool(tool_func)
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
def create_resource_tool(uri: str, usage: str) -> Tool:
|
|
110
|
+
def create_resource_tool(uri: str, usage: str = "", mcp_server: Any = None) -> Tool:
|
|
111
111
|
"""
|
|
112
112
|
Build a Tool instance from an MCP resource URI.
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
Creates a tool that fetches the resource content when called.
|
|
115
|
+
Resources declared in agent YAML become callable tools - this eliminates
|
|
116
|
+
the artificial MCP distinction between tools and resources.
|
|
117
|
+
|
|
118
|
+
Supports both:
|
|
119
|
+
- Concrete URIs: "rem://schemas" -> tool with no parameters
|
|
120
|
+
- Template URIs: "patient-profile://field/{field_key}" -> tool with field_key parameter
|
|
116
121
|
|
|
117
122
|
Args:
|
|
118
|
-
uri: The resource URI (
|
|
119
|
-
usage: The description of
|
|
123
|
+
uri: The resource URI (concrete or template with {variable} placeholders).
|
|
124
|
+
usage: The description of what this resource provides.
|
|
125
|
+
mcp_server: Optional FastMCP server instance to resolve resources from.
|
|
126
|
+
If provided, resources are resolved from this server's registry.
|
|
127
|
+
If not provided, falls back to REM's built-in load_resource().
|
|
120
128
|
|
|
121
129
|
Returns:
|
|
122
|
-
A Pydantic AI Tool instance.
|
|
123
|
-
"""
|
|
124
|
-
# Placeholder function that would read the resource
|
|
125
|
-
def read_resource():
|
|
126
|
-
"""Reads content from a resource URI."""
|
|
127
|
-
return f"Content of {uri}"
|
|
130
|
+
A Pydantic AI Tool instance that fetches the resource.
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
Example:
|
|
133
|
+
# Concrete URI -> no-param tool
|
|
134
|
+
tool = create_resource_tool("rem://schemas", "List all agent schemas")
|
|
131
135
|
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
# Template URI -> parameterized tool
|
|
137
|
+
tool = create_resource_tool("patient-profile://field/{field_key}", "Get field definition", mcp_server=mcp)
|
|
138
|
+
# Agent calls: get_patient_profile_field(field_key="safety.suicidality")
|
|
139
|
+
"""
|
|
140
|
+
import json
|
|
141
|
+
import re
|
|
142
|
+
|
|
143
|
+
# Extract template variables from URI (e.g., {field_key}, {domain_name})
|
|
144
|
+
template_vars = re.findall(r'\{([^}]+)\}', uri)
|
|
145
|
+
|
|
146
|
+
# Parse URI to create function name (strip template vars for cleaner name)
|
|
147
|
+
clean_uri = re.sub(r'\{[^}]+\}', '', uri)
|
|
148
|
+
parts = clean_uri.replace("://", "_").replace("-", "_").replace("/", "_").replace(".", "_")
|
|
149
|
+
parts = re.sub(r'_+', '_', parts).strip('_') # Clean up multiple underscores
|
|
150
|
+
func_name = f"get_{parts}"
|
|
151
|
+
|
|
152
|
+
# Build description including parameter info
|
|
153
|
+
description = usage or f"Fetch {uri} resource"
|
|
154
|
+
if template_vars:
|
|
155
|
+
param_desc = ", ".join(template_vars)
|
|
156
|
+
description = f"{description}\n\nParameters: {param_desc}"
|
|
157
|
+
|
|
158
|
+
if template_vars:
|
|
159
|
+
# Template URI -> create parameterized tool
|
|
160
|
+
async def wrapper(**kwargs: Any) -> str:
|
|
161
|
+
"""Fetch MCP resource with substituted parameters."""
|
|
162
|
+
import asyncio
|
|
163
|
+
import inspect
|
|
164
|
+
|
|
165
|
+
# Try to resolve from MCP server's resource templates first
|
|
166
|
+
if mcp_server is not None:
|
|
167
|
+
try:
|
|
168
|
+
# Get resource templates from MCP server
|
|
169
|
+
templates = await mcp_server.get_resource_templates()
|
|
170
|
+
if uri in templates:
|
|
171
|
+
template = templates[uri]
|
|
172
|
+
# Call the template's underlying function directly
|
|
173
|
+
# The fn expects the template variables as kwargs
|
|
174
|
+
fn_result = template.fn(**kwargs)
|
|
175
|
+
# Handle both sync and async functions
|
|
176
|
+
if inspect.iscoroutine(fn_result):
|
|
177
|
+
fn_result = await fn_result
|
|
178
|
+
if isinstance(fn_result, str):
|
|
179
|
+
return fn_result
|
|
180
|
+
return json.dumps(fn_result, indent=2)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.warning(f"Failed to resolve resource {uri} from MCP server: {e}")
|
|
183
|
+
|
|
184
|
+
# Fallback: substitute template variables and use load_resource
|
|
185
|
+
resolved_uri = uri
|
|
186
|
+
for var in template_vars:
|
|
187
|
+
if var in kwargs:
|
|
188
|
+
resolved_uri = resolved_uri.replace(f"{{{var}}}", str(kwargs[var]))
|
|
189
|
+
else:
|
|
190
|
+
return json.dumps({"error": f"Missing required parameter: {var}"})
|
|
191
|
+
|
|
192
|
+
from rem.api.mcp_router.resources import load_resource
|
|
193
|
+
result = await load_resource(resolved_uri)
|
|
194
|
+
if isinstance(result, str):
|
|
195
|
+
return result
|
|
196
|
+
return json.dumps(result, indent=2)
|
|
197
|
+
|
|
198
|
+
# Build parameter annotations for Pydantic AI
|
|
199
|
+
wrapper.__name__ = func_name
|
|
200
|
+
wrapper.__doc__ = description
|
|
201
|
+
# Add type hints for parameters
|
|
202
|
+
wrapper.__annotations__ = {var: str for var in template_vars}
|
|
203
|
+
wrapper.__annotations__['return'] = str
|
|
204
|
+
|
|
205
|
+
logger.info(f"Built parameterized resource tool: {func_name} (uri: {uri}, params: {template_vars})")
|
|
206
|
+
else:
|
|
207
|
+
# Concrete URI -> no-param tool
|
|
208
|
+
async def wrapper(**kwargs: Any) -> str:
|
|
209
|
+
"""Fetch MCP resource and return contents."""
|
|
210
|
+
import asyncio
|
|
211
|
+
import inspect
|
|
212
|
+
|
|
213
|
+
if kwargs:
|
|
214
|
+
logger.warning(f"Resource tool {func_name} called with unexpected kwargs: {list(kwargs.keys())}")
|
|
215
|
+
|
|
216
|
+
# Try to resolve from MCP server's resources first
|
|
217
|
+
if mcp_server is not None:
|
|
218
|
+
try:
|
|
219
|
+
resources = await mcp_server.get_resources()
|
|
220
|
+
if uri in resources:
|
|
221
|
+
resource = resources[uri]
|
|
222
|
+
# Call the resource's underlying function
|
|
223
|
+
fn_result = resource.fn()
|
|
224
|
+
if inspect.iscoroutine(fn_result):
|
|
225
|
+
fn_result = await fn_result
|
|
226
|
+
if isinstance(fn_result, str):
|
|
227
|
+
return fn_result
|
|
228
|
+
return json.dumps(fn_result, indent=2)
|
|
229
|
+
except Exception as e:
|
|
230
|
+
logger.warning(f"Failed to resolve resource {uri} from MCP server: {e}")
|
|
231
|
+
|
|
232
|
+
# Fallback to load_resource
|
|
233
|
+
from rem.api.mcp_router.resources import load_resource
|
|
234
|
+
result = await load_resource(uri)
|
|
235
|
+
if isinstance(result, str):
|
|
236
|
+
return result
|
|
237
|
+
return json.dumps(result, indent=2)
|
|
238
|
+
|
|
239
|
+
wrapper.__name__ = func_name
|
|
240
|
+
wrapper.__doc__ = description
|
|
241
|
+
|
|
242
|
+
logger.info(f"Built resource tool: {func_name} (uri: {uri})")
|
|
243
|
+
|
|
244
|
+
return Tool(wrapper)
|
rem/agentic/otel/setup.py
CHANGED