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.

Files changed (40) hide show
  1. rem/agentic/agents/sse_simulator.py +2 -0
  2. rem/agentic/context.py +23 -3
  3. rem/agentic/mcp/tool_wrapper.py +126 -15
  4. rem/agentic/otel/setup.py +1 -0
  5. rem/agentic/providers/phoenix.py +371 -108
  6. rem/agentic/providers/pydantic_ai.py +122 -43
  7. rem/agentic/schema.py +4 -1
  8. rem/api/mcp_router/tools.py +13 -2
  9. rem/api/routers/chat/completions.py +250 -4
  10. rem/api/routers/chat/models.py +81 -7
  11. rem/api/routers/chat/otel_utils.py +33 -0
  12. rem/api/routers/chat/sse_events.py +17 -1
  13. rem/api/routers/chat/streaming.py +35 -1
  14. rem/api/routers/feedback.py +134 -14
  15. rem/cli/commands/cluster.py +590 -82
  16. rem/cli/commands/configure.py +3 -4
  17. rem/cli/commands/experiments.py +436 -30
  18. rem/cli/commands/session.py +336 -0
  19. rem/cli/dreaming.py +2 -2
  20. rem/cli/main.py +2 -0
  21. rem/config.py +8 -1
  22. rem/models/core/experiment.py +54 -0
  23. rem/models/entities/ontology.py +1 -1
  24. rem/models/entities/ontology_config.py +1 -1
  25. rem/schemas/agents/examples/contract-analyzer.yaml +1 -1
  26. rem/schemas/agents/examples/contract-extractor.yaml +1 -1
  27. rem/schemas/agents/examples/cv-parser.yaml +1 -1
  28. rem/services/phoenix/client.py +59 -18
  29. rem/services/session/compression.py +7 -0
  30. rem/settings.py +236 -13
  31. rem/sql/migrations/002_install_models.sql +91 -91
  32. rem/sql/migrations/004_cache_system.sql +1 -1
  33. rem/utils/schema_loader.py +94 -3
  34. rem/utils/vision.py +1 -1
  35. rem/workers/__init__.py +2 -1
  36. rem/workers/db_listener.py +579 -0
  37. {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/METADATA +156 -144
  38. {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/RECORD +40 -37
  39. {remdb-0.3.118.dist-info → remdb-0.3.141.dist-info}/WHEEL +0 -0
  40. {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
- Key Design Pattern
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
  )
@@ -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
- This is a placeholder for now. A real implementation would create a
115
- tool that reads the content of the resource URI.
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 (e.g., "rem://resources/some-id").
119
- usage: The description of how to use the tool.
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
- read_resource.__name__ = f"read_{uri.replace('://', '_').replace('/', '_')}"
130
- read_resource.__doc__ = usage
132
+ Example:
133
+ # Concrete URI -> no-param tool
134
+ tool = create_resource_tool("rem://schemas", "List all agent schemas")
131
135
 
132
- logger.info(f"Built resource tool: {read_resource.__name__} (uri: {uri})")
133
- return Tool(read_resource)
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
@@ -158,6 +158,7 @@ def setup_instrumentation() -> None:
158
158
  base_exporter = GRPCExporter(
159
159
  endpoint=settings.otel.collector_endpoint,
160
160
  timeout=settings.otel.export_timeout,
161
+ insecure=settings.otel.insecure,
161
162
  )
162
163
  else: # http
163
164
  base_exporter = HTTPExporter(