remdb 0.3.171__py3-none-any.whl → 0.3.230__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.
Files changed (59) hide show
  1. rem/agentic/README.md +36 -2
  2. rem/agentic/context.py +173 -0
  3. rem/agentic/context_builder.py +12 -2
  4. rem/agentic/mcp/tool_wrapper.py +39 -16
  5. rem/agentic/providers/pydantic_ai.py +78 -45
  6. rem/agentic/schema.py +6 -5
  7. rem/agentic/tools/rem_tools.py +11 -0
  8. rem/api/main.py +1 -1
  9. rem/api/mcp_router/resources.py +75 -14
  10. rem/api/mcp_router/server.py +31 -24
  11. rem/api/mcp_router/tools.py +621 -166
  12. rem/api/routers/admin.py +30 -4
  13. rem/api/routers/auth.py +114 -15
  14. rem/api/routers/chat/child_streaming.py +379 -0
  15. rem/api/routers/chat/completions.py +74 -37
  16. rem/api/routers/chat/sse_events.py +7 -3
  17. rem/api/routers/chat/streaming.py +352 -257
  18. rem/api/routers/chat/streaming_utils.py +327 -0
  19. rem/api/routers/common.py +18 -0
  20. rem/api/routers/dev.py +7 -1
  21. rem/api/routers/feedback.py +9 -1
  22. rem/api/routers/messages.py +176 -38
  23. rem/api/routers/models.py +9 -1
  24. rem/api/routers/query.py +12 -1
  25. rem/api/routers/shared_sessions.py +16 -0
  26. rem/auth/jwt.py +19 -4
  27. rem/auth/middleware.py +42 -28
  28. rem/cli/README.md +62 -0
  29. rem/cli/commands/ask.py +61 -81
  30. rem/cli/commands/db.py +148 -70
  31. rem/cli/commands/process.py +171 -43
  32. rem/models/entities/ontology.py +91 -101
  33. rem/schemas/agents/rem.yaml +1 -1
  34. rem/services/content/service.py +18 -5
  35. rem/services/email/service.py +11 -2
  36. rem/services/embeddings/worker.py +26 -12
  37. rem/services/postgres/__init__.py +28 -3
  38. rem/services/postgres/diff_service.py +57 -5
  39. rem/services/postgres/programmable_diff_service.py +635 -0
  40. rem/services/postgres/pydantic_to_sqlalchemy.py +2 -2
  41. rem/services/postgres/register_type.py +12 -11
  42. rem/services/postgres/repository.py +39 -29
  43. rem/services/postgres/schema_generator.py +5 -5
  44. rem/services/postgres/sql_builder.py +6 -5
  45. rem/services/session/__init__.py +8 -1
  46. rem/services/session/compression.py +40 -2
  47. rem/services/session/pydantic_messages.py +292 -0
  48. rem/settings.py +34 -0
  49. rem/sql/background_indexes.sql +5 -0
  50. rem/sql/migrations/001_install.sql +157 -10
  51. rem/sql/migrations/002_install_models.sql +160 -132
  52. rem/sql/migrations/004_cache_system.sql +7 -275
  53. rem/sql/migrations/migrate_session_id_to_uuid.sql +45 -0
  54. rem/utils/model_helpers.py +101 -0
  55. rem/utils/schema_loader.py +79 -51
  56. {remdb-0.3.171.dist-info → remdb-0.3.230.dist-info}/METADATA +2 -2
  57. {remdb-0.3.171.dist-info → remdb-0.3.230.dist-info}/RECORD +59 -53
  58. {remdb-0.3.171.dist-info → remdb-0.3.230.dist-info}/WHEEL +0 -0
  59. {remdb-0.3.171.dist-info → remdb-0.3.230.dist-info}/entry_points.txt +0 -0
@@ -349,6 +349,53 @@ def register_agent_resources(mcp: FastMCP):
349
349
  except Exception as e:
350
350
  return f"# Available Agents\n\nError listing agents: {e}"
351
351
 
352
+ @mcp.resource("rem://agents/{agent_name}")
353
+ def get_agent_schema(agent_name: str) -> str:
354
+ """
355
+ Get a specific agent schema by name.
356
+
357
+ Args:
358
+ agent_name: Name of the agent (e.g., "ask_rem", "agent-builder")
359
+
360
+ Returns:
361
+ Full agent schema as YAML string, or error message if not found.
362
+ """
363
+ import importlib.resources
364
+ import yaml
365
+ from pathlib import Path
366
+
367
+ try:
368
+ # Find packaged agent schemas
369
+ agents_ref = importlib.resources.files("rem") / "schemas" / "agents"
370
+ agents_dir = Path(str(agents_ref))
371
+
372
+ if not agents_dir.exists():
373
+ return f"# Agent Not Found\n\nNo agent schemas directory found."
374
+
375
+ # Search for agent file (try multiple extensions)
376
+ for ext in [".yaml", ".yml", ".json"]:
377
+ # Try exact match first
378
+ agent_file = agents_dir / f"{agent_name}{ext}"
379
+ if agent_file.exists():
380
+ with open(agent_file, "r") as f:
381
+ content = f.read()
382
+ return f"# Agent Schema: {agent_name}\n\n```yaml\n{content}\n```"
383
+
384
+ # Try recursive search
385
+ matches = list(agents_dir.rglob(f"{agent_name}{ext}"))
386
+ if matches:
387
+ with open(matches[0], "r") as f:
388
+ content = f.read()
389
+ return f"# Agent Schema: {agent_name}\n\n```yaml\n{content}\n```"
390
+
391
+ # Not found - list available agents
392
+ available = [f.stem for f in agents_dir.rglob("*.yaml")] + \
393
+ [f.stem for f in agents_dir.rglob("*.yml")]
394
+ return f"# Agent Not Found\n\nAgent '{agent_name}' not found.\n\nAvailable agents: {', '.join(sorted(set(available)))}"
395
+
396
+ except Exception as e:
397
+ return f"# Error\n\nError loading agent '{agent_name}': {e}"
398
+
352
399
 
353
400
  def register_file_resources(mcp: FastMCP):
354
401
  """
@@ -501,10 +548,11 @@ async def load_resource(uri: str) -> dict | str:
501
548
  Load an MCP resource by URI.
502
549
 
503
550
  This function is called by the read_resource tool to dispatch to
504
- registered resource handlers.
551
+ registered resource handlers. Supports both regular resources and
552
+ parameterized resource templates (e.g., rem://agents/{agent_name}).
505
553
 
506
554
  Args:
507
- uri: Resource URI (e.g., "rem://schemas", "rem://status")
555
+ uri: Resource URI (e.g., "rem://agents", "rem://agents/ask_rem", "rem://status")
508
556
 
509
557
  Returns:
510
558
  Resource data (dict or string)
@@ -512,9 +560,10 @@ async def load_resource(uri: str) -> dict | str:
512
560
  Raises:
513
561
  ValueError: If URI is invalid or resource not found
514
562
  """
515
- # Create temporary MCP instance with resources
563
+ import inspect
516
564
  from fastmcp import FastMCP
517
565
 
566
+ # Create temporary MCP instance with resources
518
567
  mcp = FastMCP(name="temp")
519
568
 
520
569
  # Register all resources
@@ -523,14 +572,26 @@ async def load_resource(uri: str) -> dict | str:
523
572
  register_file_resources(mcp)
524
573
  register_status_resources(mcp)
525
574
 
526
- # Get resource handlers from MCP internal registry
527
- # FastMCP stores resources in a dict by URI
528
- if hasattr(mcp, "_resources"):
529
- if uri in mcp._resources:
530
- handler = mcp._resources[uri]
531
- if callable(handler):
532
- result = handler()
533
- return result if result else {"error": "Resource returned None"}
534
-
535
- # If not found, raise error
536
- raise ValueError(f"Resource not found: {uri}. Available resources: {list(mcp._resources.keys()) if hasattr(mcp, '_resources') else 'unknown'}")
575
+ # 1. Try exact match in regular resources
576
+ resources = await mcp.get_resources()
577
+ if uri in resources:
578
+ resource = resources[uri]
579
+ result = resource.fn()
580
+ if inspect.iscoroutine(result):
581
+ result = await result
582
+ return result if result else {"error": "Resource returned None"}
583
+
584
+ # 2. Try matching against parameterized resource templates
585
+ templates = await mcp.get_resource_templates()
586
+ for template_uri, template in templates.items():
587
+ params = template.matches(uri)
588
+ if params is not None:
589
+ # Template matched - call function with extracted parameters
590
+ result = template.fn(**params)
591
+ if inspect.iscoroutine(result):
592
+ result = await result
593
+ return result if result else {"error": "Resource returned None"}
594
+
595
+ # 3. Not found - include both resources and templates in error
596
+ available = list(resources.keys()) + list(templates.keys())
597
+ raise ValueError(f"Resource not found: {uri}. Available resources: {available}")
@@ -1,7 +1,7 @@
1
1
  """
2
2
  MCP server creation and configuration for REM.
3
3
 
4
- Design Pattern
4
+ Design Pattern
5
5
  1. Create FastMCP server with tools and resources
6
6
  2. Register tools using @mcp.tool() decorator
7
7
  3. Register resources using resource registration functions
@@ -20,10 +20,31 @@ FastMCP Features:
20
20
  """
21
21
 
22
22
  import importlib.metadata
23
+ from functools import wraps
23
24
 
24
25
  from fastmcp import FastMCP
26
+ from loguru import logger
25
27
 
26
28
  from ...settings import settings
29
+ from .prompts import register_prompts
30
+ from .resources import (
31
+ register_agent_resources,
32
+ register_file_resources,
33
+ register_schema_resources,
34
+ register_status_resources,
35
+ )
36
+ from .tools import (
37
+ ask_agent,
38
+ ask_rem_agent,
39
+ get_schema,
40
+ ingest_into_rem,
41
+ list_schema,
42
+ read_resource,
43
+ register_metadata,
44
+ save_agent,
45
+ search_rem,
46
+ test_error_handling,
47
+ )
27
48
 
28
49
  # Get package version
29
50
  try:
@@ -174,18 +195,7 @@ def create_mcp_server(is_local: bool = False) -> FastMCP:
174
195
  ),
175
196
  )
176
197
 
177
- # Register REM tools
178
- from .tools import (
179
- ask_rem_agent,
180
- get_schema,
181
- ingest_into_rem,
182
- list_schema,
183
- read_resource,
184
- register_metadata,
185
- save_agent,
186
- search_rem,
187
- )
188
-
198
+ # Register core REM tools
189
199
  mcp.tool()(search_rem)
190
200
  mcp.tool()(ask_rem_agent)
191
201
  mcp.tool()(read_resource)
@@ -194,10 +204,16 @@ def create_mcp_server(is_local: bool = False) -> FastMCP:
194
204
  mcp.tool()(get_schema)
195
205
  mcp.tool()(save_agent)
196
206
 
207
+ # Register multi-agent tools
208
+ mcp.tool()(ask_agent)
209
+
210
+ # Register test tool only in development environment (not staging/production)
211
+ if settings.environment not in ("staging", "production"):
212
+ mcp.tool()(test_error_handling)
213
+ logger.debug("Registered test_error_handling tool (dev environment only)")
214
+
197
215
  # File ingestion tool (with local path support for local servers)
198
216
  # Wrap to inject is_local parameter
199
- from functools import wraps
200
-
201
217
  @wraps(ingest_into_rem)
202
218
  async def ingest_into_rem_wrapper(
203
219
  file_uri: str,
@@ -216,18 +232,9 @@ def create_mcp_server(is_local: bool = False) -> FastMCP:
216
232
  mcp.tool()(ingest_into_rem_wrapper)
217
233
 
218
234
  # Register prompts
219
- from .prompts import register_prompts
220
-
221
235
  register_prompts(mcp)
222
236
 
223
237
  # Register schema resources
224
- from .resources import (
225
- register_agent_resources,
226
- register_file_resources,
227
- register_schema_resources,
228
- register_status_resources,
229
- )
230
-
231
238
  register_schema_resources(mcp)
232
239
  register_agent_resources(mcp)
233
240
  register_file_resources(mcp)