- Created logs/ structure (sessions, operations, incidents) - Added session-start/log/end scripts - Installed Git hooks for auto-logging commits/pushes - Added shell integration for zsh - Created CHANGELOG.md - Documented today's session (2026-01-10)
8.3 KiB
Agent Runtime Service
Executes agent logic: reads context, calls LLM, posts replies
Purpose
Agent Runtime is the execution engine for DAARION agents. It processes agent invocations by:
- Loading agent blueprints
- Reading channel history for context
- Querying agent memory (RAG)
- Building prompts for LLM
- Generating responses
- Posting back to channels
- Storing interactions in memory
Architecture
router.invoke.agent (NATS)
↓
agent-runtime: Execute Agent Logic
↓
├─ Load Blueprint
├─ Read Channel History
├─ Query Memory (RAG)
├─ Call LLM
└─ Post Reply
↓
messaging-service → Matrix → Frontend
Features
- NATS Integration: Subscribes to
router.invoke.agent - Context Loading: Fetches last 50 messages from channel
- Memory Integration: Queries agent memory for relevant context
- LLM Integration: Calls LLM Proxy with full context
- Mock LLM: Falls back to mock responses when LLM Proxy unavailable (Phase 2)
- Message Posting: Posts replies via messaging-service
- Memory Writeback: Stores interactions for future RAG
API
Health Check
GET /health
Response:
{
"status": "ok",
"service": "agent-runtime",
"version": "1.0.0",
"nats_connected": true
}
Test Invocation (Manual)
POST /internal/agent-runtime/test-channel
Content-Type: application/json
{
"agent_id": "agent:sofia",
"entrypoint": "channel_message",
"payload": {
"channel_id": "7c72d497-27aa-4e75-bb2f-4a4a21d4f91f",
"microdao_id": "microdao:daarion",
"rewrite_prompt": null
}
}
Response:
{
"status": "processed",
"agent_id": "agent:sofia"
}
Configuration
File: config.yaml
nats:
servers: ["nats://nats:4222"]
invocation_subject: "router.invoke.agent"
services:
messaging: "http://messaging-service:7004"
agent_memory: "http://agent-memory:7008"
llm_proxy: "http://llm-proxy:7007"
llm:
default_model: "gpt-4"
max_tokens: 1000
temperature: 0.7
memory:
query_top_k: 5
enable_writeback: true
Environment Variables
NATS_URL: NATS server URL (default:nats://nats:4222)MESSAGING_SERVICE_URL: messaging-service URL (default:http://messaging-service:7004)AGENT_MEMORY_URL: agent-memory URL (default:http://agent-memory:7008)LLM_PROXY_URL: LLM Proxy URL (default:http://llm-proxy:7007)
Running Locally
Install Dependencies
pip install -r requirements.txt
Run Service
uvicorn main:app --reload --port 7006
Test
# Health check
curl http://localhost:7006/health
# Test invocation
curl -X POST http://localhost:7006/internal/agent-runtime/test-channel \
-H "Content-Type: application/json" \
-d '{
"agent_id": "agent:sofia",
"entrypoint": "channel_message",
"payload": {
"channel_id": "7c72d497-27aa-4e75-bb2f-4a4a21d4f91f",
"microdao_id": "microdao:daarion"
}
}'
Docker
Build
docker build -t daarion/agent-runtime:latest .
Run
docker run -p 7006:7006 \
-e MESSAGING_SERVICE_URL=http://messaging-service:7004 \
-e NATS_URL=nats://nats:4222 \
daarion/agent-runtime:latest
Agent Execution Flow
1. Receive Invocation
From NATS subject router.invoke.agent:
{
"agent_id": "agent:sofia",
"entrypoint": "channel_message",
"payload": {
"channel_id": "uuid",
"message_id": "uuid",
"matrix_event_id": "$event:server",
"microdao_id": "microdao:X",
"rewrite_prompt": "Optional prompt modification"
}
}
2. Load Blueprint
Currently mock (Phase 2), will call agents-service in Phase 3:
blueprint = {
"name": "Sofia-Prime",
"model": "gpt-4",
"instructions": "System prompt...",
"capabilities": {...},
"tools": ["create_task", "summarize_channel"]
}
3. Load Context
Fetch last 50 messages from messaging-service:
GET /api/messaging/channels/{channel_id}/messages?limit=50
4. Query Memory
RAG query to agent-memory:
POST /internal/agent-memory/query
{
"agent_id": "agent:sofia",
"microdao_id": "microdao:daarion",
"query": "last user message",
"k": 5
}
5. Build Prompt
Combine:
- System prompt (from blueprint)
- Rewrite prompt (if quiet hours)
- Memory context (top-K results)
- Recent messages (last 10)
6. Generate Response
Call LLM Proxy:
POST /internal/llm/proxy
{
"model": "gpt-4",
"messages": [
{"role": "system", "content": "..."},
{"role": "user", "content": "..."},
...
]
}
Falls back to mock response if unavailable.
7. Post Reply
Post to messaging-service:
POST /internal/agents/{agent_id}/post-to-channel
{
"channel_id": "uuid",
"text": "Agent response..."
}
8. Store Memory
(Optional) Store interaction:
POST /internal/agent-memory/store
{
"agent_id": "agent:sofia",
"microdao_id": "microdao:daarion",
"content": {
"user_message": "...",
"agent_reply": "..."
}
}
Mock LLM (Phase 2)
When LLM Proxy is not available, agent-runtime uses mock responses based on keywords:
- "привіт" / "hello" → Greeting
- "допомож" / "help" → Help menu
- "дяку" / "thank" → Thanks acknowledgment
- "phase 2" → Phase 2 explanation
- "?" → Question response
This allows testing the full flow without real LLM in Phase 2.
NATS Events
Subscribes To
- Subject:
router.invoke.agent - Payload:
AgentInvocation
Publishes To
None directly (replies via messaging-service HTTP)
Monitoring
Logs
# Docker
docker logs -f agent-runtime
# Look for:
# ✅ Connected to NATS
# ✅ Subscribed to router.invoke.agent
# 🤖 Processing agent invocation
# 📝 Agent: agent:sofia
# ✅ Loaded blueprint
# ✅ Fetched N messages
# 💬 User message: ...
# 🤔 Generating response...
# ✅ Generated response
# ✅ Posted message to channel
# ✅ Agent replied successfully
Metrics (Future)
- Total invocations processed
- Average response time
- LLM calls per agent
- Success/failure rate
- Memory query latency
Troubleshooting
Agent Not Responding
Check logs:
docker logs agent-runtime | tail -50
Common issues:
- Not receiving invocations from router
- Cannot fetch channel messages
- LLM error (check mock fallback)
- Cannot post to channel
Cannot Post to Channel
❌ HTTP error posting message: 404
Endpoint not found. You may need to add it to messaging-service.
Solution: Ensure messaging-service has internal endpoint:
POST /internal/agents/{agent_id}/post-to-channel
Memory Errors
⚠️ Agent Memory service not available (Phase 2 - OK)
This is expected in Phase 2. Agent continues without memory.
Phase 2 vs Phase 3
Phase 2 (Current)
- ✅ NATS subscription
- ✅ Channel history reading
- ✅ Mock LLM responses
- ✅ Message posting
- ⚠️ Mock agent blueprint
- ⚠️ Memory service optional
Phase 3 (Future)
- Real agent blueprint loading from agents-service
- Real LLM via LLM Proxy (OpenAI, Anthropic, DeepSeek)
- Full RAG with vector DB
- Tool invocation (create_task, etc.)
- Advanced prompt engineering
- Multi-agent coordination
Development
Adding New Capabilities
Edit load_agent_blueprint() in main.py:
async def load_agent_blueprint(agent_id: str) -> AgentBlueprint:
return AgentBlueprint(
id=agent_id,
name="Sofia-Prime",
model="gpt-4",
instructions="Your custom instructions...",
capabilities={
"can_create_tasks": True,
"can_use_tools": True, # NEW
"can_access_docs": True # NEW
},
tools=["new_tool", ...] # NEW
)
Testing Locally
- Start messaging-service (or mock it)
- Start NATS (or run in test mode)
- Run agent-runtime
- Send test invocation via HTTP
curl -X POST http://localhost:7006/internal/agent-runtime/test-channel \
-H "Content-Type: application/json" \
-d @test_invocation.json
Future Enhancements
- Tool invocation support
- Multi-turn conversations
- Streaming responses
- Context window management
- Agent personality customization
- A/B testing for prompts
- Agent analytics dashboard
Version
Current: 1.0.0
Status: Production Ready (Phase 2)
Last Updated: 2025-11-24