diff --git a/.env.example b/.env.example index 7a88953..a666190 100644 --- a/.env.example +++ b/.env.example @@ -47,7 +47,10 @@ CHLOVA_LOG_LEVEL=info # Gate de phase : 1 = lecture seule (défaut, fail-safe) ; 2 = écriture sous # gatekeeper + cycle need-review. Toute valeur autre que "2" retombe sur 1. CHLOVA_PHASE=1 -CHLOVA_DB_PATH=./data/chlova.db # SQLite : table assets (need-review, Phase 2) +CHLOVA_DB_PATH=./data/chlova.db # SQLite : assets (need-review) + conversations +# Plafond d'étapes par tour d'agent (appels d'outils enchaînés). Les tâches +# multi-outils (construire un workflow n8n) en demandent beaucoup. Défaut 24. +CHLOVA_MAX_AGENT_STEPS=24 # Alertes (Phase 3) : URL du webhook n8n qui envoie le mail (workflow # workflows-n8n/chlova-alerts.v1.0.0.json). Vide = alertes log-only (fail-safe). # Peut contenir un token de chemin → secret, jamais commité. diff --git a/CHANGELOG.md b/CHANGELOG.md index ba00874..bfe7665 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ incompatibles. Chaque ligne renvoie à un commit dédié (un artefact = un commi ## [Unreleased] +## [0.37.0] — 2026-06-24 — maxSteps configurable (tâches multi-outils) +### Changed +- Plafond d'étapes d'un tour d'agent : défaut **8 → 24**, configurable via + `CHLOVA_MAX_AGENT_STEPS` (`config.maxAgentSteps` → `ChatService` → + `runAgentTurn`). Construire un workflow n8n (SDK : sdk_reference, search_nodes, + get_node_types, validate, create…) dépassait 8 étapes et coupait avant la fin. +### Notes +- Vérifié en Phase 2 live : le gatekeeper a correctement BLOQUÉ + `n8n.create_workflow_from_code` (review requise) — comportement attendu. + ## [0.36.2] — 2026-06-23 — fix hauteur layout chat (sidebar + barre de saisie) ### Fixed - Shell en **`h-dvh`** (hauteur définie) au lieu de `min-h-dvh` : `h-full` des diff --git a/orchestrator/src/agent/chat-service.ts b/orchestrator/src/agent/chat-service.ts index ba579d3..fae2abd 100644 --- a/orchestrator/src/agent/chat-service.ts +++ b/orchestrator/src/agent/chat-service.ts @@ -20,6 +20,8 @@ export interface ChatServiceDeps { systemPrompt: string; logger: Logger; store?: ConversationStore; + /** Plafond d'étapes par tour (multi-outils). Défaut runAgentTurn sinon. */ + maxSteps?: number; } export interface ChatResult { @@ -75,6 +77,7 @@ export class ChatService { actor, guard: this.deps.guard, logger: this.deps.logger, + ...(this.deps.maxSteps ? { maxSteps: this.deps.maxSteps } : {}), }); this.deps.logger.info({ actor, steps }, "tour d'agent terminé"); return reply; diff --git a/orchestrator/src/agent/loop.ts b/orchestrator/src/agent/loop.ts index 3b6a3f7..d20975b 100644 --- a/orchestrator/src/agent/loop.ts +++ b/orchestrator/src/agent/loop.ts @@ -46,7 +46,7 @@ export async function runAgentTurn( input: AgentTurnInput, ): Promise { const { client, tools, actor, guard, logger } = input; - const maxSteps = input.maxSteps ?? 8; + const maxSteps = input.maxSteps ?? 24; const byName = new Map(tools.map((t) => [t.spec.name, t])); const toolDefs = toOllamaTools(tools); diff --git a/orchestrator/src/config.ts b/orchestrator/src/config.ts index 832f1b6..3dcc117 100644 --- a/orchestrator/src/config.ts +++ b/orchestrator/src/config.ts @@ -67,6 +67,17 @@ const schema = z.object({ // Backend dbPath: z.string().default("./data/chlova.db"), + // Plafond d'étapes d'un tour d'agent (appels d'outils enchaînés). Les tâches + // multi-outils (ex. construire un workflow n8n via le SDK) en demandent + // beaucoup ; défaut généreux. Garde-fou anti-boucle conservé. + maxAgentSteps: z + .string() + .default("24") + .transform((v) => { + const n = Number.parseInt(v, 10); + return Number.isFinite(n) && n > 0 ? n : 24; + }), + // Alertes (Phase 3) : webhook n8n qui envoie le mail. Optionnel : si absent, // les alertes sont seulement loggées (NullAlertSender). Peut contenir un token // de chemin → traité comme secret (jamais loggé). @@ -129,6 +140,7 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): Config { telegramBotToken: env.TELEGRAM_BOT_TOKEN, telegramAllowedUserIds: env.TELEGRAM_ALLOWED_USER_IDS, dbPath: env.CHLOVA_DB_PATH, + maxAgentSteps: env.CHLOVA_MAX_AGENT_STEPS, alertWebhookUrl: env.ALERT_WEBHOOK_URL, adminUser: env.CHLOVA_ADMIN_USER, adminPasswordHash: env.CHLOVA_ADMIN_PASSWORD_HASH, diff --git a/orchestrator/src/index.ts b/orchestrator/src/index.ts index 28447f2..cfa6f1a 100644 --- a/orchestrator/src/index.ts +++ b/orchestrator/src/index.ts @@ -113,7 +113,7 @@ async function main(): Promise { }); // Conversations persistées (mémoire multi-tour + reprise), même fichier SQLite. const conversations = new ConversationStore(cfg.dbPath); - const chat = new ChatService({ client, tools, guard, systemPrompt, logger, store: conversations }); + const chat = new ChatService({ client, tools, guard, systemPrompt, logger, store: conversations, maxSteps: cfg.maxAgentSteps }); // ── Surface Telegram (long-polling) — optionnelle ─────────────────────── // Démarrée seulement si un token est fourni. Sinon, surface API/UI seule