remdb 0.3.202__py3-none-any.whl → 0.3.245__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 (44) hide show
  1. rem/agentic/README.md +36 -2
  2. rem/agentic/context.py +86 -3
  3. rem/agentic/context_builder.py +39 -33
  4. rem/agentic/mcp/tool_wrapper.py +2 -2
  5. rem/agentic/providers/pydantic_ai.py +68 -51
  6. rem/agentic/schema.py +2 -2
  7. rem/api/mcp_router/resources.py +223 -0
  8. rem/api/mcp_router/tools.py +170 -18
  9. rem/api/routers/admin.py +30 -4
  10. rem/api/routers/auth.py +175 -18
  11. rem/api/routers/chat/child_streaming.py +394 -0
  12. rem/api/routers/chat/completions.py +24 -29
  13. rem/api/routers/chat/sse_events.py +5 -1
  14. rem/api/routers/chat/streaming.py +242 -272
  15. rem/api/routers/chat/streaming_utils.py +327 -0
  16. rem/api/routers/common.py +18 -0
  17. rem/api/routers/dev.py +7 -1
  18. rem/api/routers/feedback.py +9 -1
  19. rem/api/routers/messages.py +80 -15
  20. rem/api/routers/models.py +9 -1
  21. rem/api/routers/query.py +17 -15
  22. rem/api/routers/shared_sessions.py +16 -0
  23. rem/cli/commands/ask.py +205 -114
  24. rem/cli/commands/process.py +12 -4
  25. rem/cli/commands/query.py +109 -0
  26. rem/cli/commands/session.py +117 -0
  27. rem/cli/main.py +2 -0
  28. rem/models/entities/session.py +1 -0
  29. rem/schemas/agents/rem.yaml +1 -1
  30. rem/services/postgres/repository.py +7 -7
  31. rem/services/rem/service.py +47 -0
  32. rem/services/session/__init__.py +2 -1
  33. rem/services/session/compression.py +14 -12
  34. rem/services/session/pydantic_messages.py +111 -11
  35. rem/services/session/reload.py +2 -1
  36. rem/settings.py +71 -0
  37. rem/sql/migrations/001_install.sql +4 -4
  38. rem/sql/migrations/004_cache_system.sql +3 -1
  39. rem/sql/migrations/migrate_session_id_to_uuid.sql +45 -0
  40. rem/utils/schema_loader.py +139 -111
  41. {remdb-0.3.202.dist-info → remdb-0.3.245.dist-info}/METADATA +2 -2
  42. {remdb-0.3.202.dist-info → remdb-0.3.245.dist-info}/RECORD +44 -39
  43. {remdb-0.3.202.dist-info → remdb-0.3.245.dist-info}/WHEEL +0 -0
  44. {remdb-0.3.202.dist-info → remdb-0.3.245.dist-info}/entry_points.txt +0 -0
@@ -164,7 +164,7 @@ from .models import (
164
164
  ChatCompletionUsage,
165
165
  ChatMessage,
166
166
  )
167
- from .streaming import stream_openai_response, stream_openai_response_with_save, stream_simulator_response
167
+ from .streaming import stream_openai_response, stream_openai_response_with_save, stream_simulator_response, save_user_message
168
168
 
169
169
  router = APIRouter(prefix="/api/v1", tags=["chat"])
170
170
 
@@ -215,7 +215,7 @@ async def ensure_session_with_metadata(
215
215
  Merges request metadata with existing session metadata.
216
216
 
217
217
  Args:
218
- session_id: Session identifier (maps to Session.name)
218
+ session_id: Session UUID from X-Session-Id header
219
219
  user_id: User identifier
220
220
  tenant_id: Tenant identifier
221
221
  is_eval: Whether this is an evaluation session
@@ -228,12 +228,8 @@ async def ensure_session_with_metadata(
228
228
  try:
229
229
  repo = Repository(Session, table_name="sessions")
230
230
 
231
- # Try to load existing session by name (session_id is the name field)
232
- existing_list = await repo.find(
233
- filters={"name": session_id, "tenant_id": tenant_id},
234
- limit=1,
235
- )
236
- existing = existing_list[0] if existing_list else None
231
+ # Look up session by UUID (id field)
232
+ existing = await repo.get_by_id(session_id)
237
233
 
238
234
  if existing:
239
235
  # Merge metadata if provided
@@ -254,9 +250,10 @@ async def ensure_session_with_metadata(
254
250
  await repo.upsert(existing)
255
251
  logger.debug(f"Updated session {session_id} (eval={is_eval}, metadata keys={list(merged_metadata.keys())})")
256
252
  else:
257
- # Create new session
253
+ # Create new session with the provided UUID as the id
258
254
  session = Session(
259
- name=session_id,
255
+ id=session_id, # Use the provided UUID as session id
256
+ name=session_id, # Default name to UUID, can be updated later with LLM-generated name
260
257
  mode=SessionMode.EVALUATION if is_eval else SessionMode.NORMAL,
261
258
  user_id=user_id,
262
259
  tenant_id=tenant_id,
@@ -513,7 +510,7 @@ async def chat_completions(body: ChatCompletionRequest, request: Request):
513
510
 
514
511
  # Load raw session history for proper pydantic-ai message_history format
515
512
  # This enables proper tool call/return pairing for LLM API compatibility
516
- from ....services.session import SessionMessageStore, session_to_pydantic_messages
513
+ from ....services.session import SessionMessageStore, session_to_pydantic_messages, audit_session_history
517
514
  from ....agentic.schema import get_system_prompt
518
515
 
519
516
  pydantic_message_history = None
@@ -535,6 +532,15 @@ async def chat_completions(body: ChatCompletionRequest, request: Request):
535
532
  system_prompt=agent_system_prompt,
536
533
  )
537
534
  logger.debug(f"Converted {len(raw_session_history)} session messages to {len(pydantic_message_history)} pydantic-ai messages (with system prompt)")
535
+
536
+ # Audit session history if enabled (for debugging)
537
+ audit_session_history(
538
+ session_id=context.session_id,
539
+ agent_name=schema_name or "default",
540
+ prompt=body.messages[-1].content if body.messages else "",
541
+ raw_session_history=raw_session_history,
542
+ pydantic_messages_count=len(pydantic_message_history),
543
+ )
538
544
  except Exception as e:
539
545
  logger.warning(f"Failed to load session history for message_history: {e}")
540
546
  # Fall back to old behavior (concatenated prompt)
@@ -576,24 +582,13 @@ async def chat_completions(body: ChatCompletionRequest, request: Request):
576
582
 
577
583
  # Streaming mode
578
584
  if body.stream:
579
- # Save user message before streaming starts
580
- if settings.postgres.enabled and context.session_id:
581
- user_message = {
582
- "role": "user",
583
- "content": body.messages[-1].content if body.messages else "",
584
- "timestamp": datetime.utcnow().isoformat(),
585
- }
586
- try:
587
- store = SessionMessageStore(user_id=context.user_id or settings.test.effective_user_id)
588
- await store.store_session_messages(
589
- session_id=context.session_id,
590
- messages=[user_message],
591
- user_id=context.user_id,
592
- compress=False, # User messages are typically short
593
- )
594
- logger.debug(f"Saved user message to session {context.session_id}")
595
- except Exception as e:
596
- logger.error(f"Failed to save user message: {e}", exc_info=True)
585
+ # Save user message before streaming starts (using shared utility)
586
+ if context.session_id:
587
+ await save_user_message(
588
+ session_id=context.session_id,
589
+ user_id=context.user_id,
590
+ content=body.messages[-1].content if body.messages else "",
591
+ )
597
592
 
598
593
  return StreamingResponse(
599
594
  stream_openai_response_with_save(
@@ -321,7 +321,11 @@ class MetadataEvent(BaseModel):
321
321
  # Agent info
322
322
  agent_schema: str | None = Field(
323
323
  default=None,
324
- description="Name of the agent schema used for this response (e.g., 'rem', 'query-assistant')"
324
+ description="Name of the top-level agent schema (e.g., 'siggy', 'rem')"
325
+ )
326
+ responding_agent: str | None = Field(
327
+ default=None,
328
+ description="Name of the agent that produced this response (may differ from agent_schema if delegated via ask_agent)"
325
329
  )
326
330
 
327
331
  # Session info