Skip to content

Brainstem 1.4.0

Choose a tag to compare

@jurrebuunk jurrebuunk released this 02 Nov 14:33
· 34 commits to main since this release
54bb683

Small agent tasks and the groundwork for multi-core: a generic agentOS runner for cheap, bounded agent work, destinations that hand results back to the core, a log file input, telemetry and a core registry that identify cores and destinations, and a Web UI flow built on them.

Upgrading:

  • Migrations 0003_cores and 0004_node_stats run automatically on start.
  • The Docker image omits optional dependencies (the agentOS VM runtime). Build with --build-arg INSTALL_OPTIONAL=true to use agentos-runner in Docker.
  • Handed-off observations no longer pretend to come from an input named destination:<id>: their input is empty and origin names the destination. Consumers of telemetry or output envelopes that relied on that input id should read origin.
  • Web UI destination nodes show delivered instead of outputs. Per-node totals start counting from the upgrade; earlier history isn't backfilled.

Changes:

  • Per-node totals: the API counts polls, observations, decisions, completed deliveries, handoffs, errors and the last event time per flow node in a new stat_nodes table (migration 0004_node_stats) as telemetry arrives, and returns them as nodes in GET /api/stats. The Flow page shows these totals, so node counters no longer reset when events leave the 2000-event window. Destination nodes now show delivered (completed deliveries) instead of outputs, which only ever counted the HTTP JSON destination's output events.

  • agentos-runner fails fast and clearly: a missing model API key is reported before a VM boots, and a sidecar that can't start (EPIPE and similar) becomes a permanent, readable error ("the agentOS sidecar could not start … on NixOS enable programs.nix-ld") instead of retried pipe errors. On NixOS, nix-ld is now the recommended setup; the real-VM test runs whenever nix-ld (or AGENTOS_SIDECAR_BIN) is available.

  • Fix: npm run check now fails on syntax errors (it used find -exec, which ignored them) and also checks brainstem-api.mjs and the Web UI flow model.

  • Web UI Flow page brought up to date with the runtime: structure from /api/topology (one node per configured id, so tasks of the same plugin are no longer merged), a core pool node and a Cores panel from the core registry, handoffs shown only while they happen (a short-lived "handing off" pill node linked to the destination) instead of fake destination:<id> input nodes, and an inspector that matches destinations by id and shows each decision's origin and core. Falls back to snapshot events against an older backend. The graph logic moved into a pure, unit-tested web/src/flow/model.js.

  • Core registry and GET /api/topology: each runtime registers in a new cores table (migration 0003_cores) with its role, queues, version and loaded topology, heartbeats every runtime.cores.heartbeatMs (default 10 s) and marks itself stopped on shutdown. Cores that miss 3 heartbeats are reported as lost, and rows unseen for 24 h are pruned. /api/topology serves the cores plus the inputs and destinations (with ids) from the freshest running core, and flags running cores that loaded different configs. The Web UI no longer has to derive structure from snapshot events.

  • Telemetry identity fields for multi-core and handoffs: every event carries coreId (runtime.coreId / BRAINSTEM_CORE_ID, also the job worker id); decisions and output envelopes carry origin ({ kind: "input", id } or { kind: "destination", id, depth, lineage }); the snapshot and destination plugin logs carry destination ids; a new brainstem.destination.emitted event marks each handoff. A handed-off observation no longer pretends to come from an input named destination:<id>. Its input is empty and origin names the destination. Jobs queued by the previous version are still understood.

  • Destinations can hand observations back to the core with ctx.emit(observation). They are enqueued in the same transaction that marks the delivery delivered, never routed back to a destination already in their chain, and limited by runtime.handoff.maxDepth (default 2) and maxPerDelivery (default 5).

  • agentos-runner gains handoff: a successful run's report becomes an agent_report observation (with facts.minimum_decision) that Matrix or a bigger agent can pick up.

  • New log-file input: watches a log file and emits new matching lines (default ERROR|FATAL|CRITICAL|PANIC) as one bounded observation per poll, with offset checkpoints and truncation/rotation handling.

  • Fix: the agentOS prompt and docs used observation.summary, which doesn't exist; they now use title, message and source.type/source.name.

  • New agentos-runner destination: runs a configured task in a Rivet agentOS VM for each matching decision. One plugin serves many tasks; each destination entry has its own filters, command (or agent prompt), network allowlist, read-only mounts, env, and host-side tools. Tools are validated, limited by maxCalls, can be required, and are replayed instead of repeated when a delivery is retried. runOnce: "revision" skips re-emitted observations by default. See docs/plugins/agentos-runner.md.

  • prompt tasks run a host-side agent loop against any OpenAI-compatible endpoint (model: { baseUrl, name, apiKeyEnv }). The model gets run_command (inside the VM) plus the entry's tools. Every run is bounded by limits (turns, output tokens, commands, tool output size, prompt size, conversation size, request spacing), duplicate calls are refused, and a delivery that already talked to the model fails permanently instead of being retried (maxAgentAttempts: 1).

  • @rivet-dev/agentos-core is an optional dependency. The Docker image omits optional dependencies unless built with --build-arg INSTALL_OPTIONAL=true.