remdb 0.3.103__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 +51 -27
- rem/agentic/mcp/tool_wrapper.py +155 -18
- rem/agentic/otel/setup.py +93 -4
- rem/agentic/providers/phoenix.py +371 -108
- rem/agentic/providers/pydantic_ai.py +195 -46
- rem/agentic/schema.py +361 -21
- rem/agentic/tools/rem_tools.py +3 -3
- rem/api/main.py +85 -16
- rem/api/mcp_router/resources.py +1 -1
- rem/api/mcp_router/server.py +18 -4
- rem/api/mcp_router/tools.py +394 -16
- rem/api/routers/admin.py +218 -1
- rem/api/routers/chat/completions.py +280 -7
- 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 +177 -3
- rem/api/routers/feedback.py +142 -329
- rem/api/routers/query.py +360 -0
- rem/api/routers/shared_sessions.py +13 -13
- rem/cli/commands/README.md +237 -64
- rem/cli/commands/cluster.py +1808 -0
- rem/cli/commands/configure.py +4 -7
- rem/cli/commands/db.py +354 -143
- rem/cli/commands/experiments.py +436 -30
- rem/cli/commands/process.py +14 -8
- rem/cli/commands/schema.py +92 -45
- rem/cli/commands/session.py +336 -0
- rem/cli/dreaming.py +2 -2
- rem/cli/main.py +29 -6
- rem/config.py +8 -1
- rem/models/core/experiment.py +54 -0
- rem/models/core/rem_query.py +5 -2
- rem/models/entities/ontology.py +1 -1
- rem/models/entities/ontology_config.py +1 -1
- rem/models/entities/shared_session.py +2 -28
- rem/registry.py +10 -4
- 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/content/service.py +30 -8
- rem/services/embeddings/api.py +4 -4
- rem/services/embeddings/worker.py +16 -16
- rem/services/phoenix/client.py +59 -18
- rem/services/postgres/README.md +151 -26
- rem/services/postgres/__init__.py +2 -1
- rem/services/postgres/diff_service.py +531 -0
- rem/services/postgres/pydantic_to_sqlalchemy.py +427 -129
- rem/services/postgres/schema_generator.py +205 -4
- rem/services/postgres/service.py +6 -6
- rem/services/rem/parser.py +44 -9
- rem/services/rem/service.py +36 -2
- rem/services/session/compression.py +7 -0
- rem/services/session/reload.py +1 -1
- rem/settings.py +288 -16
- rem/sql/background_indexes.sql +19 -24
- rem/sql/migrations/001_install.sql +252 -69
- rem/sql/migrations/002_install_models.sql +2197 -619
- rem/sql/migrations/003_optional_extensions.sql +326 -0
- rem/sql/migrations/004_cache_system.sql +548 -0
- rem/utils/__init__.py +18 -0
- rem/utils/date_utils.py +2 -2
- rem/utils/schema_loader.py +110 -15
- rem/utils/sql_paths.py +146 -0
- rem/utils/vision.py +1 -1
- rem/workers/__init__.py +3 -1
- rem/workers/db_listener.py +579 -0
- rem/workers/unlogged_maintainer.py +463 -0
- {remdb-0.3.103.dist-info → remdb-0.3.141.dist-info}/METADATA +300 -215
- {remdb-0.3.103.dist-info → remdb-0.3.141.dist-info}/RECORD +73 -64
- rem/sql/migrations/003_seed_default_user.sql +0 -48
- {remdb-0.3.103.dist-info → remdb-0.3.141.dist-info}/WHEEL +0 -0
- {remdb-0.3.103.dist-info → remdb-0.3.141.dist-info}/entry_points.txt +0 -0
|
@@ -175,6 +175,23 @@ class AgentRuntime:
|
|
|
175
175
|
return self.agent.iter(*args, **kwargs)
|
|
176
176
|
|
|
177
177
|
|
|
178
|
+
def _get_builtin_tools() -> list:
|
|
179
|
+
"""
|
|
180
|
+
Get built-in tools that are always available to agents.
|
|
181
|
+
|
|
182
|
+
Currently returns empty list - all tools come from MCP servers.
|
|
183
|
+
The register_metadata tool is available via the REM MCP server and
|
|
184
|
+
agents can opt-in by configuring mcp_servers in their schema.
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
List of Pydantic AI tool functions (currently empty)
|
|
188
|
+
"""
|
|
189
|
+
# NOTE: register_metadata is now an MCP tool, not a built-in.
|
|
190
|
+
# Agents that want it should configure mcp_servers to load from rem.mcp_server.
|
|
191
|
+
# This allows agents to choose which tools they need.
|
|
192
|
+
return []
|
|
193
|
+
|
|
194
|
+
|
|
178
195
|
def _create_model_from_schema(agent_schema: dict[str, Any]) -> type[BaseModel]:
|
|
179
196
|
"""
|
|
180
197
|
Create Pydantic model dynamically from JSON Schema.
|
|
@@ -530,18 +547,74 @@ async def create_agent(
|
|
|
530
547
|
default_model = context.default_model if context else settings.llm.default_model
|
|
531
548
|
model = get_valid_model_or_default(model_override, default_model)
|
|
532
549
|
|
|
533
|
-
# Extract schema fields
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
550
|
+
# Extract schema fields using typed helpers
|
|
551
|
+
from ..schema import get_system_prompt, get_metadata
|
|
552
|
+
|
|
553
|
+
if agent_schema:
|
|
554
|
+
system_prompt = get_system_prompt(agent_schema)
|
|
555
|
+
metadata = get_metadata(agent_schema)
|
|
556
|
+
mcp_server_configs = [s.model_dump() for s in metadata.mcp_servers] if hasattr(metadata, 'mcp_servers') and metadata.mcp_servers else []
|
|
557
|
+
resource_configs = metadata.resources if hasattr(metadata, 'resources') else []
|
|
558
|
+
|
|
559
|
+
if metadata.system_prompt:
|
|
560
|
+
logger.debug("Using custom system_prompt from json_schema_extra")
|
|
561
|
+
else:
|
|
562
|
+
system_prompt = ""
|
|
563
|
+
metadata = None
|
|
564
|
+
mcp_server_configs = []
|
|
565
|
+
resource_configs = []
|
|
566
|
+
|
|
567
|
+
# Auto-detect local MCP server if not explicitly configured
|
|
568
|
+
# This makes mcp_servers config optional - agents get tools automatically
|
|
569
|
+
if not mcp_server_configs:
|
|
570
|
+
import importlib
|
|
571
|
+
import os
|
|
572
|
+
import sys
|
|
573
|
+
|
|
574
|
+
# Ensure current working directory is in sys.path for local imports
|
|
575
|
+
cwd = os.getcwd()
|
|
576
|
+
if cwd not in sys.path:
|
|
577
|
+
sys.path.insert(0, cwd)
|
|
578
|
+
|
|
579
|
+
# Try common local MCP server module paths first
|
|
580
|
+
auto_detect_modules = [
|
|
581
|
+
"tools.mcp_server", # Convention: tools/mcp_server.py
|
|
582
|
+
"mcp_server", # Alternative: mcp_server.py in root
|
|
583
|
+
]
|
|
584
|
+
for module_path in auto_detect_modules:
|
|
585
|
+
try:
|
|
586
|
+
mcp_module = importlib.import_module(module_path)
|
|
587
|
+
if hasattr(mcp_module, "mcp"):
|
|
588
|
+
logger.info(f"Auto-detected local MCP server: {module_path}")
|
|
589
|
+
mcp_server_configs = [{"type": "local", "module": module_path, "id": "auto-detected"}]
|
|
590
|
+
break
|
|
591
|
+
except ImportError:
|
|
592
|
+
continue
|
|
593
|
+
|
|
594
|
+
# Fall back to REM's default MCP server if no local server found
|
|
595
|
+
if not mcp_server_configs:
|
|
596
|
+
logger.debug("No local MCP server found, using REM default")
|
|
597
|
+
mcp_server_configs = [{"type": "local", "module": "rem.mcp_server", "id": "rem"}]
|
|
538
598
|
|
|
539
599
|
# Extract temperature and max_iterations from schema metadata (with fallback to settings defaults)
|
|
540
|
-
|
|
541
|
-
|
|
600
|
+
if metadata:
|
|
601
|
+
temperature = metadata.override_temperature if metadata.override_temperature is not None else settings.llm.default_temperature
|
|
602
|
+
max_iterations = metadata.override_max_iterations if metadata.override_max_iterations is not None else settings.llm.default_max_iterations
|
|
603
|
+
use_structured_output = metadata.structured_output
|
|
604
|
+
else:
|
|
605
|
+
temperature = settings.llm.default_temperature
|
|
606
|
+
max_iterations = settings.llm.default_max_iterations
|
|
607
|
+
use_structured_output = True
|
|
608
|
+
|
|
609
|
+
# Build list of tools - start with built-in tools
|
|
610
|
+
tools = _get_builtin_tools()
|
|
611
|
+
|
|
612
|
+
# Get agent name from metadata for logging
|
|
613
|
+
agent_name = metadata.name if metadata and hasattr(metadata, 'name') else "unknown"
|
|
542
614
|
|
|
543
615
|
logger.info(
|
|
544
|
-
f"Creating agent: model={model}, mcp_servers={len(mcp_server_configs)},
|
|
616
|
+
f"Creating agent '{agent_name}': model={model}, mcp_servers={len(mcp_server_configs)}, "
|
|
617
|
+
f"resources={len(resource_configs)}, builtin_tools={len(tools)}"
|
|
545
618
|
)
|
|
546
619
|
|
|
547
620
|
# Set agent resource attributes for OTEL (before creating agent)
|
|
@@ -550,50 +623,117 @@ async def create_agent(
|
|
|
550
623
|
|
|
551
624
|
set_agent_resource_attributes(agent_schema=agent_schema)
|
|
552
625
|
|
|
553
|
-
#
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
626
|
+
# Extract schema metadata for search_rem tool description suffix
|
|
627
|
+
# This allows entity schemas to add context-specific notes to the search_rem tool
|
|
628
|
+
search_rem_suffix = None
|
|
629
|
+
if metadata:
|
|
630
|
+
# Check for default_search_table in metadata (set by entity schemas)
|
|
631
|
+
extra = agent_schema.get("json_schema_extra", {}) if agent_schema else {}
|
|
632
|
+
default_table = extra.get("default_search_table")
|
|
633
|
+
has_embeddings = extra.get("has_embeddings", False)
|
|
634
|
+
|
|
635
|
+
if default_table:
|
|
636
|
+
# Build description suffix for search_rem
|
|
637
|
+
search_rem_suffix = f"\n\nFor this schema, use `search_rem` to query `{default_table}`. "
|
|
638
|
+
if has_embeddings:
|
|
639
|
+
search_rem_suffix += f"SEARCH works well on {default_table} (has embeddings). "
|
|
640
|
+
search_rem_suffix += f"Example: `SEARCH \"your query\" FROM {default_table} LIMIT 10`"
|
|
641
|
+
|
|
642
|
+
# Add tools from MCP server (in-process, no subprocess)
|
|
643
|
+
# Track loaded MCP servers for resource resolution
|
|
644
|
+
loaded_mcp_server = None
|
|
645
|
+
|
|
646
|
+
for server_config in mcp_server_configs:
|
|
647
|
+
server_type = server_config.get("type")
|
|
648
|
+
server_id = server_config.get("id", "mcp-server")
|
|
649
|
+
|
|
650
|
+
if server_type == "local":
|
|
651
|
+
# Import MCP server directly (in-process)
|
|
652
|
+
module_path = server_config.get("module", "rem.mcp_server")
|
|
653
|
+
|
|
654
|
+
try:
|
|
655
|
+
# Dynamic import of MCP server module
|
|
656
|
+
import importlib
|
|
657
|
+
mcp_module = importlib.import_module(module_path)
|
|
658
|
+
mcp_server = mcp_module.mcp
|
|
659
|
+
|
|
660
|
+
# Store the loaded server for resource resolution
|
|
661
|
+
loaded_mcp_server = mcp_server
|
|
662
|
+
|
|
663
|
+
# Extract tools from MCP server (get_tools is async)
|
|
664
|
+
from ..mcp.tool_wrapper import create_mcp_tool_wrapper
|
|
665
|
+
|
|
666
|
+
# Await async get_tools() call
|
|
667
|
+
mcp_tools_dict = await mcp_server.get_tools()
|
|
668
|
+
|
|
669
|
+
for tool_name, tool_func in mcp_tools_dict.items():
|
|
670
|
+
# Add description suffix to search_rem tool if schema specifies a default table
|
|
671
|
+
tool_suffix = search_rem_suffix if tool_name == "search_rem" else None
|
|
672
|
+
|
|
673
|
+
wrapped_tool = create_mcp_tool_wrapper(
|
|
674
|
+
tool_name,
|
|
675
|
+
tool_func,
|
|
676
|
+
user_id=context.user_id if context else None,
|
|
677
|
+
description_suffix=tool_suffix,
|
|
678
|
+
)
|
|
679
|
+
tools.append(wrapped_tool)
|
|
680
|
+
logger.debug(f"Loaded MCP tool: {tool_name}" + (" (with schema suffix)" if tool_suffix else ""))
|
|
681
|
+
|
|
682
|
+
logger.info(f"Loaded {len(mcp_tools_dict)} tools from MCP server: {server_id} (in-process)")
|
|
683
|
+
|
|
684
|
+
except Exception as e:
|
|
685
|
+
logger.error(f"Failed to load MCP server {server_id}: {e}", exc_info=True)
|
|
686
|
+
else:
|
|
687
|
+
logger.warning(f"Unsupported MCP server type: {server_type}")
|
|
575
688
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
689
|
+
# Convert resources to tools (MCP convenience syntax)
|
|
690
|
+
# Resources declared in agent YAML become callable tools - eliminates
|
|
691
|
+
# the artificial MCP distinction between tools and resources
|
|
692
|
+
#
|
|
693
|
+
# Supports both concrete and template URIs:
|
|
694
|
+
# - Concrete: "rem://schemas" -> no-param tool
|
|
695
|
+
# - Template: "patient-profile://field/{field_key}" -> tool with field_key param
|
|
696
|
+
from ..mcp.tool_wrapper import create_resource_tool
|
|
580
697
|
|
|
581
|
-
|
|
698
|
+
# Collect all resource URIs from both resources section AND tools section
|
|
699
|
+
resource_uris = []
|
|
582
700
|
|
|
583
|
-
|
|
584
|
-
|
|
701
|
+
# From resources section (legacy format)
|
|
702
|
+
if resource_configs:
|
|
703
|
+
for resource_config in resource_configs:
|
|
704
|
+
if hasattr(resource_config, 'uri'):
|
|
705
|
+
uri = resource_config.uri
|
|
706
|
+
usage = resource_config.description or ""
|
|
585
707
|
else:
|
|
586
|
-
|
|
708
|
+
uri = resource_config.get("uri", "")
|
|
709
|
+
usage = resource_config.get("description", "")
|
|
710
|
+
if uri:
|
|
711
|
+
resource_uris.append((uri, usage))
|
|
712
|
+
|
|
713
|
+
# From tools section - detect URIs (anything with ://)
|
|
714
|
+
# This allows unified syntax: resources as tools
|
|
715
|
+
tool_configs = metadata.tools if metadata and hasattr(metadata, 'tools') else []
|
|
716
|
+
for tool_config in tool_configs:
|
|
717
|
+
if hasattr(tool_config, 'name'):
|
|
718
|
+
tool_name = tool_config.name
|
|
719
|
+
tool_desc = tool_config.description or ""
|
|
720
|
+
else:
|
|
721
|
+
tool_name = tool_config.get("name", "")
|
|
722
|
+
tool_desc = tool_config.get("description", "")
|
|
587
723
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
724
|
+
# Auto-detect resource URIs (anything with :// scheme)
|
|
725
|
+
if "://" in tool_name:
|
|
726
|
+
resource_uris.append((tool_name, tool_desc))
|
|
591
727
|
|
|
592
|
-
#
|
|
593
|
-
#
|
|
594
|
-
|
|
728
|
+
# Create tools from collected resource URIs
|
|
729
|
+
# Pass the loaded MCP server so resources can be resolved from it
|
|
730
|
+
for uri, usage in resource_uris:
|
|
731
|
+
resource_tool = create_resource_tool(uri, usage, mcp_server=loaded_mcp_server)
|
|
732
|
+
tools.append(resource_tool)
|
|
733
|
+
logger.debug(f"Loaded resource as tool: {uri}")
|
|
595
734
|
|
|
596
735
|
# Create dynamic result_type from schema if not provided
|
|
736
|
+
# Note: use_structured_output is set earlier from metadata.structured_output
|
|
597
737
|
if result_type is None and agent_schema and "properties" in agent_schema:
|
|
598
738
|
if use_structured_output:
|
|
599
739
|
# Pre-process schema for Qwen compatibility (strips min/max, sets additionalProperties=False)
|
|
@@ -615,21 +755,30 @@ async def create_agent(
|
|
|
615
755
|
wrapped_result_type = _create_schema_wrapper(
|
|
616
756
|
result_type, strip_description=strip_model_description
|
|
617
757
|
)
|
|
758
|
+
# Use InstrumentationSettings with version=3 to include agent name in span names
|
|
759
|
+
from pydantic_ai.models.instrumented import InstrumentationSettings
|
|
760
|
+
instrumentation = InstrumentationSettings(version=3) if settings.otel.enabled else False
|
|
761
|
+
|
|
618
762
|
agent = Agent(
|
|
619
763
|
model=model,
|
|
764
|
+
name=agent_name, # Used for OTEL span names (version 3: "invoke_agent {name}")
|
|
620
765
|
system_prompt=system_prompt,
|
|
621
766
|
output_type=wrapped_result_type,
|
|
622
767
|
tools=tools,
|
|
623
|
-
instrument=
|
|
768
|
+
instrument=instrumentation,
|
|
624
769
|
model_settings={"temperature": temperature},
|
|
625
770
|
retries=settings.llm.max_retries,
|
|
626
771
|
)
|
|
627
772
|
else:
|
|
773
|
+
from pydantic_ai.models.instrumented import InstrumentationSettings
|
|
774
|
+
instrumentation = InstrumentationSettings(version=3) if settings.otel.enabled else False
|
|
775
|
+
|
|
628
776
|
agent = Agent(
|
|
629
777
|
model=model,
|
|
778
|
+
name=agent_name, # Used for OTEL span names (version 3: "invoke_agent {name}")
|
|
630
779
|
system_prompt=system_prompt,
|
|
631
780
|
tools=tools,
|
|
632
|
-
instrument=
|
|
781
|
+
instrument=instrumentation,
|
|
633
782
|
model_settings={"temperature": temperature},
|
|
634
783
|
retries=settings.llm.max_retries,
|
|
635
784
|
)
|