agentic-flow 2.0.10 → 2.0.12-fix.1
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/dist/.tsbuildinfo +1 -1
- package/dist/billing/cli.js +0 -0
- package/dist/cli-proxy.js +0 -0
- package/dist/transport/index.d.ts +1 -0
- package/dist/transport/index.d.ts.map +1 -1
- package/dist/transport/index.js +1 -0
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/quic-loader.d.ts +91 -0
- package/dist/transport/quic-loader.d.ts.map +1 -0
- package/dist/transport/quic-loader.js +240 -0
- package/dist/transport/quic-loader.js.map +1 -0
- package/package.json +5 -4
- package/wasm/reasoningbank/reasoningbank_wasm_bg.js +28 -28
- package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm +0 -0
- package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm.d.ts +2 -2
package/dist/billing/cli.js
CHANGED
|
File without changes
|
package/dist/cli-proxy.js
CHANGED
|
File without changes
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export * from './quic.js';
|
|
2
|
+
export { loadQuicTransport, isQuicAvailable, getTransportCapabilities, WebSocketFallbackTransport, type AgentTransport, type AgentMessage, type PoolStatistics, type TransportCapabilities, type QuicTransportConfig as LoaderQuicTransportConfig, } from './quic-loader.js';
|
|
2
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AACA,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,wBAAwB,EACxB,0BAA0B,EAC1B,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,IAAI,yBAAyB,GACtD,MAAM,kBAAkB,CAAC"}
|
package/dist/transport/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,cAAc,WAAW,CAAC","sourcesContent":["// Transport Layer Exports\nexport * from './quic.js';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transport/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,cAAc,WAAW,CAAC;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,wBAAwB,EACxB,0BAA0B,GAM3B,MAAM,kBAAkB,CAAC","sourcesContent":["// Transport Layer Exports\nexport * from './quic.js';\nexport {\n loadQuicTransport,\n isQuicAvailable,\n getTransportCapabilities,\n WebSocketFallbackTransport,\n type AgentTransport,\n type AgentMessage,\n type PoolStatistics,\n type TransportCapabilities,\n type QuicTransportConfig as LoaderQuicTransportConfig,\n} from './quic-loader.js';\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/** Caller-facing config — minimal common surface across both backends. */
|
|
2
|
+
export interface QuicTransportConfig {
|
|
3
|
+
serverName?: string;
|
|
4
|
+
maxIdleTimeoutMs?: number;
|
|
5
|
+
maxConcurrentStreams?: number;
|
|
6
|
+
enable0Rtt?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface AgentMessage {
|
|
9
|
+
id: string;
|
|
10
|
+
type: 'task' | 'result' | 'status' | 'coordination' | 'heartbeat' | string;
|
|
11
|
+
payload: unknown;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface PoolStatistics {
|
|
15
|
+
active: number;
|
|
16
|
+
idle: number;
|
|
17
|
+
created: number;
|
|
18
|
+
closed: number;
|
|
19
|
+
}
|
|
20
|
+
/** Common interface both real-QUIC and fallback transports satisfy. */
|
|
21
|
+
export interface AgentTransport {
|
|
22
|
+
send(address: string, message: AgentMessage): Promise<void>;
|
|
23
|
+
receive(address: string): Promise<AgentMessage>;
|
|
24
|
+
request(address: string, message: AgentMessage): Promise<AgentMessage>;
|
|
25
|
+
sendBatch(address: string, messages: AgentMessage[]): Promise<void>;
|
|
26
|
+
getStats(): Promise<PoolStatistics>;
|
|
27
|
+
close(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* WebSocket fallback transport.
|
|
31
|
+
*
|
|
32
|
+
* Spec compliance: implements the AgentTransport interface using
|
|
33
|
+
* `ws://` (or `wss://` if address starts with `wss://`). Each call to
|
|
34
|
+
* `send` lazily opens (or reuses) a connection to `address`. The
|
|
35
|
+
* `receive(address)` call drains the next queued message for that
|
|
36
|
+
* address; if none is queued it polls every 100ms until one arrives.
|
|
37
|
+
*
|
|
38
|
+
* Limits vs real QUIC: no 0-RTT resumption, no multiplexed streams
|
|
39
|
+
* (one TCP connection per peer), TLS handled by the WS layer (use
|
|
40
|
+
* `wss://` for encryption). Performance is "good enough" for federation
|
|
41
|
+
* messages at human/agent rates (≤ 100 RPS per peer).
|
|
42
|
+
*/
|
|
43
|
+
declare class WebSocketFallbackTransport implements AgentTransport {
|
|
44
|
+
private readonly config;
|
|
45
|
+
private connections;
|
|
46
|
+
private messageQueue;
|
|
47
|
+
private connectionsCreated;
|
|
48
|
+
private connectionsClosed;
|
|
49
|
+
private servers;
|
|
50
|
+
constructor(config: Required<QuicTransportConfig>);
|
|
51
|
+
static create(config?: QuicTransportConfig): Promise<WebSocketFallbackTransport>;
|
|
52
|
+
/**
|
|
53
|
+
* Bind a server-side listener so this transport instance can RECEIVE
|
|
54
|
+
* messages from a remote peer (in addition to sending). Federation
|
|
55
|
+
* peers run BOTH a listener and a client — calling listen(9100) plus
|
|
56
|
+
* send('peer:9100', ...) gives bidirectional connectivity.
|
|
57
|
+
*/
|
|
58
|
+
listen(port: number, host?: string): Promise<void>;
|
|
59
|
+
private getOrCreateConnection;
|
|
60
|
+
send(address: string, message: AgentMessage): Promise<void>;
|
|
61
|
+
receive(address: string): Promise<AgentMessage>;
|
|
62
|
+
request(address: string, message: AgentMessage): Promise<AgentMessage>;
|
|
63
|
+
sendBatch(address: string, messages: AgentMessage[]): Promise<void>;
|
|
64
|
+
getStats(): Promise<PoolStatistics>;
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Public API — load a working transport, preferring real QUIC when
|
|
69
|
+
* available, falling back to WebSocket otherwise. The returned object
|
|
70
|
+
* satisfies the AgentTransport interface in both cases.
|
|
71
|
+
*
|
|
72
|
+
* Example:
|
|
73
|
+
* const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });
|
|
74
|
+
* await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });
|
|
75
|
+
*
|
|
76
|
+
* Federation v1 ships on the WebSocket fallback (this is the actual
|
|
77
|
+
* working transport today). When the native QUIC binding lands, set
|
|
78
|
+
* the AGENTIC_FLOW_QUIC_NATIVE=1 environment variable and the same
|
|
79
|
+
* code path picks up the upgrade with no API changes.
|
|
80
|
+
*/
|
|
81
|
+
export declare function loadQuicTransport(config?: QuicTransportConfig): Promise<AgentTransport>;
|
|
82
|
+
/** Quick capability probe for the doctor / health surface. */
|
|
83
|
+
export declare function isQuicAvailable(): Promise<boolean>;
|
|
84
|
+
export interface TransportCapabilities {
|
|
85
|
+
quicAvailable: boolean;
|
|
86
|
+
webSocketFallbackAvailable: true;
|
|
87
|
+
selectedBackend: 'quic' | 'websocket';
|
|
88
|
+
}
|
|
89
|
+
export declare function getTransportCapabilities(): Promise<TransportCapabilities>;
|
|
90
|
+
export { WebSocketFallbackTransport };
|
|
91
|
+
//# sourceMappingURL=quic-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quic-loader.d.ts","sourceRoot":"","sources":["../../src/transport/quic-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// QUIC Transport Loader with WebSocket fallback
|
|
2
|
+
//
|
|
3
|
+
// Backported from outer repo loader pattern. Exposes a single
|
|
4
|
+
// loadQuicTransport(config) entry point that:
|
|
5
|
+
//
|
|
6
|
+
// 1. Tries to load the WASM-backed QuicClient/QuicServer (real QUIC if a
|
|
7
|
+
// native build is wired in the future).
|
|
8
|
+
// 2. Falls back to WebSocketFallbackTransport when QUIC is unavailable
|
|
9
|
+
// OR when the WASM stub is detected (current state — see
|
|
10
|
+
// crates/agentic-flow-quic/src/wasm.rs comment: WASM build is a stub
|
|
11
|
+
// because browsers can't do raw UDP/QUIC; production QUIC needs
|
|
12
|
+
// native Node.js builds which haven't shipped yet).
|
|
13
|
+
//
|
|
14
|
+
// The fallback uses standard WebSocket (ws://) so it works on all Node
|
|
15
|
+
// versions without complex native dependencies. Same async send/receive
|
|
16
|
+
// API surface as QuicTransport.
|
|
17
|
+
//
|
|
18
|
+
// Federation use case (ruvnet/ruflo ADR-104): two peers on the same
|
|
19
|
+
// tailnet can call loadQuicTransport({ serverName: 'peer.tailnet' }) and
|
|
20
|
+
// exchange signed envelopes today, with zero code change required when
|
|
21
|
+
// the native QUIC build lands later.
|
|
22
|
+
import { logger } from '../utils/logger.js';
|
|
23
|
+
import WebSocket, { WebSocketServer } from 'ws';
|
|
24
|
+
/**
|
|
25
|
+
* WebSocket fallback transport.
|
|
26
|
+
*
|
|
27
|
+
* Spec compliance: implements the AgentTransport interface using
|
|
28
|
+
* `ws://` (or `wss://` if address starts with `wss://`). Each call to
|
|
29
|
+
* `send` lazily opens (or reuses) a connection to `address`. The
|
|
30
|
+
* `receive(address)` call drains the next queued message for that
|
|
31
|
+
* address; if none is queued it polls every 100ms until one arrives.
|
|
32
|
+
*
|
|
33
|
+
* Limits vs real QUIC: no 0-RTT resumption, no multiplexed streams
|
|
34
|
+
* (one TCP connection per peer), TLS handled by the WS layer (use
|
|
35
|
+
* `wss://` for encryption). Performance is "good enough" for federation
|
|
36
|
+
* messages at human/agent rates (≤ 100 RPS per peer).
|
|
37
|
+
*/
|
|
38
|
+
class WebSocketFallbackTransport {
|
|
39
|
+
config;
|
|
40
|
+
connections = new Map();
|
|
41
|
+
messageQueue = new Map();
|
|
42
|
+
connectionsCreated = 0;
|
|
43
|
+
connectionsClosed = 0;
|
|
44
|
+
servers = new Map();
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.config = config;
|
|
47
|
+
}
|
|
48
|
+
static async create(config = {}) {
|
|
49
|
+
const fullConfig = {
|
|
50
|
+
serverName: config.serverName ?? 'localhost',
|
|
51
|
+
maxIdleTimeoutMs: config.maxIdleTimeoutMs ?? 30000,
|
|
52
|
+
maxConcurrentStreams: config.maxConcurrentStreams ?? 100,
|
|
53
|
+
// Not applicable for WebSocket — record but ignore
|
|
54
|
+
enable0Rtt: config.enable0Rtt ?? false,
|
|
55
|
+
};
|
|
56
|
+
return new WebSocketFallbackTransport(fullConfig);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Bind a server-side listener so this transport instance can RECEIVE
|
|
60
|
+
* messages from a remote peer (in addition to sending). Federation
|
|
61
|
+
* peers run BOTH a listener and a client — calling listen(9100) plus
|
|
62
|
+
* send('peer:9100', ...) gives bidirectional connectivity.
|
|
63
|
+
*/
|
|
64
|
+
async listen(port, host = '0.0.0.0') {
|
|
65
|
+
if (this.servers.has(port))
|
|
66
|
+
return;
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const wss = new WebSocketServer({ port, host });
|
|
69
|
+
wss.on('listening', () => {
|
|
70
|
+
this.servers.set(port, wss);
|
|
71
|
+
resolve();
|
|
72
|
+
});
|
|
73
|
+
wss.on('error', reject);
|
|
74
|
+
wss.on('connection', (ws, req) => {
|
|
75
|
+
const remoteAddr = `${req.socket.remoteAddress}:${req.socket.remotePort}`;
|
|
76
|
+
ws.on('message', (raw) => {
|
|
77
|
+
try {
|
|
78
|
+
const message = JSON.parse(raw.toString());
|
|
79
|
+
const queue = this.messageQueue.get(remoteAddr) ?? [];
|
|
80
|
+
queue.push(message);
|
|
81
|
+
this.messageQueue.set(remoteAddr, queue);
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
logger.warn('Dropped malformed inbound WS message', { remoteAddr, err });
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async getOrCreateConnection(address) {
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const existing = this.connections.get(address);
|
|
93
|
+
if (existing && existing.readyState === WebSocket.OPEN) {
|
|
94
|
+
resolve(existing);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const url = address.startsWith('ws://') || address.startsWith('wss://')
|
|
98
|
+
? address
|
|
99
|
+
: `ws://${address}`;
|
|
100
|
+
const ws = new WebSocket(url);
|
|
101
|
+
ws.on('open', () => {
|
|
102
|
+
this.connections.set(address, ws);
|
|
103
|
+
this.connectionsCreated++;
|
|
104
|
+
resolve(ws);
|
|
105
|
+
});
|
|
106
|
+
ws.on('error', (error) => {
|
|
107
|
+
reject(new Error(`WebSocket connection to ${url} failed: ${error.message}`));
|
|
108
|
+
});
|
|
109
|
+
ws.on('close', () => {
|
|
110
|
+
this.connectionsClosed++;
|
|
111
|
+
this.connections.delete(address);
|
|
112
|
+
});
|
|
113
|
+
ws.on('message', (raw) => {
|
|
114
|
+
try {
|
|
115
|
+
const message = JSON.parse(raw.toString());
|
|
116
|
+
const queue = this.messageQueue.get(address) ?? [];
|
|
117
|
+
queue.push(message);
|
|
118
|
+
this.messageQueue.set(address, queue);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
logger.warn('Dropped malformed WebSocket message', { address, err });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
async send(address, message) {
|
|
127
|
+
const ws = await this.getOrCreateConnection(address);
|
|
128
|
+
ws.send(JSON.stringify(message));
|
|
129
|
+
}
|
|
130
|
+
async receive(address) {
|
|
131
|
+
// Fast path
|
|
132
|
+
const queue = this.messageQueue.get(address) ?? [];
|
|
133
|
+
if (queue.length > 0)
|
|
134
|
+
return queue.shift();
|
|
135
|
+
// Poll (caller must time out externally if they don't want to wait)
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
const interval = setInterval(() => {
|
|
138
|
+
const q = this.messageQueue.get(address) ?? [];
|
|
139
|
+
if (q.length > 0) {
|
|
140
|
+
clearInterval(interval);
|
|
141
|
+
resolve(q.shift());
|
|
142
|
+
}
|
|
143
|
+
}, 100);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
async request(address, message) {
|
|
147
|
+
await this.send(address, message);
|
|
148
|
+
return this.receive(address);
|
|
149
|
+
}
|
|
150
|
+
async sendBatch(address, messages) {
|
|
151
|
+
await Promise.all(messages.map((m) => this.send(address, m)));
|
|
152
|
+
}
|
|
153
|
+
async getStats() {
|
|
154
|
+
return {
|
|
155
|
+
active: this.connections.size,
|
|
156
|
+
idle: 0,
|
|
157
|
+
created: this.connectionsCreated,
|
|
158
|
+
closed: this.connectionsClosed,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async close() {
|
|
162
|
+
for (const ws of this.connections.values()) {
|
|
163
|
+
ws.close();
|
|
164
|
+
}
|
|
165
|
+
this.connections.clear();
|
|
166
|
+
this.messageQueue.clear();
|
|
167
|
+
for (const wss of this.servers.values()) {
|
|
168
|
+
await new Promise((resolve) => wss.close(() => resolve()));
|
|
169
|
+
}
|
|
170
|
+
this.servers.clear();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Detect whether the WASM-backed QUIC transport is "real" (i.e. it
|
|
175
|
+
* actually moves bytes on the wire) vs the current stub. The stub
|
|
176
|
+
* returns 0ms for connect+send and never increments the server's
|
|
177
|
+
* received-bytes counter. We probe by observing a documented marker
|
|
178
|
+
* on the WASM module: when it's truly wired the loader function
|
|
179
|
+
* `defaultConfig` returns an object whose round-trip through
|
|
180
|
+
* `WasmQuicClient.new` actually opens a UDP socket — failing fast on
|
|
181
|
+
* an OS that blocks UDP outbound (e.g. some sandboxed CI envs).
|
|
182
|
+
*
|
|
183
|
+
* Until the native build lands this returns false; the loader picks
|
|
184
|
+
* WebSocket. When the native binding is wired this returns true and
|
|
185
|
+
* the loader picks real QUIC. Callers get the same API either way.
|
|
186
|
+
*/
|
|
187
|
+
async function isRealQuicAvailable() {
|
|
188
|
+
try {
|
|
189
|
+
// The WASM file is published in `wasm/quic/` of this package. We
|
|
190
|
+
// do NOT use it for federation today (per the wasm.rs note: it's a
|
|
191
|
+
// stub since browsers can't do UDP). When a native binding is added
|
|
192
|
+
// this probe should switch to detect that binding instead.
|
|
193
|
+
const native = process.env.AGENTIC_FLOW_QUIC_NATIVE === '1';
|
|
194
|
+
return native;
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Public API — load a working transport, preferring real QUIC when
|
|
202
|
+
* available, falling back to WebSocket otherwise. The returned object
|
|
203
|
+
* satisfies the AgentTransport interface in both cases.
|
|
204
|
+
*
|
|
205
|
+
* Example:
|
|
206
|
+
* const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });
|
|
207
|
+
* await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });
|
|
208
|
+
*
|
|
209
|
+
* Federation v1 ships on the WebSocket fallback (this is the actual
|
|
210
|
+
* working transport today). When the native QUIC binding lands, set
|
|
211
|
+
* the AGENTIC_FLOW_QUIC_NATIVE=1 environment variable and the same
|
|
212
|
+
* code path picks up the upgrade with no API changes.
|
|
213
|
+
*/
|
|
214
|
+
export async function loadQuicTransport(config = {}) {
|
|
215
|
+
if (await isRealQuicAvailable()) {
|
|
216
|
+
// Future: wire to the native binding here.
|
|
217
|
+
logger.info('QUIC transport: native binding selected');
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
221
|
+
logger.warn('QUIC native binding not available; using WebSocket fallback. ' +
|
|
222
|
+
'Set AGENTIC_FLOW_QUIC_NATIVE=1 once a native build is installed.');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return WebSocketFallbackTransport.create(config);
|
|
226
|
+
}
|
|
227
|
+
/** Quick capability probe for the doctor / health surface. */
|
|
228
|
+
export async function isQuicAvailable() {
|
|
229
|
+
return isRealQuicAvailable();
|
|
230
|
+
}
|
|
231
|
+
export async function getTransportCapabilities() {
|
|
232
|
+
const quic = await isRealQuicAvailable();
|
|
233
|
+
return {
|
|
234
|
+
quicAvailable: quic,
|
|
235
|
+
webSocketFallbackAvailable: true,
|
|
236
|
+
selectedBackend: quic ? 'quic' : 'websocket',
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
export { WebSocketFallbackTransport };
|
|
240
|
+
//# sourceMappingURL=quic-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quic-loader.js","sourceRoot":"","sources":["../../src/transport/quic-loader.ts"],"names":[],"mappings":"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","sourcesContent":["// QUIC Transport Loader with WebSocket fallback\n//\n// Backported from outer repo loader pattern. Exposes a single\n// loadQuicTransport(config) entry point that:\n//\n// 1. Tries to load the WASM-backed QuicClient/QuicServer (real QUIC if a\n// native build is wired in the future).\n// 2. Falls back to WebSocketFallbackTransport when QUIC is unavailable\n// OR when the WASM stub is detected (current state — see\n// crates/agentic-flow-quic/src/wasm.rs comment: WASM build is a stub\n// because browsers can't do raw UDP/QUIC; production QUIC needs\n// native Node.js builds which haven't shipped yet).\n//\n// The fallback uses standard WebSocket (ws://) so it works on all Node\n// versions without complex native dependencies. Same async send/receive\n// API surface as QuicTransport.\n//\n// Federation use case (ruvnet/ruflo ADR-104): two peers on the same\n// tailnet can call loadQuicTransport({ serverName: 'peer.tailnet' }) and\n// exchange signed envelopes today, with zero code change required when\n// the native QUIC build lands later.\n\nimport { logger } from '../utils/logger.js';\nimport WebSocket, { WebSocketServer, type RawData } from 'ws';\n\n/** Caller-facing config — minimal common surface across both backends. */\nexport interface QuicTransportConfig {\n serverName?: string;\n maxIdleTimeoutMs?: number;\n maxConcurrentStreams?: number;\n enable0Rtt?: boolean;\n}\n\nexport interface AgentMessage {\n id: string;\n type: 'task' | 'result' | 'status' | 'coordination' | 'heartbeat' | string;\n payload: unknown;\n metadata?: Record<string, unknown>;\n}\n\nexport interface PoolStatistics {\n active: number;\n idle: number;\n created: number;\n closed: number;\n}\n\n/** Common interface both real-QUIC and fallback transports satisfy. */\nexport interface AgentTransport {\n send(address: string, message: AgentMessage): Promise<void>;\n receive(address: string): Promise<AgentMessage>;\n request(address: string, message: AgentMessage): Promise<AgentMessage>;\n sendBatch(address: string, messages: AgentMessage[]): Promise<void>;\n getStats(): Promise<PoolStatistics>;\n close(): Promise<void>;\n}\n\n/**\n * WebSocket fallback transport.\n *\n * Spec compliance: implements the AgentTransport interface using\n * `ws://` (or `wss://` if address starts with `wss://`). Each call to\n * `send` lazily opens (or reuses) a connection to `address`. The\n * `receive(address)` call drains the next queued message for that\n * address; if none is queued it polls every 100ms until one arrives.\n *\n * Limits vs real QUIC: no 0-RTT resumption, no multiplexed streams\n * (one TCP connection per peer), TLS handled by the WS layer (use\n * `wss://` for encryption). Performance is \"good enough\" for federation\n * messages at human/agent rates (≤ 100 RPS per peer).\n */\nclass WebSocketFallbackTransport implements AgentTransport {\n private connections = new Map<string, WebSocket>();\n private messageQueue = new Map<string, AgentMessage[]>();\n private connectionsCreated = 0;\n private connectionsClosed = 0;\n private servers = new Map<number, WebSocketServer>();\n\n constructor(private readonly config: Required<QuicTransportConfig>) {}\n\n static async create(config: QuicTransportConfig = {}): Promise<WebSocketFallbackTransport> {\n const fullConfig: Required<QuicTransportConfig> = {\n serverName: config.serverName ?? 'localhost',\n maxIdleTimeoutMs: config.maxIdleTimeoutMs ?? 30000,\n maxConcurrentStreams: config.maxConcurrentStreams ?? 100,\n // Not applicable for WebSocket — record but ignore\n enable0Rtt: config.enable0Rtt ?? false,\n };\n return new WebSocketFallbackTransport(fullConfig);\n }\n\n /**\n * Bind a server-side listener so this transport instance can RECEIVE\n * messages from a remote peer (in addition to sending). Federation\n * peers run BOTH a listener and a client — calling listen(9100) plus\n * send('peer:9100', ...) gives bidirectional connectivity.\n */\n async listen(port: number, host = '0.0.0.0'): Promise<void> {\n if (this.servers.has(port)) return;\n return new Promise((resolve, reject) => {\n const wss = new WebSocketServer({ port, host });\n wss.on('listening', () => {\n this.servers.set(port, wss);\n resolve();\n });\n wss.on('error', reject);\n wss.on('connection', (ws, req) => {\n const remoteAddr = `${req.socket.remoteAddress}:${req.socket.remotePort}`;\n ws.on('message', (raw: RawData) => {\n try {\n const message = JSON.parse(raw.toString()) as AgentMessage;\n const queue = this.messageQueue.get(remoteAddr) ?? [];\n queue.push(message);\n this.messageQueue.set(remoteAddr, queue);\n } catch (err) {\n logger.warn('Dropped malformed inbound WS message', { remoteAddr, err });\n }\n });\n });\n });\n }\n\n private async getOrCreateConnection(address: string): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const existing = this.connections.get(address);\n if (existing && existing.readyState === WebSocket.OPEN) {\n resolve(existing);\n return;\n }\n\n const url = address.startsWith('ws://') || address.startsWith('wss://')\n ? address\n : `ws://${address}`;\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.connections.set(address, ws);\n this.connectionsCreated++;\n resolve(ws);\n });\n\n ws.on('error', (error: Error) => {\n reject(new Error(`WebSocket connection to ${url} failed: ${error.message}`));\n });\n\n ws.on('close', () => {\n this.connectionsClosed++;\n this.connections.delete(address);\n });\n\n ws.on('message', (raw: RawData) => {\n try {\n const message = JSON.parse(raw.toString()) as AgentMessage;\n const queue = this.messageQueue.get(address) ?? [];\n queue.push(message);\n this.messageQueue.set(address, queue);\n } catch (err) {\n logger.warn('Dropped malformed WebSocket message', { address, err });\n }\n });\n });\n }\n\n async send(address: string, message: AgentMessage): Promise<void> {\n const ws = await this.getOrCreateConnection(address);\n ws.send(JSON.stringify(message));\n }\n\n async receive(address: string): Promise<AgentMessage> {\n // Fast path\n const queue = this.messageQueue.get(address) ?? [];\n if (queue.length > 0) return queue.shift()!;\n\n // Poll (caller must time out externally if they don't want to wait)\n return new Promise((resolve) => {\n const interval = setInterval(() => {\n const q = this.messageQueue.get(address) ?? [];\n if (q.length > 0) {\n clearInterval(interval);\n resolve(q.shift()!);\n }\n }, 100);\n });\n }\n\n async request(address: string, message: AgentMessage): Promise<AgentMessage> {\n await this.send(address, message);\n return this.receive(address);\n }\n\n async sendBatch(address: string, messages: AgentMessage[]): Promise<void> {\n await Promise.all(messages.map((m) => this.send(address, m)));\n }\n\n async getStats(): Promise<PoolStatistics> {\n return {\n active: this.connections.size,\n idle: 0,\n created: this.connectionsCreated,\n closed: this.connectionsClosed,\n };\n }\n\n async close(): Promise<void> {\n for (const ws of this.connections.values()) {\n ws.close();\n }\n this.connections.clear();\n this.messageQueue.clear();\n for (const wss of this.servers.values()) {\n await new Promise<void>((resolve) => wss.close(() => resolve()));\n }\n this.servers.clear();\n }\n}\n\n/**\n * Detect whether the WASM-backed QUIC transport is \"real\" (i.e. it\n * actually moves bytes on the wire) vs the current stub. The stub\n * returns 0ms for connect+send and never increments the server's\n * received-bytes counter. We probe by observing a documented marker\n * on the WASM module: when it's truly wired the loader function\n * `defaultConfig` returns an object whose round-trip through\n * `WasmQuicClient.new` actually opens a UDP socket — failing fast on\n * an OS that blocks UDP outbound (e.g. some sandboxed CI envs).\n *\n * Until the native build lands this returns false; the loader picks\n * WebSocket. When the native binding is wired this returns true and\n * the loader picks real QUIC. Callers get the same API either way.\n */\nasync function isRealQuicAvailable(): Promise<boolean> {\n try {\n // The WASM file is published in `wasm/quic/` of this package. We\n // do NOT use it for federation today (per the wasm.rs note: it's a\n // stub since browsers can't do UDP). When a native binding is added\n // this probe should switch to detect that binding instead.\n const native = process.env.AGENTIC_FLOW_QUIC_NATIVE === '1';\n return native;\n } catch {\n return false;\n }\n}\n\n/**\n * Public API — load a working transport, preferring real QUIC when\n * available, falling back to WebSocket otherwise. The returned object\n * satisfies the AgentTransport interface in both cases.\n *\n * Example:\n * const t = await loadQuicTransport({ serverName: 'ruvultra:9100' });\n * await t.send('ruvultra:9100', { id: '1', type: 'task', payload: {...} });\n *\n * Federation v1 ships on the WebSocket fallback (this is the actual\n * working transport today). When the native QUIC binding lands, set\n * the AGENTIC_FLOW_QUIC_NATIVE=1 environment variable and the same\n * code path picks up the upgrade with no API changes.\n */\nexport async function loadQuicTransport(\n config: QuicTransportConfig = {},\n): Promise<AgentTransport> {\n if (await isRealQuicAvailable()) {\n // Future: wire to the native binding here.\n logger.info('QUIC transport: native binding selected');\n } else {\n if (process.env.NODE_ENV !== 'test') {\n logger.warn(\n 'QUIC native binding not available; using WebSocket fallback. ' +\n 'Set AGENTIC_FLOW_QUIC_NATIVE=1 once a native build is installed.',\n );\n }\n }\n return WebSocketFallbackTransport.create(config);\n}\n\n/** Quick capability probe for the doctor / health surface. */\nexport async function isQuicAvailable(): Promise<boolean> {\n return isRealQuicAvailable();\n}\n\nexport interface TransportCapabilities {\n quicAvailable: boolean;\n webSocketFallbackAvailable: true;\n selectedBackend: 'quic' | 'websocket';\n}\n\nexport async function getTransportCapabilities(): Promise<TransportCapabilities> {\n const quic = await isRealQuicAvailable();\n return {\n quicAvailable: quic,\n webSocketFallbackAvailable: true,\n selectedBackend: quic ? 'quic' : 'websocket',\n };\n}\n\nexport { WebSocketFallbackTransport };\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-flow",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.12-fix.1",
|
|
4
4
|
"description": "Production-ready AI agent orchestration platform with 66 specialized agents, 213 MCP tools, ReasoningBank learning memory, and autonomous multi-agent swarms. Built by @ruvnet with Claude Agent SDK, neural networks, memory persistence, GitHub integration, and distributed consensus protocols.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"./router": "./dist/router/index.js",
|
|
24
24
|
"./agent-booster": "./dist/agent-booster/index.js",
|
|
25
25
|
"./transport/quic": "./dist/transport/quic.js",
|
|
26
|
-
"./embeddings": "./dist/embeddings/index.js"
|
|
26
|
+
"./embeddings": "./dist/embeddings/index.js",
|
|
27
|
+
"./transport/loader": "./dist/transport/quic-loader.js"
|
|
27
28
|
},
|
|
28
29
|
"scripts": {
|
|
29
30
|
"postinstall": "node scripts/postinstall.js || true",
|
|
@@ -169,7 +170,7 @@
|
|
|
169
170
|
"ruvector-onnx-embeddings-wasm": "^0.1.2",
|
|
170
171
|
"tiktoken": "^1.0.22",
|
|
171
172
|
"ulid": "^3.0.1",
|
|
172
|
-
"ws": "^8.
|
|
173
|
+
"ws": "^8.20.0",
|
|
173
174
|
"yaml": "^2.8.1",
|
|
174
175
|
"zod": "^3.25.76"
|
|
175
176
|
},
|
|
@@ -177,7 +178,7 @@
|
|
|
177
178
|
"@rollup/rollup-darwin-arm64": "^4.59.0",
|
|
178
179
|
"@ruvector/attention": "^0.1.4",
|
|
179
180
|
"@ruvector/sona": "^0.1.4",
|
|
180
|
-
"agentdb": "^3.0.0-alpha.
|
|
181
|
+
"agentdb": "^3.0.0-alpha.14",
|
|
181
182
|
"better-sqlite3": "^11.10.0",
|
|
182
183
|
"onnxruntime-node": "^1.23.2",
|
|
183
184
|
"sharp": "^0.32.6",
|
|
@@ -104,28 +104,28 @@ export function log(message) {
|
|
|
104
104
|
const len0 = WASM_VECTOR_LEN;
|
|
105
105
|
wasm.log(ptr0, len0);
|
|
106
106
|
}
|
|
107
|
-
export function
|
|
107
|
+
export function __wbg___wbindgen_debug_string_edece8177ad01481(arg0, arg1) {
|
|
108
108
|
const ret = debugString(getObject(arg1));
|
|
109
109
|
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
110
110
|
const len1 = WASM_VECTOR_LEN;
|
|
111
111
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
112
112
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
113
113
|
}
|
|
114
|
-
export function
|
|
114
|
+
export function __wbg___wbindgen_is_function_5cd60d5cf78b4eef(arg0) {
|
|
115
115
|
const ret = typeof(getObject(arg0)) === 'function';
|
|
116
116
|
return ret;
|
|
117
117
|
}
|
|
118
|
-
export function
|
|
118
|
+
export function __wbg___wbindgen_is_undefined_35bb9f4c7fd651d5(arg0) {
|
|
119
119
|
const ret = getObject(arg0) === undefined;
|
|
120
120
|
return ret;
|
|
121
121
|
}
|
|
122
|
-
export function
|
|
122
|
+
export function __wbg___wbindgen_throw_9c31b086c2b26051(arg0, arg1) {
|
|
123
123
|
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
124
124
|
}
|
|
125
|
-
export function
|
|
125
|
+
export function __wbg__wbg_cb_unref_3fa391f3fcdb55f8(arg0) {
|
|
126
126
|
getObject(arg0)._wbg_cb_unref();
|
|
127
127
|
}
|
|
128
|
-
export function
|
|
128
|
+
export function __wbg_call_dfde26266607c996() { return handleError(function (arg0, arg1, arg2) {
|
|
129
129
|
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
|
|
130
130
|
return addHeapObject(ret);
|
|
131
131
|
}, arguments); }
|
|
@@ -143,15 +143,15 @@ export function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
|
|
|
143
143
|
export function __wbg_getRandomValues_ef12552bf5acd2fe() { return handleError(function (arg0, arg1) {
|
|
144
144
|
globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
|
|
145
145
|
}, arguments); }
|
|
146
|
-
export function
|
|
146
|
+
export function __wbg_get_dcf82ab8aad1a593() { return handleError(function (arg0, arg1) {
|
|
147
147
|
const ret = Reflect.get(getObject(arg0), getObject(arg1));
|
|
148
148
|
return addHeapObject(ret);
|
|
149
149
|
}, arguments); }
|
|
150
|
-
export function
|
|
150
|
+
export function __wbg_indexedDB_cbfeacc981615a77() { return handleError(function (arg0) {
|
|
151
151
|
const ret = getObject(arg0).indexedDB;
|
|
152
152
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
153
153
|
}, arguments); }
|
|
154
|
-
export function
|
|
154
|
+
export function __wbg_instanceof_Window_faa5cf994f49cca7(arg0) {
|
|
155
155
|
let result;
|
|
156
156
|
try {
|
|
157
157
|
result = getObject(arg0) instanceof Window;
|
|
@@ -161,21 +161,21 @@ export function __wbg_instanceof_Window_4153c1818a1c0c0b(arg0) {
|
|
|
161
161
|
const ret = result;
|
|
162
162
|
return ret;
|
|
163
163
|
}
|
|
164
|
-
export function
|
|
164
|
+
export function __wbg_log_eb752234eec406d1(arg0) {
|
|
165
165
|
console.log(getObject(arg0));
|
|
166
166
|
}
|
|
167
167
|
export function __wbg_new_227d7c05414eb861() {
|
|
168
168
|
const ret = new Error();
|
|
169
169
|
return addHeapObject(ret);
|
|
170
170
|
}
|
|
171
|
-
export function
|
|
171
|
+
export function __wbg_new_typed_c072c4ce9a2a0cdf(arg0, arg1) {
|
|
172
172
|
try {
|
|
173
173
|
var state0 = {a: arg0, b: arg1};
|
|
174
174
|
var cb0 = (arg0, arg1) => {
|
|
175
175
|
const a = state0.a;
|
|
176
176
|
state0.a = 0;
|
|
177
177
|
try {
|
|
178
|
-
return
|
|
178
|
+
return __wasm_bindgen_func_elem_357(a, state0.b, arg0, arg1);
|
|
179
179
|
} finally {
|
|
180
180
|
state0.a = a;
|
|
181
181
|
}
|
|
@@ -186,22 +186,22 @@ export function __wbg_new_typed_1137602701dc87d4(arg0, arg1) {
|
|
|
186
186
|
state0.a = 0;
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
|
-
export function
|
|
189
|
+
export function __wbg_open_40ab11cdd8f5ac5a() { return handleError(function (arg0, arg1, arg2, arg3) {
|
|
190
190
|
const ret = getObject(arg0).open(getStringFromWasm0(arg1, arg2), arg3 >>> 0);
|
|
191
191
|
return addHeapObject(ret);
|
|
192
192
|
}, arguments); }
|
|
193
|
-
export function
|
|
194
|
-
queueMicrotask(getObject(arg0));
|
|
195
|
-
}
|
|
196
|
-
export function __wbg_queueMicrotask_74d092439f6494c1(arg0) {
|
|
193
|
+
export function __wbg_queueMicrotask_78d584b53af520f5(arg0) {
|
|
197
194
|
const ret = getObject(arg0).queueMicrotask;
|
|
198
195
|
return addHeapObject(ret);
|
|
199
196
|
}
|
|
197
|
+
export function __wbg_queueMicrotask_b39ea83c7f01971a(arg0) {
|
|
198
|
+
queueMicrotask(getObject(arg0));
|
|
199
|
+
}
|
|
200
200
|
export function __wbg_reasoningbankwasm_new(arg0) {
|
|
201
201
|
const ret = ReasoningBankWasm.__wrap(arg0);
|
|
202
202
|
return addHeapObject(ret);
|
|
203
203
|
}
|
|
204
|
-
export function
|
|
204
|
+
export function __wbg_resolve_d17db9352f5a220e(arg0) {
|
|
205
205
|
const ret = Promise.resolve(getObject(arg0));
|
|
206
206
|
return addHeapObject(ret);
|
|
207
207
|
}
|
|
@@ -212,29 +212,29 @@ export function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
|
|
|
212
212
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
213
213
|
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
214
214
|
}
|
|
215
|
-
export function
|
|
215
|
+
export function __wbg_static_accessor_GLOBAL_THIS_02344c9b09eb08a9() {
|
|
216
216
|
const ret = typeof globalThis === 'undefined' ? null : globalThis;
|
|
217
217
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
218
218
|
}
|
|
219
|
-
export function
|
|
219
|
+
export function __wbg_static_accessor_GLOBAL_ac6d4ac874d5cd54() {
|
|
220
220
|
const ret = typeof global === 'undefined' ? null : global;
|
|
221
221
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
222
222
|
}
|
|
223
|
-
export function
|
|
223
|
+
export function __wbg_static_accessor_SELF_9b2406c23aeb2023() {
|
|
224
224
|
const ret = typeof self === 'undefined' ? null : self;
|
|
225
225
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
226
226
|
}
|
|
227
|
-
export function
|
|
227
|
+
export function __wbg_static_accessor_WINDOW_b34d2126934e16ba() {
|
|
228
228
|
const ret = typeof window === 'undefined' ? null : window;
|
|
229
229
|
return isLikeNone(ret) ? 0 : addHeapObject(ret);
|
|
230
230
|
}
|
|
231
|
-
export function
|
|
231
|
+
export function __wbg_then_837494e384b37459(arg0, arg1) {
|
|
232
232
|
const ret = getObject(arg0).then(getObject(arg1));
|
|
233
233
|
return addHeapObject(ret);
|
|
234
234
|
}
|
|
235
235
|
export function __wbindgen_cast_0000000000000001(arg0, arg1) {
|
|
236
236
|
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 95, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
|
|
237
|
-
const ret = makeMutClosure(arg0, arg1,
|
|
237
|
+
const ret = makeMutClosure(arg0, arg1, __wasm_bindgen_func_elem_348);
|
|
238
238
|
return addHeapObject(ret);
|
|
239
239
|
}
|
|
240
240
|
export function __wbindgen_cast_0000000000000002(arg0, arg1) {
|
|
@@ -249,10 +249,10 @@ export function __wbindgen_object_clone_ref(arg0) {
|
|
|
249
249
|
export function __wbindgen_object_drop_ref(arg0) {
|
|
250
250
|
takeObject(arg0);
|
|
251
251
|
}
|
|
252
|
-
function
|
|
252
|
+
function __wasm_bindgen_func_elem_348(arg0, arg1, arg2) {
|
|
253
253
|
try {
|
|
254
254
|
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
255
|
-
wasm.
|
|
255
|
+
wasm.__wasm_bindgen_func_elem_348(retptr, arg0, arg1, addHeapObject(arg2));
|
|
256
256
|
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
257
257
|
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
258
258
|
if (r1) {
|
|
@@ -263,8 +263,8 @@ function __wasm_bindgen_func_elem_346(arg0, arg1, arg2) {
|
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
|
|
266
|
-
function
|
|
267
|
-
wasm.
|
|
266
|
+
function __wasm_bindgen_func_elem_357(arg0, arg1, arg2, arg3) {
|
|
267
|
+
wasm.__wasm_bindgen_func_elem_357(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
const ReasoningBankWasmFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
Binary file
|
|
@@ -10,8 +10,8 @@ export const reasoningbankwasm_new: (a: number, b: number) => number;
|
|
|
10
10
|
export const reasoningbankwasm_searchByCategory: (a: number, b: number, c: number, d: number) => number;
|
|
11
11
|
export const reasoningbankwasm_storePattern: (a: number, b: number, c: number) => number;
|
|
12
12
|
export const init: () => void;
|
|
13
|
-
export const
|
|
14
|
-
export const
|
|
13
|
+
export const __wasm_bindgen_func_elem_348: (a: number, b: number, c: number, d: number) => void;
|
|
14
|
+
export const __wasm_bindgen_func_elem_357: (a: number, b: number, c: number, d: number) => void;
|
|
15
15
|
export const __wbindgen_export: (a: number, b: number) => number;
|
|
16
16
|
export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
17
17
|
export const __wbindgen_export3: (a: number) => void;
|