Skip to content

Reactive Coeffects : réponse des dépendances spatiale

论文版本948a07b (main)

L'article utilise les Reactive Coeffects pour résoudre la spatial composability — le système peut-il ajuster automatiquement les cycles de vie et le câblage des dépendances après l'apparition, la disparition ou le remplacement des dépendances d'un composant. Idée centrale : les composants déclarent ce dont ils ont besoin (une spécification de coeffect), et le runtime les notifie selon la spécification lorsque le contexte change.

Coeffect Context et « set est un effect »

[Conclusion originale de l'article §3.2.1] Le coeffect context Σ ≔ (k : K) ⇀ 𝒱_k est une fonction partielle finie des clés de dépendance vers des valeurs typées. get et set sont les deux opérations centrales (Def 23), et set(k, v) est lui-même un effect — une opération de coeffect est un effect, donc la provision de coeffect hérite automatiquement de la trackability et de la recoverability. C'est le pont entre Revertible Effects et Reactive Coeffects : déclarer une dépendance (provide) est en même temps effectuer un effect révertible.

Coeffect Specification et le changement à trois états

[Conclusion originale de l'article §3.2.2] Une coeffect specification d ⊆ K est l'ensemble des clés de dépendance qu'un composant déclare ; le satisfaction predicate σ ⊧ d ≔ ∀k ∈ d. k ∈ dom(σ). Tout effect transformant σ en σ' peut être classé selon d comme activating / deactivating / neutral (Def 26) :

  • activating : avant le changement σ ne satisfaisait pas d, après le changement σ' satisfait — le composant devrait être activé ;
  • deactivating : avant le changement il satisfaisait, après le changement il ne satisfait plus — le composant devrait être déchargé ;
  • neutral : satisfait avant et après, ou non satisfait avant et après — le composant n'a pas besoin de changer d'état (mais l'instance de dépendance a pu être remplacée).

L'exemple complet base de données A + RAG B

Cas concret (l'exemple standard qui traverse tout l'article) :

Plugin A (plugin de base de données) : set('database', dbService)  fournit la dépendance
Plugin B (plugin RAG) :               déclare d_B = {'database'}     nécessite la dépendance
  • A apparaît : A fournit le service de base de données via ctx.set('database', dbService) ; la clé 'database' apparaît dans σ. Le d_B = {'database'} déclaré par B passe de non satisfait à satisfait — activating, B est notifié et activé automatiquement, et obtient dbService depuis ctx.get('database').
  • A disparaît ou est remplacé : le fiber de A entre dans Unloading ; la clé 'database' est retirée de σ. Le d_B de B passe de satisfait à non satisfait — deactivating, B est notifié et déchargé automatiquement (son propre inverse accumulator est appliqué, libérant les ressources détenues par B).
  • Un nouveau A est prêt : le nouveau plugin de base de données A' fournit via ctx.set('database', newDbService). Le d_B de B passe à nouveau de non satisfait à satisfait — activating, B se réactive en utilisant la nouvelle dépendance et obtient newDbService.

Tout au long du processus, le code de B n'a jamais besoin de sonder activement « si A n'est plus là, alors... » — le runtime notifie automatiquement selon la spécification de coeffect.

Committed View vs Target View

[Conclusion originale de l'article §4.1, §4.2] Dans l'implémentation Cordis, il y a deux vues clés de résolution de dépendances :

  • Committed View (ω) : la résolution de dépendances actuellement committée, enregistrant le mapping nom-de-fiber vers provider. Ce qu'un composant lit pendant tout un episode est cette vue, garantissant que les dépendances sont stables durant le cycle de vie courant du composant (voir le théorème d'Ordering).
  • Target View : l'état de résolution de dépendances dans lequel le fiber devrait se trouver, recalculé par refresh quand la configuration change. Quand target diverge de committed, des transitions de cycle de vie (activation, déchargement, ou rechargement) sont déclenchées.

[Conclusion originale de l'article §4.2] Détail clé : la target view enregistre provider identity (fiber uid), pas l'égalité de value. L'article note explicitement : « makes the comparison usable, since a different fiber providing an equal value would otherwise compare equal » — si l'on comparait seulement les values, des fibers différents fournissant des values égales seraient mal jugés comme « la dépendance n'a pas changé », la réactivation ne se déclencherait pas, et le consumer continuerait à utiliser un snapshot de l'ancien fiber sans savoir que le provider avait été remplacé. fiber.target dans l'implémentation Cordis stocke un digest uid du résultat de résolution de dépendances (§5.1.3).

Isolation et Interception

[Conclusion originale de l'article §3.2.3] Deux mécanismes dérivés orthogonaux :

  • Isolation : via la isolation realm table ρ : K ⇀ R, la même key k résout vers différents realms r dans différents contextes, et se lie donc à différentes valeurs. ctx.isolate(k, r) dérive un nouveau contexte qui ne surcharge que le mapping de ρ à k (une derived realization, ne modifiant pas la table parente).
  • Interception : attache des métadonnées à un coeffect ι : K → ℙ_k ; la fonction provider reçoit les métadonnées et ajuste son comportement en conséquence. ctx.intercept(k, ν) dérive un contexte qui fusionne ν dans les métadonnées à k.

Différence : Isolation remplace « vers quel binding une key se résout » (swap d'instance), tandis qu'Interception modifie « comment le binding est utilisé » (ajout de contraintes, pas de swap). Isolation est une derived realization (pas d'inverse nécessaire — il suffit de jeter le contexte enfant), alors que set est une in-place realization (un inverse est nécessaire pour réverter).

Comparaison de scénarios

ScénarioUtiliser IsolationUtiliser Interception
Multi-tenant / différents workspacesLa même key 'db' résout vers l'instance de chaque tenant
Environnement indépendant de sous-AgentLe même 'filesystem' résout vers des instances indépendantes par sous-Agent
Doubles de testSurcharge avec un mock realm
Permission filesystem en lecture seuleAttacher une métadonnée readonly
Différents plugins utilisant différents modèlesIsoler la key 'model' de chacun
Politique d'accès stricte pour plugins communautairesAttacher une métadonnée de restriction de capability

Les Reactive Coeffects résolvent « percevoir les changements de dépendance », mais le processus de chargement/déchargement/rechargement de l'instance du composant lui-même requiert encore une machine à états pour le gérer. Voir Cycle de vie et ordre de déchargement.

Site d'apprentissage communautaire non officiel. Interprète le paper de cordiverse/paper et le relie à l'architecture de DeepSeek Harness. Auteurs : Yifan Shi, Wei Zhang (PKU), Tianyi Cui (DeepSeek-AI). · Confidentialité · Conditions · À propos