🇬🇧 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 parAddOrkeonInfrastructure()(les deux surcharges) : chacun s'active par son extensionAddOrkeonXxx()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 (sectionMCP, via la surchargeIConfiguration, ou l'hôte des runners dès queMCP:Serversdé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'IStateStorede checkpointing opt-in (à enregistrer d'abord), transformantGET /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) exposantPOST /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);IA2AServern'est enregistré que siEnableServerest vrai. - Dépendances : l'extension enregistre elle-même (TryAdd)
IHttpClientFactory,IDomainEventDispatcher,IUnitOfWork, ainsi que l'annuaire d'agents A2A (IAgentRegistrationStoresingleton +IAgentRepositoryscoped, voir ci-dessous) lorsque l'hôte ne les a pas déjà câblés viaAddOrkeonInfrastructure(). - Cycle de vie du dépôt d'agents (R4.6 / ANT-001, décision « scoped par requête ») :
IAgentRepositoryest scoped ; le serveur et le routeur (singletons) ne le capturent jamais — ils ouvrent un scope DI par requête A2A viaIServiceScopeFactoryet résolvent le dépôt dedans. La résolution passe avecValidateScopes = 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 leInMemoryAgentRepositoryà store par scope),AddOrkeonA2A(...)surclasse cette implémentation par défaut versSharedStoreAgentRepository(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. AppelerAddOrkeonA2A(...)aprèsAddOrkeonInfrastructure()et après un éventuel dépôt custom (ordre recommandé, cf. Principe) ; un dépôt custom enregistré aprèsAddOrkeonA2A(...)gagne (dernier enregistrement).
- Limites connues : le store in-memory est local au processus — pour un annuaire
d'agents multi-instances, fournir un
IAgentRepositorycustom 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 (
MeterListenersurOrkeonMetrics) 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 surchargeAddOrkeonInfrastructure(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, optionsSecurity: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, sectionOrkeon:Dlp) et 5 intercepteurs de canaux (sortie d'outil, délégation, logs, mémoire, sortie externe). - Activation :
services.AddOrkeonDlp(); - Dépendances : logging +
IConfiguration(liaisonOrkeon: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 lePiiDetectionValidatordu 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, sectionToolRateLimiting) et suivi de budget de tokens par agent/crew (ITokenBudgetTracker, sectionTokenBudget). - Activation :
services.AddOrkeonToolRateLimiting(); - Dépendances : logging +
IConfiguration. SiAddOrkeonCostTracking()(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é viaProvisionNewKeyAsync(secretStore, secretName, keySizeInBits)(IWritableSecretProvider, implémenté parDpapiSecretProvider). - 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
RotateAsyncavec 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.ContinueOnUnreadableEntriespermet de l'ignorer (entrée laissée telle quelle et signalée dansKeyRotationResult.Errors).
- Activation :
services.AddOrkeonKeyRotation();— à coupler avecAddOrkeonEncryption()(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, typeMemoryProviderBasepour l'énumération des clés) et suppose qu'aucune écriture concurrente n'a lieu pendant la fenêtre de rotation.AesEncryptionProvider.RotateKeyAsyncest neutralisé (NotSupportedException, plus aucun faux log de succès) : une rotation « sur place » orphelinerait les données existantes — passer parIKeyRotationService.
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 avecAddOrkeonEvaluation()(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 viaLlmMessage.MultiModalContent.AnthropicLlmProviderémet des blocs de contenu image conformes à l'API Messages ({"type":"image","source":{"type":"base64"|"url",…}}) ;OpenAIProviderémet des partsimage_urlconformes à 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(optionsOrkeon:MultiModal) et chargement d'images depuis le système de fichiers virtuel viaIMultiModalContentLoader(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 :
IContentValidationServicen'a besoin que des options ;IMultiModalContentLoaderrequiert unIFileSystemServiceré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 parOpenAICompatibleProviderBase) — les 16 providers la déclarent (DeepSeek depuis la campagne du 2026-08-30 qui a mesurédeepseek-v4-flash-vision-exp, natif surdeepseek-flashdepuis 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 uneNotSupportedExceptionexplicite si elles atteignent un payload vision.
Hooks de kickoff — AddOrkeonKickoffHooks()
- Rôle : exécution de callbacks
BeforeKickoffHook/AfterKickoffHookautour du kickoff d'un crew, par ordre dePrioritycroissante, avec sémantiqueContinueOnError(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 :
ICodebaseContextProviderproduit des résumés de codebase destinés à être injectés dans le contexte des agents (fonctionnalité RaggableTree). - Activation : enregistré par
AddRaggableTree(options)(projetOrkeon.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/adaptiveAddOrkeonRagcâ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êmeAddOrkeonRagWebFallback(configuration)est un no-op ; la fonctionnalité est gouvernée par les deux interrupteurs de configuration ci-dessous. - Profils (
Orkeon:Rag:Profile, dĂ©fautfast; les surcharges clĂ© par clĂ© s'appliquent par-dessus le preset) :fast(vectoriel seul) etcorrective(graphe CRAG — boucle au lieu d'un Ă©tage de rerank linĂ©aire) fonctionnent sans les paquets ONNX ;balanced/qualityactivent l'Ă©tage de rerank cross-encoder etadaptivedĂ©lègue sa routeSingleShotĂ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_fallbackdu graphe correctif ne s'exécute que quand les deuxOrkeon:Rag:Corrective:WebFallback:Enabled(politique) etOrkeon:Rag:WebFallback:Enabled+ unEndpointnon vide (transport, SearxNG) sont posés. Chaque page téléchargée est filtrée parPromptInjectionDocumentValidator(Rejectedn'entre jamais dans le working set ;Suspicioussuit 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 viaCreateStateAsync(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) :
Avec la surcharge// 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:PersistenceAddOrkeonInfrastructure(IConfiguration), la présence de la sectionOrkeon: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étrieToolsUseddes sorties de tâches n'est pas persistée (v1).
Barrière de permissions — AddOrkeonPermissionGate(configuration)
- Activation : appelée par
RunnerHostet le bootstrap de la ConsoleApp, mais n'enregistre rien tant queOrkeon:Security:PermissionGate:Enabled = truen'est pas posĂ©.Interactive(dĂ©fautfalse) dĂ©clare un canal d'approbation ; le laisser Ăfalsetant que le flux Ask du REPL n'a pas atterri (v2). - Effet :
ModePermissionGateest consulté par la boucle scriptéectx.llm.actavant 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 unDENIED: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) etshell_command/http_api(Execute) se déclarent tous. - Défaut rétro-compatible : flag absent → aucune barrière enregistrée →
actse comporte exactement comme avant. Les scripts optent pour un mode Ă l'appel via l'option d'actpermissionMode.
Shell : interpréteurs, allowlist & réécriture VFS — Orkeon:Tools:Shell:*
AllowInterpreters = true(config seule, lue parAddOrkeonCodeTools()) : réactivenode/dotnet/npm/findET lève la restriction git lecture-seule (git add/commit/branchfonctionnent). É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 — voirexamples/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 autorisermake/cargo/etc. Compose avecAllowInterpreters.AllowedCommands— remplacement intĂ©gral verbatim ; par contrat du ctor deShellCommandTool, il annuleAllowInterpreterset 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. MountsAgentFacing, 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 = truen'est pas posé. - Effet : enregistre
ConsoleLlmDeltaSinkcommeILlmDeltaSink. Quand un sink est présent et que le provider LLM streame (IStreamingLlmProvider), la boucle scriptéectx.llm.actbascule sur le chemin SSE et chaque delta de contenu est écrit incrémentalement vers l'IConsoleAdapterde l'hôte — le REPL rend les tokens au fil de leur arrivée sans que le script passeonDelta. Les tours qui ne streament aucun contenu visible (appels d'outils purs) n'émettent rien. Le sink compose avec unonDeltacôté script (les deux reçoivent chaque delta). - Défaut rétro-compatible : flag absent → aucun sink enregistré →
actconserve son rendu bufferisé (identique à l'octet près), les scripts peuvent toujours streamer viaonDelta.
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 :
- 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 ; - que chaque
AddOrkeonXxx()produit un graphe résolvable seul (avec logging et, le cas échéant, uneIConfiguration) ; - que les opt-ins composent avec le socle (sémantique
TryAdd, pas de doublons).