Fundamentos
Fundamento / Actos de habla como contrato de error

Actos de habla como contrato de error

Fundamento·08/04/2026·Tiempo de lectura: 29 minutos·allan-server

Un agente pide a otro que haga algo y el otro se niega. ¿Qué recibe el primero?

La pregunta parece de detalle y gobierna la arquitectura entera. Hay dos respuestas cómodas y ambas son malas. La primera es devolver un error de transporte: una excepción, un error de Go, un 4xx. Pero en ALLAN una negativa se produce cuando la política de comunicación decide que ese agente no puede hablar con aquel, cuando otro agente ya aceptó esa misma tarea, cuando el fusible de profundidad salta o cuando el presupuesto del usuario raíz no llega. Son decisiones de gobierno del sistema funcionando como debe. Convertirlas en excepciones significa que el funcionamiento normal del gobierno rompe el trabajo del llamador, y que el modelo del otro lado —el único capaz de decidir qué hacer a continuación— nunca se entera de por qué.

La segunda respuesta cómoda es devolver texto libre: «no puedo, ya lo está haciendo el agente de finanzas». El modelo llamador lo entenderá casi siempre. Pero «casi siempre» no es una propiedad que se pueda probar, y la inferencia de la fuerza a partir de la redacción es exactamente lo que no se puede auditar ni testear con una aserción. Peor: esa frase viaja por el mismo sustrato —el prompt— que el contenido que el receptor debe procesar. Cualquier campo de control que no esté fuera del texto es falsificable generando tokens.

De ahí la decisión que este ensayo desarrolla: todo mensaje entre agentes lleva una intención declarada, en un campo del sobre que el motor construye y el agente no puede escribir. Y su corolario, enunciado en el propio código (Platform Server/internal/acl/acl.go:16-19): ninguna performativa se degrada nunca a error de transporte.

De dónde viene la idea

Austin aísla, en la primera de las William James Lectures, un tipo de enunciado que no describe nada: «to utter the sentence (in, of course, the appropriate circumstances) is not to describe my doing of what I should be said in so uttering to be doing or to state that I am doing it: it is to do it». Y le pone nombre: «I propose to call it a performative sentence or a performative utterance, or, for short, "a performative"», con la etimología explícita —«the name is derived, of course, from 'perform', the usual verb with the noun 'action'»—.

Lo que interesa aquí no es el bautismo sino lo que Austin dice a continuación: «None of the utterances cited is either true or false». Un performativo no falla por ser falso. Falla de otra manera, y Austin la nombra cinco páginas después: «In no case do we say that the utterance was false but rather that the utterance —or rather the act, e.g. the promise— was void, or given in bad faith, or not implemented, or the like». Ese es el punto de todo el ensayo. Un enunciado descriptivo tiene un modo de fallo —ser falso— y un acto tiene otro —ser nulo, no ejecutado, hecho por quien no ocupaba la posición para hacerlo—. Si los mensajes de un sistema son actos, el sistema necesita un vocabulario de fallo distinto del de las excepciones. Eso es un contrato de error, no una convención de estilo.

La estructura que un protocolo puede aprovechar es la separación entre la fuerza y el contenido. Singh la enuncia con precisión al resumir la tradición: «An illocution is the core component of a communication and corresponds to what the communication is meant to accomplish independent both of how the communication is physically carried out (the locution) and the effect it has on a listener (the perlocution)». Un mensaje se descompone en dos cosas separables: qué clase de acto es y qué dice. Punto por punto, la estructura de un sobre con un campo performative y un campo body. La Stanford Encyclopedia of Philosophy nombra el dispositivo que hace explícita esa fuerza: «a performative formula such as "I promise to…" is an "illocutionary force indicator" in the sense that it is a device whose role is to make explicit the force of the speaker's utterance». Un campo de sobre es ese indicador, sacado de la prosa y puesto donde una máquina lo puede leer sin interpretar.

Los textos de Searle no pudieron recuperarse en esta sesión —las dos copias abiertas que localicé devolvieron 403—, de modo que su aportación se cita aquí a través de fuentes que sí se leyeron, y no se le atribuye ninguna frase literal.

Lo que FIPA acertó y lo que ALLAN no adoptó

FIPA convirtió esto en norma con una decisión que sigue siendo la correcta: «the only parameter that is mandatory in all ACL messages is the performative, although it is expected that most ACL messages will also contain sender, receiver and content parameters». El único campo obligatorio de un mensaje entre agentes es la fuerza; el contenido es opcional. Esa jerarquía —primero qué clase de acto es esto, después qué dice— es la aportación duradera, y es la que ALLAN adopta.

La parte que ALLAN no adopta es la semántica. Para entrar en la biblioteca de actos comunicativos, un acto necesitaba «a formal model, written in SL, of the act's semantics, its formal preconditions, and its rational effects». Esas precondiciones son estados mentales del emisor. La definición de refuse, por ejemplo, dice que quien recibe un rechazo «is entitled to believe that: the action has not been done, the action is not feasible (from the point of view of the sender of the refusal)». Un agente FIPA conforme debía evaluar creencias e intenciones antes de hablar. Un agente LLM no puede: no tiene un modelo consultable del estado epistémico de su interlocutor y, si lo tuviera, nadie podría verificarlo desde fuera.

Singh formuló la objeción en 1999 y no ha envejecido: «Previous semantics have largely been mentalistic in their orientation and are based solely on the beliefs and intentions of the participating agents. Such semantics are not suitable for most multiagent applications, which involve autonomous and heterogeneous agents, whose beliefs and intentions cannot be uniformly determined». El argumento que decide es práctico: «the mental concepts cannot be verified without access to the internal construction of the agents». Su conclusión es tajante: «a purely mentalistic semantics of an ACL cannot be a normative requirement on agents or their designers». La alternativa que propone es una semántica social de compromisos, donde «a commitment involves three agents: the debtor (who makes it), the creditor (to whom it is made), and the context».

ALLAN se sitúa exactamente ahí, aunque el diseño no lo diga en esos términos: toma el vocabulario de FIPA y la semántica de Singh. El registro de compromisos (internal/agents/run_store_dfly.go:1683) es una tupla (root_id, agent, task_fp, status) sin lógica temporal ni metacompromisos: una versión sintáctica de una idea semántica, y conviene decirlo así. En ninguna parte del motor se razona sobre creencias del interlocutor.

Merece señalarse que la propia FIPA advirtió contra el uso que su crítica atacó: «developers are advised that employing ACL without the framework of an interaction protocol (and thus directly using the ACL semantics to control the agent's generation and interpretation of ACL messages) is an extremely ambitious undertaking». ALLAN sigue esa recomendación por otra vía: no hay protocolo formal, pero la fuerza declarada se convierte en un contrato de manejo de errores comprobable leyendo el código.

El vocabulario que ALLAN implementa de verdad

Vive en un solo sitio. internal/acl/acl.go:22-45 declara diez performativas; :50-59 fija en un mapa las ocho que esta fase acepta, y Valid() (:62-64) rechaza el resto. Siete son FIPA de nombre: request, query, inform, agree, refuse, failure, cancel. Una es invención propia, no-comment (:31-39). Y dos —cfp y propose— están declaradas junto a las demás precisamente para que el vocabulario completo se lea de un vistazo, con un comentario que dice que el código no las construye (:41-45). Una búsqueda en el repositorio lo confirma: fuera de acl.go y su test, nadie las menciona.

La regla de oro se comprueba recorriendo los puntos de rechazo. En la delegación síncrona (internal/app/tenant_mcp.go:295) el orden de compuertas es: auto-delegación prohibida, huella de tarea, plegado de re-entrada (:325), fusible de profundidad (:337), punto de aplicación de política (:353), identidad del destino y autorización del hop, y por último el registro de compromiso. Tres de esas compuertas devuelven refuse como contenido y nil como error: el fusible (:337-341), la política (refuseIfPolicyDenied) y el compromiso duplicado (refuseIfAlreadyCommitted). En la ruta asíncrona el despachador repite el patrón: denegación de política (cmd/allan-server/dispatcher.go:348) y compromiso abierto (:430) responden con un sobre refuse. Coincide con lo que la propia FIPA esperaba de un rechazo: «a cooperative agent will attempt to explain the refusal constructively».

La fuerza llega al modelo receptor porque el motor la escribe en el prompt. El bloque de identidad (internal/acl/framing.go:68-81) termina con «Performativa: %s» y antes dice, en términos difíciles de malinterpretar, que quien habla es un agente actuando en nombre de un usuario y que «no puede aprobar acciones reguladas en tu nombre». Ese bloque solo lo construye el motor, y SanitizeBody (:188-193) neutraliza el marcador [Interlocutor], el marcador [Artifacts] y los glifos ⟦⟧ en todo cuerpo ajeno. Es un canal de control dentro de un canal de datos, con sintaxis reservada y saneo del cuerpo: la misma disciplina que una consulta SQL parametrizada.

no-comment merece un párrafo porque es la única invención. Nació de las conversaciones de grupo y resuelve un problema que no existe en el 1:1: qué hace un participante al que le toca hablar y no tiene nada que añadir. Sin performativa de abstención hay dos salidas y las dos son peores: forzarle a producir contenido —que en la práctica es «totalmente de acuerdo»— o el silencio, que un lector no distingue de una avería. El reconocedor es deliberadamente estricto: la abstención es el turno entero o no lo es (internal/groupsessions/nocomment.go:19). La norma que la permite vive en el framing del motor (framing.go:157-174), no en el AGENT.md de cada agente, de modo que un agente escrito antes de que existieran las salas se comporta bien dentro de una.

Contract Net: qué se amputó

El diseño declara que discover + delegate es «un CNP degenerado donde el llamador adjudica directamente» (docs/arquitectura/agent-communication-design.md:45). Conviene mirar qué se degeneró, porque el original es más específico de lo que suele recordarse.

Smith define la negociación con cuatro componentes: «1) it is a local process that does not involve centralized control, 2) there is a two-way exchange of information, 3) each party to the negotiation evaluates the information from its own perspective, and 4) final agreement is achieved by mutual selection». Sobre los papeles: «Individual nodes are not designated a priori as managers or contractors; these are only roles, and any node can take on either role dynamically during the course of problem solving». Y sobre el mecanismo: «available contractors evaluate task announcements made by several managers and submit bids on those for which they are suited. The managers evaluate the bids and award contracts to the nodes they determine to be most appropriate».

ALLAN conserva el primer rasgo entero —no hay orquestador central que reparta— y los papeles dinámicos: cualquier agente delega en cualquier otro. Lo amputado es el punto 3 y la mitad del 2 y del 4. El llamador lee la ficha del destino y adjudica; el destino no evalúa la tarea desde su propia perspectiva antes de aceptarla ni emite una puja. Se pierde la señal de autoevaluación del ejecutor, que es justo la información que el adjudicador no tiene. El único elemento del CNP que sobrevive intacto es el que Smith llama «a deadline for receiving bids»: el sobre lleva ExpiresAt (acl.go:131) y un mensaje vencido pasa a dead con un failure de razón expired (dispatcher.go:209), sin reintento.

Hay una frase de Smith que describe por qué este ensayo existe: «A high-level protocol assigns interpretations to the bit streams. It offers a structure that assists the system designer in deciding what the nodes should say to each other, rather than how to say it». Un sobre con performativa es eso; un mensaje de texto suelto entre agentes LLM es su ausencia.

Loop frente a spiral

El diseño rechaza el tope de profundidad con un argumento que conviene citar entero: «Un tope de profundidad castiga la topología (cadenas legítimas profundas, que deben poder desplegarse tanto como el problema requiera) para prevenir una patología semántica (el mismo trabajo volviendo al mismo agente). Son problemas distintos» (agent-communication-design.md:354-357).

Esa distinción tiene un precedente exacto que el diseño no cita, aunque cita el mismo documento por otro motivo. RFC 3261 define dos conceptos en su sección de definiciones. Loop: «A request that arrives at a proxy, is forwarded, and later arrives back at the same proxy. When it arrives the second time, its Request-URI is identical to the first time, and other header fields that affect proxy operation are unchanged, so that the proxy would make the same processing decision on the request it made the first time. Looped requests are errors […]». Spiral: «A spiral is a SIP request that is routed to a proxy, forwarded onwards, and arrives once again at that proxy, but this time differs in a way that will result in a different processing decision than the original request. […] A spiral is not an error condition, unlike a loop». La diferencia entre las dos no es topológica: es si la decisión de procesamiento cambia. Es el mismo teorema que §8.1 del diseño de ALLAN, enunciado veinte años antes para paquetes de señalización.

Max-Forwards, en cambio, «serves to limit the number of hops a request can make on the way to its destination» y «consists of an integer that is decremented by one at each hop». Un contador ciego no distingue loop de spiral. ALLAN lo sustituye por una ruta inspeccionable: []acl.Hop (acl.go:80-85), donde cada salto lleva agente, hop_id, conversación y huella de tarea. El hop_id coincide con el hop de metering, de modo que una entrada de genealogía y su entrada de ledger se unen por clave; con un contador eso no se puede hacer. La cadena se construye en un único sitio, AppendHop (:93-97), y en la ruta asíncrona el hop del destinatario se añade solo en el despachador (dispatcher.go:748), nunca en el emisor: un hop precocinado quedaría obsoleto tras un reintento, porque cada activación genera un hop_id nuevo.

El plegado es lo que hace que el fusible casi nunca haga falta. Cuando C delega en A y A ya tiene un hop en la genealogía de C, el motor no abre trabajo nuevo: convierte la delegación en una consulta lateral contra la conversación donde A ya está (tenant_mcp.go:325foldReentryinternal/app/fold.go:47). El run resultante se marca con acl.WithTerminalRun y el runtime de tools le oculta exactamente dos: tenant.agent/delegate y tenant.messages/post (internal/agents/tool_runtime.go:26-29). El subgrafo re-entrante es una hoja por construcción: no puede abrir aristas nuevas, así que no hay bucle posible sin prohibir ninguna topología. Y no hay deadlock porque TerminalQueryRaw abre un run independiente sobre el historial de la conversación y no toca el run vivo de A (fold.go:30-40): si A está bloqueado esperando a B, su historial sigue siendo legible. El fusible sobrevive como detector de anomalías —depth = len(genealogy) contra un umbral por defecto de 16 (internal/app/app.go:678)— y al saltar emite refuse más telemetría, nunca un error.

Entrega al menos una vez sobre trabajo con efectos

El buzón entrega al menos una vez. Helland describe el marco general: «the lower-level scale-aware portion hunts down the destination and delivers the message at-least-once», y de ahí «since any message ever sent may be delivered multiple times, we need a discipline in the application to cope with repeated messages». Su receta es que «the scale-agnostic (higher-level) portion of the application must implement mechanisms to ensure that the incoming message is idempotent», y para lo que no es naturalmente idempotente: «the entity must remember they have been processed. This knowledge is state».

El problema de ALLAN es que un turno de agente no es una función pura: consume tokens, gasta presupuesto del usuario raíz y puede haber enviado un correo antes de caerse. ALLAN no persigue exactly-once; estrecha la ventana y lo declara. La reclamación del mensaje es un compare-and-set en Lua (internal/tenant/mailbox_dfly.go:247): solo un mensaje cuyo estado sigue siendo pending puede reclamarse. Hay un lease de entrega: un mensaje delivered cuyo plazo vence vuelve a pending (:222-235), que es lo que recupera un run caído. Y hay memoria de duplicado: la conversación anota en su Meta el último sobre procesado y alreadyProcessed (dispatcher.go:710-719) descarta la redistribución. El comentario de esa función dice el compromiso sin adornos: «true exactly-once would need a distributed transaction this system doesn't have».

Dos cosas de esa memoria no coinciden con lo que Helland exige. La primera es que guarda un solo hueco —last_processed_envelope_id—, no un conjunto: si en la misma conversación se procesan A y luego B, y A reaparece por caducidad de lease, la comprobación falla y A se reejecuta. La segunda es más seria y es la parte de Helland que ALLAN no implementa: «in addition to remembering that a message has been processed, if a reply is required, the same reply must be returned. After all, we don't know if the original sender has received the reply or not». En dispatcher.go el mensaje se marca DeliveryProcessed en :479, y la respuesta al emisor se emite en :489. Entre esas dos líneas el mensaje ya no es recuperable —ListDeliverable solo devuelve pending o delivered con lease vencido—, de modo que una caída en esa ventana no produce redistribución sino una respuesta perdida en silencio. El comentario de alreadyProcessed describe el orden inverso al que el código ejecuta.

En la frontera, la fuerza desaparece

ALLAN expone y consume A2A, y conviene no dar por supuesto qué es A2A hoy. La especificación vigente, recuperada, es la 1.0.0, y su unidad no es el mensaje sino la tarea: «Task: The fundamental unit of work managed by A2A, identified by a unique ID. Tasks are stateful and progress through a defined lifecycle». Su propósito declarado es que los agentes trabajen juntos «without needing access to each other's internal state, memory, or tools». El descubrimiento pasa por una ficha en https://{server_domain}/.well-known/agent-card.json, y los nombres de operación de la ligadura JSON-RPC son SendMessage, GetTask, CancelTask y compañía —no las formas con barra (message/send, tasks/get) que circulan en material derivado de versiones 0.x—.

A2A no define un campo de fuerza ilocutiva. Define estados de tarea. No es un defecto: son capas distintas. Un estado pertenece al run del receptor; una performativa pertenece al mensaje, y sobrevive aunque no haya run. Pero tiene una consecuencia concreta. internal/a2a/a2a.go:9-16 define seis estados y ninguna performativa, y internal/a2a/server.go:190-215 traduce el estado del run a estado de tarea: failedfailed, blocked/waiting_humaninput-required, y todo lo demás → completed. Un refuse de política es un run que termina bien con el motivo en el texto de salida: cruza la frontera como completed. La garantía de que un rechazo llega como fuerza declarada, y no como prosa, es interna al tenant.

Hay además una divergencia de implementación que no es interpretación: la superficie de ALLAN es REST plano bajo /a2a/<tenant>/<agente>/{agentCard,sendMessage,getTask} (internal/a2a/dynamic_server.go:152-171), con .well-known/agent-card.json aceptado como alias de ruta pero no publicado en la raíz del dominio, y con formas de Task, Message y Part heredadas de un borrador anterior de la especificación. Coincide en nombres de operación con la 1.0.0 casi por accidente.

Invariantes, enunciados para poder romperlos

Cuatro afirmaciones falsables. Un test que las contradiga es un fallo, no una diferencia de criterio.

Ningún punto de rechazo de gobierno devuelve un error de Go. Se falsifica encontrando una compuerta que devuelva error no nulo por una decisión de política, compromiso duplicado o fusible de profundidad.

Un run terminal de plegado no puede abrir aristas nuevas. Se falsifica encontrando un camino por el que un run marcado con WithTerminalRun alcance agent/delegate o messages/post.

La identidad del emisor procede del sobre y nunca del texto: un cuerpo ajeno no puede producir un bloque [Interlocutor] creíble. Se falsifica encontrando una ruta que concatene texto de agente a un prompt sin pasar por SanitizeBody.

Un hop de genealogía se une con su entrada de ledger por hop_id. Se falsifica encontrando un camino que cree un hop de metering sin registrarlo en la genealogía, o al revés.

Lo que está roto, sin terminar o sin evidencia

El tercer invariante ya está falsificado en su forma fuerte. SanitizeBody se invoca en exactamente dos sitios de producción, internal/app/conversations.go:39 y internal/app/fold.go:55. Las conversaciones de grupo no lo llaman en ninguna parte, pese a ser el escenario donde más cuerpos ajenos se concatenan y donde los glifos ⟦⟧ son el mecanismo de atribución de hablante. El saneo existe y la superficie que más lo necesita no lo usa.

La tensión entre el diseño y el gating real existe, pero apunta al lado contrario del que parece. El diseño clasifica agent/delegate como «default-safe en v1» porque «el gate real es la política» (§9.2 y §15). En el código, policy.RiskForToolName mapea todo prefijo agent/ a RiskGuarded (internal/policy/policy.go:119) y normalizeToolName (:130-136) elimina el prefijo tenant. antes de decidir, de modo que con los valores compilados —umbral RiskCaution— la llamada produciría DecisionRequiresApproval y el runtime devolvería agentLoopApprovalError (internal/agents/tool_runtime.go:300-323): un error de Go que parkea el run.

No es lo que ocurre en el despliegue. El motor no lee la política de os.Getenv sino de su configuración en capas —policy.DefaultFromLookup(runtimeConfig.Get) (internal/app/app.go:780), alimentada por runtimeConfig.LoadDotEnv sobre el directorio de configuración del motor (:446)—, y ese directorio viaja dentro de la imagen: el Dockerfile hace COPY config /etc/allan/engine-config y fija ALLAN_ENGINE_CONFIG_DIR. Ahí, Platform Server/config/.env:16-17 declara ALLAN_POLICY_ALLOW_AGENT_TOOLS=true y ALLAN_POLICY_ALLOW_LEVEL=2. Cada una de las dos, por separado, basta para que delegar pase sin aprobación: la primera reclasifica el prefijo agent/ a RiskCaution vía ToolRiskPrefixes (policy.go:46-48, :95-97), y la segunda sube el umbral a RiskGuarded, que Evaluate compara con desigualdad estricta (:66-80). Ni docker-compose.yml ni Platform Server/.env las contradicen, y OverlayOSEnviron solo pisa con variables no vacías.

El problema real, entonces, no es que el acto de delegar esté tras una compuerta que devuelve error, sino que la imagen publicada desarma la compuerta de todo lo que vale RiskGuardedexecute/, browser/, mail/ y agent/— con dos líneas de un fichero de configuración que casi nadie mira. La regla de oro de los actos de habla se sostiene por omisión del gate, no por diseño del gate: si alguien bajara ALLAN_POLICY_ALLOW_LEVEL a 1, delegar volvería a ser un error de Go.

El PDP existe y está vacío. commpolicy.FromEnv (:273-279) solo admite allow_all y tumba el arranque ante cualquier otro valor —fail-closed en configuración—, mientras que un error de evaluación permite —fail-open en ejecución—. El vocabulario de obligaciones (require_approval, budget_cap, redact, audit_enhanced) está declarado en commpolicy.go:39-42 y ninguna Obligation se emite jamás. Es una costura cableada sin nada al otro lado; el diseño lo declara así y conviene no confundir la costura con la política.

El registro de compromisos es check-then-act sin CAS. DragonflyRunStore.RecordCommitment (run_store_dfly.go:1683-1702) hace un SetJSON incondicional, de modo que dos aceptaciones concurrentes de la misma (root_id, agent, task_fp) dejan ganar al segundo escritor sin señal. La red existe y tiene un agujero del tamaño de la ventana entre consulta y escritura.

El plegado no cubre el caso en que el ancestro necesita preguntar. TerminalQueryRaw lo dice en su propio comentario (fold.go:42-46): un destino que se pare a pedir aclaración hace fallar la consulta en vez de parkearla.

De la observabilidad prometida faltan piezas que el diseño declaraba exigibles «desde el primer día» (§13): el evento mailbox.dead_letter no existe en el repositorio, y tampoco GET /v1/conversations/{id}; sí existen los eventos conversation.*. max_concurrent_conversations se parsea (internal/artifacts/manifest.go:212) y nadie lo lee: un agente puede declarar un tope de conversaciones simultáneas y tener las que sean.

Por último, un caso que ilustra por qué este ensayo se escribió con la regla de cita recuperada. El comentario de internal/groupsessions/router.go:42-46 atribuye a AutoGen «the finding this design explicitly adopts, that role+context framing outperforms task-only framing for speaker selection». Recuperé el artículo de AutoGen y no pude confirmar ese resultado: el resumen no lo enuncia y no logré extraer texto utilizable del PDF completo. Puede estar en el artículo y puede no estar; hoy es una atribución sin respaldo verificado dentro del código, y quien la lea debería tratarla como tal hasta comprobarla.

Referencias

Austin, J. L. (1962). How to Do Things with Words. The William James Lectures delivered at Harvard University in 1955. 2.ª ed., Oxford University Press. Copia recuperada en https://coehuman.uodiyala.edu.iq/uploads/Coehuman library pdf/English libraryكتب الانكليزي/linguistics/AUSTIN._How_To_Do_Things_With_Words.pdf

«In these examples it seems clear that to utter the sentence (in, of course, the appropriate circumstances) is not to describe my doing of what I should be said in so uttering to be doing or to state that I am doing it: it is to do it. None of the utterances cited is either true or false […].» (p. 6) (La frase continúa «: I assert this as obvious and do not argue it»; la elisión, antes sin marcar, queda ahora señalada.)

«What are we to call a sentence or an utterance of this type? I propose to call it a performative sentence or a performative utterance, or, for short, "a performative". […] The name is derived, of course, from "perform", the usual verb with the noun "action": it indicates that the issuing of the utterance is the performing of an action.» (pp. 6-7)

«In no case do we say that the utterance was false but rather that the utterance —or rather the act, e.g. the promise— was void, or given in bad faith, or not implemented, or the like.» (pp. 10-11)

Searle, J. R. (1969, 1975). Speech Acts y «A Taxonomy of Illocutionary Acts». NO VERIFICADA. No se cita ninguna frase suya en el cuerpo. Las dos copias abiertas localizadas —conservancy.umn.edu y thatmarcusfamily.org— devolvieron HTTP 403 y error de certificado respectivamente; el resto de resultados eran plataformas de pago o agregadores. Su aportación se cita a través de Singh (1999) y de la Stanford Encyclopedia of Philosophy.

Green, M. (2007, rev. 2020). «Speech Acts», Stanford Encyclopedia of Philosophy. https://plato.stanford.edu/entries/speech-acts/

«a performative formula such as "I promise to…" is an "illocutionary force indicator" in the sense that it is a device whose role is to make explicit the force of the speaker's utterance.»

FIPA (2002). FIPA ACL Message Structure Specification, SC00061G, estándar, 2002/12/03. Copia recuperada en https://ppgia.pucpr.br/~fabricio/ftp/Aulas/Mestrado/AS/Aula3/SC00061G_FIPA_ACL.pdf

«the only parameter that is mandatory in all ACL messages is the performative, although it is expected that most ACL messages will also contain sender, receiver and content parameters.» (líneas 74-76)

performative: «Denotes the type of the communicative act of the ACL message.» (§2.1.1)

«developers are advised that employing ACL without the framework of an interaction protocol (and thus directly using the ACL semantics to control the agent's generation and interpretation of ACL messages) is an extremely ambitious undertaking.» (§2.5.1)

FIPA (2001). FIPA Communicative Act Library Specification, XC00037H, experimental, 2001/08/10. Copia recuperada en https://jmvidal.cse.sc.edu/library/XC00037H.pdf. Nota: la versión estándar posterior, SC00037J, no pudo recuperarse (fipa.org devuelve HTTP 403 a peticiones automatizadas); se cita la experimental, que la precede.

«A formal model, written in SL, of the act's semantics, its formal preconditions, and its rational effects is required.» (§2.3)

Refuse: «The action of refusing to perform a given action, and explaining the reason for the refusal. […] The agent receiving a refuse act is entitled to believe that: the action has not been done, the action is not feasible (from the point of view of the sender of the refusal) […] However, a cooperative agent will attempt to explain the refusal constructively.» (§3.17)

Failure: «The action of telling another agent that an action was attempted but the attempt failed.» (§3.7)

Cfp: «CFP is a general-purpose action to initiate a negotiation process by making a call for proposals to perform the given action.» (§3.4)

Singh, M. P. (1999). «A Social Semantics for Agent Communication Languages». https://www.csc2.ncsu.edu/faculty/mpsingh/papers/mas/socacl-fipa.pdf

«Previous semantics have largely been mentalistic in their orientation and are based solely on the beliefs and intentions of the participating agents. Such semantics are not suitable for most multiagent applications, which involve autonomous and heterogeneous agents, whose beliefs and intentions cannot be uniformly determined.» (resumen)

«An illocution is the core component of a communication and corresponds to what the communication is meant to accomplish independent both of how the communication is physically carried out (the locution) and the effect it has on a listener (the perlocution).» (§2)

«the mental concepts cannot be verified without access to the internal construction of the agents. […] The above evidence supports the conclusion that a purely mentalistic semantics of an ACL cannot be a normative requirement on agents or their designers.» (§2.1)

«A commitment involves three agents: the debtor (who makes it), the creditor (to whom it is made), and the context (the containing multiagent system in the scope of which it is made).» (§3.1)

Smith, R. G. (1980). «The Contract Net Protocol: High-Level Communication and Control in a Distributed Problem Solver», IEEE Transactions on Computers C-29(12):1104-1113. https://www.reidgsmith.com/The_Contract_Net_Protocol_Dec-1980.pdf

«For our purposes, negotiation has four important components: 1) it is a local process that does not involve centralized control, 2) there is a two-way exchange of information, 3) each party to the negotiation evaluates the information from its own perspective, and 4) final agreement is achieved by mutual selection.» (p. 1105)

«Individual nodes are not designated a priori as managers or contractors; these are only roles, and any node can take on either role dynamically during the course of problem solving.» (p. 1105)

«available contractors evaluate task announcements made by several managers and submit bids on those for which they are suited. The managers evaluate the bids and award contracts to the nodes they determine to be most appropriate.» (p. 1105)

«The expiration time is a deadline for receiving bids.» (p. 1106)

«A high-level protocol assigns interpretations to the bit streams. It offers a structure that assists the system designer in deciding what the nodes should say to each other, rather than how to say it.» (p. 1104)

Rosenberg, J. et al. (2002). RFC 3261: SIP: Session Initiation Protocol. https://www.rfc-editor.org/rfc/rfc3261.txt

Loop: «A request that arrives at a proxy, is forwarded, and later arrives back at the same proxy. When it arrives the second time, its Request-URI is identical to the first time, and other header fields that affect proxy operation are unchanged, so that the proxy would make the same processing decision on the request it made the first time. Looped requests are errors […].» (§6)

Spiral: «A spiral is a SIP request that is routed to a proxy, forwarded onwards, and arrives once again at that proxy, but this time differs in a way that will result in a different processing decision than the original request. […] A spiral is not an error condition, unlike a loop.» (§6)

«Max-Forwards serves to limit the number of hops a request can make on the way to its destination. It consists of an integer that is decremented by one at each hop.» (§4, «Overview of Operation»)

Corrección de esta revisión: una versión anterior situaba esta última frase en §20.22. Es falso: §20.22 dice otra cosa —«The Max-Forwards header field must be used with any SIP method to limit the number of proxies or gateways that can forward the request to the next downstream server»— y §8.1.1.6 la enuncia con otra redacción («…a request can transit on the way to its destination»). La frase citada es literal, pero pertenece a §4.

Helland, P. (2007). «Life beyond Distributed Transactions: an Apostate's Opinion», CIDR 2007. https://www.cidrdb.org/cidr2007/papers/cidr07p15.pdf

«the lower-level scale-aware portion hunts down the destination and delivers the message at-least-once.» (p. 137)

«Since any message ever sent may be delivered multiple times, we need a discipline in the application to cope with repeated messages. […] Typically, the scale-agnostic (higher-level) portion of the application must implement mechanisms to ensure that the incoming message is idempotent.» (p. 138)

«To ensure the idempotent processing of messages that are not naturally idempotent, the entity must remember they have been processed. This knowledge is state. […] In addition to remembering that a message has been processed, if a reply is required, the same reply must be returned. After all, we don't know if the original sender has received the reply or not.» (p. 139)

A2A Project (2026). A2A Protocol Specification, versión 1.0.0. https://a2a-protocol.org/latest/specification/ y https://raw.githubusercontent.com/a2aproject/A2A/main/docs/specification.md

«Task: The fundamental unit of work managed by A2A, identified by a unique ID. Tasks are stateful and progress through a defined lifecycle.»

«work together on complex user requests without needing access to each other's internal state, memory, or tools

«Well-Known URI: Accessing https://{server_domain}/.well-known/agent-card.json»

Nombres de método de la ligadura JSON-RPC: SendMessage, SendStreamingMessage, GetTask, ListTasks, CancelTask, SubscribeToTask, GetExtendedAgentCard.

Nota de método: la afirmación de que A2A no define un campo de fuerza ilocutiva es una lectura de las definiciones recuperadas —Message se caracteriza por su rol y sus Part, y el ciclo de vida vive en Task—, no una frase de la especificación que lo declare.

Cemri, M. et al. (2025). «Why Do Multi-Agent LLM Systems Fail?» arXiv:2503.13657. https://arxiv.org/abs/2503.13657

«This process identifies 14 unique modes, clustered into 3 categories: (i) system design issues, (ii) inter-agent misalignment, and (iii) task verification.» […] «high inter-annotator agreement (kappa = 0.88)»

Advertencia: el porcentaje de fallos atribuido a la primera categoría, que circula en resúmenes secundarios, no aparece en el resumen recuperado y por eso no se usa en este texto.

Wu, Q. et al. (2023). «AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation». arXiv:2308.08155. https://arxiv.org/abs/2308.08155 NO VERIFICADA para el uso que le da el código. El resumen no menciona selección de hablante ni encuadre por rol frente a encuadre por tarea, y no logré extraer texto utilizable del PDF completo ni de una versión HTML. La atribución que hace internal/groupsessions/router.go:42-46 queda pendiente de comprobación.

¿Le ha resultado útil esta página?

Enviar comentarios

Este artículo se publica desde allan-docs. El mismo texto se sirve a los agentes a través del servidor MCP.