From 69c3817579339ffd416e446c5efc127d5da573c3 Mon Sep 17 00:00:00 2001 From: bruno Date: Mon, 5 Oct 2026 12:59:51 -0400 Subject: [PATCH] docs: diagramme de flux de l'agent AI (boucle run_agent + pipeline call_tool + 50 outils) --- docs/agent-flow.dot | 87 ++++++++++ docs/agent-flow.svg | 394 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 481 insertions(+) create mode 100644 docs/agent-flow.dot create mode 100644 docs/agent-flow.svg diff --git a/docs/agent-flow.dot b/docs/agent-flow.dot new file mode 100644 index 0000000..e7fb508 --- /dev/null +++ b/docs/agent-flow.dot @@ -0,0 +1,87 @@ +// ObsiGate AI Agent — flux de traitement d'une demande (b89af91) +digraph ObsiGateAgent { + rankdir=TB; + splines=polyline; + nodesep=0.35; ranksep=0.45; + graph [fontname="DejaVu Sans", fontsize=13, bgcolor="white", pad=0.3]; + node [fontname="DejaVu Sans", fontsize=12, style=filled, shape=box, color="#333333", margin="0.16,0.09"]; + edge [fontname="DejaVu Sans", fontsize=11, color="#555555", arrowsize=0.8]; + + // ── Entrée ── + user [label="Demande utilisateur\n(frontend bookslm.js)", fillcolor="#dbeafe"]; + deep [label="Chip « Deep Research »\n= agent mode + prompt injecté :\n« décomposer les étapes, chercher\ndans le vault, croiser,\nsynthétiser avec sources »", + shape=note, fillcolor="#fef3c7"]; + api [label="POST /api/bookslm/agent\n→ réponse SSE (thought · tool ·\nconfirmation · message · done)", fillcolor="#e0f2fe"]; + prompt [label="Construction du system prompt\nmode directory / documents / general\ncontexte vault pré-chargé (BooksLM :\n≤200 fichiers, ≤200k chars, cache 5 min)\nprotocole agent = function calling natif", fillcolor="#f1f5f9"]; + + user -> api; deep -> user [style=dashed, label="active", fontsize=10]; + api -> prompt; + + // ── Boucle agent ── + subgraph cluster_loop { + label="BOUCLE AGENT — backend/agent/loop.py · run_agent()"; + style=rounded; color="#e11d48"; penwidth=2; fontsize=13; fontcolor="#e11d48"; + + llm [label="Appel LLM — chat_completion()\nfournisseur OpenAI-compatible / Gemini\ntemp=0.3 · max_tokens 8192\nschemas des 50 outils exposés\n(si modèle sans tools → retombe chat simple)", fillcolor="#fee2e2"]; + decide [label="Le LLM demande des\noutils (tool_calls) ?", shape=diamond, fillcolor="#fff7ed"]; + thought [label="note de raisonnement\nintermédiaire → step visible « pensée »", fillcolor="#fef9c3"]; + tools [label="Exécution de chaque tool call\nvia call_tool() (voir pipeline)", fillcolor="#dcfce7"]; + back [label="résultat (JSON, tronqué ≤100k chars)\najouté à la conversation →\nitération suivante", shape=plaintext]; + + llm -> decide; + decide -> thought [label="oui", color="#e11d48"]; + thought -> tools; + tools -> llm [label="itération ≤ 10\nquota tools ≤ 25\n(BOOKSLM_MAX_TOOL_CALLS)", color="#e11d48"]; + } + prompt -> llm; + + // ── Pipeline call_tool ── + subgraph cluster_pipe { + label="PIPELINE call_tool() — backend/tools/registry.py · chaque appel passe par là"; + style=rounded; color="#7c3aed"; fontsize=13; fontcolor="#7c3aed"; + + p1 [label="1 · Schéma Pydantic\n+ validation arguments", fillcolor="#ede9fe"]; + p2 [label="2 · Rate limit\npar identité + outil", fillcolor="#ede9fe"]; + p3 [label="3 · Permission vault\n(+ déstructif si risque\nDANGEROUS)", fillcolor="#ede9fe"]; + p4 [label="4 · Risque READ ?\n→ exécution directe", shape=diamond, fillcolor="#f5f3ff"]; + p5 [label="PAUSE CONFIRMATION\noutil WRITE/DANGEROUS → event SSE\n« confirmation » avec le plan complet\nbatché (BUG-075) : une seule\napprobation applique toutes les mutations\n(resume via confirm / confirm_all)", fillcolor="#fde68a"]; + p6 [label="5 · Handler exécuté\n6 · Audit JSON-lines\n7 · Redaction secrets (redact_payload)", fillcolor="#dcfce7"]; + p1 -> p2 -> p3 -> p4; + p4 -> p6 [label="read"]; + p4 -> p5 [label="mutation", color="#d97706"]; + p5 -> p6 [label="approuvé", style=dashed]; + } + tools -> p1; + p6 -> back [label="tool result", style=invis]; + p6 -> tools [style=invis]; + back -> p1 [style=invis]; + + // ── Sorties ── + done [label="Réponse finale\nréponse sans tool_calls\n→ SSE « message »\n(Markdown + sources citées)", fillcolor="#bbf7d0"]; + final [label="Budget épuisé (10 itérations\nou 25 appels) → _finalize_answer :\ndernier appel SANS outils pour forcer\nune synthèse, sinon liste des sources\ndéterministe (jamais de réponse vide)", fillcolor="#fed7aa"]; + decide -> done [label="non", color="#059669", penwidth=2]; + decide -> final [label="budget atteint", color="#ea580c"]; + answer [label="Affichage UI : bloc\n« N étapes » Notion-style\n(pensées + outils dépliables)", fillcolor="#dbeafe"]; + done -> answer; final -> answer; + + // ── Boîte à outils ── + subgraph cluster_tools { + label="50 OUTILS — backend/tools/*.py · risque READ / WRITE / DANGEROUS"; + style=rounded; color="#0369a1"; fontsize=13; fontcolor="#0369a1"; + node [fillcolor="#f0f9ff", fontsize=10]; + + fam_vault [label="VAULT · service.py (22)\nlecture : list_vaults, list_directory,\nlist_all_files, read_file, read_file_raw,\nsearch_fulltext, search_advanced,\nsearch_paths, get_graph, get_backlinks,\nlist_tags, suggest_tags, list_recent,\nlist_backups, diff_backup\nécriture : create_file, create_directory,\nappend_to_file, edit_file, restore_backup\nDANGEROUS : delete_file, delete_directory,\nmove_path, rename_file, rename_directory,\nreplace_in_files"]; + fam_web [label="WEB · web.py + crawler.py\nweb_search · fetch_url\ncrawl_site (≤20 pages, même hôte)"]; + fam_doc [label="DOCUMENTS · documents.py\ncreate_pdf · create_docx\ncreate_xlsx · create_csv"]; + fam_xlsx [label="TABLEURS · spreadsheets.py\nlist_xlsx_sheets · xlsx_to_markdown\nsearch_workbook · analyze_range\nupdate_xlsx_cells · append_xlsx_rows\nedit_xlsx_structure"]; + fam_dup [label="DOUBLONS · duplicates.py\nfind_duplicates\nmerge_duplicate_notes (DANG.)"]; + fam_git [label="GIT CONNECTÉ · connected.py\ngit_list_repos · git_get_file\ngit_search_issues (Gitea/GitHub)"]; + fam_sched [label="SCHEDULER · scheduled.py\nlist/create/delete/run_scheduled_task"]; + fam_notify [label="NOTIFICATIONS · notify.py\nnotify_external (Discord,\nTelegram, SMTP, webhook)"]; + } + p6 -> cluster_tools [style=invis]; + fam_vault -> fam_web [style=invis]; fam_web -> fam_doc [style=invis]; + fam_doc -> fam_xlsx [style=invis]; fam_xlsx -> fam_dup [style=invis]; + fam_dup -> fam_git [style=invis]; fam_git -> fam_sched [style=invis]; + fam_sched -> fam_notify [style=invis]; +} diff --git a/docs/agent-flow.svg b/docs/agent-flow.svg new file mode 100644 index 0000000..361877d --- /dev/null +++ b/docs/agent-flow.svg @@ -0,0 +1,394 @@ + + + + + + +ObsiGateAgent + + +cluster_loop + +BOUCLE AGENT — backend/agent/loop.py · run_agent() + + +cluster_pipe + +PIPELINE call_tool() — backend/tools/registry.py · chaque appel passe par là + + +cluster_tools + +50 OUTILS — backend/tools/*.py · risque READ / WRITE / DANGEROUS + + + +user + +Demande utilisateur +(frontend bookslm.js) + + + +api + +POST /api/bookslm/agent +→ réponse SSE (thought · tool · +confirmation · message · done) + + + +user->api + + + + + +deep + + + +Chip « Deep Research » += agent mode + prompt injecté : +« décomposer les étapes, chercher +dans le vault, croiser, +synthétiser avec sources » + + + +deep->user + + +active + + + +prompt + +Construction du system prompt +mode directory / documents / general +contexte vault pré-chargé (BooksLM : +≤200 fichiers, ≤200k chars, cache 5 min) +protocole agent = function calling natif + + + +api->prompt + + + + + +llm + +Appel LLM — chat_completion() +fournisseur OpenAI-compatible / Gemini +temp=0.3 · max_tokens 8192 +schemas des 50 outils exposés +(si modèle sans tools → retombe chat simple) + + + +prompt->llm + + + + + +decide + +Le LLM demande des +outils (tool_calls) ? + + + +llm->decide + + + + + +thought + +note de raisonnement +intermédiaire → step visible « pensée » + + + +decide->thought + + +oui + + + +done + +Réponse finale +réponse sans tool_calls +→ SSE « message » +(Markdown + sources citées) + + + +decide->done + + +non + + + +final + +Budget épuisé (10 itérations +ou 25 appels) → _finalize_answer : +dernier appel SANS outils pour forcer +une synthèse, sinon liste des sources +déterministe (jamais de réponse vide) + + + +decide->final + + +budget atteint + + + +tools + +Exécution de chaque tool call +via call_tool() (voir pipeline) + + + +thought->tools + + + + + +tools->llm + + +itération ≤ 10 +quota tools ≤ 25 +(BOOKSLM_MAX_TOOL_CALLS) + + + +p1 + +1 · Schéma Pydantic ++ validation arguments + + + +tools->p1 + + + + + +back + +résultat (JSON, tronqué ≤100k chars) +ajouté à la conversation → +itération suivante + + + + +p2 + +2 · Rate limit +par identité + outil + + + +p1->p2 + + + + + +p3 + +3 · Permission vault +(+ déstructif si risque +DANGEROUS) + + + +p2->p3 + + + + + +p4 + +4 · Risque READ ? +→ exécution directe + + + +p3->p4 + + + + + +p5 + +PAUSE CONFIRMATION +outil WRITE/DANGEROUS → event SSE +« confirmation » avec le plan complet +batché (BUG-075) : une seule +approbation applique toutes les mutations +(resume via confirm / confirm_all) + + + +p4->p5 + + +mutation + + + +p6 + +5 · Handler exécuté +6 · Audit JSON-lines +7 · Redaction secrets (redact_payload) + + + +p4->p6 + + +read + + + +p5->p6 + + +approuvé + + + + + +cluster_tools + +cluster_tools + + + + +answer + +Affichage UI : bloc +« N étapes » Notion-style +(pensées + outils dépliables) + + + +done->answer + + + + + +final->answer + + + + + +fam_vault + +VAULT · service.py (22) +lecture : list_vaults, list_directory, +list_all_files, read_file, read_file_raw, +search_fulltext, search_advanced, +search_paths, get_graph, get_backlinks, +list_tags, suggest_tags, list_recent, +list_backups, diff_backup +écriture : create_file, create_directory, +append_to_file, edit_file, restore_backup +DANGEROUS : delete_file, delete_directory, +move_path, rename_file, rename_directory, +replace_in_files + + + +fam_web + +WEB · web.py + crawler.py +web_search · fetch_url +crawl_site (≤20 pages, même hôte) + + + + +fam_doc + +DOCUMENTS · documents.py +create_pdf · create_docx +create_xlsx · create_csv + + + + +fam_xlsx + +TABLEURS · spreadsheets.py +list_xlsx_sheets · xlsx_to_markdown +search_workbook · analyze_range +update_xlsx_cells · append_xlsx_rows +edit_xlsx_structure + + + + +fam_dup + +DOUBLONS · duplicates.py +find_duplicates +merge_duplicate_notes (DANG.) + + + + +fam_git + +GIT CONNECTÉ · connected.py +git_list_repos · git_get_file +git_search_issues (Gitea/GitHub) + + + + +fam_sched + +SCHEDULER · scheduled.py +list/create/delete/run_scheduled_task + + + + +fam_notify + +NOTIFICATIONS · notify.py +notify_external (Discord, +Telegram, SMTP, webhook) + + + +