Skip to content

Perfiles de outcomes para Agent v11

Estado: contrato de composición y evaluación, no decisión de retirada. Agent es la superficie canónica para composición nueva. SymfonicAgent sigue siendo una API pública viva y agent/engine.py sigue atendiendo los turnos que no caben en el sobre migrado. Este catálogo no cambia defaults de FrameworkConfig, no abre ese sobre y no autoriza eliminar compatibilidad.

Un perfil es una receta explícita para obtener un outcome observable. No es una clase, preset oculto ni traductor de flags. La raíz de composición elige collaborators, grants y autoridad; las capabilities declaran las etapas que se ejecutan. Tener una capability construida, o un manifest con su nombre, prueba composición, no que el outcome haya ocurrido.

  • Sólo hay cinco perfiles canónicos: chat sin estado, continuidad de memoria, herramientas enrutadas, gobernanza y continuación humana.
  • La ausencia de una capability significa que ese comportamiento está apagado. Agent no toma los booleanos de FrameworkConfig como perfil implícito.
  • La evidencia combina composition_manifest, eventos/etapas y un efecto final determinista. Nunca se acepta sólo el texto de la respuesta.
  • Una raíz puede combinar perfiles si declara sus fronteras. Memoria + prompting renderiza recall; memoria sola recupera y publica, pero no pone recall ante el modelo.
  • Una relación legacy es candidata de transición, no aprobación CORE-1. Cada fila que cambie o se elimine conserva decisión, nodo y evidencia propios.

Qué atestigua el manifest

Agent.composition_manifest es una atestación sin payload de la compilación: capabilities, descriptores de etapa, herramientas contribuidas, preconditions y un digest. Sirve para impedir que un eval describa un Agent distinto al que se ejecutó. No contiene instrucciones, registros de memoria, prompts, credenciales, texto de usuario ni prueba de una llamada externa.

Todo eval de perfil debe comprobar primero el digest/filas relevantes y después observar la etapa o puerto que hace material el outcome. Si se cambia la capability o sus collaborators, digest y batería de outcomes cambian juntos.

1. Chat sin estado

Outcome. Un proveedor recibe una vuelta con instrucciones, input y herramientas estáticas declaradas; la llamada devuelve AgentResult o una secuencia de AgentEvent. La continuidad entre vueltas pertenece al adopter, que vuelve a pasar result.messages como history.

from symfonic import Agent

agent = Agent(provider, instructions="Ayuda con precisión.", tools=TOOLS)
result = await agent.run("Resume el pedido")
next_result = await agent.run("¿Qué falta?", history=result.messages)
Aspecto Contrato
Raíz pública Agent(provider, instructions=..., model=..., tools=..., max_model_rounds=...)
Capabilities Ninguna. Las herramientas estáticas pertenecen a tools=.
Evidencia Manifest sin etapas/capabilities no solicitadas; llamada de proveedor; run devuelve resultado o stream entrega los eventos terminales esperados.
Autoridad El adopter elige proveedor, instrucciones, modelo, herramientas y límite de rondas. El kernel concede model_call y tool_call sólo si hay herramientas.
No es Sesión durable, recuperación de proceso, HMS, routing ni gobernanza.

El baseline es deliberadamente pequeño. session_id en Agent.run es correlación de vuelta, no un checkpointer ni historial persistido.

2. Continuidad de memoria

Outcome. Para un scope fijado por la raíz, un turno puede recuperar memoria, publicar la nueva interacción y hacer visible una publicación en una vuelta posterior. Con prompting apropiado, el recall entra además al prompt. Consolidación, extracción, ventana, activación y telemetría son extensiones explícitas, no defaults del perfil.

from symfonic import Agent
from symfonic.capabilities.memory import MemoryScope, memory_capabilities
from symfonic.capabilities.prompting import PromptingCapability

scope = MemoryScope("acme")
agent = Agent(
    provider,
    capabilities=[
        *memory_capabilities(store, scope, extractor=extractor),
        PromptingCapability(sources=[memory_prompt_source]),
    ],
)

memory_prompt_source representa la fuente que consume el snapshot de retrieval; no es intercambiable con una cadena legacy. La raíz puede omitirla, pero entonces sólo evalúa recall/publicación, no que el modelo vio memoria.

Aspecto Contrato
Raíz pública memory_capabilities(store, scope, ...) junto a Agent(..., capabilities=...); para prompt, PromptingCapability compatible.
Capabilities/grants La factory entrega MemoryCapability y GrantEffects("memory-read", "memory-write", "memory-flush"); añade memory-consolidate sólo con coordinator.
Evidencia Manifest con retrieval, write y lifecycle; una vuelta escribe y flushes; la siguiente recupera en el mismo scope; otro scope no recupera. Si se promete prompt, capturar la solicitud del proveedor y el bloque de recall.
Autoridad La raíz fija store, scope, límite, retrieval policy, extractor, consolidación y fuentes de prompt. La capability no puede otorgarse efectos.
No es Traducción de auto_hydrate/auto_consolidate, ni transcript literal/restart.

Un control anti-vacuidad cambia dato o scope y observa el puerto/etapa. Por ejemplo, recent_turns se prueba en la llamada a WorkingWindow, no con texto del modelo.

3. Herramientas enrutadas

Outcome. Una vuelta ofrece al proveedor sólo la paleta seleccionada por un router/pipeline explícito y después puede ejecutar una herramienta ofrecida. Routing reduce la oferta; no es por sí mismo una frontera de autorización.

from symfonic import Agent
from symfonic.capabilities.tools import ToolsCapability, keyword_router, tool_name
from symfonic.platform import GrantEffects

names = tuple(tool_name(tool) for tool in TOOLS)
agent = Agent(
    provider,
    tools=TOOLS,
    capabilities=[
        GrantEffects("memory-read"),
        ToolsCapability(
            registered=names,
            entries_for=keyword_router(KEYWORDS, registered=names),
        ),
    ],
)
Aspecto Contrato
Raíz pública Agent(tools=TOOLS, capabilities=[GrantEffects(...), ToolsCapability(...)])
Capabilities/grants ToolsCapability declara tools.routing; los grants dependen del router/stages. La raíz declara exactamente los efectos necesarios.
Evidencia Manifest con tools.routing y herramientas registradas; dos cues dan paletas distintas antes de bind_tools; una herramienta permitida ejecuta y deja su efecto esperado. Probar run y stream cuando el host lo publique.
Autoridad La raíz registra herramientas servibles, selecciona router/pipeline/preconditions y grants. Governance/preconditions autorizan, reparan o rehúsan llamadas.
No es intent_filter_mode, garantía de que el modelo llamará una herramienta ni autorización de una herramienta no ofrecida.

La mutación de cue o retirada del routing debe volver rojo el spy de bind_tools; sólo comprobar que existe ToolsCapability sería vacuo.

4. Gobernanza

Outcome. Las reglas compuestas pueden enmendar o rechazar una acción/draft antes de que llegue al consumidor. Una negativa debe atribuir su regla y no producir el efecto prohibido; una enmienda debe observarse en la entrada del puerto posterior, no sólo en un registro.

from symfonic import Agent
from symfonic.platform import governance

agent = Agent(
    provider,
    tools=TOOLS,
    capabilities=[governance(preconditions=[policy], decisions=decision_log)],
)
Aspecto Contrato
Raíz pública Agent(..., capabilities=[governance(...)]), con los collaborators de policy, reflector, decision sink y reglas autorizados.
Capabilities/grants governance(...) compone etapas de ingreso/egreso y, donde aplique, preconditions de tool call.
Evidencia Manifest con etapas/preconditions; caso rechazado atribuye regla y no llama al tool/event sink prohibido; caso enmendado observa el dato enmendado en el siguiente puerto. Drenar stream si se ofrece.
Autoridad El despliegue define reglas, patrones, decision sink y efectos. Governance puede negar/enmendar; no recibe autoridad implícita por existir.
No es Default global de seguridad, equivalencia textual con booleans legacy ni prueba de que toda respuesta histórica fue reescrita.

Una caída de reflector conserva su política fail-open vigente donde aplique; no debe relabelarse como rechazo. Una negativa válida prueba ausencia del side effect, no solamente GovernanceRefused.

5. Continuación humana

Outcome. El agente puede ofrecer una interacción humana que pausa una vuelta; un AgentHost recupera después un token duradero, deriva scope desde claims autenticados y continúa una sola vez. Capability y host son dos mitades obligatorias.

from symfonic import Agent
from symfonic.capabilities.human import human_interaction
from symfonic.platform import AgentHost, human_continuation

interaction = human_interaction(
    signer=signer,
    binding=binding_for_current_turn,
    encode_token=encode_token,
    decode_token=decode_token,
    consumption=shared_consumption,
)
host = AgentHost(
    composer=lambda scope, resources: Agent(
        resources.provider, capabilities=[interaction],
    ),
    resources=resources,
    continuation_factory=human_continuation(
        capability=interaction,
        scope_for_claims=scope_for_verified_claims,
    ),
)

En una raíz real, el capability entregado al Agent y a human_continuation es el mismo objeto de token/ledger/checkpoint. La función binding debe producir el binding del turno y scope que la raíz ya verificó. Sin decode_token se puede pausar pero no hay lector público de continuidad; no satisface el perfil.

Aspecto Contrato
Raíz pública human_interaction(...) dentro de Agent, más AgentHost(..., continuation_factory=human_continuation(...))
Capabilities/grants HumanInteractionCapability ofrece interacción y guarda pausa; AgentHost posee agentes por scope y el redemption service.
Evidencia Manifest con herramienta/etapa humana; proceso 1 pausa; proceso 2 crea host nuevo y reanuda. Probar scope mismatch, payload corrupto, expiry y segundo canje; sólo el válido continúa.
Autoridad Raíz provee signer, binding, codec, TTL, ledger/consumption, checkpoint y scope_for_claims. El host, no HTTP ni el agente, deriva scope.
No es Agent.resume(token), importación SQLite legacy, ni paridad de streaming token a token con el motor legado. El puerto HTTP tipado entrega el resultado o los eventos que exponga la raíz.

El consumo en memoria sólo es válido para un proceso. Con réplicas, el despliegue elige y prueba un consumption store compartido.

Relación con filas legacy

Esta tabla es un índice de transición, no un veredicto de producto. “Equivale” sólo repite equivalent-proven de la matriz existente; no aprueba sustituir un consumidor. “Cambia” y “elimina” requieren CORE-1 por fila antes de migrar una raíz o modificar compatibilidad.

Perfil Filas legacy relacionadas Relación actual Límite
Chat sin estado state_class, messages_cache_policy, activation_log_mode cambia / elimina State es mapping por vuelta; no hay conversión de clase, rolling cache ni footer equivalente.
Memoria working_memory_recent_turns, enabled_layers, hydration_min_relevance, scope_blend_mode, quick_nap_interval, scorer_on_hot_path cambia Son policy/collaborators explícitos; cada uno conserva semántica y evidencia de fila.
Herramientas enrutadas procedural_force_first_action_tool, skill_auto_approve, read_only_tools equivale / cambia Forced choice tiene evidencia nativa; auto-approval sigue inactivo y read-only es governance explícita.
Gobernanza metacognition_*, credential_patterns, fabrication_refuse_min_confidence, domain.core_preferences cambia Policies y pruebas nativas no aprueban firmas/defaults ni activación de preferencias.
Continuación humana dev_sqlite_checkpoint_path, ask_user_pause_ttl_seconds, ask_user_tool_descriptions cambia / equivale TTL/descripción tienen evidencia pública; token, scope y durability son composición explícita, sin import de checkpoint legacy.

Prompt, extraction, cache, subagents, callbacks y transporte quedan fuera hasta que tengan outcome y raíz nativos propios. No se absorben por similitud de nombre.

Batería común de certificación

Para cada perfil anunciado por una raíz:

  1. Construir Agent directamente, sin FrameworkConfig, SymfonicAgent ni engine.py.
  2. Afirmar manifest/digest y las etapas, tools o preconditions relevantes sin inspeccionar payloads.
  3. Ejecutar fixture determinista que observe etapa y efecto final; usar run y añadir stream cuando el root prometa streaming.
  4. Ejecutar control negativo: retirar capability/grant o cambiar input/scope debe invalidar el outcome por la razón declarada.
  5. Para una fila legacy, añadir diferencial por fila y decisión de owner. Un perfil verde no convierte una fila a equivalente ni habilita retirar fallback.

Las pruebas existentes que cubren parte de esta base son tests/retirement/test_core15_measurable_native_evidence.py (memoria/prompt), tests/agent/cutover/test_lazy_palette_end_to_end.py (paleta routed), tests/platform/test_governance_amends.py y tests/platform/test_governance_refusal_precedence.py (autoridad), y tests/platform/test_fp3_public_preservation_journeys.py (continuación tras reinicio). Son evidencia localizada, no certificación automática de todas las raíces consumidoras.

Límite de migración

Una root adopta un perfil con collaborators públicos, protocolos de transporte ya probados y telemetría de fallback separada del tráfico legacy elegido por configuración. Cero fallbacks requiere el evento durable CORE-24; el manifest de Agent no mide producción.

La secuencia es: definir outcome, componer perfil, certificarlo en una raíz delimitada, decidir cada fila legacy afectada y sólo entonces migrar consumidores. Ninguna etapa implica que el engine dejó de servir turns ni que el retirement gate quedó satisfecho.