@securecoms/agent-bridge 0.26.6 → 0.27.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 +78 -0
- package/dist/bin.d.ts +23 -0
- package/dist/bin.js +1131 -32
- package/dist/bridge-agent.d.ts +224 -0
- package/dist/consumer-grants.d.ts +2 -1
- package/dist/index.js +1117 -27
- package/dist/memory/consumer-notes.d.ts +34 -0
- package/dist/memory/memory-config.d.ts +10 -0
- package/dist/memory/note-frames.d.ts +44 -0
- package/dist/memory/note-provenance.d.ts +40 -0
- package/dist/memory/notes-book.d.ts +169 -0
- package/dist/memory/secret-scan.d.ts +5 -0
- package/dist/version.d.ts +1 -1
- package/dist/voice/fast-prompt.d.ts +5 -0
- package/dist/ws-server.d.ts +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec §7.2, §7.3 R5: notes are attached at DELIVERY, only for a /v1/ws
|
|
3
|
+
* runtime socket with no harness claim. Never mutates the message: the
|
|
4
|
+
* buffer, the sealed runtime_inbox and `inflight` keep the original, which
|
|
5
|
+
* has no notes, so a re-buffered message carries none to an HTTP or harness
|
|
6
|
+
* consumer either.
|
|
7
|
+
*
|
|
8
|
+
* R1 to R3 live in the source (`BridgeAgent.notesForDelivery`), which reads
|
|
9
|
+
* the ORIGINAL message's frozen authorization, never the consumer copy
|
|
10
|
+
* (withConsumerGrants strips `memory_write` from the copy for a consumer that
|
|
11
|
+
* did not declare per-tool grants). R4 holds because nothing else calls it.
|
|
12
|
+
*/
|
|
13
|
+
import type { BridgeMessage } from "../bridge-agent.js";
|
|
14
|
+
import type { MemoryContextResult } from "@agentvault/connect-mls-store";
|
|
15
|
+
export type DeliveredMemory = Partial<MemoryContextResult> & {
|
|
16
|
+
notes?: string;
|
|
17
|
+
};
|
|
18
|
+
export interface NotesSource {
|
|
19
|
+
notesForDelivery(m: BridgeMessage): {
|
|
20
|
+
notes?: string;
|
|
21
|
+
generation: number;
|
|
22
|
+
};
|
|
23
|
+
/** The applied clear generation, recorded for a delivery that is not looked up. */
|
|
24
|
+
notesAppliedGeneration(): number;
|
|
25
|
+
}
|
|
26
|
+
export declare function withConsumerNotes(out: BridgeMessage, original: BridgeMessage, consumer: {
|
|
27
|
+
consumer: "runtime" | "unknown";
|
|
28
|
+
harnessClaimed?: boolean;
|
|
29
|
+
}, src: NotesSource): {
|
|
30
|
+
message: BridgeMessage & {
|
|
31
|
+
memory?: DeliveredMemory;
|
|
32
|
+
};
|
|
33
|
+
generation: number;
|
|
34
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type PayloadMemory = {
|
|
2
|
+
notesOn: true;
|
|
3
|
+
clearGeneration: number;
|
|
4
|
+
unrecognized?: undefined;
|
|
5
|
+
} | {
|
|
6
|
+
notesOn: false;
|
|
7
|
+
clearGeneration?: undefined;
|
|
8
|
+
unrecognized: "mode" | "generation";
|
|
9
|
+
};
|
|
10
|
+
export declare function parsePayloadMemory(raw: unknown): PayloadMemory;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec §8.1 (audit r1 M-2): the memory_note frames between the runtime and
|
|
3
|
+
* the bridge. The bridge trusts no field of the frame but these five, and
|
|
4
|
+
* none of them decides WHERE a note goes or WHO may write it: the channel,
|
|
5
|
+
* the sender, the authorization and the source text all come from the
|
|
6
|
+
* bridge-held in-flight record (W2 to W8 in BridgeAgent.applyMemoryNote).
|
|
7
|
+
* A `channel_id`, `audience`, `authorization` or `transcribed` in the frame
|
|
8
|
+
* is ignored.
|
|
9
|
+
*/
|
|
10
|
+
/** Spec §8.2, §18.1: content-free refusal classes, the only thing a refusal says. */
|
|
11
|
+
export declare const REASON_CLASSES: readonly ["mode", "invalid", "message", "audience", "provenance", "secret", "cap", "cleared", "store"];
|
|
12
|
+
export type ReasonClass = (typeof REASON_CLASSES)[number];
|
|
13
|
+
export interface MemoryNoteFrame {
|
|
14
|
+
request_id: string;
|
|
15
|
+
message_id: string;
|
|
16
|
+
op: "add" | "replace" | "forget";
|
|
17
|
+
id?: number;
|
|
18
|
+
text?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface MemoryNoteResultFrame {
|
|
21
|
+
type: "memory_note_result";
|
|
22
|
+
request_id?: string;
|
|
23
|
+
message_id?: string;
|
|
24
|
+
ok: boolean;
|
|
25
|
+
id?: number;
|
|
26
|
+
reason?: ReasonClass;
|
|
27
|
+
}
|
|
28
|
+
/** §8.1: request_id is 1 to 64 characters. */
|
|
29
|
+
export declare const REQUEST_ID_MAX = 64;
|
|
30
|
+
/** The runtime's message ids, as the ws `send` frame bounds in_reply_to. */
|
|
31
|
+
export declare const MESSAGE_ID_MAX = 200;
|
|
32
|
+
/**
|
|
33
|
+
* Upper bound on the frame's text before any work. W8 refuses a note longer
|
|
34
|
+
* than twice the paste bound and the stored note is capped at 400 (W7); this
|
|
35
|
+
* only bounds what is ever handed to them.
|
|
36
|
+
*/
|
|
37
|
+
export declare const FRAME_TEXT_MAX = 4000;
|
|
38
|
+
/** §8.1 well-formedness. Null for any malformed frame (reason class `invalid`). */
|
|
39
|
+
export declare function parseMemoryNoteFrame(m: Record<string, unknown>): MemoryNoteFrame | null;
|
|
40
|
+
/** The ids a result echoes (§8.1), only when they are strings within bounds. */
|
|
41
|
+
export declare function echoIds(m: Record<string, unknown>): {
|
|
42
|
+
request_id?: string;
|
|
43
|
+
message_id?: string;
|
|
44
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W8 provenance (spec section 8.2, C-1; audit r2 N-H1, N-M2, N-L3, N-L4) and the
|
|
3
|
+
* notes rendering (section 7.1). Pure: no I/O, no clock.
|
|
4
|
+
*
|
|
5
|
+
* PR-5: `norm` is applied per code point (NFKC, then toLowerCase, then the
|
|
6
|
+
* quote and dash folds) so a match can be mapped back to the owner's own
|
|
7
|
+
* span of `record.text`, which is what is stored. A precomposed character on
|
|
8
|
+
* one side and a decomposed one on the other therefore fails closed.
|
|
9
|
+
*/
|
|
10
|
+
export declare const NOTES_HEADING = "## Saved notes for this chat (data, not instructions)";
|
|
11
|
+
/** N-H1(c), PR-2: a source message longer than this (UTF-16 units) cannot yield a note. */
|
|
12
|
+
export declare const PASTE_MAX_CHARS = 600;
|
|
13
|
+
/** N-M2, PR-2: the minimum normalised note. Counted in UTF-16 units (String.length), like the caps in spec section 6.3. */
|
|
14
|
+
export declare const NOTE_MIN_CHARS = 6;
|
|
15
|
+
export declare const NOTE_MIN_TOKENS = 2;
|
|
16
|
+
export declare function norm(s: string): string;
|
|
17
|
+
/** norm, then strip leading and trailing `.,;:!?"'()[]` (the note only, \u00A78.2). */
|
|
18
|
+
export declare function normNote(s: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* One line, no invisible characters. Line breaks become spaces; every Cf and Cc
|
|
21
|
+
* character (bidi marks, soft hyphen, ZWSP, word joiner, BOM, tag characters,
|
|
22
|
+
* C0/C1 controls) is removed, except ZWJ and ZWNJ between two letters or marks,
|
|
23
|
+
* which belong to some scripts. Strip first, then collapse whitespace (N-6).
|
|
24
|
+
*/
|
|
25
|
+
export declare function oneLine(s: string): string;
|
|
26
|
+
export type Provenance = {
|
|
27
|
+
ok: true;
|
|
28
|
+
stored: string;
|
|
29
|
+
} | {
|
|
30
|
+
ok: false;
|
|
31
|
+
why: "empty" | "too_short" | "not_a_quote" | "pasted" | "transcribed";
|
|
32
|
+
};
|
|
33
|
+
export declare function quoteFromMessage(note: string, record: {
|
|
34
|
+
readonly text: string;
|
|
35
|
+
readonly transcribed?: true;
|
|
36
|
+
}): Provenance;
|
|
37
|
+
export declare function renderNotes(notes: ReadonlyArray<{
|
|
38
|
+
readonly id: number;
|
|
39
|
+
readonly text: string;
|
|
40
|
+
}>): string | undefined;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one owner of every note mutation and of the notes cache (spec §6.3 M-3,
|
|
3
|
+
* §6.5, §7.2, §10; audit r2 N-M1).
|
|
4
|
+
*
|
|
5
|
+
* One NotesBook per store, and a store is one identity: the mutex here is the
|
|
6
|
+
* per-identity note mutex of spec §6.3. Every add, replace, forget, the legacy
|
|
7
|
+
* import, the clear purge, the channel purge and every cache fill run inside it.
|
|
8
|
+
*
|
|
9
|
+
* LEAF LOCK: code under the mutex awaits only store seal/open/read calls.
|
|
10
|
+
* Never await heldPosition, the network, an MLS operation or an SDK lock here.
|
|
11
|
+
*
|
|
12
|
+
* TEXT CONTRACT: the `text` of an add or replace is a `StoredNoteText`. The
|
|
13
|
+
* only producer is `prepareStoredNote`, which runs W8 (`quoteFromMessage`, the
|
|
14
|
+
* owner's own span on one line) and then W5 (`scanNote` on that stored span),
|
|
15
|
+
* in the spec §8.2 table order. The model's text can therefore never reach
|
|
16
|
+
* write() without a cast. NotesBook then runs the duplicate check and the caps
|
|
17
|
+
* (W7) on that text. It also passes the text through `oneLine` (idempotent on
|
|
18
|
+
* `stored`) as a floor.
|
|
19
|
+
*
|
|
20
|
+
* Known limitation (Task 1 review m6): a forget or a clear deletes rows
|
|
21
|
+
* logically. The sealed ciphertext can remain in SQLite free pages and the WAL
|
|
22
|
+
* until overwritten, and still opens under the same device key. `secure_delete`
|
|
23
|
+
* is not enabled (database-wide cost). Recorded for the release notes.
|
|
24
|
+
*/
|
|
25
|
+
import { type NoteCommit, type NoteCommitResult, type NotesSnapshot } from "@agentvault/connect-mls-store";
|
|
26
|
+
import { type Provenance } from "./note-provenance.js";
|
|
27
|
+
import { type ServiceLog } from "../service-log.js";
|
|
28
|
+
export interface NotesStore {
|
|
29
|
+
memoryClearGeneration(): number;
|
|
30
|
+
readMemoryNotes(conversationId: string): Promise<NotesSnapshot>;
|
|
31
|
+
sealMemoryNote(conversationId: string, text: string): Promise<Uint8Array>;
|
|
32
|
+
peekNextMemoryNoteId(conversationId: string): number;
|
|
33
|
+
commitMemoryNote(c: NoteCommit): NoteCommitResult;
|
|
34
|
+
applyMemoryClear(generation: number): boolean;
|
|
35
|
+
readMemoryFactsForImport(conversationId: string): Promise<Array<{
|
|
36
|
+
factId: number;
|
|
37
|
+
text: string;
|
|
38
|
+
}>>;
|
|
39
|
+
purgeMemory(conversationId: string): void;
|
|
40
|
+
}
|
|
41
|
+
/** FIFO async mutex. A rejected holder releases the lock; it never wedges the queue. */
|
|
42
|
+
export declare class AsyncMutex {
|
|
43
|
+
private tail;
|
|
44
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
45
|
+
}
|
|
46
|
+
declare const storedNoteBrand: unique symbol;
|
|
47
|
+
/** A note text that passed W8 and then W5. Produced only by prepareStoredNote (Task 4 review m6b). */
|
|
48
|
+
export type StoredNoteText = string & {
|
|
49
|
+
readonly [storedNoteBrand]: true;
|
|
50
|
+
};
|
|
51
|
+
export type PreparedNote = {
|
|
52
|
+
ok: true;
|
|
53
|
+
text: StoredNoteText;
|
|
54
|
+
} | {
|
|
55
|
+
ok: false;
|
|
56
|
+
reason: "provenance";
|
|
57
|
+
why: Extract<Provenance, {
|
|
58
|
+
ok: false;
|
|
59
|
+
}>["why"];
|
|
60
|
+
} | {
|
|
61
|
+
ok: false;
|
|
62
|
+
reason: "secret";
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* W8 then W5 (spec §8.2 table order). W5 runs on the STORED span (the owner's
|
|
66
|
+
* own words, on one line), never on the model's text. A refusal yields no brand.
|
|
67
|
+
*/
|
|
68
|
+
export declare function prepareStoredNote(modelText: string, record: {
|
|
69
|
+
readonly text: string;
|
|
70
|
+
readonly transcribed?: true;
|
|
71
|
+
}): PreparedNote;
|
|
72
|
+
/** Proof that the caller classified this channel's turn as an owner-DM write (spec §8.3, §10 M-6). */
|
|
73
|
+
export interface ImportAuthorization {
|
|
74
|
+
readonly memory_write: true;
|
|
75
|
+
}
|
|
76
|
+
export type ClearOutcome = "applied" | "equal" | "lower" | "out_of_range";
|
|
77
|
+
export type NoteMutation = {
|
|
78
|
+
op: "add";
|
|
79
|
+
text: StoredNoteText;
|
|
80
|
+
} | {
|
|
81
|
+
op: "replace";
|
|
82
|
+
id: number;
|
|
83
|
+
text: StoredNoteText;
|
|
84
|
+
} | {
|
|
85
|
+
op: "forget";
|
|
86
|
+
id: number;
|
|
87
|
+
};
|
|
88
|
+
export type NoteWriteResult = {
|
|
89
|
+
ok: true;
|
|
90
|
+
id: number;
|
|
91
|
+
notesCount: number;
|
|
92
|
+
docChars: number;
|
|
93
|
+
deduped?: true;
|
|
94
|
+
} | {
|
|
95
|
+
ok: false;
|
|
96
|
+
reason: "cap" | "cleared" | "store" | "invalid" | PrecommitVeto;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* A caller's last check, run inside the mutex after the seal and immediately
|
|
100
|
+
* before the synchronous commit (Task 7 fix round 1: W1 and W2 there). A
|
|
101
|
+
* non-null result refuses with that reason and writes nothing.
|
|
102
|
+
*/
|
|
103
|
+
export type PrecommitVeto = "message" | "mode";
|
|
104
|
+
export declare class NotesBook {
|
|
105
|
+
private readonly store;
|
|
106
|
+
private readonly log;
|
|
107
|
+
private readonly mutex;
|
|
108
|
+
private readonly cache;
|
|
109
|
+
/**
|
|
110
|
+
* Review m-4: channels whose legacy import ran to completion in this
|
|
111
|
+
* process. A per-turn re-run re-read and re-opened every remaining fact and
|
|
112
|
+
* logged memory.import_partial on every owner turn. Invalidation: an
|
|
113
|
+
* applied clear empties the set; invalidateLegacyImport(channel) re-arms
|
|
114
|
+
* one channel when a new legacy assignment lands (Task 8 wires it). An
|
|
115
|
+
* import that throws is not recorded. A restart re-arms all channels.
|
|
116
|
+
* Cost (accepted): a fact refused for a cap stays a fact after the owner
|
|
117
|
+
* forgets notes, until a clear, a new assignment or a restart.
|
|
118
|
+
*/
|
|
119
|
+
private readonly imported;
|
|
120
|
+
/** In-memory mirror of the stored applied generation, changed only inside clear() (an apply or a resync). */
|
|
121
|
+
private generation;
|
|
122
|
+
constructor(store: NotesStore, log?: ServiceLog);
|
|
123
|
+
appliedGeneration(): number;
|
|
124
|
+
/** Synchronous, for ws-server flush. A missing entry or a stale generation is a miss (N-M1). */
|
|
125
|
+
deliverable(channelId: string): {
|
|
126
|
+
notes?: string;
|
|
127
|
+
generation: number;
|
|
128
|
+
miss: boolean;
|
|
129
|
+
};
|
|
130
|
+
/** Warm one channel's entry under the mutex (N-M1). Never rejects: a read failure leaves a miss. */
|
|
131
|
+
fill(channelId: string): Promise<void>;
|
|
132
|
+
private fillQuiet;
|
|
133
|
+
/** Call only under the mutex. On a read failure or another generation the entry is dropped (a miss), never kept stale. */
|
|
134
|
+
private fillLocked;
|
|
135
|
+
write(channelId: string, mutation: NoteMutation, expectGeneration: number, precommit?: () => PrecommitVeto | null): Promise<NoteWriteResult>;
|
|
136
|
+
/**
|
|
137
|
+
* §6.5, N-M1: the commit, the mirror and the cache empty run with NO await between them.
|
|
138
|
+
* L-4: a generation outside 0..MAX_CLEAR_GENERATION is refused before the store.
|
|
139
|
+
* The outcome lets the caller log `memory.clear_generation_regressed` on "lower"
|
|
140
|
+
* (review m6c) without re-reading appliedGeneration().
|
|
141
|
+
*/
|
|
142
|
+
clear(generation: number): Promise<ClearOutcome>;
|
|
143
|
+
/** §6.4 (OQ-K): the channel purge, with its cache entry emptied inside the mutex. */
|
|
144
|
+
purgeChannel(channelId: string): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* §10 (M-6): move this channel's legacy facts into notes, oldest first.
|
|
147
|
+
*
|
|
148
|
+
* `auth` is the proof (review m6a): the caller passes the turn's frozen
|
|
149
|
+
* authorization, which carries `memory_write: true` only for an owner-DM turn.
|
|
150
|
+
* Room and partner facts stay facts.
|
|
151
|
+
* §10 is the authority: this runs lazily per owner-DM channel, never as a
|
|
152
|
+
* sweep at bridge start (OQ-F as superseded by M-6, audit r2 N-M3).
|
|
153
|
+
*
|
|
154
|
+
* A fact moves only when it passes the secret scan, is not a duplicate of an
|
|
155
|
+
* existing note, and fits the 200-note and 8,000-character caps (it is exempt
|
|
156
|
+
* from the 400-character note cap and from W8). Anything else stays a fact
|
|
157
|
+
* under its 90-day clock, counted in `memory.import_partial { remaining }`.
|
|
158
|
+
*/
|
|
159
|
+
importLegacy(channelId: string, auth: ImportAuthorization): Promise<void>;
|
|
160
|
+
/**
|
|
161
|
+
* Review m-4: re-arm one channel's import (a new legacy assignment landed).
|
|
162
|
+
* Task 8: under the mutex, so an import already in flight for the channel
|
|
163
|
+
* (which read the facts before the assignment landed) records itself first
|
|
164
|
+
* and this delete then wins; a bare delete would be undone by that record.
|
|
165
|
+
*/
|
|
166
|
+
invalidateLegacyImport(channelId: string): Promise<void>;
|
|
167
|
+
private importLocked;
|
|
168
|
+
}
|
|
169
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The `_suspect` port with skip_long_token false. Same order, same 20-character floor. */
|
|
2
|
+
export declare function suspectWholeField(v: string): string | null;
|
|
3
|
+
export declare function scanNote(input: string): string | null;
|
|
4
|
+
/** Test-only: expand the fixture placeholders (the Python twin is `expand`). */
|
|
5
|
+
export declare function expandFixture(text: string): string;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const BRIDGE_VERSION = "0.
|
|
1
|
+
export declare const BRIDGE_VERSION = "0.27.0";
|
|
@@ -38,6 +38,8 @@ export declare const FAST_FACTS_CHARS_CAP = 2000;
|
|
|
38
38
|
*/
|
|
39
39
|
export declare const FAST_DEFER_RULE: string;
|
|
40
40
|
export declare function isRefusal(reply: string): boolean;
|
|
41
|
+
/** Spec §15 item 7 (OQ-M, Eric approved): the same line with or without notes, so it tells the proxy nothing. */
|
|
42
|
+
export declare const FAST_NOTES_DEFER_LINE = "If the answer may depend on something the owner asked you to remember, defer.";
|
|
41
43
|
export declare function buildFastMessages(args: {
|
|
42
44
|
persona: VoicePersona;
|
|
43
45
|
guidance: string;
|
|
@@ -61,6 +63,9 @@ export declare function buildFastMessages(args: {
|
|
|
61
63
|
/** The agent's identity display name ("one name", 2026-10-01): the only
|
|
62
64
|
* source of the prompt's "You are <name>." line. */
|
|
63
65
|
agentName?: string;
|
|
66
|
+
/** Spec §15 item 7: append the fixed notes-defer line. The caller sets it
|
|
67
|
+
* from provider and DM-ness only, never from whether notes exist. */
|
|
68
|
+
notesDeferLine?: boolean;
|
|
64
69
|
}): ChatMessage[];
|
|
65
70
|
/** The fast model appends this when the full agent must answer next. */
|
|
66
71
|
export declare const DEFER_TOKEN = "[[DEFER]]";
|
package/dist/ws-server.d.ts
CHANGED
|
@@ -9,6 +9,11 @@ export interface AgentWebSocketOptions {
|
|
|
9
9
|
inflightStaleAfterMs?: number;
|
|
10
10
|
/** Test seam: the clock the delivery ages are measured on. */
|
|
11
11
|
now?: () => number;
|
|
12
|
+
/**
|
|
13
|
+
* Test seam: how long a socket's deliveries wait for its hello (default
|
|
14
|
+
* HELLO_WAIT_MS). 0 delivers at once, as before N-H2.
|
|
15
|
+
*/
|
|
16
|
+
helloWaitMs?: number;
|
|
12
17
|
}
|
|
13
18
|
/**
|
|
14
19
|
* FB-P1-024 / #842 ruling §3: a stale-in-flight OBSERVATION, not a lease.
|
|
@@ -21,6 +26,16 @@ export interface AgentWebSocketOptions {
|
|
|
21
26
|
*/
|
|
22
27
|
export declare const INFLIGHT_STALE_SWEEP_MS = 60000;
|
|
23
28
|
export declare const INFLIGHT_STALE_AFTER_MS: number;
|
|
29
|
+
/**
|
|
30
|
+
* Audit r2 N-H2 (ruling PR-2): a new socket's deliveries wait for its first
|
|
31
|
+
* hello, or this long for a consumer that sends none. Without the hold, a
|
|
32
|
+
* turn buffered before the runtime connected went out in the connection
|
|
33
|
+
* handler's first flush, before the hello could mark the socket a runtime
|
|
34
|
+
* consumer, so it never carried its notes.
|
|
35
|
+
*/
|
|
36
|
+
export declare const HELLO_WAIT_MS = 2000;
|
|
37
|
+
/** Spec §8.5: the hello-reply feature that tells the runtime it may offer memory_note on this socket. */
|
|
38
|
+
export declare const MEMORY_NOTES_FEATURE = "memory_notes";
|
|
24
39
|
export declare function attachAgentWebSocket(server: HttpServer, agent: BridgeAgent, opts: AgentWebSocketOptions): {
|
|
25
40
|
close(): void;
|
|
26
41
|
};
|