@antseed/cli 0.1.189 → 0.1.191
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/cli/commands/seller/start.d.ts.map +1 -1
- package/dist/cli/commands/seller/start.js +2 -1
- package/dist/cli/commands/seller/start.js.map +1 -1
- package/dist/config/service-metadata.test.js +1 -1
- package/dist/config/service-metadata.test.js.map +1 -1
- package/dist/gateway/routing-through-gateway.test.d.ts +2 -0
- package/dist/gateway/routing-through-gateway.test.d.ts.map +1 -0
- package/dist/gateway/routing-through-gateway.test.js +177 -0
- package/dist/gateway/routing-through-gateway.test.js.map +1 -0
- package/dist/plugins/registry.d.ts.map +1 -1
- package/dist/plugins/registry.js +9 -3
- package/dist/plugins/registry.js.map +1 -1
- package/dist/proxy/buyer-proxy.d.ts +8 -2
- package/dist/proxy/buyer-proxy.d.ts.map +1 -1
- package/dist/proxy/buyer-proxy.js +37 -8
- package/dist/proxy/buyer-proxy.js.map +1 -1
- package/dist/proxy/buyer-proxy.test.js +51 -41
- package/dist/proxy/buyer-proxy.test.js.map +1 -1
- package/dist/proxy/conversation-store.test.js +2 -2
- package/dist/proxy/conversation-store.test.js.map +1 -1
- package/dist/proxy/gateway-policy.test.js +3 -3
- package/dist/proxy/gateway-policy.test.js.map +1 -1
- package/dist/proxy/network-models.d.ts +6 -0
- package/dist/proxy/network-models.d.ts.map +1 -1
- package/dist/proxy/network-models.js.map +1 -1
- package/dist/proxy/request-utils.d.ts +10 -10
- package/dist/proxy/request-utils.d.ts.map +1 -1
- package/dist/proxy/request-utils.js +8 -30
- package/dist/proxy/request-utils.js.map +1 -1
- package/dist/proxy/router-execution.d.ts +3 -3
- package/dist/proxy/router-execution.d.ts.map +1 -1
- package/dist/proxy/router-execution.js +9 -7
- package/dist/proxy/router-execution.js.map +1 -1
- package/dist/proxy/router-execution.test.js +6 -6
- package/dist/proxy/router-execution.test.js.map +1 -1
- package/dist/proxy/routing-services.d.ts +17 -6
- package/dist/proxy/routing-services.d.ts.map +1 -1
- package/dist/proxy/routing-services.js +31 -23
- package/dist/proxy/routing-services.js.map +1 -1
- package/dist/proxy/routing-services.test.js +4 -4
- package/dist/proxy/routing-services.test.js.map +1 -1
- package/package.json +9 -9
|
@@ -21,15 +21,15 @@ function makePeer(seed, providers) {
|
|
|
21
21
|
providers,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
test('the buyer switches between a model and a
|
|
24
|
+
test('the buyer switches between a model and a routing service without replacing the plugin', async () => {
|
|
25
25
|
const inferencePeer = makeRankedRoutingFixture().peers[0];
|
|
26
26
|
const routingPeer = makePeer('d', ['alpha']);
|
|
27
27
|
routingPeer.metadata = {
|
|
28
28
|
peerId: routingPeer.peerId, version: 12, timestamp: Date.now(), signature: '', region: 'test',
|
|
29
29
|
providers: [{ provider: 'alpha', services: ['alpha-route'], maxConcurrency: 1, currentLoad: 0,
|
|
30
30
|
defaultPricing: { inputUsdPerMillion: 0, outputUsdPerMillion: 0 },
|
|
31
|
-
serviceApiProtocols: { 'alpha-route': ['
|
|
32
|
-
serviceUnitBillingModels: { 'alpha-route': { '
|
|
31
|
+
serviceApiProtocols: { 'alpha-route': ['irp-suggest'] },
|
|
32
|
+
serviceUnitBillingModels: { 'alpha-route': { 'irp-suggest': {
|
|
33
33
|
version: 1, components: [{ unit: 'completed_requests', priceUsd: 0.001 }],
|
|
34
34
|
} } },
|
|
35
35
|
}],
|
|
@@ -73,8 +73,18 @@ test('the buyer switches between a model and a model-routing service without rep
|
|
|
73
73
|
assert.equal((await setModel()).statusCode, 200);
|
|
74
74
|
assert.equal((await infer()).statusCode, 200);
|
|
75
75
|
assert.equal(requests.length, 1);
|
|
76
|
-
const selection = { kind: 'router', service: { peerId: routingPeer.peerId, provider: 'alpha', serviceId: 'alpha-route' },
|
|
76
|
+
const selection = { kind: 'router', service: { peerId: routingPeer.peerId, provider: 'alpha', serviceId: 'alpha-route' }, options: { cost_quality_tradeoff: 1 } };
|
|
77
|
+
// Options are checked against the router's advertised protocol (irp-suggest) when it is saved.
|
|
78
|
+
for (const options of [{ cost_quality_tradeoff: 11 }, { cost_quality_tradeoff: 2.5 }, { tier: 'fast' }]) {
|
|
79
|
+
const refused = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody({ ...selection, options }) }));
|
|
80
|
+
assert.equal(refused.statusCode, 400, refused.body);
|
|
81
|
+
}
|
|
77
82
|
assert.equal((await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody(selection) }))).statusCode, 200);
|
|
83
|
+
// ...and per request, before any ranking is bought.
|
|
84
|
+
const badRequest = await invokeProxy(proxy, makeProxyRequest({ body: { model: 'antseed', messages: [{ role: 'user', content: 'Hello' }], routing: { cost_quality_tradeoff: 11 } } }));
|
|
85
|
+
assert.equal(badRequest.statusCode, 400, badRequest.body);
|
|
86
|
+
assert.equal(JSON.parse(badRequest.body).error.code, 'invalid_routing');
|
|
87
|
+
assert.equal(requests.length, 1);
|
|
78
88
|
const routed = await infer();
|
|
79
89
|
assert.equal(routed.statusCode, 200, routed.body);
|
|
80
90
|
assert.deepEqual(requests.map(request => request.path.split('?')[0]), ['/v1/chat/completions', '/v1/routing/models', '/v1/routing/rank', '/v1/chat/completions']);
|
|
@@ -138,7 +148,7 @@ test('the buyer and chat router selections pass their cost/quality tradeoff to t
|
|
|
138
148
|
routingPeer.metadata = { peerId: routingPeer.peerId, version: 12, region: 'test', timestamp: Date.now(), signature: '',
|
|
139
149
|
providers: [{ provider: 'alternative', services: ['route'], maxConcurrency: 1, currentLoad: 0,
|
|
140
150
|
defaultPricing: { inputUsdPerMillion: 0, outputUsdPerMillion: 0 },
|
|
141
|
-
serviceApiProtocols: { route: ['
|
|
151
|
+
serviceApiProtocols: { route: ['irp-suggest'] },
|
|
142
152
|
}] };
|
|
143
153
|
const contexts = [];
|
|
144
154
|
const client = {
|
|
@@ -166,31 +176,31 @@ test('the buyer and chat router selections pass their cost/quality tradeoff to t
|
|
|
166
176
|
};
|
|
167
177
|
const target = { peerId: routingPeer.peerId, provider: 'alternative', serviceId: 'route' };
|
|
168
178
|
const select = (costQualityTradeoff) => invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route',
|
|
169
|
-
body: routeBody({ kind: 'router', service: target, ...(costQualityTradeoff !== undefined ? { costQualityTradeoff } : {}) }) }));
|
|
179
|
+
body: routeBody({ kind: 'router', service: target, ...(costQualityTradeoff !== undefined ? { options: { cost_quality_tradeoff: costQualityTradeoff } } : {}) }) }));
|
|
170
180
|
const chosen = await select(0);
|
|
171
181
|
assert.equal(chosen.statusCode, 200, chosen.body);
|
|
172
182
|
const response = await invokeProxy(proxy, makeProxyRequest({ body: { model: 'antseed', messages: [{ role: 'user', content: 'Hello' }] } }));
|
|
173
183
|
assert.equal(response.statusCode, 200, response.body);
|
|
174
184
|
assert.equal(contexts.length, 1);
|
|
175
185
|
assert.equal(inferenceCalls, 1);
|
|
176
|
-
assert.equal(contexts[0].
|
|
186
|
+
assert.equal(contexts[0].options?.cost_quality_tradeoff, 0);
|
|
177
187
|
assert.deepEqual(contexts[0].routingService, target);
|
|
178
188
|
assert.equal((await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody({ kind: 'router', service: target }) }))).statusCode, 200);
|
|
179
189
|
store.touch({ tool: 'vpr', sessionKey: 'client-chat' });
|
|
180
190
|
const selectChat = (costQualityTradeoff) => invokeProxy(proxy, makeProxyRequest({
|
|
181
|
-
path: '/_antseed/conversations/update', body: { id: 'vpr:client-chat', routingSelection: { kind: 'router', service: target, costQualityTradeoff } },
|
|
191
|
+
path: '/_antseed/conversations/update', body: { id: 'vpr:client-chat', routingSelection: { kind: 'router', service: target, options: { cost_quality_tradeoff: costQualityTradeoff } } },
|
|
182
192
|
}));
|
|
183
193
|
assert.equal((await selectChat(10)).statusCode, 200);
|
|
184
194
|
const chatResponse = await invokeProxy(proxy, makeProxyRequest({ headers: { 'x-vpr-session-id': 'client-chat' },
|
|
185
195
|
body: { model: 'antseed', messages: [{ role: 'user', content: 'Hello' }] },
|
|
186
196
|
}));
|
|
187
197
|
assert.equal(chatResponse.statusCode, 200, chatResponse.body);
|
|
188
|
-
assert.equal(contexts[1].
|
|
198
|
+
assert.equal(contexts[1].options?.cost_quality_tradeoff, 10);
|
|
189
199
|
assert.deepEqual(contexts[1].routingService, target);
|
|
190
200
|
assert.equal((await select()).statusCode, 200);
|
|
191
201
|
const defaultResponse = await invokeProxy(proxy, makeProxyRequest({ body: { model: 'antseed', messages: [{ role: 'user', content: 'Hello' }] } }));
|
|
192
202
|
assert.equal(defaultResponse.statusCode, 200, defaultResponse.body);
|
|
193
|
-
assert.equal(contexts[2].
|
|
203
|
+
assert.equal(contexts[2].options?.cost_quality_tradeoff, undefined);
|
|
194
204
|
assert.equal(contexts.length, 3);
|
|
195
205
|
assert.equal(inferenceCalls, 3);
|
|
196
206
|
});
|
|
@@ -279,7 +289,7 @@ function setRouter(proxy, selection) {
|
|
|
279
289
|
proxy._defaultRoutedModel = null;
|
|
280
290
|
proxy._defaultRouter = selection;
|
|
281
291
|
}
|
|
282
|
-
/** `POST /_antseed/route` body: `{ model }` for a model, `{ router: { service,
|
|
292
|
+
/** `POST /_antseed/route` body: `{ model }` for a model, `{ router: { service, options } }` for a router. */
|
|
283
293
|
function routeBody(selection) {
|
|
284
294
|
if (selection.kind === 'model')
|
|
285
295
|
return { model: selection.model ?? '' };
|
|
@@ -287,7 +297,7 @@ function routeBody(selection) {
|
|
|
287
297
|
return { router };
|
|
288
298
|
}
|
|
289
299
|
function chatRouterSelection(peer, costQualityTradeoff) {
|
|
290
|
-
return { kind: 'router', service: { peerId: peer.repeat(40), provider: 'alpha', serviceId: 'alpha-route' }, costQualityTradeoff };
|
|
300
|
+
return { kind: 'router', service: { peerId: peer.repeat(40), provider: 'alpha', serviceId: 'alpha-route' }, options: { cost_quality_tradeoff: costQualityTradeoff } };
|
|
291
301
|
}
|
|
292
302
|
async function makeConversationRoutingFixture(context) {
|
|
293
303
|
const fixture = makeRankedRoutingFixture([]);
|
|
@@ -320,18 +330,18 @@ test('chats keep independent routing-service targets and tradeoffs while unconfi
|
|
|
320
330
|
assert.equal((await update('chat-b', second)).statusCode, 200);
|
|
321
331
|
for (const session of ['chat-a', 'chat-b', 'chat-c'])
|
|
322
332
|
assert.equal((await request(session)).statusCode, 200);
|
|
323
|
-
assert.deepEqual(captured.map(entry => [entry.routingService, entry.
|
|
333
|
+
assert.deepEqual(captured.map(entry => [entry.routingService, entry.options?.cost_quality_tradeoff]), [first, second, chatRouterSelection('c', 5)].map(selection => [selection.service, selection.options?.cost_quality_tradeoff]));
|
|
324
334
|
setRouter(proxy, chatRouterSelection('f', 3));
|
|
325
335
|
for (const session of ['chat-a', 'chat-b', 'chat-c'])
|
|
326
336
|
assert.equal((await request(session)).statusCode, 200);
|
|
327
|
-
assert.deepEqual(captured.slice(3).map(entry => [entry.routingService, entry.
|
|
337
|
+
assert.deepEqual(captured.slice(3).map(entry => [entry.routingService, entry.options?.cost_quality_tradeoff]), [first, second, chatRouterSelection('f', 3)].map(selection => [selection.service, selection.options?.cost_quality_tradeoff]));
|
|
328
338
|
assert.equal(store.get('vpr:chat-c')?.routingSelection, null);
|
|
329
339
|
const get = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/conversations/vpr%3Achat-a', method: 'GET' }));
|
|
330
340
|
assert.deepEqual(JSON.parse(get.body).conversation.routingSelection, first);
|
|
331
341
|
assert.equal((await update('chat-a', null)).statusCode, 200);
|
|
332
342
|
assert.equal((await request('chat-a')).statusCode, 200);
|
|
333
343
|
assert.deepEqual(captured.at(-1).routingService, chatRouterSelection('f', 3).service);
|
|
334
|
-
assert.equal(captured.at(-1).
|
|
344
|
+
assert.equal(captured.at(-1).options?.cost_quality_tradeoff, 3);
|
|
335
345
|
});
|
|
336
346
|
test('chat routing overrides beat the buyer model default, inherit into children, and yield to explicit model pins', async (context) => {
|
|
337
347
|
const { proxy, peers, calls, captured, update, request, store } = await makeConversationRoutingFixture(context);
|
|
@@ -362,7 +372,7 @@ test('chat routing updates reject malformed selections without partially changin
|
|
|
362
372
|
assert.equal((await update('chat-a', selection)).statusCode, 200);
|
|
363
373
|
for (const invalid of [[], { kind: 'model', model: 'model-a' }, { kind: 'router' },
|
|
364
374
|
{ ...selection, service: { ...selection.service, peerId: 'invalid' } },
|
|
365
|
-
{ ...selection,
|
|
375
|
+
{ ...selection, options: { cost_quality_tradeoff: {} } }, { ...selection, options: [] }, { ...selection, costQualityTradeoff: 5 }, { ...selection, preferences: { tradeoff: '9' } }]) {
|
|
366
376
|
assert.equal((await update('chat-a', invalid)).statusCode, 400);
|
|
367
377
|
assert.deepEqual(store.get('vpr:chat-a')?.routingSelection, selection);
|
|
368
378
|
}
|
|
@@ -382,7 +392,7 @@ test('persisted chat overrides route after reload and fail closed when the route
|
|
|
382
392
|
await store.flush();
|
|
383
393
|
proxy._conversations = new ConversationStore(directory);
|
|
384
394
|
assert.equal((await request('chat-a')).statusCode, 200);
|
|
385
|
-
assert.equal(captured[0].
|
|
395
|
+
assert.equal(captured[0].options?.cost_quality_tradeoff, selection.options?.cost_quality_tradeoff);
|
|
386
396
|
client.listModels = listModelsWith(['model-z']);
|
|
387
397
|
proxy._routingModels.invalidate(selection.service);
|
|
388
398
|
assert.equal((await request('chat-a')).statusCode, 422);
|
|
@@ -421,15 +431,15 @@ test('chat and buyer selection changes leave in-flight requests using their orig
|
|
|
421
431
|
for (const response of await Promise.all([first, second, inherited]))
|
|
422
432
|
assert.equal(response.statusCode, 200);
|
|
423
433
|
});
|
|
424
|
-
/** A peer advertising one `
|
|
434
|
+
/** A peer advertising one `irp-suggest` routing service, `alpha-route`. */
|
|
425
435
|
function makeRoutingPeer(seed) {
|
|
426
436
|
const peer = makePeer(seed, ['alpha']);
|
|
427
437
|
peer.metadata = {
|
|
428
438
|
peerId: peer.peerId, version: 12, timestamp: Date.now(), signature: '', region: 'test',
|
|
429
439
|
providers: [{ provider: 'alpha', services: ['alpha-route'], maxConcurrency: 1, currentLoad: 0,
|
|
430
440
|
defaultPricing: { inputUsdPerMillion: 0, outputUsdPerMillion: 0 },
|
|
431
|
-
serviceApiProtocols: { 'alpha-route': ['
|
|
432
|
-
serviceUnitBillingModels: { 'alpha-route': { '
|
|
441
|
+
serviceApiProtocols: { 'alpha-route': ['irp-suggest'] },
|
|
442
|
+
serviceUnitBillingModels: { 'alpha-route': { 'irp-suggest': {
|
|
433
443
|
version: 1, components: [{ unit: 'completed_requests', priceUsd: 0.001 }],
|
|
434
444
|
} } },
|
|
435
445
|
}],
|
|
@@ -457,7 +467,7 @@ test('a routing service pinned as the model ranks and serves the request without
|
|
|
457
467
|
assert.equal(response.statusCode, 200, response.body);
|
|
458
468
|
assert.equal(calls.routing, 1);
|
|
459
469
|
assert.deepEqual(captured[0].routingService, target);
|
|
460
|
-
assert.equal(captured[0].
|
|
470
|
+
assert.equal(captured[0].options?.cost_quality_tradeoff, undefined);
|
|
461
471
|
assert.equal(calls.requests.length, 1);
|
|
462
472
|
assert.equal(calls.requests[0].peer.peerId, peers[0].peerId);
|
|
463
473
|
assert.equal(JSON.parse(Buffer.from(calls.requests[0].request.body).toString()).model, 'model-a');
|
|
@@ -468,7 +478,7 @@ test('the body routing object sets the tradeoff for a pinned router and never re
|
|
|
468
478
|
model, messages: [{ role: 'user', content: 'Hello' }], routing: { cost_quality_tradeoff: 7 },
|
|
469
479
|
} }));
|
|
470
480
|
assert.equal(response.statusCode, 200, response.body);
|
|
471
|
-
assert.equal(captured[0].
|
|
481
|
+
assert.equal(captured[0].options?.cost_quality_tradeoff, 7);
|
|
472
482
|
const sent = JSON.parse(Buffer.from(calls.requests[0].request.body).toString());
|
|
473
483
|
assert.equal('routing' in sent, false);
|
|
474
484
|
const direct = await invokeProxy(proxy, makeProxyRequest({ body: {
|
|
@@ -482,28 +492,28 @@ test('the body routing object sets the tradeoff for a pinned router and never re
|
|
|
482
492
|
});
|
|
483
493
|
test('the body routing tradeoff overrides the buyer default router tradeoff', async () => {
|
|
484
494
|
const { proxy, captured } = makePinnedRouterFixture();
|
|
485
|
-
setRouter(proxy, { kind: 'router', service: { peerId: 'd'.repeat(40), provider: 'alpha', serviceId: 'alpha-route' },
|
|
495
|
+
setRouter(proxy, { kind: 'router', service: { peerId: 'd'.repeat(40), provider: 'alpha', serviceId: 'alpha-route' }, options: { cost_quality_tradeoff: 1 } });
|
|
486
496
|
const response = await invokeProxy(proxy, makeProxyRequest({ body: {
|
|
487
497
|
model: 'antseed', messages: [{ role: 'user', content: 'Hello' }], routing: { cost_quality_tradeoff: 9 },
|
|
488
498
|
} }));
|
|
489
499
|
assert.equal(response.statusCode, 200, response.body);
|
|
490
|
-
assert.equal(captured[0].
|
|
500
|
+
assert.equal(captured[0].options?.cost_quality_tradeoff, 9);
|
|
491
501
|
});
|
|
492
502
|
test('a pinned router without a routing object uses the saved settings for that router only', async () => {
|
|
493
503
|
const { proxy, peers, captured, target, model } = makePinnedRouterFixture();
|
|
494
|
-
setRouter(proxy, { kind: 'router', service: target,
|
|
504
|
+
setRouter(proxy, { kind: 'router', service: target, options: { cost_quality_tradeoff: 3 }, allowedModels: [{ provider: 'openai', serviceId: 'model-b' }] });
|
|
495
505
|
const saved = await invokeProxy(proxy, makeProxyRequest({ body: { model, messages: [{ role: 'user', content: 'Hello' }] } }));
|
|
496
506
|
assert.equal(saved.statusCode, 200, saved.body);
|
|
497
|
-
assert.equal(captured[0].
|
|
507
|
+
assert.equal(captured[0].options?.cost_quality_tradeoff, 3);
|
|
498
508
|
assert.deepEqual([...new Set(captured[0].candidates.map((candidate) => candidate.serviceId))], ['model-b']);
|
|
499
509
|
const overridden = await invokeProxy(proxy, makeProxyRequest({ body: { model, messages: [{ role: 'user', content: 'Hello' }], routing: { cost_quality_tradeoff: 9 } } }));
|
|
500
510
|
assert.equal(overridden.statusCode, 200, overridden.body);
|
|
501
|
-
assert.equal(captured[1].
|
|
511
|
+
assert.equal(captured[1].options?.cost_quality_tradeoff, 9);
|
|
502
512
|
assert.deepEqual([...new Set(captured[1].candidates.map((candidate) => candidate.serviceId))], ['model-b']);
|
|
503
|
-
setRouter(proxy, { kind: 'router', service: { ...target, peerId: 'e'.repeat(40) },
|
|
513
|
+
setRouter(proxy, { kind: 'router', service: { ...target, peerId: 'e'.repeat(40) }, options: { cost_quality_tradeoff: 3 }, allowedModels: [{ provider: 'openai', serviceId: 'model-b' }] });
|
|
504
514
|
const other = await invokeProxy(proxy, makeProxyRequest({ body: { model, messages: [{ role: 'user', content: 'Hello' }] } }));
|
|
505
515
|
assert.equal(other.statusCode, 200, other.body);
|
|
506
|
-
assert.equal(captured[2].
|
|
516
|
+
assert.equal(captured[2].options?.cost_quality_tradeoff, undefined);
|
|
507
517
|
assert.ok(captured[2].candidates.some((candidate) => candidate.serviceId === 'model-a'));
|
|
508
518
|
assert.ok(peers.length > 0);
|
|
509
519
|
});
|
|
@@ -514,7 +524,7 @@ test('a router pinned as the default route serves the antseed alias through that
|
|
|
514
524
|
assert.equal(response.statusCode, 200, response.body);
|
|
515
525
|
assert.equal(calls.routing, 1);
|
|
516
526
|
assert.deepEqual(captured[0].routingService, target);
|
|
517
|
-
assert.equal(captured[0].
|
|
527
|
+
assert.equal(captured[0].options?.cost_quality_tradeoff, 6);
|
|
518
528
|
assert.equal(calls.requests[0].peer.peerId, peers[0].peerId);
|
|
519
529
|
assert.equal(JSON.parse(Buffer.from(calls.requests[0].request.body).toString()).model, 'model-a');
|
|
520
530
|
});
|
|
@@ -569,7 +579,7 @@ test('a chat\'s own router wins over a router pinned as the default route', asyn
|
|
|
569
579
|
assert.equal(chatTurn.statusCode, 200, chatTurn.body);
|
|
570
580
|
const plain = await turn();
|
|
571
581
|
assert.equal(plain.statusCode, 200, plain.body);
|
|
572
|
-
assert.deepEqual(captured.map((entry) => [entry.routingService.peerId, entry.
|
|
582
|
+
assert.deepEqual(captured.map((entry) => [entry.routingService.peerId, entry.options?.cost_quality_tradeoff]), [[chatRouter.peerId, 9], [routingPeer.peerId, undefined]]);
|
|
573
583
|
assert.equal(calls.routing, 2);
|
|
574
584
|
});
|
|
575
585
|
test('an automatic chat route never turns a seller into a router pin', async (context) => {
|
|
@@ -675,28 +685,28 @@ test('a pinned service that is not the peer\'s routing service is a normal selle
|
|
|
675
685
|
assert.equal(calls.routing, 0);
|
|
676
686
|
assert.equal(calls.requests[0].peer.peerId, peers[1].peerId);
|
|
677
687
|
});
|
|
678
|
-
test('routing selection carries
|
|
688
|
+
test('routing selection carries router options, rejects malformed ones and preserves model mode', async () => {
|
|
679
689
|
const { proxy, calls } = makeRankedRoutingFixture([200, 200, 200, 200]);
|
|
680
690
|
const client = proxy._modelRoutingClient;
|
|
681
691
|
const captured = [];
|
|
682
692
|
const select = client.selectRoute;
|
|
683
693
|
client.selectRoute = (request, peers, context) => {
|
|
684
|
-
captured.push({ tradeoff: context.
|
|
694
|
+
captured.push({ tradeoff: context.options?.cost_quality_tradeoff, target: context.routingService });
|
|
685
695
|
return select(request, peers, context);
|
|
686
696
|
};
|
|
687
697
|
proxy._mergeStateFile = async () => { };
|
|
688
698
|
setDefaultModel(proxy, 'stale-model');
|
|
689
699
|
const service = { peerId: 'd'.repeat(40), provider: 'alpha', serviceId: 'alpha-route' };
|
|
690
|
-
const selected = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody({ kind: 'router', service,
|
|
700
|
+
const selected = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody({ kind: 'router', service, options: { cost_quality_tradeoff: 9 } }) }));
|
|
691
701
|
assert.equal(selected.statusCode, 200, selected.body);
|
|
692
702
|
const first = await invokeProxy(proxy, makeProxyRequest({ body: { model: 'antseed', messages: [{ role: 'user', content: 'Hello' }] } }));
|
|
693
703
|
assert.equal(first.statusCode, 200, first.body);
|
|
694
704
|
assert.deepEqual(captured[0], { tradeoff: 9, target: service });
|
|
695
|
-
const updated = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody({ kind: 'router', service,
|
|
705
|
+
const updated = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody({ kind: 'router', service, options: { cost_quality_tradeoff: 1 } }) }));
|
|
696
706
|
assert.equal(updated.statusCode, 200, updated.body);
|
|
697
707
|
await invokeProxy(proxy, makeProxyRequest({ body: { model: 'antseed', messages: [{ role: 'user', content: 'Hello' }] } }));
|
|
698
708
|
assert.equal(captured[1].tradeoff, 1);
|
|
699
|
-
for (const selection of [{ kind: 'router', service,
|
|
709
|
+
for (const selection of [{ kind: 'router', service, options: { cost_quality_tradeoff: null } }, { kind: 'router', service, options: 'cheap' }, { kind: 'router', service, preferences: { tradeoff: '9' } }]) {
|
|
700
710
|
const invalid = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody(selection) }));
|
|
701
711
|
assert.equal(invalid.statusCode, 400, invalid.body);
|
|
702
712
|
}
|
|
@@ -772,7 +782,7 @@ test('explicit routing-service target and tradeoff survive the local state-file
|
|
|
772
782
|
const client = proxy._modelRoutingClient;
|
|
773
783
|
const stateFile = join(directory, 'buyer.state.json');
|
|
774
784
|
proxy._stateFile = stateFile;
|
|
775
|
-
const selection = { kind: 'router', service: { peerId: 'c'.repeat(40), provider: 'alpha', serviceId: 'alpha-route' },
|
|
785
|
+
const selection = { kind: 'router', service: { peerId: 'c'.repeat(40), provider: 'alpha', serviceId: 'alpha-route' }, options: { cost_quality_tradeoff: 9 } };
|
|
776
786
|
const response = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: routeBody(selection) }));
|
|
777
787
|
assert.equal(response.statusCode, 200, response.body);
|
|
778
788
|
assert.deepEqual(JSON.parse(await readFile(stateFile, 'utf8')).defaultRouter, routeBody(selection).router);
|
|
@@ -809,7 +819,7 @@ test('config reload updates eligibility policy without replacing the active rout
|
|
|
809
819
|
proxy._configPath = path;
|
|
810
820
|
proxy._mergeStateFile = async () => { assert.fail('Config reload must not persist selection'); };
|
|
811
821
|
const service = { peerId: 'c'.repeat(40), provider: 'alpha', serviceId: 'alpha-route' };
|
|
812
|
-
const activeSelection = { kind: 'router', service,
|
|
822
|
+
const activeSelection = { kind: 'router', service, options: { cost_quality_tradeoff: 5 } };
|
|
813
823
|
setRouter(proxy, activeSelection);
|
|
814
824
|
for (const maxInputUsdPerMillion of [15, 25]) {
|
|
815
825
|
const routingPreferences = { ...priceAndTrustPreferences, maxInputUsdPerMillion };
|
|
@@ -905,7 +915,7 @@ test('changing model selection affects the next request without cancelling the c
|
|
|
905
915
|
assert.equal(next.statusCode, 200);
|
|
906
916
|
assert.equal(JSON.parse(Buffer.from(calls.requests[1].request.body).toString()).model, 'model-b');
|
|
907
917
|
});
|
|
908
|
-
test('client disconnect still cancels a pending
|
|
918
|
+
test('client disconnect still cancels a pending routing decision', { timeout: 5_000 }, async () => {
|
|
909
919
|
const { proxy, calls } = makeRankedRoutingFixture([200]);
|
|
910
920
|
const client = proxy._modelRoutingClient;
|
|
911
921
|
let started;
|
|
@@ -1301,7 +1311,7 @@ test('ordinary requests keep attributing spend after the conversation already ex
|
|
|
1301
1311
|
assert.equal(conversation.requestCount, 2);
|
|
1302
1312
|
assert.equal(conversation.inputTokens, '8');
|
|
1303
1313
|
});
|
|
1304
|
-
test('model and
|
|
1314
|
+
test('model and routing requests use the same duplicate tracking guard', () => {
|
|
1305
1315
|
const proxy = makeBuyerProxyWithPeers([]);
|
|
1306
1316
|
for (const purpose of [undefined, 'routing']) {
|
|
1307
1317
|
const requestId = randomUUID();
|
|
@@ -4136,7 +4146,7 @@ test('route control endpoint sets, persists, and returns the default routed mode
|
|
|
4136
4146
|
assert.equal(automaticPersisted['defaultRoutedModel'], 'gpt-4o');
|
|
4137
4147
|
const invalid = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: { model: 'not-a-peer@gpt-4o' } }));
|
|
4138
4148
|
assert.equal(invalid.statusCode, 400);
|
|
4139
|
-
const router = { service: { peerId: validPeerId, provider: 'alpha', serviceId: 'alpha-route' },
|
|
4149
|
+
const router = { service: { peerId: validPeerId, provider: 'alpha', serviceId: 'alpha-route' }, options: { cost_quality_tradeoff: 5 } };
|
|
4140
4150
|
const routed = await invokeProxy(proxy, makeProxyRequest({ path: '/_antseed/route', body: { router } }));
|
|
4141
4151
|
assert.deepEqual(JSON.parse(routed.body), { ok: true, model: null, router });
|
|
4142
4152
|
const routedPersisted = JSON.parse(await readFile(join(dir, 'buyer.state.json'), 'utf-8'));
|