@securecoms/agent-bridge 0.26.3 → 0.26.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,80 +1,3 @@
1
- /**
2
- * Agent-facing keepalive WebSocket (/v1/ws).
3
- *
4
- * Adds a single persistent bidirectional socket for the AGENT⇄DAEMON hop,
5
- * modeled on AgentVault's keepalive WS (token in `?token=` query OR
6
- * `Authorization: Bearer`). This replaces the curl/long-poll loop: the agent
7
- * receives live inbound messages as JSON frames and sends/reports status over
8
- * the same socket.
9
- *
10
- * Protocol (all frames are JSON text):
11
- * Daemon → agent:
12
- * { "type":"message", channel_id, message_id, sender_id, text, ts,
13
- * authorization:{version,audience,sender_membership,tool_grants} } // inbound, decrypted
14
- * { "type":"sent", message_id } // ack of a send
15
- * { "type":"ok" } // ack of a status report
16
- * { "type":"error", error, message, detail? } // canonical codes (see errors.ts):
17
- * // channel_pending | rate_limited |
18
- * // invalid_request | agent_paused |
19
- * // send_forbidden (those two are
20
- * // TERMINAL: the in_reply_to message
21
- * // is acked by the daemon, no retry) |
22
- * // group_superseded (NOT terminal:
23
- * // the reply is republished after
24
- * // the agent rejoins)
25
- * Agent → daemon:
26
- * { "type":"send", channel_id, text?, a2a?, idempotency_key?,
27
- * in_reply_to? } // exactly one of text | a2a. SEC-06 #18: in_reply_to
28
- * // and/or idempotency_key make the send idempotent — a
29
- * // deterministic keyed message_id and a durable reply
30
- * // intent written before the publish, so a retry or a
31
- * // redelivery republishes the SAME reply
32
- * { "type":"status", channel_id, state, detail? }
33
- * { "type":"ack", message_id } // confirms a delivered `message` was consumed
34
- * { "type":"nack", message_id, reason? } // final-wave I1(b): THIS message's turn
35
- * // failed — requeued behind a backoff; the
36
- * // socket and other channels' turns stay up
37
- * { "type":"hello", features? } // → { "type":"hello", features:["nack"] }; a
38
- * // runtime nacks only after seeing "nack" here
39
- * { "type":"action_begin", channel_id } // → { "type":"action_begun", run_id }
40
- * { "type":"action_start", run_id, node_type, title, parent_id? } // → { "type":"action_started", node_id }
41
- * { "type":"action_update", run_id, node_id, status?, detail? } // → { "type":"ok" }
42
- * { "type":"action_finish", run_id, node_id, status, detail? } // → { "type":"ok" }
43
- * { "type":"action_settle", run_id, result_message_id? } // → { "type":"action_settled", run_id }
44
- *
45
- * Inbound delivery is at-least-once. A delivered `message` is held in-flight
46
- * until the agent sends a matching `ack`; if the socket drops first, the frame
47
- * is re-buffered and redelivered to the next consumer. The agent dedups by
48
- * message_id. SEC-06 #18: a redelivered message whose reply already has a
49
- * durable intent is NOT handed to the agent again; the daemon republishes that
50
- * reply itself (same message_id), so the model does not run twice.
51
- *
52
- * Bounded work (Phase 3):
53
- * - F2 ordering: at most ONE message per channel is in flight on a socket;
54
- * the next message for that channel is sent only after the previous one is
55
- * acked (or retired). A backlog replays in order instead of flooding the
56
- * runtime, which used to answer the overflow with a "busy" reply and ack it.
57
- * - F1 attempt cap: every delivery is counted durably; a message that
58
- * reaches the cap is dead-lettered (content-free log + ack + one
59
- * content-free notice to the channel per hour) rather than redelivered
60
- * forever, and a channel where the agent is paused is not delivered at
61
- * all (no model call).
62
- * - Final-wave I1: a FAILED delivery (a `nack`, or the socket closing with
63
- * it in flight — older runtimes close on any failed turn) is requeued
64
- * behind a 2^attempts × 5 s backoff. A nack fails only its own message.
65
- * Messages never handed over (mid-flush close, a failed frame write) go
66
- * back without that penalty.
67
- * - #842: a delivery still un-acked after INFLIGHT_STALE_AFTER_MS is LOGGED
68
- * once (`runtime_inbox.inflight_stale`) and otherwise left alone. There
69
- * is deliberately no lease: see INFLIGHT_STALE_AFTER_MS.
70
- *
71
- * Single consumer: the daemon serves one agent per process. A new `/v1/ws`
72
- * connection replaces the prior one (newest wins, mirroring the SSE path); the
73
- * replaced socket's un-acked in-flight messages are re-buffered.
74
- *
75
- * Keepalive uses the ws library's server-side ping (the protocol-level ping
76
- * frame, not an application message); dead sockets are reaped via pong tracking.
77
- */
78
1
  import type { Server as HttpServer } from "node:http";
79
2
  import type { BridgeAgent } from "./bridge-agent.js";
80
3
  export interface AgentWebSocketOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@securecoms/agent-bridge",
3
- "version": "0.26.3",
3
+ "version": "0.26.5",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22.5.0"