diff --git a/frontend/src/pages/AgentsPage.tsx b/frontend/src/pages/AgentsPage.tsx
index babe1cca..f78c28d8 100644
--- a/frontend/src/pages/AgentsPage.tsx
+++ b/frontend/src/pages/AgentsPage.tsx
@@ -1280,7 +1280,7 @@ function InteractTab({ agentId, agentStatus }: { agentId: string; agentStatus: s
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
- handleSend('queued');
+ handleSend('immediate');
}
}}
placeholder="Send a message to this agent..."
@@ -1293,23 +1293,8 @@ function InteractTab({ agentId, agentStatus }: { agentId: string; agentStatus: s
disabled={sending || !input.trim()}
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm cursor-pointer font-medium"
style={{ background: 'var(--color-accent)', color: '#fff', opacity: sending || !input.trim() ? 0.5 : 1 }}
- title="Send immediately (interrupts agent)"
>
- Immediate
-
-
diff --git a/src/openjarvis/agents/executor.py b/src/openjarvis/agents/executor.py
index d6f7beb2..f7f1b086 100644
--- a/src/openjarvis/agents/executor.py
+++ b/src/openjarvis/agents/executor.py
@@ -203,6 +203,12 @@ class AgentExecutor:
if not model:
raise FatalError("No model configured for agent")
+ logger.info(
+ "Agent %s [%s]: using model=%s, engine=%s",
+ agent["name"], agent["id"],
+ model, type(engine).__name__,
+ )
+
# Optionally override model via router policy
router_policy_key = config.get("router_policy")
if router_policy_key and self._system:
@@ -247,6 +253,16 @@ class AgentExecutor:
input_text = f"{input_text}\n\nNew instructions:\n{user_msgs}"
for m in pending:
self._manager.mark_message_delivered(m["id"])
+ logger.info(
+ "Agent %s: delivering %d pending message(s)",
+ agent["name"], len(pending),
+ )
+ else:
+ logger.info(
+ "Agent %s: no pending messages, running with "
+ "instruction only",
+ agent["name"],
+ )
# Build AgentContext with memory results from FTS5 backend
from openjarvis.agents._stubs import AgentContext
@@ -298,7 +314,22 @@ class AgentExecutor:
pass # Don't break agent tick if memory retrieval fails
agent_ctx.memory_results = memory_results
- return agent_instance.run(input_text, context=agent_ctx)
+ logger.info(
+ "Agent %s: calling agent.run() with %d chars input",
+ agent["name"], len(input_text),
+ )
+ _t0 = time.time()
+ result = agent_instance.run(input_text, context=agent_ctx)
+ _elapsed = time.time() - _t0
+ logger.info(
+ "Agent %s: agent.run() completed in %.1fs, "
+ "content_len=%d, turns=%d, tokens=%s",
+ agent["name"], _elapsed,
+ len(result.content or ""),
+ result.turns,
+ result.metadata.get("total_tokens", "?"),
+ )
+ return result
def _build_error_detail(self, error: AgentTickError) -> dict[str, Any]:
"""Build structured error detail for trace metadata."""
@@ -336,6 +367,12 @@ class AgentExecutor:
"""Update agent state after tick completion or failure."""
if error is None:
# Success
+ logger.info(
+ "Tick succeeded for agent %s in %.1fs, "
+ "response_len=%d",
+ agent_id, duration,
+ len(result.content or "") if result else 0,
+ )
self._manager.end_tick(agent_id)
self._manager.update_agent(agent_id, total_runs_increment=1)
@@ -381,6 +418,10 @@ class AgentExecutor:
"status": "ok",
})
elif isinstance(error, EscalateError):
+ logger.warning(
+ "Tick escalated for agent %s after %.1fs: %s",
+ agent_id, duration, error,
+ )
self._manager.end_tick(agent_id)
self._manager.update_agent(agent_id, status="needs_attention")
self._bus.publish(EventType.AGENT_TICK_ERROR, {
@@ -390,6 +431,10 @@ class AgentExecutor:
"duration": duration,
})
else:
+ logger.error(
+ "Tick failed for agent %s after %.1fs: %s",
+ agent_id, duration, error, exc_info=error,
+ )
self._manager.end_tick(agent_id)
self._manager.update_agent(agent_id, status="error")
# Write error detail to summary_memory so frontend can display it
diff --git a/src/openjarvis/server/agent_manager_routes.py b/src/openjarvis/server/agent_manager_routes.py
index d92d51ab..f2a03386 100644
--- a/src/openjarvis/server/agent_manager_routes.py
+++ b/src/openjarvis/server/agent_manager_routes.py
@@ -64,6 +64,24 @@ _BROWSER_SUB_TOOLS = {
}
+class _LightweightSystem:
+ """Minimal system facade for the executor — avoids rebuilding the
+ full JarvisSystem (which picks a random model from Ollama)."""
+
+ def __init__(self, engine: Any, model: str, config: Any = None):
+ self.engine = engine
+ self.model = model
+ self.config = config
+ self.memory_backend = None
+
+
+def _make_lightweight_system(
+ engine: Any, model: str, config: Any = None,
+) -> _LightweightSystem:
+ """Build a minimal system from the server's existing state."""
+ return _LightweightSystem(engine, model, config)
+
+
def _ensure_registries_populated() -> None:
"""Ensure ToolRegistry and ChannelRegistry are populated.
@@ -452,7 +470,7 @@ def create_agent_manager_router(
return {"status": "idle"}
@agents_router.post("/{agent_id}/run")
- async def run_agent(agent_id: str):
+ async def run_agent(agent_id: str, request: Request):
import threading
agent = manager.get_agent(agent_id)
@@ -473,28 +491,30 @@ def create_agent_manager_router(
status_code=409, detail="Agent is already running"
)
+ # Re-use the server's engine + model so we don't pick a
+ # random model from Ollama's list.
+ server_engine = getattr(request.app.state, "engine", None)
+ server_model = getattr(request.app.state, "model", "")
+ server_config = getattr(request.app.state, "config", None)
+
def _run_tick():
try:
from openjarvis.agents.executor import AgentExecutor
from openjarvis.core.events import get_event_bus
- from openjarvis.system import SystemBuilder
executor = AgentExecutor(
manager=manager, event_bus=get_event_bus(),
)
- try:
- system = SystemBuilder().build()
- executor.set_system(system)
- except Exception as build_err:
- manager.end_tick(agent_id)
- manager.update_agent(agent_id, status="error")
- manager.update_summary_memory(
- agent_id,
- f"ERROR: Failed to build system: {build_err}",
- )
- return
+ system = _make_lightweight_system(
+ server_engine, server_model, server_config,
+ )
+ executor.set_system(system)
executor.execute_tick(agent_id)
except Exception as exc:
+ logger.error(
+ "Run-tick failed for agent %s: %s",
+ agent_id, exc, exc_info=True,
+ )
try:
manager.end_tick(agent_id)
except Exception:
@@ -603,25 +623,56 @@ def create_agent_manager_router(
if not req.stream and req.mode == "immediate":
# Non-streaming immediate: trigger a background tick so the
# agent processes the message, then return the stored msg.
+ # Re-use the server's existing system (correct model/engine).
import threading
+ import time as _time
from openjarvis.agents.executor import AgentExecutor
from openjarvis.core.events import get_event_bus
- from openjarvis.system import SystemBuilder
+
+ _srv_engine = getattr(request.app.state, "engine", None)
+ _srv_model = getattr(request.app.state, "model", "")
+ _srv_config = getattr(request.app.state, "config", None)
def _immediate_tick():
+ _start = _time.time()
+ logger.info(
+ "Immediate tick starting for agent %s "
+ "(model=%s)",
+ agent_id, _srv_model,
+ )
try:
executor = AgentExecutor(
manager=manager, event_bus=get_event_bus(),
)
- try:
- system = SystemBuilder().build()
- executor.set_system(system)
- except Exception:
- return
+ system = _make_lightweight_system(
+ _srv_engine, _srv_model, _srv_config,
+ )
+ executor.set_system(system)
+ logger.info(
+ "Immediate tick: system ready in %.1fs, "
+ "executing tick for agent %s",
+ _time.time() - _start, agent_id,
+ )
executor.execute_tick(agent_id)
- except Exception:
- pass
+ logger.info(
+ "Immediate tick completed for agent %s "
+ "in %.1fs",
+ agent_id, _time.time() - _start,
+ )
+ except Exception as exc:
+ logger.error(
+ "Immediate tick failed for agent %s: %s",
+ agent_id, exc, exc_info=True,
+ )
+ try:
+ manager.end_tick(agent_id)
+ except Exception:
+ pass
+ manager.update_agent(agent_id, status="error")
+ manager.update_summary_memory(
+ agent_id, f"ERROR: {exc}",
+ )
threading.Thread(
target=_immediate_tick, daemon=True,