feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out: los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms + E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client). - go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths relativos reajustados a la nueva ubicacion dentro de fn_registry). - app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales. - modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports). agents_and_robots queda archivado como museo de la era Matrix.
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
name: unibots
|
||||
lang: go
|
||||
domain: infra
|
||||
version: 0.1.0
|
||||
description: "Plataforma de bots que consumen el bus unibus; primer bot = eco (bot sin LLM que demuestra los dos patrones de conversación del bus)."
|
||||
tags: [bots, messaging, unibus-client]
|
||||
version: 0.2.0
|
||||
description: "Plataforma de bots en Go (core puro + shell impuro: LLM, memoria, tools, crons, dashboard TUI) que hablan por el bus unibus. Migrada desde agents_and_robots con Matrix-out: el transporte ya no es Matrix sino unibus (rooms + E2E)."
|
||||
tags: [bots, messaging, unibus-client, llm, service]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
framework: ""
|
||||
entry_point: "cmd/echobot"
|
||||
entry_point: "cmd/dashboard"
|
||||
dir_path: "projects/message_bus/apps/unibots"
|
||||
repo_url: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/unibots"
|
||||
e2e_checks:
|
||||
@@ -26,108 +26,128 @@ e2e_checks:
|
||||
## Qué es
|
||||
|
||||
`unibots` es la plataforma de **bots** que consumen el bus de mensajería
|
||||
[`unibus`](../unibus/). Un **bot** es todo peer automatizado del bus, con o sin
|
||||
LLM. Un **bot agente** es un bot que contiene un LLM (no aplica todavía aquí). El
|
||||
término único en código, nombres y docs es **bot**.
|
||||
[`unibus`](../unibus/). Es la evolución de `agents_and_robots`: el mismo cerebro
|
||||
(personalidad, reglas de decisión, memoria, tools, crons, LLM) pero con el
|
||||
**transporte migrado de Matrix a unibus** (operación "Matrix-out", 07/06/2026).
|
||||
|
||||
El primer bot es el **bot eco** (`cmd/echobot`): un bot **sin LLM** que se une al
|
||||
bus y devuelve cada mensaje prefijado con `"echo: "`. Existe para demostrar de
|
||||
forma autónoma los **dos patrones de conversación** que el bus expone, sin
|
||||
depender de ningún modelo:
|
||||
Un **bot** es todo peer automatizado del bus, con o sin LLM. Un **bot agente** es
|
||||
un bot que contiene un LLM. El término único en código, nombres y docs es **bot**.
|
||||
Ver [[convencion-bot-vs-agente]].
|
||||
|
||||
| Patrón | Subject | Cómo | Pareja |
|
||||
|---|---|---|---|
|
||||
| **Chat** (bot↔humano) | `room.echo` (cleartext, `room.ModeNATS`) | `Subscribe` a la room + `Publish` la respuesta | cualquier peer en el mismo subject |
|
||||
| **RPC** (bot↔proceso) | `rpc.echo` | request/reply de NATS (`Client.Reply` registra el responder) | cualquier proceso que haga `Client.Request` |
|
||||
### Arquitectura
|
||||
|
||||
Cada bot combina un **core puro** (`pkg/`: transformaciones, reglas de decisión,
|
||||
personalidad — determinista, sin I/O) con un **shell impuro** (`shell/`: LLM, SSH,
|
||||
base de datos, tools, side effects). El acoplamiento a Matrix se eliminó de raíz;
|
||||
en su lugar hay un **seam neutral**:
|
||||
|
||||
- `pkg/transport` — interfaz `Transport` + tipo `InboundMessage` agnósticos del
|
||||
transporte. El core (`agents/handler.go::handleInbound`) no sabe si detrás hay
|
||||
Matrix, unibus o un mock.
|
||||
- `shell/transportunibus/` — implementación de `Transport` sobre la librería
|
||||
cliente de unibus (`github.com/enmanuel/unibus/pkg/client`). Modelo **"todo son
|
||||
rooms"** + **E2E** (`room.ModeMatrix`): el bot descubre las rooms a las que
|
||||
pertenece por polling de `client.ListMyRooms()` (endpoint `GET
|
||||
/members/{endpoint}/rooms` de unibus ≥ v0.4.0), hace `Join` + `Subscribe`,
|
||||
descifra y responde en la misma room. `busSender` adapta runner / cron / tools
|
||||
a ese transporte.
|
||||
|
||||
### Comandos (`cmd/`)
|
||||
|
||||
| Comando | Qué hace |
|
||||
|---|---|
|
||||
| `cmd/dashboard` | TUI interactiva de gestión de bots (entry point principal) |
|
||||
| `cmd/launcher` | Supervisa y relanza los bots cuando salen sin cancelación |
|
||||
| `cmd/agentctl` | CLI de control: arrancar/parar/estado de bots, HTTP API + SSE |
|
||||
| `cmd/register` | Alta de un bot nuevo |
|
||||
|
||||
### Configuración de un bot
|
||||
|
||||
Cada bot declara un bloque `bus:` (sustituye al antiguo `matrix:`):
|
||||
|
||||
```yaml
|
||||
bus:
|
||||
nats_url: nats://127.0.0.1:4250
|
||||
ctrl_url: http://127.0.0.1:8470
|
||||
identity_path: local_files/<bot>.id
|
||||
handle: <nombre-publico>
|
||||
command_prefix: "!"
|
||||
threads: true
|
||||
```
|
||||
|
||||
`unibots` es **código de aplicación**, no funciones del registry: orquesta la
|
||||
librería cliente de `unibus` (`pkg/client`) y no reimplementa nada. Por eso
|
||||
librería cliente de `unibus` y no reimplementa protocolo ni cripto. Por eso
|
||||
`uses_functions` está vacío — el crypto/transporte lo aporta `unibus`, que a su
|
||||
vez importa las primitivas del registry.
|
||||
vez importa las primitivas del dominio `cybersecurity` del registry.
|
||||
|
||||
Referencia: [[convencion-bot-vs-agente]]. Consumidor de [[unibus]].
|
||||
> Nota de módulo Go: el `module` interno sigue siendo `github.com/enmanuel/agents`
|
||||
> (heredado de agents_and_robots) para no reescribir ~100 imports durante el move.
|
||||
> El repositorio Gitea es `dataforge/unibots`. El desajuste nombre-módulo/repo es
|
||||
> cosmético y no afecta al build; renombrar el módulo a `github.com/enmanuel/unibots`
|
||||
> queda como tarea futura opcional.
|
||||
|
||||
## Ejemplo
|
||||
|
||||
Lanzar el echobot contra un `membershipd` corriendo (NATS embebido en `:4250`,
|
||||
HTTP en `:8470`, los defaults productivos de unibus):
|
||||
Levantar el bus y lanzar la plataforma de bots contra él:
|
||||
|
||||
```bash
|
||||
# 1. Bus de membresía/claves (NATS embebido :4250, control plane HTTP :8470)
|
||||
cd projects/message_bus/apps/unibus
|
||||
|
||||
# 1. Bus de membresía/claves (NATS embebido + control plane HTTP)
|
||||
go run ./cmd/membershipd
|
||||
|
||||
# 2. En otra terminal: el bot eco (defaults: nats://127.0.0.1:4250, http://127.0.0.1:8470)
|
||||
cd ../unibots
|
||||
go run ./cmd/echobot
|
||||
# Loguea al arrancar: endpoint id, subjects de chat y rpc, y a qué bus apunta.
|
||||
```
|
||||
# 2. En otra terminal: la TUI de gestión de bots
|
||||
cd projects/message_bus/apps/unibots
|
||||
go run ./cmd/dashboard
|
||||
|
||||
Probarlo desde otra terminal sin escribir más Go:
|
||||
|
||||
```bash
|
||||
# Modo RPC (bot<->proceso) con la CLI de NATS contra el mismo NATS embebido:
|
||||
# nats --server nats://127.0.0.1:4250 request rpc.echo "ping"
|
||||
# -> recibe "echo: ping"
|
||||
|
||||
# Modo chat (bot<->humano): cualquier peer que publique en el subject room.echo
|
||||
# (p.ej. el `chat` de unibus apuntando a ese subject, o un cliente propio) recibe
|
||||
# de vuelta "echo: <su mensaje>".
|
||||
```
|
||||
|
||||
Apuntar a un bus distinto:
|
||||
|
||||
```bash
|
||||
go run ./cmd/echobot \
|
||||
--nats-url nats://mi-host:4222 \
|
||||
--ctrl-url http://mi-host:8470 \
|
||||
--room-subject room.demo \
|
||||
--rpc-subject rpc.demo
|
||||
# Alternativa headless: supervisor que mantiene los bots vivos
|
||||
go run ./cmd/launcher
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
- Cuando quieras **validar que un bus unibus está vivo** end-to-end (chat y RPC)
|
||||
sin montar un bot agente con LLM.
|
||||
- Como **plantilla mínima** para escribir un bot nuevo: copia `cmd/echobot`,
|
||||
cambia la lógica del handler (en vez de `"echo: " + body`, llama a tu servicio,
|
||||
base de datos o, más adelante, a un LLM para convertirlo en bot agente).
|
||||
- Para **demostrar los dos patrones** del bus (chat por room cleartext vs RPC
|
||||
request/reply) a alguien que aprende la arquitectura.
|
||||
- Cuando quieras **correr bots autónomos** (con o sin LLM) que conversen por el
|
||||
bus unibus en vez de Matrix.
|
||||
- Como **plataforma destino del ecosistema de bots**: a partir de ahora se trabaja
|
||||
aquí, no en `agents_and_robots` (archivado como museo de la era Matrix).
|
||||
- Para añadir un **bot nuevo**: `cmd/register` + un bloque `bus:` en su config; el
|
||||
core es transport-agnóstico, así que solo escribes la lógica del handler (regla
|
||||
`.claude/rules/create_agent.md`).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Guard anti-bucle (crítico).** El handler de chat ignora los mensajes cuyo
|
||||
`frame.Frame.Sender == c.Endpoint().ID`. Sin este guard, el bot se haría eco de
|
||||
su propio `"echo: ..."` indefinidamente (y dos echobots en el mismo subject
|
||||
entrarían en un bucle infinito). El test `TestChatEcho` verifica que nunca
|
||||
aparece `"echo: echo: hola"`.
|
||||
- **Cleartext comparte subject, no room id.** El bot usa `room.ModeNATS`
|
||||
(cleartext, efímero, sin firma). NATS enruta por **subject**, así que el bot
|
||||
conversa con cualquier peer en el mismo subject aunque cada uno tenga su propio
|
||||
`room_id` (mismo patrón que el worker/chat de unibus). No hay "unirse a una room
|
||||
por nombre": cada `CreateRoom` produce un ULID nuevo mapeado al subject.
|
||||
- **Modo RPC sí está soportado.** La librería de unibus expone request/reply:
|
||||
`Client.Request(subject, body, timeout)` y `Client.Reply(subject, handler)`
|
||||
(cleartext v1, sobre `rpc.*`). El echobot registra un responder con `Reply`. No
|
||||
hubo que omitir ni inventar nada en unibus.
|
||||
- **Identidad = secreto crítico.** `local_files/echobot.id` contiene las claves
|
||||
privadas (Ed25519 + X25519), se escribe 0600. Perderlo no rompe el eco (es
|
||||
cleartext) pero cambia la identidad del bot. Está gitignorado.
|
||||
- **Build sin CGO.** Igual que unibus: `CGO_ENABLED=0`, sin `fts5` ni `gcc`. El
|
||||
crypto del registry (`cybersecurity`) y el driver SQLite pure-Go compilan
|
||||
limpio.
|
||||
- **Los tests usan puertos propios aislados.** El test de integración levanta un
|
||||
`membershipd` con NATS embebido en puertos libres (`:0`) bajo `t.TempDir()`,
|
||||
nunca en `8470/4250` ni en los del playground del usuario; todo se limpia por
|
||||
handle vía `t.Cleanup`.
|
||||
- **Matrix-out total.** Se borraron `shell/matrix/`, `tools/matrix/`, `cmd/verify/`
|
||||
(cross-signing) y la dependencia `maunium.net/go/mautrix`. El build es
|
||||
`CGO_ENABLED=0 go build ./...` a secas, sin `-tags goolm` ni `libolm`. Presencia,
|
||||
typing y avatares desaparecieron: no existen en unibus.
|
||||
- **Imports relativos a unibus y al registry.** `go.mod` usa `replace
|
||||
github.com/enmanuel/unibus => ../unibus` y `replace fn-registry => ../../../..`.
|
||||
Ambos son paths relativos a la ubicación de la app: si se mueve, hay que
|
||||
reajustarlos o el build rompe. (Se ajustaron al traer la app desde
|
||||
`~/DataProyects/Github/agents_and_robots`.)
|
||||
- **Identidad = secreto crítico.** Cada `local_files/<bot>.id` lleva las claves
|
||||
privadas del bot (Ed25519 + X25519), 0600, gitignorado. Perderlo cambia la
|
||||
identidad pública del bot en el bus.
|
||||
- **El bot descubre rooms por polling.** No hay push de invitaciones: el transporte
|
||||
unibus hace polling de `ListMyRooms()`. La latencia de incorporación a una room
|
||||
≈ el intervalo de polling.
|
||||
- **Build sin CGO.** Crypto del registry (`cybersecurity`) + driver SQLite pure-Go
|
||||
(`modernc.org/sqlite`) compilan limpio sin `gcc`.
|
||||
|
||||
## Convención de subjects (heredada de unibus)
|
||||
## Gaps abiertos (heredados del Matrix-out)
|
||||
|
||||
```
|
||||
proc.<svc>.<canal> telemetría/coordinación de procesos
|
||||
rpc.<svc> request/reply (rpc.echo)
|
||||
room.<grupo> chat humano/grupo (room.echo)
|
||||
agent.<nombre>.{in,out} inbox/outbox de bot agente (futuro)
|
||||
```
|
||||
- **Directorio de bots** (handle → endpoint público) para que un frontend pueda
|
||||
invitar a un bot por nombre.
|
||||
- **Orquestador multi-bot** aparcado: existía atado a mautrix, aún sin recablear al
|
||||
bus.
|
||||
- **Docs internas desactualizadas**: `README.md` y `.claude/CLAUDE.md` todavía
|
||||
describen la era Matrix (homeserver, `-tags goolm`, `matrix:`). Pendiente de
|
||||
reescritura para reflejar el transporte unibus.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
- v0.2.0 (2026-06-07) — la app deja de ser el scaffold del echobot y pasa a ser la
|
||||
plataforma completa de bots importada desde `agents_and_robots` con el transporte
|
||||
migrado a unibus (Matrix-out). El módulo Go conserva el path
|
||||
`github.com/enmanuel/agents`; los `replace` de unibus y fn-registry se reajustaron
|
||||
a la nueva ubicación. `agents_and_robots` queda archivado; el trabajo activo
|
||||
continúa aquí.
|
||||
|
||||
Reference in New Issue
Block a user