Table of Contents

🇬🇧 English version

Sous-systèmes opt-in

Décision R4.9 (QCM 2026-06-11) : les 13 ports DI dormants identifiés par l'audit (MORT-003) et les sous-systèmes associés sont conservés, sortis de l'enregistrement par défaut et activables explicitement. Aucun de ces services n'est enregistré par AddOrkeonApplication() ni par AddOrkeonInfrastructure() (les deux surcharges) : chacun s'active par son extension AddOrkeonXxx() dédiée.

Principe

Ces sous-systèmes sont complets et testés unitairement, mais aucun chemin d'exécution de production ne les consomme encore : les enregistrer par défaut gonflait le conteneur DI sans bénéfice et masquait leur statut réel. Le passage en opt-in rend leur activation intentionnelle, documentée et vérifiable.

Chaque extension d'activation est autoporteuse : elle enregistre (via TryAdd*) toutes les dépendances dont le sous-système a besoin et qui ne sont pas déjà fournies par l'hôte. Prérequis communs à tous : le logging (services.AddLogging()) et, pour les sous-systèmes qui lient des options de configuration, un IConfiguration enregistré (toujours présent dans une application basée sur Host/WebApplication).

L'ordre recommandé est d'appeler l'extension après AddOrkeonInfrastructure() : les TryAdd* laissent alors la priorité aux services déjà câblés par le socle.

services.AddOrkeonApplication();
services.AddOrkeonInfrastructure();

// Activations explicites (exemples)
services.AddOrkeonMonitoring(configuration);
services.AddOrkeonDlp();
services.AddOrkeonA2A(options => options.EnableServer = true);

Catalogue

Sous-système Activation Projet Ports exposés Maturité
Serveur/protocole A2A AddOrkeonA2A(...) Infrastructure IA2AServer, IA2AClient, IA2AAgentDiscovery, IA2ATaskRouter BĂŞta
Backend de monitoring AddOrkeonMonitoring(...) Infrastructure IMetricsAggregation, ITraceExplorer BĂŞta
Conformité NIST AddOrkeonNistCompliance() Infrastructure INistComplianceReporter Expérimental
DLP (Data Loss Prevention) AddOrkeonDlp() Infrastructure IDlpPolicyProvider, IPiiDetector, IDlpInterceptor (×5) Expérimental
Rate-limiting d'outils & budget de tokens AddOrkeonToolRateLimiting() Infrastructure IToolRateLimiter, ITokenBudgetTracker Expérimental
Rotation de clés AddOrkeonKeyRotation() Infrastructure IKeyRotationService Bêta
Benchmarking d'évaluation AddOrkeonBenchmarking() Infrastructure IBenchmarkRunner Bêta
Contenu multi-modal (vision) AddOrkeonMultiModal(...) Infrastructure IContentValidationService, IMultiModalContentLoader Bêta (réel depuis R3.9)
Hooks de kickoff AddOrkeonKickoffHooks() Application ICrewKickoffHookRunner Expérimental
Contexte de codebase (RaggableTree) AddRaggableTree(options) — ⚠️ les hôtes runner font l'inverse (opt-out) : RunnerHost l'enregistre par défaut et RaggableTree:Enabled = false le désactive Analysis ICodebaseContextProvider Bêta
Sous-système RAG (RAG-02…06) AddOrkeonRag(config) (namespace Orkeon.Rag.DependencyInjection) + AddOrkeonRagTools() (Orkeon.Tools.Rag) ; profils fast/balanced/quality/adaptive/corrective via Orkeon:Rag:Profile (défaut fast) ; balanced/quality/adaptive exigent le cross-encoder ONNX — AddOrkeonOnnxReranker() (Orkeon.Rag.Onnx + Orkeon.Rag.Onnx.Model, poids embarqués, hors-ligne) ; corrective non (le graphe boucle au lieu de reranker) ; le repli web correctif est purement config — AddOrkeonRag câble déjà le transport, les deux interrupteurs Enabled gouvernent (Orkeon:Rag:Corrective:WebFallback politique, Orkeon:Rag:WebFallback transport) — voir la section détaillée plus bas Orkeon.Rag.Abstractions / Orkeon.Rag / Orkeon.Tools.Rag / Orkeon.Rag.Onnx / Orkeon.Rag.Onnx.Model IRagPipeline (à étages / graphe correctif), IRagProfileResolver, IIngestionPipeline, IDocumentStore, IRagEvalHarness, rag_search/rag_ingest/rag_eval (IBaseTool) Bêta
Étages de middleware EventHub AddOrkeonEventHubObservability() (journalisation + télémétrie) · AddOrkeonEventHubAcl(policy?) (applique les blocs links: des crews — déjà câblé par le host du runner et orkeon-host, avec le défaut permissif : une crew sans liens se comporte comme avant, une crew qui déclare y est tenue ; seule la politique fermée reste un opt-in) · AddOrkeonEventHubIdempotency(capacity?) (point à point seulement, en mémoire, ne survit pas au processus) · AddOrkeonEventHubValidation() (un SchemaId déclaré doit être enregistré — l'existence du contrat, pas la conformité de la charge utile). Chacun est indépendant ; l'ordre d'enregistrement est l'ordre du pipeline — voir EventHub §12 Infrastructure IEventHubMiddleware, ICrewLinkProvider/ICrewLinkRegistry, IEventSchemaRegistry Beta
Persistance d'état d'exécution (R3.8) AddCrewExecutionStatePersistence(...) Infrastructure ICrewExecutionStateManager (durable via IStateStore) Bêta
Barrière de permissions (par appel d'outil) AddOrkeonPermissionGate(config) + Orkeon:Security:PermissionGate:Enabled = true Infrastructure IPermissionGate (ModePermissionGate) — consommé par la boucle scriptée ctx.llm.act Bêta
Shell : interpréteurs & git mutant config seule : Orkeon:Tools:Shell:AllowInterpreters = true Tools.Code (ré-enregistre ShellCommandTool avec allowInterpreters: true — équivalent RCE, avertissement de sécurité émis) Bêta
Shell : allowlist personnalisée config seule : Orkeon:Tools:Shell:ExtraAllowedCommands (additive) / Orkeon:Tools:Shell:AllowedCommands (remplacement intégral — annule AllowInterpreters) Tools.Code (façonne l'allowlist d'exécutables de ShellCommandTool ; section absente/vide = défauts) Bêta
Streaming console LLM natif AddLlmConsoleStreaming(config) + Orkeon:Cli:ConsoleStreaming:Enabled = true Cli.Scripting ILlmDeltaSink (ConsoleLlmDeltaSink) — deltas ctx.llm.act streamés rendus sur la console REPL Bêta
Système de plugins AddOrkeonPlugins(...) (jamais enregistré implicitement) Orkeon.Plugins IOrkeonPlugin, IPluginRegistry — découverte par répertoire, AssemblyLoadContext collectables isolés ; ⚠️ les assemblies chargées s'exécutent en pleine confiance — voir Plugins Bêta
Embeddings locaux sur machine AddOrkeonLocalEmbeddings() Tools.Embeddings.Local IEmbeddingProvider (BGE-micro-v2 ONNX, 384 dims, CPU, sans clé API) — premier maillon de la chaîne de résolution des embeddings Bêta
Fournisseurs de mémoire externes (LanceDB, Redis) AddOrkeonLanceDb(...) / AddOrkeonRedisMemory(...) (ou clés de type via MemoryProviderFactory). ⚠️ ChromaDB et Pinecone ne sont pas opt-in : AddOrkeonInfrastructure(configuration) les enregistre automatiquement quand leur section Orkeon:ChromaDb/Orkeon:Pinecone existe Infrastructure Implémentations IMemoryProvider — voir Système de mémoire Bêta
Mémoire cognitive AddOrkeonCognitiveMemory(...) Infrastructure Couche de mémoire cognitive au-dessus d'IMemoryProvider Expérimental

Hors de ce catalogue — enregistrés par AddOrkeonInfrastructure() et gouvernés par la configuration, pas par un geste d'enregistrement : MCP (section MCP, via la surcharge IConfiguration, ou l'hôte des runners dès que MCP:Servers déclare un serveur), le store de checkpointing sans paramètre (AddOrkeonCheckpointing() ; les variantes SQLite/Postgres restent explicites), le pipeline Guardian, le moteur de Flows, Training, Consensus, CostTracking, Encryption, Auth et CodeSandbox. Leurs sections de configuration sont cartographiées dans la Référence de configuration.

Maturité — Bêta : implémentation complète et testée, API susceptible d'évoluer avant la v1. Expérimental : implémentation fonctionnelle mais non câblée dans le pipeline d'exécution (l'hôte invoque le service lui-même) ou comportement encore partiel (signalé au cas par cas ci-dessous).


Serveur/protocole A2A — AddOrkeonA2A(...)

Complément persistance des tâches (PUB-08) : AddOrkeonA2ATaskPersistence() stocke les cycles de vie des tâches A2A sur l'IStateStore de checkpointing opt-in (à enregistrer d'abord), transformant GET /a2a/tasks/{id} en vrai endpoint 200/404 au lieu du 501 explicite.

  • RĂ´le : communication agent-Ă -agent inter-processus (protocole A2A) : dĂ©couverte d'agents (/.well-known/agent.json), client HTTP, routage de tâches et, en option, un serveur HTTP (HttpListener) exposant POST /a2a/tasks/send, sendSubscribe (SSE), GET/DELETE /a2a/tasks/{id}.
  • Activation :
    // Par configuration (section "A2A" ; "A2A:Security" pour mTLS/auth)
    services.AddOrkeonA2A(configuration);
    
    // Ou par délégué, sans IConfiguration
    services.AddOrkeonA2A(options => options.EnableServer = true);
    
    IA2AServer n'est enregistré que si EnableServer est vrai.
  • DĂ©pendances : l'extension enregistre elle-mĂŞme (TryAdd) IHttpClientFactory, IDomainEventDispatcher, IUnitOfWork, ainsi que l'annuaire d'agents A2A (IAgentRegistrationStore singleton + IAgentRepository scoped, voir ci-dessous) lorsque l'hĂ´te ne les a pas dĂ©jĂ  câblĂ©s via AddOrkeonInfrastructure().
  • Cycle de vie du dĂ©pĂ´t d'agents (R4.6 / ANT-001, dĂ©cision « scoped par requĂŞte ») :
    • IAgentRepository est scoped ; le serveur et le routeur (singletons) ne le capturent jamais — ils ouvrent un scope DI par requĂŞte A2A via IServiceScopeFactory et rĂ©solvent le dĂ©pĂ´t dedans. La rĂ©solution passe avec ValidateScopes = true (dĂ©faut en Development).
    • Un dĂ©pĂ´t scoped ne conserve rien entre deux requĂŞtes : les enregistrements vivent dans IAgentRegistrationStore, un backing store singleton thread-safe (InMemoryAgentRegistrationStore, ConcurrentDictionary) dont le dĂ©pĂ´t scoped (SharedStoreAgentRepository) s'hydrate Ă  chaque appel. Les agents enregistrĂ©s par le pipeline (dans ses propres scopes) sont donc visibles du routeur A2A, et rĂ©ciproquement.
    • Composition : si l'hĂ´te a appelĂ© AddOrkeonInfrastructure() (qui enregistre le InMemoryAgentRepository Ă  store par scope), AddOrkeonA2A(...) surclasse cette implĂ©mentation par dĂ©faut vers SharedStoreAgentRepository (mĂŞme durĂ©e de vie scoped, donnĂ©es partagĂ©es) — sinon le routeur ne retrouverait jamais les agents. Tout autre enregistrement d'IAgentRepository (dĂ©pĂ´t custom/BD, qui fournit dĂ©jĂ  un stockage inter-requĂŞtes) est laissĂ© intact. Appeler AddOrkeonA2A(...) après AddOrkeonInfrastructure() et après un Ă©ventuel dĂ©pĂ´t custom (ordre recommandĂ©, cf. Principe) ; un dĂ©pĂ´t custom enregistrĂ© après AddOrkeonA2A(...) gagne (dernier enregistrement).
  • Limites connues : le store in-memory est local au processus — pour un annuaire d'agents multi-instances, fournir un IAgentRepository custom adossĂ© Ă  un stockage partagĂ© externe (il sera respectĂ© tel quel par l'extension).

Backend de monitoring — AddOrkeonMonitoring(...)

  • RĂ´le : agrĂ©gation in-process des mĂ©triques Orkeon (MeterListener sur OrkeonMetrics) et exploration des traces rĂ©centes (buffer circulaire) pour exposition par un endpoint hĂ´te (dashboard, API de diagnostic).
  • Activation :
    services.AddOrkeonMonitoring(configuration); // lie Orkeon:Monitoring
    services.AddOrkeonMonitoring();              // options par défaut
    
  • DĂ©pendances : logging uniquement (les options par dĂ©faut sont enregistrĂ©es si aucune configuration n'est passĂ©e).
  • Note : ne remplace pas la tĂ©lĂ©mĂ©trie OpenTelemetry (AddOrkeonTelemetry), qui reste câblĂ©e par la surcharge AddOrkeonInfrastructure(IConfiguration).

Traces et métriques suivent les conventions GenAI d'OpenTelemetry

Pas un opt-in — chaque run les émet, et les runners (orkeon run, orkeon-host) les exportent là où pointe la variable standard OTEL_EXPORTER_OTLP_ENDPOINT (un AppHost .NET Aspire la pose — voir ADR-011) ou là où la section Telemetry des réglages le dit (Telemetry:OtlpEndpoint, Telemetry:ExportToConsole). Depuis le 2026-09-11 le chemin d'exécution lui-même porte les spans (ils vivaient dans des helpers que rien n'appelait en production), nommés et attribués selon les conventions sémantiques OpenTelemetry pour l'IA générative, si bien que Langfuse, Honeycomb, Application Insights ou le dashboard Aspire les lisent sans mapping. Les noms sont les constantes de Orkeon.Constants.Llm.GenAiAttributes.

Span (ActivitySource) Nom Attributs
Tour d'agent (Orkeon.Agent) invoke_agent {agent} gen_ai.operation.name=invoke_agent, gen_ai.agent.name, gen_ai.agent.id, gen_ai.provider.name, gen_ai.request.model, orkeon.task.id
Appel au modèle (Orkeon.Llm, kind Client) chat {model} gen_ai.operation.name=chat, gen_ai.provider.name (minuscules), gen_ai.request.model, gen_ai.request.temperature, gen_ai.request.max_tokens, gen_ai.response.model, gen_ai.response.id, gen_ai.response.finish_reasons, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, error.type en cas d'échec
Exécution d'outil (Orkeon.Tool) execute_tool {tool} gen_ai.operation.name=execute_tool, gen_ai.tool.name, gen_ai.tool.call.id (l'identifiant donné par le modèle), gen_ai.agent.name, error.type en cas d'échec
Runtime de scripting (Orkeon.Scripting) les trois mĂŞmes, plus crew.run mĂŞmes attributs ; orkeon.llm.method (complete/act), orkeon.crew.name, orkeon.crew.process

Métriques (OrkeonMetrics, meter Orkeon) : gen_ai.client.token.usage (histogramme, tokens, gen_ai.token.type = input | output) et gen_ai.client.operation.duration (histogramme, secondes), toutes deux étiquetées gen_ai.provider.name et gen_ai.request.model ; les compteurs orkeon.* (appels, exécutions d'outils, coût) gardent leurs noms. Ce qui n'a pas de convention garde le préfixe orkeon. — le crew, la tâche, le coût estimé.

Conformité NIST — AddOrkeonNistCompliance()

  • RĂ´le : gĂ©nĂ©ration de rapports de conformitĂ© NIST SP 800-53 Ă  partir de la piste d'audit (IAuditLogger).
  • Activation : services.AddOrkeonNistCompliance();
  • DĂ©pendances : l'extension TryAdd une chaĂ®ne d'audit de repli (StructuredLogAuditSink + AuditLogger) ; quand l'hĂ´te a appelĂ© AddOrkeonInfrastructure(), la chaĂ®ne d'audit du socle (sinks structurĂ© + in-memory, options Security:Audit) est utilisĂ©e.
  • Limites connues : la profondeur du rapport dĂ©pend des Ă©vĂ©nements rĂ©ellement auditĂ©s par l'hĂ´te ; aucun contrĂ´le automatisĂ© n'est exĂ©cutĂ©.

DLP — AddOrkeonDlp()

  • RĂ´le : prĂ©vention de fuite de donnĂ©es — dĂ©tection de PII par expressions rĂ©gulières (IPiiDetector), politiques par canal (IDlpPolicyProvider, section Orkeon:Dlp) et 5 intercepteurs de canaux (sortie d'outil, dĂ©lĂ©gation, logs, mĂ©moire, sortie externe).
  • Activation : services.AddOrkeonDlp();
  • DĂ©pendances : logging + IConfiguration (liaison Orkeon:Dlp). Autoporteuse pour le reste.
  • Limites connues : les intercepteurs ne sont pas invoquĂ©s automatiquement par le pipeline d'exĂ©cution — l'hĂ´te les rĂ©sout (GetServices<IDlpInterceptor>()) et les applique aux canaux qu'il veut protĂ©ger. Ă€ ne pas confondre avec le PiiDetectionValidator du pipeline de validation de sortie, qui reste enregistrĂ© par dĂ©faut et est indĂ©pendant.

Rate-limiting d'outils & budget de tokens — AddOrkeonToolRateLimiting()

  • RĂ´le : limitation de dĂ©bit par outil (IToolRateLimiter, section ToolRateLimiting) et suivi de budget de tokens par agent/crew (ITokenBudgetTracker, section TokenBudget).
  • Activation : services.AddOrkeonToolRateLimiting();
  • DĂ©pendances : logging + IConfiguration. Si AddOrkeonCostTracking() (inclus dans le socle) a enregistrĂ© IModelPricingRegistry, le tracker l'utilise pour la conversion tokens → coĂ»t.
  • Limites connues : non câblĂ© dans l'exĂ©cution des outils — l'hĂ´te interroge le limiteur/le tracker autour de ses appels d'outils. Le rate-limiting LLM (ILlmRateLimiter), lui, reste enregistrĂ© par dĂ©faut car consommĂ© par l'orchestrateur d'exĂ©cution.

Rotation de clés — AddOrkeonKeyRotation()

  • RĂ´le : re-chiffrement rĂ©el (R2.8) des entrĂ©es d'un store mĂ©moire chiffrĂ© lors d'une rotation de clĂ© — IKeyRotationService.RotateAsync(store, oldProvider, newProvider, options?) — plus la gĂ©nĂ©ration et la persistance d'une nouvelle clĂ© via ProvisionNewKeyAsync(secretStore, secretName, keySizeInBits) (IWritableSecretProvider, implĂ©mentĂ© par DpapiSecretProvider).
  • Fonctionnement : parcours en deux phases. Staging : chaque entrĂ©e est dĂ©chiffrĂ©e avec l'ancienne clĂ©, re-chiffrĂ©e avec la nouvelle et Ă©crite sous une clĂ© de staging (<clĂ©>::rotation-staging) — les originaux restent intacts. Bascule : chaque copie re-chiffrĂ©e remplace son original puis le staging est supprimĂ©. Un marqueur d'Ă©tat (__orkeon.key-rotation.state, JSON en clair) persiste la version de clĂ© et la phase ; chaque entrĂ©e re-chiffrĂ©e porte la propriĂ©tĂ© orkeon-key-version.
  • Échecs et reprise :
    • Ă©chec en staging → rollback automatique des copies de staging : le store reste intĂ©gralement lisible avec l'ancienne clĂ© ;
    • Ă©chec en bascule → roll-forward : relancer RotateAsync avec les mĂŞmes providers reprend la rotation lĂ  oĂą elle s'est arrĂŞtĂ©e. La classification par dĂ©chiffrement authentifiĂ© (AES-GCM) garantit l'idempotence : aucune entrĂ©e perdue, aucune double-chiffrĂ©e ;
    • entrĂ©e illisible avec les deux clĂ©s → Ă©chec fail-closed par dĂ©faut (rollback) ; KeyRotationOptions.ContinueOnUnreadableEntries permet de l'ignorer (entrĂ©e laissĂ©e telle quelle et signalĂ©e dans KeyRotationResult.Errors).
  • Activation : services.AddOrkeonKeyRotation(); — Ă  coupler avec AddOrkeonEncryption() (le fournisseur AES-256-GCM, lui, reste dans le socle).
  • DĂ©pendances : logging uniquement (le store et les providers sont passĂ©s en arguments de mĂ©thode).
  • Marche Ă  suivre :
    var rotation = provider.GetRequiredService<IKeyRotationService>();
    
    // 1. Générer et persister la nouvelle clé sous un nom de secret versionné
    //    (refuse d'écraser un secret existant — fail-closed)
    await rotation.ProvisionNewKeyAsync(writableSecrets, "orkeon-encryption-key-v2");
    
    // 2. Re-chiffrer le store brut (sous le décorateur) de l'ancienne vers la nouvelle clé
    var result = await rotation.RotateAsync(rawStore, oldProvider, newProvider);
    
    // 3. Basculer la configuration de l'hĂ´te sur le nouveau nom de secret
    
  • Limites connues : la rotation s'exĂ©cute sur le provider mĂ©moire brut (sous le dĂ©corateur EncryptedMemoryProviderDecorator, type MemoryProviderBase pour l'Ă©numĂ©ration des clĂ©s) et suppose qu'aucune Ă©criture concurrente n'a lieu pendant la fenĂŞtre de rotation. AesEncryptionProvider.RotateKeyAsync est neutralisĂ© (NotSupportedException, plus aucun faux log de succès) : une rotation « sur place » orphelinerait les donnĂ©es existantes — passer par IKeyRotationService.

Benchmarking d'évaluation — AddOrkeonBenchmarking()

  • RĂ´le : exĂ©cution rĂ©pĂ©tĂ©e d'une suite d'Ă©valuation par cas de test avec statistiques mean/stddev (IBenchmarkRunner).
  • Activation : services.AddOrkeonBenchmarking(); — Ă  coupler avec AddOrkeonEvaluation() (inclus dans le socle) pour construire les suites.
  • DĂ©pendances : aucune (la suite d'Ă©valuation est fournie via BenchmarkConfig Ă  l'appel).

Contenu multi-modal (vision) — AddOrkeonMultiModal(...)

  • Statut : rĂ©el (R3.9) — la vision est câblĂ©e de bout en bout : les contenus image circulent des abstractions MultiModalContent (Domain) aux payloads providers via LlmMessage.MultiModalContent. AnthropicLlmProvider Ă©met des blocs de contenu image conformes Ă  l'API Messages ({"type":"image","source":{"type":"base64"|"url",…}}) ; OpenAIProvider Ă©met des parts image_url conformes Ă  Chat Completions (URL http(s) ou data URL base64). Voir le guide multi-modal.
  • RĂ´le : validation des contenus multi-modaux (taille, format, durĂ©e) via IContentValidationService (options Orkeon:MultiModal) et chargement d'images depuis le système de fichiers virtuel via IMultiModalContentLoader (lecture VFS → bytes → base64, type MIME infĂ©rĂ© de l'extension, validation des contraintes configurĂ©es).
  • Activation :
    services.AddOrkeonMultiModal(configuration); // lie Orkeon:MultiModal
    services.AddOrkeonMultiModal();              // options par défaut
    
  • DĂ©pendances : IContentValidationService n'a besoin que des options ; IMultiModalContentLoader requiert un IFileSystemService rĂ©solvable (AddOrkeonFileSystem(configuration) dans les hĂ´tes rĂ©els).
  • Limites connues : la composition des payloads vision est pilotĂ©e par capacitĂ© (LlmProviderCapabilities.Vision, traduite une fois par OpenAICompatibleProviderBase) — les 16 providers la dĂ©clarent (DeepSeek depuis la campagne du 2026-08-30 qui a mesurĂ© deepseek-v4-flash-vision-exp, natif sur deepseek-flash depuis V4.1) ; un provider sans la capacitĂ© dĂ©grade les messages multi-modaux vers leur repli texte (LlmMessage.Content). Formats image supportĂ©s : png, jpeg, gif, webp. Les parts audio/fichier ne sont envoyĂ©es par aucun provider et lèvent une NotSupportedException explicite si elles atteignent un payload vision.

Hooks de kickoff — AddOrkeonKickoffHooks()

  • RĂ´le : exĂ©cution de callbacks BeforeKickoffHook / AfterKickoffHook autour du kickoff d'un crew, par ordre de Priority croissante, avec sĂ©mantique ContinueOnError (les exceptions des hooks tolĂ©rants sont loguĂ©es puis ignorĂ©es).
  • Activation :
    services.AddOrkeonKickoffHooks(); // runner seul
    services.AddBeforeKickoffHook(new BeforeKickoffHook
    {
        Name = "audit",
        Priority = 1,
        Execute = crew => /* ... */ System.Threading.Tasks.Task.CompletedTask,
    }); // enregistre le hook ET le runner
    
  • DĂ©pendances : aucune (collections de hooks vides par dĂ©faut, logging optionnel).
  • Limites connues : l'orchestrateur n'invoque pas (encore) le runner — son câblage dans le pipeline d'exĂ©cution relève de la dĂ©composition de l'orchestrateur (R4.1). En attendant, l'hĂ´te appelle lui-mĂŞme :
    var runner = provider.GetRequiredService<ICrewKickoffHookRunner>();
    await runner.RunBeforeKickoffAsync(crew, ct);
    var result = await orchestrator.KickoffAsync(crew.Id, input, ct);
    await runner.RunAfterKickoffAsync(crew, result, ct);
    

Contexte de codebase (RaggableTree) — AddRaggableTree(options)

  • RĂ´le : ICodebaseContextProvider produit des rĂ©sumĂ©s de codebase destinĂ©s Ă  ĂŞtre injectĂ©s dans le contexte des agents (fonctionnalitĂ© RaggableTree).
  • Activation : enregistrĂ© par AddRaggableTree(options) (projet Orkeon.Analysis). La bibliothèque cĹ“ur ne l'appelle jamais — mais le runner host, lui, l'appelle par dĂ©faut (orkeon run/orkeon-host ; opt-out via "RaggableTree:Enabled": false), en cohĂ©rence avec l'entrĂ©e de ce catalogue plus haut. Voir raggable-tree.md.
  • Limites connues : aucun composant du framework ne le consomme automatiquement — l'hĂ´te le rĂ©sout et injecte les rĂ©sumĂ©s lĂ  oĂą il le souhaite (prompt système, contexte de tâche…).

Sous-système RAG — AddOrkeonRag(configuration) (RAG-02…06)

  • RĂ´le : gĂ©nĂ©ration augmentĂ©e par rĂ©cupĂ©ration — ingestion (loaders, chunking, validation, manifeste incrĂ©mental), pipeline de rĂ©cupĂ©ration Ă  Ă©tages (transform → retrieve → fuse (+ MMR opt-in) → rerank → assemble → generate → groundedness), graphe correctif CRAG, presets de profils et harnais d'Ă©valuation hors ligne. Guide complet : rag-pipeline.md, dĂ©cisions : ADR-006.
  • Activation :
    services.AddOrkeonRag(configuration);   // Orkeon.Rag.DependencyInjection
    services.AddOrkeonRagTools();           // Orkeon.Tools.Rag : rag_search / rag_ingest / rag_eval
    services.AddOrkeonOnnxReranker();       // opt-in — requis par balanced/quality/adaptive
    
    AddOrkeonRag câble déjà les transformers de requête, le routage, l'hybride BM25+RRF, le graphe correctif et l'enregistrement du transport du repli web — appeler soi-même AddOrkeonRagWebFallback(configuration) est un no-op ; la fonctionnalité est gouvernée par les deux interrupteurs de configuration ci-dessous.
  • Profils (Orkeon:Rag:Profile, dĂ©faut fast ; les surcharges clĂ© par clĂ© s'appliquent par-dessus le preset) : fast (vectoriel seul) et corrective (graphe CRAG — boucle au lieu d'un Ă©tage de rerank linĂ©aire) fonctionnent sans les paquets ONNX ; balanced/quality activent l'Ă©tage de rerank cross-encoder et adaptive dĂ©lègue sa route SingleShot Ă  balanced, donc ces trois-lĂ  Ă©chouent explicitement Ă  la première requĂŞte (exception actionnable) tant qu'AddOrkeonOnnxReranker() (Orkeon.Rag.Onnx + Orkeon.Rag.Onnx.Model, poids int8 embarquĂ©s, hors-ligne) n'est pas enregistrĂ©.
  • Repli web (double opt-in, dĂ©sactivĂ© par dĂ©faut) : le nĹ“ud web_fallback du graphe correctif ne s'exĂ©cute que quand les deux Orkeon:Rag:Corrective:WebFallback:Enabled (politique) et Orkeon:Rag:WebFallback:Enabled + un Endpoint non vide (transport, SearxNG) sont posĂ©s. Chaque page tĂ©lĂ©chargĂ©e est filtrĂ©e par PromptInjectionDocumentValidator (Rejected n'entre jamais dans le working set ; Suspicious suit la politique configurĂ©e) — voir security.md.
  • Projets : Orkeon.Rag.Abstractions (contrats, dĂ©pendance Domain seule), Orkeon.Rag (implĂ©mentations), Orkeon.Tools.Rag (outils agents), Orkeon.Rag.Onnx + Orkeon.Rag.Onnx.Model (reranker opt-in + poids).
  • Limites connues : voir limitations.md — dĂ©gradation hors ligne des nĹ“uds dĂ©pendant d'un LLM (corrective/adaptive), classifieur heuristique par dĂ©faut, BM25 in-process non persistĂ©.

Persistance d'état d'exécution — AddCrewExecutionStatePersistence(...) (R3.8)

  • RĂ´le : persistance durable des Ă©tats d'exĂ©cution de crew (ScopedCrewExecutionStateManager) dans un state store de checkpointing (IStateStore) : chaque transition (crĂ©ation, mise Ă  jour, complĂ©tion, archivage) est persistĂ©e, et au redĂ©marrage les Ă©tats sont rechargĂ©s — y compris la reprise via CreateStateAsync(crewId, executionId, input) quand un Ă©tat persistĂ© existe dĂ©jĂ  pour l'identifiant de reprise (crash recovery).
  • Activation (deux conditions — un store et l'option) :
    // 1. Un state store de checkpointing (in-memory, SQLite ou PostgreSQL)
    services.AddOrkeonSqliteCheckpointing("Data Source=orkeon-state.db");
    // ou : services.AddOrkeonCheckpointing();              // in-memory
    // ou : services.AddOrkeonPostgresCheckpointing(configuration);
    
    // 2. L'opt-in de persistance
    services.AddCrewExecutionStatePersistence();             // code-first
    services.AddCrewExecutionStatePersistence(configuration); // lie Orkeon:ExecutionState:Persistence
    
    Avec la surcharge AddOrkeonInfrastructure(IConfiguration), la présence de la section Orkeon:ExecutionState:Persistence (Enabled, DeleteFromStoreOnArchive) suffit à lier les options.
  • DĂ©faut rĂ©tro-compatible : sans activation, les Ă©tats restent in-memory only (aucune reprise après crash) — comportement historique inchangĂ©. Si l'option est activĂ©e sans store enregistrĂ©, le manager logue un avertissement et continue en mĂ©moire.
  • Cohabitation : les sessions d'Ă©tat d'exĂ©cution sont espacĂ©es de noms (prĂ©fixe crew-exec: sur l'id de session et l'id de crew) et ne polluent jamais les sessions de checkpointing de tâches (CheckpointManager/ResumeEngine) partageant le mĂŞme store.
  • Limites connues : les mĂ©tadonnĂ©es d'exĂ©cution sont persistĂ©es en chaĂ®nes invariantes (les lectures primitives restent converties via GetValue<T>) ; la tĂ©lĂ©mĂ©trie ToolsUsed des sorties de tâches n'est pas persistĂ©e (v1).

Barrière de permissions — AddOrkeonPermissionGate(configuration)

  • Activation : appelĂ©e par RunnerHost et le bootstrap de la ConsoleApp, mais n'enregistre rien tant que Orkeon:Security:PermissionGate:Enabled = true n'est pas posĂ©. Interactive (dĂ©faut false) dĂ©clare un canal d'approbation ; le laisser Ă  false tant que le flux Ask du REPL n'a pas atterri (v2).
  • Effet : ModePermissionGate est consultĂ© par la boucle scriptĂ©e ctx.llm.act avant CHAQUE exĂ©cution d'outil. Modes : bypassPermissions → tout autoriser ; plan → refuser tout ce qui n'est pas une lecture ; acceptEdits → accepter automatiquement les lectures + file_write, demander pour le shell ; default → tout demander. En headless, chaque demande dĂ©grade en un DENIED: motivĂ© renvoyĂ© au modèle comme rĂ©sultat d'outil (pas d'exception). Les outils inconnus sont classĂ©s comme Ă©critures (fail-closed).
  • Classification dĂ©clarative : les outils peuvent auto-dĂ©clarer leur classe via IBaseTool.Access (ToolAccess.Read / Edit / Execute) — une dĂ©claration l'emporte sur les tables de noms de la barrière ; Unspecified (le dĂ©faut) se replie sur les tables. Les outils de lecture intĂ©grĂ©s (file/directory/session/memory/analysis), file_write (Edit) et shell_command/http_api (Execute) se dĂ©clarent tous.
  • DĂ©faut rĂ©tro-compatible : flag absent → aucune barrière enregistrĂ©e → act se comporte exactement comme avant. Les scripts optent pour un mode Ă  l'appel via l'option d'act permissionMode.

Shell : interpréteurs, allowlist & réécriture VFS — Orkeon:Tools:Shell:*

  • AllowInterpreters = true (config seule, lue par AddOrkeonCodeTools()) : rĂ©active node/dotnet/npm/find ET lève la restriction git lecture-seule (git add/commit/branch fonctionnent). Équivalent RCE sur l'hĂ´te — Ă  rĂ©server aux hĂ´tes coding-agent de confiance (le REPL scripted-commands est le consommateur de rĂ©fĂ©rence — voir examples/cli-ts-commands/ ; une commande de commit ne marche pas sans). Avertissement de sĂ©curitĂ© loggĂ©.
  • Allowlist personnalisĂ©e (deux clĂ©s tableau de chaĂ®nes) :
    • ExtraAllowedCommands — additive sur l'allowlist par dĂ©faut (ou de remplacement) ; la voie recommandĂ©e pour autoriser make/cargo/etc. Compose avec AllowInterpreters.
    • AllowedCommands — remplacement intĂ©gral verbatim ; par contrat du ctor de ShellCommandTool, il annule AllowInterpreters et rĂ©active la restriction git lecture-seule.
    • Une section absente ou vide se lie Ă  null (dĂ©fauts) — jamais Ă  un tableau vide, qui bloquerait toute commande.
  • Réécriture de chemins VFS (toujours active, sans flag) : les arguments qui nomment un chemin virtuel prĂ©fixĂ© par un mount (y compris la forme --out=/workspace/dist) sont rĂ©solus virtuel→physique avant le dĂ©marrage du processus — un chemin refusĂ© fait Ă©chouer l'appel avec la raison expurgĂ©e — et stdout/stderr sont réécrits physique→virtuel : le modèle ne voit jamais que des chemins virtuels. Mounts AgentFacing, matching ordinal ; sans mount, les deux passes sont des no-ops.
  • DĂ©faut rĂ©tro-compatible : aucune clĂ© → allowlist stricte lecture-seule, comportement historique inchangĂ©.

Streaming console LLM natif — AddLlmConsoleStreaming(configuration)

  • Activation : appelĂ©e par le bootstrap de la ConsoleApp, mais n'enregistre rien tant que Orkeon:Cli:ConsoleStreaming:Enabled = true n'est pas posĂ©.
  • Effet : enregistre ConsoleLlmDeltaSink comme ILlmDeltaSink. Quand un sink est prĂ©sent et que le provider LLM streame (IStreamingLlmProvider), la boucle scriptĂ©e ctx.llm.act bascule sur le chemin SSE et chaque delta de contenu est Ă©crit incrĂ©mentalement vers l'IConsoleAdapter de l'hĂ´te — le REPL rend les tokens au fil de leur arrivĂ©e sans que le script passe onDelta. Les tours qui ne streament aucun contenu visible (appels d'outils purs) n'Ă©mettent rien. Le sink compose avec un onDelta cĂ´tĂ© script (les deux reçoivent chaque delta).
  • DĂ©faut rĂ©tro-compatible : flag absent → aucun sink enregistrĂ© → act conserve son rendu bufferisĂ© (identique Ă  l'octet près), les scripts peuvent toujours streamer via onDelta.

Garanties de non-régression

Les tests d'enregistrement (tests/core/Orkeon.Infrastructure.Tests/DependencyInjection/OptInSubsystemsRegistrationTests.cs et tests/core/Orkeon.Application.Tests/DependencyInjection/KickoffHookExtensionsTests.cs) vérifient :

  1. qu'aucun port dormant du jeu opt-in d'origine n'est enregistré par AddOrkeonApplication() / AddOrkeonInfrastructure() (les deux surcharges) — les lignes ajoutées ensuite (plugins, embeddings locaux, LanceDB/Redis, mémoire cognitive) sont gardées par leurs propres suites, pas par ce test ;
  2. que chaque AddOrkeonXxx() produit un graphe résolvable seul (avec logging et, le cas échéant, une IConfiguration) ;
  3. que les opt-ins composent avec le socle (sémantique TryAdd, pas de doublons).