Phase 7: Agent Selector — per-agent soul.md + ChromaDB memory filtering
- Agent dropdown UI (chip button + hidden select) in composer header - Session.agent field persists agent selection across refresh - soul.md loaded per-agent via ephemeral_system_prompt injection - ChromaDB memory filtered by agent topic (lotus/, sunflower/, etc.) - Fixed streaming.py: agent→_ai_agent variable shadowing (lines 1161, 1163) - New API endpoints: /api/agents/topology, /api/agents/memory/search - Agent metadata registry with emoji, name, description per Tier-2 agent
This commit is contained in:
@@ -23,6 +23,7 @@ from api.config import (
|
||||
resolve_model_provider,
|
||||
)
|
||||
from api.helpers import redact_session_data
|
||||
from api.agents_memory import _get_agent_soul, _get_agent_memory_context
|
||||
|
||||
# Global lock for os.environ writes. Per-session locks (_agent_lock) prevent
|
||||
# concurrent runs of the SAME session, but two DIFFERENT sessions can still
|
||||
@@ -774,7 +775,7 @@ def _sse(handler, event, data):
|
||||
handler.wfile.flush()
|
||||
|
||||
|
||||
def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, attachments=None):
|
||||
def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, attachments=None, agent=None):
|
||||
"""Run agent in background thread, writing SSE events to STREAMS[stream_id]."""
|
||||
q = STREAMS.get(stream_id)
|
||||
if q is None:
|
||||
@@ -814,6 +815,8 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
|
||||
s = get_session(session_id)
|
||||
s.workspace = str(Path(workspace).expanduser().resolve())
|
||||
s.model = model
|
||||
if agent:
|
||||
s.agent = agent
|
||||
|
||||
_agent_lock = _get_session_agent_lock(session_id)
|
||||
# TD1: set thread-local env context so concurrent sessions don't clobber globals
|
||||
@@ -1071,7 +1074,7 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
|
||||
else:
|
||||
_fallback_resolved = None
|
||||
|
||||
agent = _AIAgent(
|
||||
_ai_agent = _AIAgent(
|
||||
model=resolved_model,
|
||||
provider=resolved_provider,
|
||||
base_url=resolved_base_url,
|
||||
@@ -1096,14 +1099,26 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
|
||||
),
|
||||
)
|
||||
|
||||
# ── Per-agent identity: load soul.md + memory context ──────────────────
|
||||
if _ai_agent:
|
||||
_soul = _get_agent_soul(agent) # agent = selected agent_id string
|
||||
_mem_ctx = _get_agent_memory_context(agent, msg_text, limit=5)
|
||||
if _soul or _mem_ctx:
|
||||
_parts = []
|
||||
if _soul:
|
||||
_parts.append(f"=== AGENT IDENTITY: {agent.upper()} ===\n{_soul}")
|
||||
if _mem_ctx:
|
||||
_parts.append(f"=== PERTINENT MEMORY ===\n{_mem_ctx}")
|
||||
_ai_agent.ephemeral_system_prompt = "\n\n".join(_parts)
|
||||
|
||||
# Store agent instance for cancel/interrupt propagation
|
||||
with STREAMS_LOCK:
|
||||
AGENT_INSTANCES[stream_id] = agent
|
||||
AGENT_INSTANCES[stream_id] = _ai_agent
|
||||
# Check if cancel was requested during agent initialization
|
||||
if stream_id in CANCEL_FLAGS and CANCEL_FLAGS[stream_id].is_set():
|
||||
# Cancel arrived during agent creation - interrupt immediately
|
||||
try:
|
||||
agent.interrupt("Cancelled before start")
|
||||
_ai_agent.interrupt("Cancelled before start")
|
||||
except Exception:
|
||||
logger.debug("Failed to interrupt agent before start")
|
||||
put('cancel', {'message': 'Cancelled by user'})
|
||||
@@ -1143,9 +1158,9 @@ def _run_agent_streaming(session_id, msg_text, model, workspace, stream_id, atta
|
||||
_personality_prompt = str(_pval)
|
||||
# Pass personality via ephemeral_system_prompt (agent's own mechanism)
|
||||
if _personality_prompt:
|
||||
agent.ephemeral_system_prompt = _personality_prompt
|
||||
_ai_agent.ephemeral_system_prompt = _personality_prompt
|
||||
_previous_messages = list(s.messages or [])
|
||||
result = agent.run_conversation(
|
||||
result = _ai_agent.run_conversation(
|
||||
user_message=workspace_ctx + msg_text,
|
||||
system_message=workspace_system_msg,
|
||||
conversation_history=_sanitize_messages_for_api(s.messages),
|
||||
|
||||
Reference in New Issue
Block a user