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>
339 lines
16 KiB
Markdown
339 lines
16 KiB
Markdown
# 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 internes
|
|
- `src/shared/tools/InternalTools.cpp` - Implémentation
|
|
- `src/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** :
|
|
|
|
```cpp
|
|
// 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 MCP
|
|
- `src/shared/mcp/MCPClient.cpp` - Implémentation
|
|
- `src/shared/mcp/MCPTransport.hpp` - Transport stdio/SSE
|
|
- `src/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** :
|
|
|
|
```cpp
|
|
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** :
|
|
|
|
```json
|
|
// 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** :
|
|
|
|
```cpp
|
|
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 execution
|
|
- `tests/test_mcp_client.cpp` - Mock server, vérifier protocole
|
|
- `tests/test_tool_registry.cpp` - Vérifier aggregation
|
|
|
|
**Test d'intégration** :
|
|
|
|
```cpp
|
|
// 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
|
|
|
|
1. **IOBridge** - Request/response synchrone via IIO
|
|
2. **InternalTools** - Définition et implémentation des tools
|
|
3. **Modules handlers** - Ajouter la gestion des requêtes tools dans chaque module
|
|
4. **Test internal tools** - Vérifier que ça marche
|
|
5. **MCPTypes** - Types de base MCP
|
|
6. **StdioTransport** - Fork/exec + communication JSON-RPC
|
|
7. **MCPClient** - Orchestration des serveurs
|
|
8. **Test MCP** - Vérifier avec un vrai serveur (filesystem)
|
|
9. **Unification** - Merger dans LLMService
|
|
10. **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ésent
|
|
- `spdlog` - 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 |
|