diff --git a/README.md b/README.md index 24052cbbb..f428fcaa0 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Trinity implements four foundational capabilities that transform simple AI assis - **First-Time Setup Wizard** — Guided setup for admin password and API key configuration ### Agent Capabilities +- **Multi-Runtime Support** — Choose between Claude Code (Anthropic) or Gemini CLI (Google) per agent - **MCP Integration** — 16 tools for external agent orchestration via Model Context Protocol - **Agent-to-Agent Communication** — Hierarchical delegation with fine-grained permission controls - **Vector Memory (Chroma)** — Per-agent semantic memory with MCP tools for retrieval @@ -42,7 +43,7 @@ Trinity implements four foundational capabilities that transform simple AI assis ### Prerequisites - Docker and Docker Compose v2+ -- Anthropic API key (for Claude-powered agents) +- Anthropic API key (for Claude-powered agents) OR Google API key (for Gemini-powered agents) ### One-Line Install @@ -319,6 +320,8 @@ AUTH0_DOMAIN=your-tenant.us.auth0.com - [Development Workflow](docs/DEVELOPMENT_WORKFLOW.md) — How to develop Trinity (context loading, testing, documentation) - [Deployment Guide](docs/DEPLOYMENT.md) — Production deployment instructions +- [Versioning & Upgrades](docs/VERSIONING_AND_UPGRADES.md) — Version strategy and upgrade procedures +- [Gemini Support Guide](docs/GEMINI_SUPPORT.md) — Using Gemini CLI runtime for cost optimization - [Trinity Compatible Agent Guide](docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md) — Creating Trinity-compatible agents - [Multi-Agent System Guide](docs/MULTI_AGENT_SYSTEM_GUIDE.md) — Building multi-agent systems with coordinated workflows - [Testing Guide](docs/TESTING_GUIDE.md) — Testing approach and standards diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..eba334028 --- /dev/null +++ b/VERSION @@ -0,0 +1,2 @@ +0.9.0 + diff --git a/config/agent-templates/test-gemini/CLAUDE.md b/config/agent-templates/test-gemini/CLAUDE.md new file mode 100644 index 000000000..cb2fcbe59 --- /dev/null +++ b/config/agent-templates/test-gemini/CLAUDE.md @@ -0,0 +1,38 @@ +# Test Gemini Agent + +You are a test agent running on **Google's Gemini 2.5 Pro** via Gemini CLI. + +## Your Purpose + +Validate that Trinity's multi-runtime support works correctly: +- Gemini CLI integration +- MCP tool access +- Cost tracking +- Token usage reporting +- Large context window (1M tokens) + +## Key Differences from Claude Code + +1. **Context Window:** You have 1 million tokens (5x larger than Claude Code) +2. **Cost:** Free tier with generous limits (60 req/min, 1K/day) +3. **Search:** Native Google Search integration +4. **Provider:** Google DeepMind (not Anthropic) + +## Testing Commands + +When asked to test, verify: +- `/test` - Basic functionality +- Tool calling works (filesystem, web_search) +- MCP servers are accessible +- Cost tracking reports correctly + +## Capabilities + +You have the same tools as Claude Code agents: +- Filesystem access +- Web search +- Terminal commands +- Code execution (Python, Node, Go) + +Report any differences in behavior compared to Claude Code agents. + diff --git a/config/agent-templates/test-gemini/template.yaml b/config/agent-templates/test-gemini/template.yaml new file mode 100644 index 000000000..d0c679d3f --- /dev/null +++ b/config/agent-templates/test-gemini/template.yaml @@ -0,0 +1,32 @@ +name: test-gemini +display_name: Test Gemini Agent +description: Test agent using Google's Gemini CLI runtime for validation +version: "1.0.0" +author: Trinity Platform +priority: 10 # Lower = higher in list (after system templates) + +type: business-assistant + +# Use Gemini runtime instead of Claude Code +runtime: + type: gemini-cli + model: gemini-3-flash + +resources: + cpu: "2" + memory: "2g" # Gemini is lighter than Claude Code + +capabilities: + - chat + - code-generation + - google-search-integration + - large-context # 1M tokens + +mcp_servers: [] + +credentials: {} + +slash_commands: + - name: /test + description: Test command to verify Gemini runtime is working + diff --git a/config/agent-templates/trinity-system/template.yaml b/config/agent-templates/trinity-system/template.yaml index fb02c80ce..f30026ebb 100644 --- a/config/agent-templates/trinity-system/template.yaml +++ b/config/agent-templates/trinity-system/template.yaml @@ -3,12 +3,13 @@ display_name: Trinity System Agent description: Platform operations manager responsible for agent health, lifecycle, resource governance, and schedule control. Auto-deployed, deletion-protected, with full access to all Trinity MCP tools. version: "1.1.0" author: Trinity Platform +priority: 1 # System template - always first type: system-orchestrator resources: cpu: "4" - memory: "8g" + memory: "4g" capabilities: - health-monitoring diff --git a/docker-compose.yml b/docker-compose.yml index 7a8324d7b..002d1be79 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,12 +11,14 @@ services: - SECRET_KEY=${SECRET_KEY:-} # Required - generate with: openssl rand -hex 32 - DEV_MODE_ENABLED=${DEV_MODE_ENABLED:-false} # Set to true for local development - ADMIN_PASSWORD=${ADMIN_PASSWORD:-} # Required for dev mode - set a strong password + - ADMIN_USERNAME=${ADMIN_USERNAME:-admin} - AUDIT_URL=http://audit-logger:8001 - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-} - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-} - REDIS_URL=redis://redis:6379 - REDIS_PASSWORD=${REDIS_PASSWORD:-} # Optional - set for production - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} + - GOOGLE_API_KEY=${GOOGLE_API_KEY:-} # For Gemini-powered agents - GITHUB_PAT=${GITHUB_PAT:-} - HOST_TEMPLATES_PATH=${PWD}/config/agent-templates - HOST_META_PROMPT_PATH=${PWD}/config/trinity-meta-prompt diff --git a/docker/base-image/Dockerfile b/docker/base-image/Dockerfile index 36a231e38..ba6cf6d72 100644 --- a/docker/base-image/Dockerfile +++ b/docker/base-image/Dockerfile @@ -41,6 +41,9 @@ RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o / RUN npm install -g @anthropic-ai/claude-code@latest +# Install Gemini CLI for multi-runtime support +RUN npm install -g @google/gemini-cli + RUN useradd -m -s /bin/bash -u 1000 developer && \ echo "developer:developer" | chpasswd && \ usermod -aG sudo developer && \ diff --git a/docker/base-image/agent_server/config.py b/docker/base-image/agent_server/config.py index 4ae91a2ed..e14d0c85c 100644 --- a/docker/base-image/agent_server/config.py +++ b/docker/base-image/agent_server/config.py @@ -26,9 +26,16 @@ # File size limits MAX_FILE_SIZE_BYTES = 100 * 1024 * 1024 # 100MB +# Runtime configuration +AGENT_RUNTIME = os.getenv("AGENT_RUNTIME", "claude-code") # "claude-code" or "gemini-cli" +AGENT_RUNTIME_MODEL = os.getenv("AGENT_RUNTIME_MODEL", None) # Optional model override + # Claude Code defaults DEFAULT_CONTEXT_WINDOW = 200000 +# Gemini CLI defaults +GEMINI_CONTEXT_WINDOW = 1000000 # 1M tokens + # Git configuration GIT_TIMEOUT_SECONDS = 60 diff --git a/docker/base-image/agent_server/main.py b/docker/base-image/agent_server/main.py index 0fedbbe01..9ce87bcaf 100644 --- a/docker/base-image/agent_server/main.py +++ b/docker/base-image/agent_server/main.py @@ -63,7 +63,8 @@ def run_server(): logger.info(f"Starting Agent API Server on port {port}") logger.info(f"Agent Name: {agent_state.agent_name}") - logger.info(f"Claude Code Available: {agent_state.claude_code_available}") + logger.info(f"Runtime: {agent_state.agent_runtime} (available: {agent_state.runtime_available})") + logger.info(f"Context Window: {agent_state.session_context_window:,} tokens") logger.info("SECURITY: This server is internal-only, accessed via Trinity backend proxy") # Phase: Agent-to-Agent Collaboration - Inject Trinity MCP if configured diff --git a/docker/base-image/agent_server/models.py b/docker/base-image/agent_server/models.py index fc5ef46fb..5a3062722 100644 --- a/docker/base-image/agent_server/models.py +++ b/docker/base-image/agent_server/models.py @@ -65,6 +65,7 @@ class ExecutionLogEntry(BaseModel): type: str # "tool_use" or "tool_result" tool: str input: Optional[Dict[str, Any]] = None + output: Optional[str] = None # Tool output for tool_result entries success: Optional[bool] = None duration_ms: Optional[int] = None timestamp: str diff --git a/docker/base-image/agent_server/routers/chat.py b/docker/base-image/agent_server/routers/chat.py index c25c1d01f..3ddd25b96 100644 --- a/docker/base-image/agent_server/routers/chat.py +++ b/docker/base-image/agent_server/routers/chat.py @@ -1,5 +1,7 @@ """ Chat endpoints for the agent server. + +Now supports multiple runtimes (Claude Code, Gemini CLI) via runtime adapter. """ import json import logging @@ -9,7 +11,8 @@ from ..models import ChatRequest, ModelRequest, ParallelTaskRequest from ..state import agent_state -from ..services.claude_code import execute_claude_code, execute_headless_task, get_execution_lock +from ..services.claude_code import get_execution_lock +from ..services.runtime_adapter import get_runtime logger = logging.getLogger(__name__) router = APIRouter() @@ -32,11 +35,15 @@ async def chat(request: ChatRequest): # Add user message to history agent_state.add_message("user", request.message) - # Execute Claude Code - now returns (response, execution_log, metadata) - response_text, execution_log, metadata = await execute_claude_code( - request.message, - stream=request.stream, - model=request.model + # Execute via runtime adapter (supports Claude Code or Gemini CLI) + runtime = get_runtime() + # Use request.model if provided, otherwise use the model set via /api/model endpoint + effective_model = request.model or agent_state.current_model + response_text, execution_log, metadata = await runtime.execute( + prompt=request.message, + model=effective_model, + continue_session=True, + stream=request.stream ) # Add assistant response to history @@ -99,8 +106,9 @@ async def execute_task(request: ParallelTaskRequest): """ logger.info(f"[Task] Executing parallel task: {request.message[:50]}...") - # Execute in headless mode (no lock, no --continue) - response_text, execution_log, metadata, session_id = await execute_headless_task( + # Execute via runtime adapter in headless mode (no lock, no --continue) + runtime = get_runtime() + response_text, execution_log, metadata, session_id = await runtime.execute_headless( prompt=request.message, model=request.model, allowed_tools=request.allowed_tools, @@ -144,11 +152,22 @@ async def get_session_info(): @router.get("/api/model") async def get_model(): """Get the current model being used""" - return { - "model": agent_state.current_model, - "available_models": ["sonnet", "opus", "haiku"], - "note": "Model aliases: sonnet (Sonnet 4.5), opus (Opus 4.5), haiku. Add [1m] suffix for 1M context (e.g., sonnet[1m])" - } + runtime = agent_state.agent_runtime + + if runtime == "gemini-cli" or runtime == "gemini": + return { + "model": agent_state.current_model, + "runtime": runtime, + "available_models": ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash"], + "note": "Gemini models. 2.5-pro has 1M context window." + } + else: + return { + "model": agent_state.current_model, + "runtime": runtime, + "available_models": ["sonnet", "opus", "haiku"], + "note": "Claude model aliases: sonnet (Sonnet 4.5), opus (Opus 4.5), haiku. Add [1m] suffix for 1M context." + } @router.put("/api/model") @@ -156,22 +175,40 @@ async def set_model(request: ModelRequest): """Set the model to use for subsequent messages""" from fastapi import HTTPException - valid_aliases = ["sonnet", "opus", "haiku", "sonnet[1m]", "opus[1m]", "haiku[1m]"] - - # Accept aliases or full model names (e.g., claude-sonnet-4-5-20250929) - if request.model in valid_aliases or request.model.startswith("claude-"): - agent_state.current_model = request.model - logger.info(f"Model changed to: {request.model}") - return { - "status": "success", - "model": agent_state.current_model, - "note": "Model will be used for subsequent messages" - } + runtime = agent_state.agent_runtime + + # Validate based on runtime + if runtime == "gemini-cli" or runtime == "gemini": + valid_models = ["gemini-3-pro", "gemini-3-flash", "gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash", "gemini-1.5-pro", "gemini-1.5-flash"] + if request.model in valid_models or request.model.startswith("gemini-"): + agent_state.current_model = request.model + logger.info(f"Model changed to: {request.model}") + return { + "status": "success", + "model": agent_state.current_model, + "note": "Model will be used for subsequent messages" + } + else: + raise HTTPException( + status_code=400, + detail=f"Invalid Gemini model: {request.model}. Use: gemini-2.5-pro, gemini-2.5-flash, etc." + ) else: - raise HTTPException( - status_code=400, - detail=f"Invalid model: {request.model}. Use aliases (sonnet, opus, haiku) or full model names." - ) + # Claude Code validation + valid_aliases = ["sonnet", "opus", "haiku", "sonnet[1m]", "opus[1m]", "haiku[1m]"] + if request.model in valid_aliases or request.model.startswith("claude-"): + agent_state.current_model = request.model + logger.info(f"Model changed to: {request.model}") + return { + "status": "success", + "model": agent_state.current_model, + "note": "Model will be used for subsequent messages" + } + else: + raise HTTPException( + status_code=400, + detail=f"Invalid Claude model: {request.model}. Use aliases (sonnet, opus, haiku) or full model names." + ) @router.delete("/api/chat/history") @@ -202,8 +239,16 @@ async def websocket_chat(websocket: WebSocket): # Add user message agent_state.add_message("user", message["content"]) - # Send response with execution log - response_text, execution_log, metadata = await execute_claude_code(message["content"], stream=True) + # Send response via runtime adapter + runtime = get_runtime() + # Use model from message if provided, otherwise use current_model from state + effective_model = message.get("model") or agent_state.current_model + response_text, execution_log, metadata = await runtime.execute( + prompt=message["content"], + model=effective_model, + continue_session=True, + stream=True + ) agent_state.add_message("assistant", response_text) await websocket.send_json({ diff --git a/docker/base-image/agent_server/routers/info.py b/docker/base-image/agent_server/routers/info.py index 03c0ed048..f48f36b64 100644 --- a/docker/base-image/agent_server/routers/info.py +++ b/docker/base-image/agent_server/routers/info.py @@ -50,10 +50,15 @@ async def get_agent_info(): except Exception as e: logger.error(f"Failed to read agent config: {e}") + # Determine runtime version + runtime_version = None + if agent_state.runtime_available: + runtime_version = "available" + return AgentInfo( name=agent_state.agent_name, status="running", - claude_version="2.0.49" if agent_state.claude_code_available else None, + claude_version=runtime_version if agent_state.agent_runtime == "claude-code" else None, mcp_servers=mcp_servers, uptime=None # TODO: Calculate uptime ) @@ -65,6 +70,9 @@ async def health_check(): return { "status": "healthy", "agent_name": agent_state.agent_name, + "runtime": agent_state.agent_runtime, + "runtime_available": agent_state.runtime_available, + # Backward compatibility "claude_available": agent_state.claude_code_available, "message_count": len(agent_state.conversation_history) } diff --git a/docker/base-image/agent_server/services/__init__.py b/docker/base-image/agent_server/services/__init__.py index bb49ef87e..089660874 100644 --- a/docker/base-image/agent_server/services/__init__.py +++ b/docker/base-image/agent_server/services/__init__.py @@ -2,12 +2,19 @@ Service modules for the agent server. """ from .activity_tracking import start_tool_execution, complete_tool_execution -from .claude_code import execute_claude_code +from .runtime_adapter import get_runtime, AgentRuntime from .trinity_mcp import inject_trinity_mcp_if_configured +# Backward compatibility - expose Claude-specific functions +from .claude_code import execute_claude_code, get_claude_runtime + __all__ = [ "start_tool_execution", "complete_tool_execution", - "execute_claude_code", + "get_runtime", + "AgentRuntime", "inject_trinity_mcp_if_configured", + # Backward compatibility + "execute_claude_code", + "get_claude_runtime", ] diff --git a/docker/base-image/agent_server/services/claude_code.py b/docker/base-image/agent_server/services/claude_code.py index 51c160562..83357552f 100644 --- a/docker/base-image/agent_server/services/claude_code.py +++ b/docker/base-image/agent_server/services/claude_code.py @@ -1,5 +1,7 @@ """ Claude Code execution service. + +Now implements AgentRuntime interface for multi-provider support. """ import os import json @@ -7,7 +9,7 @@ import asyncio import subprocess import logging -from typing import List, Dict, Optional +from typing import List, Dict, Optional, Tuple from datetime import datetime from pathlib import Path from concurrent.futures import ThreadPoolExecutor @@ -17,6 +19,7 @@ from ..models import ExecutionLogEntry, ExecutionMetadata from ..state import agent_state from .activity_tracking import start_tool_execution, complete_tool_execution +from .runtime_adapter import AgentRuntime logger = logging.getLogger(__name__) @@ -30,6 +33,72 @@ _execution_lock = asyncio.Lock() +class ClaudeCodeRuntime(AgentRuntime): + """Claude Code implementation of AgentRuntime interface.""" + + def is_available(self) -> bool: + """Check if Claude Code CLI is installed.""" + try: + result = subprocess.run( + ["claude", "--version"], + capture_output=True, + text=True, + timeout=5 + ) + return result.returncode == 0 + except Exception: + return False + + def get_default_model(self) -> str: + """Get default Claude model.""" + return "sonnet" # Claude Sonnet 4.5 + + def get_context_window(self, model: Optional[str] = None) -> int: + """Get context window for Claude models.""" + # Check for 1M context models + if model and "[1m]" in model.lower(): + return 1000000 + return 200000 # Standard 200K context + + def configure_mcp(self, mcp_servers: Dict) -> bool: + """ + Configure MCP servers via .mcp.json file. + Claude Code reads from ~/.mcp.json automatically. + """ + try: + mcp_config_path = Path.home() / ".mcp.json" + config = {"mcpServers": mcp_servers} + mcp_config_path.write_text(json.dumps(config, indent=2)) + logger.info(f"Configured {len(mcp_servers)} MCP servers for Claude Code") + return True + except Exception as e: + logger.error(f"Failed to configure MCP: {e}") + return False + + async def execute( + self, + prompt: str, + model: Optional[str] = None, + continue_session: bool = False, + stream: bool = False + ) -> Tuple[str, List[ExecutionLogEntry], ExecutionMetadata]: + """Execute Claude Code with the given prompt.""" + # Note: continue_session is handled internally by agent_state.session_started + # The execute_claude_code function checks agent_state and uses --continue automatically + return await execute_claude_code(prompt, stream, model) + + async def execute_headless( + self, + prompt: str, + model: Optional[str] = None, + allowed_tools: Optional[List[str]] = None, + system_prompt: Optional[str] = None, + timeout_seconds: int = 300 + ) -> Tuple[str, List[ExecutionLogEntry], ExecutionMetadata, str]: + """Execute Claude Code in headless mode for parallel tasks.""" + return await execute_headless_task(prompt, model, allowed_tools, system_prompt, timeout_seconds) + + def parse_stream_json_output(output: str) -> tuple[str, List[ExecutionLogEntry], ExecutionMetadata]: """ Parse stream-json output from Claude Code. @@ -604,3 +673,14 @@ def read_subprocess_output_with_timeout(): except Exception as e: logger.error(f"[Headless Task] Execution error: {e}") raise HTTPException(status_code=500, detail=f"Task execution error: {str(e)}") + + +# Global Claude Code runtime instance +_claude_runtime = None + +def get_claude_runtime() -> ClaudeCodeRuntime: + """Get or create the global Claude Code runtime instance.""" + global _claude_runtime + if _claude_runtime is None: + _claude_runtime = ClaudeCodeRuntime() + return _claude_runtime diff --git a/docker/base-image/agent_server/services/gemini_runtime.py b/docker/base-image/agent_server/services/gemini_runtime.py new file mode 100644 index 000000000..fd2590691 --- /dev/null +++ b/docker/base-image/agent_server/services/gemini_runtime.py @@ -0,0 +1,635 @@ +""" +Gemini CLI execution service. + +Implements AgentRuntime interface for Google's Gemini models. +""" +import os +import json +import uuid +import asyncio +import subprocess +import logging +from typing import List, Dict, Optional, Tuple +from datetime import datetime +from pathlib import Path + +from fastapi import HTTPException + +from ..models import ExecutionLogEntry, ExecutionMetadata +from ..state import agent_state +from .activity_tracking import start_tool_execution, complete_tool_execution +from .runtime_adapter import AgentRuntime + +logger = logging.getLogger(__name__) + +# Gemini pricing per 1K tokens (as of Dec 2024, from ai.google.dev/pricing) +# Free tier has limits, but we calculate what it *would* cost +# Note: Prices are for standard context (≤200K tokens) +GEMINI_PRICING = { + "gemini-3-pro": { + "input": 0.002, # $2.00 per 1M = $0.002 per 1K + "output": 0.012, # $12.00 per 1M = $0.012 per 1K + }, + "gemini-3-flash": { + "input": 0.0005, # $0.50 per 1M = $0.0005 per 1K + "output": 0.003, # $3.00 per 1M = $0.003 per 1K + }, + "gemini-2.5-pro": { + "input": 0.00125, # $1.25 per 1M = $0.00125 per 1K + "output": 0.01, # $10.00 per 1M = $0.01 per 1K + }, + "gemini-2.5-flash": { + "input": 0.0003, # $0.30 per 1M = $0.0003 per 1K + "output": 0.0025, # $2.50 per 1M = $0.0025 per 1K + }, + "gemini-2.0-flash": { + "input": 0.0001, # $0.10 per 1M = $0.0001 per 1K + "output": 0.0004, # $0.40 per 1M = $0.0004 per 1K + }, + "gemini-2.0-flash-lite": { + "input": 0.000075, # $0.075 per 1M = $0.000075 per 1K + "output": 0.0003, # $0.30 per 1M = $0.0003 per 1K + }, + # Default to 2.5 Pro pricing for unknown models + "default": { + "input": 0.00125, + "output": 0.01, + } +} + + +def calculate_gemini_cost(input_tokens: int, output_tokens: int, model: Optional[str] = None) -> float: + """ + Calculate estimated cost for Gemini API usage. + + Note: Free tier doesn't actually charge, but we calculate + what it would cost for tracking/comparison purposes. + """ + # Get pricing for model or use default + model_key = model.lower() if model else "default" + pricing = GEMINI_PRICING.get(model_key, GEMINI_PRICING["default"]) + + input_cost = (input_tokens / 1000) * pricing["input"] + output_cost = (output_tokens / 1000) * pricing["output"] + + return round(input_cost + output_cost, 6) + + +class GeminiRuntime(AgentRuntime): + """Gemini CLI implementation of AgentRuntime interface.""" + + def is_available(self) -> bool: + """Check if Gemini CLI is installed.""" + try: + result = subprocess.run( + ["gemini", "--version"], + capture_output=True, + text=True, + timeout=5 + ) + return result.returncode == 0 + except Exception: + return False + + def get_default_model(self) -> str: + """Get default Gemini model.""" + return "gemini-3-flash" + + def get_context_window(self, model: Optional[str] = None) -> int: + """Get context window for Gemini models.""" + # Gemini 2.5 Pro has 1M token context + return 1000000 + + def configure_mcp(self, mcp_servers: Dict) -> bool: + """ + Configure MCP servers via Gemini CLI commands. + + Gemini uses "gemini mcp add [args...]" instead of .mcp.json. + Uses the shared implementation from trinity_mcp.py for consistency. + """ + from .trinity_mcp import _configure_gemini_mcp_servers + return _configure_gemini_mcp_servers(mcp_servers) + + async def execute( + self, + prompt: str, + model: Optional[str] = None, + continue_session: bool = False, + stream: bool = False + ) -> Tuple[str, List[ExecutionLogEntry], ExecutionMetadata]: + """ + Execute Gemini CLI with the given prompt. + + Uses same output format as Claude Code for compatibility. + """ + if not self.is_available(): + raise HTTPException( + status_code=503, + detail="Gemini CLI is not available in this container" + ) + + try: + # Get GEMINI_API_KEY from environment + api_key = os.getenv("GEMINI_API_KEY") + if not api_key: + raise HTTPException( + status_code=500, + detail="GEMINI_API_KEY not configured in agent container" + ) + + # Build command + cmd = ["gemini", "--output-format", "stream-json", "--yolo"] + + # Add model selection if specified + if model: + cmd.extend(["--model", model]) + logger.info(f"Using Gemini model: {model}") + + # Session continuity + if continue_session and agent_state.session_started: + cmd.append("--resume") + logger.info("Resuming existing Gemini session") + else: + agent_state.session_started = True + logger.info("Starting new Gemini session") + + # Initialize tracking structures + execution_log: List[ExecutionLogEntry] = [] + metadata = ExecutionMetadata() + metadata.context_window = self.get_context_window(model) + tool_start_times: Dict[str, datetime] = {} + tool_names: Dict[str, str] = {} # Map tool_id -> tool_name + response_parts: List[str] = [] + + logger.info(f"Starting Gemini CLI: {' '.join(cmd[:5])}...") + + # Use Popen for real-time streaming + process = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1 # Line buffered + ) + + # Write prompt to stdin and close it + process.stdin.write(prompt) + process.stdin.close() + + # Helper function that reads subprocess output (runs in thread pool) + def read_subprocess_output(): + """Blocking function to read subprocess output line by line""" + try: + for line in iter(process.stdout.readline, ''): + if not line: + break + # Process each line immediately + # Gemini CLI uses same stream-json format as Claude Code + self._process_stream_line(line, execution_log, metadata, tool_start_times, tool_names, response_parts, model) + except Exception as e: + logger.error(f"Error reading Gemini output: {e}") + + # Wait for process to complete and get stderr + stderr = process.stderr.read() + return_code = process.wait() + return stderr, return_code + + # Run the blocking subprocess reading in a thread pool + from concurrent.futures import ThreadPoolExecutor + executor = ThreadPoolExecutor(max_workers=1) + loop = asyncio.get_event_loop() + stderr_output, return_code = await loop.run_in_executor(executor, read_subprocess_output) + + # Check for errors + if return_code != 0: + logger.error(f"Gemini CLI failed (exit {return_code}): {stderr_output[:500]}") + raise HTTPException( + status_code=500, + detail=f"Gemini execution failed: {stderr_output[:200] if stderr_output else 'Unknown error'}" + ) + + # Build final response text + logger.info(f"[Stream] Building response from {len(response_parts)} parts") + response_text = "\n".join(response_parts) if response_parts else "" + + # Count unique tools used + tool_use_count = len([e for e in execution_log if e.type == "tool_use"]) + metadata.tool_count = tool_use_count + + # Handle empty response gracefully + # Sometimes Gemini returns success with no assistant message (tool result IS the response) + if not response_text: + logger.warning(f"[Stream] Empty response - parts were: {response_parts[:3] if response_parts else 'EMPTY'}") + if tool_use_count > 0: + # Tools were used but no final message - use tool result as response + tool_results = [e for e in execution_log if e.type == "tool_result"] + if tool_results and tool_results[-1].output: + # Use the last tool result output as the response + response_text = tool_results[-1].output + logger.info(f"Using tool result as response: {response_text[:100]}...") + else: + response_text = "(Task completed)" + logger.warning("Gemini returned empty response after tool execution") + else: + # No response and no tools - unusual but not necessarily an error + response_text = "(No response from model)" + logger.warning("Gemini returned empty response with no tool calls") + + # Update session stats + if metadata.cost_usd: + agent_state.session_total_cost += metadata.cost_usd + agent_state.session_total_output_tokens += metadata.output_tokens + if metadata.input_tokens > agent_state.session_context_tokens: + agent_state.session_context_tokens = metadata.input_tokens + agent_state.session_context_window = metadata.context_window + + logger.info(f"Gemini response: cost=${metadata.cost_usd}, duration={metadata.duration_ms}ms, tools={metadata.tool_count}, context={metadata.input_tokens}/{metadata.context_window}") + + return response_text, execution_log, metadata + + except HTTPException: + raise + except Exception as e: + logger.error(f"Gemini execution error: {e}") + raise HTTPException(status_code=500, detail=f"Execution error: {str(e)}") + + def _process_stream_line( + self, + line: str, + execution_log: List[ExecutionLogEntry], + metadata: ExecutionMetadata, + tool_start_times: Dict[str, datetime], + tool_names: Dict[str, str], + response_parts: List[str], + current_model: Optional[str] = None + ) -> None: + """ + Process a single line of stream-json output from Gemini CLI. + + Gemini CLI uses the same stream-json format as Claude Code, so we can + reuse the parsing logic with minor adjustments. + """ + if not line.strip(): + return + + try: + msg = json.loads(line) + except json.JSONDecodeError: + logger.warning(f"Failed to parse line as JSON: {line[:100]}") + return + + msg_type = msg.get("type") + + if msg_type == "init": + metadata.session_id = msg.get("session_id") + + elif msg_type == "message": + # Gemini CLI sends response text as {"type":"message","role":"assistant","content":"..."} + role = msg.get("role") + content = msg.get("content", "") + logger.info(f"[Stream] message: role={role}, content_len={len(content) if content else 0}") + if role == "assistant" and content: + # Append to response parts (Gemini sends streaming deltas) + response_parts.append(content) + logger.info(f"[Stream] Appended assistant content, parts_count={len(response_parts)}") + + elif msg_type == "result": + # Final result message with stats + metadata.duration_ms = msg.get("duration_ms") + metadata.num_turns = msg.get("num_turns") + result_text = msg.get("result", "") + if result_text: + response_parts.clear() + response_parts.append(result_text) + + # Extract token usage from stats field (Gemini CLI format) + stats = msg.get("stats", {}) + if stats: + metadata.input_tokens = stats.get("input_tokens", 0) + metadata.output_tokens = stats.get("output_tokens", 0) + metadata.duration_ms = stats.get("duration_ms", metadata.duration_ms) + + # Fallback to usage field if stats not present + usage = msg.get("usage", {}) + if not stats and usage: + metadata.input_tokens = usage.get("input_tokens", 0) + metadata.output_tokens = usage.get("output_tokens", 0) + + # Gemini might use different field names - adapt if needed + model_usage = msg.get("modelUsage", {}) + detected_model = None + for model_name, model_data in model_usage.items(): + detected_model = model_name + if "contextWindow" in model_data: + metadata.context_window = model_data["contextWindow"] + if "inputTokens" in model_data: + metadata.input_tokens = model_data["inputTokens"] + if "outputTokens" in model_data: + metadata.output_tokens = model_data["outputTokens"] + break + + # Calculate cost from tokens (Gemini CLI doesn't report cost directly) + # Use reported cost if available, otherwise calculate + reported_cost = msg.get("total_cost_usd", 0) + if reported_cost and reported_cost > 0: + metadata.cost_usd = reported_cost + else: + # Calculate estimated cost based on token usage + # Priority: detected_model > current_model (UI selected) > env default + model_for_pricing = detected_model or current_model or os.getenv("AGENT_RUNTIME_MODEL", "gemini-3-flash") + metadata.cost_usd = calculate_gemini_cost( + metadata.input_tokens, + metadata.output_tokens, + model_for_pricing + ) + + elif msg_type == "tool_use": + # Gemini CLI outputs tool_use at top level: {"type":"tool_use","tool_name":"...","tool_id":"...","parameters":{}} + tool_id = msg.get("tool_id", str(uuid.uuid4())) + tool_name = msg.get("tool_name") or msg.get("name", "Unknown") + tool_input = msg.get("parameters") or msg.get("input", {}) + timestamp = datetime.now() + + tool_start_times[tool_id] = timestamp + tool_names[tool_id] = tool_name # Store for later lookup + + execution_log.append(ExecutionLogEntry( + id=tool_id, + type="tool_use", + tool=tool_name, + input=tool_input, + timestamp=timestamp.isoformat() + )) + + # Update session activity + start_tool_execution(tool_id, tool_name, tool_input) + logger.debug(f"Tool started: {tool_name} ({tool_id})") + + elif msg_type == "tool_result": + # Gemini CLI outputs tool_result at top level: {"type":"tool_result","tool_id":"...","status":"success","output":"..."} + tool_id = msg.get("tool_id", "") + is_error = msg.get("status") == "error" + tool_output = msg.get("output", "") + timestamp = datetime.now() + + # Look up tool name from previous tool_use + tool_name = tool_names.get(tool_id, "Unknown") + + # Calculate duration + duration_ms = None + if tool_id in tool_start_times: + delta = timestamp - tool_start_times[tool_id] + duration_ms = int(delta.total_seconds() * 1000) + + execution_log.append(ExecutionLogEntry( + id=tool_id, # Use same ID for correlation + type="tool_result", + tool=tool_name, + output=tool_output, + success=not is_error, + duration_ms=duration_ms, + timestamp=timestamp.isoformat() + )) + + # Update session activity + complete_tool_execution(tool_id, tool_output, is_error) + logger.debug(f"Tool completed: {tool_name} ({tool_id}) success={not is_error}") + + elif msg_type in ("assistant", "user"): + # Handle tool_use and tool_result blocks (Claude Code format - nested in message) + message = msg.get("message", {}) + message_content = message.get("content", []) + + for content_block in message_content: + block_type = content_block.get("type") + + if block_type == "tool_use": + # Tool is being called + tool_id = content_block.get("id", str(uuid.uuid4())) + tool_name = content_block.get("name", "Unknown") + tool_input = content_block.get("input", {}) + timestamp = datetime.now() + + tool_start_times[tool_id] = timestamp + + execution_log.append(ExecutionLogEntry( + id=tool_id, + type="tool_use", + tool=tool_name, + input=tool_input, + timestamp=timestamp.isoformat() + )) + + # Update session activity + start_tool_execution(tool_id, tool_name, tool_input) + logger.debug(f"Tool started: {tool_name} ({tool_id})") + + elif block_type == "tool_result": + # Tool result returned + tool_id = content_block.get("tool_use_id", "") + is_error = content_block.get("is_error", False) + timestamp = datetime.now() + + # Extract output content + tool_output = "" + result_content = content_block.get("content", []) + if isinstance(result_content, list): + for item in result_content: + if isinstance(item, dict) and item.get("type") == "text": + tool_output = item.get("text", "") + break + elif isinstance(result_content, str): + tool_output = result_content + + # Calculate duration + duration_ms = None + if tool_id in tool_start_times: + delta = timestamp - tool_start_times[tool_id] + duration_ms = int(delta.total_seconds() * 1000) + + # Find tool name from tool_use entry + tool_name = "Unknown" + for entry in execution_log: + if entry.id == tool_id and entry.type == "tool_use": + tool_name = entry.tool + break + + execution_log.append(ExecutionLogEntry( + id=tool_id, + type="tool_result", + tool=tool_name, + success=not is_error, + duration_ms=duration_ms, + timestamp=timestamp.isoformat() + )) + + # Update session activity + complete_tool_execution(tool_id, not is_error, tool_output) + logger.debug(f"Tool completed: {tool_name} ({tool_id}) - success={not is_error}") + + elif block_type == "text": + # Gemini's text response + text = content_block.get("text", "") + if text: + response_parts.append(text) + + + async def execute_headless( + self, + prompt: str, + model: Optional[str] = None, + allowed_tools: Optional[List[str]] = None, + system_prompt: Optional[str] = None, + timeout_seconds: int = 300 + ) -> Tuple[str, List[ExecutionLogEntry], ExecutionMetadata, str]: + """ + Execute Gemini CLI in headless mode for parallel tasks. + + Unlike execute(), this function: + - Does NOT use --resume (stateless) + - Each call is independent + - Supports tool restrictions and custom system prompts + """ + if not self.is_available(): + raise HTTPException( + status_code=503, + detail="Gemini CLI is not available in this container" + ) + + try: + # Get GEMINI_API_KEY from environment + api_key = os.getenv("GEMINI_API_KEY") + if not api_key: + raise HTTPException( + status_code=500, + detail="GEMINI_API_KEY not configured in agent container" + ) + + # Generate unique session ID for this task + session_id = str(uuid.uuid4())[:8] + + # Build command - stateless (no --resume) + cmd = ["gemini", "--output-format", "stream-json", "--yolo"] + + # Add model selection if specified + if model: + cmd.extend(["--model", model]) + + # Add tool restrictions if specified + if allowed_tools: + for tool in allowed_tools: + cmd.extend(["--allowed-tools", tool]) + + # Add system prompt if specified + if system_prompt: + cmd.extend(["--system-prompt", system_prompt]) + + # Initialize tracking structures + execution_log: List[ExecutionLogEntry] = [] + metadata = ExecutionMetadata() + metadata.context_window = self.get_context_window(model) + tool_start_times: Dict[str, datetime] = {} + tool_names: Dict[str, str] = {} # Map tool_id -> tool_name + response_parts: List[str] = [] + + logger.info(f"[Headless Task {session_id}] Starting Gemini CLI...") + + # Use Popen for real-time streaming with timeout + process = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + bufsize=1 + ) + + # Write prompt to stdin and close it + process.stdin.write(prompt) + process.stdin.close() + + # Helper function that reads subprocess output + def read_subprocess_output(): + """Blocking function to read subprocess output line by line with timeout""" + import time + start_time = time.time() + try: + for line in iter(process.stdout.readline, ''): + if not line: + break + if time.time() - start_time > timeout_seconds: + process.kill() + raise TimeoutError(f"Task exceeded {timeout_seconds}s timeout") + self._process_stream_line(line, execution_log, metadata, tool_start_times, tool_names, response_parts, model) + except Exception as e: + logger.error(f"[Headless Task {session_id}] Error: {e}") + raise + + stderr = process.stderr.read() + return_code = process.wait() + return stderr, return_code + + # Run the blocking subprocess reading in a thread pool + from concurrent.futures import ThreadPoolExecutor + executor = ThreadPoolExecutor(max_workers=1) + loop = asyncio.get_event_loop() + stderr_output, return_code = await loop.run_in_executor(executor, read_subprocess_output) + + # Check for errors + if return_code != 0: + logger.error(f"[Headless Task {session_id}] Gemini CLI failed (exit {return_code}): {stderr_output[:500]}") + raise HTTPException( + status_code=500, + detail=f"Gemini execution failed: {stderr_output[:200] if stderr_output else 'Unknown error'}" + ) + + # Build final response text + response_text = "\n".join(response_parts) if response_parts else "" + + # Count unique tools used + tool_use_count = len([e for e in execution_log if e.type == "tool_use"]) + metadata.tool_count = tool_use_count + + # Handle empty response gracefully + if not response_text: + if tool_use_count > 0: + # Use tool result as response if available + tool_results = [e for e in execution_log if e.type == "tool_result"] + if tool_results and tool_results[-1].output: + response_text = tool_results[-1].output + logger.info(f"[Headless Task {session_id}] Using tool result as response") + else: + response_text = "(Task completed)" + logger.warning(f"[Headless Task {session_id}] Gemini returned empty response after tool execution") + else: + response_text = "(No response from model)" + logger.warning(f"[Headless Task {session_id}] Gemini returned empty response with no tool calls") + + # Use session_id from metadata if available, otherwise use our generated one + final_session_id = metadata.session_id or session_id + + logger.info(f"[Headless Task {final_session_id}] Completed: cost=${metadata.cost_usd}, duration={metadata.duration_ms}ms, tools={metadata.tool_count}") + + return response_text, execution_log, metadata, final_session_id + + except HTTPException: + raise + except TimeoutError as e: + logger.error(f"[Headless Task] Timeout: {e}") + raise HTTPException(status_code=504, detail=str(e)) + except Exception as e: + logger.error(f"[Headless Task] Execution error: {e}") + raise HTTPException(status_code=500, detail=f"Task execution error: {str(e)}") + + +# Global Gemini runtime instance +_gemini_runtime = None + +def get_gemini_runtime() -> GeminiRuntime: + """Get or create the global Gemini runtime instance.""" + global _gemini_runtime + if _gemini_runtime is None: + _gemini_runtime = GeminiRuntime() + return _gemini_runtime + diff --git a/docker/base-image/agent_server/services/runtime_adapter.py b/docker/base-image/agent_server/services/runtime_adapter.py new file mode 100644 index 000000000..a1be72cd9 --- /dev/null +++ b/docker/base-image/agent_server/services/runtime_adapter.py @@ -0,0 +1,149 @@ +""" +Runtime Adapter - Abstract interface for agent execution engines. + +Allows Trinity to support multiple AI providers (Claude Code, Gemini CLI, etc.) +while maintaining a unified interface for chat, tool execution, and cost tracking. +""" +import os +import logging +from abc import ABC, abstractmethod +from typing import List, Dict, Optional, Tuple +from datetime import datetime + +from ..models import ExecutionLogEntry, ExecutionMetadata + +logger = logging.getLogger(__name__) + + +class AgentRuntime(ABC): + """ + Abstract base class for agent execution runtimes. + + Implementations must provide: + - execute(): Run the agent with a prompt + - configure_mcp(): Set up MCP tool servers + - is_available(): Check if runtime is installed + """ + + @abstractmethod + async def execute( + self, + prompt: str, + model: Optional[str] = None, + continue_session: bool = False, + stream: bool = False + ) -> Tuple[str, List[ExecutionLogEntry], ExecutionMetadata]: + """ + Execute agent with the given prompt. + + Args: + prompt: User message or task to execute + model: Model identifier (e.g., "sonnet-4.5", "gemini-2.5-pro") + continue_session: Whether to continue previous conversation context + stream: Whether to stream responses (for future use) + + Returns: + Tuple of (response_text, execution_log, metadata) + """ + pass + + @abstractmethod + def configure_mcp(self, mcp_servers: Dict) -> bool: + """ + Configure MCP servers for tool access. + + Args: + mcp_servers: Dict of server configurations from .mcp.json + + Returns: + True if configuration succeeded, False otherwise + """ + pass + + @abstractmethod + def is_available(self) -> bool: + """ + Check if this runtime is installed and available. + + Returns: + True if runtime CLI is installed, False otherwise + """ + pass + + @abstractmethod + def get_default_model(self) -> str: + """ + Get the default model for this runtime. + + Returns: + Model identifier string + """ + pass + + @abstractmethod + def get_context_window(self, model: Optional[str] = None) -> int: + """ + Get the context window size for a model. + + Args: + model: Optional model identifier (uses default if None) + + Returns: + Context window size in tokens + """ + pass + + @abstractmethod + async def execute_headless( + self, + prompt: str, + model: Optional[str] = None, + allowed_tools: Optional[List[str]] = None, + system_prompt: Optional[str] = None, + timeout_seconds: int = 300 + ) -> Tuple[str, List[ExecutionLogEntry], ExecutionMetadata, str]: + """ + Execute a stateless task in headless mode (no conversation context). + + Used for: + - Agent delegation from orchestrators + - Batch processing without context pollution + - Parallel task execution + + Args: + prompt: Task description + model: Model to use + allowed_tools: List of allowed tool names (None = all tools) + system_prompt: Custom system prompt + timeout_seconds: Execution timeout + + Returns: + Tuple of (response_text, execution_log, metadata, session_id) + """ + pass + + +def get_runtime() -> AgentRuntime: + """ + Factory function to get the appropriate runtime based on configuration. + + Reads AGENT_RUNTIME environment variable to determine which runtime to use. + Defaults to Claude Code for backward compatibility. + + Returns: + AgentRuntime instance (ClaudeCodeRuntime or GeminiRuntime) + """ + runtime_type = os.getenv("AGENT_RUNTIME", "claude-code").lower() + + if runtime_type == "gemini-cli" or runtime_type == "gemini": + from .gemini_runtime import get_gemini_runtime + runtime = get_gemini_runtime() + logger.info("Using Gemini CLI runtime") + return runtime + else: + # Default to Claude Code + from .claude_code import get_claude_runtime + runtime = get_claude_runtime() + logger.info("Using Claude Code runtime") + return runtime + diff --git a/docker/base-image/agent_server/services/trinity_mcp.py b/docker/base-image/agent_server/services/trinity_mcp.py index 0e2ee2116..c398ef9c1 100644 --- a/docker/base-image/agent_server/services/trinity_mcp.py +++ b/docker/base-image/agent_server/services/trinity_mcp.py @@ -1,9 +1,12 @@ """ Trinity MCP injection service for agent-to-agent collaboration. + +Supports both Claude Code (.mcp.json) and Gemini CLI (gemini mcp add). """ import os import json import logging +import subprocess from pathlib import Path logger = logging.getLogger(__name__) @@ -11,10 +14,13 @@ def inject_trinity_mcp_if_configured() -> bool: """ - Inject Trinity MCP server into agent's .mcp.json if credentials are configured. + Inject Trinity MCP server - runtime aware. This enables agent-to-agent communication via the Trinity platform. Called on agent startup. + + For Claude Code: Writes to ~/.mcp.json + For Gemini CLI: Writes to ~/.gemini/settings.json """ trinity_mcp_url = os.getenv("TRINITY_MCP_URL") trinity_mcp_api_key = os.getenv("TRINITY_MCP_API_KEY") @@ -23,6 +29,16 @@ def inject_trinity_mcp_if_configured() -> bool: logger.info("Trinity MCP not configured - skipping injection") return False + runtime = os.getenv("AGENT_RUNTIME", "claude-code").lower() + + if runtime == "gemini-cli": + return _inject_gemini_mcp(trinity_mcp_url, trinity_mcp_api_key) + else: + return _inject_claude_mcp(trinity_mcp_url, trinity_mcp_api_key) + + +def _inject_claude_mcp(trinity_mcp_url: str, trinity_mcp_api_key: str) -> bool: + """Inject Trinity MCP into Claude Code's .mcp.json file.""" home_dir = Path("/home/developer") mcp_file = home_dir / ".mcp.json" @@ -57,9 +73,141 @@ def inject_trinity_mcp_if_configured() -> bool: # Write back to file mcp_file.write_text(json.dumps(mcp_config, indent=2)) - logger.info(f"Injected Trinity MCP server into {mcp_file}") + logger.info(f"Injected Trinity MCP server into {mcp_file} (Claude Code)") + return True + + except Exception as e: + logger.warning(f"Failed to inject Trinity MCP for Claude Code: {e}") + return False + + +def _inject_gemini_mcp(trinity_mcp_url: str, trinity_mcp_api_key: str) -> bool: + """ + Inject Trinity MCP into Gemini CLI by writing to settings.json. + + Note: `gemini mcp add --transport http` has a bug where it creates a 'type' field + that the config parser rejects as unrecognized. We work around this by writing + directly to ~/.gemini/settings.json with the correct format. + + The correct format for HTTP/SSE MCP servers uses 'url' and 'headers' fields. + """ + try: + home_dir = Path("/home/developer") + gemini_dir = home_dir / ".gemini" + settings_file = gemini_dir / "settings.json" + + # Ensure .gemini directory exists + gemini_dir.mkdir(parents=True, exist_ok=True) + + # Read existing settings or create new + if settings_file.exists(): + content = settings_file.read_text() + settings = json.loads(content) if content.strip() else {} + else: + settings = {} + + # Ensure mcpServers key exists + if "mcpServers" not in settings: + settings["mcpServers"] = {} + + # Add/update Trinity MCP server with HTTP transport and auth header + # Using 'url' and 'headers' format (NOT 'type' which causes parser errors) + settings["mcpServers"]["trinity"] = { + "url": trinity_mcp_url, + "headers": { + "Authorization": f"Bearer {trinity_mcp_api_key}" + } + } + + # Write settings back + settings_file.write_text(json.dumps(settings, indent=2)) + + logger.info(f"Injected Trinity MCP server into {settings_file} (Gemini CLI)") return True except Exception as e: - logger.warning(f"Failed to inject Trinity MCP: {e}") + logger.warning(f"Failed to inject Trinity MCP for Gemini CLI: {e}") return False + + +def configure_mcp_servers(mcp_servers: dict) -> bool: + """ + Configure additional MCP servers for the agent - runtime aware. + + Args: + mcp_servers: Dict of server configs from template + {"server_name": {"command": "...", "args": [...]}} + """ + if not mcp_servers: + return True + + runtime = os.getenv("AGENT_RUNTIME", "claude-code").lower() + + if runtime == "gemini-cli": + return _configure_gemini_mcp_servers(mcp_servers) + else: + return _configure_claude_mcp_servers(mcp_servers) + + +def _configure_claude_mcp_servers(mcp_servers: dict) -> bool: + """Configure MCP servers for Claude Code via .mcp.json.""" + home_dir = Path("/home/developer") + mcp_file = home_dir / ".mcp.json" + + try: + if mcp_file.exists(): + content = mcp_file.read_text() + mcp_config = json.loads(content) if content.strip() else {"mcpServers": {}} + else: + mcp_config = {"mcpServers": {}} + + if "mcpServers" not in mcp_config: + mcp_config["mcpServers"] = {} + + # Add each MCP server + for server_name, config in mcp_servers.items(): + mcp_config["mcpServers"][server_name] = config + + mcp_file.write_text(json.dumps(mcp_config, indent=2)) + logger.info(f"Configured {len(mcp_servers)} MCP servers for Claude Code") + return True + + except Exception as e: + logger.warning(f"Failed to configure MCP servers for Claude Code: {e}") + return False + + +def _configure_gemini_mcp_servers(mcp_servers: dict) -> bool: + """Configure MCP servers for Gemini CLI via `gemini mcp add` commands.""" + success_count = 0 + + for server_name, config in mcp_servers.items(): + try: + command = config.get("command", "") + args = config.get("args", []) + + if not command: + logger.warning(f"Skipping MCP server '{server_name}': no command specified") + continue + + # Build the gemini mcp add command with --scope user for home directory + cmd = ["gemini", "mcp", "add", "--scope", "user", server_name, command] + args + + result = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=30 + ) + + if result.returncode == 0: + logger.info(f"Added MCP server '{server_name}' for Gemini CLI") + success_count += 1 + else: + logger.warning(f"Failed to add MCP server '{server_name}': {result.stderr}") + + except Exception as e: + logger.warning(f"Error adding MCP server '{server_name}': {e}") + + logger.info(f"Configured {success_count}/{len(mcp_servers)} MCP servers for Gemini CLI") + return success_count > 0 or len(mcp_servers) == 0 diff --git a/docker/base-image/agent_server/state.py b/docker/base-image/agent_server/state.py index d3809ce37..3375a7c4a 100644 --- a/docker/base-image/agent_server/state.py +++ b/docker/base-image/agent_server/state.py @@ -21,20 +21,50 @@ class AgentState: def __init__(self): self.conversation_history: List[ChatMessage] = [] self.agent_name = os.getenv("AGENT_NAME", "unknown") - self.claude_code_available = self._check_claude_code() + self.agent_runtime = os.getenv("AGENT_RUNTIME", "claude-code") + # Check if the configured runtime is available + self.runtime_available = self._check_runtime_available() + # Backward compatibility alias + self.claude_code_available = self.runtime_available if self.agent_runtime == "claude-code" else self._check_claude_code() self.session_started = False # Track if we've started a conversation # Session-level token tracking self.session_total_cost: float = 0.0 self.session_total_output_tokens: int = 0 self.session_context_tokens: int = 0 # Latest context size - self.session_context_window: int = 200000 # Max context + self.session_context_window: int = self._get_default_context_window() # Model selection (persists across session) - self.current_model: Optional[str] = os.getenv("CLAUDE_MODEL", None) # Default from env or None + self.current_model: Optional[str] = os.getenv("AGENT_RUNTIME_MODEL", None) or os.getenv("CLAUDE_MODEL", None) # Session activity tracking (for real-time monitoring) self.session_activity = self._create_empty_activity() # Store full tool outputs for drill-down (separate from timeline summaries) self.tool_outputs: Dict[str, str] = {} + def _get_default_context_window(self) -> int: + """Get default context window based on runtime""" + if self.agent_runtime == "gemini-cli" or self.agent_runtime == "gemini": + return 1000000 # 1M tokens for Gemini + return 200000 # 200K for Claude Code + + def _check_runtime_available(self) -> bool: + """Check if the configured runtime CLI is available""" + if self.agent_runtime == "gemini-cli" or self.agent_runtime == "gemini": + return self._check_gemini_cli() + return self._check_claude_code() + + def _check_gemini_cli(self) -> bool: + """Check if Gemini CLI is available""" + try: + result = subprocess.run( + ["gemini", "--version"], + capture_output=True, + text=True, + timeout=5 + ) + return result.returncode == 0 + except Exception as e: + logger.error(f"Gemini CLI check failed: {e}") + return False + def _create_empty_activity(self) -> Dict: """Create empty session activity structure""" return { diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 5b7034611..82803ae8b 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -45,10 +45,21 @@ SECRET_KEY=your-secret-key-here ADMIN_USERNAME=admin ADMIN_PASSWORD=your-secure-password -# Anthropic API Key - Required for agents +# Anthropic API Key - Required for Claude-powered agents ANTHROPIC_API_KEY=sk-ant-your-api-key ``` +### Google API Key (Optional - for Gemini-powered agents) + +To use Gemini CLI as an alternative runtime (free tier with 1M token context): + +```bash +# Get from: https://makersuite.google.com/app/apikey +GOOGLE_API_KEY=your-google-api-key +``` + +See [Gemini Support Guide](GEMINI_SUPPORT.md) for details on multi-runtime configuration. + ### GitHub Templates (Optional) To use GitHub-based agent templates (private repositories), add your GitHub Personal Access Token: diff --git a/docs/GEMINI_SUPPORT.md b/docs/GEMINI_SUPPORT.md new file mode 100644 index 000000000..8726b13e9 --- /dev/null +++ b/docs/GEMINI_SUPPORT.md @@ -0,0 +1,218 @@ +# Gemini CLI Runtime Support + +Trinity now supports **multiple AI runtimes**, allowing you to choose between Claude Code (Anthropic) and Gemini CLI (Google) for your agents. + +## Why Multi-Runtime? + +**Cost Optimization:** +- Gemini: Free tier (60 req/min, 1,000/day) +- Claude: Pay-per-use + +**Context Window:** +- Gemini: 1 million tokens (5x larger) +- Claude: 200K tokens + +**Use Case Matching:** +- Gemini: Data processing, monitoring, large codebases +- Claude: Complex reasoning, code quality, reliability + +## Getting Started + +### 1. Get a Google API Key + +1. Go to [Google AI Studio](https://makersuite.google.com/app/apikey) +2. Click "Create API Key" +3. Copy your key + +### 2. Configure Trinity + +Add to your `.env` file: +```bash +GOOGLE_API_KEY=your-google-api-key-here +``` + +### 3. Create a Gemini Agent + +**Via UI:** +1. Click "Create Agent" +2. Enter agent name +3. Select runtime: **Gemini CLI** +4. Choose model: `gemini-2.5-pro` +5. Click "Create" + +**Via API:** +```bash +curl -X POST http://localhost:8000/api/agents \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-gemini-agent", + "runtime": "gemini-cli", + "runtime_model": "gemini-2.5-pro", + "resources": {"cpu": "2", "memory": "2g"} + }' +``` + +**Via Template:** +```yaml +# config/agent-templates/my-agent/template.yaml +name: my-gemini-agent +runtime: + type: gemini-cli + model: gemini-2.5-pro +resources: + memory: "2g" # Gemini is lighter +``` + +## Feature Parity Matrix + +| Feature | Claude Code | Gemini CLI | Status | +|---------|-------------|------------|--------| +| **Chat Interface** | ✅ | ✅ | Identical | +| **MCP Tools** | ✅ | ✅ | Supported | +| **Cost Tracking** | ✅ | ✅ | Unified | +| **Token Tracking** | ✅ | ✅ | Unified | +| **Session Continuity** | ✅ | ✅ | `--resume` | +| **Tool Restrictions** | ✅ | ✅ | `--allowed-tools` | +| **YOLO Mode** | ✅ | ✅ | `--yolo` | +| **Context Window** | 200K | 1M | 5x larger | +| **Pricing** | Pay-per-use | Free tier | Different | +| **Native Search** | ❌ | ✅ | Gemini only | + +## Cost Comparison + +### Example: 100 Messages/Day + +**Claude Code (Sonnet 4.5):** +- Input: $3/M tokens +- Output: $15/M tokens +- Estimated: **$5-10/day** + +**Gemini CLI (2.5 Pro):** +- Free tier: 1,000 requests/day +- Estimated: **$0/day** (within limits) + +## Architecture + +Trinity uses a **Runtime Adapter** pattern: + +``` +User Chat → Backend → Agent Container → [Runtime Adapter] + ↓ + ┌─────────┴─────────┐ + ↓ ↓ + ClaudeCodeRuntime GeminiRuntime + ↓ ↓ + claude CLI gemini CLI +``` + +Both runtimes implement the same interface: +- `execute(prompt, model, continue_session)` +- `configure_mcp(servers)` +- Return same format: `(response, execution_log, metadata)` + +## Instruction File (CLAUDE.md) + +Both Claude Code and Gemini CLI read agent instructions from `CLAUDE.md`. + +**Why keep the name `CLAUDE.md`?** +- Backward compatibility with existing agents +- Both runtimes understand markdown instruction files +- Renaming would break existing templates + +``` +workspace/ +├── CLAUDE.md # ← Both runtimes read this +├── .mcp.json # ← Claude Code only +└── ... +``` + +**In your CLAUDE.md**, you can write instructions that work for both: +```markdown +# Agent Instructions + +You are a helpful agent. [Instructions work for both Claude and Gemini] + +## Tools Available +- filesystem operations +- web search +- etc. +``` + +## MCP Configuration + +**Claude Code:** Uses `.mcp.json` file +```json +{ + "mcpServers": { + "trinity": { + "url": "http://mcp-server:8080/mcp", + "headers": {"Authorization": "Bearer KEY"} + } + } +} +``` + +**Gemini CLI:** Uses CLI commands (Trinity handles this automatically) +```bash +gemini mcp add trinity http://mcp-server:8080/mcp +``` + +Trinity translates MCP configuration to each runtime's format automatically. + +## Switching Runtimes + +You can run both Claude and Gemini agents simultaneously: + +```yaml +# Multi-runtime system +agents: + orchestrator: + runtime: claude-code # Complex reasoning + model: sonnet-4.5 + resources: {memory: "4g"} + + worker-1: + runtime: gemini-cli # Data processing + model: gemini-2.5-pro + resources: {memory: "2g"} + + worker-2: + runtime: gemini-cli # Monitoring + model: gemini-2.5-pro + resources: {memory: "2g"} +``` + +**Cost:** $2-3/day for orchestrator, $0 for workers + +## Troubleshooting + +### "Gemini CLI is not available" +- Rebuild base image: `./scripts/deploy/build-base-image.sh` +- Gemini CLI is installed during image build + +### "GOOGLE_API_KEY not configured" +- Add to `.env`: `GOOGLE_API_KEY=your-key` +- Restart agent container + +### MCP Tools Not Working +- Check `gemini mcp list` inside container +- Verify Trinity MCP server is accessible +- Check agent permissions + +## Limitations + +**Gemini Free Tier Limits:** +- 60 requests/minute +- 1,000 requests/day +- If exceeded, agent will fail with rate limit error + +**Workaround:** Mix Claude and Gemini agents to stay within limits. + +## Next Steps + +1. **Test:** Create a test agent with `local:test-gemini` template +2. **Compare:** Run same task on Claude and Gemini agents +3. **Optimize:** Move simple tasks to Gemini, keep complex ones on Claude +4. **Monitor:** Track costs via `/api/observability/metrics` + diff --git a/docs/MULTI_AGENT_SYSTEM_GUIDE.md b/docs/MULTI_AGENT_SYSTEM_GUIDE.md index 234821f15..496e88a09 100644 --- a/docs/MULTI_AGENT_SYSTEM_GUIDE.md +++ b/docs/MULTI_AGENT_SYSTEM_GUIDE.md @@ -1835,6 +1835,83 @@ test_mode: true 3. **Audit Inter-Agent Calls**: Trinity logs all MCP communications 4. **Review Shared Data**: Don't put secrets in shared folders +### Delegation Best Practices + +Trinity supports **two types of delegation** that serve different purposes: + +#### MCP-Based Delegation (Trinity Platform) +Cross-agent communication via the Trinity MCP server (`chat_with_agent` tool). + +``` +Agent A ──[MCP]──► Trinity MCP Server ──► Agent B + │ + Audit Log +``` + +**Use MCP delegation for:** +- Cross-agent communication (Claude agent ↔ Gemini agent) +- Persistent tasks that need tracking +- Work requiring audit trails and cost tracking +- Specialized agents with their own credentials/tooling +- Long-running tasks that may outlive a conversation + +#### Runtime Sub-Agents (Built-in) +Both Claude Code and Gemini CLI have built-in sub-agent capabilities: + +| Runtime | Built-in Sub-Agent | Use Case | +|---------|-------------------|----------| +| **Gemini CLI** | `codebase_investigator` | Deep codebase analysis, architecture mapping | +| **Claude Code** | Custom agents via `--agents` | User-defined specialized tasks | + +**Use runtime sub-agents for:** +- Quick parallel file operations (read 10 files simultaneously) +- Ephemeral investigation tasks +- Performance optimization (no network round-trips) +- Fast codebase exploration within a single context + +#### Decision Matrix + +``` +Is the task... +├─ Talking to ANOTHER Trinity agent? → MCP Delegation +├─ Needs audit trail/cost tracking? → MCP Delegation +├─ Cross-runtime (Claude ↔ Gemini)? → MCP Delegation +├─ Quick parallel file ops? → Runtime Sub-agent OK +├─ Deep codebase investigation? → Runtime Sub-agent OK +└─ Uncertain? → Default to MCP Delegation +``` + +#### Anti-Patterns to Avoid + +| ❌ Don't | Why | +|----------|-----| +| Define custom agents inside containers that duplicate Trinity agents | Confusing, duplicate costs, no platform visibility | +| Use runtime sub-agents for persistent/important work | No audit trail, lost on container restart | +| Use runtime sub-agents for cross-runtime tasks | Gemini sub-agent can't call Claude agent | + +#### Architecture Overview + +``` +┌─────────────────────────────────────────────────────┐ +│ Trinity Platform │ +│ ┌─────────────┐ MCP ┌─────────────┐ │ +│ │ Claude Agent│◄──────────►│ Gemini Agent│ │ +│ │ ┌───────┐ │ │ ┌────────┐ │ │ +│ │ │custom │ │ │ │codebase│ │ │ +│ │ │agents │ │ │ │invest. │ │ │ +│ │ └───────┘ │ │ └────────┘ │ │ +│ └─────────────┘ └─────────────┘ │ +│ ▲ ▲ │ +│ └──────── Audit Log ───────┘ │ +└─────────────────────────────────────────────────────┘ + +Legend: + ◄────────► = MCP Delegation (audited, cross-runtime) + ┌───────┐ = Runtime Sub-agents (ephemeral, fast) +``` + +**Bottom line**: Use MCP for orchestration and cross-agent work. Use runtime sub-agents for optimization and ephemeral parallelism. Don't reinvent Trinity's delegation inside containers. + --- ## System Definition Template diff --git a/docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md b/docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md index 33304c308..abdd4cfa9 100644 --- a/docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md +++ b/docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md @@ -253,6 +253,12 @@ resources: cpu: "2" # CPU cores (string) memory: "4g" # Memory limit (e.g., "2g", "4g", "8g") +# === RUNTIME CONFIGURATION (Optional) === +# Defaults to Claude Code if not specified +runtime: + type: claude-code # "claude-code" or "gemini-cli" + model: sonnet # Optional model override (e.g., "gemini-2.5-pro") + # === CREDENTIAL SCHEMA === # Trinity uses this to inject secrets credentials: @@ -410,6 +416,50 @@ These are injected by the platform - don't add them to your CLAUDE.md: --- +## Runtime Options + +Trinity supports multiple AI runtimes, allowing you to choose the best provider for each agent's use case. + +### Available Runtimes + +| Runtime | Provider | Context Window | Pricing | Best For | +|---------|----------|----------------|---------|----------| +| `claude-code` | Anthropic | 200K tokens | Pay-per-use | Complex reasoning, code quality | +| `gemini-cli` | Google | 1M tokens | Free tier | Large codebases, data processing | + +### Configuring Runtime in template.yaml + +```yaml +# Option 1: Simple runtime selection +runtime: + type: gemini-cli + +# Option 2: With model override +runtime: + type: gemini-cli + model: gemini-2.5-pro + +# Option 3: Claude with specific model +runtime: + type: claude-code + model: opus # or sonnet, haiku +``` + +### Default Behavior + +If `runtime:` is not specified, agents default to `claude-code` for backward compatibility. + +### Environment Requirements + +| Runtime | Required Environment Variable | +|---------|------------------------------| +| `claude-code` | `ANTHROPIC_API_KEY` | +| `gemini-cli` | `GOOGLE_API_KEY` | + +See [Gemini Support Guide](GEMINI_SUPPORT.md) for detailed setup instructions and cost comparisons. + +--- + ## Credential Management ### Credential Injection Flow diff --git a/docs/VERSIONING_AND_UPGRADES.md b/docs/VERSIONING_AND_UPGRADES.md new file mode 100644 index 000000000..e5e6d9991 --- /dev/null +++ b/docs/VERSIONING_AND_UPGRADES.md @@ -0,0 +1,280 @@ +# Trinity Versioning and Upgrade Guide + +## Versioning Philosophy + +Trinity follows [Semantic Versioning](https://semver.org/) (SemVer): + +``` +MAJOR.MINOR.PATCH (e.g., 1.2.3) +``` + +| Version | When to Increment | Example | +|---------|-------------------|---------| +| **MAJOR** | Breaking changes requiring migration | Database schema changes, API incompatibilities | +| **MINOR** | New features, backward compatible | Gemini runtime support, new MCP tools | +| **PATCH** | Bug fixes, security patches | Fix port allocation bug, UI fixes | + +## Current Version: 0.x (Pre-1.0) + +During the `0.x` phase: +- API may change between minor versions +- Breaking changes documented in changelog +- Recommended: Pin to specific version tags + +**Post-1.0**: Strict semver adherence with deprecation warnings before breaking changes. + +--- + +## Component Versioning + +Trinity consists of multiple components that version together: + +| Component | Location | Versioning Strategy | +|-----------|----------|---------------------| +| **Backend** | `src/backend/` | Single version with platform | +| **Frontend** | `src/frontend/` | Single version with platform | +| **Base Image** | `docker/base-image/` | Single version with platform | +| **Agent Server** | `docker/base-image/agent_server/` | Single version with platform | +| **MCP Server** | `src/mcp-server/` | Single version with platform | + +All components share the same version number for simplicity. + +--- + +## Version Tagging Strategy + +### Git Tags + +```bash +# Release tags +v0.9.0 # Feature release +v0.9.1 # Patch release +v1.0.0 # Major release + +# Pre-release tags +v1.0.0-alpha.1 # Alpha testing +v1.0.0-beta.1 # Beta testing +v1.0.0-rc.1 # Release candidate +``` + +### Docker Image Tags + +```bash +# Production tags +trinity-agent-base:0.9.0 # Specific version (recommended) +trinity-agent-base:0.9 # Latest patch in minor version +trinity-agent-base:latest # Latest release (not for production) + +# Development tags +trinity-agent-base:main # Latest main branch (CI/CD only) +trinity-agent-base:dev # Development builds +``` + +--- + +## Upgrade Categories + +### 1. Non-Breaking Updates (PATCH) + +**Examples**: Bug fixes, documentation updates, UI tweaks + +**Upgrade Process**: +```bash +git pull origin main +docker compose pull +docker compose up -d +``` + +**Downtime**: ~30 seconds (container restart) + +### 2. Feature Updates (MINOR) + +**Examples**: Gemini runtime support, new API endpoints + +**Upgrade Process**: +```bash +# 1. Backup (recommended) +./scripts/deploy/backup.sh + +# 2. Pull changes +git pull origin main + +# 3. Rebuild base image (if changed) +./scripts/deploy/build-base-image.sh + +# 4. Restart services +docker compose down +docker compose up -d + +# 5. Verify +curl http://localhost:8000/health +``` + +**Downtime**: 2-5 minutes + +**Impact on Running Agents**: +- Existing agents continue running (no rebuild needed) +- New features available only after agent recreation +- For Gemini support: Agents must be recreated with `runtime: gemini-cli` + +### 3. Breaking Updates (MAJOR) + +**Examples**: Database schema changes, API breaking changes + +**Upgrade Process**: +```bash +# 1. Stop all agents +curl -X POST http://localhost:8000/api/ops/stop-all + +# 2. Full backup +./scripts/deploy/backup.sh + +# 3. Pull changes +git pull origin main + +# 4. Run migrations (if any) +./scripts/deploy/migrate.sh + +# 5. Rebuild everything +./scripts/deploy/build-base-image.sh +docker compose build + +# 6. Start services +docker compose up -d + +# 7. Recreate agents (if base image changed) +# Use UI or API to recreate agents from templates +``` + +**Downtime**: 10-30 minutes + +--- + +## Gemini Runtime Upgrade (v0.9.0) + +This is a **MINOR** version update. Here's the specific upgrade path: + +### What Changed + +| Component | Change Type | Impact | +|-----------|-------------|--------| +| Base Image | Modified | New agents need rebuild | +| Backend | Modified | Restart required | +| Frontend | No change | N/A | +| Database | No change | No migration needed | +| Config | Optional | Add `GOOGLE_API_KEY` if using Gemini | + +### Upgrade Steps + +```bash +# 1. Pull latest code +git fetch origin +git checkout v0.9.0 # Or: git pull origin main + +# 2. (Optional) Add Google API key for Gemini +echo "GOOGLE_API_KEY=your-key" >> .env + +# 3. Rebuild base image +./scripts/deploy/build-base-image.sh + +# 4. Restart backend +docker compose restart backend + +# 5. Verify +curl http://localhost:8000/health +``` + +### Agent Migration + +**Existing agents**: Continue working unchanged (use Claude Code) + +**To use Gemini on existing agent**: +1. Note agent's template and configuration +2. Delete the agent +3. Recreate with `runtime: gemini-cli` in template + +**New agents**: Can choose runtime at creation time + +### Rollback + +```bash +# If issues occur +git checkout v0.8.0 # Previous version +./scripts/deploy/build-base-image.sh +docker compose restart backend +``` + +--- + +## Recommended Upgrade Practices + +### Pre-Upgrade Checklist + +- [ ] Read changelog for breaking changes +- [ ] Backup database (`data/trinity.db`) +- [ ] Backup Redis (`data/redis/`) +- [ ] Note running agents and their configurations +- [ ] Schedule maintenance window if production + +### Post-Upgrade Verification + +```bash +# 1. Health check +curl http://localhost:8000/health + +# 2. Test agent creation +# Create test agent via UI + +# 3. Test chat +# Send message to test agent + +# 4. Verify logs +docker compose logs backend --tail=50 +``` + +### Rollback Plan + +Always have a rollback plan: + +```bash +# Quick rollback (config/code only) +git checkout +docker compose up -d + +# Full rollback (including data) +./scripts/deploy/restore.sh +``` + +--- + +## Version History + +| Version | Date | Type | Key Changes | +|---------|------|------|-------------| +| 0.9.0 | 2025-12-28 | MINOR | Gemini CLI runtime support | +| 0.8.x | 2025-12-24 | PATCH | Test suite fixes, bug fixes | +| 0.8.0 | 2025-12-23 | MINOR | First-time setup wizard, API keys management | + +See [changelog.md](memory/changelog.md) for detailed history. + +--- + +## Future: Automated Upgrades + +Planned for v1.0+: + +1. **Version Check Endpoint**: `/api/version` returns current and latest available +2. **Upgrade Notifications**: UI banner when new version available +3. **One-Click Upgrades**: For non-breaking updates +4. **Migration Scripts**: Automatic database migrations +5. **Agent Auto-Rebuild**: Option to auto-rebuild agents on base image change + +--- + +## Questions? + +If you encounter upgrade issues: +1. Check [Known Issues](KNOWN_ISSUES.md) +2. Review [Troubleshooting](onboarding/04-troubleshooting.md) +3. Open an issue on GitHub + diff --git a/docs/backlog/001-claude-context-window-display-bug.md b/docs/backlog/001-claude-context-window-display-bug.md new file mode 100644 index 000000000..9bc0acce4 --- /dev/null +++ b/docs/backlog/001-claude-context-window-display-bug.md @@ -0,0 +1,227 @@ +# BUG: Claude Agent Context Window Display Shows Incorrect Values + +**Priority:** High +**Type:** Bug Fix +**Component:** Agent Server / Claude Code Runtime +**Created:** 2025-12-28 +**Status:** Open + +--- + +## Summary + +The context window usage displayed in the UI for Claude Code agents is **significantly understated** (showing ~0.4% when actual usage is ~10-15%). This gives users a false sense of available context and can lead to unexpected context exhaustion. + +--- + +## Problem Description + +### What Users See + +| Agent Type | Displayed Context | Actual Context (estimated) | Error | +|------------|-------------------|---------------------------|-------| +| Claude Code | 730 / 200K (0.4%) | ~15-20K / 200K (~10%) | **~20-30x understated** | +| Gemini CLI | 21K / 1M (2.1%) | 21K / 1M (2.1%) | Accurate ✓ | + +### Evidence + +From testing session on 2025-12-28: + +**Claude agent (test-claude):** +- UI shows: 730 tokens for 6 messages +- Session cost: $0.1111 +- If only 730 tokens were used, cost would be ~$0.002 + +**Gemini agent (test):** +- UI shows: 21K tokens for 2 messages +- Session cost: $0.0126 +- Cost aligns with reported token usage ✓ + +The **cost proves** Claude is using much more than 730 tokens - the displayed number is just incremental conversation tokens, not full context. + +--- + +## Root Cause Analysis + +### Claude Code CLI Output + +Claude Code's `stream-json` output provides: + +```json +{ + "type": "result", + "usage": { + "input_tokens": 730, // ← Incremental tokens THIS TURN only + "output_tokens": 150, + "cache_creation_input_tokens": 0, + "cache_read_input_tokens": 0 + }, + "modelUsage": { + "claude-sonnet-4-20250514": { + "inputTokens": 730, // ← Sometimes cumulative, inconsistent + "outputTokens": 150, + "contextWindow": 200000 + } + }, + "total_cost_usd": 0.044 +} +``` + +**The issue:** `usage.input_tokens` reports only the NEW tokens added in this turn, NOT the full context sent to the API. + +### Gemini CLI Output + +```json +{ + "type": "result", + "stats": { + "input_tokens": 10485, // ← Full context including system/tools + "output_tokens": 8, + "cached": 9833, + "total_tokens": 10516 + } +} +``` + +**Gemini correctly reports** the full context window usage. + +--- + +## Files to Investigate/Modify + +### Primary File +- `docker/base-image/agent_server/services/claude_code.py` + - Lines 141-159: Token extraction from `result` message + - The `input_tokens` value is used directly without adjustment + +### Related Files +- `docker/base-image/agent_server/state.py` - Stores `session_context_tokens` +- `docker/base-image/agent_server/routers/chat.py` - Uses metadata for response +- `src/frontend/src/views/AgentDetail.vue` - Displays context bar + +--- + +## Proposed Solutions + +### Option A: Estimate from Cost (Recommended) + +Back-calculate actual tokens from the reported cost: + +```python +# Claude Sonnet pricing (approximate) +INPUT_COST_PER_TOKEN = 3.0 / 1_000_000 # $3 per 1M tokens +OUTPUT_COST_PER_TOKEN = 15.0 / 1_000_000 # $15 per 1M tokens + +def estimate_input_tokens_from_cost(total_cost, output_tokens): + output_cost = output_tokens * OUTPUT_COST_PER_TOKEN + input_cost = total_cost - output_cost + return int(input_cost / INPUT_COST_PER_TOKEN) +``` + +**Pros:** Accurate reflection of API usage +**Cons:** Requires pricing lookup, may drift if pricing changes + +### Option B: Track Cumulative Tokens + +Sum all `input_tokens` across the session to approximate context growth: + +```python +# In agent_state +session_cumulative_input_tokens = 0 + +# After each message +session_cumulative_input_tokens += metadata.input_tokens +``` + +**Pros:** Simple implementation +**Cons:** Still won't capture system prompt/tool definitions (~10K tokens) + +### Option C: Add Base Context Constant + +Add a known base context amount for Claude Code: + +```python +CLAUDE_BASE_CONTEXT = 12000 # System prompt + tool definitions + +actual_context = CLAUDE_BASE_CONTEXT + reported_input_tokens +``` + +**Pros:** Simple +**Cons:** Base context may vary by configuration + +### Option D: Hybrid Approach (Best) + +Combine cost estimation with cumulative tracking: + +```python +def get_actual_context_tokens(metadata, session_state): + # If we have cost data, estimate from that (most accurate) + if metadata.cost_usd and metadata.output_tokens: + return estimate_input_tokens_from_cost( + metadata.cost_usd, + metadata.output_tokens + ) + + # Fallback to cumulative + base estimate + return CLAUDE_BASE_CONTEXT + session_state.cumulative_input_tokens +``` + +--- + +## Acceptance Criteria + +- [ ] Claude agent context window percentage reflects actual API context usage +- [ ] Context bar in UI shows meaningful progress toward 200K limit +- [ ] Cost and context usage are consistent (higher context = higher cost) +- [ ] Users can trust the context % to know when they're approaching limits +- [ ] No regression in Gemini context reporting (already accurate) + +--- + +## Testing Plan + +1. Create a fresh Claude agent +2. Send "hi" message +3. Verify context shows ~10-15K (not 100-200 tokens) +4. Send 10 more messages +5. Verify context grows appropriately +6. Compare context growth with cost growth (should correlate) +7. Verify Gemini still reports correctly + +--- + +## Related Context + +### Session Data Endpoint +``` +GET /api/chat/session +``` +Returns: +```json +{ + "context_tokens": 730, // ← This is wrong for Claude + "context_window": 200000, + "context_percent": 0.4 // ← Derived from above, also wrong +} +``` + +### How Gemini Gets It Right + +In `gemini_runtime.py`, the `stats.input_tokens` field is used directly: +```python +stats = msg.get("stats", {}) +if stats: + metadata.input_tokens = stats.get("input_tokens", 0) +``` + +Gemini CLI reports full context, so this works correctly. + +--- + +## References + +- Claude Code CLI: https://github.com/anthropics/claude-code +- Anthropic API pricing: https://www.anthropic.com/pricing +- Related file: `docker/base-image/agent_server/services/claude_code.py` +- Related file: `docker/base-image/agent_server/services/gemini_runtime.py` (for comparison) + diff --git a/docs/backlog/002-unified-context-reporting.md b/docs/backlog/002-unified-context-reporting.md new file mode 100644 index 000000000..c3493de13 --- /dev/null +++ b/docs/backlog/002-unified-context-reporting.md @@ -0,0 +1,186 @@ +# IMPROVEMENT: Unified Context Reporting Across Runtimes + +**Priority:** Medium +**Type:** Enhancement +**Component:** Agent Server / Runtime Adapter +**Created:** 2025-12-28 +**Status:** Open +**Depends On:** #001 (Claude Context Window Display Bug) + +--- + +## Summary + +Create a unified context reporting interface that provides consistent, accurate context window information regardless of the underlying runtime (Claude Code, Gemini CLI, or future runtimes). + +--- + +## Current State + +Each runtime reports context differently: + +| Runtime | Field Used | What It Reports | Accuracy | +|---------|------------|-----------------|----------| +| Claude Code | `usage.input_tokens` | Incremental turn tokens | ❌ Misleading | +| Gemini CLI | `stats.input_tokens` | Full context | ✅ Accurate | + +This inconsistency means: +- Users can't compare context usage between agents +- The context bar means different things for different agents +- Future runtimes will need ad-hoc handling + +--- + +## Proposed Design + +### New Interface in Runtime Adapter + +Add to `docker/base-image/agent_server/services/runtime_adapter.py`: + +```python +class AgentRuntime(ABC): + # ... existing methods ... + + @abstractmethod + def get_context_metrics(self, metadata: ExecutionMetadata) -> ContextMetrics: + """ + Get standardized context metrics for this runtime. + + Returns: + ContextMetrics with: + - total_context_tokens: Full context sent to API + - conversation_tokens: Just the conversation portion + - system_tokens: System prompt + tool definitions + - cached_tokens: Tokens served from cache (if applicable) + - context_window: Maximum context for this model + - utilization_percent: Accurate % of window used + """ + pass +``` + +### New Data Model + +```python +@dataclass +class ContextMetrics: + total_context_tokens: int # Full context (what matters for limits) + conversation_tokens: int # User + assistant messages only + system_tokens: int # System prompt + tools + cached_tokens: int # Tokens that were cached + context_window: int # Model's max context + utilization_percent: float # total / window * 100 + + # Optional breakdown + tool_definition_tokens: int = 0 + instruction_file_tokens: int = 0 +``` + +### Implementation Per Runtime + +**Claude Code:** +```python +def get_context_metrics(self, metadata: ExecutionMetadata) -> ContextMetrics: + # Estimate total from cost if available + if metadata.cost_usd: + total = estimate_from_cost(metadata.cost_usd, metadata.output_tokens) + else: + # Fallback: assume base + incremental + total = CLAUDE_BASE_CONTEXT + metadata.input_tokens + + return ContextMetrics( + total_context_tokens=total, + conversation_tokens=metadata.input_tokens, + system_tokens=total - metadata.input_tokens, + cached_tokens=metadata.cache_read_tokens, + context_window=metadata.context_window, + utilization_percent=(total / metadata.context_window) * 100 + ) +``` + +**Gemini CLI:** +```python +def get_context_metrics(self, metadata: ExecutionMetadata) -> ContextMetrics: + # Gemini reports accurately, use directly + return ContextMetrics( + total_context_tokens=metadata.input_tokens, + conversation_tokens=metadata.input_tokens - GEMINI_BASE_CONTEXT, + system_tokens=GEMINI_BASE_CONTEXT, + cached_tokens=metadata.cached_tokens or 0, + context_window=metadata.context_window, + utilization_percent=(metadata.input_tokens / metadata.context_window) * 100 + ) +``` + +--- + +## Files to Modify + +1. **`docker/base-image/agent_server/services/runtime_adapter.py`** + - Add `get_context_metrics()` abstract method + - Add `ContextMetrics` dataclass + +2. **`docker/base-image/agent_server/services/claude_code.py`** + - Implement `get_context_metrics()` with cost-based estimation + +3. **`docker/base-image/agent_server/services/gemini_runtime.py`** + - Implement `get_context_metrics()` using direct values + +4. **`docker/base-image/agent_server/routers/chat.py`** + - Use new `get_context_metrics()` for responses + +5. **`docker/base-image/agent_server/models.py`** + - Add `ContextMetrics` model + +6. **`src/frontend/src/views/AgentDetail.vue`** + - Update to display additional context breakdown (optional) + +--- + +## API Changes + +### Updated Session Endpoint Response + +```json +{ + "session_started": true, + "message_count": 6, + "total_cost_usd": 0.1111, + "context": { + "total_tokens": 18500, + "conversation_tokens": 730, + "system_tokens": 17770, + "cached_tokens": 15000, + "context_window": 200000, + "utilization_percent": 9.25 + }, + "model": "claude-sonnet-4-20250514" +} +``` + +--- + +## Benefits + +1. **Consistent UX** - Context bar means the same thing for all agents +2. **Accurate planning** - Users know when they're approaching limits +3. **Better debugging** - See where context is being consumed +4. **Future-proof** - New runtimes just implement the interface + +--- + +## Acceptance Criteria + +- [ ] `ContextMetrics` provides consistent data across runtimes +- [ ] UI context bar reflects `total_context_tokens` (not incremental) +- [ ] Session endpoint returns detailed context breakdown +- [ ] Existing functionality unchanged (backward compatible) +- [ ] Documentation updated + +--- + +## Out of Scope + +- Automatic context management/pruning (separate feature) +- Context optimization suggestions (separate feature) +- Historical context tracking (separate feature) + diff --git a/docs/backlog/README.md b/docs/backlog/README.md new file mode 100644 index 000000000..348dfaf82 --- /dev/null +++ b/docs/backlog/README.md @@ -0,0 +1,60 @@ +# Trinity Backlog + +This folder contains documented backlog items for future development. Each item is designed to be picked up by an AI agent or human developer with full context. + +--- + +## Backlog Item Format + +Each item follows this structure: + +- **Summary** - One-line description +- **Problem Description** - What's wrong or what's needed +- **Root Cause Analysis** - Technical investigation findings +- **Files to Modify** - Specific code locations +- **Proposed Solutions** - Implementation options with pros/cons +- **Acceptance Criteria** - Definition of done +- **Testing Plan** - How to verify the fix + +--- + +## Current Backlog Items + +| ID | Title | Priority | Type | Status | +|----|-------|----------|------|--------| +| 001 | [Claude Context Window Display Bug](./001-claude-context-window-display-bug.md) | High | Bug | Open | +| 002 | [Unified Context Reporting](./002-unified-context-reporting.md) | Medium | Enhancement | Open | + +--- + +## Priority Levels + +- **Critical** - Blocks core functionality, needs immediate attention +- **High** - Significant user impact, should be addressed soon +- **Medium** - Important improvement, can wait for appropriate sprint +- **Low** - Nice to have, address when time permits + +--- + +## For AI Agents + +When picking up a backlog item: + +1. **Read the full document** - All context is provided +2. **Check dependencies** - Some items depend on others +3. **Follow the testing plan** - Verify your fix works +4. **Update status** - Mark as "In Progress" or "Done" +5. **Document changes** - Add notes about implementation decisions + +--- + +## Adding New Items + +Use the next available ID (e.g., `003-feature-name.md`) and follow the existing format. Include: + +- All investigation findings +- Specific file paths and line numbers +- Code snippets showing current behavior +- Proposed code changes +- Clear acceptance criteria + diff --git a/docs/memory/changelog.md b/docs/memory/changelog.md index bc4afa566..1162b2acb 100644 --- a/docs/memory/changelog.md +++ b/docs/memory/changelog.md @@ -25,6 +25,24 @@ --- +### 2025-12-28 18:30:00 +📚 **Documentation - Delegation Best Practices** + +Added comprehensive delegation best practices to the Multi-Agent System Guide, covering the hybrid delegation strategy for Trinity. + +**New Documentation** (`docs/MULTI_AGENT_SYSTEM_GUIDE.md`): +- **MCP vs Runtime Sub-Agents**: When to use each delegation type +- **Decision Matrix**: Clear guidance for choosing delegation method +- **Anti-Patterns**: Common mistakes to avoid +- **Architecture Diagram**: Visual overview of delegation layers + +**Key Concepts Documented**: +- MCP delegation for cross-agent, audited, persistent work +- Runtime sub-agents (Gemini's `codebase_investigator`, Claude's `--agents`) for ephemeral parallelism +- Don't reinvent Trinity's orchestration inside containers + +--- + ### 2025-12-28 18:15:00 🐛 **Fixed Credential Hot-Reload Not Saving to Redis** @@ -84,6 +102,46 @@ The conflict resolution handles duplicates intelligently: --- +### 2025-12-28 15:00:00 +🚀 **Multi-Runtime Support - Gemini CLI Integration** + +Added support for Google's Gemini CLI as an alternative agent runtime, enabling cost optimization and 1M token context windows. + +**New Features**: +- **Runtime Adapter Pattern**: Abstract interface for swapping execution engines +- **Gemini CLI Support**: Full integration with Google's free-tier AI +- **Per-Agent Runtime Selection**: Choose Claude Code or Gemini CLI per agent +- **Template Configuration**: New `runtime:` field in template.yaml + +**Key Benefits**: +- **Cost Savings**: Gemini free tier (60 req/min, 1K/day) +- **5x Context Window**: 1M tokens vs 200K for Claude +- **Provider Flexibility**: Mix runtimes based on task complexity + +**Files Added**: +- `docker/base-image/agent_server/services/runtime_adapter.py` - Abstract interface +- `docker/base-image/agent_server/services/gemini_runtime.py` - Gemini implementation +- `config/agent-templates/test-gemini/` - Test template +- `docs/GEMINI_SUPPORT.md` - User guide + +**Files Modified**: +- `docker/base-image/Dockerfile` - Added Gemini CLI installation +- `docker/base-image/agent_server/services/claude_code.py` - Wrapped in ClaudeCodeRuntime +- `docker/base-image/agent_server/state.py` - Runtime-aware availability checks +- `docker/base-image/agent_server/routers/chat.py` - Uses runtime adapter +- `src/backend/models.py` - Added runtime fields to AgentConfig +- `src/backend/routers/agents.py` - Runtime env var injection +- `docker-compose.yml` - GOOGLE_API_KEY support + +**Documentation Updated**: +- `README.md` - Multi-runtime feature mention +- `docs/DEPLOYMENT.md` - GOOGLE_API_KEY instructions +- `docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md` - Runtime Options section + +**Backward Compatibility**: ✅ All existing agents continue using Claude Code by default. + +--- + ### 2025-12-28 12:28:00 ⚡ **Fixed Terminal Thread Pool Exhaustion (v2)** @@ -903,1792 +961,3 @@ Fixed fundamental architecture issue where MCP tool tried to access local filesy - `docs/memory/feature-flows/local-agent-deploy.md` - Updated architecture and usage docs **Backend API Unchanged**: `POST /api/agents/deploy-local` still accepts same parameters. - ---- - -### 2025-12-24 10:15:00 -🐛 **Test Suite Fixes - 11 Failures Resolved** - -Fixed 11 failing tests in `test_deploy_local.py` and `test_settings.py`. - -**Issue 1: Deploy-Local Filesystem (6 tests)** -- **Root Cause**: `/agent-configs/templates/` was mounted read-only in docker-compose.yml -- **Fix**: Changed `routers/agents.py` to detect read-only mounts using write test instead of `.exists()` check -- **Files**: `src/backend/routers/agents.py` (lines 1014-1030) - -**Issue 2: API Keys Settings Route (2 tests)** -- **Root Cause**: `GET /api/settings/api-keys` was matched by `/{key}` catch-all route (wrong order) -- **Fix**: Moved API keys routes before the `/{key}` catch-all in `routers/settings.py` -- **Files**: `src/backend/routers/settings.py` (route reordering) - -**Issue 3: Test Assertions (4 tests)** -- **Root Cause**: Tests assumed `detail` is string, but backend returns dict `{error, code}` -- **Fix**: Updated assertions to handle both string and dict responses -- **Files**: `tests/test_deploy_local.py` (lines 110, 131, 373, 408) - -**Issue 4: Versioning Test Field** -- **Root Cause**: Test checked non-existent `version_number` field -- **Fix**: Changed to check correct fields: `new_version`, `base_name` -- **Files**: `tests/test_deploy_local.py` (line 343) - -**Test Results**: -- `test_deploy_local.py`: 14/14 passed (was 5/14) -- `test_settings.py`: 35/35 passed (was 33/35) - ---- - -### 2025-12-23 21:35:00 -🐛 **Fleet Operations Schedule Resume Bug Fixed** - -Fixed 500 Internal Server Error in `POST /api/ops/schedules/resume` endpoint. - -**Root Cause**: Two bugs in `routers/ops.py:559`: -1. `agent.get("name")` → `agent.name` - `list_all_agents()` returns `AgentStatus` Pydantic models, not dicts -2. `db.list_schedules()` → `db.list_agent_schedules()` - Incorrect method name - -**Impact**: Fleet operations schedule resume now works correctly. - -**Files Changed**: -- `src/backend/routers/ops.py` - Fixed `resume_all_schedules()` fallback logic - -**Testing**: -- `test_ops.py::TestScheduleControl::test_resume_schedules_returns_count` - PASSED - ---- - -### 2025-12-23 16:00:00 -📚 **Feature Flow Documentation Updated** - -Updated all outdated feature flows after recent platform changes. - -**Workplan/Task DAG Removal** (Req 9.8 - system deleted): -- `testing-agents.md` - Removed reference to deleted `agent_server/routers/plans.py` -- `agent-custom-metrics.md` - Removed test-worker metrics referencing plans -- `agent-network.md` - Updated header stats (removed plans), updated revision history -- `internal-system-agent.md` - Changed "archive old plans" to "clear stale context" -- `activity-stream-collaboration-tracking.md` - Updated context polling description - -**OWASP Security Documentation**: -- `auth0-authentication.md` - Added Security Hardening section documenting bcrypt password hashing and SECRET_KEY handling - -**New Feature Flows Verified**: -- `first-time-setup.md` - Status updated to Working (was Not Tested) -- `public-agent-links.md` - Complete flow documented -- `parallel-headless-execution.md` - Complete flow documented - -**Index Updated**: -- `feature-flows.md` - Added 2025-12-23 update note summarizing all changes - ---- - -### 2025-12-23 14:30:00 -🔒 **OWASP Security Hardening - Critical & High Issues Fixed** - -Addressed 7 of 14 security issues from OWASP Top 10:2025 compliance audit. - -**Critical Fixes (A02, A04)**: -- `config.py` - SECRET_KEY now auto-generates if not set, warns on default value -- `docker-compose.yml` - Removed default SECRET_KEY and ADMIN_PASSWORD values -- `database.py` - Admin password now hashed with bcrypt; auto-migrates plaintext passwords - -**High Priority Fixes (A02, A10)**: -- `docker-compose.yml` - DEV_MODE_ENABLED now defaults to `false` -- `docker-compose.yml` - Redis supports optional password via REDIS_PASSWORD env var -- `config.py` - REDIS_URL construction supports password authentication -- `routers/auth.py`, `routers/agents.py`, `routers/chat.py` - Removed `str(e)` from HTTP responses (prevents internal error exposure) -- `main.py` - Audit logs endpoint sanitized error responses - -**Medium Priority Fixes (A01, A02)**: -- `main.py` - WebSocket endpoint now accepts JWT token via query param or first message -- `main.py` - CORS methods/headers restricted in production mode (when DEV_MODE_ENABLED=false) - -**New Files**: -- `utils/errors.py` - Centralized error handling utilities with logging and safe messages - -**Configuration Updates**: -- `.env.example` - Added REDIS_PASSWORD, security documentation, removed default SECRET_KEY - -**Remaining Work**: -- ~40 `str(e)` occurrences in less critical endpoints (medium-term) -- Security alerting, account lockout, MFA (long-term) - -See `docs/security/OWASP_COMPLIANCE_REPORT.md` for full audit and remediation status. - ---- - -### 2025-12-23 12:16:00 -📦 **Dependencies Updated to Latest Versions** - -Audited and updated all project dependencies to their latest stable versions. - -**Backend (docker/backend/Dockerfile)**: -- fastapi: 0.104.1 → 0.115.6 -- uvicorn: 0.24.0 → 0.34.0 -- pydantic: 2.5.0 → 2.10.4 -- python-multipart: 0.0.6 → 0.0.20 -- websockets: 12.0 → 14.1 -- redis: 5.0.1 → 5.2.1 -- httpx: 0.25.2 → 0.28.1 -- pyyaml: 6.0.1 → 6.0.2 -- docker: 7.0.0 → 7.1.0 -- aiofiles: 23.2.1 → 24.1.0 -- apscheduler: 3.10.4 → 3.11.0 -- croniter: 2.0.1 → 5.0.1 -- pytz: 2024.1 → 2024.2 -- Added bcrypt==4.2.1 pin (for passlib compatibility) -- Removed deprecated urllib3/requests version constraints - -**Base Image (docker/base-image/Dockerfile)**: -- Go: 1.21.5 → 1.23.4 - -**Frontend (src/frontend/package.json)**: -- vue: 3.3.8 → 3.5.13 -- vite: 5.0.2 → 6.0.6 -- pinia: 2.1.7 → 2.3.0 -- axios: 1.6.2 → 1.7.9 -- chart.js: 4.4.0 → 4.4.7 -- vue-router: 4.2.5 → 4.5.0 -- tailwindcss: 3.3.5 → 3.4.17 -- @vitejs/plugin-vue: 4.5.0 → 5.2.1 -- postcss: 8.4.31 → 8.4.49 -- autoprefixer: 10.4.16 → 10.4.20 - -**MCP Server (src/mcp-server/package.json)**: -- fastmcp: 3.23.1 → 3.24.0 -- zod: 3.23.8 → 3.24.1 - -**Root (package.json)**: -- @modelcontextprotocol/sdk: 1.21.1 → 1.25.1 - -**Tests (tests/requirements-test.txt)**: -- pytest: 8.0.0 → 8.3.0 -- pytest-asyncio: 0.23.0 → 0.24.0 -- pytest-cov: 4.1.0 → 6.0.0 -- httpx: 0.27.0 → 0.28.0 - -**Security Note**: passlib remains at 1.7.4 (unmaintained but no replacement). bcrypt pinned to 4.2.1 for compatibility (5.0.0 breaks passlib). - ---- - -### 2025-12-23 12:00:00 -🔑 **MCP Keys First-Time Setup UX Improvements** - -Improved the MCP API Keys page for better first-time user experience. When a user first visits the MCP Keys page without any user-scoped keys, a default key is automatically created and displayed with the full MCP configuration ready to copy. - -**Backend Changes**: -- `routers/mcp_keys.py` - Added `POST /api/mcp/keys/ensure-default` endpoint that auto-creates a default MCP key for first-time users - -**Frontend Changes**: -- `ApiKeys.vue` - Auto-calls ensure-default on page load, shows modal with full MCP config when key created -- Key created modal now shows ready-to-copy MCP JSON configuration with the key embedded -- Added "Copy Config" button for one-click MCP config copying -- Agent-scoped keys filtered from non-admin users (system/agent keys are internal) -- Added scope badges (Agent/System) for admin visibility - -**First-Time UX Flow**: -1. User logs in → navigates to MCP Keys -2. System auto-creates "Default MCP Key" -3. Modal displays with full `.mcp.json` configuration including the key -4. User clicks "Copy Config" → pastes into their MCP client -5. Done! - ---- - -### 2025-12-23 11:00:00 -❌ **Workplan System Removed (9.8) - Complete Cleanup** - -Removed the individual agent-level Workplan/Task DAG system. Task management at the agent level is handled by Claude Code itself. System-level task management will be implemented via orchestrator agents in future phases. - -**Code Removed**: -- `WorkplanPanel.vue` component and "Workplan" tab from AgentDetail -- Task progress display from AgentNode.vue and Dashboard.vue -- Plan API endpoints from backend (`/api/agents/{name}/plans/*`, `/api/agents/plans/aggregate`) -- Plan router from agent-server (`routers/plans.py`) -- Task DAG models from agent-server (`models.py`) -- Workplan command files from `config/trinity-meta-prompt/commands/` -- Plan-related state and actions from stores (agents.js, network.js) -- planStats helper functions from Agents.vue -- Test files: `tests/test_agent_plans.py`, `tests/agent_server/test_agent_plans_direct.py` - -**Templates/Configs Removed**: -- `config/agent-templates/test-worker/` - Workplan test agent template -- `.claude/commands/demo-agent-fleet.md` - Demo command (heavily workplan-focused) - -**Testing Docs Removed**: -- `docs/testing/phases/PHASE_06_WORKPLAN_SYSTEM.md` -- `docs/memory/TERMINOLOGY_CLARITY_REFACTOR.md` (obsolete) - -**Pillar Update**: Four Pillars of Deep Agency updated: -1. Hierarchical Delegation → (was: Explicit Planning) -2. Persistent Memory -3. Extreme Context Engineering -4. Autonomous Operations → (new) - -**Documentation Updated**: -- `README.md` and `CLAUDE.md` - Updated Four Pillars, removed Workplan feature -- `requirements.md` - 9.8 marked as REMOVED -- `feature-flows.md` - Removed workplan flow entries -- Feature flow docs - Removed workplan references from 7 files -- Testing docs - Updated INDEX.md, README.md, phase files to remove Phase 6 - ---- - -### 2025-12-23 09:30:00 -🔐 **First-Time Setup - Feature Implemented (12.3)** - -Implemented first-time setup wizard for admin password and API key configuration. On fresh install, users are redirected to `/setup` to set an admin password before accessing the platform. - -**New Features**: -- Setup wizard for initial admin password -- Bcrypt password hashing for security -- Login blocked until setup complete -- API Keys management in Settings page -- Anthropic API key test button -- Settings-based API key with env var fallback - -**Backend Changes**: -- `dependencies.py` - Added `hash_password()`, updated `verify_password()` for bcrypt -- `db/users.py` - Added `update_user_password()` method -- `database.py` - Added delegation method for password update -- `routers/setup.py` - New router for setup endpoints -- `routers/auth.py` - Added setup status check, login block -- `routers/settings.py` - Added API key management endpoints -- `routers/agents.py` - Uses `get_anthropic_api_key()` helper -- `services/system_agent_service.py` - Uses `get_anthropic_api_key()` helper -- `main.py` - Registered setup router - -**Frontend Changes**: -- `SetupPassword.vue` - New setup wizard view -- `router/index.js` - Added `/setup` route with setup guard -- `Settings.vue` - Added API Keys section with test/save - -**API Endpoints**: -| Endpoint | Method | Auth | Description | -|----------|--------|------|-------------| -| `/api/setup/status` | GET | No | Check setup status | -| `/api/setup/admin-password` | POST | No | Set admin password (once) | -| `/api/settings/api-keys` | GET | Admin | Get API key status | -| `/api/settings/api-keys/anthropic` | PUT | Admin | Save API key | -| `/api/settings/api-keys/anthropic` | DELETE | Admin | Delete API key | -| `/api/settings/api-keys/anthropic/test` | POST | Admin | Test API key | - -**Security**: -- Bcrypt hashing (passlib with bcrypt scheme) -- Setup endpoint only works once (403 after completion) -- Backward compatible with plaintext passwords -- API keys never exposed in full (masked display) - ---- - -### 2025-12-22 22:30:00 -🔗 **Public Agent Links - Feature Implemented (12.2)** - -Implemented shareable public links that allow unauthenticated users to chat with agents. Owners can create links with optional email verification, expiration dates, and usage tracking. - -**New Features**: -- Public links with unique URL-safe tokens -- Optional email verification (6-digit codes, 10-min expiry) -- Session tokens for verified users (24-hour validity) -- Usage statistics (message counts, unique users) -- Link enable/disable and expiration -- Rate limiting (30 messages/minute per IP) - -**Backend Changes**: -- 3 new database tables: `agent_public_links`, `public_link_verifications`, `public_link_usage` -- New router: `routers/public_links.py` - Owner endpoints (CRUD) -- New router: `routers/public.py` - Public endpoints (no auth) -- New service: `services/email_service.py` - Email verification (console/SMTP/SendGrid) -- Database operations: `db/public_links.py` -- Pydantic models in `db_models.py` -- Config additions: `FRONTEND_URL`, email settings - -**Frontend Changes**: -- `PublicChat.vue` - Public chat interface with verification flow -- `PublicLinksPanel.vue` - Owner management panel -- New route: `/chat/:token` (public, no auth required) -- "Public Links" tab in AgentDetail (owner only) - -**API Endpoints**: -| Endpoint | Method | Auth | Description | -|----------|--------|------|-------------| -| `/api/agents/{name}/public-links` | GET | Yes | List links | -| `/api/agents/{name}/public-links` | POST | Yes | Create link | -| `/api/agents/{name}/public-links/{id}` | PUT | Yes | Update link | -| `/api/agents/{name}/public-links/{id}` | DELETE | Yes | Delete link | -| `/api/public/link/{token}` | GET | No | Check link | -| `/api/public/verify/request` | POST | No | Request code | -| `/api/public/verify/confirm` | POST | No | Verify code | -| `/api/public/chat/{token}` | POST | No | Send message | - -**Configuration**: -- `EMAIL_PROVIDER`: console (default), smtp, sendgrid -- `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_FROM` -- `SENDGRID_API_KEY` -- `FRONTEND_URL`: Base URL for public link generation - -**Use Cases**: -- Share agent demo with prospects -- Customer support bots without login -- Public information agents - -**Testing** (17:34 UTC): -- All API endpoints tested and working -- Full link lifecycle verified (create, list, update, enable/disable, delete) -- Email verification flow tested (console mode) -- Public chat requires agents with `/api/task` endpoint (Phase 12.1 base image) -- Test file: `tests/test_public_links.py` - ---- - -### 2025-12-22 20:00:00 -🚀 **Parallel Headless Execution - Feature Implemented (12.1)** - -Implemented stateless parallel task execution enabling orchestrators to spawn N concurrent worker tasks without queue blocking. - -**New Endpoints**: -- `POST /api/task` (agent-server) - Stateless task execution, no lock, no --continue -- `POST /api/agents/{name}/task` (backend) - Proxy endpoint bypassing execution queue - -**MCP Tool Updated**: -- `chat_with_agent` now supports `parallel: boolean` parameter -- `parallel=false` (default): Sequential chat mode with execution queue -- `parallel=true`: Stateless parallel task mode, N concurrent allowed - -**Key Implementation Details**: -- `execute_headless_task()` function runs Claude Code without --continue flag -- No execution lock acquired (parallel allowed) -- Each task gets unique session_id -- Supports model override, allowed_tools, system_prompt, timeout_seconds -- Activity tracking with parallel_mode flag -- Audit logging for parallel tasks - -**Modified Files**: -- `docker/base-image/agent_server/models.py` - Added ParallelTaskRequest, ParallelTaskResponse -- `docker/base-image/agent_server/services/claude_code.py` - Added execute_headless_task() -- `docker/base-image/agent_server/routers/chat.py` - Added POST /api/task endpoint -- `src/backend/models.py` - Added ParallelTaskRequest -- `src/backend/routers/chat.py` - Added POST /api/agents/{name}/task endpoint -- `src/mcp-server/src/client.ts` - Added task() method -- `src/mcp-server/src/tools/chat.ts` - Updated chat_with_agent with parallel parameter -- `tests/test_parallel_task.py` - New test file with 12 tests - -**Use Cases**: -- Orchestrator spawns N parallel worker tasks -- Batch processing without context pollution -- Agent-to-agent delegation at scale - -**Feature Flow Doc**: `docs/memory/feature-flows/parallel-headless-execution.md` - ---- - -### 2025-12-22 18:30:00 -📋 **Parallel Headless Execution - Requirements Document Created (12.1)** - -Created comprehensive requirements document for parallel task execution feature based on Claude Code documentation research. - -**Research Findings**: -- Claude Code headless mode (`claude -p`) runs stateless, independent sessions -- No `--continue` flag = no conversation memory = can run in parallel -- Can spawn N instances concurrently -- Output format: `--output-format stream-json` for structured results - -**Proposed Architecture**: -- **Sequential Chat** (existing): `POST /api/agents/{name}/chat` - uses `--continue`, execution queue, maintains context -- **Parallel Task** (new): `POST /api/agents/{name}/task` - stateless, no queue, N concurrent allowed - -**Key Requirements**: -1. Agent-server: New `/api/task` endpoint (no lock, no --continue) -2. Backend: New `/api/agents/{name}/task` endpoint (bypasses execution queue) -3. MCP: Update `chat_with_agent` with `parallel: boolean` parameter -4. Concurrency limits: Agent-level (default 5), platform-level (default 50) -5. Activity tracking: New `parallel_task` activity type - -**Use Cases**: -- Orchestrator spawns N parallel worker tasks -- Batch processing without context pollution -- Agent-to-agent delegation at scale - -**Design Doc**: `docs/drafts/PARALLEL_HEADLESS_EXECUTION.md` - ---- - -### 2025-12-22 15:30:00 -🐛 **Fixed Template Detail Endpoint for GitHub Templates** - -Fixed `GET /api/templates/{id}` returning 404 for GitHub templates like `github:abilityai/agent-ruby`. - -**Root Cause**: The `/` in GitHub template IDs (e.g., `github:org/repo`) was interpreted as a URL path separator by FastAPI, causing the route to not match at all. - -**Fix**: Changed route from `{template_id}` to `{template_id:path}` to capture the full path including slashes. - -**Verified**: `.env Template Endpoint` already works correctly - code at lines 110-130 handles both string credentials (GitHub templates) and dict credentials (local templates). - -**Modified Files**: -- `src/backend/routers/templates.py` - Changed route to use `{template_id:path}` (~5 lines) - ---- - -### 2025-12-22 04:55:00 -🐛 **Fixed Port Allocation Race Condition** - -Fixed agent creation failing with "port already allocated" when a port was in use by another process on the host system. - -**Root Cause**: `get_next_available_port()` only checked Trinity container labels, not actual host port availability. - -**Fix**: Added `is_port_available()` that tests actual TCP socket binding before assigning a port. - -**Modified Files**: -- `src/backend/services/docker_service.py` - Added is_port_available(), enhanced get_next_available_port() (~25 lines) - ---- - -### 2025-12-21 16:30:00 -🚀 **Local Agent Deployment via MCP (New Feature)** - -Implemented the ability to deploy Trinity-compatible local agents to Trinity platform with a single MCP command. This enables zero-setup deployment from local development to remote platform. - -**New MCP Tool**: `deploy_local_agent` -- Packages local agent directory as tar.gz -- Auto-imports credentials from `.env` with conflict resolution -- Versioned deployment (my-agent → my-agent-2 on repeat deploy) -- Validates Trinity-compatible structure (template.yaml required) - -**Backend Endpoint**: `POST /api/agents/deploy-local` -- Accepts base64-encoded archive + credentials -- Validates template.yaml with `name` and `resources` fields -- Size limits: 50MB archive, 100 credentials, 1000 files -- Security: Path traversal protection, temp cleanup - -**Credential Import with Conflict Resolution**: -- Same name + same value = reuse existing -- Same name + different value = create with suffix (_2, _3) -- New name = create new credential - -**Versioning Logic**: -- `get_next_version_name()` finds next available version -- Previous version is stopped (not deleted) -- Pattern: base-name → base-name-2 → base-name-3 - -**Modified Files**: -- `src/backend/models.py` - Added DeployLocalRequest, DeployLocalResponse, VersioningInfo, CredentialImportResult (~40 lines) -- `src/backend/services/template_service.py` - Added is_trinity_compatible(), get_name_from_template() (~70 lines) -- `src/backend/credentials.py` - Added import_credential_with_conflict_resolution(), get_credential_by_name() (~100 lines) -- `src/backend/routers/agents.py` - Added deploy-local endpoint + versioning functions (~250 lines) -- `src/mcp-server/src/tools/agents.ts` - Added deployLocalAgent tool (~190 lines) -- `src/mcp-server/src/server.ts` - Registered new tool -- `docs/memory/feature-flows/local-agent-deploy.md` - New feature flow doc - -**Total**: ~470 lines of new code - ---- - -### 2025-12-21 14:15:00 -🧪 **Added UI Integration Test Phases for OTel and System Agent** - -Added two new test phases to the modular testing framework: - -**Phase 14: OpenTelemetry Integration** -- Tests OTel status API, collector health, Prometheus metrics -- Validates Dashboard header stats (cost/tokens display) -- Verifies agent OTel environment variable injection -- Tests resilience to collector downtime -- 10 test steps covering full OTel integration - -**Phase 15: System Agent & Fleet Operations** -- Tests system agent auto-deployment and status API -- Validates deletion protection (403 on DELETE) -- Tests fleet status and health APIs -- Validates System Agent UI page (/system-agent) -- Tests operations console and quick actions -- Tests reinitialize and ops settings endpoints -- 18 test steps covering full system agent functionality - -**Test Results**: Both phases PASSED (100% success rate) - -**Modified Files**: -- `docs/testing/phases/PHASE_14_OPENTELEMETRY.md` - New file (250 lines) -- `docs/testing/phases/PHASE_15_SYSTEM_AGENT.md` - New file (400 lines) -- `docs/testing/phases/INDEX.md` - Added phases 14-15 -- `.claude/agents/ui-integration-tester.md` - Updated phase list and paths - ---- - -### 2025-12-21 13:00:00 -📚 **Authentication & Authorization Architecture Documentation** - -Expanded the architecture document with a comprehensive "Authentication & Authorization Architecture" section that covers all component authentication flows: - -**7 Authentication Layers Documented**: -1. **User Authentication** - Dev mode (username/password) and Prod mode (Auth0/OAuth) -2. **MCP API Keys** - User → MCP Server authentication via `trinity_mcp_*` keys -3. **MCP Server → Backend** - Key passthrough pattern (no admin credentials in prod) -4. **Agent MCP Keys** - Auto-generated keys with `scope: "agent"` for agent-to-agent collaboration -5. **Agent-to-Agent Permissions** - Fine-grained permission checks at MCP layer -6. **System Agent** - `scope: "system"` bypasses all permission checks -7. **External Credentials** - Redis-backed storage with hot-reload to containers - -**Added**: -- ASCII diagram showing authentication flow between all components -- Tables for each authentication layer with key properties -- MCP Scope Summary table (user/agent/system) -- Permission rules matrix for agent-to-agent access - -**Modified File**: `docs/memory/architecture.md` - ---- - -### 2025-12-21 11:45:00 -🐛 **System Agent OTel Access Fix** - -Fixed issue where the system agent couldn't access OpenTelemetry metrics via the `/ops/costs` command. - -**Root Cause**: -1. Environment variable mismatch: Slash command used `$TRINITY_API_KEY` but agent has `$TRINITY_MCP_API_KEY` -2. System agent missing `/trinity-meta-prompt` mount - not being created with the volume -3. Reinitialize endpoint deleted `.claude/commands/ops/` from template without re-copying - -**Fixes Applied**: -- Updated `costs.md` slash command to use correct env var `$TRINITY_MCP_API_KEY` -- Added Trinity meta-prompt mount to `system_agent_service.py` `_create_system_agent()` -- Added template copy step to `system_agent.py` reinitialize endpoint (copies `.claude` and `CLAUDE.md` after cleanup) -- Updated `CLAUDE.md` Cost Monitoring section with explicit API call instructions - -**Modified Files**: -- `config/agent-templates/trinity-system/.claude/commands/ops/costs.md` - Fixed env var name -- `config/agent-templates/trinity-system/CLAUDE.md` - Expanded Cost Monitoring section -- `src/backend/services/system_agent_service.py` - Added `/trinity-meta-prompt` mount -- `src/backend/routers/system_agent.py` - Added template copy step in reinitialize - -**Testing**: Verified system agent can now call `/api/ops/costs` and receive OTel metrics. - ---- - -### 2025-12-21 11:20:00 -🎨 **System Agent Visibility Improvements** - -Made the trinity-system agent distinct from user agents across the UI. - -**Changes**: -- **Agents Page**: System agent hidden from list (users only see their agents) -- **Dashboard**: System agent has distinct purple styling: - - Purple background and border (vs white for user agents) - - "System Dashboard" link instead of "View Details" button - - Links directly to `/system-agent` page - -**Modified Files**: -- `src/frontend/src/stores/agents.js` - Added `userAgents` getter, updated `sortedAgents` to exclude system -- `src/frontend/src/components/AgentNode.vue` - Added purple styling for system agents, replaced button with link - ---- - -### 2025-12-21 11:10:00 -📊 **System Agent UI: Compact Header with OTel Visualization (Req 11.3)** - -Redesigned the System Agent page (`/system-agent`) with a compact header and integrated OpenTelemetry metrics visualization. - -**UI Changes**: -- **Compact Header**: Agent info, status, and actions on single line -- **Fleet Stats Bar**: Inline horizontal display (Fleet: X agents | Y running | Z stopped) -- **OTel Metrics Grid**: 6 metric cards with mini progress bars and icons - - Total Cost ($) with progress bar scaled to $10 max - - Tokens with colored breakdown (blue=input, purple=output, teal=cache) - - Sessions, Active Time, Commits, Lines of Code - -**Technical Details**: -- Fetches from `/api/observability/metrics` directly (no store dependency) -- OTel metrics poll every 30 seconds (fleet status every 10s) -- Graceful handling: disabled, unavailable, no-data states -- Added `/ops/costs` quick command button in Operations Console - -**Modified Files**: -- `src/frontend/src/views/SystemAgent.vue` - Complete rewrite (~830 lines) - -**Verified**: OTel metrics display live data ($0.07 cost, 19.9K tokens after test chat) - ---- - -### 2025-12-21 00:15:00 -📊 **System Agent OTel Integration (Req 11.2 Enhancement)** - -Added `/api/ops/costs` endpoint to give the system agent access to OpenTelemetry metrics in an ops-focused format. This keeps OTel (data collection) and Ops (interpretation) decoupled. - -**New Endpoint**: `GET /api/ops/costs` -- Fetches raw metrics from OTel Collector's Prometheus endpoint -- Reuses parsing from `observability.py` (no code duplication) -- Adds ops-specific analysis: threshold checks, cost alerts, formatted output -- Returns structured JSON the system agent can interpret - -**Features**: -- Cost summary with daily limit tracking (`ops_cost_limit_daily_usd` setting) -- Alerts when approaching (80%) or exceeding daily limit -- Cost breakdown by model with token counts -- Productivity metrics (sessions, commits, PRs, lines added/removed) -- Graceful handling when OTel is disabled or collector is unreachable - -**Modified Files**: -- `src/backend/routers/ops.py` - Added `get_ops_costs()` endpoint (~170 lines) -- `config/agent-templates/trinity-system/.claude/commands/ops/costs.md` - Updated slash command with API details -- `docs/memory/feature-flows/internal-system-agent.md` - Documented Cost & Observability section - -**Architecture Decision**: System agent calls the ops API to get interpreted metrics rather than accessing OTel directly. This keeps the two features independent: -- **OTel Integration** = Raw data collection + Prometheus endpoint + Dashboard UI -- **Ops Module** = Threshold analysis + alerts + system agent commands - ---- - -### 2025-12-20 23:30:00 -🐛 **Critical: Fleet Status API Fix** - -Fixed critical bug in `/api/ops/fleet/status` and related endpoints where agent data was not being read correctly. - -**Root Cause**: `list_all_agents()` returns `AgentStatus` Pydantic objects, but the ops.py code was using `.get("name")` dictionary syntax instead of attribute access (`.name`). This caused all agent lookups to fail silently, returning 0 counts. - -**Fixed Files**: -- `src/backend/routers/ops.py` - Changed all `agent.get("field")` to `agent.field` attribute access - -**Affected Endpoints**: -- `GET /api/ops/fleet/status` - Now returns correct agent list and summary counts -- `GET /api/ops/fleet/health` - Now correctly iterates over agents -- `POST /api/ops/fleet/restart` - Now correctly identifies agents to restart -- `POST /api/ops/fleet/stop` - Now correctly identifies agents to stop -- `POST /api/ops/emergency-stop` - Now correctly stops non-system agents - -**Restart Required**: Backend must be restarted for fix to take effect. - ---- - -### 2025-12-20 23:15:00 -🐛 **System Agent UI Fixes** - -Fixed two issues with the System Agent page: - -**Bug Fixes**: -- Fleet status cards now show correct agent counts (was showing 0s due to incorrect API response parsing) -- Changed from manual filtering to using `response.data.summary` from fleet API - -**UI Improvements**: -- Removed aggressive purple gradient header - now uses clean white/gray design matching rest of system -- Toned down Quick Action buttons from bright solid colors to muted bordered style -- Emergency Stop now uses subtle red border instead of solid red background -- Restart/Pause/Resume buttons now use gray borders, consistent with Dashboard -- Quick command buttons (/ops/status etc.) now use gray instead of purple -- Chat bubbles changed from purple to blue (matching system color scheme) -- NavBar System link icon changed from purple to gray (consistent with other nav items) - -**Design Principle**: Consistent muted color palette across all pages - no more aggressive bright colors. - ---- - -### 2025-12-20 22:30:00 -🖥️ **System Agent UI (Req 11.3) - IMPLEMENTED** - -Added dedicated operations dashboard for the system agent at `/system-agent` route. - -**New Files**: -- `src/frontend/src/views/SystemAgent.vue` - Ops-focused UI with fleet overview, quick actions, and chat - -**Modified Files**: -- `src/frontend/src/router/index.js` - Added `/system-agent` route (admin-only) -- `src/frontend/src/components/NavBar.vue` - Added purple "System" link with CPU icon (admin-only) -- `docs/memory/feature-flows/internal-system-agent.md` - Added Frontend UI section - -**Features**: -- Purple gradient header with system agent branding -- Fleet overview cards (Total, Running, Stopped, Issues) -- Quick action buttons (Emergency Stop, Restart All, Pause/Resume Schedules) -- Operations console with quick command buttons (/ops/status, /ops/health, /ops/schedules) -- Chat interface for sending commands to the system agent -- Auto-refresh every 10 seconds - -**Design**: Simplified single-page layout unlike complex AgentDetail.vue - focused purely on operations. - ---- - -### 2025-12-20 21:00:00 -🛠️ **System Agent Operations Scope (Req 11.2) - IMPLEMENTED** - -Enhanced the system agent to focus exclusively on platform operations (health, lifecycle, resource governance) rather than workflow orchestration. Implemented comprehensive fleet operations API and ops settings. - -**Guiding Principle**: "The system agent manages the orchestra, not the music." - -**New Files**: -- `src/backend/routers/ops.py` - Fleet operations endpoints (status, health, restart, stop, emergency) -- `config/agent-templates/trinity-system/commands/ops/status.md` - Fleet status report command -- `config/agent-templates/trinity-system/commands/ops/health.md` - Health check command -- `config/agent-templates/trinity-system/commands/ops/restart.md` - Restart specific agent command -- `config/agent-templates/trinity-system/commands/ops/restart-all.md` - Restart fleet command -- `config/agent-templates/trinity-system/commands/ops/stop.md` - Stop agent command -- `config/agent-templates/trinity-system/commands/ops/schedules.md` - Schedule overview command -- `config/agent-templates/trinity-system/commands/ops/costs.md` - Cost report command - -**Modified Files**: -- `config/agent-templates/trinity-system/CLAUDE.md` - Rewrote with ops-only scope -- `config/agent-templates/trinity-system/template.yaml` - Updated capabilities and slash commands -- `src/backend/main.py` - Added ops_router import and registration -- `src/backend/routers/settings.py` - Added ops settings with defaults -- `src/backend/database.py` - Added `list_all_disabled_schedules` method -- `src/backend/db/schedules.py` - Added `list_all_disabled_schedules` query - -**New API Endpoints**: -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/api/ops/fleet/status` | GET | All agents with status, context, activity | -| `/api/ops/fleet/health` | GET | Health summary with critical/warning issues | -| `/api/ops/fleet/restart` | POST | Restart all/filtered agents | -| `/api/ops/fleet/stop` | POST | Stop all/filtered agents | -| `/api/ops/schedules/pause` | POST | Pause all schedules | -| `/api/ops/schedules/resume` | POST | Resume all schedules | -| `/api/ops/emergency-stop` | POST | Halt all executions immediately | -| `/api/settings/ops/config` | GET/PUT | Get/update ops settings | -| `/api/settings/ops/reset` | POST | Reset ops settings to defaults | - -**Ops Settings**: -- `ops_context_warning_threshold` (75) - Context % to trigger warning -- `ops_context_critical_threshold` (90) - Context % to trigger critical -- `ops_idle_timeout_minutes` (30) - Minutes before stuck detection -- `ops_cost_limit_daily_usd` (50.0) - Daily cost limit -- `ops_max_execution_minutes` (10) - Max chat execution time -- `ops_alert_suppression_minutes` (15) - Suppress duplicate alerts -- `ops_log_retention_days` (7) - Days to keep container logs -- `ops_health_check_interval` (60) - Seconds between health checks - -**Slash Commands** (system agent only): -- `/ops/status` - Fleet status report -- `/ops/health` - Health check with recommendations -- `/ops/restart ` - Restart specific agent -- `/ops/restart-all` - Restart entire fleet -- `/ops/stop ` - Stop specific agent -- `/ops/schedules` - Schedule overview -- `/ops/costs` - Cost report from OTel - ---- - -### 2025-12-20 19:30:00 -🤖 **Internal System Agent (Req 11.1) - IMPLEMENTED** - -Implemented the privileged, auto-deployed platform orchestrator agent "trinity-system". - -**New Files**: -- `config/agent-templates/trinity-system/template.yaml` - System agent template with orchestration capabilities -- `config/agent-templates/trinity-system/CLAUDE.md` - Platform orchestrator instructions -- `src/backend/services/system_agent_service.py` - Auto-deployment service -- `src/backend/routers/system_agent.py` - Status, restart, reinitialize endpoints - -**Backend Changes**: -- `src/backend/database.py` - Added `is_system` column migration for agent_ownership -- `src/backend/db/agents.py` - Added system agent checks, SYSTEM_AGENT_NAME constant -- `src/backend/routers/agents.py` - Deletion protection with specific error message for system agents -- `src/backend/main.py` - Auto-deploy system agent on startup, registered system_agent router - -**MCP Server Changes**: -- `src/mcp-server/src/types.ts` - Added "system" scope to McpAuthContext -- `src/mcp-server/src/server.ts` - Handle system scope in authentication -- `src/mcp-server/src/tools/agents.ts` - System agents see all agents, cannot delete themselves -- `src/mcp-server/src/tools/chat.ts` - System-scoped keys bypass all permission checks - -**Frontend Changes**: -- `src/frontend/src/components/AgentNode.vue` - Purple "SYSTEM" badge for system agents -- `src/frontend/src/views/AgentDetail.vue` - System badge in agent header - -**Key Features**: -- Auto-deploys on backend startup if not exists -- Cannot be deleted (403 error with helpful message) -- System-scoped MCP key bypasses all permission checks -- Can communicate with any agent regardless of owner -- Can list all agents without filtering -- Purple SYSTEM badge in UI - -**API Endpoints**: -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/api/system-agent/status` | GET | Get system agent status | -| `/api/system-agent/restart` | POST | Restart system agent (admin) | -| `/api/system-agent/reinitialize` | POST | Reset to clean state (admin) | - ---- - -### 2025-12-20 17:30:00 -📋 **Internal System Agent Requirements (Req 11.1) - DRAFTED** - -Created requirements document for a privileged, auto-deployed platform orchestrator agent. - -**Document**: `docs/drafts/INTERNAL_SYSTEM_AGENT.md` - -**Key Features**: -- **Auto-Deployment**: System agent created on platform startup if not exists -- **Deletion Protection**: Cannot be deleted via API, MCP, or UI (only re-initialized) -- **Re-Initialization**: Admins can reset to clean state without losing identity -- **Local Template**: `config/agent-templates/trinity-system/` with platform-specific CLAUDE.md -- **MCP Integration**: Full access to all Trinity MCP tools, bypasses permission checks -- **System-Scoped Key**: Special MCP API key with `scope: "system"` -- **UI Visibility**: System badge, special styling, hidden delete button - -**Implementation Phases**: -1. Core Infrastructure (template, deletion protection, auto-deploy) -2. MCP Integration (system-scoped key, permission bypass) -3. Re-Initialization (endpoint, MCP tool, audit logging) -4. UI Integration (badges, styling, admin controls) -5. Observability (metrics, health check, activity tracking) - -**Database Change**: Add `is_system` flag to `agent_ownership` table - -**Roadmap**: Added as Phase 11 priority item (11.1) - ---- - -### 2025-12-20 16:00:00 -📊 **OpenTelemetry UI Integration (Req 10.8) - IMPLEMENTED** - -Added UI components to display OTel metrics in the Trinity Dashboard. - -**Backend Changes**: -- `src/backend/routers/observability.py` - New router with `/api/observability/metrics` and `/api/observability/status` endpoints -- `src/backend/main.py` - Registered observability router - -**Frontend Changes**: -- `src/frontend/src/stores/observability.js` - New Pinia store for OTel metrics with polling -- `src/frontend/src/components/ObservabilityPanel.vue` - Collapsible panel showing full metric breakdown -- `src/frontend/src/views/Dashboard.vue` - Added OTel stats to header (cost, tokens, status indicator) - -**Features**: -- Dashboard header shows total cost and token count when OTel is active -- Observability panel (bottom-left) with expand/collapse: - - Cost breakdown by model - - Token usage by type (input, output, cacheCreation, cacheRead) - - Productivity metrics (sessions, active time, commits, PRs) - - Lines of code (added/removed) -- Auto-refresh every 60 seconds -- Graceful handling when OTel disabled or collector unavailable -- Full dark mode support - -**API Response Format**: -```json -{ - "enabled": true, - "available": true, - "metrics": { "cost_by_model": {}, "tokens_by_model": {}, ... }, - "totals": { "total_cost": 0.0246, "total_tokens": 48093, ... } -} -``` - ---- - -### 2025-12-20 14:30:00 -📋 **Requirements Update: OpenTelemetry UI Integration (10.8)** - -Added new requirement 10.8 for displaying OTel metrics in Trinity UI as next priority. - -**Requirement Summary**: -- Backend API: `GET /api/observability/metrics` endpoint to query Prometheus -- Dashboard Header: Quick stats (total cost, total tokens, OTel status) -- Dashboard Panel: "Observability" tab with full metric breakdown -- Opt-in visibility: Only shows when `OTEL_ENABLED=1` and collector reachable - -**UI Placement Decided**: -| Location | What to Show | -|----------|--------------| -| Dashboard Header | Total cost, total tokens, OTel status indicator | -| Dashboard Panel | Full breakdown by model/type in "Observability" tab | -| AgentDetail | *Future* - Per-agent cost (requires agent_name label) | - -**Files Updated**: -- `docs/memory/requirements.md` - Added 10.8 OpenTelemetry UI Integration -- `docs/memory/roadmap.md` - Added to Phase 11 as next priority - ---- - -### 2025-12-20 12:00:00 -📊 **OpenTelemetry Integration (Phase 2) - OTEL Collector Service** - -Added OTEL Collector service for receiving metrics from Claude Code agents and exposing them in Prometheus format. - -**Changes**: -1. `docker-compose.yml` (lines 132-151) - - Added `otel-collector` service using `otel/opentelemetry-collector:0.91.0` - - Exposes ports 4317 (gRPC), 4318 (HTTP), 8889 (Prometheus) - - Connected to trinity-network for agent access - -2. `config/otel-collector.yaml` (new file) - - OTLP receiver on gRPC and HTTP - - Batch processor for efficiency - - Prometheus exporter with `trinity` namespace - - Debug exporter for troubleshooting - -**Metrics Collected** (verified with test agent): -- `trinity_claude_code_cost_usage_USD_total` - Cost per model (Haiku, Sonnet) -- `trinity_claude_code_token_usage_tokens_total` - Token usage by type (input, output, cacheCreation, cacheRead) - -**Labels Available**: -- `model` - Model name (claude-haiku-4-5-20251001, claude-sonnet-4-5-20250929) -- `session_id` - Unique session identifier -- `terminal_type` - non-interactive -- `platform` - trinity - -**Testing**: -- ✅ Collector starts with `docker-compose up` -- ✅ Agent sends metrics via OTLP gRPC -- ✅ Prometheus endpoint returns metrics at :8889/metrics -- ✅ Metrics update after chat activity - ---- - -### 2025-12-20 11:50:00 -📊 **OpenTelemetry Integration (Phase 1) - Environment Variable Injection** - -Implemented opt-in OpenTelemetry metrics export for Trinity agents, leveraging Claude Code's built-in OTel support. - -**Changes**: -1. `src/backend/routers/agents.py` (lines 514-522) - - Added conditional OTel env var injection during agent container creation - - Only injects when `OTEL_ENABLED=1` (default: disabled) - - Sets: `CLAUDE_CODE_ENABLE_TELEMETRY`, `OTEL_METRICS_EXPORTER`, `OTEL_LOGS_EXPORTER`, `OTEL_EXPORTER_OTLP_PROTOCOL`, `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_METRIC_EXPORT_INTERVAL` - -2. `docker-compose.yml` (lines 21-27) - - Added OTel configuration environment variables to backend service - - All with sensible defaults (`OTEL_ENABLED=0` by default) - -3. `.env.example` (lines 76-94) - - Documented all OTel configuration options with comments - -4. `docs/DEPLOYMENT.md` (lines 336-394) - - Added "OpenTelemetry Metrics (Optional)" section - - Documents metrics available, quick start, collector setup, verification - -**Testing**: -- ✅ With `OTEL_ENABLED=1`: Agent gets all OTel env vars -- ✅ With `OTEL_ENABLED=0` (default): No OTel vars injected -- ✅ Existing agents unaffected - -**Draft Doc**: `docs/drafts/OTEL_INTEGRATION.md` - Phase 2 (Collector) and Phase 3 (Prometheus/Grafana) available for future implementation. - ---- - -### 2025-12-19 16:45:00 -🎨 **Dark Mode: Fixed GitPanel, SchedulesPanel, and ExecutionsPanel Components** - -Fixed dark mode styling for three additional components in AgentDetail that were displaying white backgrounds in dark mode. - -**Files Modified**: -1. `src/frontend/src/components/GitPanel.vue` - Git tab in AgentDetail - - Fixed loading/disabled/error states with dark variants - - Fixed repository info header card - - Fixed branch and sync status badges - - Fixed pending changes and commit sections - - Updated `getChangeStatusClass()` function with dark variants - -2. `src/frontend/src/components/SchedulesPanel.vue` - Schedules tab in AgentDetail - - Fixed header text colors - - Fixed create/edit form modal with dark inputs, labels, buttons - - Fixed cron preset buttons with dark hover states - - Fixed schedule cards and status badges - - Fixed execution history rows and modal - - Fixed stats row and tool call displays - -3. `src/frontend/src/components/ExecutionsPanel.vue` - Executions tab in AgentDetail - - Fixed summary stats cards - - Fixed executions table header, body, and row hover states - - Fixed status and trigger badges with dark variants - - Fixed execution detail modal with dark styling - - Fixed context bar, tool calls, and response sections - -**Pattern Applied**: Consistent with existing dark mode - `dark:bg-gray-800` for cards, `dark:bg-gray-900/30` for colored badges, `dark:text-gray-400` for secondary text. - ---- - -### 2025-12-19 16:15:00 -🎨 **Dark Mode: Fixed FoldersPanel and AgentNode Components** - -Fixed dark mode styling for two components that were displaying white backgrounds in dark mode. - -**Files Modified**: -1. `src/frontend/src/components/FoldersPanel.vue` - Folders tab in AgentDetail - - Added `dark:bg-gray-800` to all white card sections - - Added `dark:border-gray-700` to all borders - - Added `dark:text-white/gray-400` to text elements - - Fixed toggle switch backgrounds (`dark:bg-gray-600`) - - Fixed code element backgrounds (`dark:bg-gray-700`) - - Fixed status badges (mounted/pending) with dark variants - -2. `src/frontend/src/components/AgentNode.vue` - Agent tiles on Dashboard - - Added `dark:bg-gray-800` to main card container - - Added `dark:border-gray-700` to card border - - Fixed all text colors with dark variants - - Fixed progress bar backgrounds (`dark:bg-gray-700`) - - Fixed View Details button with dark hover states - - Fixed connection handle colors for dark mode - - Updated computed `activityStateColor` with dark variants - -**Pattern Applied**: Consistent with existing dark mode in NavBar, Dashboard, other panels. - ---- - -### 2025-12-19 15:30:00 -🐛 **Bug Fix: Context Tracking Reset After First Message (P0)** - -Fixed critical bug where context window usage would reset to ~4 tokens on subsequent chat messages. - -**Root Cause**: -- Claude Code with `--continue` flag may report only new input tokens, not cumulative context -- Agent server was overwriting `session_context_tokens` with each response, causing resets - -**Fix Applied** (`docker/base-image/agent_server/routers/chat.py`): -- Context tokens now only increase within a session (monotonic growth) -- If new value is lower than previous, keep the maximum (with warning logged) -- Session reset still clears context to 0 as expected - -**Testing**: Verified with 3 consecutive messages - context stays at 660 tokens (not resetting to ~4) - -**Related Issues Clarified**: -- P1 Permissions Auth Error: NOT a bug - caused by JWT token invalidation after backend restart (documented behavior) -- P1 Agent Name Validation: NOT a bug - API sanitizes invalid names by design (converts `@#! ` to `-`) - ---- - -### 2025-12-19 12:30:00 -✅ **Test Suite: Fixed 4 Failing Tests - Now 179/179 Pass** - -Fixed all failing test assertions to match actual API response formats. - -**Fixes Applied**: -1. `test_agent_lifecycle.py:128` - Updated `test_invalid_name_returns_400` to `test_invalid_name_is_sanitized` - - API sanitizes invalid names (by design) rather than rejecting them - - Test now verifies sanitization behavior: `"invalid name with spaces!"` → `"invalid-name-with-spaces"` - -2. `test_systems.py:497,935` - Fixed permitted_agents assertion - - API returns list of objects `[{name, status, type, permitted}]`, not strings - - Extract names: `[p["name"] for p in permitted]` before checking membership - -3. `test_systems.py:640,953` - Fixed schedules response assertion - - API returns list directly `[{...}]`, not wrapped `{"schedules": [...]}` - - Handle both formats: `schedules = data if isinstance(data, list) else data.get("schedules", [])` - -**Test Results**: 179 passed, 28 skipped, 0 failed (20:36 duration) - ---- - -### 2025-12-19 10:55:00 -🐛 **Bug Fix: MCP Client YAML Response Handling** - -Fixed `get_system_manifest` MCP tool failing with "Unexpected token" JSON parse error. - -**Root Cause**: -- `TrinityClient.request()` always parsed responses as JSON -- `/api/systems/{name}/manifest` endpoint returns YAML (text/plain) -- Attempting to JSON.parse() YAML content caused the error - -**Fix**: -- Modified `src/mcp-server/src/client.ts` line 130-134 -- Added content-type check before parsing response -- Returns raw text for `text/plain`, `text/yaml`, `application/x-yaml` content types - -**Also Fixed**: -- `agents/Ruby/ruby-cms.yaml`: Changed template names from `github:Abilityai/ruby-*` to `github:abilityai/ruby-*` (lowercase) to match registered templates - -**Testing**: -- Successfully deployed Ruby CMS system via MCP `deploy_system` tool -- All 16 MCP tools verified working (9 agent, 3 chat, 4 system) -- Full verification: 3 agents, 6 permissions, 3 shared folder volumes, 6 schedules - ---- - -### 2025-12-18 05:15:00 -📝 **Documentation: Updated Ruby CMS System Definition** - -Updated Ruby Content Management System operational definition to reflect System Manifest deployment (Req 10.7). - -**Files Updated/Created**: -- `agents/Ruby/ruby-content-system-definition.md` (updated) -- `agents/Ruby/ruby-cms.yaml` (new) -- `agents/Ruby/README.md` (new) - -**Changes**: -1. **New Section: "System Manifest Deployment (Recommended)"**: - - Complete YAML manifest for Ruby CMS with all 3 agents - - Includes global prompt for demo/test mode - - All 6 schedules defined in YAML - - Full-mesh permissions preset - - Deployment instructions via API and MCP tools - - System management endpoints (list, get, restart, export) - -2. **Updated Agent Repositories Table**: - - Added "Trinity Template" column with correct template IDs - - Added deployment method reference - -3. **Renamed Section: "Manual Deployment (Alternative)"**: - - Original deployment section now marked as alternative approach - - Cross-references Multi-Agent System Guide for manual steps - -4. **Updated Operations Guide**: - - Initial deployment now shows System Manifest method - - Added system-level management commands - - Updated container names to use `ruby-cms-` prefix (from manifest naming convention) - -5. **Version Bump**: 1.0.0 → 1.1.0 - - Updated header and version history - - Last updated date: 2025-12-18 - -6. **New File: ruby-cms.yaml**: - - Ready-to-deploy System Manifest file - - Complete YAML with all 3 agents, schedules, permissions - - Users can deploy directly: `curl ... -d "$(cat ruby-cms.yaml)"` - -7. **New File: README.md**: - - Quick start guide for Ruby CMS - - Directory structure explanation - - Deployment options (manifest, MCP, manual) - - System management commands - - Links to detailed documentation - -**Impact**: -- Ruby CMS now serves as complete reference example for System Manifest deployment -- Users can copy YAML manifest directly and deploy entire system -- Demonstrates all System Manifest features: permissions, folders, schedules, global prompt -- Original manual deployment docs preserved as alternative - ---- - -### 2025-12-18 05:00:00 -📝 **Documentation: System Manifest Deployment Guide** - -Updated multi-agent system documentation to include System Manifest (YAML-based deployment) as the recommended deployment method. - -**Files Updated**: - -1. **MULTI_AGENT_SYSTEM_GUIDE.md**: - - Added new section: "System Manifest Deployment (Recommended)" - - Comprehensive YAML manifest examples (minimal and complete) - - Permission preset documentation (full-mesh, orchestrator-workers, none, explicit) - - Deployment options: API and MCP tools - - Agent naming convention and conflict resolution - - System management endpoints (list, get, restart, export) - - Recipe vs. declarative model explanation - - Best practices for manifest deployment - - Renamed old section to "Manual Deployment Workflow (Alternative)" - -2. **TRINITY_COMPATIBLE_AGENT_GUIDE.md**: - - Added new section: "Multi-Agent Systems" - - Deployment options (System Manifest vs. Manual) - - Design considerations for multi-agent templates - - Cross-references to MULTI_AGENT_SYSTEM_GUIDE.md - -**Impact**: -- Users now have clear guidance on deploying multi-agent systems via YAML manifests -- System Manifest positioned as recommended approach (faster, more consistent, less error-prone) -- Manual deployment still documented as alternative for fine-grained control -- Single-agent guide now cross-references multi-agent guide - -**Documentation Links**: -- Feature Flow: `docs/memory/feature-flows/system-manifest.md` (complete implementation details) -- Design Doc: `docs/drafts/SYSTEM_MANIFEST_SIMPLIFIED.md` (design rationale) -- Requirements: `docs/memory/requirements.md` (Req 10.7) - ---- - -### 2025-12-18 04:30:00 -🔧 **Bug Fixes: Critical System Manifest Test Failures (P0-P2)** - -Fixed all critical bugs identified in system manifest test report 2025-12-17. - -**P0 - CRITICAL: YAML Export Serialization Bug (SECURITY RISK)** ✅ -- **Issue**: Python object tags in exported YAML (RCE vector, can't re-import) -- **Root Cause**: `db.get_setting("trinity_prompt")` returned ORM object, not string -- **Fix**: Changed to `db.get_setting_value()` which returns just the value -- **Also Fixed**: Changed `db.get_agent_schedules()` → `db.list_agent_schedules()` and converted Schedule objects to dicts -- **Modified Files**: - - `src/backend/services/system_service.py`: - - Line 454: Fixed function call and dict conversion for schedules - - Line 542: Fixed trinity_prompt to use get_setting_value() -- **Security Impact**: Eliminated Python object serialization in YAML exports -- **Test Impact**: `test_export_manifest_endpoint` and `test_export_and_redeploy` should now pass - -**P1 - HIGH: List Systems Endpoint Bug** ✅ -- **Issue**: System names with hyphens (e.g., `test-list-abc123`) not grouped correctly -- **Root Cause**: Code split on `-` and took first part, but system names can have multiple hyphens -- **Example**: `test-list-abc123-worker1` → extracted `test` instead of `test-list-abc123` -- **Fix**: Split on `-` and take all parts except last: `'-'.join(parts[:-1])` -- **Modified Files**: - - `src/backend/routers/systems.py`: - - Lines 264-268: Fixed prefix extraction logic with comment explaining the fix -- **Test Impact**: `test_list_systems_endpoint` should now pass - -**P2 - MEDIUM: Test Configuration Issues** ✅ -1. **Wrong Default Password**: - - Changed `tests/utils/api_client.py` line 28: `"changeme"` → `"password"` - - Eliminates 401 Unauthorized errors when env var not set - -2. **Deployment Timeouts**: - - Added `timeout=120.0` to slow deployment tests in `test_systems.py`: - - `test_shared_folders_configuration` (line 576) - - `test_complete_system_deployment` (line 899) - - Default 30s timeout insufficient for multi-agent deployments with folders/schedules - -**P3 - LOW: Schedules Endpoint** (No Fix Needed) -- **Issue**: Test calls `.get("schedules")` on array, expects dict -- **Analysis**: API returns `List[ScheduleResponse]` (bare array) - this is correct -- **Frontend**: Consumes `response.data` directly as array - working as designed -- **Conclusion**: Test bug, not API bug - test should use array directly - -**Files Modified** (5 total): -- `src/backend/services/system_service.py` - YAML export fixes -- `src/backend/routers/systems.py` - List systems prefix extraction -- `tests/utils/api_client.py` - Default password fix -- `tests/test_systems.py` - Timeout increases (2 tests) - -**Expected Test Improvements**: -- ✅ `test_export_manifest_endpoint` - PASS (was failing with YAML constructor error) -- ✅ `test_export_and_redeploy` - PASS (was failing with YAML constructor error) -- ✅ `test_list_systems_endpoint` - PASS (was failing with None assertion) -- ✅ `test_shared_folders_configuration` - PASS (was timing out) -- ✅ `test_complete_system_deployment` - PASS (was timing out) - -**Test Suite Status Prediction**: -- Before: 23/30 passed (76.7%) -- After: 28/30 passed (93.3%) -- Remaining failures: `test_explicit_permissions` (test assertion bug), `test_schedules_created` (test API misuse) - ---- - -### 2025-12-18 03:00:00 -🔧 **Bug Fixes: System Manifest Import Errors & Template Endpoints (HIGH PRIORITY)** - -Fixed critical import errors blocking System Manifest endpoints and template retrieval errors. - -**Issues Fixed (from Test Report 2025-12-17 21:02:04):** - -1. **Missing Import: `list_agents_for_user` (7 test failures)** ✅ - - **Root Cause**: systems.py attempted to import non-existent function from docker_service - - **Fix**: Changed all imports to use `get_accessible_agents()` from routers.agents - - **Modified Files**: - - `src/backend/routers/systems.py` - 4 import corrections - - list_systems: line 256 - - get_system: line 304 - - restart_system: line 380 - - get_system_manifest: line 458 - -2. **Template Endpoint 500 Errors (2 test failures)** ✅ - - **Root Cause**: Type mismatch - code expected dict but got string in required_credentials - - **Fix**: Added type checking for both dict and string credentials - - **Modified Files**: - - `src/backend/routers/templates.py`: - - get_template_env_template: Added isinstance() checks (lines 107-125) - - get_template: Added try/except wrapper and "local:" prefix handling (lines 161-199) - - get_template_env_template: Added error handling (lines 161-167) - -**Technical Details:** -- Replaced `list_agents_for_user(username)` with `get_accessible_agents(current_user)` pattern -- Fixed restart_system to use container.stop() directly instead of non-existent stop_agent() -- Added template_id prefix stripping for "local:" templates -- Added comprehensive error logging for template operations - -**Expected Impact:** -- **CRITICAL**: All 7 System Manifest backend endpoint tests should now pass -- **MEDIUM**: Template detail and env template endpoints should work correctly -- Estimated fix: **9 of 13 failing tests** (remaining 4 are timeout and test logic issues) - -**Next Steps:** -1. Re-run test suite to verify fixes -2. Address timeout issues (increase timeout for system deployment tests) -3. Fix test assertion errors (test_explicit_permissions, test_schedules_created) - ---- - -# Changelog - -> **Purpose**: Document all changes with progressive condensation. -> Update after EVERY task completion. Keep ~500 lines through consolidation. - -## Emoji Prefixes -- 🎉 Major milestones -- ✨ New features -- 🔧 Bug fixes -- 🔄 Refactoring -- 📝 Documentation -- 🔒 Security updates -- 🚀 Performance improvements -- 💾 Data/persistence changes -- 🐳 Docker/infrastructure - ---- - -## Recent Changes (Full Detail) - -### 2025-12-18 02:30:00 -🧪 **Testing: System Manifest Integration Test Suite** - -Created comprehensive integration tests for System Manifest deployment (Req 10.7). - -**New Files:** -- `tests/test_systems.py` - 35 tests covering all phases of System Manifest - -**Test Coverage:** -1. **Phase 1 - YAML Parsing & Validation** (8 smoke tests) - - Dry run validation with minimal and full manifests - - Invalid YAML syntax handling - - Missing required fields (name, agents) - - Invalid system/agent name formats - - Invalid template prefixes - - Invalid permission presets - - Conflicting permission configurations - -2. **Phase 1 - Deployment** (3 core tests) - - Deploy minimal system with correct agent naming - - Conflict resolution with `_N` suffix - - Trinity prompt update verification - -3. **Phase 2 - Permissions** (4 core tests) - - Full-mesh preset (each agent ↔ all others) - - Orchestrator-workers preset (orchestrator → workers only) - - Explicit permission matrix - - None preset (clear all permissions) - -4. **Phase 2 - Configuration** (3 core tests) - - Shared folders (expose/consume flags) - - Schedule creation and verification - - Agent auto-start after deployment - -5. **Phase 3 - Backend Endpoints** (5 core tests) - - List systems with grouping - - Get system details with enriched data - - Nonexistent system returns 404 - - Restart system agents - - Export manifest as YAML - -6. **Integration Tests** (2 slow tests) - - Complete system with all features (prompt, folders, schedules, permissions) - - Export and redeploy workflow - -7. **Edge Cases** (6 tests) - - Authentication requirements - - Empty manifest handling - - Unknown agents in permissions - - Nonexistent system operations - -**Test Organization:** -- Smoke tests: No agent creation (YAML validation only) -- Core tests: Agent creation with cleanup (module-scoped) -- Slow tests: Full multi-agent systems with all features -- Edge cases: Error handling and authentication - -**Updated Files:** -- `.claude/agents/test-runner.md` - Added System Manifest to test categories - -**Expected Results:** -- ~8 smoke tests (30 seconds) -- ~18 core tests (3-5 minutes) -- ~2 slow tests (2-3 minutes) -- ~7 edge case tests (1 minute) -- **Total: 35 tests** covering all 3 phases - ---- - -### 2025-12-18 01:45:00 -✨ **Feature: System Manifest Phase 2 - Configuration & Startup (Req 10.7)** - -Completed Phase 2 of System Manifest deployment - now supports permissions, folders, schedules, and auto-starts agents. - -**Modified Files:** -- `src/backend/services/system_service.py` - Added 4 configuration functions -- `src/backend/routers/systems.py` - Extended deploy endpoint with Phase 2 steps -- `src/backend/routers/agents.py` - Extracted `start_agent_internal()` for reuse - -**New Configuration Functions:** -1. `configure_permissions()` - Apply permission presets or explicit rules -2. `configure_folders()` - Set expose/consume for shared folders -3. `create_schedules()` - Create agent schedules from manifest -4. `start_all_agents()` - Start all created agents (triggers Trinity injection) - -**Permission Presets:** -- `full-mesh` - Every agent can call every other agent -- `orchestrator-workers` - Only orchestrator can call workers, workers isolated -- `none` - Clear all default permissions, agents cannot communicate -- `explicit` - Custom permission matrix from manifest - -**Tests Passed (6/6):** -1. Full-mesh permissions (each agent can call all others) -2. Orchestrator-workers (orchestrator→workers, workers→[]) -3. Explicit permissions (custom matrix) -4. None preset (all permissions cleared) -5. Shared folders (expose/consume flags applied) -6. Complete system (prompt + agents + folders + schedules + permissions + start) - ---- - -### 2025-12-17 22:52:00 -✨ **Feature: System Manifest Phase 1 - Core Deployment Engine (Req 10.7)** - -Implemented `POST /api/systems/deploy` endpoint for recipe-based multi-agent deployment from YAML manifests. - -**New Files:** -- `src/backend/models.py` - Added 5 new models: SystemAgentConfig, SystemPermissions, SystemManifest, SystemDeployRequest, SystemDeployResponse -- `src/backend/services/system_service.py` - YAML parsing, validation, agent name resolution -- `src/backend/routers/systems.py` - Deploy endpoint with dry_run support - -**Modified Files:** -- `src/backend/routers/agents.py` - Extracted `create_agent_internal()` for reuse -- `src/backend/main.py` - Registered systems router - -**Features:** -- Parse and validate YAML manifests -- Agent naming: `{system}-{agent}` format -- Conflict resolution with `_N` suffix (e.g., `my-agent_2`) -- Dry run mode for validation without deployment -- Updates `trinity_prompt` setting from manifest -- Full audit logging - -**Tests:** 6/6 passed -1. Dry run validation -2. Invalid YAML error handling -3. Missing required fields validation -4. Actual deployment with agent creation -5. Conflict resolution with suffix -6. Trinity prompt update - ---- - -### 2025-12-17 11:45:00 -📝 **Design: System Manifest (Multi-Agent Deployment)** - -Finalized design for recipe-based multi-agent deployment via YAML manifest (Req 10.7). - -**Key Decisions:** -- Agent naming: `{system}-{agent}` format (e.g., `content-production-orchestrator`) -- Re-deploy creates new agents with `_N` suffix (`ruby` → `ruby_2` → `ruby_3`) -- Updates global `trinity_prompt` setting (reuses existing 10.6) -- No `systems` table - agents are independent after creation (recipe, not declarative) - -**YAML Format:** -```yaml -name: content-production -prompt: "System-wide instructions..." -agents: - orchestrator: - template: github:YourOrg/repo - folders: {expose: true, consume: true} - schedules: [{name: daily, cron: "0 9 * * *", message: "..."}] -permissions: - preset: full-mesh # or orchestrator-workers, none, explicit -``` - -**Maps to Existing APIs:** -- `prompt` → `PUT /api/settings/trinity_prompt` -- `agents.*` → `POST /api/agents` -- `folders` → `PUT /api/agents/{name}/folders` -- `schedules` → `POST /api/agents/{name}/schedules` -- `permissions` → `PUT /api/agents/{name}/permissions` - -**Files:** -- Design: `docs/drafts/SYSTEM_MANIFEST_SIMPLIFIED.md` -- Requirement: `docs/memory/requirements.md` (10.7) -- Roadmap: Phase 11 priority item - ---- - -### 2025-12-17 10:35:02 -🔧 **Dark Mode: Fix Agent Detail Panel Components** - -Added dark mode support to 4 components on the Agent Detail page that were displaying with light mode styles: - -**Files updated:** -- `UnifiedActivityPanel.vue` - Session activity panel (header, timeline, tool chips, modal) -- `InfoPanel.vue` - Agent info tab (template info, use cases, resources, capabilities sections) -- `MetricsPanel.vue` - Custom metrics tab (empty states, metrics grid, progress bars) -- `WorkplanPanel.vue` - Workplan tab (summary stats, current task banner, plans list, modal) - -**Changes:** -- Added `dark:` variants to all background, border, and text color classes -- Updated gradients (e.g., `from-indigo-50 to-purple-50` → `dark:from-indigo-900/30 dark:to-purple-900/30`) -- Fixed modal overlays, buttons, and interactive states for dark mode -- Updated status badge helper functions with dark mode color variants - -### 2025-12-17 10:05:28 -🔒 **Security: Pre-Commit Security Check Command** - -Created `/security-check` command to validate staged changes don't contain sensitive information. - -**Checks for:** -- API keys/tokens (Anthropic, OpenAI, GitHub, Slack, Google, AWS patterns) -- Real email addresses (excluding example.com placeholders) -- IP addresses (internal and public) -- .env files with actual values -- Hardcoded secrets in code -- Internal URLs/domains -- Credential files (.pem, .key, credentials.json, etc.) - -**Features:** -- Severity levels (CRITICAL/HIGH/MEDIUM/LOW) -- Quick fix instructions for each issue type -- False positive guidance -- Report format with actionable findings - -**Key file**: `.claude/commands/security-check.md` - ---- - -### 2025-12-17 10:02:11 -📝 **Documentation: Development Workflow Guide** - -Created `docs/DEVELOPMENT_WORKFLOW.md` - comprehensive guide for developers and AI assistants working on Trinity. - -**Documents the optimal workflow:** -1. **Context Loading** - Start with `/read-docs` or read relevant feature flows -2. **Development** - Reference feature flows while implementing -3. **Testing** - Run API tests (required) and UI tests (recommended) -4. **Documentation** - Update feature flows via analyzer, then `/update-docs` - -**Includes:** -- Complete development cycle diagram -- Sub-agents reference (when to use each) -- Slash commands reference -- Memory files explanation and relationships -- Example development sessions -- Best practices checklist - -**Key files**: `docs/DEVELOPMENT_WORKFLOW.md` - ---- - -### 2025-12-15 00:15:00 -📝 **Documentation: Multi-Agent System Guide - Runtime Injection & Credentials** - -Enhanced the multi-agent guide with clear documentation about what Trinity injects at runtime vs. what system designers should provide in templates. - -**Key Additions:** -- **Runtime Injection System** section explaining `POST /api/trinity/inject` flow -- **⚡ RUNTIME INJECTION** markers on auto-injected features (Vector DB, Workplan, Trinity MCP, Chroma MCP) -- **"What NOT to Include"** table - Lists all files/sections that Trinity injects automatically -- **"What TO Include"** table - Clarifies template designer responsibilities -- **Credential System** comprehensive documentation with flow diagram -- **Required .gitignore** section showing what to exclude from repos -- Updated Repository Contents section with clearer annotations - -**Impact**: System designers now have clear guidance on avoiding duplication of platform-injected content in their agent templates. - ---- - -### 2025-12-14 23:45:00 -📝 **Documentation: Multi-Agent System Guide - Platform Capabilities Section** - -Added comprehensive "Trinity Platform Capabilities" section to the multi-agent guide, documenting all platform features available to agent designers. - -**New Section Contents:** -- Vector Database (Chroma) - Python API + 12 MCP tools with examples -- Scheduling System - Cron patterns, API endpoints, coordination patterns -- Workplan System (Task DAGs) - Format, states, cross-agent coordination -- Trinity MCP Tools - All 12 agent-to-agent tools -- Shared Folders - Paths, configuration, permission gating -- Credential Hot-Reload - API for live updates -- Collaboration Dashboard - Real-time visualization features -- Activity Stream - Unified audit trail API -- Context Tracking - Monitoring and warnings -- Custom Metrics - template.yaml schema and examples -- Git Sync - Bidirectional GitHub synchronization -- Capability Summary Table with scope, access method, multi-agent benefit -- Design Implications section with 7 key considerations - ---- - -### 2025-12-14 23:30:00 -📝 **Documentation: Multi-Agent System Guide** - -Created comprehensive guide for building multi-agent systems on Trinity platform. - -**New File**: -- `docs/MULTI_AGENT_SYSTEM_GUIDE.md` - Complete guide for multi-agent architecture - -**Guide Contents (19 sections)**: -- When to use multi-agent systems vs single agents -- Architecture patterns: Orchestrator-Workers, Pipeline, Mesh, Hierarchical -- System design process (5 steps) -- Agent boundaries and responsibilities -- Communication strategies (shared folders vs MCP) -- Shared folder architecture with file contracts -- Scheduling coordination and collision avoidance -- Permissions and access control patterns -- State management with ownership tables -- Repository structure (one repo per agent) -- Deployment workflow with step-by-step scripts -- Observability and monitoring patterns -- Testing multi-agent systems (unit, integration, system) -- Best practices for design, communication, operations -- System definition template -- Example: Ruby Content Management System reference -- Troubleshooting common issues - -**Updated Files**: -- `README.md` - Added link to new guide in Documentation section -- `docs/memory/feature-flows.md` - Added to Core Specifications table - -**Based On**: Ruby Content Management System (`ruby-content-system-definition.md`) as reference architecture - ---- - -### 2025-12-14 22:15:00 -📝 **Documentation: Consolidated Agent Compatibility Guides** - -Merged two overlapping documentation files into a single comprehensive guide. - -**New File**: -- `docs/TRINITY_COMPATIBLE_AGENT_GUIDE.md` - Single source of truth for agent compatibility - -**Deleted Files**: -- `docs/AGENT_TEMPLATE_SPEC.md` - Merged into new guide -- `docs/memory/trinity-compatible-agent.md` - Merged into new guide - -**Updated Files**: -- `README.md` - Updated references to new guide (lines 130, 223) -- `docs/memory/feature-flows.md` - Updated Core Specifications reference - -**Guide Contents**: -- Overview and Four Pillars of Deep Agency -- Required files (template.yaml, CLAUDE.md, .mcp.json.template, .gitignore) -- Complete directory structure -- Full template.yaml schema with all fields -- CLAUDE.md requirements -- Credential management and hot-reload -- Platform injection (meta-prompt, commands, MCP) -- Task planning system (DAG format, state machine) -- Inter-agent collaboration (MCP tools, access control) -- Shared folders and custom metrics -- Memory management patterns -- Testing locally guide -- Compatibility checklist -- Migration guide and troubleshooting - ---- - -### 2025-12-14 21:30:00 -📝 **Testing: Added UI Test Phase 13 for System Settings** - -Created comprehensive UI test phase for the System Settings feature (Trinity Prompt). - -**New Files**: -- `docs/testing/phases/PHASE_13_SETTINGS.md` - Full UI test phase with 8 test steps - -**Updated Files**: -- `docs/testing/phases/INDEX.md` - Added Phase 13 to phase overview table, file list, and version history - -**Test Phase Coverage**: -1. Admin access verification (navbar + page) -2. Non-admin access denial -3. Trinity Prompt creation -4. Persistence verification via API -5. Prompt injection into new agent -6. Prompt update on agent restart -7. Prompt removal when cleared -8. Markdown content support - -**API Tests Verified**: `tests/test_settings.py` - All 19 tests passing - -**UI Test Results**: PARTIAL - Core functionality verified via API, auth issue in long-running backend detected during UI testing (to be investigated separately) - ---- - -### 2025-12-14 19:45:00 -🔧 **Bug Fix: Custom Instructions Removal + Integration Tests** - -Fixed bug where clearing the `trinity_prompt` setting didn't remove the "## Custom Instructions" section from CLAUDE.md on agent restart. Also added comprehensive integration tests. - -**Bug Fix**: -- `docker/base-image/agent_server/routers/trinity.py`: - - Added `had_custom_instructions` flag tracking - - Modified condition at line 271 to `elif custom_section or had_custom_instructions:` - - Now properly writes updated content without Custom Instructions when prompt is cleared - - Added log message "Removed Custom Instructions from CLAUDE.md" - -**New Tests** (`tests/test_settings.py`): -- `TestSettingsEndpointsAuthentication` (4 tests) - Auth requirements -- `TestSettingsEndpointsAdmin` (6 tests) - CRUD operations -- `TestTrinityPromptSetting` (3 tests) - Prompt-specific operations -- `TestTrinityPromptInjection` (3 tests) - Agent injection verification -- `TestSettingsValidation` (3 tests) - Input validation -- **Total: 19 tests, all passing** - -**Documentation Updates**: -- `feature-flows/system-wide-trinity-prompt.md` - Updated test status -- `docs/TESTING_GUIDE.md` - Added System Settings to test coverage - ---- - -### 2025-12-14 02:30:00 -✨ **Feature: System-Wide Trinity Prompt (Settings Page)** - -Added ability to set a custom system prompt that gets injected into all agents' CLAUDE.md at startup. Accessible via new admin-only Settings page. - -**Architecture**: -- System setting stored in SQLite `system_settings` table -- Retrieved during agent start and passed to agent-server injection API -- Injected as "## Custom Instructions" section in CLAUDE.md after Trinity section - -**Backend Changes**: -- `src/backend/db/settings.py` - New SettingsOperations class (CRUD for system settings) -- `src/backend/db/__init__.py` - Export SettingsOperations -- `src/backend/db_models.py` - Added SystemSetting, SystemSettingUpdate models -- `src/backend/database.py` - Added system_settings table, integrated operations -- `src/backend/routers/settings.py` - New router with GET/PUT/DELETE endpoints (admin-only) -- `src/backend/main.py` - Mounted settings router -- `src/backend/routers/agents.py` - `inject_trinity_meta_prompt()` now fetches `trinity_prompt` setting and passes to agent-server - -**Agent-Server Changes**: -- `docker/base-image/agent_server/models.py` - Added `custom_prompt` field to TrinityInjectRequest -- `docker/base-image/agent_server/routers/trinity.py` - Inject custom prompt as "## Custom Instructions" section - -**Frontend Changes**: -- `src/frontend/src/views/Settings.vue` - New Settings page with Trinity Prompt editor -- `src/frontend/src/stores/settings.js` - New Pinia store for settings API -- `src/frontend/src/router/index.js` - Added `/settings` route -- `src/frontend/src/components/NavBar.vue` - Added Settings link (admin-only via role check) - -**API Endpoints**: -- `GET /api/settings` - List all settings (admin only) -- `GET /api/settings/{key}` - Get specific setting (admin only) -- `PUT /api/settings/{key}` - Create/update setting (admin only) -- `DELETE /api/settings/{key}` - Delete setting (admin only) - -**Setting Key**: `trinity_prompt` - The custom instructions text - -**Usage**: -1. Login as admin -2. Navigate to Settings page -3. Enter custom prompt text (supports Markdown) -4. Save changes -5. Start/restart agents - they will receive the custom instructions - ---- - -### 2025-12-14 00:15:00 -✨ **Feature: Chroma MCP Server Integration (Req 10.5)** - -Added auto-configuration of official chroma-mcp server in agent containers, enabling agents to use vector memory via MCP tools instead of Python code. - -**Changes**: -- `docker/base-image/Dockerfile` - Added `chroma-mcp` package -- `docker/base-image/agent_server/routers/trinity.py`: - - Added CHROMA_MCP_CONFIG constant with MCP server configuration - - inject_trinity() now injects chroma server into `.mcp.json` - - check_trinity_injection_status() includes `chroma_mcp_configured` field - - Simplified CLAUDE.md vector memory section (MCP tools auto-discovered) -- `config/trinity-meta-prompt/vector-memory.md` - Updated with MCP tool examples - -**MCP Config Injected**: -```json -{ - "mcpServers": { - "chroma": { - "command": "python3", - "args": ["-m", "chroma_mcp", "--client-type", "persistent", "--data-dir", "/home/developer/vector-store"] - } - } -} -``` - -**Agent Usage**: `mcp__chroma__chroma_add_documents()`, `mcp__chroma__chroma_query_documents()`, etc. - -**Rollout**: Requires base image rebuild with `./scripts/deploy/build-base-image.sh` - ---- - -### 2025-12-13 23:30:00 -✨ **Feature: Agent Vector Memory with Chroma (Req 10.4)** - -Added per-agent Chroma vector database with pre-configured all-MiniLM-L6-v2 embedding model for semantic memory storage and retrieval. - diff --git a/docs/memory/feature-flows/gemini-runtime.md b/docs/memory/feature-flows/gemini-runtime.md new file mode 100644 index 000000000..16571774d --- /dev/null +++ b/docs/memory/feature-flows/gemini-runtime.md @@ -0,0 +1,126 @@ +# Gemini CLI Runtime Integration + +**Status**: ✅ Implemented +**Date**: 2025-12-28 +**Priority**: High + +--- + +## Problem Statement + +Trinity was originally built for Claude Code only. To support cost optimization and provider flexibility, we needed to add Gemini CLI as an alternative runtime while maintaining feature parity. + +--- + +## Implementation Summary + +| Priority | Item | Status | Date | +|----------|------|--------|------| +| 1 | MCP injection for Gemini | ✅ Done | 2025-12-28 | +| 2 | Complete `configure_mcp` | ✅ Done | 2025-12-28 | +| 3 | Instruction file docs | ✅ Done | 2025-12-28 | +| 4 | Tool name mapping | ⏸️ Deferred | N/A | + +--- + +## 1. Instruction File Name + +### Decision: Keep `CLAUDE.md` (Option C) + +Both Claude Code and Gemini CLI read agent instructions from `CLAUDE.md`. + +**Rationale**: +- Backward compatibility with existing agents +- Both runtimes understand markdown instruction files +- Renaming would break existing templates without benefit + +Documented in [GEMINI_SUPPORT.md](../../GEMINI_SUPPORT.md). + +--- + +## 2. MCP Injection - Runtime Aware + +### Status: ✅ Implemented + +**Files Updated**: +- `docker/base-image/agent_server/services/trinity_mcp.py` + +**Implementation**: +```python +def inject_trinity_mcp_if_configured() -> bool: + """Inject Trinity MCP server - runtime aware.""" + runtime = os.getenv("AGENT_RUNTIME", "claude-code") + + if runtime == "gemini-cli": + return _inject_gemini_mcp(url, key) # gemini mcp add + else: + return _inject_claude_mcp(url, key) # .mcp.json +``` + +**New functions**: +- `_inject_claude_mcp()` - writes to `.mcp.json` +- `_inject_gemini_mcp()` - uses `gemini mcp add` command +- `configure_mcp_servers()` - shared runtime-aware MCP config +- `_configure_claude_mcp_servers()` - Claude-specific +- `_configure_gemini_mcp_servers()` - Gemini-specific + +--- + +## 3. Gemini MCP Configuration + +### Status: ✅ Implemented + +**Files Updated**: +- `docker/base-image/agent_server/services/gemini_runtime.py` + +`GeminiRuntime.configure_mcp()` now delegates to shared `_configure_gemini_mcp_servers()` function for consistency. + +--- + +## 4. Tool Name Mapping + +### Status: ⏸️ Deferred + +No action needed - both runtimes have equivalent built-in tools: + +| Generic Name | Claude Code | Gemini CLI | +|--------------|-------------|------------| +| filesystem | Read, Write, Edit | read_file, write_file, replace | +| shell | Bash | run_shell_command | +| web_search | WebSearch | google_web_search | +| memory | Task | save_memory | + +The `tools` array in templates is informational only. + +--- + +## Testing Checklist + +- [x] Gemini agent can use Trinity MCP (via `gemini mcp add`) +- [ ] Gemini agent can delegate to other agents (needs testing) +- [x] Custom MCP servers work with Gemini agents +- [x] Template MCP configurations apply correctly +- [ ] Vector memory (Chroma MCP) works with Gemini (needs testing) + +--- + +## Key Implementation Files + +| Layer | File | Purpose | +|-------|------|---------| +| **Runtime Adapter** | `docker/base-image/agent_server/services/runtime_adapter.py` | Abstract interface | +| **Gemini Runtime** | `docker/base-image/agent_server/services/gemini_runtime.py` | Gemini CLI execution | +| **Claude Runtime** | `docker/base-image/agent_server/services/claude_code.py` | Claude Code execution | +| **MCP Injection** | `docker/base-image/agent_server/services/trinity_mcp.py` | Runtime-aware MCP config | +| **Agent Config** | `src/backend/models.py` | `runtime` field in AgentConfig | +| **Agent Creation** | `src/backend/routers/agents.py` | Injects AGENT_RUNTIME env var | + +--- + +## Related Documentation + +- [Gemini Support Guide](../../GEMINI_SUPPORT.md) - User-facing setup guide +- [Trinity Compatible Agent Guide](../../TRINITY_COMPATIBLE_AGENT_GUIDE.md) - Template configuration +- [Multi-Runtime Architecture](../requirements.md#12-multi-runtime-support) - Requirements +- [Delegation Best Practices](../../MULTI_AGENT_SYSTEM_GUIDE.md#delegation-best-practices) - MCP vs runtime sub-agents + diff --git a/docs/memory/requirements.md b/docs/memory/requirements.md index 83e689ff7..a13e6c04e 100644 --- a/docs/memory/requirements.md +++ b/docs/memory/requirements.md @@ -1589,10 +1589,68 @@ Trinity implements infrastructure for "System 2" AI — Deep Agents that plan, r --- +### 12. Multi-Runtime Support + +#### 12.1 Runtime Adapter Architecture +- **Status**: ✅ Implemented (2025-12-28) +- **Priority**: Medium +- **Description**: Abstract interface for agent execution engines, enabling provider flexibility +- **Implementation**: + - `AgentRuntime` abstract base class in `runtime_adapter.py` + - `ClaudeCodeRuntime` wrapping existing Claude Code integration + - `GeminiRuntime` implementing Google's Gemini CLI + - Factory function `get_runtime()` for runtime selection +- **Acceptance Criteria**: + - [x] Runtime adapter interface defined + - [x] Claude Code wrapped in adapter + - [x] Gemini CLI implementation + - [x] Per-agent runtime selection + - [x] Template-based runtime configuration + +#### 12.2 Gemini CLI Integration +- **Status**: ✅ Implemented (2025-12-28) +- **Priority**: Medium +- **Description**: Support Google's Gemini CLI as alternative runtime +- **Benefits**: + - Free tier (60 req/min, 1,000/day) + - 1M token context window (5x Claude) + - Native Google Search integration +- **Configuration**: + ```yaml + # template.yaml + runtime: + type: gemini-cli + model: gemini-2.5-pro + ``` +- **Environment**: `GOOGLE_API_KEY` in `.env` +- **Acceptance Criteria**: + - [x] Gemini CLI installed in base image + - [x] MCP configuration translation + - [x] Cost/token tracking integration + - [x] Session continuity (--resume) + - [x] Headless task execution + +#### 12.3 Runtime Configuration in Templates +- **Status**: ✅ Implemented (2025-12-28) +- **Priority**: Medium +- **Description**: Runtime selection via template.yaml `runtime:` field +- **Schema**: + ```yaml + runtime: + type: claude-code | gemini-cli # Default: claude-code + model: string # Optional model override + ``` +- **Acceptance Criteria**: + - [x] template.yaml parsing extracts runtime config + - [x] AgentConfig model supports runtime fields + - [x] Environment variables passed to containers + - [x] Backward compatible (defaults to claude-code) + +--- + ## Out of Scope - Multi-tenant deployment (single org only) -- Custom model providers (Claude only) - Mobile application - Billing/payment integration - Agent marketplace diff --git a/docs/onboarding/00-welcome.md b/docs/onboarding/00-welcome.md new file mode 100644 index 000000000..73cc174e9 --- /dev/null +++ b/docs/onboarding/00-welcome.md @@ -0,0 +1,227 @@ +# Welcome to Trinity 🚀 + +**The Deep Agent Orchestration Platform** + +Trinity transforms the way you deploy and manage autonomous AI agents. Whether you're building a single intelligent assistant or orchestrating a network of specialized agents working together, Trinity provides the infrastructure you need. + +--- + +## What is Trinity? + +Trinity is a **sovereign infrastructure platform** for deploying, orchestrating, and governing autonomous AI systems. Unlike simple chatbots that react to user input, Trinity enables **Deep Agents** — AI systems that: + +- 🎯 **Plan independently** — Break down complex goals into executable tasks +- 🧠 **Remember persistently** — Store knowledge across sessions using vector databases +- 🤝 **Collaborate autonomously** — Delegate work to specialized sub-agents +- ⏰ **Run on schedules** — Execute workflows without human intervention +- 📊 **Learn from experience** — Build semantic memory over time +- 🔄 **Recover from failures** — Handle errors and continue execution +- 🔀 **Multi-runtime support** — Choose between Claude Code or Gemini CLI per agent + +--- + +## Who Should Use Trinity? + +Trinity is designed for: + +### Developers & Engineers +Build sophisticated AI applications with multi-agent workflows, automated pipelines, and intelligent automation. + +### Business Teams +Deploy AI assistants that manage your workflows: content creation, customer support, research coordination, data analysis. + +### Researchers & Innovators +Experiment with autonomous agent architectures, test new AI patterns, and push the boundaries of what's possible. + +--- + +## What Can You Build? + +### 🎨 Content Creation Systems +**Scenario**: Autonomous content pipeline +- **Research Agent** discovers trending topics and gathers sources +- **Writer Agent** creates drafts based on research findings +- **Editor Agent** reviews and refines content +- **Publisher Agent** distributes to social platforms + +### 💼 Business Operations Assistants +**Scenario**: Executive assistant network +- **Email Manager** triages inbox and drafts responses +- **Calendar Agent** schedules meetings and resolves conflicts +- **Document Manager** organizes files and extracts insights +- **Task Coordinator** tracks projects and sends reminders + +### 🔬 Research & Analysis Teams +**Scenario**: Multi-source research system +- **Data Collector** gathers information from APIs, documents, and web +- **Analyst Agent** processes data and identifies patterns +- **Synthesis Agent** creates comprehensive reports +- **Knowledge Agent** maintains searchable knowledge base + +### 🛠️ Development & DevOps +**Scenario**: Automated infrastructure management +- **Monitor Agent** tracks system health and performance +- **Alert Agent** detects and diagnoses issues +- **Deployment Agent** handles releases and rollbacks +- **Documentation Agent** keeps docs synchronized with code + +### 📊 Customer Intelligence +**Scenario**: Customer support automation +- **Inbox Agent** categorizes and routes support tickets +- **Research Agent** finds relevant knowledge base articles +- **Response Agent** drafts personalized replies +- **Analytics Agent** tracks satisfaction and identifies trends + +--- + +## Core Capabilities + +### 🔀 Multi-Runtime Support +Choose the best AI runtime for each agent: +- **Claude Code** — Anthropic's powerful reasoning model (200K-1M context) +- **Gemini CLI** — Google's fast, cost-effective model (1M context, free tier available) + +Mix and match runtimes in your agent fleet — they can communicate seamlessly via MCP. + +### 🐳 Isolated Agent Containers +Every agent runs in its own Docker container with dedicated resources, ensuring stability and security. + +### 📝 Template-Based Deployment +Create agents from pre-configured templates or build your own. Deploy in seconds with GitHub integration. + +### 🔄 Agent-to-Agent Communication +Agents can message each other, share files, and coordinate work through fine-grained permission controls. + +### 🗄️ Persistent Memory +Each agent has a Chroma vector database for semantic memory that survives restarts. + +### ⏰ Autonomous Scheduling +Set cron-based schedules for agents to run workflows automatically without human intervention. + +### 📁 Shared Folders +Agents share data via Docker volumes — perfect for exchanging files, state, and coordination data. + +### 🔑 Secure Credential Management +Store API keys and secrets centrally with hot-reload capability. No hardcoded credentials. + +### 📊 Real-Time Monitoring +Beautiful web dashboard shows agent activity, context usage, and inter-agent communications. + +### 🔧 Trinity MCP Server +External tools can orchestrate your agents via the Model Context Protocol — 16+ tools available. + +### 📈 OpenTelemetry Integration +Track costs, token usage, and performance metrics across your agent fleet. + +--- + +## The Trinity Philosophy + +### Start Simple, Scale Thoughtfully +Begin with a single agent. Only add more agents when you have clear evidence that specialization or parallelization would help. + +### Domain Logic in Agents, Infrastructure in Platform +Your agents focus on their domain expertise. Trinity handles orchestration, memory, scheduling, and communication. + +### Loose Coupling, High Cohesion +Agents should work independently but coordinate effectively. Design for failure — agents should handle missing data gracefully. + +### Observable and Debuggable +Every interaction is logged. Every state change is traceable. You should always know what your agents are doing and why. + +--- + +## Quick Start Journey + +Here's what your first few days with Trinity might look like: + +### Day 1: Setup & First Agent +- Install Trinity on your machine +- Create your first agent from a template +- Chat with your agent and see it respond +- Explore the dashboard and understand the UI + +### Day 2: Customize & Schedule +- Edit your agent's instructions (CLAUDE.md) +- Add API credentials for external services +- Create a schedule for autonomous execution +- Watch your agent run tasks automatically + +### Day 3: Multi-Agent System +- Deploy a second specialized agent +- Configure permissions for agent-to-agent communication +- Set up shared folders for data exchange +- Watch agents coordinate on a workflow + +### Week 2: Production System +- Build a complete multi-agent system for your use case +- Set up monitoring and alerts +- Configure production credentials +- Deploy autonomous workflows + +--- + +## What Makes Trinity Different? + +| Feature | Traditional Chatbots | Trinity Deep Agents | +|---------|---------------------|-------------------| +| **Execution Model** | Reactive (responds to input) | Autonomous (runs on schedules) | +| **Memory** | Ephemeral conversation history | Persistent vector database | +| **Task Handling** | Single-turn responses | Multi-step workflows with planning | +| **Collaboration** | Isolated | Agent-to-agent delegation | +| **Infrastructure** | Cloud service (black box) | Self-hosted (full control) | +| **Customization** | Limited to API parameters | Full template control | +| **Cost Model** | Per-token pricing | Your own API keys | + +--- + +## Learning Path + +### 📚 Recommended Reading Order + +1. **[Getting Started Guide](01-getting-started.md)** — Install Trinity and create your first agent +2. **[Use Case Scenarios](02-use-case-scenarios.md)** — See practical examples of what you can build +3. **[Common Workflows](03-common-workflows.md)** — Learn day-to-day operations +4. **[Troubleshooting Guide](04-troubleshooting.md)** — Solve common issues + +### 📖 Deep Dives + +For advanced topics, explore the main documentation: +- **[Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md)** — Build custom agent templates +- **[Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md)** — Design complex multi-agent systems +- **[Development Workflow](../DEVELOPMENT_WORKFLOW.md)** — Contribute to Trinity +- **[Deployment Guide](../DEPLOYMENT.md)** — Production deployment + +--- + +## Community & Support + +### 💬 Get Help +- **GitHub Issues**: Report bugs and request features +- **Documentation**: Comprehensive guides for every feature +- **API Reference**: Interactive API docs at `http://localhost:8000/docs` + +### 🤝 Contribute +Trinity is open source under the Polyform Noncommercial License. We welcome contributions! + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines. + +### 🏢 Commercial Use +For commercial licensing, contact hello@ability.ai + +--- + +## What's Next? + +Ready to get started? Head over to the **[Getting Started Guide](01-getting-started.md)** to install Trinity and create your first agent. + +Or jump straight to **[Use Case Scenarios](02-use-case-scenarios.md)** to see what's possible and get inspired. + +--- + +**Welcome to the future of autonomous AI. Let's build something amazing together.** 🚀 + +--- + +*Built by [Ability AI](https://ability.ai)* + diff --git a/docs/onboarding/01-getting-started.md b/docs/onboarding/01-getting-started.md new file mode 100644 index 000000000..925382cfb --- /dev/null +++ b/docs/onboarding/01-getting-started.md @@ -0,0 +1,453 @@ +# Getting Started with Trinity + +This guide will walk you through installing Trinity, creating your first agent, and understanding the core concepts. By the end, you'll have a working Trinity installation and a running agent. + +--- + +## Prerequisites + +Before you begin, make sure you have: + +- [ ] **Docker & Docker Compose v2+** installed ([Install Docker](https://docs.docker.com/get-docker/)) +- [ ] **At least one AI API Key**: + - **Anthropic API Key** for Claude agents ([Get API Key](https://console.anthropic.com/)) + - **Google API Key** for Gemini agents ([Get API Key](https://aistudio.google.com/apikey)) — *Free tier available!* +- [ ] **10GB+ free disk space** for images and agent containers +- [ ] **Basic command line skills** (running commands, editing files) + +### System Requirements + +- **OS**: Linux, macOS, or Windows with WSL2 +- **RAM**: 8GB minimum, 16GB recommended +- **CPU**: 4+ cores recommended + +> 💡 **Tip**: You can start with just Gemini (free tier) to try Trinity without any costs! + +--- + +## Installation + +### Option 1: Quick Install (Recommended) + +Run the one-line installer: + +```bash +curl -fsSL https://raw.githubusercontent.com/abilityai/trinity/main/install.sh | bash +``` + +This will: +1. Clone the Trinity repository +2. Create `.env` file from template +3. Build the base agent image +4. Start all services + +**Time**: ~10-15 minutes depending on your connection speed. + +### Option 2: Manual Installation + +If you prefer manual control: + +```bash +# 1. Clone the repository +git clone https://github.com/abilityai/trinity.git +cd trinity + +# 2. Copy environment template +cp .env.example .env + +# 3. Generate a secure secret key +openssl rand -hex 32 + +# 4. Edit .env and set at minimum: +# SECRET_KEY= +# ADMIN_PASSWORD= +nano .env + +# 5. Build the base agent image (one-time, takes ~5 minutes) +./scripts/deploy/build-base-image.sh + +# 6. Start all services +./scripts/deploy/start.sh +``` + +### Verify Installation + +Check that all services are running: + +```bash +docker compose ps +``` + +You should see: +- `trinity-backend` (running) +- `trinity-frontend` (running) +- `trinity-redis` (running) +- `trinity-audit-logger` (running) +- `trinity-mcp-server` (running) +- `trinity-otel-collector` (running, optional) + +--- + +## First-Time Setup + +### Step 1: Access the Web UI + +Open your browser and navigate to: + +``` +http://localhost:3000 +``` + +You'll be redirected to the **Setup Wizard** on first launch. + +### Step 2: Create Admin Account + +1. **Set Admin Password** + - Enter a strong password (minimum 8 characters) + - Confirm the password + - Click **Create Account** + +2. **Login** + - Username: `admin` + - Password: (the password you just created) + - Click **Sign In** + +### Step 3: Configure API Keys + +After logging in, configure your API keys in the `.env` file: + +```bash +# For Claude Code agents +ANTHROPIC_API_KEY=sk-ant-api03-... + +# For Gemini CLI agents (free tier available!) +GOOGLE_API_KEY=AIza... +``` + +You need at least one of these configured. You can use both to mix Claude and Gemini agents. + +> 💡 **Tip**: Gemini's free tier is great for experimentation. Claude is better for complex reasoning tasks. + +--- + +## Create Your First Agent + +Now let's create your first agent! + +### Step 1: Navigate to Agent Creation + +1. Click **Agents** in the navigation menu +2. Click the **+ Create Agent** button + +### Step 2: Configure Agent + +Fill in the agent details: + +- **Name**: `my-first-agent` (lowercase, hyphens allowed) +- **Template**: Select from available templates: + - `Blank Agent` — Empty Claude Code agent (default) + - `Test Gemini Agent` — Gemini CLI agent for testing + - Or any custom template from `config/agent-templates/` + +Click **Create Agent**. + +> 💡 **Runtime Selection**: Templates define which runtime (Claude or Gemini) the agent uses. Check the template's `runtime` field in its `template.yaml`. + +### Step 3: Wait for Agent to Start + +Trinity will: +1. Create a Docker container for your agent +2. Inject platform capabilities (vector memory, planning tools, etc.) +3. Start the Claude Code agent server +4. Show status updates in the UI + +**Time**: ~30-60 seconds for first agent (downloads Claude image). + +### Step 4: Chat with Your Agent + +Once the agent shows **Status: Running**: + +1. Click on your agent in the list +2. Go to the **Chat** tab +3. Type a message: `Hello! What can you do?` +4. Press Enter or click **Send** + +Your agent should respond, explaining its capabilities! + +--- + +## Understanding the UI + +Let's explore the Trinity web interface. + +### Dashboard (Home Page) + +The **Collaboration Dashboard** at `/` shows: + +- 🟢 **Agent Nodes** — Visual representation of all your agents +- 🔗 **Connections** — Animated lines show agent-to-agent communication +- 📊 **Context Bars** — See how much of the context window each agent is using +- 🔴 **Status Indicators** — Active/Idle/Offline states + +**Try This**: Drag agents around to organize them visually. The layout persists. + +### Agents Page + +The **Agents** page lists all your agents with: + +- Status (running/stopped/error) +- Resource usage +- Last activity timestamp +- Quick actions (start/stop/delete) + +### Agent Detail View + +Click on any agent to see: + +- **Chat** — Talk with your agent +- **Activity** — See what tools the agent is using +- **Files** — Browse the agent's workspace +- **Logs** — View container logs for debugging +- **Schedules** — Set up cron-based automation +- **Permissions** — Control which agents can communicate +- **Shared Folders** — Configure file sharing +- **Plans** — View persistent task plans (if agent creates them) + +--- + +## Core Concepts + +### Agents + +An **agent** is an AI runtime (Claude Code or Gemini CLI) running in a Docker container. Each agent: +- Has its own isolated filesystem +- Gets dedicated CPU and memory resources +- Can have custom instructions (CLAUDE.md) +- Can access different tools via MCP servers +- Has persistent storage for memory and files +- Uses a specific **runtime** (Claude or Gemini) defined by its template + +**Runtime Comparison**: +| Feature | Claude Code | Gemini CLI | +|---------|-------------|------------| +| Context Window | 200K (up to 1M) | 1M tokens | +| Free Tier | No | Yes | +| Best For | Complex reasoning | Fast, cost-effective tasks | +| Model Selector | Sonnet, Opus, Haiku | Gemini 2.5/3 Pro/Flash | + +### Templates + +A **template** defines an agent's behavior and configuration. Templates include: +- `template.yaml` — Metadata (name, resources, credentials) +- `CLAUDE.md` — Instructions that define agent behavior +- `.mcp.json.template` — MCP server configurations +- `.env.example` — Documentation of required credentials + +Trinity includes a `default` template, and you can use templates from GitHub repositories. + +### Credentials + +**Credentials** are API keys and secrets your agents need to access external services. Trinity: +- Stores credentials securely in Redis (encrypted) +- Injects them into agents at creation time +- Supports hot-reload (update credentials without restarting) +- Never exposes secrets in logs or UI + +### Schedules + +**Schedules** allow agents to run autonomously without human input. You define: +- Cron expression (e.g., `0 9 * * *` for 9 AM daily) +- Message to send to the agent +- Timezone +- Enabled/disabled state + +The agent receives the scheduled message and executes the workflow. + +### Permissions + +**Permissions** control agent-to-agent communication. By default, agents cannot see or talk to each other. You explicitly grant permissions to enable collaboration. + +### Shared Folders + +**Shared folders** enable file-based communication between agents: +- Each agent has `/home/developer/shared-out/` (their output) +- Other agents can read this at `/home/developer/shared-in/{agent-name}/` +- Perfect for exchanging data, state, or coordination files + +--- + +## Try These Tasks + +Here are some hands-on exercises to get familiar with Trinity. + +### Task 1: View Agent Activity + +1. Chat with your agent: "Tell me a joke" +2. Go to the **Activity** tab +3. See the tool calls the agent made (token counting, chat history, etc.) + +### Task 2: Explore the Filesystem + +1. Go to the **Files** tab +2. Browse the agent's workspace +3. Look for `.trinity/` directory (platform-injected docs) +4. Open `CLAUDE.md` to see the agent's instructions + +### Task 3: Check Logs + +1. Go to the **Logs** tab +2. See the container startup logs +3. Try making the agent do something, then refresh logs +4. Use logs for debugging when things go wrong + +### Task 4: Create a Schedule + +1. Go to the **Schedules** tab +2. Click **+ Create Schedule** +3. Configure: + - Name: `Daily Greeting` + - Cron: `0 9 * * *` (9 AM daily) + - Message: `Good morning! Summarize your tasks for today.` + - Timezone: `America/Los_Angeles` (or your timezone) + - Enabled: ✅ +4. Click **Create** +5. Test it immediately with **Trigger Now** button + +--- + +## What's Auto-Injected? + +When your agent starts, Trinity automatically injects: + +### 1. Vector Memory (Chroma) +- Database at `/home/developer/vector-store/` +- MCP tools for storing and querying semantic memory +- Documentation at `.trinity/vector-memory.md` + +### 2. Planning System +- Slash commands: `/trinity-plan-create`, `/trinity-plan-update`, etc. +- Directories: `plans/active/`, `plans/archive/` +- Documentation at `.trinity/prompt.md` + +### 3. Trinity MCP Tools +- Tools to list, chat with, and manage other agents +- Requires permissions to use +- Documented in appended section of `CLAUDE.md` + +### 4. Platform Documentation +- `.trinity/prompt.md` — Planning instructions +- `.trinity/vector-memory.md` — Memory usage guide + +**Important**: Your custom templates should NOT include this content. Trinity injects it automatically. + +--- + +## Common First-Time Issues + +### Issue: "Services failed to start" + +**Solution**: Check Docker is running and you have enough disk space. + +```bash +docker info +df -h +``` + +### Issue: "Agent stuck in 'starting' state" + +**Solution**: Check logs for errors: + +```bash +docker logs agent-my-first-agent +``` + +Common causes: +- Anthropic API key not set or invalid +- Network issues downloading Claude image +- Insufficient memory + +### Issue: "Permission denied" errors + +**Solution**: Make sure you have Docker permissions: + +```bash +# Add yourself to docker group (Linux) +sudo usermod -aG docker $USER +newgrp docker +``` + +### Issue: "Agent responds very slowly" + +**Solution**: This is normal for the first message. Subsequent messages are faster. If consistently slow: +- Check CPU usage: `docker stats` +- Check API key is valid +- Try stopping other agents to free resources + +--- + +## Next Steps + +Congratulations! You now have Trinity running and understand the basics. + +### Ready to Build Something Real? + +Continue to **[Use Case Scenarios](02-use-case-scenarios.md)** to see practical examples of what you can build. + +### Want to Customize Your Agent? + +Learn about agent templates in the **[Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md)**. + +### Building Multi-Agent Systems? + +Check out the **[Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md)** for advanced patterns. + +### Need Help? + +- **Troubleshooting**: [04-troubleshooting.md](04-troubleshooting.md) +- **API Reference**: http://localhost:8000/docs +- **GitHub Issues**: https://github.com/abilityai/trinity/issues + +--- + +## Quick Reference + +### Useful Commands + +```bash +# Start Trinity +./scripts/deploy/start.sh + +# Stop Trinity +./scripts/deploy/stop.sh + +# View logs +docker compose logs -f backend +docker compose logs -f frontend +docker logs agent-my-first-agent + +# Rebuild after changes +docker compose build backend +docker compose up -d backend + +# Check agent status +docker ps | grep agent- +``` + +### Important URLs + +- **Web UI**: http://localhost:3000 +- **API**: http://localhost:8000 +- **API Docs**: http://localhost:8000/docs +- **MCP Server**: http://localhost:8080/mcp + +### Important Directories + +- **Agent configs**: `./config/agent-templates/` +- **Trinity data**: Docker volume `trinity-data` +- **Backend code**: `./src/backend/` +- **Frontend code**: `./src/frontend/` + +--- + +**You're ready to go! Head to the next guide to explore real use cases.** 🎉 + diff --git a/docs/onboarding/02-use-case-scenarios.md b/docs/onboarding/02-use-case-scenarios.md new file mode 100644 index 000000000..a6b20fb47 --- /dev/null +++ b/docs/onboarding/02-use-case-scenarios.md @@ -0,0 +1,865 @@ +# Trinity Use Case Scenarios + +This guide presents practical, real-world scenarios showing how to use Trinity to build autonomous AI systems. Each scenario includes the problem, solution architecture, step-by-step implementation, and expected outcomes. + +--- + +## Table of Contents + +1. [Scenario 1: Personal Research Assistant](#scenario-1-personal-research-assistant) +2. [Scenario 2: Social Media Content Automation](#scenario-2-social-media-content-automation) +3. [Scenario 3: Email Management & Response System](#scenario-3-email-management--response-system) +4. [Scenario 4: Document Processing Pipeline](#scenario-4-document-processing-pipeline) +5. [Scenario 5: Development Team Assistant](#scenario-5-development-team-assistant) +6. [Scenario 6: Customer Support Triage System](#scenario-6-customer-support-triage-system) + +--- + +## Scenario 1: Personal Research Assistant + +### The Problem + +You need to stay up-to-date on industry topics, but manually reading articles, watching videos, and summarizing findings takes hours each week. You want an agent that autonomously researches topics and creates digestible summaries. + +### The Solution + +A single agent that runs on a daily schedule to: +1. Monitor RSS feeds and news sources +2. Read and summarize relevant articles +3. Store summaries in a searchable knowledge base +4. Create a daily digest email + +### Implementation + +#### Step 1: Create the Agent + +```yaml +# Create from default template +Name: research-assistant +Template: local:default +``` + +#### Step 2: Customize Instructions + +Edit the agent's `CLAUDE.md` to include: + +```markdown +# Research Assistant + +## Purpose +You are a research assistant that monitors topics of interest and creates summaries. + +## Topics to Monitor +- Artificial Intelligence +- Deep Learning +- Agent Systems +- Productivity Tools + +## Daily Workflow +1. Check RSS feeds for new articles +2. Read and summarize the most relevant ones (top 5) +3. Store summaries in vector memory using MCP tools +4. Create a daily digest markdown file in workspace/digests/ + +## Summary Format +For each article: +- Title and URL +- 3-4 sentence summary +- Key takeaways (bullet points) +- Relevance score (1-10) +``` + +#### Step 3: Add MCP Tools + +Create `.mcp.json.template` with RSS and web browsing tools: + +```json +{ + "mcpServers": { + "fetch": { + "command": "uvx", + "args": ["mcp-server-fetch"] + } + } +} +``` + +#### Step 4: Create Schedule + +In the Trinity UI: +- Go to agent → Schedules +- Create schedule: + - Name: `Daily Research` + - Cron: `0 8 * * *` (8 AM daily) + - Message: `Run your daily research workflow: check feeds, summarize articles, and create digest.` + - Timezone: Your timezone + - Enabled: ✅ + +#### Step 5: Test + +Trigger the schedule manually to verify: +1. Agent reads sources +2. Summarizes articles +3. Stores in vector memory +4. Creates digest file + +### Expected Outcome + +Every morning at 8 AM: +- Agent runs autonomously +- Processes 5-10 articles +- Stores summaries in vector memory +- Creates `workspace/digests/YYYY-MM-DD.md` + +You can chat with the agent anytime to ask: "What did you learn about X yesterday?" + +### Advanced: Query Your Knowledge Base + +Chat with the agent: + +``` +User: "What have we learned about transformer models in the past week?" + +Agent: [Uses vector memory MCP to query summaries, synthesizes response] +``` + +--- + +## Scenario 2: Social Media Content Automation + +### The Problem + +You need to maintain an active social media presence, but creating, scheduling, and posting content daily is time-consuming. You want automated content creation that still maintains quality and brand voice. + +### The Solution + +A multi-agent system with specialized roles: +- **Content Creator Agent**: Generates post ideas and drafts +- **Scheduler Agent**: Plans posting times and manages calendar +- **Publisher Agent**: Posts to platforms at scheduled times + +### Implementation + +#### Step 1: Deploy Multi-Agent System + +Create a system manifest `content-system.yaml`: + +```yaml +name: social-content +description: Automated social media content system + +agents: + scheduler: + template: local:default + resources: + cpu: "1" + memory: "2g" + folders: + expose: true + consume: true + schedules: + - name: weekly-planning + cron: "0 9 * * 1" # Monday at 9 AM + message: "Plan this week's content schedule" + enabled: true + + creator: + template: local:default + resources: + cpu: "2" + memory: "4g" + folders: + expose: true + consume: true + schedules: + - name: daily-creation + cron: "0 10 * * *" # Daily at 10 AM + message: "Check schedule and create today's content" + enabled: true + + publisher: + template: local:default + resources: + cpu: "1" + memory: "2g" + folders: + expose: true + consume: true + schedules: + - name: publishing-check + cron: "*/30 * * * *" # Every 30 minutes + message: "Check for content ready to publish" + enabled: true + +permissions: + preset: full-mesh +``` + +Deploy via API: + +```bash +curl -X POST http://localhost:8000/api/systems/deploy \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"manifest\": \"$(cat content-system.yaml)\"}" +``` + +#### Step 2: Configure Scheduler Agent + +Customize `CLAUDE.md` for scheduler: + +```markdown +# Content Scheduler + +## Purpose +Plan weekly content schedule and coordinate with creator/publisher. + +## Weekly Planning Workflow +1. Review past week's performance (check shared-in/publisher/stats.json) +2. Create content calendar for upcoming week +3. Write schedule.json to shared-out/ +4. Notify creator agent of new schedule + +## Schedule Format +```json +{ + "week_of": "2025-12-23", + "posts": [ + { + "id": "post-001", + "scheduled_time": "2025-12-23T14:00:00Z", + "topic": "AI trends", + "platform": "twitter", + "status": "pending" + } + ] +} +``` +``` + +#### Step 3: Configure Creator Agent + +Customize `CLAUDE.md` for creator: + +```markdown +# Content Creator + +## Purpose +Generate engaging social media posts based on schedule. + +## Daily Workflow +1. Read schedule from shared-in/scheduler/schedule.json +2. Find posts assigned to today +3. Generate content for each post +4. Save to shared-out/content/{post-id}.json + +## Content Guidelines +- Keep tweets under 280 characters +- Include relevant hashtags +- Maintain professional but friendly tone +- Include call-to-action when appropriate + +## Output Format +```json +{ + "post_id": "post-001", + "content": "Post text here...", + "hashtags": ["#AI", "#TechTrends"], + "created_at": "2025-12-23T10:15:00Z", + "status": "ready" +} +``` +``` + +#### Step 4: Configure Publisher Agent + +Add Twitter MCP credentials: + +```json +{ + "mcpServers": { + "twitter": { + "command": "uvx", + "args": ["twitter-mcp"], + "env": { + "TWITTER_API_KEY": "${TWITTER_API_KEY}", + "TWITTER_API_SECRET": "${TWITTER_API_SECRET}", + "TWITTER_ACCESS_TOKEN": "${TWITTER_ACCESS_TOKEN}", + "TWITTER_ACCESS_SECRET": "${TWITTER_ACCESS_SECRET}" + } + } + } +} +``` + +Store credentials via Trinity UI → Settings → Credentials. + +#### Step 5: Test the System + +1. Trigger scheduler manually: Creates weekly plan +2. Trigger creator manually: Generates content +3. Trigger publisher manually: Posts to Twitter (test mode first!) + +### Expected Outcome + +Weekly automation: +- **Monday 9 AM**: Scheduler plans the week +- **Daily 10 AM**: Creator generates content for scheduled posts +- **Every 30 min**: Publisher checks for posts ready to publish and posts them + +### Monitoring + +- Dashboard shows all three agents and their connections +- Check shared folders to see data flow +- View Activity tab for each agent to see their work + +--- + +## Scenario 3: Email Management & Response System + +### The Problem + +Your inbox gets 50+ emails daily. Many are routine questions that could be answered automatically. You want an agent that triages emails, drafts responses, and flags items needing your attention. + +### The Solution + +Single agent with Gmail access that: +1. Monitors inbox on schedule +2. Categorizes emails (urgent/routine/spam) +3. Drafts responses for routine emails +4. Creates summary report of items needing attention + +### Implementation + +#### Step 1: Create Agent + +```yaml +Name: email-assistant +Template: local:default +``` + +#### Step 2: Set Up Gmail Access + +Create `.mcp.json.template`: + +```json +{ + "mcpServers": { + "google": { + "command": "uvx", + "args": ["mcp-server-google-gmail"], + "env": { + "GOOGLE_CLIENT_ID": "${GOOGLE_CLIENT_ID}", + "GOOGLE_CLIENT_SECRET": "${GOOGLE_CLIENT_SECRET}", + "GOOGLE_REFRESH_TOKEN": "${GOOGLE_REFRESH_TOKEN}" + } + } + } +} +``` + +Follow [Google OAuth Setup Guide](../GOOGLE_OAUTH_SETUP.md) to get credentials. + +#### Step 3: Customize Instructions + +```markdown +# Email Assistant + +## Purpose +Monitor Gmail inbox and handle routine emails automatically. + +## Email Categories +1. **Urgent**: Requires immediate attention → Flag for human review +2. **Routine**: Can be answered with templates → Draft response +3. **Info**: FYI only → Mark as read +4. **Spam**: Obvious spam → Archive + +## Hourly Workflow +1. Fetch unread emails from last hour +2. For each email: + - Categorize using the above rules + - If routine: draft response using appropriate template + - If urgent: add to summary report +3. Write summary report to workspace/email-reports/YYYY-MM-DD-HH.md +4. Store email patterns in vector memory for learning + +## Response Templates + +### Meeting Request +"Thanks for reaching out! I'd be happy to meet. Please use my calendar link to find a time that works: [link]" + +### Information Request +"Thanks for your question about [topic]. Here's the information you requested: [details]" + +### Out of Office +"Thanks for your email. I'm currently [status] and will respond within [timeframe]." + +## Don't Auto-Respond To +- Emails from CEO or direct manager +- Emails containing "urgent" or "ASAP" +- First-time senders (unknown email addresses) +``` + +#### Step 4: Create Schedule + +``` +Name: Email Check +Cron: 0 * * * * # Every hour +Message: Run your hourly email triage workflow +Enabled: ✅ +``` + +#### Step 5: Review Workflow + +Each hour: +1. Check agent's workspace: `workspace/email-reports/` +2. Review flagged urgent items +3. Approve drafted responses before sending (or configure auto-send for trusted patterns) + +### Expected Outcome + +- **60% of routine emails** handled automatically +- **Urgent emails** flagged within 1 hour +- **Daily summary** of what the agent handled +- **Learning over time**: Vector memory improves categorization + +### Safety Features + +Configure the agent to: +- Never auto-send without human approval (until you trust it) +- Save drafts only, you review and send +- Flag uncertain emails for review +- Log all actions for audit trail + +--- + +## Scenario 4: Document Processing Pipeline + +### The Problem + +Your team receives documents (PDFs, contracts, reports) that need to be: +1. Categorized and filed +2. Key information extracted +3. Summarized for quick review +4. Searchable in a knowledge base + +Doing this manually takes hours per document. + +### The Solution + +Multi-agent pipeline: +- **Intake Agent**: Watches folder for new documents +- **Processor Agent**: Extracts text, categorizes, extracts metadata +- **Summarizer Agent**: Creates executive summaries +- **Indexer Agent**: Stores in vector database for searching + +### Implementation + +#### Step 1: Deploy System + +```yaml +name: doc-pipeline +description: Automated document processing + +agents: + intake: + template: local:default + folders: + expose: true + schedules: + - name: check-inbox + cron: "*/5 * * * *" # Every 5 minutes + message: "Check for new documents" + + processor: + template: local:default + folders: + expose: true + consume: true + schedules: + - name: process-queue + cron: "*/10 * * * *" + message: "Process queued documents" + + summarizer: + template: local:default + folders: + expose: true + consume: true + schedules: + - name: summarize-queue + cron: "*/10 * * * *" + message: "Summarize processed documents" + + indexer: + template: local:default + folders: + consume: true + schedules: + - name: index-queue + cron: "*/10 * * * *" + message: "Index completed summaries" + +permissions: + preset: orchestrator-workers +``` + +#### Step 2: Configure Data Flow + +**Intake** writes to `shared-out/queue/`: +```json +{ + "document_id": "doc-001", + "filename": "contract.pdf", + "received_at": "2025-12-23T10:00:00Z", + "status": "queued" +} +``` + +**Processor** reads queue, extracts data, writes to `shared-out/processed/`: +```json +{ + "document_id": "doc-001", + "category": "contract", + "parties": ["Company A", "Company B"], + "date": "2025-12-15", + "extracted_text": "...", + "status": "processed" +} +``` + +**Summarizer** reads processed, creates summaries, writes to `shared-out/summaries/`: +```json +{ + "document_id": "doc-001", + "summary": "Service agreement between Company A and B...", + "key_points": ["Term: 12 months", "Value: $50k", "Renewal: automatic"], + "status": "summarized" +} +``` + +**Indexer** reads summaries and stores in vector memory for searching. + +#### Step 3: Set Up Document Upload + +Option 1: Manual upload to agent workspace +```bash +docker cp document.pdf agent-doc-pipeline-intake:/home/developer/workspace/inbox/ +``` + +Option 2: Watch external folder (mount volume in docker-compose) +Option 3: API endpoint for document upload + +#### Step 4: Query the System + +Chat with indexer agent: +``` +User: "Find all contracts from 2025 worth over $25k" + +Agent: [Queries vector memory, returns results] +``` + +### Expected Outcome + +Pipeline processes documents in 15-30 minutes: +- **Minute 0**: Document uploaded +- **Minute 5**: Intake detects and queues +- **Minute 10**: Processor extracts and categorizes +- **Minute 20**: Summarizer creates summary +- **Minute 30**: Indexer stores in searchable database + +### Scaling + +For higher volume: +- Reduce schedule intervals +- Increase agent resources +- Add multiple processor agents for parallel processing + +--- + +## Scenario 5: Development Team Assistant + +### The Problem + +Your dev team needs help with: +- Monitoring GitHub PRs and issues +- Running tests and reporting results +- Updating documentation when code changes +- Tracking deployment status + +### The Solution + +Single agent with GitHub and CI/CD access that autonomously monitors and assists. + +### Implementation + +#### Step 1: Create Agent + +```yaml +Name: dev-assistant +Template: local:default +Resources: + cpu: "2" + memory: "4g" +``` + +#### Step 2: Add GitHub Access + +```json +{ + "mcpServers": { + "github": { + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-github"], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PAT}" + } + } + } +} +``` + +#### Step 3: Configure Monitoring + +```markdown +# Dev Assistant + +## Purpose +Monitor GitHub repository and assist development team. + +## Daily Workflow (9 AM) +1. Check for new PRs +2. For each PR: + - Verify tests passed + - Check for obvious issues + - Add comment with suggestions if needed +3. Check open issues +4. Identify stale issues (no activity > 30 days) +5. Create daily summary report + +## Weekly Workflow (Monday 9 AM) +1. Summarize week's activity +2. Identify documentation gaps +3. Create list of improvement suggestions +4. Generate weekly report + +## What to Flag +- PRs without tests +- PRs failing CI +- Issues without labels +- Security vulnerabilities +- Outdated dependencies +``` + +#### Step 4: Create Schedules + +Daily check: +``` +Cron: 0 9 * * * +Message: Run daily GitHub monitoring workflow +``` + +Weekly report: +``` +Cron: 0 9 * * 1 +Message: Generate weekly team report +``` + +### Expected Outcome + +Daily: +- Team gets report of PR status +- Agents flags issues needing attention +- Documentation gaps identified + +Weekly: +- Comprehensive activity summary +- Trend analysis +- Improvement recommendations + +--- + +## Scenario 6: Customer Support Triage System + +### The Problem + +Support tickets come in via email, chat, and forms. Many are duplicate questions or can be answered with existing knowledge base articles. Support team is overwhelmed. + +### The Solution + +Multi-agent system: +- **Intake Agent**: Receives tickets from all channels +- **Classifier Agent**: Categories by type and urgency +- **Response Agent**: Drafts responses using knowledge base +- **Escalation Agent**: Routes complex issues to humans + +### Implementation + +#### Step 1: Deploy System + +```yaml +name: support-triage +description: Customer support automation + +agents: + intake: + template: local:default + schedules: + - name: check-channels + cron: "*/2 * * * *" # Every 2 minutes + message: "Check all channels for new tickets" + + classifier: + template: local:default + schedules: + - name: classify-queue + cron: "*/3 * * * *" + message: "Classify pending tickets" + + responder: + template: local:default + schedules: + - name: respond-queue + cron: "*/5 * * * *" + message: "Draft responses for classified tickets" + + escalation: + template: local:default + schedules: + - name: route-complex + cron: "*/10 * * * *" + message: "Route complex issues to humans" + +permissions: + preset: orchestrator-workers +``` + +#### Step 2: Build Knowledge Base + +Upload existing support articles to a knowledge base agent: + +```markdown +# Knowledge Base + +## Common Issues + +### Issue: Login Problems +**Solution**: Reset password via link, clear cookies, check email for 2FA code + +### Issue: Payment Failed +**Solution**: Verify card details, check billing address, try different payment method +... +``` + +Store articles in vector memory for semantic search. + +#### Step 3: Configure Classification + +```markdown +# Classifier Agent + +## Categories +1. **Technical Issue** - Product bug or technical problem +2. **Billing** - Payment, invoices, subscription +3. **Feature Request** - New feature or enhancement +4. **How-To** - Usage questions +5. **Bug Report** - Detailed bug report + +## Urgency Levels +- **P0 Critical**: Service down, data loss, security issue +- **P1 High**: Major feature broken, affects multiple users +- **P2 Medium**: Feature partially broken, workaround exists +- **P3 Low**: Minor issue, feature request + +## Auto-Resolve Criteria +- Duplicate of closed ticket +- Already answered in knowledge base +- User error with clear solution +``` + +#### Step 4: Configure Response Agent + +```markdown +# Response Agent + +## Purpose +Draft helpful, friendly responses using knowledge base. + +## Workflow +1. Read classified tickets from shared-in/classifier/ +2. For each ticket with classification: + - Query knowledge base using vector memory + - Draft response based on matching articles + - Add response to ticket in shared-out/responses/ +3. Flag for human review if confidence < 80% + +## Response Template +"Hi [name], + +Thanks for contacting us about [issue]. + +[Solution based on knowledge base] + +[Additional helpful info] + +Let me know if this resolves your issue! + +Best regards, +Support Team" +``` + +### Expected Outcome + +- **50-70% of tickets** auto-resolved with knowledge base articles +- **Response time**: 2-5 minutes for common issues +- **Human agents** focus on complex, high-value issues +- **Learning**: System improves as knowledge base grows + +### Metrics to Track + +- Resolution rate (auto vs. manual) +- Average response time +- Customer satisfaction (for auto-responses) +- Escalation rate +- Knowledge base coverage + +--- + +## Choosing the Right Scenario + +| Your Need | Best Scenario | Agents Needed | +|-----------|---------------|---------------| +| Stay informed | Research Assistant | 1 | +| Social presence | Content Automation | 3 | +| Email overload | Email Management | 1 | +| Document chaos | Document Pipeline | 4 | +| Dev team help | Dev Assistant | 1 | +| Support tickets | Support Triage | 4 | + +## Next Steps + +Ready to implement one of these scenarios? Here's your path: + +1. **Start Simple**: Pick the scenario that matches your need +2. **Single Agent First**: Build and test with one agent +3. **Add Complexity**: Add more agents only when needed +4. **Monitor & Iterate**: Use Trinity dashboard to observe and improve + +Continue to **[Common Workflows](03-common-workflows.md)** to learn day-to-day operations. + +--- + +## Contributing Your Scenario + +Built something awesome? Share it! + +1. Document your use case +2. Share agent templates +3. Submit PR to add to this guide + +Community scenarios help everyone build better systems. + + + + + diff --git a/docs/onboarding/03-common-workflows.md b/docs/onboarding/03-common-workflows.md new file mode 100644 index 000000000..5eb18a9a5 --- /dev/null +++ b/docs/onboarding/03-common-workflows.md @@ -0,0 +1,740 @@ +# Common Workflows + +This guide covers the day-to-day operations you'll perform when working with Trinity. These are the tasks you'll do regularly as you manage your agents and systems. + +--- + +## Table of Contents + +1. [Daily Operations](#daily-operations) +2. [Agent Management](#agent-management) +3. [Credential Management](#credential-management) +4. [Schedule Management](#schedule-management) +5. [Monitoring & Debugging](#monitoring--debugging) +6. [Multi-Agent Coordination](#multi-agent-coordination) +7. [Backup & Recovery](#backup--recovery) +8. [Performance Optimization](#performance-optimization) + +--- + +## Daily Operations + +### Morning Routine: Check Agent Health + +**Time**: 2-3 minutes + +1. **Open Dashboard** + ``` + http://localhost:3000 + ``` + +2. **Visual Health Check** + - All agents showing green (running)? + - Any red indicators (stopped/error)? + - Context bars not at 100%? + +3. **Check Recent Activity** + - Click **Activity** in navigation + - Filter by last 24 hours + - Look for error patterns + +4. **Review Scheduled Tasks** + - Did scheduled tasks run successfully? + - Check execution history for any failures + +**Red Flags to Watch For**: +- 🔴 Agent stuck in "starting" state +- 🔴 Schedule showing repeated failures +- 🔴 Context bar at 95%+ (nearing limit) +- 🔴 No activity from an agent that should be active + +### Evening Routine: Review Results + +**Time**: 5-10 minutes + +1. **Check Agent Outputs** + - Navigate to each agent → Files tab + - Look for new files in expected locations + - Review shared-out folders for coordination data + +2. **Read Agent Summaries** + - Many agents create daily summaries + - Check `workspace/reports/` or similar directories + +3. **Plan Tomorrow** + - Any schedule adjustments needed? + - Any credentials expiring soon? + - Any agents that should be paused? + +--- + +## Agent Management + +### Creating a New Agent + +**Scenario**: You need a new specialized agent. + +#### Via Web UI + +1. Click **Agents** → **+ Create Agent** + +2. Fill in details: + - **Name**: `my-new-agent` (lowercase, hyphens only) + - **Display Name**: `My New Agent` (optional) + - **Template**: Choose from: + - `local:default` — Basic agent + - `github:owner/repo` — From GitHub + - `local:custom-template` — Your custom template + +3. Click **Create** + +4. Wait for status to show **Running** (~30-60 seconds) + +#### Via API + +```bash +curl -X POST http://localhost:8000/api/agents \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-new-agent", + "template": "local:default", + "display_name": "My New Agent" + }' +``` + +#### Via MCP (from another agent) + +```python +# Inside an agent with Trinity MCP access +mcp__trinity__create_agent( + name="my-new-agent", + template="local:default" +) +``` + +### Editing Agent Instructions + +**Scenario**: You need to change how an agent behaves. + +1. Go to agent → **Files** tab +2. Navigate to `CLAUDE.md` +3. Click **Edit** (if supported in UI) or: + +```bash +# SSH into container +docker exec -it agent-my-agent bash + +# Edit CLAUDE.md +nano CLAUDE.md + +# Restart agent to apply changes +exit +``` + +Or via Trinity UI: +- Stop the agent +- Edit configuration (some platforms support live edit) +- Start the agent + +**Pro Tip**: Keep agent templates in Git. When you need to update, commit changes and redeploy from template. + +### Stopping & Starting Agents + +**When to Stop**: +- Agent misbehaving or stuck +- Need to conserve resources +- Applying configuration changes +- Debugging issues + +**Via UI**: +1. Go to agent detail page +2. Click **Stop Agent** button +3. Wait for status to change to "Stopped" +4. Click **Start Agent** to restart + +**Via API**: +```bash +# Stop +curl -X POST http://localhost:8000/api/agents/my-agent/stop \ + -H "Authorization: Bearer $TOKEN" + +# Start +curl -X POST http://localhost:8000/api/agents/my-agent/start \ + -H "Authorization: Bearer $TOKEN" +``` + +**Via Command Line**: +```bash +# Stop +docker stop agent-my-agent + +# Start +docker start agent-my-agent +``` + +### Deleting an Agent + +**Scenario**: Agent no longer needed or needs complete reset. + +⚠️ **Warning**: This permanently deletes: +- The Docker container +- All agent files (workspace, memory, etc.) +- Configuration and credentials +- **Cannot be undone** + +**Before Deleting**: +1. Backup important files from agent's workspace +2. Remove agent from any schedules or dependencies +3. Update other agents that might reference this one + +**Via UI**: +1. Go to agent detail page +2. Click **Delete Agent** +3. Confirm deletion + +**Via API**: +```bash +curl -X DELETE http://localhost:8000/api/agents/my-agent \ + -H "Authorization: Bearer $TOKEN" +``` + +--- + +## Credential Management + +### Adding Credentials to an Agent + +**Scenario**: Your agent needs API keys for external services. + +#### Step 1: Store Credentials Centrally + +1. Go to **Settings** → **Credentials** +2. Click **+ Add Credential** +3. Fill in: + - **Name**: `TWITTER_API_KEY` + - **Service**: `twitter` + - **Type**: `api_key` + - **Value**: `your-actual-key` +4. Click **Save** + +Repeat for all required credentials. + +#### Step 2: Link to Agent + +Trinity automatically injects credentials that match placeholders in your agent's `.mcp.json.template`. + +If agent already exists: +1. Go to agent → **Credentials** tab +2. Click **Reload Credentials** +3. Trinity fetches from central store and updates agent + +### Hot-Reloading Credentials + +**Scenario**: API key changed, need to update without restarting agent. + +#### Option 1: From Central Store + +1. Update credential in **Settings** → **Credentials** +2. Go to agent → **Credentials** tab +3. Click **Reload from Store** + +#### Option 2: Direct Paste + +1. Go to agent → **Credentials** tab +2. Click **Hot-Reload** +3. Paste credentials in `KEY=VALUE` format: + ``` + TWITTER_API_KEY=new-key-value + TWITTER_API_SECRET=new-secret-value + ``` +4. Click **Apply** + +Agent receives updated credentials **without restarting**. + +### Checking Credential Status + +**Scenario**: Agent not working, might be credentials issue. + +1. Go to agent → **Credentials** tab +2. See which credentials are loaded +3. Check for: + - ❌ Missing credentials (red warning) + - ⚠️ Expired credentials + - ✅ Valid credentials + +**Via API**: +```bash +curl http://localhost:8000/api/agents/my-agent/credentials/status \ + -H "Authorization: Bearer $TOKEN" +``` + +--- + +## Schedule Management + +### Creating a Schedule + +**Scenario**: You want an agent to run a task automatically. + +1. Go to agent → **Schedules** tab +2. Click **+ Create Schedule** +3. Configure: + - **Name**: Descriptive name (e.g., "Daily Report") + - **Cron Expression**: When to run (e.g., `0 9 * * *`) + - **Message**: What to tell the agent + - **Timezone**: Your timezone + - **Enabled**: ✅ + +4. Click **Create** + +#### Cron Expression Examples + +```bash +# Every hour at :00 +0 * * * * + +# Every day at 9 AM +0 9 * * * + +# Every Monday at 9 AM +0 9 * * 1 + +# Every 15 minutes +*/15 * * * * + +# Weekdays at 9 AM and 5 PM +0 9,17 * * 1-5 + +# First day of month at midnight +0 0 1 * * +``` + +**Pro Tip**: Use [crontab.guru](https://crontab.guru/) to build and validate cron expressions. + +### Testing a Schedule + +**Before enabling**, test manually: + +1. Create schedule but leave **Enabled** unchecked +2. Click **Trigger Now** button +3. Watch agent → **Activity** tab +4. Verify expected behavior +5. If good, enable the schedule + +### Disabling a Schedule + +**Scenario**: Temporarily pause automation without deleting schedule. + +1. Go to agent → **Schedules** tab +2. Find the schedule +3. Toggle **Enabled** to off +4. Schedule won't run but configuration is saved + +Re-enable anytime by toggling back on. + +### Viewing Execution History + +**Scenario**: Check if scheduled tasks ran successfully. + +1. Go to agent → **Schedules** tab +2. Click on a schedule +3. View **Execution History**: + - Timestamp of each run + - Success/failure status + - Duration + - Logs/errors + +### Modifying Schedule Timing + +**Scenario**: Need to change when a schedule runs. + +1. Go to agent → **Schedules** tab +2. Click **Edit** on the schedule +3. Update cron expression +4. Save changes + +New timing takes effect immediately. + +--- + +## Monitoring & Debugging + +### Viewing Agent Logs + +**Scenario**: Agent not behaving as expected, need to see what's happening. + +#### Via Web UI + +1. Go to agent → **Logs** tab +2. See real-time container logs +3. Use filters: + - Error only + - Last N lines + - Search for keywords + +#### Via Command Line + +```bash +# View logs (live tail) +docker logs -f agent-my-agent + +# Last 100 lines +docker logs --tail 100 agent-my-agent + +# Since specific time +docker logs --since 30m agent-my-agent + +# Search logs +docker logs agent-my-agent 2>&1 | grep ERROR +``` + +### Checking Agent Activity + +**Scenario**: See what tools an agent is using and when. + +1. Go to agent → **Activity** tab +2. See chronological list of: + - Tool calls (MCP, functions, etc.) + - Chat messages + - File operations + - Schedule executions + +3. Filter by: + - Time range + - Activity type + - Success/error status + +### Monitoring Context Usage + +**Scenario**: Agent getting close to context limit. + +1. **Dashboard View**: + - See context bars below each agent + - Colors: Green → Yellow → Orange → Red + - Percentage shown + +2. **Agent Detail View**: + - Go to agent detail page + - Top bar shows context usage + - "Reset Context" button if needed + +**When to Reset Context**: +- Context > 90% (agent might lose track) +- Agent giving confused/contradictory responses +- After completing a major workflow + +**How to Reset**: +```bash +# Via Trinity API +curl -X POST http://localhost:8000/api/agents/my-agent/reset-context \ + -H "Authorization: Bearer $TOKEN" +``` + +### Checking File System + +**Scenario**: Verify agent created expected files. + +1. Go to agent → **Files** tab +2. Browse directory structure +3. Click files to view content +4. Download files if needed + +**Via Command Line**: +```bash +# List files +docker exec agent-my-agent ls -la /home/developer/workspace + +# Read file +docker exec agent-my-agent cat /home/developer/workspace/report.txt + +# Copy file out +docker cp agent-my-agent:/home/developer/workspace/report.txt ./local-report.txt +``` + +### Debugging Agent Communication + +**Scenario**: Multi-agent system, agents not communicating correctly. + +1. **Check Permissions**: + - Go to agent → **Permissions** tab + - Verify target agent is listed + - Grant permission if missing + +2. **Check Shared Folders**: + - Go to agent → **Shared Folders** tab + - Verify "expose" and "consume" are enabled + - Check which agents are mounted + +3. **Verify Folder Contents**: + ```bash + # Check what agent is sharing + docker exec agent-source ls /home/developer/shared-out + + # Check what agent can see + docker exec agent-consumer ls /home/developer/shared-in/source-agent + ``` + +4. **Check Activity Timeline**: + - Dashboard → Activity + - Filter: "Agent Collaboration" + - See all inter-agent messages + +--- + +## Multi-Agent Coordination + +### Setting Up Agent Permissions + +**Scenario**: Two agents need to communicate. + +1. Go to source agent → **Permissions** tab +2. Click **+ Grant Permission** +3. Select target agent +4. Click **Grant** + +Repeat in reverse if bidirectional communication needed. + +**Via API (full mesh for system)**: +```bash +# Grant all agents permission to talk to each other +AGENTS=("agent-a" "agent-b" "agent-c") + +for source in "${AGENTS[@]}"; do + for target in "${AGENTS[@]}"; do + if [ "$source" != "$target" ]; then + curl -X POST "http://localhost:8000/api/agents/$source/permissions" \ + -H "Authorization: Bearer $TOKEN" \ + -d "{\"target_agent\": \"$target\"}" + fi + done +done +``` + +### Configuring Shared Folders + +**Scenario**: Agents need to share files. + +1. Go to agent → **Shared Folders** tab +2. Enable options: + - **Expose** ✅: Other agents can read your files + - **Consume** ✅: You can read other agents' files +3. Click **Save** +4. **Restart agent** (required for folder mounts to apply) + +**Folder Layout**: +``` +/home/developer/ +├── shared-out/ # This agent's output (others read) +└── shared-in/ # Other agents' output (you read) + ├── agent-a/ # Agent A's shared-out + └── agent-b/ # Agent B's shared-out +``` + +### Coordinating Schedule Timing + +**Scenario**: Multiple agents need to run in sequence. + +**Pattern: Leader-Follower** +``` +Orchestrator: 0 * * * * # :00 - Plan work +Worker A: 5 * * * * # :05 - Execute work +Worker B: 10 * * * * # :10 - Process results +Orchestrator: 15 * * * * # :15 - Verify completion +``` + +**Pattern: Staggered Workers** +``` +Worker A: 0,15,30,45 * * * * # Every 15 min starting :00 +Worker B: 5,20,35,50 * * * * # Every 15 min starting :05 +Worker C: 10,25,40,55 * * * * # Every 15 min starting :10 +``` + +--- + +## Backup & Recovery + +### Backing Up Agent Workspace + +**Scenario**: Want to save agent's work before major change. + +```bash +# Backup entire workspace +docker exec agent-my-agent tar czf /tmp/backup.tar.gz /home/developer/workspace +docker cp agent-my-agent:/tmp/backup.tar.gz ./backups/agent-my-agent-$(date +%Y%m%d).tar.gz + +# Backup specific files +docker cp agent-my-agent:/home/developer/workspace/important-data.json ./backups/ +``` + +### Backing Up Vector Memory + +**Scenario**: Preserve agent's learned knowledge. + +```bash +# Backup Chroma database +docker exec agent-my-agent tar czf /tmp/vector-backup.tar.gz /home/developer/vector-store +docker cp agent-my-agent:/tmp/vector-backup.tar.gz ./backups/vector-my-agent-$(date +%Y%m%d).tar.gz +``` + +### Restoring from Backup + +**Scenario**: Need to restore agent to previous state. + +```bash +# Copy backup into container +docker cp ./backups/agent-my-agent-20251223.tar.gz agent-my-agent:/tmp/ + +# Extract +docker exec agent-my-agent tar xzf /tmp/agent-my-agent-20251223.tar.gz -C / +``` + +### Exporting Agent Configuration + +**Scenario**: Want to recreate agent or move to another Trinity instance. + +1. Export agent template files from GitHub repo +2. Export system manifest (if part of multi-agent system): + ```bash + curl http://localhost:8000/api/systems/my-system/manifest \ + -H "Authorization: Bearer $TOKEN" > my-system.yaml + ``` +3. Document credentials needed (don't export actual secrets!) + +--- + +## Performance Optimization + +### Checking Resource Usage + +**Scenario**: System feels slow, check what's consuming resources. + +```bash +# See all containers and resource usage +docker stats + +# See specific agent +docker stats agent-my-agent +``` + +Look for: +- High CPU% (agent is working hard or stuck) +- High MEM% (close to limit, might OOM) +- High NET I/O (lots of API calls) + +### Adjusting Agent Resources + +**Scenario**: Agent needs more memory or CPU. + +Currently requires recreating agent with new resource limits: + +1. Note current agent configuration +2. Delete agent +3. Create new agent with higher resources in `template.yaml`: + ```yaml + resources: + cpu: "4" # Was "2" + memory: "8g" # Was "4g" + ``` + +### Reducing Context Usage + +**Strategies to keep context low**: + +1. **Use Vector Memory**: Store long-term knowledge outside context + ```python + # Instead of keeping in context + # Store in Chroma + mcp__chroma__add_documents( + collection="knowledge", + documents=["Important info"], + ids=["doc1"] + ) + ``` + +2. **Use Files**: Store data in files, not in chat + ```python + # Write to file + with open('workspace/data.json', 'w') as f: + json.dump(large_data, f) + # Reference file instead of keeping in context + ``` + +3. **Reset Context Periodically**: After major workflows + - Manually via UI + - Agent can request reset + - Schedule context resets + +4. **Use Planning System**: Persist tasks outside context + ```bash + /trinity-plan-create + ``` + +### Reducing API Costs + +**Strategies to minimize token usage**: + +1. **Batch Operations**: Process multiple items in one message +2. **Use Smaller Models**: For simple tasks, use faster/cheaper models +3. **Cache Results**: Store frequent queries in vector memory +4. **Filter Input**: Only process what's necessary +5. **Monitor Usage**: Check OpenTelemetry metrics + +--- + +## Quick Reference + +### Most Common Commands + +```bash +# View all agents +docker ps | grep agent- + +# View agent logs +docker logs -f agent-NAME + +# Restart agent +docker restart agent-NAME + +# Stop Trinity +docker compose down + +# Start Trinity +docker compose up -d + +# View Trinity logs +docker compose logs -f backend +docker compose logs -f frontend + +# Check disk usage +docker system df +``` + +### Most Common Issues & Fixes + +| Issue | Quick Fix | +|-------|-----------| +| Agent stuck starting | Check logs: `docker logs agent-NAME` | +| Agent not responding | Restart: `docker restart agent-NAME` | +| Credentials not working | Reload: Agent → Credentials → Reload | +| Shared folder empty | Check: Permissions granted & agent restarted | +| Schedule not running | Check: Enabled ✅ & cron syntax valid | +| Context at 100% | Reset: Agent → Reset Context button | +| High memory usage | Restart agent, check for memory leaks | + +--- + +## Next Steps + +- **Need Help?** Check [Troubleshooting Guide](04-troubleshooting.md) +- **Building Systems?** Read [Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md) +- **Creating Templates?** See [Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md) + +--- + +**These workflows will become second nature quickly. Happy building!** 🚀 + + + + + diff --git a/docs/onboarding/04-troubleshooting.md b/docs/onboarding/04-troubleshooting.md new file mode 100644 index 000000000..b4d90619e --- /dev/null +++ b/docs/onboarding/04-troubleshooting.md @@ -0,0 +1,1013 @@ +# Troubleshooting Guide + +This guide helps you diagnose and fix common issues when working with Trinity. Issues are organized by category with clear symptoms, causes, and solutions. + +--- + +## Table of Contents + +1. [Installation Issues](#installation-issues) +2. [Agent Startup Issues](#agent-startup-issues) +3. [Agent Runtime Issues](#agent-runtime-issues) +4. [Communication Issues](#communication-issues) +5. [Credential Issues](#credential-issues) +6. [Schedule Issues](#schedule-issues) +7. [Performance Issues](#performance-issues) +8. [Data & Storage Issues](#data--storage-issues) +9. [Network Issues](#network-issues) +10. [Getting More Help](#getting-more-help) + +--- + +## Installation Issues + +### Issue: Docker Compose Fails to Start + +**Symptoms**: +- `docker compose up` exits with error +- Services fail to start +- "Port already in use" errors + +**Diagnosis**: +```bash +# Check if ports are available +netstat -an | grep LISTEN | grep -E "3000|8000|8080|6379|8001" + +# Check Docker is running +docker info + +# Check disk space +df -h +``` + +**Solutions**: + +**If ports are in use**: +```bash +# Find what's using the port +lsof -i :3000 +lsof -i :8000 + +# Kill the process or change Trinity ports in docker-compose.yml +``` + +**If Docker isn't running**: +```bash +# macOS +open -a Docker + +# Linux +sudo systemctl start docker +``` + +**If out of disk space**: +```bash +# Clean up Docker +docker system prune -a --volumes + +# Remove old images +docker image prune -a +``` + +--- + +### Issue: Base Image Build Fails + +**Symptoms**: +- `build-base-image.sh` script fails +- "No space left on device" +- Network timeout errors + +**Diagnosis**: +```bash +# Check Docker disk usage +docker system df + +# Check build logs +docker compose logs backend +``` + +**Solutions**: + +**Out of space**: +```bash +# Free up space +docker system prune -a --volumes + +# Increase Docker Desktop disk limit (Settings → Resources) +``` + +**Network issues**: +```bash +# Retry with verbose output +./scripts/deploy/build-base-image.sh 2>&1 | tee build.log + +# Check internet connection +ping google.com +``` + +**Corrupted cache**: +```bash +# Build with no cache +docker compose build --no-cache backend +``` + +--- + +### Issue: Permission Denied Errors + +**Symptoms**: +- "Permission denied" when running scripts +- "Cannot connect to Docker daemon" + +**Solutions**: + +**Script permissions**: +```bash +# Make scripts executable +chmod +x scripts/deploy/*.sh +``` + +**Docker permissions (Linux)**: +```bash +# Add user to docker group +sudo usermod -aG docker $USER + +# Apply immediately +newgrp docker + +# Verify +docker ps +``` + +**macOS/Windows**: Ensure Docker Desktop is running with proper permissions. + +--- + +## Agent Startup Issues + +### Issue: Agent Stuck in "Starting" State + +**Symptoms**: +- Agent shows "Starting..." for > 2 minutes +- Never transitions to "Running" + +**Diagnosis**: +```bash +# Check agent logs +docker logs agent-AGENT-NAME + +# Check if container is running +docker ps -a | grep agent-AGENT-NAME +``` + +**Common Causes & Solutions**: + +**1. Anthropic API Key Missing/Invalid**: +```bash +# Check backend logs +docker logs trinity-backend | grep "ANTHROPIC" + +# Verify key is set +docker exec trinity-backend env | grep ANTHROPIC_API_KEY +``` +**Fix**: Set key in Settings → API Keys or in `.env` file. + +**2. Claude Code Image Download Failing**: +```bash +# Check if download is progressing +docker exec agent-AGENT-NAME ps aux + +# Check network +docker exec agent-AGENT-NAME ping google.com +``` +**Fix**: Wait for download to complete (can take 5-10 minutes first time) or check network. + +**3. Port Conflict**: +```bash +# Check if agent's port is available +docker logs agent-AGENT-NAME | grep "address already in use" +``` +**Fix**: Trinity auto-assigns ports, but if you have many agents, you might hit limits. Delete unused agents. + +**4. Resource Constraints**: +```bash +# Check if host is low on resources +docker stats +free -h # Linux +``` +**Fix**: Close other applications or increase Docker Desktop resources. + +--- + +### Issue: Agent Exits Immediately After Starting + +**Symptoms**: +- Agent starts then immediately stops +- Status shows "Exited (1)" or similar + +**Diagnosis**: +```bash +# View exit logs +docker logs agent-AGENT-NAME + +# Check exit code +docker inspect agent-AGENT-NAME | grep ExitCode +``` + +**Common Causes**: + +**Missing template files**: +``` +Error: CLAUDE.md not found +``` +**Fix**: Ensure template repository has `CLAUDE.md` file. + +**Invalid template.yaml**: +``` +Error: Failed to parse template.yaml +``` +**Fix**: Validate YAML syntax, check required fields. + +**Credential injection failed**: +``` +Error: Missing required credential: TWITTER_API_KEY +``` +**Fix**: Add required credentials before creating agent. + +--- + +### Issue: Agent Container Not Created + +**Symptoms**: +- Create agent button succeeds +- No container appears in `docker ps -a` +- Backend logs show errors + +**Diagnosis**: +```bash +# Check backend logs for agent creation +docker logs trinity-backend | tail -100 + +# Check if Docker socket is accessible +docker exec trinity-backend ls -la /var/run/docker.sock +``` + +**Solutions**: + +**Docker socket permission issues**: +```bash +# Check backend can access Docker +docker exec trinity-backend docker ps +``` + +**Base image missing**: +```bash +# Check if base image exists +docker images | grep trinity-agent-base + +# Rebuild if missing +./scripts/deploy/build-base-image.sh +``` + +--- + +## Agent Runtime Issues + +### Issue: Agent Not Responding to Messages + +**Symptoms**: +- Chat messages stuck in "Sending..." state +- No response after several minutes +- No errors in UI + +**Diagnosis**: +```bash +# Check if agent is actually running +docker ps | grep agent-AGENT-NAME + +# Check agent logs +docker logs -f agent-AGENT-NAME + +# Check backend logs +docker logs -f trinity-backend +``` + +**Solutions**: + +**Agent crashed**: +```bash +# Restart agent +docker restart agent-AGENT-NAME + +# Or via UI: Stop → Start +``` + +**Context window full**: +- Check context bar in UI +- If near 100%, reset context: Agent → Reset Context + +**Agent busy with long-running task**: +- Wait for current task to complete +- Check Activity tab to see what it's doing +- Cancel task if stuck (restart agent) + +**API rate limit hit**: +```bash +# Check logs for rate limit errors +docker logs agent-AGENT-NAME | grep -i "rate limit" +``` +**Fix**: Wait for rate limit to reset, or add delay between requests. + +--- + +### Issue: Agent Giving Nonsensical Responses + +**Symptoms**: +- Agent responses don't make sense +- Agent confused about context +- Agent repeating same responses + +**Solutions**: + +**1. Context Window Polluted**: +- **Fix**: Reset context via UI + +**2. Conflicting Instructions**: +- Check `CLAUDE.md` for contradictions +- Simplify instructions +- Remove ambiguous guidance + +**3. Too Many Tools**: +- Agent overwhelmed by options +- **Fix**: Reduce number of MCP servers +- Be more specific in instructions about when to use which tool + +**4. Memory Issues**: +```bash +# Check if agent is hitting memory limits +docker stats agent-AGENT-NAME +``` +**Fix**: Increase memory in template.yaml and recreate agent. + +--- + +### Issue: Agent Not Using MCP Tools + +**Symptoms**: +- Agent says "I don't have access to that tool" +- No MCP tool calls in Activity tab +- Expected MCP functionality not working + +**Diagnosis**: +```bash +# Check if MCP config exists +docker exec agent-AGENT-NAME cat /home/developer/.mcp.json + +# Check for MCP errors in logs +docker logs agent-AGENT-NAME | grep -i mcp +``` + +**Solutions**: + +**MCP config not generated**: +- Check if `.mcp.json.template` exists in template +- Verify credentials are injected +- Restart agent + +**MCP server failed to start**: +```bash +# Check Claude Code logs for server errors +docker logs agent-AGENT-NAME | grep -i "failed to start" +``` +**Fix**: Check MCP server configuration syntax, verify credentials. + +**Agent not instructed to use tools**: +- Update `CLAUDE.md` to explicitly mention available tools +- Give examples of when/how to use them + +--- + +## Communication Issues + +### Issue: Agents Can't See Each Other + +**Symptoms**: +- Agent A tries to list agents, doesn't see Agent B +- "Permission denied" when trying to chat +- Trinity MCP tools return empty lists + +**Diagnosis**: +```bash +# Check permissions +curl http://localhost:8000/api/agents/agent-a/permissions \ + -H "Authorization: Bearer $TOKEN" + +# Check both agents are running +docker ps | grep agent- +``` + +**Solutions**: + +**Missing permissions**: +1. Go to Agent A → Permissions tab +2. Grant permission to Agent B +3. Repeat in reverse if bidirectional needed + +**Agent not running**: +```bash +# Start the target agent +docker start agent-AGENT-B +``` + +**Network isolation issue**: +```bash +# Check agents are on same Docker network +docker network inspect trinity-agent-network +``` +All agents should be listed. If not: +```bash +# Recreate agent to attach to network +docker stop agent-AGENT-NAME +docker rm agent-AGENT-NAME +# Create again via Trinity UI +``` + +--- + +### Issue: Shared Folders Empty or Not Accessible + +**Symptoms**: +- `shared-in/other-agent/` directory empty +- Files not appearing that should be there +- Permission denied reading shared files + +**Diagnosis**: +```bash +# Check if source agent has sharing enabled +curl http://localhost:8000/api/agents/source-agent/folders \ + -H "Authorization: Bearer $TOKEN" + +# Check if target agent has consume enabled +curl http://localhost:8000/api/agents/target-agent/folders \ + -H "Authorization: Bearer $TOKEN" + +# Check folder contents in source +docker exec agent-source-agent ls -la /home/developer/shared-out + +# Check folder mount in target +docker exec agent-target-agent ls -la /home/developer/shared-in +``` + +**Solutions**: + +**Sharing not enabled**: +1. Source agent → Shared Folders → Enable "Expose" +2. Target agent → Shared Folders → Enable "Consume" +3. **Restart both agents** (required!) + +**Permission not granted**: +- Sharing only works between agents with granted permissions +- Grant permission from source to target + +**Files in wrong location**: +- Source agent must write to `/home/developer/shared-out/` +- Not `workspace/` or other directories + +**Agent not restarted**: +- Folder mounts only apply after restart +- Always restart agents after changing folder settings + +--- + +## Credential Issues + +### Issue: Credentials Not Found + +**Symptoms**: +- Agent errors about missing API keys +- MCP server fails to start +- "Missing required credential" errors + +**Diagnosis**: +```bash +# Check credential status +curl http://localhost:8000/api/agents/AGENT-NAME/credentials/status \ + -H "Authorization: Bearer $TOKEN" + +# Check .mcp.json generation +docker exec agent-AGENT-NAME cat /home/developer/.mcp.json + +# Check .env file +docker exec agent-AGENT-NAME cat /home/developer/.env +``` + +**Solutions**: + +**Credentials not stored**: +1. Go to Settings → Credentials +2. Add the missing credentials +3. Reload agent credentials + +**Placeholder mismatch**: +- `.mcp.json.template` has `${TWITTER_API_KEY}` +- But credential stored as `TWITTER_KEY` +- **Fix**: Names must match exactly (case-sensitive) + +**Credentials not injected**: +```bash +# Manually reload +curl -X POST http://localhost:8000/api/agents/AGENT-NAME/credentials/reload \ + -H "Authorization: Bearer $TOKEN" +``` + +--- + +### Issue: Hot-Reload Not Working + +**Symptoms**: +- Updated credentials via hot-reload +- Agent still using old values +- MCP tools still failing with auth errors + +**Solutions**: + +**1. MCP server needs restart**: +- Some MCP servers cache credentials +- **Fix**: Stop and start agent (not just hot-reload) + +**2. .mcp.json not regenerated**: +```bash +# Check if .mcp.json updated +docker exec agent-AGENT-NAME cat /home/developer/.mcp.json +``` +**Fix**: Reload via API instead of UI. + +**3. Credential format wrong**: +- Hot-reload expects `KEY=VALUE` format +- One per line +- No quotes around values + +--- + +## Schedule Issues + +### Issue: Schedule Not Running + +**Symptoms**: +- Expected schedule execution never happens +- Execution history empty +- No errors shown + +**Diagnosis**: +```bash +# Check schedule configuration +curl http://localhost:8000/api/agents/AGENT-NAME/schedules \ + -H "Authorization: Bearer $TOKEN" + +# Check backend scheduler logs +docker logs trinity-backend | grep -i schedule + +# Check if agent is running +docker ps | grep agent-AGENT-NAME +``` + +**Solutions**: + +**Schedule disabled**: +- Check **Enabled** toggle is ON + +**Cron expression invalid**: +- Test at [crontab.guru](https://crontab.guru/) +- Common mistake: Wrong field count (must be 5 fields) + +**Timezone mismatch**: +- Schedule says "9 AM" but set to wrong timezone +- **Fix**: Update timezone to match your location + +**Agent stopped**: +- Schedules only run if agent is running +- **Fix**: Start the agent + +**Backend scheduler crashed**: +```bash +# Restart backend +docker restart trinity-backend +``` + +--- + +### Issue: Schedule Executes But Agent Does Nothing + +**Symptoms**: +- Execution history shows "Success" +- But agent didn't do expected work +- No errors logged + +**Solutions**: + +**1. Check message content**: +- Schedule message might be vague +- **Fix**: Be specific: "Run daily report workflow: gather data, analyze, create summary.md" + +**2. Check agent's CLAUDE.md**: +- Agent might not understand what to do +- **Fix**: Add workflow documentation for scheduled tasks + +**3. Check Activity tab**: +- Agent might have done something, just not what you expected +- Review what tools were called + +--- + +### Issue: Schedule Execution Fails + +**Symptoms**: +- Execution history shows "Failed" +- Errors in execution log + +**Diagnosis**: +```bash +# View failed execution details +# Via UI: Schedules → Click schedule → Execution History → Click failed execution + +# Or check agent logs at time of execution +docker logs agent-AGENT-NAME --since "2025-12-23T09:00:00" +``` + +**Common Causes**: +- Credential expired/missing +- External API down +- Agent hit context limit +- File permission issue + +**Fix**: Address the specific error shown in logs. + +--- + +## Performance Issues + +### Issue: System Very Slow + +**Symptoms**: +- UI laggy +- Agents respond slowly +- Commands take forever + +**Diagnosis**: +```bash +# Check system resources +docker stats + +# Check disk usage +docker system df +df -h + +# Check network latency +ping api.anthropic.com +``` + +**Solutions**: + +**High CPU usage**: +```bash +# See which container is using CPU +docker stats --no-stream | sort -k3 -h +``` +- Stop unused agents +- Restart problematic agent +- Increase Docker CPU limit + +**High memory usage**: +- Close unused agents +- Restart agents periodically +- Increase Docker memory limit +- Check for memory leaks (agent running for weeks) + +**Disk full**: +```bash +# Clean up Docker +docker system prune -a --volumes + +# Check agent workspaces +du -sh /var/lib/docker/volumes/* +``` + +**Network issues**: +- Check internet connection +- Try different network +- Check if Anthropic API is down: [status.anthropic.com](https://status.anthropic.com) + +--- + +### Issue: Agent Using Too Much Memory + +**Symptoms**: +- Agent container killed with OOM +- "Out of memory" in logs +- Agent keeps restarting + +**Diagnosis**: +```bash +# Check memory usage +docker stats agent-AGENT-NAME + +# Check memory limit +docker inspect agent-AGENT-NAME | grep Memory +``` + +**Solutions**: + +**1. Increase memory limit**: +- Edit template.yaml: `memory: "8g"` (was 4g) +- Recreate agent + +**2. Reset context regularly**: +- Context bloat causes memory issues +- Use `/trinity-plan-*` commands to persist outside context +- Reset context after major workflows + +**3. Optimize agent behavior**: +- Store data in files, not in context +- Use vector memory for large datasets +- Avoid loading huge files into memory + +**4. Check for leaks**: +```bash +# Restart agent +docker restart agent-AGENT-NAME + +# If memory grows again quickly, might be a leak +# Report to Trinity team +``` + +--- + +### Issue: Slow API Responses + +**Symptoms**: +- Agent takes 30+ seconds to respond +- Other agents timing out waiting +- High latency + +**Causes & Solutions**: + +**Context window too large**: +- Check context bar in UI +- **Fix**: Reset context + +**Using wrong Claude model**: +- Sonnet is faster than Opus +- Check which model agent is using + +**Complex tool chains**: +- Agent making 10+ tool calls per response +- **Fix**: Simplify workflows, batch operations + +**Rate limiting**: +```bash +# Check logs for rate limit errors +docker logs agent-AGENT-NAME | grep "429" +``` +**Fix**: Add delays between requests, use cheaper models for non-critical tasks. + +--- + +## Data & Storage Issues + +### Issue: Vector Memory Not Persisting + +**Symptoms**: +- Agent forgets stored knowledge after restart +- Vector queries return empty results +- `vector-store/` directory empty + +**Diagnosis**: +```bash +# Check if vector-store exists +docker exec agent-AGENT-NAME ls -la /home/developer/vector-store + +# Check Chroma files +docker exec agent-AGENT-NAME ls -la /home/developer/vector-store/chroma.sqlite3 +``` + +**Solutions**: + +**Database not created**: +- Agent needs to use Chroma MCP tools to create collections +- Check if agent ever called vector memory tools + +**Volume not persisting**: +```bash +# Check Docker volumes +docker volume ls | grep agent-AGENT-NAME +``` +If no volume, agent might be using ephemeral storage. + +**Agent recreated without preserving data**: +- When you delete and recreate agent, data is lost +- **Fix**: Backup before deleting + +--- + +### Issue: Files Disappearing from Agent Workspace + +**Symptoms**: +- Files agent created are gone after restart +- Workspace resets to initial state + +**Cause**: Agent is being fully recreated (not just restarted). + +**Solutions**: + +**Use persistent directories**: +- `workspace/` should persist across restarts +- Check if Docker volume is attached + +**Backup important data**: +```bash +# Regular backups +docker exec agent-AGENT-NAME tar czf /tmp/backup.tar.gz /home/developer/workspace +docker cp agent-AGENT-NAME:/tmp/backup.tar.gz ./backups/ +``` + +**Use external storage**: +- Shared folders (persist as Docker volumes) +- External databases +- Cloud storage via APIs + +--- + +## Network Issues + +### Issue: Agent Can't Reach External APIs + +**Symptoms**: +- MCP tools fail with connection errors +- "Network unreachable" in logs +- Timeouts connecting to external services + +**Diagnosis**: +```bash +# Test network from agent +docker exec agent-AGENT-NAME ping google.com +docker exec agent-AGENT-NAME curl https://api.anthropic.com +docker exec agent-AGENT-NAME nslookup google.com +``` + +**Solutions**: + +**Docker network issue**: +```bash +# Restart Docker networking +docker network disconnect trinity-agent-network agent-AGENT-NAME +docker network connect trinity-agent-network agent-AGENT-NAME +``` + +**Firewall blocking**: +- Check if corporate firewall blocks API endpoints +- Try from host machine: `curl https://api.anthropic.com` + +**DNS resolution failing**: +```bash +# Add custom DNS to docker-compose.yml +dns: + - 8.8.8.8 + - 8.8.4.4 +``` + +--- + +### Issue: Can't Access Trinity UI + +**Symptoms**: +- `http://localhost:3000` doesn't load +- "Connection refused" +- Page never loads + +**Diagnosis**: +```bash +# Check if frontend is running +docker ps | grep trinity-frontend + +# Check frontend logs +docker logs trinity-frontend + +# Check if port is open +curl http://localhost:3000 +``` + +**Solutions**: + +**Frontend not started**: +```bash +docker compose up -d frontend +``` + +**Port conflict**: +```bash +# Check what's using port 3000 +lsof -i :3000 + +# Change port in docker-compose.yml if needed +``` + +**Backend not reachable**: +- Frontend needs backend at `http://localhost:8000` +- Check backend is running: `docker ps | grep trinity-backend` + +--- + +## Getting More Help + +### Diagnostic Information to Collect + +When asking for help, gather: + +```bash +# Trinity version +git log -1 --oneline + +# Docker version +docker --version +docker compose version + +# System info +uname -a +docker info + +# Service status +docker compose ps + +# Recent logs +docker compose logs --tail=100 backend > backend.log +docker compose logs --tail=100 frontend > frontend.log +docker logs --tail=100 agent-AGENT-NAME > agent.log +``` + +### Where to Get Help + +1. **Documentation**: + - [Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md) + - [Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md) + - [Development Workflow](../DEVELOPMENT_WORKFLOW.md) + +2. **GitHub Issues**: + - Search existing issues: https://github.com/abilityai/trinity/issues + - Create new issue with diagnostic info + - Use issue templates + +3. **API Documentation**: + - Interactive docs: http://localhost:8000/docs + - Try API calls directly to debug + +4. **Community**: + - Check GitHub discussions + - Review example agent templates + +### Reporting Bugs + +When filing a bug report, include: + +- [ ] Trinity version (git commit hash) +- [ ] Docker version +- [ ] Operating system +- [ ] Steps to reproduce +- [ ] Expected behavior +- [ ] Actual behavior +- [ ] Relevant logs (backend, frontend, agent) +- [ ] Screenshots if applicable + +### Commercial Support + +For commercial licensing and priority support: +- Email: hello@ability.ai + +--- + +## Quick Checklist for Common Issues + +When something goes wrong, work through this checklist: + +- [ ] Check all containers are running: `docker compose ps` +- [ ] Check logs for errors: `docker compose logs` +- [ ] Check agent is running: `docker ps | grep agent-NAME` +- [ ] Check agent logs: `docker logs agent-NAME` +- [ ] Try restarting agent: `docker restart agent-NAME` +- [ ] Check credentials are loaded +- [ ] Check permissions are granted (if multi-agent) +- [ ] Check shared folders are enabled (if using them) +- [ ] Check schedules are enabled (if automated) +- [ ] Check disk space: `df -h` +- [ ] Check Docker resources: `docker stats` +- [ ] Try restarting Trinity: `docker compose restart` +- [ ] Check for updates: `git pull` + +--- + +**Most issues can be resolved by carefully checking logs and verifying configuration. When in doubt, restart the problematic component.** 🔧 + + + + + diff --git a/docs/onboarding/README.md b/docs/onboarding/README.md new file mode 100644 index 000000000..f6360a012 --- /dev/null +++ b/docs/onboarding/README.md @@ -0,0 +1,317 @@ +# Trinity Onboarding Documentation + +Welcome! This folder contains comprehensive onboarding guides to help you get started with Trinity and understand how to use the platform effectively. + +--- + +## 📚 Documentation Index + +### [00 - Welcome to Trinity](00-welcome.md) +**Start here!** An introduction to Trinity, what it is, who should use it, and what you can build. + +**Topics**: +- What is Trinity and how is it different? +- The four pillars of deep agency +- What you can build with Trinity +- Core capabilities overview +- Quick start journey roadmap + +**Time to read**: 10 minutes + +--- + +### [01 - Getting Started](01-getting-started.md) +**Your first hour with Trinity.** Step-by-step installation, setup, and creating your first agent. + +**Topics**: +- Installation (quick install & manual) +- First-time setup wizard +- Creating your first agent +- Understanding the UI +- Core concepts (agents, templates, credentials, schedules) +- Hands-on tasks to try +- Common first-time issues + +**Time to complete**: 30-60 minutes + +--- + +### [02 - Use Case Scenarios](02-use-case-scenarios.md) +**See what's possible.** Six detailed real-world scenarios showing how to use Trinity for practical applications. + +**Scenarios**: +1. **Personal Research Assistant** — Autonomous research and knowledge management +2. **Social Media Content Automation** — Multi-agent content creation and publishing +3. **Email Management System** — Automated email triage and response +4. **Document Processing Pipeline** — Intelligent document categorization and indexing +5. **Development Team Assistant** — GitHub monitoring and team support +6. **Customer Support Triage** — Automated ticket handling and routing + +Each scenario includes: +- Problem statement +- Solution architecture +- Step-by-step implementation +- Expected outcomes +- Monitoring and scaling tips + +**Time to read**: 20-30 minutes (or jump to the scenario that matches your needs) + +--- + +### [03 - Common Workflows](03-common-workflows.md) +**Day-to-day operations.** The tasks you'll perform regularly when managing Trinity. + +**Topics**: +- Daily operations (morning routine, health checks) +- Agent management (create, edit, start/stop, delete) +- Credential management (adding, updating, hot-reload) +- Schedule management (creating, testing, modifying) +- Monitoring & debugging (logs, activity, context) +- Multi-agent coordination (permissions, shared folders) +- Backup & recovery +- Performance optimization + +**Time to read**: 15-20 minutes (reference guide — read as needed) + +--- + +### [04 - Troubleshooting](04-troubleshooting.md) +**When things go wrong.** Comprehensive guide to diagnosing and fixing common issues. + +**Categories**: +- Installation issues +- Agent startup issues +- Agent runtime issues +- Communication issues (multi-agent) +- Credential issues +- Schedule issues +- Performance issues +- Data & storage issues +- Network issues + +Each issue includes: +- Symptoms +- Diagnosis steps +- Solutions +- Prevention tips + +**Time to read**: As needed when troubleshooting + +--- + +## 🗺️ Learning Paths + +### Path 1: Quick Start (1-2 hours) +For those who want to dive in quickly: + +1. Read [Welcome](00-welcome.md) (10 min) +2. Follow [Getting Started](01-getting-started.md) (60 min) +3. Try the "Personal Research Assistant" from [Use Case Scenarios](02-use-case-scenarios.md) (30 min) + +**Outcome**: You'll have Trinity running and a working agent. + +--- + +### Path 2: Comprehensive Onboarding (3-4 hours) +For those who want deep understanding: + +1. Read [Welcome](00-welcome.md) (10 min) +2. Follow [Getting Started](01-getting-started.md) (60 min) +3. Read all scenarios in [Use Case Scenarios](02-use-case-scenarios.md) (30 min) +4. Review [Common Workflows](03-common-workflows.md) (20 min) +5. Skim [Troubleshooting](04-troubleshooting.md) to know what's available (10 min) +6. Build your own use case (2+ hours) + +**Outcome**: Deep understanding of Trinity capabilities and patterns. + +--- + +### Path 3: Use Case Specific (2-3 hours) +For those with a specific goal: + +1. Skim [Welcome](00-welcome.md) (5 min) +2. Follow [Getting Started](01-getting-started.md) up to "Create Your First Agent" (30 min) +3. Jump to your matching scenario in [Use Case Scenarios](02-use-case-scenarios.md) (20 min) +4. Implement your use case (1-2 hours) +5. Reference [Common Workflows](03-common-workflows.md) and [Troubleshooting](04-troubleshooting.md) as needed + +**Outcome**: Working implementation of your specific use case. + +--- + +## 🎯 What to Read Based on Your Role + +### I'm a Developer/Engineer +**Goal**: Build sophisticated AI applications with multi-agent workflows + +**Read**: +1. [Getting Started](01-getting-started.md) — Understand the platform +2. [Use Case Scenarios](02-use-case-scenarios.md) — See architectural patterns +3. [Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md) — Deep dive on multi-agent systems +4. [Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md) — Build custom templates + +**Focus on**: System architecture, API integration, multi-agent patterns + +--- + +### I'm a Business User +**Goal**: Deploy AI assistants to automate workflows + +**Read**: +1. [Welcome](00-welcome.md) — Understand what's possible +2. [Getting Started](01-getting-started.md) — Get Trinity running +3. [Use Case Scenarios](02-use-case-scenarios.md) — Find scenarios matching your needs +4. [Common Workflows](03-common-workflows.md) — Learn daily operations + +**Focus on**: Use cases, scheduling, monitoring results + +--- + +### I'm a Researcher/Experimenter +**Goal**: Explore autonomous agent architectures and capabilities + +**Read**: +1. [Welcome](00-welcome.md) — Understand Trinity's philosophy +2. [Getting Started](01-getting-started.md) — Set up your lab +3. [Use Case Scenarios](02-use-case-scenarios.md) — See what's been built +4. [Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md) — Understand patterns +5. [Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md) — Create experiments + +**Focus on**: Architecture patterns, agent capabilities, experimentation + +--- + +## 🚀 After Onboarding + +Once you've completed the onboarding guides, explore: + +### Advanced Topics + +- **[Gemini Support Guide](../GEMINI_SUPPORT.md)** + Configure and use Gemini CLI agents (free tier available!) + +- **[Multi-Agent System Guide](../MULTI_AGENT_SYSTEM_GUIDE.md)** + Deep dive into building multi-agent systems with coordinated workflows + +- **[Trinity Compatible Agent Guide](../TRINITY_COMPATIBLE_AGENT_GUIDE.md)** + Learn to create custom agent templates + +- **[Development Workflow](../DEVELOPMENT_WORKFLOW.md)** + Contribute to Trinity development + +- **[Deployment Guide](../DEPLOYMENT.md)** + Deploy Trinity in production + +### Example Agents + +Check out these public agent templates for inspiration: + +- **[Cornelius](https://github.com/abilityai/agent-cornelius)** — Knowledge Base Manager +- **[Corbin](https://github.com/abilityai/agent-corbin)** — Business Assistant +- **[Ruby](https://github.com/abilityai/agent-ruby)** — Content Creator + +### API Reference + +- **Interactive API Docs**: http://localhost:8000/docs +- **MCP Server**: http://localhost:8080/mcp + +--- + +## 💬 Getting Help + +### Documentation +- Start with [Troubleshooting Guide](04-troubleshooting.md) +- Check the [main documentation folder](../) +- Browse the [API reference](http://localhost:8000/docs) + +### Community +- **GitHub Issues**: Report bugs and request features +- **GitHub Discussions**: Ask questions and share what you've built + +### Commercial Support +For commercial licensing and priority support: +- Email: hello@ability.ai + +--- + +## 📝 Contributing to Documentation + +Found an error? Want to add a new scenario? Contributions are welcome! + +1. Fork the repository +2. Make your changes +3. Submit a pull request + +See [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines. + +--- + +## 🎓 Onboarding Checklist + +Use this checklist to track your progress: + +### Setup Phase +- [ ] Installed Docker and Docker Compose +- [ ] Cloned Trinity repository +- [ ] Built base agent image +- [ ] Started all services +- [ ] Accessed web UI at http://localhost:3000 +- [ ] Created admin account +- [ ] Configured at least one API key: + - [ ] Anthropic API key (for Claude agents) + - [ ] Google API key (for Gemini agents — free tier available!) + +### First Agent +- [ ] Created first agent from template +- [ ] Successfully chatted with agent +- [ ] Explored agent Files tab +- [ ] Viewed agent Logs +- [ ] Checked agent Activity +- [ ] Understood what was auto-injected + +### Automation +- [ ] Created a schedule +- [ ] Tested schedule manually +- [ ] Verified scheduled execution +- [ ] Reviewed execution history + +### Multi-Agent (Optional) +- [ ] Created second agent +- [ ] Granted permissions between agents +- [ ] Configured shared folders +- [ ] Verified agents can communicate + +### Production Readiness (Optional) +- [ ] Set up credential management +- [ ] Configured schedules for autonomous operation +- [ ] Set up monitoring routine +- [ ] Created backup procedures +- [ ] Reviewed security best practices + +--- + +## 📊 Feedback + +We're constantly improving Trinity and its documentation. Your feedback helps! + +**Did this onboarding help you?** +- What worked well? +- What was confusing? +- What's missing? + +Share your feedback: +- Open a GitHub issue with the `documentation` label +- Email: hello@ability.ai + +--- + +**Ready to get started? Begin with [Welcome to Trinity](00-welcome.md)!** 🚀 + +--- + +*Last updated: December 2025* +*Trinity Platform by [Ability AI](https://ability.ai)* + + + + diff --git a/docs/testing/GEMINI_TESTING_PLAN.md b/docs/testing/GEMINI_TESTING_PLAN.md new file mode 100644 index 000000000..cb8b5cc4c --- /dev/null +++ b/docs/testing/GEMINI_TESTING_PLAN.md @@ -0,0 +1,368 @@ +# Gemini Runtime Testing Plan + +**Purpose**: Validate Gemini CLI integration before merging to main. +**Duration**: ~30-45 minutes +**Prerequisites**: +- Trinity running locally (`docker compose up -d`) +- Google API key from [AI Studio](https://makersuite.google.com/app/apikey) + +--- + +## Phase 1: Setup (5 min) + +### 1.1 Add Google API Key + +```bash +# Add to your .env file +echo "GOOGLE_API_KEY=your-google-api-key-here" >> .env + +# Verify it's set +grep GOOGLE_API_KEY .env +``` + +### 1.2 Rebuild Base Image + +```bash +# This installs Gemini CLI in the base image +./scripts/deploy/build-base-image.sh + +# Verify version tag +docker images | grep trinity-agent-base +# Should show: trinity-agent-base:0.9.0 and :latest +``` + +### 1.3 Restart Backend + +```bash +docker compose restart backend + +# Verify backend picked up GOOGLE_API_KEY +docker compose logs backend | grep -i "google\|gemini" | head -5 +``` + +### 1.4 Verify Version Endpoint + +```bash +curl -s http://localhost:8000/api/version | jq +# Should show version 0.9.0 and runtimes: ["claude-code", "gemini-cli"] +``` + +--- + +## Phase 2: UI Testing (10 min) + +### 2.1 Create Claude Agent (Control) + +1. Open http://localhost:3000 +2. Login with your credentials +3. Click **"+ Create Agent"** +4. Configure: + - **Name**: `test-claude` + - **Template**: `local:test-echo` (or any simple template) +5. Click **Create** +6. Wait for agent to start (green status) + +**Expected**: Agent created successfully, shows "claude-code" or no runtime indicator (default) + +### 2.2 Create Gemini Agent + +1. Click **"+ Create Agent"** again +2. Configure: + - **Name**: `test-gemini` + - **Template**: `local:test-gemini` +3. Click **Create** +4. Wait for agent to start + +**Expected**: Agent created successfully + +### 2.3 Test Chat - Claude Agent + +1. Click on `test-claude` +2. Send message: `Hello, what runtime are you using?` +3. Observe: + - [ ] Response received + - [ ] Cost tracking shows ($ amount) + - [ ] Context window shows 200K + +### 2.4 Test Chat - Gemini Agent + +1. Click on `test-gemini` +2. Send message: `Hello, what runtime are you using? What's your context window?` +3. Observe: + - [ ] Response received + - [ ] Cost tracking (may show $0 for free tier) + - [ ] Context window shows 1M (1,000,000) + +### 2.5 Test Model Selection (Gemini) + +1. In `test-gemini` chat, click model selector (if available) +2. Try changing to `gemini-2.5-flash` +3. Send another message +4. Observe model is respected + +--- + +## Phase 3: API Testing (10 min) + +### 3.1 Get Auth Token + +```bash +# Login and get token +TOKEN=$(curl -s -X POST http://localhost:8000/api/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"admin","password":"your-password"}' | jq -r '.access_token') + +echo "Token: ${TOKEN:0:20}..." +``` + +### 3.2 Check Agent Health - Claude + +```bash +curl -s http://localhost:8000/api/agents/test-claude/health \ + -H "Authorization: Bearer $TOKEN" | jq +``` + +**Expected**: +```json +{ + "status": "healthy", + "runtime": "claude-code", + "runtime_available": true +} +``` + +### 3.3 Check Agent Health - Gemini + +```bash +curl -s http://localhost:8000/api/agents/test-gemini/health \ + -H "Authorization: Bearer $TOKEN" | jq +``` + +**Expected**: +```json +{ + "status": "healthy", + "runtime": "gemini-cli", + "runtime_available": true +} +``` + +### 3.4 Test Chat API - Gemini + +```bash +curl -s -X POST http://localhost:8000/api/agents/test-gemini/chat \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"message": "What is 2+2? Reply with just the number."}' | jq +``` + +**Expected**: Response with `"response"`, `"metadata"` including cost/tokens + +### 3.5 Test Model API - Gemini + +```bash +# Get current model +curl -s http://localhost:8000/api/agents/test-gemini/proxy/api/model \ + -H "Authorization: Bearer $TOKEN" | jq + +# Should show available_models: ["gemini-2.5-pro", "gemini-2.5-flash", ...] +``` + +### 3.6 Test Session Info + +```bash +curl -s http://localhost:8000/api/agents/test-gemini/proxy/api/chat/session \ + -H "Authorization: Bearer $TOKEN" | jq +``` + +**Expected**: Shows `context_window: 1000000` for Gemini + +--- + +## Phase 4: Agent-to-Agent Communication (15 min) + +This tests if a Gemini agent can delegate tasks to a Claude agent (and vice versa). + +### 4.1 Create Orchestrator Agent (Gemini) + +```bash +# Create orchestrator that uses Gemini +curl -s -X POST http://localhost:8000/api/agents \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "orchestrator-gemini", + "type": "orchestrator", + "runtime": "gemini-cli", + "runtime_model": "gemini-2.5-pro", + "resources": {"cpu": "2", "memory": "4g"} + }' | jq +``` + +### 4.2 Create Worker Agent (Claude) + +```bash +# Create worker that uses Claude +curl -s -X POST http://localhost:8000/api/agents \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "worker-claude", + "type": "worker", + "runtime": "claude-code", + "resources": {"cpu": "2", "memory": "4g"} + }' | jq +``` + +### 4.3 Grant Permissions + +```bash +# Grant orchestrator permission to call worker +curl -s -X POST http://localhost:8000/api/agents/orchestrator-gemini/permissions \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"target_agent": "worker-claude", "permission": "delegate"}' | jq +``` + +### 4.4 Test Cross-Runtime Delegation + +In the UI or via API, send to `orchestrator-gemini`: + +``` +Use the Trinity MCP tools to send a task to worker-claude asking it to +calculate the factorial of 5. Report back what it says. +``` + +**Expected**: +- Gemini orchestrator calls Trinity MCP +- Worker (Claude) receives task +- Worker responds with "120" +- Orchestrator reports result + +### 4.5 Verify in Logs + +```bash +# Check orchestrator logs +docker logs agent-orchestrator-gemini 2>&1 | tail -20 + +# Check worker logs +docker logs agent-worker-claude 2>&1 | tail -20 +``` + +--- + +## Phase 5: Edge Cases & Error Handling (5 min) + +### 5.1 Test Without Google API Key + +```bash +# Create agent without GOOGLE_API_KEY in container +# (This should fail gracefully) +docker exec agent-test-gemini env | grep -i google +# Should show GOOGLE_API_KEY +``` + +### 5.2 Test Invalid Model + +```bash +curl -s -X PUT http://localhost:8000/api/agents/test-gemini/proxy/api/model \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"model": "invalid-model-name"}' | jq +``` + +**Expected**: Error message about invalid model + +### 5.3 Test Rate Limiting (Gemini Free Tier) + +Send multiple rapid requests to test free tier limits: + +```bash +for i in {1..5}; do + curl -s -X POST http://localhost:8000/api/agents/test-gemini/chat \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"message\": \"Count to $i\"}" & +done +wait +``` + +**Expected**: All should succeed (free tier is 60/min) + +### 5.4 Test Parallel Task (Headless) + +```bash +curl -s -X POST http://localhost:8000/api/agents/test-gemini/proxy/api/task \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "message": "What is the capital of France? Reply in one word.", + "timeout_seconds": 30 + }' | jq +``` + +**Expected**: Returns response with `session_id` + +--- + +## Phase 6: Cleanup + +```bash +# Delete test agents +for agent in test-claude test-gemini orchestrator-gemini worker-claude; do + curl -s -X DELETE "http://localhost:8000/api/agents/$agent" \ + -H "Authorization: Bearer $TOKEN" + echo "Deleted: $agent" +done +``` + +--- + +## Test Results Checklist + +### Core Functionality +- [ ] Claude agent creates and chats successfully +- [ ] Gemini agent creates and chats successfully +- [ ] Context window shows correctly (200K vs 1M) +- [ ] Cost tracking works for both runtimes +- [ ] Model selection works for Gemini + +### API Endpoints +- [ ] `/api/version` returns runtime info +- [ ] `/health` shows runtime status +- [ ] Chat API works for both runtimes +- [ ] Model API validates correctly per runtime +- [ ] Session API shows correct context window + +### Agent Communication +- [ ] Gemini → Claude delegation works +- [ ] Claude → Gemini delegation works (optional test) +- [ ] MCP tools accessible from both runtimes + +### Error Handling +- [ ] Invalid model rejected with clear error +- [ ] Missing API key shows helpful message +- [ ] Rate limits handled gracefully + +--- + +## Issues Found + +Document any issues here during testing: + +| Issue | Severity | Notes | +|-------|----------|-------| +| | | | +| | | | +| | | | + +--- + +## Next Steps + +After testing: +1. Fix any issues found +2. Update changelog if needed +3. Create PR for review +4. Tag release: `git tag v0.9.0` + diff --git a/gemini-research-summary.md b/gemini-research-summary.md new file mode 100644 index 000000000..bbb455760 --- /dev/null +++ b/gemini-research-summary.md @@ -0,0 +1,97 @@ +# Gemini CLI Research - Trinity Universal Runtime Support + +## Key Findings + +### ✅ Gemini CLI IS MCP-Compatible! + +**Package:** `@google/gemini-cli` (npm) +**Version:** 0.22.4 (as of Dec 2025) + +### MCP Support +```bash +gemini mcp add [args...] # Add MCP server +gemini mcp remove # Remove server +gemini mcp list # List configured servers +``` + +**Important:** Gemini CLI uses its OWN MCP configuration format (not `.mcp.json`). +It stores MCP servers via CLI commands, similar to how npm manages global packages. + +### CLI Feature Parity with Claude Code + +| Feature | Claude Code | Gemini CLI | Compatible? | +|---------|-------------|------------|-------------| +| **Output Format** | `--output-format stream-json` | `--output-format stream-json` | ✅ YES | +| **Tool Restrictions** | `--allowedTools` | `--allowed-tools` | ✅ YES | +| **Session Continuity** | `--continue` | `--resume` | ✅ YES | +| **MCP Support** | `.mcp.json` file | `gemini mcp add` command | ⚠️ DIFFERENT | +| **Non-interactive** | `--print` | `-p/--prompt` | ✅ YES | +| **YOLO Mode** | `--dangerously-skip-permissions` | `--yolo` or `--approval-mode yolo` | ✅ YES | + +### Context Window +- **Gemini:** 1 million tokens (5x larger than Claude Code!) +- **Claude Code:** 200K tokens + +### Pricing +- **Gemini:** FREE tier (60 req/min, 1K/day) +- **Claude Code:** Pay-per-use (API costs) + +## Trinity Integration Path + +### Option 1: Adapter Layer (Recommended) +Create a `GeminiAdapter` that translates Trinity's interface: + +```python +# agent_server/services/gemini_adapter.py +class GeminiRuntime: + def execute(prompt, mcp_servers): + # 1. Configure MCP servers via "gemini mcp add" + for server_name, server_config in mcp_servers.items(): + subprocess.run(["gemini", "mcp", "add", server_name, ...]) + + # 2. Execute with same flags as Claude Code + result = subprocess.run([ + "gemini", + "--output-format", "stream-json", + "--prompt", prompt, + "--resume" # for session continuity + ]) + + return parse_stream_json_output(result.stdout) +``` + +### Option 2: Runtime Selector in Templates +```yaml +# template.yaml +runtime: + type: gemini-cli # or "claude-code" + model: gemini-2.5-pro + max_context: 1000000 +``` + +### Key Differences to Handle +1. **MCP Config:** Gemini uses `gemini mcp add` instead of `.mcp.json` +2. **Authentication:** Needs `GOOGLE_API_KEY` instead of `ANTHROPIC_API_KEY` +3. **Session Format:** `--resume` works differently than `--continue` + +## Next Steps + +1. **Prototype:** Create `gemini_adapter.py` that mirrors `claude_code.py` +2. **Test:** Run side-by-side comparison of same task +3. **Bridge:** Build MCP config translator (`.mcp.json` → `gemini mcp add` commands) +4. **Extend:** Add runtime selector to `AgentConfig` model + +## Business Value + +**Cost Savings:** +- Run 10 Gemini agents free vs $5-10/day for Claude +- Use Gemini for simple tasks, Claude for complex reasoning + +**Redundancy:** +- If Anthropic API is down, Gemini keeps working +- Multi-cloud strategy + +**Feature Access:** +- 1M context window for huge codebases +- Google Search integration built-in + diff --git a/scripts/deploy/build-base-image.sh b/scripts/deploy/build-base-image.sh index 2fb53cf13..f77a94829 100755 --- a/scripts/deploy/build-base-image.sh +++ b/scripts/deploy/build-base-image.sh @@ -4,14 +4,26 @@ set -e cd "$(dirname "$0")/../.." +# Read version from VERSION file +VERSION=$(cat VERSION 2>/dev/null || echo "latest") +VERSION=$(echo "$VERSION" | tr -d '[:space:]') + echo "=====================================" echo "Building Trinity Agent Base Image" +echo "Version: $VERSION" echo "=====================================" echo "" -docker build -t trinity-agent-base:latest -f docker/base-image/Dockerfile docker/base-image/ +# Build with version tag and latest tag +docker build \ + -t trinity-agent-base:${VERSION} \ + -t trinity-agent-base:latest \ + --build-arg VERSION=${VERSION} \ + -f docker/base-image/Dockerfile docker/base-image/ echo "" -echo "✅ Base image built successfully: trinity-agent-base:latest" +echo "✅ Base image built successfully:" +echo " - trinity-agent-base:${VERSION}" +echo " - trinity-agent-base:latest" echo "" diff --git a/src/backend/database.py b/src/backend/database.py index e02a48039..4a9a4c99d 100644 --- a/src/backend/database.py +++ b/src/backend/database.py @@ -581,8 +581,9 @@ def init_database(): def _ensure_admin_user(cursor, conn): """Ensure the admin user exists with properly hashed password.""" admin_password = os.getenv("ADMIN_PASSWORD", "") + admin_username = os.getenv("ADMIN_USERNAME", "admin") - cursor.execute("SELECT id, password_hash FROM users WHERE username = ?", ("admin",)) + cursor.execute("SELECT id, password_hash FROM users WHERE username = ?", (admin_username,)) existing = cursor.fetchone() if existing is None: @@ -601,9 +602,9 @@ def _ensure_admin_user(cursor, conn): cursor.execute(""" INSERT INTO users (username, password_hash, role, created_at, updated_at) VALUES (?, ?, ?, ?, ?) - """, ("admin", hashed, "admin", now, now)) + """, (admin_username, hashed, "admin", now, now)) conn.commit() - print("Created admin user with hashed password") + print(f"Created admin user '{admin_username}' with hashed password") else: # Check if existing password needs migration from plaintext to bcrypt existing_hash = existing[1] @@ -617,9 +618,9 @@ def _ensure_admin_user(cursor, conn): cursor.execute(""" UPDATE users SET password_hash = ?, updated_at = ? WHERE username = ? - """, (hashed, datetime.utcnow().isoformat(), "admin")) + """, (hashed, datetime.utcnow().isoformat(), admin_username)) conn.commit() - print("Migrated admin password from plaintext to bcrypt") + print(f"Migrated admin user '{admin_username}' password from plaintext to bcrypt") class DatabaseManager: diff --git a/src/backend/main.py b/src/backend/main.py index b81a28f89..f8e495098 100644 --- a/src/backend/main.py +++ b/src/backend/main.py @@ -299,6 +299,32 @@ async def health_check(): return {"status": "healthy", "timestamp": datetime.now()} +# Version endpoint +@app.get("/api/version") +async def get_version(): + """Get Trinity platform version information.""" + import os + from pathlib import Path + + # Read version from VERSION file + version_file = Path(__file__).parent.parent.parent / "VERSION" + version = "unknown" + if version_file.exists(): + version = version_file.read_text().strip() + + return { + "version": version, + "platform": "trinity", + "components": { + "backend": version, + "agent_server": version, + "base_image": f"trinity-agent-base:{version}" + }, + "runtimes": ["claude-code", "gemini-cli"], + "build_date": os.getenv("BUILD_DATE", "unknown") + } + + # Audit logs endpoint (admin only) @app.get("/api/audit/logs") async def get_audit_logs( diff --git a/src/backend/models.py b/src/backend/models.py index 42656efb4..ef18a5533 100644 --- a/src/backend/models.py +++ b/src/backend/models.py @@ -21,6 +21,9 @@ class AgentConfig(BaseModel): # GitHub-native agent support github_repo: Optional[str] = None # GitHub repo (e.g., "Abilityai/agent-ruby") github_credential_id: Optional[str] = None # Credential ID for GitHub PAT + # Multi-runtime support + runtime: Optional[str] = "claude-code" # "claude-code" or "gemini-cli" + runtime_model: Optional[str] = None # Model override (e.g., "sonnet-4.5", "gemini-2.5-pro") class AgentStatus(BaseModel): @@ -33,6 +36,7 @@ class AgentStatus(BaseModel): resources: dict container_id: Optional[str] = None template: Optional[str] = None + runtime: Optional[str] = "claude-code" # "claude-code" or "gemini-cli" class Config: json_encoders = { diff --git a/src/backend/routers/agents.py b/src/backend/routers/agents.py index 388cb018c..53570c292 100644 --- a/src/backend/routers/agents.py +++ b/src/backend/routers/agents.py @@ -798,12 +798,14 @@ async def update_agent_api_key_setting( async def agent_terminal( websocket: WebSocket, agent_name: str, - mode: str = Query(default="claude") + mode: str = Query(default="claude"), + model: str = Query(default=None) ): """Interactive terminal WebSocket for any agent.""" await _terminal_manager.handle_terminal_session( websocket=websocket, agent_name=agent_name, mode=mode, - decode_token_fn=decode_token + decode_token_fn=decode_token, + model=model ) diff --git a/src/backend/routers/chat.py b/src/backend/routers/chat.py index e0454db90..498d6da87 100644 --- a/src/backend/routers/chat.py +++ b/src/backend/routers/chat.py @@ -354,6 +354,16 @@ async def execute_parallel_task( action="parallel_task" ) + # Create execution record for manual tasks (so they appear in Tasks panel) + # Use "manual" as schedule_id for manual/user-triggered tasks + triggered_by = "agent" if x_source_agent else "manual" + execution_record = db.create_schedule_execution( + schedule_id="manual", + agent_name=name, + message=request.message, + triggered_by=triggered_by + ) + try: # Build payload for agent's /api/task endpoint payload = { @@ -380,6 +390,18 @@ async def execute_parallel_task( execution_time_ms = int((datetime.utcnow() - start_time).total_seconds() * 1000) metadata = response_data.get("metadata", {}) + # Update execution record with success + if execution_record: + db.update_execution_status( + execution_id=execution_record.id, + status="success", + response=response_data.get("response", ""), + context_used=metadata.get("context_used"), + context_max=metadata.get("context_max"), + cost=metadata.get("cost_usd"), + tool_calls=str(len(response_data.get("execution_log", []))) + ) + # Track task completion await activity_service.complete_activity( activity_id=task_activity_id, @@ -410,6 +432,14 @@ async def execute_parallel_task( return response_data except httpx.TimeoutException: + # Update execution record with failure + if execution_record: + db.update_execution_status( + execution_id=execution_record.id, + status="failed", + error=f"Task execution timed out after {request.timeout_seconds} seconds" + ) + await activity_service.complete_activity( activity_id=task_activity_id, status="failed", @@ -435,6 +465,14 @@ async def execute_parallel_task( import logging logging.getLogger("trinity.errors").error(f"Failed to execute parallel task on {name}: {e}") + # Update execution record with failure + if execution_record: + db.update_execution_status( + execution_id=execution_record.id, + status="failed", + error=f"HTTP error: {type(e).__name__}" + ) + await activity_service.complete_activity( activity_id=task_activity_id, status="failed", diff --git a/src/backend/routers/system_agent.py b/src/backend/routers/system_agent.py index 40f792694..6ccba8f6c 100644 --- a/src/backend/routers/system_agent.py +++ b/src/backend/routers/system_agent.py @@ -459,7 +459,13 @@ async def system_agent_terminal( ) # Step 5: Create exec with TTY - cmd = ["claude"] if mode == "claude" else ["/bin/bash"] + # Support multiple terminal modes: claude (Claude Code), gemini (Gemini CLI), bash + if mode == "claude": + cmd = ["claude"] + elif mode == "gemini": + cmd = ["gemini"] + else: + cmd = ["/bin/bash"] # Use docker API to create exec instance exec_instance = docker_client.api.exec_create( diff --git a/src/backend/routers/templates.py b/src/backend/routers/templates.py index 215062fc5..4352a73f4 100644 --- a/src/backend/routers/templates.py +++ b/src/backend/routers/templates.py @@ -48,10 +48,14 @@ async def list_templates(current_user: User = Depends(get_current_user)): "mcp_servers": template_data.get("mcp_servers", []), "resources": template_data.get("resources", {"cpu": "2", "memory": "4g"}), "source": "local", - "required_credentials": creds_info.get("required_credentials", []) + "required_credentials": creds_info.get("required_credentials", []), + "priority": template_data.get("priority", 100) # Default priority }) except Exception as e: print(f"Error loading template {template_path}: {e}") + + # Sort by priority (lower = higher in list), then by display_name + templates.sort(key=lambda t: (t.get("priority", 100), t.get("display_name", ""))) return templates diff --git a/src/backend/services/agent_service/crud.py b/src/backend/services/agent_service/crud.py index bec63d936..ad597bdca 100644 --- a/src/backend/services/agent_service/crud.py +++ b/src/backend/services/agent_service/crud.py @@ -128,6 +128,13 @@ async def create_agent_internal( mcp_servers = list(creds.get("mcp_servers", {}).keys()) if mcp_servers: config.mcp_servers = mcp_servers + # Multi-runtime support - extract runtime config from template + runtime_config = template_data.get("runtime", {}) + if isinstance(runtime_config, dict): + config.runtime = runtime_config.get("type", config.runtime) + config.runtime_model = runtime_config.get("model", config.runtime_model) + elif isinstance(runtime_config, str): + config.runtime = runtime_config except Exception as e: logger.warning(f"Error loading template config: {e}") @@ -221,9 +228,21 @@ async def create_agent_internal( 'ENABLE_SSH': 'true', 'ENABLE_AGENT_UI': 'true', 'AGENT_SERVER_PORT': '8000', - 'TEMPLATE_NAME': config.template if config.template else '' + 'TEMPLATE_NAME': config.template if config.template else '', + # Multi-runtime support + 'AGENT_RUNTIME': config.runtime or 'claude-code', + 'AGENT_RUNTIME_MODEL': config.runtime_model or '' } + # Add Google API key if using Gemini runtime + # Gemini CLI expects GEMINI_API_KEY environment variable + if config.runtime == 'gemini-cli' or config.runtime == 'gemini': + google_api_key = os.getenv('GOOGLE_API_KEY', '') + if google_api_key: + env_vars['GEMINI_API_KEY'] = google_api_key # Gemini CLI expects this name + else: + logger.warning("Gemini runtime selected but GOOGLE_API_KEY not configured") + # OpenTelemetry Configuration (enabled by default) # Claude Code has built-in OTel support - these vars enable metrics export if os.getenv('OTEL_ENABLED', '1') == '1': @@ -358,7 +377,8 @@ async def create_agent_internal( 'trinity.cpu': config.resources['cpu'], 'trinity.memory': config.resources['memory'], 'trinity.created': datetime.now().isoformat(), - 'trinity.template': config.template or '' + 'trinity.template': config.template or '', + 'trinity.agent-runtime': config.runtime or 'claude-code' }, security_opt=['no-new-privileges:true', 'apparmor:docker-default'], cap_drop=['ALL'], diff --git a/src/backend/services/agent_service/deploy.py b/src/backend/services/agent_service/deploy.py index d61d5e76f..17e926ae9 100644 --- a/src/backend/services/agent_service/deploy.py +++ b/src/backend/services/agent_service/deploy.py @@ -218,11 +218,23 @@ async def deploy_local_agent_logic( logger.info(f"Copied agent template to: {dest_path}") # 10. Create agent + # Extract runtime config from template + runtime_config = template_data.get("runtime", {}) + runtime_type = None + runtime_model = None + if isinstance(runtime_config, dict): + runtime_type = runtime_config.get("type") + runtime_model = runtime_config.get("model") + elif isinstance(runtime_config, str): + runtime_type = runtime_config + agent_config = AgentConfig( name=version_name, template=f"local:{version_name}", type=template_data.get("type", "business-assistant"), - resources=template_data.get("resources", {"cpu": "2", "memory": "4g"}) + resources=template_data.get("resources", {"cpu": "2", "memory": "4g"}), + runtime=runtime_type, + runtime_model=runtime_model ) agent_status = await create_agent_fn( diff --git a/src/backend/services/agent_service/terminal.py b/src/backend/services/agent_service/terminal.py index 852d6c1b0..93778bae1 100644 --- a/src/backend/services/agent_service/terminal.py +++ b/src/backend/services/agent_service/terminal.py @@ -60,7 +60,8 @@ async def handle_terminal_session( websocket: WebSocket, agent_name: str, mode: str, - decode_token_fn + decode_token_fn, + model: str = None ): """ Handle a WebSocket terminal session. @@ -68,8 +69,9 @@ async def handle_terminal_session( Args: websocket: The WebSocket connection agent_name: Name of the agent to connect to - mode: Terminal mode ('claude' or 'bash') + mode: Terminal mode ('claude', 'gemini', or 'bash') decode_token_fn: Function to decode JWT tokens + model: Optional model to use (e.g., 'gemini-2.5-flash', 'sonnet') """ await websocket.accept() @@ -190,7 +192,19 @@ async def handle_terminal_session( ) # Step 5: Create exec with TTY - cmd = ["claude"] if mode == "claude" else ["/bin/bash"] + # Support multiple terminal modes: claude (Claude Code), gemini (Gemini CLI), bash + if mode == "claude": + cmd = ["claude"] + if model: + cmd.extend(["--model", model]) + elif mode == "gemini": + cmd = ["gemini"] + if model: + cmd.extend(["--model", model]) + else: + cmd = ["/bin/bash"] + + logger.info(f"Starting terminal with command: {cmd}") # Use docker API to create exec instance exec_instance = docker_client.api.exec_create( diff --git a/src/backend/services/docker_service.py b/src/backend/services/docker_service.py index a6dfe5adc..93deb27ec 100644 --- a/src/backend/services/docker_service.py +++ b/src/backend/services/docker_service.py @@ -43,6 +43,18 @@ def get_agent_status_from_container(container) -> AgentStatus: else: normalized_status = docker_status # paused, restarting, etc. + # Extract runtime from container environment variables + runtime = "claude-code" # Default + try: + # Get environment variables from container attrs + env_list = container.attrs.get("Config", {}).get("Env", []) + for env in env_list: + if env.startswith("AGENT_RUNTIME="): + runtime = env.split("=", 1)[1] + break + except Exception: + pass # Use default if we can't read env vars + return AgentStatus( name=agent_name, type=labels.get("trinity.agent-type", "unknown"), @@ -54,7 +66,8 @@ def get_agent_status_from_container(container) -> AgentStatus: "memory": labels.get("trinity.memory", "4g") }, container_id=container.id, - template=labels.get("trinity.template", None) or None + template=labels.get("trinity.template", None) or None, + runtime=runtime ) diff --git a/src/frontend/src/components/AgentNode.vue b/src/frontend/src/components/AgentNode.vue index a1287a15f..500584593 100644 --- a/src/frontend/src/components/AgentNode.vue +++ b/src/frontend/src/components/AgentNode.vue @@ -21,12 +21,14 @@
- +
{{ data.label }}
+ +
-

Blank Agent

-

Start with an empty configuration

+

Blank Agent (Claude Code)

+

Start with empty config using Claude Code runtime

@@ -67,16 +67,16 @@
- -
+ +

- - + + - GitHub Templates + Local Templates

-
- - +
+ +

{{ template.display_name }}

-

{{ template.github_repo }}

+

{{ truncateDescription(template.description) }}

@@ -101,16 +101,16 @@
- -
+ +

- - + + - Local Templates + GitHub Templates

-
- - +
+ +

{{ template.display_name }}

-

{{ truncateDescription(template.description) }}

+

{{ template.github_repo }}

diff --git a/src/frontend/src/components/RuntimeBadge.vue b/src/frontend/src/components/RuntimeBadge.vue new file mode 100644 index 000000000..3d75214ae --- /dev/null +++ b/src/frontend/src/components/RuntimeBadge.vue @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ label }} + + + + + diff --git a/src/frontend/src/composables/useSessionActivity.js b/src/frontend/src/composables/useSessionActivity.js index 2f15036bd..448a0334d 100644 --- a/src/frontend/src/composables/useSessionActivity.js +++ b/src/frontend/src/composables/useSessionActivity.js @@ -2,9 +2,65 @@ import { ref, computed, onUnmounted } from 'vue' /** * Composable for session info and activity polling - * Manages context window, token usage, and activity status + * Manages context window, token usage, cost tracking, and activity status + * + * ============================================================================= + * REUSABLE COST & CONTEXT TRACKING LOGIC + * ============================================================================= + * + * This composable contains the core logic for tracking session costs and context + * window usage. While currently not displayed in the Terminal tab, this data is + * still collected and can be reused in other UI components. + * + * DATA AVAILABLE (via sessionInfo ref): + * - context_tokens: Current token count used in the session + * - context_window: Maximum context window size (e.g., 200000 for Claude) + * - context_percent: Percentage of context window used (0-100) + * - total_cost_usd: Cumulative session cost in USD + * - message_count: Number of messages in the session + * + * BACKEND API: + * - Endpoint: GET /api/agents/{name}/chat/session + * - Returns session data from the agent's internal API at http://agent-{name}:8000/api/chat/session + * + * USAGE EXAMPLE (for future UI integration): + * ```vue + * + * + * + * ``` + * + * RELATED FILES: + * - src/backend/routers/chat.py - Backend endpoint for session data + * - src/backend/services/scheduler_service.py - Uses cost data for scheduled executions + * - src/frontend/src/components/SchedulesPanel.vue - Shows cost in execution history + * - src/frontend/src/stores/agents.js - getSessionInfo() store method + * + * TODO: Consider integrating cost/context display into: + * - Dashboard overview + * - Agent metrics panel + * - Activity timeline + * ============================================================================= */ export function useSessionActivity(agentRef, agentsStore) { + /** + * Session info containing cost and context window tracking data. + * This data is fetched from the agent's internal chat session API. + * + * @property {number} context_tokens - Current tokens used in context + * @property {number} context_window - Max context window size (model-dependent) + * @property {number} context_percent - Percentage of context used (0-100) + * @property {number} total_cost_usd - Cumulative session cost in USD + * @property {number} message_count - Number of messages exchanged + */ const sessionInfo = ref({ context_tokens: 0, context_window: 200000, diff --git a/src/frontend/src/stores/agents.js b/src/frontend/src/stores/agents.js index 51e136fe9..01e9026cd 100644 --- a/src/frontend/src/stores/agents.js +++ b/src/frontend/src/stores/agents.js @@ -95,7 +95,8 @@ export const useAgentsStore = defineStore('agents', { const response = await axios.post('/api/agents', config, { headers: authStore.authHeader }) - this.agents.push(response.data) + // Don't push here - WebSocket 'agent_created' event handles adding to list + // This prevents duplicate entries from race conditions return response.data } catch (error) { this.error = error.response?.data?.detail || error.message diff --git a/src/frontend/src/stores/network.js b/src/frontend/src/stores/network.js index c61e54793..a560d1c46 100644 --- a/src/frontend/src/stores/network.js +++ b/src/frontend/src/stores/network.js @@ -247,6 +247,7 @@ export const useNetworkStore = defineStore('network', () => { status: agent.status, type: agent.type || 'business-assistant', owner: agent.owner, + runtime: agent.runtime || 'claude-code', githubRepo: agent.github_repo || null, is_system: agent.is_system || false, // Set initial activityState based on running status to avoid "Offline" flash diff --git a/src/frontend/src/utils/websocket.js b/src/frontend/src/utils/websocket.js index 5266fa6bb..aa89b2094 100644 --- a/src/frontend/src/utils/websocket.js +++ b/src/frontend/src/utils/websocket.js @@ -51,7 +51,11 @@ export function useWebSocket() { const handleMessage = (data) => { switch (data.event) { case 'agent_created': - agentsStore.agents.push(data.data) + // Add to list (createAgent() no longer pushes to avoid race conditions) + // Still check for duplicates in case of reconnection/replay + if (!agentsStore.agents.find(a => a.name === data.data.name)) { + agentsStore.agents.push(data.data) + } break case 'agent_deleted': agentsStore.agents = agentsStore.agents.filter(a => a.name !== data.data.name) diff --git a/src/frontend/src/views/AgentDetail.vue b/src/frontend/src/views/AgentDetail.vue index cdec458f0..db2935cbe 100644 --- a/src/frontend/src/views/AgentDetail.vue +++ b/src/frontend/src/views/AgentDetail.vue @@ -35,6 +35,8 @@ ]"> {{ agent.status }} + +
-
+