aws-runtime-bridge 1.8.1 → 1.8.3
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/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +64 -6
- package/dist/adapter/AcodeSdkAdapter.test.js +129 -0
- package/dist/adapter/OpencodeSdkAdapter.js +1 -1
- package/dist/routes/runtime-binding.d.ts.map +1 -1
- package/dist/routes/runtime-binding.js +36 -1
- package/dist/services/mcp-launch-binding-queue.d.ts +7 -0
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +25 -0
- package/package/acode/dist/runtime.d.ts +1 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +265 -31
- package/package/acode/dist/types.d.ts +1 -1
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.js +15 -0
- package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
- package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +79 -1
- package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.test.js +129 -265
- package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,19 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { EventEmitter } from 'node:events';
|
|
3
2
|
import { afterEach, beforeEach, describe, it, mock } from 'node:test';
|
|
4
|
-
import WebSocket from 'ws';
|
|
5
3
|
import { HttpClient } from './http-client.js';
|
|
6
|
-
import { WebSocketClient } from './websocket-client.js';
|
|
7
|
-
class FakeSocket extends EventEmitter {
|
|
8
|
-
readyState = WebSocket.CONNECTING;
|
|
9
|
-
send() { }
|
|
10
|
-
close() {
|
|
11
|
-
this.readyState = WebSocket.CLOSED;
|
|
12
|
-
}
|
|
13
|
-
terminate() {
|
|
14
|
-
this.readyState = WebSocket.CLOSED;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
4
|
describe('HttpClient', () => {
|
|
18
5
|
const originalFetch = global.fetch;
|
|
19
6
|
let fetchCalls = [];
|
|
@@ -296,12 +283,12 @@ describe('HttpClient', () => {
|
|
|
296
283
|
statusText: 'Unauthorized',
|
|
297
284
|
};
|
|
298
285
|
}
|
|
299
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
286
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
300
287
|
return {
|
|
301
288
|
ok: true,
|
|
302
289
|
status: 200,
|
|
303
290
|
statusText: 'OK',
|
|
304
|
-
json: async () => ({
|
|
291
|
+
json: async () => ({ runtimeAccessToken: 'fresh-token' }),
|
|
305
292
|
};
|
|
306
293
|
}
|
|
307
294
|
return {
|
|
@@ -315,17 +302,15 @@ describe('HttpClient', () => {
|
|
|
315
302
|
assert.deepEqual(result, { data: 'retried' });
|
|
316
303
|
assert.equal(fetchCalls.length, 3);
|
|
317
304
|
assert.equal(fetchCalls[0][1].headers['X-Runtime-Token'], 'stale-token');
|
|
318
|
-
assert.equal(fetchCalls[1][0], 'http://127.0.0.1:18081/runtime/binding/
|
|
305
|
+
assert.equal(fetchCalls[1][0], 'http://127.0.0.1:18081/runtime/binding/refresh-token');
|
|
319
306
|
assert.equal(fetchCalls[1][1].body, JSON.stringify({
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
forceRefresh: true,
|
|
323
|
-
rejectedRuntimeAccessToken: 'stale-token',
|
|
307
|
+
agentId: 'agent-1',
|
|
308
|
+
currentToken: 'stale-token',
|
|
324
309
|
}));
|
|
325
310
|
assert.equal(fetchCalls[2][1].headers['X-Runtime-Token'], 'fresh-token');
|
|
326
311
|
assert.equal(config.runtimeAccessToken, 'fresh-token');
|
|
327
312
|
});
|
|
328
|
-
it('shares one
|
|
313
|
+
it('shares one bridge token refresh across concurrent 401 responses', async () => {
|
|
329
314
|
const config = {
|
|
330
315
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
331
316
|
heartbeatInterval: 15000,
|
|
@@ -339,13 +324,13 @@ describe('HttpClient', () => {
|
|
|
339
324
|
const staleTokenCalls = new Set();
|
|
340
325
|
global.fetch = async (url, options) => {
|
|
341
326
|
fetchCalls.push([url.toString(), options]);
|
|
342
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
327
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
343
328
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
344
329
|
return {
|
|
345
330
|
ok: true,
|
|
346
331
|
status: 200,
|
|
347
332
|
statusText: 'OK',
|
|
348
|
-
json: async () => ({
|
|
333
|
+
json: async () => ({ runtimeAccessToken: 'fresh-token' }),
|
|
349
334
|
};
|
|
350
335
|
}
|
|
351
336
|
const body = JSON.parse(String(options?.body || '{}'));
|
|
@@ -372,10 +357,10 @@ describe('HttpClient', () => {
|
|
|
372
357
|
assert.deepEqual(first, { tool: 'get_memory_stats', token: 'fresh-token' });
|
|
373
358
|
assert.deepEqual(second, { tool: 'discover_group_rooms', token: 'fresh-token' });
|
|
374
359
|
assert.deepEqual(staleTokenCalls, new Set(['get_memory_stats', 'discover_group_rooms']));
|
|
375
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/
|
|
360
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/refresh-token').length, 1);
|
|
376
361
|
assert.equal(config.runtimeAccessToken, 'fresh-token');
|
|
377
362
|
});
|
|
378
|
-
it('
|
|
363
|
+
it('throws when no runtimeAccessToken and no bridge for startup', async () => {
|
|
379
364
|
const config = {
|
|
380
365
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
381
366
|
heartbeatInterval: 15000,
|
|
@@ -385,270 +370,139 @@ describe('HttpClient', () => {
|
|
|
385
370
|
runtimeBridgeBaseUrl: 'http://127.0.0.1:18081',
|
|
386
371
|
};
|
|
387
372
|
const client = new HttpClient(config);
|
|
388
|
-
global.fetch = async (
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
statusText: 'OK',
|
|
396
|
-
json: async () => ({ ok: true, runtimeAccessToken: 'startup-token' }),
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
const body = JSON.parse(String(options?.body || '{}'));
|
|
400
|
-
return {
|
|
401
|
-
ok: true,
|
|
402
|
-
status: 200,
|
|
403
|
-
statusText: 'OK',
|
|
404
|
-
json: async () => ({ tool: body.tool, token: options.headers['X-Runtime-Token'] }),
|
|
405
|
-
};
|
|
406
|
-
};
|
|
407
|
-
const [first, second] = await Promise.all([
|
|
408
|
-
client.callTool('get_memory_stats', { agentId: 'agent-1' }),
|
|
409
|
-
client.callTool('discover_group_rooms', { agentId: 'agent-1' }),
|
|
410
|
-
]);
|
|
411
|
-
assert.deepEqual(first, { tool: 'get_memory_stats', token: 'startup-token' });
|
|
412
|
-
assert.deepEqual(second, { tool: 'discover_group_rooms', token: 'startup-token' });
|
|
413
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/request-token').length, 1);
|
|
414
|
-
assert.equal(fetchCalls[0][1].body, JSON.stringify({
|
|
415
|
-
userId: 'user-1',
|
|
416
|
-
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
417
|
-
forceRefresh: false,
|
|
418
|
-
}));
|
|
419
|
-
assert.equal(config.runtimeAccessToken, 'startup-token');
|
|
373
|
+
global.fetch = async () => ({
|
|
374
|
+
ok: true,
|
|
375
|
+
status: 200,
|
|
376
|
+
statusText: 'OK',
|
|
377
|
+
json: async () => ({ result: 'success' }),
|
|
378
|
+
});
|
|
379
|
+
await assert.rejects(() => client.callTool('get_memory_stats', { agentId: 'agent-1' }), /runtimeAccessToken is required; MCP nodes must claim a session token from launch binding/);
|
|
420
380
|
});
|
|
421
|
-
it('
|
|
381
|
+
it('throws original 401 when bridge refresh fails', async () => {
|
|
422
382
|
const config = {
|
|
423
383
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
424
384
|
heartbeatInterval: 15000,
|
|
425
385
|
reconnectInterval: 200,
|
|
426
386
|
maxReconnectAttempts: -1,
|
|
427
387
|
userId: 'user-1',
|
|
388
|
+
runtimeAccessToken: 'stale-token',
|
|
428
389
|
runtimeBridgeBaseUrl: 'http://127.0.0.1:18081',
|
|
429
390
|
};
|
|
430
391
|
const client = new HttpClient(config);
|
|
431
|
-
let tokenRequestCount = 0;
|
|
432
392
|
global.fetch = async (url, options) => {
|
|
433
393
|
fetchCalls.push([url.toString(), options]);
|
|
434
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
394
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
395
|
+
return {
|
|
396
|
+
ok: false,
|
|
397
|
+
status: 503,
|
|
398
|
+
statusText: 'Service Unavailable',
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
ok: false,
|
|
403
|
+
status: 401,
|
|
404
|
+
statusText: 'Unauthorized',
|
|
405
|
+
};
|
|
406
|
+
};
|
|
407
|
+
await assert.rejects(() => client.callTool('get_memory_stats', { agentId: 'agent-1' }), /MCP tool get_memory_stats call failed: 401 Unauthorized/);
|
|
408
|
+
// Can retry again after failure
|
|
409
|
+
global.fetch = async (url, options) => {
|
|
410
|
+
fetchCalls.push([url.toString(), options]);
|
|
411
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
444
412
|
return {
|
|
445
413
|
ok: true,
|
|
446
414
|
status: 200,
|
|
447
415
|
statusText: 'OK',
|
|
448
|
-
json: async () => ({
|
|
416
|
+
json: async () => ({ runtimeAccessToken: 'recovered-token' }),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
const token = options.headers['X-Runtime-Token'];
|
|
420
|
+
if (token === 'recovered-token') {
|
|
421
|
+
return {
|
|
422
|
+
ok: true,
|
|
423
|
+
status: 200,
|
|
424
|
+
statusText: 'OK',
|
|
425
|
+
json: async () => ({ token }),
|
|
449
426
|
};
|
|
450
427
|
}
|
|
451
428
|
return {
|
|
452
|
-
ok:
|
|
453
|
-
status:
|
|
454
|
-
statusText: '
|
|
455
|
-
json: async () => ({ token: options.headers['X-Runtime-Token'] }),
|
|
429
|
+
ok: false,
|
|
430
|
+
status: 401,
|
|
431
|
+
statusText: 'Unauthorized',
|
|
456
432
|
};
|
|
457
433
|
};
|
|
458
|
-
await assert.rejects(() => client.callTool('get_memory_stats', { agentId: 'agent-1' }), /Failed to request runtime token from runtime-bridge: 503 Service Unavailable - bridge unavailable/);
|
|
459
434
|
const result = await client.callTool('get_memory_stats', { agentId: 'agent-1' });
|
|
460
435
|
assert.deepEqual(result, { token: 'recovered-token' });
|
|
461
|
-
assert.equal(tokenRequestCount, 2);
|
|
462
436
|
assert.equal(config.runtimeAccessToken, 'recovered-token');
|
|
463
437
|
});
|
|
464
|
-
it('
|
|
438
|
+
it('returns 401 when bridge refresh has no new token for running agent', async () => {
|
|
465
439
|
const config = {
|
|
466
440
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
467
|
-
heartbeatInterval:
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
maxReconnectAttempts: 2,
|
|
471
|
-
userId: 'user-1',
|
|
441
|
+
heartbeatInterval: 15000,
|
|
442
|
+
reconnectInterval: 200,
|
|
443
|
+
maxReconnectAttempts: -1,
|
|
472
444
|
runtimeAccessToken: 'stale-token',
|
|
473
445
|
runtimeBridgeBaseUrl: 'http://127.0.0.1:18081',
|
|
474
446
|
};
|
|
475
|
-
const
|
|
476
|
-
let tokenRequestCount = 0;
|
|
477
|
-
let websocketAttempt = 0;
|
|
478
|
-
const websocketUrls = [];
|
|
479
|
-
let releaseRefresh;
|
|
480
|
-
const refreshGate = new Promise((resolve) => {
|
|
481
|
-
releaseRefresh = resolve;
|
|
482
|
-
});
|
|
447
|
+
const client = new HttpClient(config);
|
|
483
448
|
global.fetch = async (url, options) => {
|
|
484
449
|
fetchCalls.push([url.toString(), options]);
|
|
485
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
486
|
-
|
|
487
|
-
await refreshGate;
|
|
488
|
-
return {
|
|
489
|
-
ok: true,
|
|
490
|
-
status: 200,
|
|
491
|
-
statusText: 'OK',
|
|
492
|
-
json: async () => ({ ok: true, runtimeAccessToken: 'shared-fresh-token' }),
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
const body = JSON.parse(String(options?.body || '{}'));
|
|
496
|
-
const token = options.headers['X-Runtime-Token'];
|
|
497
|
-
if (token === 'stale-token') {
|
|
450
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
451
|
+
// Bridge says no new token available (409 conflict)
|
|
498
452
|
return {
|
|
499
453
|
ok: false,
|
|
500
|
-
status:
|
|
501
|
-
statusText: '
|
|
454
|
+
status: 409,
|
|
455
|
+
statusText: 'Conflict',
|
|
456
|
+
json: async () => ({ error: 'token_unchanged' }),
|
|
502
457
|
};
|
|
503
458
|
}
|
|
504
459
|
return {
|
|
505
|
-
ok:
|
|
506
|
-
status:
|
|
507
|
-
statusText: '
|
|
508
|
-
json: async () => ({ tool: body.tool, token }),
|
|
460
|
+
ok: false,
|
|
461
|
+
status: 401,
|
|
462
|
+
statusText: 'Unauthorized',
|
|
509
463
|
};
|
|
510
464
|
};
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
if (websocketAttempt === 1) {
|
|
519
|
-
socket.readyState = WebSocket.CLOSED;
|
|
520
|
-
socket.emit('close', 1008, Buffer.from('policy violation'));
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
return socket;
|
|
524
|
-
});
|
|
525
|
-
try {
|
|
526
|
-
wsClient.on('error', () => {
|
|
527
|
-
// suppress unhandled error event in test environment
|
|
528
|
-
});
|
|
529
|
-
const websocketConnected = wsClient.connect('agent-1');
|
|
530
|
-
const httpCall = httpClient.callTool('get_memory_stats', { agentId: 'agent-1' });
|
|
531
|
-
await new Promise((resolve, reject) => {
|
|
532
|
-
const timer = setTimeout(() => reject(new Error('expected both refresh waiters')), 500);
|
|
533
|
-
const interval = setInterval(() => {
|
|
534
|
-
if (tokenRequestCount === 1 && config.runtimeAccessTokenRefreshPromise) {
|
|
535
|
-
clearInterval(interval);
|
|
536
|
-
clearTimeout(timer);
|
|
537
|
-
resolve();
|
|
538
|
-
}
|
|
539
|
-
}, 5);
|
|
540
|
-
});
|
|
541
|
-
const websocketReconnected = new Promise((resolve, reject) => {
|
|
542
|
-
const timer = setTimeout(() => reject(new Error('expected websocket reconnect')), 500);
|
|
543
|
-
wsClient.on('connected', () => {
|
|
544
|
-
if (websocketAttempt >= 2) {
|
|
545
|
-
clearTimeout(timer);
|
|
546
|
-
resolve();
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
});
|
|
550
|
-
releaseRefresh?.();
|
|
551
|
-
const result = await httpCall;
|
|
552
|
-
await websocketConnected;
|
|
553
|
-
await websocketReconnected;
|
|
554
|
-
assert.deepEqual(result, { tool: 'get_memory_stats', token: 'shared-fresh-token' });
|
|
555
|
-
assert.equal(tokenRequestCount, 1);
|
|
556
|
-
assert.equal(config.runtimeAccessToken, 'shared-fresh-token');
|
|
557
|
-
assert.equal(new URL(websocketUrls[1] || '').searchParams.get('runtimeAccessToken'), 'shared-fresh-token');
|
|
558
|
-
}
|
|
559
|
-
finally {
|
|
560
|
-
releaseRefresh?.();
|
|
561
|
-
wsClient.disconnect();
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
it('shares one forced refresh among multiple waiters after an initial non-forced refresh', async () => {
|
|
465
|
+
await assert.rejects(() => client.callTool('get_memory_stats', { agentId: 'agent-1' }), /MCP tool get_memory_stats call failed: 401 Unauthorized/);
|
|
466
|
+
// 1 initial MCP call + 1 refresh attempt + 0 retries (refresh failed)
|
|
467
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:8080/mcp/call').length, 1);
|
|
468
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/refresh-token').length, 1);
|
|
469
|
+
assert.equal(config.runtimeAccessToken, 'stale-token');
|
|
470
|
+
});
|
|
471
|
+
it('returns 404 from bridge refresh when agent has no cached token', async () => {
|
|
565
472
|
const config = {
|
|
566
473
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
567
474
|
heartbeatInterval: 15000,
|
|
568
475
|
reconnectInterval: 200,
|
|
569
476
|
maxReconnectAttempts: -1,
|
|
570
477
|
userId: 'user-1',
|
|
478
|
+
runtimeAccessToken: 'stale-token',
|
|
571
479
|
runtimeBridgeBaseUrl: 'http://127.0.0.1:18081',
|
|
572
480
|
};
|
|
573
|
-
const
|
|
574
|
-
const forceClient = new HttpClient(config);
|
|
575
|
-
let tokenRequestCount = 0;
|
|
576
|
-
let forceRequestCount = 0;
|
|
577
|
-
let releaseInitialRefresh;
|
|
578
|
-
const initialRefreshGate = new Promise((resolve) => {
|
|
579
|
-
releaseInitialRefresh = resolve;
|
|
580
|
-
});
|
|
481
|
+
const client = new HttpClient(config);
|
|
581
482
|
global.fetch = async (url, options) => {
|
|
582
483
|
fetchCalls.push([url.toString(), options]);
|
|
583
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
584
|
-
|
|
585
|
-
const body = JSON.parse(String(options?.body || '{}'));
|
|
586
|
-
if (body.forceRefresh) {
|
|
587
|
-
forceRequestCount += 1;
|
|
588
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
589
|
-
return {
|
|
590
|
-
ok: true,
|
|
591
|
-
status: 200,
|
|
592
|
-
statusText: 'OK',
|
|
593
|
-
json: async () => ({ ok: true, runtimeAccessToken: 'forced-token' }),
|
|
594
|
-
};
|
|
595
|
-
}
|
|
596
|
-
await initialRefreshGate;
|
|
597
|
-
return {
|
|
598
|
-
ok: true,
|
|
599
|
-
status: 200,
|
|
600
|
-
statusText: 'OK',
|
|
601
|
-
json: async () => ({ ok: true, runtimeAccessToken: 'initial-token' }),
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
const body = JSON.parse(String(options?.body || '{}'));
|
|
605
|
-
const token = options.headers['X-Runtime-Token'];
|
|
606
|
-
if (token === 'initial-token') {
|
|
484
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
485
|
+
// Bridge has no cached token for this agent
|
|
607
486
|
return {
|
|
608
487
|
ok: false,
|
|
609
|
-
status:
|
|
610
|
-
statusText: '
|
|
488
|
+
status: 404,
|
|
489
|
+
statusText: 'Not Found',
|
|
490
|
+
json: async () => ({ error: 'no cached token for agent' }),
|
|
611
491
|
};
|
|
612
492
|
}
|
|
613
493
|
return {
|
|
614
|
-
ok:
|
|
615
|
-
status:
|
|
616
|
-
statusText: '
|
|
617
|
-
json: async () => ({ tool: body.tool, token }),
|
|
494
|
+
ok: false,
|
|
495
|
+
status: 401,
|
|
496
|
+
statusText: 'Unauthorized',
|
|
618
497
|
};
|
|
619
498
|
};
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
clearTimeout(timer);
|
|
628
|
-
resolve();
|
|
629
|
-
}
|
|
630
|
-
}, 5);
|
|
631
|
-
});
|
|
632
|
-
const firstForceCall = forceClient.callTool('get_memory_stats', { agentId: 'agent-1' });
|
|
633
|
-
const secondForceCall = forceClient.callTool('discover_group_rooms', { agentId: 'agent-1' });
|
|
634
|
-
releaseInitialRefresh?.();
|
|
635
|
-
const [initialResult, firstForceResult, secondForceResult] = await Promise.all([
|
|
636
|
-
initialCall,
|
|
637
|
-
firstForceCall,
|
|
638
|
-
secondForceCall,
|
|
639
|
-
]);
|
|
640
|
-
assert.deepEqual(initialResult, { tool: 'get_profile', token: 'forced-token' });
|
|
641
|
-
assert.deepEqual(firstForceResult, { tool: 'get_memory_stats', token: 'forced-token' });
|
|
642
|
-
assert.deepEqual(secondForceResult, { tool: 'discover_group_rooms', token: 'forced-token' });
|
|
643
|
-
assert.equal(tokenRequestCount, 2);
|
|
644
|
-
assert.equal(forceRequestCount, 1);
|
|
645
|
-
assert.equal(config.runtimeAccessToken, 'forced-token');
|
|
646
|
-
}
|
|
647
|
-
finally {
|
|
648
|
-
releaseInitialRefresh?.();
|
|
649
|
-
}
|
|
650
|
-
});
|
|
651
|
-
it('does not retry 401 more than once after forced token refresh', async () => {
|
|
499
|
+
await assert.rejects(() => client.callTool('get_profile', { agentId: 'agent-unknown' }), /MCP tool get_profile call failed: 401 Unauthorized/);
|
|
500
|
+
// 1 initial MCP call + 1 refresh attempt (404) + 0 retries
|
|
501
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:8080/mcp/call').length, 1);
|
|
502
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/refresh-token').length, 1);
|
|
503
|
+
assert.equal(config.runtimeAccessToken, 'stale-token');
|
|
504
|
+
});
|
|
505
|
+
it('does not retry 401 after bridge refresh returns same token', async () => {
|
|
652
506
|
const config = {
|
|
653
507
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
654
508
|
heartbeatInterval: 15000,
|
|
@@ -660,12 +514,13 @@ describe('HttpClient', () => {
|
|
|
660
514
|
const client = new HttpClient(config);
|
|
661
515
|
global.fetch = async (url, options) => {
|
|
662
516
|
fetchCalls.push([url.toString(), options]);
|
|
663
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
517
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
518
|
+
// Bridge returns same token
|
|
664
519
|
return {
|
|
665
520
|
ok: true,
|
|
666
521
|
status: 200,
|
|
667
522
|
statusText: 'OK',
|
|
668
|
-
json: async () => ({
|
|
523
|
+
json: async () => ({ runtimeAccessToken: 'stale-token' }),
|
|
669
524
|
};
|
|
670
525
|
}
|
|
671
526
|
return {
|
|
@@ -675,11 +530,11 @@ describe('HttpClient', () => {
|
|
|
675
530
|
};
|
|
676
531
|
};
|
|
677
532
|
await assert.rejects(() => client.callTool('my_task', { agentId: 'agent-1' }), /MCP tool my_task call failed: 401 Unauthorized/);
|
|
678
|
-
|
|
679
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:8080/mcp/call').length,
|
|
680
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/
|
|
533
|
+
// 1 initial MCP call + 1 refresh + 0 retries (same token, not updated)
|
|
534
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:8080/mcp/call').length, 1);
|
|
535
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/refresh-token').length, 1);
|
|
681
536
|
});
|
|
682
|
-
it('
|
|
537
|
+
it('retries refresh on second call if first call 401 with different fresh token', async () => {
|
|
683
538
|
const config = {
|
|
684
539
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
685
540
|
heartbeatInterval: 15000,
|
|
@@ -690,14 +545,24 @@ describe('HttpClient', () => {
|
|
|
690
545
|
runtimeBridgeBaseUrl: 'http://127.0.0.1:18081',
|
|
691
546
|
};
|
|
692
547
|
const client = new HttpClient(config);
|
|
548
|
+
let refreshCount = 0;
|
|
693
549
|
global.fetch = async (url, options) => {
|
|
694
550
|
fetchCalls.push([url.toString(), options]);
|
|
695
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
551
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
552
|
+
refreshCount += 1;
|
|
696
553
|
return {
|
|
697
554
|
ok: true,
|
|
698
555
|
status: 200,
|
|
699
556
|
statusText: 'OK',
|
|
700
|
-
json: async () => ({
|
|
557
|
+
json: async () => ({ runtimeAccessToken: `fresh-token-${refreshCount}` }),
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
const token = options.headers['X-Runtime-Token'];
|
|
561
|
+
if (token && token.startsWith('fresh-token-')) {
|
|
562
|
+
return {
|
|
563
|
+
ok: false,
|
|
564
|
+
status: 401,
|
|
565
|
+
statusText: 'Unauthorized',
|
|
701
566
|
};
|
|
702
567
|
}
|
|
703
568
|
return {
|
|
@@ -707,13 +572,12 @@ describe('HttpClient', () => {
|
|
|
707
572
|
};
|
|
708
573
|
};
|
|
709
574
|
await assert.rejects(() => client.callTool('discover_group_rooms', { agentId: 'agent-1' }), /MCP tool discover_group_rooms call failed: 401 Unauthorized/);
|
|
575
|
+
// Second call also tries refresh
|
|
710
576
|
await assert.rejects(() => client.callTool('poll_message', { agentId: 'agent-1' }), /MCP tool poll_message call failed: 401 Unauthorized/);
|
|
711
|
-
assert.equal(config.runtimeAccessToken, 'fresh-
|
|
712
|
-
assert.equal(
|
|
713
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/request-token').length, 1);
|
|
714
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:8080/mcp/call').length, 3);
|
|
577
|
+
assert.equal(config.runtimeAccessToken, 'fresh-token-2');
|
|
578
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/refresh-token').length, 2);
|
|
715
579
|
});
|
|
716
|
-
it('
|
|
580
|
+
it('shares one refresh promise among concurrent 401 calls', async () => {
|
|
717
581
|
const config = {
|
|
718
582
|
serverUrl: 'ws://localhost:8080/ws/agent',
|
|
719
583
|
heartbeatInterval: 15000,
|
|
@@ -724,32 +588,27 @@ describe('HttpClient', () => {
|
|
|
724
588
|
runtimeBridgeBaseUrl: 'http://127.0.0.1:18081',
|
|
725
589
|
};
|
|
726
590
|
const client = new HttpClient(config);
|
|
727
|
-
let
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
resolveFreshTokenValidationStarted = resolve;
|
|
731
|
-
});
|
|
732
|
-
const freshTokenValidationReleased = new Promise((resolve) => {
|
|
733
|
-
releaseFreshTokenValidation = resolve;
|
|
591
|
+
let resolveRefresh = () => { };
|
|
592
|
+
const refreshGate = new Promise((resolve) => {
|
|
593
|
+
resolveRefresh = resolve;
|
|
734
594
|
});
|
|
595
|
+
let refreshCallCount = 0;
|
|
735
596
|
let freshTokenMcpCallCount = 0;
|
|
736
597
|
global.fetch = async (url, options) => {
|
|
737
598
|
fetchCalls.push([url.toString(), options]);
|
|
738
|
-
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/
|
|
599
|
+
if (url.toString() === 'http://127.0.0.1:18081/runtime/binding/refresh-token') {
|
|
600
|
+
refreshCallCount += 1;
|
|
601
|
+
await refreshGate;
|
|
739
602
|
return {
|
|
740
603
|
ok: true,
|
|
741
604
|
status: 200,
|
|
742
605
|
statusText: 'OK',
|
|
743
|
-
json: async () => ({
|
|
606
|
+
json: async () => ({ runtimeAccessToken: 'fresh-but-rejected-token' }),
|
|
744
607
|
};
|
|
745
608
|
}
|
|
746
609
|
const requestHeaders = (options?.headers ?? {});
|
|
747
610
|
if (requestHeaders.Authorization === 'Bearer fresh-but-rejected-token') {
|
|
748
611
|
freshTokenMcpCallCount += 1;
|
|
749
|
-
if (freshTokenMcpCallCount === 1) {
|
|
750
|
-
resolveFreshTokenValidationStarted();
|
|
751
|
-
await freshTokenValidationReleased;
|
|
752
|
-
}
|
|
753
612
|
}
|
|
754
613
|
return {
|
|
755
614
|
ok: false,
|
|
@@ -758,14 +617,19 @@ describe('HttpClient', () => {
|
|
|
758
617
|
};
|
|
759
618
|
};
|
|
760
619
|
const firstCall = client.callTool('discover_group_rooms', { agentId: 'agent-1' });
|
|
761
|
-
|
|
762
|
-
await
|
|
763
|
-
|
|
620
|
+
// Wait for the refresh to start
|
|
621
|
+
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
622
|
+
// Second call should share the same refresh promise
|
|
623
|
+
const secondCall = client.callTool('poll_message', { agentId: 'agent-1' });
|
|
624
|
+
resolveRefresh();
|
|
764
625
|
await assert.rejects(() => firstCall, /MCP tool discover_group_rooms call failed: 401 Unauthorized/);
|
|
626
|
+
await assert.rejects(() => secondCall, /MCP tool poll_message call failed: 401 Unauthorized/);
|
|
765
627
|
assert.equal(config.runtimeAccessToken, 'fresh-but-rejected-token');
|
|
766
|
-
|
|
767
|
-
assert.equal(
|
|
768
|
-
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:
|
|
628
|
+
// Only one refresh call to bridge
|
|
629
|
+
assert.equal(refreshCallCount, 1);
|
|
630
|
+
assert.equal(fetchCalls.filter(([url]) => url === 'http://127.0.0.1:18081/runtime/binding/refresh-token').length, 1);
|
|
631
|
+
// Both tools retried once with fresh token
|
|
632
|
+
assert.equal(freshTokenMcpCallCount, 2);
|
|
769
633
|
});
|
|
770
634
|
it('handles 404 not found response', async () => {
|
|
771
635
|
const config = {
|