Add complete tool calling infrastructure for Claude Code-like functionality: Internal Tools (via GroveEngine IIO): - Scheduler: get_current_task, list_tasks, start_task, complete_task, start_break - Monitoring: get_focus_stats, get_current_app - Storage: save_note, query_notes, get_session_history - Voice: speak MCP Client (for external servers): - StdioTransport for fork/exec JSON-RPC communication - MCPClient for multi-server orchestration - Support for filesystem, brave-search, fetch servers Architecture: - IOBridge for sync request/response over async IIO pub/sub - Tool handlers added to all modules (SchedulerModule, MonitoringModule, StorageModule, VoiceModule) - LLMService unifies internal tools + MCP tools in ToolRegistry 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
16 KiB
16 KiB
Plan d'Intégration MCP + Agent Vocal
Objectif
Transformer AISSIA en "Claude Code vocal" : un assistant qui peut utiliser des tools (internes + MCP) pour accomplir des tâches, piloté par la voix.
Architecture Cible
┌─────────────────────────────────────────────────────────────────────────────┐
│ AISSIA - Agent Vocal │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌─────────────────────────────────────┐ │
│ │ Micro │───►│ STT │───►│ LLMService │ │
│ └──────────┘ │ (Whisper)│ │ (Agentic Loop) │ │
│ └──────────┘ │ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ ToolRegistry │ │ │
│ │ │ │ │ │
│ │ │ ┌───────────────────────┐ │ │ │
│ │ │ │ Internal Tools │ │ │ │
│ │ │ │ (via GroveEngine) │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ • get_schedule │ │ │ │
│ │ │ │ • start_break │ │ │ │
│ │ │ │ • get_focus_stats │ │ │ │
│ │ │ │ • save_note │ │ │ │
│ │ │ │ • query_history │ │ │ │
│ │ │ └───────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌───────────────────────┐ │ │ │
│ │ │ │ MCP Tools │ │ │ │
│ │ │ │ (via MCPClient) │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ • read_file │ │ │ │
│ │ │ │ • write_file │ │ │ │
│ │ │ │ • list_directory │ │ │ │
│ │ │ │ • web_search │ │ │ │
│ │ │ │ • fetch_url │ │ │ │
│ │ │ └───────────────────────┘ │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────┬──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌─────────────────────────────────────┐ │
│ │ Speaker │◄───│ TTS │◄───│ Response Text │ │
│ └──────────┘ │ (espeak) │ └─────────────────────────────────────┘ │
│ └──────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
COMMUNICATION INTERNE (GroveEngine IIO)
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Scheduler │ │ Monitoring │ │ Storage │ │ Voice │
│ Module │ │ Module │ │ Module │ │ Module │
├──────────────┤ ├──────────────┤ ├──────────────┤ ├──────────────┤
│ │ │ │ │ │ │ │
│ • tasks │ │ • app usage │ │ • sessions │ │ • TTS queue │
│ • breaks │ │ • focus time │ │ • notes │ │ • STT events │
│ • hyperfocus │ │ • idle │ │ • history │ │ │
│ │ │ │ │ │ │ │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │ │
└────────────────────┴────────────────────┴────────────────────┘
│
IIO Pub/Sub
│
┌───────────────┴───────────────┐
│ LLMService │
│ (écoute les tool:* topics) │
└───────────────────────────────┘
Phases d'Implémentation
Phase 1 : Tools Internes via IIO
Objectif : Les modules GroveEngine exposent leurs fonctionnalités comme tools LLM.
Fichiers à créer/modifier :
src/shared/tools/InternalTools.hpp- Définitions des tools internessrc/shared/tools/InternalTools.cpp- Implémentationsrc/services/LLMService.cpp- Enregistrement des tools
Tools à implémenter :
| Tool | Module Source | Description |
|---|---|---|
get_current_task |
SchedulerModule | Retourne la tâche en cours |
list_tasks |
SchedulerModule | Liste toutes les tâches planifiées |
start_task |
SchedulerModule | Démarre une tâche par ID |
complete_task |
SchedulerModule | Marque une tâche comme terminée |
start_break |
SchedulerModule | Déclenche une pause |
get_focus_stats |
MonitoringModule | Stats de focus (temps, apps) |
get_current_app |
MonitoringModule | App actuellement active |
save_note |
StorageModule | Sauvegarde une note |
query_notes |
StorageModule | Recherche dans les notes |
get_session_history |
StorageModule | Historique des sessions |
speak |
VoiceModule | Fait parler l'assistant |
Pattern d'implémentation :
// Le tool envoie une requête via IIO et attend la réponse
json InternalTools::executeGetCurrentTask(const json& input) {
// 1. Créer la requête
auto request = std::make_unique<grove::JsonDataNode>("request");
request->setString("action", "get_current_task");
// 2. Publier et attendre réponse (sync via promise/future)
auto response = m_ioBridge->requestAndWait("scheduler:query", std::move(request), 1000);
// 3. Convertir en JSON pour le LLM
return {
{"task_id", response->getString("task_id", "")},
{"task_name", response->getString("task_name", "")},
{"duration_minutes", response->getInt("duration_minutes", 0)}
};
}
Phase 2 : Client MCP
Objectif : Se connecter à des serveurs MCP externes (filesystem, brave-search, etc.)
Fichiers à créer :
src/shared/mcp/MCPClient.hpp- Interface client MCPsrc/shared/mcp/MCPClient.cpp- Implémentationsrc/shared/mcp/MCPTransport.hpp- Transport stdio/SSEsrc/shared/mcp/MCPTypes.hpp- Types MCP (Tool, Resource, etc.)
Protocole MCP simplifié :
Client Server (ex: filesystem)
│ │
│──── initialize ─────────────────►│
│◄─── initialized (capabilities) ──│
│ │
│──── tools/list ─────────────────►│
│◄─── tools (read_file, etc.) ─────│
│ │
│──── tools/call ─────────────────►│
│ {name: "read_file", │
│ arguments: {path: "..."}} │
│◄─── result ──────────────────────│
│ {content: "..."} │
│ │
Transport stdio :
class StdioTransport : public IMCPTransport {
public:
StdioTransport(const std::string& command, const std::vector<std::string>& args) {
// Fork + exec le serveur MCP
// Rediriger stdin/stdout pour JSON-RPC
}
json sendRequest(const std::string& method, const json& params) {
json request = {
{"jsonrpc", "2.0"},
{"id", m_nextId++},
{"method", method},
{"params", params}
};
// Écrire sur stdin du process
write(request.dump() + "\n");
// Lire la réponse sur stdout
return json::parse(readLine());
}
};
Configuration MCP :
// config/mcp.json
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-filesystem", "/home/user/documents"],
"enabled": true
},
"brave-search": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-brave-search"],
"env": {
"BRAVE_API_KEY": "${BRAVE_API_KEY}"
},
"enabled": true
},
"fetch": {
"command": "npx",
"args": ["-y", "@anthropic-ai/mcp-server-fetch"],
"enabled": true
}
}
}
Phase 3 : Unification ToolRegistry
Objectif : Le ToolRegistry agrège tools internes + MCP de façon transparente.
Modification de LLMService :
void LLMService::initializeTools() {
// 1. Tools internes (via IIO)
m_internalTools = std::make_unique<InternalTools>(m_io);
for (const auto& tool : m_internalTools->getTools()) {
m_toolRegistry.registerTool(tool);
}
// 2. Tools MCP (via MCPClient)
m_mcpClient = std::make_unique<MCPClient>();
m_mcpClient->loadConfig("config/mcp.json");
m_mcpClient->connectAll();
for (const auto& tool : m_mcpClient->listAllTools()) {
m_toolRegistry.registerTool(
tool.name,
tool.description,
tool.inputSchema,
[this, name = tool.name](const json& input) {
return m_mcpClient->callTool(name, input);
}
);
}
m_logger->info("Tools loaded: {} internal, {} MCP",
m_internalTools->size(), m_mcpClient->toolCount());
}
Phase 4 : Tests
Tests unitaires :
tests/test_internal_tools.cpp- Mock IIO, vérifier tool executiontests/test_mcp_client.cpp- Mock server, vérifier protocoletests/test_tool_registry.cpp- Vérifier aggregation
Test d'intégration :
// tests/integration/test_agentic_loop.cpp
TEST_CASE("Agentic loop with tools") {
LLMService service;
service.initialize(io);
service.loadConfig("config/llm.json");
// Simuler une query qui nécessite des tools
auto result = service.query("Quelle tâche je fais en ce moment ?");
// Vérifier que le tool get_current_task a été appelé
REQUIRE(result.contains("task"));
}
Fichiers à Créer
src/
├── shared/
│ ├── tools/
│ │ ├── InternalTools.hpp # Tools internes (IIO)
│ │ ├── InternalTools.cpp
│ │ └── IOBridge.hpp # Request/response sync via IIO
│ └── mcp/
│ ├── MCPClient.hpp # Client MCP principal
│ ├── MCPClient.cpp
│ ├── MCPTransport.hpp # Interface transport
│ ├── StdioTransport.hpp # Transport stdio (fork/exec)
│ ├── StdioTransport.cpp
│ └── MCPTypes.hpp # Tool, Resource, etc.
├── services/
│ └── LLMService.cpp # Modifier pour init tools
└── modules/
├── SchedulerModule.cpp # Ajouter handlers pour tools
├── MonitoringModule.cpp
└── StorageModule.cpp
config/
└── mcp.json # Configuration serveurs MCP
tests/
├── test_internal_tools.cpp
├── test_mcp_client.cpp
└── integration/
└── test_agentic_loop.cpp
Ordre d'Implémentation
- IOBridge - Request/response synchrone via IIO
- InternalTools - Définition et implémentation des tools
- Modules handlers - Ajouter la gestion des requêtes tools dans chaque module
- Test internal tools - Vérifier que ça marche
- MCPTypes - Types de base MCP
- StdioTransport - Fork/exec + communication JSON-RPC
- MCPClient - Orchestration des serveurs
- Test MCP - Vérifier avec un vrai serveur (filesystem)
- Unification - Merger dans LLMService
- Test intégration - End-to-end
Estimation Temps
| Phase | Temps estimé |
|---|---|
| Phase 1 : Tools Internes | 2-3h |
| Phase 2 : Client MCP | 2-3h |
| Phase 3 : Unification | 1h |
| Phase 4 : Tests | 1-2h |
| Total | 6-9h |
Dépendances
nlohmann/json- Déjà présentspdlog- Déjà présent- Node.js/npx - Pour les serveurs MCP (optionnel, on peut aussi implémenter nos propres serveurs en C++)
Risques et Mitigations
| Risque | Mitigation |
|---|---|
| Fork/exec complexe sur Windows | Utiliser _popen ou process lib cross-platform |
| Timeout sur tools lents | Configurable per-tool, default 30s |
| Serveur MCP crash | Reconnect automatique, fallback graceful |
| Trop de tools = confusion LLM | Grouper par namespace, limiter à ~20 tools |