@securecoms/agent-bridge 0.36.0 → 0.38.0
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.
- package/README.md +31 -0
- package/connectors/hermes/__pycache__/securecoms_gate.cpython-310.pyc +0 -0
- package/connectors/hermes/__pycache__/securecoms_transport.cpython-310.pyc +0 -0
- package/connectors/hermes/adapter.py +424 -32
- package/connectors/hermes/securecoms_transport.py +97 -1
- package/connectors/hermes/tests/test_adapter_wiring.py +887 -0
- package/connectors/hermes/tests/test_securecoms_transport.py +127 -0
- package/connectors/openclaw/openclaw-entry.contract.test.ts +96 -0
- package/connectors/openclaw/openclaw-entry.inbound.test.ts +228 -1
- package/connectors/openclaw/openclaw-entry.js +128 -3
- package/dist/attachments.d.ts +33 -1
- package/dist/bin.js +4607 -1020
- package/dist/bridge-agent.d.ts +129 -0
- package/dist/grants/mcp-policy.d.ts +7 -0
- package/dist/index.js +4577 -990
- package/dist/version.d.ts +1 -1
- package/dist/ws-server.d.ts +1 -1
- package/package.json +1 -1
package/dist/bridge-agent.d.ts
CHANGED
|
@@ -519,6 +519,12 @@ export interface BridgeAgentDeps {
|
|
|
519
519
|
* Injected so tests do not wait the full window.
|
|
520
520
|
*/
|
|
521
521
|
voiceCoalesceWindowMs?: number;
|
|
522
|
+
/**
|
|
523
|
+
* Image + caption coalescing: how long a caption-less image share waits for
|
|
524
|
+
* its sender's caption (default CAPTION_COALESCE_WINDOW_MS; 0 disables the
|
|
525
|
+
* hold, every image is staged at once as before).
|
|
526
|
+
*/
|
|
527
|
+
captionCoalesceWindowMs?: number;
|
|
522
528
|
/**
|
|
523
529
|
* B7 (FileSafe vault): persistence for the vault kekset's owner-pin TOFU
|
|
524
530
|
* state. Defaults to a {@link FileOwnerAuthorityStore} at
|
|
@@ -566,6 +572,30 @@ export declare function voiceWindowEligible(t: {
|
|
|
566
572
|
voiceGuidance: string | undefined;
|
|
567
573
|
isCallStart: boolean;
|
|
568
574
|
}): boolean;
|
|
575
|
+
/**
|
|
576
|
+
* Image + caption coalescing (2026-11-11). The web client sends an image with a
|
|
577
|
+
* caption as TWO channel messages: an `artifact_share` with no text, then a plain
|
|
578
|
+
* text message. Delivered as two turns, the agent answered the bare image and
|
|
579
|
+
* then the caption without the image. A caption-less image share from a sender
|
|
580
|
+
* that is not an agent is staged durably but HELD this long; the next message
|
|
581
|
+
* from the same sender in the same channel, if it is a text turn, is delivered
|
|
582
|
+
* as ONE frame: the caption's id, text, authorization and memory, plus the held
|
|
583
|
+
* images' attachments. Anything else in the channel releases the held images
|
|
584
|
+
* first, in order. Rules (see BridgeAgent.holdCaptionImage and the text path):
|
|
585
|
+
* - consecutive images from the same sender join one hold (the window restarts
|
|
586
|
+
* from the latest image), up to CAPTION_MERGE_MAX_ATTACHMENTS; with no caption
|
|
587
|
+
* each image is released as its own frame, in order, as before;
|
|
588
|
+
* - the merge happens only when every held image's authorization equals the
|
|
589
|
+
* caption's (never widens or narrows a grant), else the images go alone first;
|
|
590
|
+
* - in a room, a caption the @mention filter rejects drops the held images too
|
|
591
|
+
* (image + caption was one message, addressed elsewhere); a caption-less image
|
|
592
|
+
* alone still follows the unchanged broadcast rule;
|
|
593
|
+
* - close() releases nothing: held images stay in runtime_inbox and a restart
|
|
594
|
+
* restores them as ordinary turns.
|
|
595
|
+
*/
|
|
596
|
+
export declare const CAPTION_COALESCE_WINDOW_MS = 1500;
|
|
597
|
+
/** The connectors accept at most 8 attachments per frame (#1450): a hold never grows past that. */
|
|
598
|
+
export declare const CAPTION_MERGE_MAX_ATTACHMENTS = 8;
|
|
569
599
|
/** Default inbound-buffer cap (messages) when deps.maxBuffer is unset. */
|
|
570
600
|
export declare const DEFAULT_MAX_BUFFER = 1000;
|
|
571
601
|
/**
|
|
@@ -1119,6 +1149,14 @@ export declare class BridgeAgent {
|
|
|
1119
1149
|
private readonly voiceCoalescedIds;
|
|
1120
1150
|
/** Merged turn id -> the absorbed fragments' held frames, retired with it. */
|
|
1121
1151
|
private readonly voiceCoalescedTails;
|
|
1152
|
+
/** Image + caption coalescing: the open hold per channel (CAPTION_COALESCE_WINDOW_MS). */
|
|
1153
|
+
private readonly captionHolds;
|
|
1154
|
+
/**
|
|
1155
|
+
* Ids of held images whose content was consumed (capped FIFO): merged into a caption frame, or dropped with a
|
|
1156
|
+
* caption the room filter rejected. A redelivered row is acked, never downloaded or delivered (audit L1, round 2).
|
|
1157
|
+
*/
|
|
1158
|
+
private readonly captionConsumedIds;
|
|
1159
|
+
private readonly captionCoalesceWindowMs;
|
|
1122
1160
|
/** (4) recv.lag: application queue ids already measured (capped FIFO), so a re-pulled row is not re-counted. */
|
|
1123
1161
|
private readonly recvLagSeen;
|
|
1124
1162
|
private static readonly RECV_LAG_SEEN_CAP;
|
|
@@ -1240,6 +1278,29 @@ export declare class BridgeAgent {
|
|
|
1240
1278
|
*/
|
|
1241
1279
|
private mcpPolicyWritten;
|
|
1242
1280
|
private mcpPolicyWrittenJson;
|
|
1281
|
+
/** Deletion-ack ruling §3: the manifest counter in force when `mcpPolicyWrittenJson` was written (never read live). */
|
|
1282
|
+
private mcpPolicyWrittenCounter;
|
|
1283
|
+
/** Ruling §3: newest counter whose written policy the runtime fully acted on. Memory only, monotonic, starts at 0. */
|
|
1284
|
+
private mcpDeletionsThrough;
|
|
1285
|
+
/** Ruling §3: the last `credentials_present` an accepted frame carried; null until one arrives. */
|
|
1286
|
+
private mcpCredentialsPresentValue;
|
|
1287
|
+
/** Ruling §3: per attached socket, whether its latest hello declared mcp_deletion_ack_v1 (harness noted false). */
|
|
1288
|
+
private readonly mcpDeletionAckSockets;
|
|
1289
|
+
/** Ruling §3 rate: the ack-derived report values in the last report posted (null until one is). */
|
|
1290
|
+
private lastReportedMcpAck;
|
|
1291
|
+
/** #1351 round 2 M-1: bumped on every byte-changing policy write (and on the inert document being put in force). */
|
|
1292
|
+
private policyWriteSeq;
|
|
1293
|
+
/** M-1: per ack-capable socket, the policyWriteSeq at the dispatch of each owner-DM turn, by message id (bounded). */
|
|
1294
|
+
private readonly mcpTurnSeq;
|
|
1295
|
+
/**
|
|
1296
|
+
* #1351 round 2 H-1: the ack values the REPORT may carry. An ack lands seconds after an owner-DM turn and a report
|
|
1297
|
+
* posted then would time the turn (record_report sets applied_at). So, as the tool-status sender: `open` holds a
|
|
1298
|
+
* change while its 15-minute UTC bucket is open, `closed` what the report carries, and the only post is from one
|
|
1299
|
+
* timer at the next bucket boundary plus jitter.
|
|
1300
|
+
*/
|
|
1301
|
+
private mcpAckOpen;
|
|
1302
|
+
private mcpAckClosed;
|
|
1303
|
+
private mcpAckTimer;
|
|
1243
1304
|
/** PR-B2 follow-up: a failed write is retried on this backoff (the last value repeats) until one lands or close(). */
|
|
1244
1305
|
private readonly mcpPolicyRetryDelaysMs;
|
|
1245
1306
|
private mcpPolicyRetryTimer;
|
|
@@ -2911,6 +2972,33 @@ export declare class BridgeAgent {
|
|
|
2911
2972
|
* deferring fast reply was actually published — F3).
|
|
2912
2973
|
*/
|
|
2913
2974
|
private speakAndSettle;
|
|
2975
|
+
/**
|
|
2976
|
+
* Image + caption coalescing: stage a caption-less image share durably but
|
|
2977
|
+
* HELD, joining its sender's open hold in this channel or opening one. The
|
|
2978
|
+
* hold's job takes the channel queue now, so every later frame of the channel
|
|
2979
|
+
* (all staged through stageRuntimeMessageInOrder or the queue) waits behind it.
|
|
2980
|
+
* Returns false on backpressure (the row stays unacked). The caller has
|
|
2981
|
+
* checked the id is not already staged (a redelivered row).
|
|
2982
|
+
*/
|
|
2983
|
+
private holdCaptionImage;
|
|
2984
|
+
/** Release one held image as its own frame: the room web_search count it skipped at staging runs now (audit M3). */
|
|
2985
|
+
private releaseCaptionImage;
|
|
2986
|
+
/**
|
|
2987
|
+
* Retire held images whose content left with a merged frame or was dropped with a filtered caption. Never throws
|
|
2988
|
+
* (audit M1: a throw here left the hold job asleep and the channel queue wedged): a row that cannot be retired
|
|
2989
|
+
* stays in runtime_inbox and comes back at a restart as an ordinary turn.
|
|
2990
|
+
*/
|
|
2991
|
+
private retireCaptionImages;
|
|
2992
|
+
/** Audit L3: best-effort removal of the decrypted files of images dropped with a filtered caption. Never throws. */
|
|
2993
|
+
private unlinkCaptionImages;
|
|
2994
|
+
private noteCaptionConsumed;
|
|
2995
|
+
private armCaptionHold;
|
|
2996
|
+
/** Detach a hold synchronously: nothing joins or merges into it after this. */
|
|
2997
|
+
private detachCaptionHold;
|
|
2998
|
+
/** Detach (if still open) and wake the hold's job with its outcome. Idempotent on the outcome. */
|
|
2999
|
+
private closeCaptionHold;
|
|
3000
|
+
/** The open hold a text turn from `senderId` in `channelId` may take, if any. */
|
|
3001
|
+
private captionHoldFor;
|
|
2914
3002
|
/**
|
|
2915
3003
|
* Stage a runtime frame without overtaking a turn of the same channel that
|
|
2916
3004
|
* is still queued behind the fast path (F2): while the channel has a queue,
|
|
@@ -3744,6 +3832,45 @@ export declare class BridgeAgent {
|
|
|
3744
3832
|
private readonly mcpClientSockets;
|
|
3745
3833
|
noteMcpClientSocket(token: object, declared: boolean): void;
|
|
3746
3834
|
clearMcpClientSocket(token: object): void;
|
|
3835
|
+
/** Deletion-ack ruling §3: ws-server notes every runtime hello's mcp_deletion_ack_v1 declaration (harness: false). */
|
|
3836
|
+
noteMcpDeletionAckSocket(token: object, declared: boolean): void;
|
|
3837
|
+
/** #1351 round 2 observation: with no ack-capable socket left (detached, or re-hello'd without the feature), the last
|
|
3838
|
+
* credentials value is no longer known: forget it, so a later socket does not inherit a stale value. */
|
|
3839
|
+
private forgetCredentialsIfNoAckSocket;
|
|
3840
|
+
clearMcpDeletionAckSocket(token: object): void;
|
|
3841
|
+
/** #1351 round 2 M-1: ws-server calls this when it sends an owner-DM turn to an ack-capable socket. Bounded. */
|
|
3842
|
+
noteMcpTurnDispatch(token: object, messageId: string): void;
|
|
3843
|
+
/** Ruling §3 / §5.3: the AND over attached sockets, false with none attached (as mcpClientCapable). */
|
|
3844
|
+
private mcpDeletionAckCapable;
|
|
3845
|
+
/**
|
|
3846
|
+
* Deletion-ack ruling (2026-10-31) §3 acceptance. ws-server has validated the frame shape and the socket (declared
|
|
3847
|
+
* mcp_deletion_ack_v1 and mcp_client_v1, no harness). `credentials_present` is taken as is. `applied_sha256` advances
|
|
3848
|
+
* `mcpDeletionsThrough` only when it is the SHA-256 of the bytes THIS bridge last wrote (JSON + newline) and still
|
|
3849
|
+
* holds in force, and that document's top state is one whose deletion set covers the signed removal; then to the
|
|
3850
|
+
* counter recorded at that write, never the live one. Anything else is ignored silently. Never throws.
|
|
3851
|
+
*/
|
|
3852
|
+
noteMcpDeletionAck(token: object, frame: {
|
|
3853
|
+
credentials_present: boolean;
|
|
3854
|
+
message_id?: string;
|
|
3855
|
+
applied_sha256?: string;
|
|
3856
|
+
}): void;
|
|
3857
|
+
/** H-1: a change of the ack values goes into the open bucket; the report sees it only once the bucket has closed. */
|
|
3858
|
+
private noteMcpAckChanged;
|
|
3859
|
+
private promoteMcpAck;
|
|
3860
|
+
/** H-1: one timer, at the first bucket boundary strictly after now plus a jitter in [0, 60 s), as the tool-status sender. */
|
|
3861
|
+
private scheduleMcpAckReport;
|
|
3862
|
+
/**
|
|
3863
|
+
* Ruling §5.3: the three keys. The two ack values come from the CLOSED bucket only (H-1), so no report, whatever
|
|
3864
|
+
* posts it, reveals an owner-DM turn before its 15-minute bucket has closed. `mcp_r3_hold` is not DM timing: live.
|
|
3865
|
+
*/
|
|
3866
|
+
private reportedMcpAck;
|
|
3867
|
+
private mcpAckSignature;
|
|
3868
|
+
/**
|
|
3869
|
+
* A SOCKET change (attach, detach, a hello) can change which keys the report carries; their values are the closed
|
|
3870
|
+
* ones, so this is not owner-DM timing and may use the capability refetch. An ACK never comes here (H-1): it goes
|
|
3871
|
+
* through noteMcpAckChanged and the bucket timer.
|
|
3872
|
+
*/
|
|
3873
|
+
private maybeReportMcpAck;
|
|
3747
3874
|
/** MCP Task 18: ws-server registers (or, with null, removes) a socket's loopback catalog lister. */
|
|
3748
3875
|
noteMcpCatalogLister(token: object, lister: McpCatalogLister | null): void;
|
|
3749
3876
|
/**
|
|
@@ -3790,6 +3917,8 @@ export declare class BridgeAgent {
|
|
|
3790
3917
|
* switches and the new capability, then a debounced refetch (one per burst) only when needed.
|
|
3791
3918
|
*/
|
|
3792
3919
|
private onCapabilityMaybeChanged;
|
|
3920
|
+
/** Debounced, with a max wait: a burst that never pauses still refetches at most maxWait after its first change. */
|
|
3921
|
+
private scheduleCapabilityRefetch;
|
|
3793
3922
|
/**
|
|
3794
3923
|
* A refetch re-renders skills.json (owner_dm_search_cap counts web_extract only with the capability, D39) and posts
|
|
3795
3924
|
* the report. Needed under a manifest in force, or when the reported value is stale. Never before the boot fetch.
|
|
@@ -33,6 +33,13 @@ import { type ServiceLog } from "../service-log.js";
|
|
|
33
33
|
* backend can write that name (ws-server.test.ts same-build row).
|
|
34
34
|
*/
|
|
35
35
|
export declare const MCP_POLICY_WRITER_FEATURE = "mcp_policy_writer_v1";
|
|
36
|
+
/**
|
|
37
|
+
* Deletion-ack ruling (2026-10-31) §3: declared in the hello reply and by the runtime in its hello. Only a socket that
|
|
38
|
+
* declared it (and mcp_client_v1, no harness) may send `mcp_deletion_ack`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const MCP_DELETION_ACK_FEATURE = "mcp_deletion_ack_v1";
|
|
41
|
+
/** Ruling §3: the top states whose deletion set covers the manifest's signed `removed` (ok), or everything on disk. */
|
|
42
|
+
export declare const MCP_ACK_STATES: ReadonlySet<string>;
|
|
36
43
|
export type McpEntitlementReading = "entitled" | "not_entitled" | "suspended";
|
|
37
44
|
/**
|
|
38
45
|
* OQ-1 ruling (ADR G). Only `true`/"entitled" is in force and only `false`/"not_entitled" is the deleting downgrade.
|