Skip to content

Reactive Coeffects: respuesta de dependencias espacial

论文版本948a07b (main)

El artículo usa Reactive Coeffects para resolver la spatial composability — si el sistema puede ajustar automáticamente los ciclos de vida y el cableado de dependencias después de que las dependencias de un componente aparecen, desaparecen o se reemplazan. Idea central: los componentes declaran lo que necesitan (una especificación de coeffect), y el runtime les notifica según la especificación cuando el contexto cambia.

Coeffect Context y "set es un effect"

[Conclusión original del artículo §3.2.1] El coeffect context Σ ≔ (k : K) ⇀ 𝒱_k es una función parcial finita de claves de dependencia a valores tipados. get y set son las dos operaciones centrales (Def 23), y set(k, v) es en sí mismo un effect — una operación de coeffect es un effect, por lo que la provisión de coeffect hereda automáticamente la trackability y recoverability. Este es el puente entre Revertible Effects y Reactive Coeffects: declarar una dependencia (provide) es al mismo tiempo realizar un effect revertible.

Coeffect Specification y el cambio de tres estados

[Conclusión original del artículo §3.2.2] Una coeffect specification d ⊆ K es el conjunto de claves de dependencia que declara un componente; el satisfaction predicate σ ⊧ d ≔ ∀k ∈ d. k ∈ dom(σ). Cualquier effect que transforme σ en σ' puede clasificarse según d como activating / deactivating / neutral (Def 26):

  • activating: antes del cambio σ no satisfacía d, después del cambio σ' sí — el componente debería activarse;
  • deactivating: antes del cambio sí, después del cambio no — el componente debería descargarse;
  • neutral: satisface antes y después, o no satisface antes ni después — el componente no necesita cambiar de estado (pero la instancia de dependencia puede haberse cambiado).

El caso completo de base de datos A + RAG B

Caso concreto (el ejemplo estándar que recorre todo el artículo):

Plugin A (plugin de base de datos): set('database', dbService)  proporciona la dependencia
Plugin B (plugin RAG):              declara d_B = {'database'}    necesita la dependencia
  • A aparece: A proporciona el servicio de base de datos mediante ctx.set('database', dbService); la clave 'database' aparece en σ. El d_B = {'database'} declarado por B pasa de no satisfecho a satisfecho — activating, B es notificado y activado automáticamente, y obtiene dbService desde ctx.get('database').
  • A desaparece o se reemplaza: el fiber de A entra en Unloading; la clave 'database' se elimina de σ. El d_B de B pasa de satisfecho a no satisfecho — deactivating, B es notificado y descargado automáticamente (se aplica su propio inverse accumulator, liberando los recursos retenidos por B).
  • Un nuevo A está listo: el nuevo plugin de base de datos A' proporciona vía ctx.set('database', newDbService). El d_B de B pasa de nuevo de no satisfecho a satisfecho — activating, B se reactiva usando la nueva dependencia y obtiene newDbService.

Durante todo el proceso, el código de B no necesita escribir comprobaciones activas del estilo "si A ya no está, entonces..." — el runtime notifica automáticamente según la especificación de coeffect.

Committed View vs Target View

[Conclusión original del artículo §4.1, §4.2] En la implementación de Cordis hay dos vistas clave de resolución de dependencias:

  • Committed View (ω): la resolución de dependencias actualmente comprometida, que registra el mapeo de nombres de fiber a provider. Lo que un componente lee a lo largo de un episode es esta vista, garantizando que las dependencias son estables durante el ciclo de vida actual del componente (véase el teorema de Ordering).
  • Target View: el estado de resolución de dependencias en el que se espera que esté el fiber, recalculado por refresh cuando cambia la configuración. Cuando target diverge de committed, se disparan transiciones del ciclo de vida (activación, descarga o recarga).

[Conclusión original del artículo §4.2] Detalle clave: target view registra provider identity (fiber uid), no si el value es igual. El artículo señala explícitamente: "makes the comparison usable, since a different fiber providing an equal value would otherwise compare equal" — si solo se comparara value, fibers distintos que proveen el mismo value serían mal juzgados como "la dependencia no cambió", no se dispararía la reactivación, y el consumer seguiría usando una instantánea del fiber antiguo sin saber que el provider se había cambiado. fiber.target en la implementación de Cordis almacena un digest uid del resultado de resolución de dependencias (§5.1.3).

Isolation e Interception

[Conclusión original del artículo §3.2.3] Dos mecanismos derivados ortogonales:

  • Isolation: mediante la isolation realm table ρ : K ⇀ R, la misma key k resuelve a distintos realms r en distintos contextos, y por tanto se vincula a distintos valores. ctx.isolate(k, r) deriva un nuevo contexto que solo sobrescribe el mapeo de ρ en k (derived realization, no modifica la tabla padre).
  • Interception: cuelga metadata de un coeffect ι : K → ℙ_k; la función provider recibe la metadata y ajusta su comportamiento en consecuencia. ctx.intercept(k, ν) deriva un contexto que fusiona ν en la metadata de k.

Diferencia: Isolation reemplaza "a qué binding se resuelve una key" (intercambio de instancia), mientras que Interception modifica "cómo se usa el binding" (añade restricciones, sin intercambio). Isolation es una derived realization (no necesita inverse — basta con descartar el contexto hijo), mientras que set es una in-place realization (necesita un inverse para revertir).

Comparación de escenarios

EscenarioUsar IsolationUsar Interception
Multi-tenant / diferentes workspacesLa misma key 'db' resuelve a la instancia de cada tenant
Entorno independiente de sub-AgenteEl mismo 'filesystem' resuelve a instancias independientes por sub-Agente
Dobles de pruebaSobrescribir con un mock realm
Permiso de solo lectura del sistema de ficherosAdjuntar metadata readonly
Diferentes plugins usando diferentes modelosAislar la key 'model' de cada uno
Política de acceso estricta para plugins comunitariosAdjuntar metadata de restricción de capability

Los Reactive Coeffects resuelven "percibir cambios de dependencia", pero el proceso de carga/descarga/recarga de la propia instancia del componente aún requiere una máquina de estados para gestionarlo. Véase Ciclo de vida y orden de descarga.

Sitio de aprendizaje comunitario no oficial. Interpreta el paper de cordiverse/paper y lo relaciona con la arquitectura de DeepSeek Harness. Autores: Yifan Shi, Wei Zhang (PKU), Tianyi Cui (DeepSeek-AI). · Privacidad · Términos · Acerca de