UNPKG

@essentialai/cogent-bridge

Version:

Cogent Bridge — cross-agent comms for Claude Code, OpenAI Codex and Slack. Codex users: install with `curl -fsSL https://cogent.tools/install.sh | sh`, then start with `cogent-codex` for real-time peer wake.

181 lines • 10 kB
// --------------------------------------------------------------------------- // PEER PRESENCE — what state this agent is in on its channel, why, and getting // it back to `online` without anyone being told to restart something. // // ── THE VOCABULARY, taken from what this codebase already says ────────────── // "local" COGENT_LOCAL / no relay. Presence is not a concept here. // "deferred" EXISTING TERM (backend-provider.ts): cloud-CONFIGURED but never joined — // there are no stored credentials for this working directory. Nothing to // restore; the agent must join a channel first. // "offline" Stored credentials name a peer for this working directory, but this // process has not registered it. The bridge is running; the AGENT IS NOT // IN THE CHANNEL. Other peers see it as absent and cannot address it. // "online" Registered. The channel lists this agent and messages reach it. // // ── HOW AN AGENT ENDS UP `offline` — the mechanism, stated plainly ────────── // Registration is an explicit act: something must call `cogent_register_peer`. The // bridge starting does NOT register — it only publishes the tools. So every time an // agent session starts, the bridge comes up holding valid credentials while the agent // is absent from its own channel, and stays that way until the agent calls the tool. // If the agent never calls it — it forgot, it crashed first, the session was resumed // from a transcript that had already registered — the peer is never (re-)created, and // the relay's stale sweep eventually deletes the entry left over from last time. // // That state used to be both SILENT and SELF-PERPETUATING, because every repair in // this client sat behind a successful registration: // - announceBridge() (auto-relay) — written at register time // - reapStaleBridges() (auto-relay) — "only after a peer is genuinely registered" // - triggerReRegistration()(startup) — reads in-memory state, null in a fresh process // So when registration was the thing that did not happen, nothing recovered and nothing // cleaned up. Measured 2026-09-14 on one checkout: 18 live bridges at 3.23.9, last // successful register five days earlier, the peer absent from a healthy Team channel // whose two other agents were present and waiting on it. // // ── WHY RESTORING IT IS SAFE ──────────────────────────────────────────────── // - Credentials are keyed PER WORKING DIRECTORY // (~/.cogent/credentials/<sha256(cwd)[..16]>.json, commit f758d8ee). Reading this // directory's own file cannot inherit another project's session — that was the // LEGACY GLOBAL file, which is only ever `fs.access`'d for a warning and never read. // - The agent-session id need not be correct here: auto-relay re-resolves it on every // wake (auto-relay.ts, "Only adopt a resolved id") and register-peer itself falls // back to the channel session id on an unresolved resolution. // - `peerId` in the credential is the CONSENT SIGNAL. create/join write credentials // without one, and deregister clears it, so a deliberate departure is never undone. // // ── WHY WE DO NOT JUST ANNOUNCE ───────────────────────────────────────────── // Reap signal 4 skips any ANNOUNCED pid, reasoning that an announced bridge is 3.23.4+ // and stands down by itself. Announcing WITHOUT registering would make every leftover // immortal: exempt from reaping, yet never superseding itself (supersession is only // consulted on a wake, which a bridge with no peer never gets). The invariant is "a live // bridge either REGISTERS — and so announces and can stand down — or it stays reapable." // Restoring presence registers, so the announce it performs is correct. // --------------------------------------------------------------------------- import { logger } from "../logger.js"; /** * Automatic presence restore. ON by default — a default-off self-heal heals nobody. * Opt out with COGENT_AUTO_PRESENCE=false to observe the state without acting on it. */ export function autoPresenceEnabled(env = process.env) { const v = env.COGENT_AUTO_PRESENCE; if (v === undefined || v === "") return true; return !/^(0|false|no|off)$/i.test(v.trim()); } /** * Determine this agent's presence and, when it is `offline` with a peer it owns, * bring it back `online`. * * NEVER THROWS. Runs fire-and-forget after the MCP transport connects — the * `initialize` handshake must never wait on I/O (scripts/startup-nonblocking-test.mjs). */ export async function restorePresence(deps) { try { if (!deps.isCloudConfigured()) { return { state: "local", restored: false, detail: "local mode — presence does not apply" }; } if (deps.alreadyRegisteredInProcess()) { return { state: "online", restored: false, detail: "registered by this process" }; } const creds = await deps.loadCredentials(); if (!creds || !creds.endpoint || !creds.sessionId || !creds.token) { return { state: "deferred", restored: false, detail: "no stored channel credentials for this working directory — join a channel first", }; } if (!creds.peerId) { // Credentials WITHOUT a peerId: created by join/create, or cleared by a deliberate // deregister. Either way this agent is not meant to be in the channel right now. return { state: "deferred", restored: false, detail: "channel credentials exist but name no peer — nothing was registered here", }; } const peerId = creds.peerId; // Someone live is already this peer. Registering again would take the identity from them. if (deps.peerAlreadyServed(peerId)) { return { state: "online", restored: false, detail: `peer '${peerId}' is already served by a live bridge for this working directory`, }; } if (!autoPresenceEnabled(deps.env ?? process.env)) { // Report the state, take no action. This is the "observe, do not act" mode. return { state: "offline", restored: false, detail: `peer '${peerId}' is not registered and COGENT_AUTO_PRESENCE is off — this agent is absent from its channel`, }; } await deps.goOnline({ peerId, endpoint: creds.endpoint, sessionId: creds.sessionId, token: creds.token, cwd: deps.cwd(), // 🔴 THE PEER'S DISPLAY LABEL IS NOT PERSISTED ANYWHERE — only the CHANNEL's is, // in credentials.label (create-session.ts writes `label: data.label`; join-session // writes the resolved channel label). Using that would label the agent after the // channel: a restore once put "paymentorchestrator" beside a sibling called "POFE". // peerId is the one identifier we hold that genuinely names this agent. The // operator's chosen label returns on the next cogent_register_peer, which carries it. label: peerId, // 🔴 WITHOUT THIS THE RESTORE CANNOT RECLAIM ITS OWN PEER. A re-join issues a NEW // token, and AUD-003 ownership is proven by the token that CREATED the peer or by // the secret issued with it. Omitting it means an entry owned by an earlier token // answers PEER_NOT_YOURS and the agent stays offline — precisely the state this // module exists to leave. The secret is in the credential file; send it. peerSecret: creds.peerSecret, }); return { state: "online", restored: true, peerId, // Says what THIS process did. Whether the relay now lists the peer is the relay's // state, and asserting it from here would be a success nobody measured. detail: `re-registered peer '${peerId}' from stored credentials`, }; } catch (err) { const reason = err instanceof Error ? err.message : String(err); return { state: "offline", restored: false, detail: `presence restore failed: ${reason}`, }; } } /** * Last evaluated presence, so cogent_health_check can report the agent's own state * without re-probing the relay. * * It lives HERE, in the leaf module, and not in startup.ts: a tool importing startup.ts * creates an import cycle (tools -> startup -> tools) and the imported binding reads back * `undefined` at call time. That cost 26 health-check tests once; do not move it. */ let lastPresence = null; /** Record the evaluated presence. Called by startup after each evaluation. */ export function setPresence(outcome) { lastPresence = outcome; } /** The agent's own view of its channel presence. Null until first evaluated. */ export function getPresence() { return lastPresence; } /** Report the outcome once, at a level that matches how much it matters. */ export function logPresence(outcome) { if (outcome.state === "online" && outcome.restored) { logger.info(`Presence: offline -> online — ${outcome.detail}. This agent is addressable on its ` + `channel again, and leftover bridges for this checkout are now reapable.`); } else if (outcome.state === "offline") { logger.warn(`Presence: OFFLINE — ${outcome.detail}.`); } else { logger.debug(`Presence: ${outcome.state} — ${outcome.detail}.`); } } //# sourceMappingURL=peer-presence.js.map