@antseed/cli 0.1.173 → 0.1.175
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/network/peer.d.ts.map +1 -1
- package/dist/cli/commands/network/peer.js +2 -1
- package/dist/cli/commands/network/peer.js.map +1 -1
- package/dist/proxy/buyer-proxy.d.ts.map +1 -1
- package/dist/proxy/buyer-proxy.js +6 -2
- package/dist/proxy/buyer-proxy.js.map +1 -1
- package/dist/proxy/buyer-proxy.test.js +105 -0
- package/dist/proxy/buyer-proxy.test.js.map +1 -1
- package/dist/proxy/conversation-store.d.ts +3 -1
- package/dist/proxy/conversation-store.d.ts.map +1 -1
- package/dist/proxy/conversation-store.js +5 -2
- package/dist/proxy/conversation-store.js.map +1 -1
- package/dist/proxy/conversation-store.test.js +27 -0
- package/dist/proxy/conversation-store.test.js.map +1 -1
- package/dist/proxy/network-models.test.js +1 -1
- package/dist/proxy/network-models.test.js.map +1 -1
- package/dist/proxy/video-download.d.ts.map +1 -1
- package/dist/proxy/video-download.js +19 -1
- package/dist/proxy/video-download.js.map +1 -1
- package/dist/proxy/video-download.test.js +20 -0
- package/dist/proxy/video-download.test.js.map +1 -1
- package/package.json +6 -6
|
@@ -3263,6 +3263,32 @@ test('adaptPeerFaultErrorResponse upgrades a generic wrapper for a pinned route'
|
|
|
3263
3263
|
'Original Response: {"message":"Insufficient balance or no resource package. Please recharge.","status":429}',
|
|
3264
3264
|
].join('\n'));
|
|
3265
3265
|
});
|
|
3266
|
+
test('adaptPeerFaultErrorResponse keeps string errors and validation details', () => {
|
|
3267
|
+
const response = adaptPeerFaultErrorResponse({
|
|
3268
|
+
requestId: 'req-venice-details',
|
|
3269
|
+
statusCode: 400,
|
|
3270
|
+
headers: { 'content-type': 'application/json' },
|
|
3271
|
+
body: Buffer.from(JSON.stringify({
|
|
3272
|
+
error: 'Invalid request parameters',
|
|
3273
|
+
details: { _errors: [], audio: { _errors: ['Audio is not configurable for this model'] } },
|
|
3274
|
+
})),
|
|
3275
|
+
}, 'venice-video', { pinned: true });
|
|
3276
|
+
const parsed = JSON.parse(Buffer.from(response.body).toString('utf8'));
|
|
3277
|
+
assert.equal(parsed.error.type, 'Invalid request parameters');
|
|
3278
|
+
assert.equal(parsed.error.peer_message, 'Invalid request parameters: audio: Audio is not configurable for this model');
|
|
3279
|
+
assert.equal(parsed.error.peer_status, 400);
|
|
3280
|
+
assert.match(parsed.error.message, /audio: Audio is not configurable for this model/);
|
|
3281
|
+
});
|
|
3282
|
+
test('adaptPeerFaultErrorResponse falls back to JSON for unstructured details', () => {
|
|
3283
|
+
const response = adaptPeerFaultErrorResponse({
|
|
3284
|
+
requestId: 'req-raw-details',
|
|
3285
|
+
statusCode: 400,
|
|
3286
|
+
headers: { 'content-type': 'application/json' },
|
|
3287
|
+
body: Buffer.from(JSON.stringify({ error: 'Bad input', details: { field: 'resolution' } })),
|
|
3288
|
+
}, 'venice-video');
|
|
3289
|
+
const parsed = JSON.parse(Buffer.from(response.body).toString('utf8'));
|
|
3290
|
+
assert.equal(parsed.error.peer_message, 'Bad input: {"field":"resolution"}');
|
|
3291
|
+
});
|
|
3266
3292
|
test('adaptPeerFaultErrorResponse preserves payment-required control messages', () => {
|
|
3267
3293
|
const body = Buffer.from(JSON.stringify({
|
|
3268
3294
|
error: 'payment_required',
|
|
@@ -3358,4 +3384,83 @@ test('getSweepReceipt returns cached relayer receipts case-insensitively', () =>
|
|
|
3358
3384
|
assert.equal(proxy.getSweepReceipt(nonce.toLowerCase()), receipt);
|
|
3359
3385
|
assert.equal(proxy.getSweepReceipt('0x' + '00'.repeat(32)), null);
|
|
3360
3386
|
});
|
|
3387
|
+
test('switching a chat route while a request is in flight is not reverted when that request completes', async () => {
|
|
3388
|
+
const dir = await mkdtemp(join(tmpdir(), 'antseed-buyer-route-race-'));
|
|
3389
|
+
try {
|
|
3390
|
+
const oldPeer = makePeer('a', ['openai']);
|
|
3391
|
+
oldPeer.providerServiceApiProtocols = { openai: { services: { 'gpt-5': ['openai-chat-completions'] } } };
|
|
3392
|
+
const newPeer = makePeer('b', ['openai']);
|
|
3393
|
+
newPeer.providerServiceApiProtocols = { openai: { services: { 'claude-sonnet': ['openai-chat-completions'] } } };
|
|
3394
|
+
const proxy = new BuyerProxy({
|
|
3395
|
+
port: 0,
|
|
3396
|
+
dataDir: dir,
|
|
3397
|
+
node: { router: permissiveRouter() },
|
|
3398
|
+
});
|
|
3399
|
+
proxy._getPeers = async () => [oldPeer, newPeer];
|
|
3400
|
+
proxy._cacheLastUpdatedAtMs = Date.now();
|
|
3401
|
+
proxy._defaultRoutedModel = 'gpt-5';
|
|
3402
|
+
const attempts = [];
|
|
3403
|
+
let holdNext = false;
|
|
3404
|
+
let releaseHeld = null;
|
|
3405
|
+
let markDispatched = null;
|
|
3406
|
+
const dispatched = new Promise((resolve) => { markDispatched = resolve; });
|
|
3407
|
+
proxy._node.sendRequest = async (peer, request) => {
|
|
3408
|
+
attempts.push(peer.peerId);
|
|
3409
|
+
if (holdNext) {
|
|
3410
|
+
holdNext = false;
|
|
3411
|
+
markDispatched?.();
|
|
3412
|
+
await new Promise((resolve) => { releaseHeld = resolve; });
|
|
3413
|
+
}
|
|
3414
|
+
return {
|
|
3415
|
+
requestId: request.requestId,
|
|
3416
|
+
statusCode: 200,
|
|
3417
|
+
headers: { 'content-type': 'application/json' },
|
|
3418
|
+
body: Buffer.from(JSON.stringify({ peerId: peer.peerId })),
|
|
3419
|
+
};
|
|
3420
|
+
};
|
|
3421
|
+
const headers = { 'x-vpr-session-id': 'route-race' };
|
|
3422
|
+
const chatId = 'vpr:route-race';
|
|
3423
|
+
const store = proxy._conversations;
|
|
3424
|
+
// Turn 1 settles the chat on the old route as soft (auto) affinity.
|
|
3425
|
+
const first = await invokeProxy(proxy, makeProxyRequest({
|
|
3426
|
+
headers,
|
|
3427
|
+
body: { model: 'antseed', messages: [{ role: 'user', content: 'first turn' }] },
|
|
3428
|
+
}));
|
|
3429
|
+
assert.equal(first.statusCode, 200);
|
|
3430
|
+
assert.equal(store.get(chatId)?.pinnedModel, `${oldPeer.peerId}@gpt-5`);
|
|
3431
|
+
assert.equal(store.get(chatId)?.peerSource, 'auto');
|
|
3432
|
+
// Turn 2 is held open upstream on the old route.
|
|
3433
|
+
holdNext = true;
|
|
3434
|
+
const inFlight = invokeProxy(proxy, makeProxyRequest({
|
|
3435
|
+
headers,
|
|
3436
|
+
body: { model: 'antseed', messages: [{ role: 'user', content: 'long turn' }] },
|
|
3437
|
+
}));
|
|
3438
|
+
await dispatched;
|
|
3439
|
+
// The user switches the chat's model mid-flight.
|
|
3440
|
+
const update = await invokeProxy(proxy, makeProxyRequest({
|
|
3441
|
+
path: '/_antseed/conversations/update',
|
|
3442
|
+
body: { id: chatId, pinnedModel: 'claude-sonnet', peerSource: 'auto' },
|
|
3443
|
+
}));
|
|
3444
|
+
assert.equal(update.statusCode, 200);
|
|
3445
|
+
releaseHeld?.();
|
|
3446
|
+
const finished = await inFlight;
|
|
3447
|
+
assert.equal(finished.statusCode, 200);
|
|
3448
|
+
assert.equal(store.get(chatId)?.pinnedModel, 'claude-sonnet');
|
|
3449
|
+
assert.equal(store.get(chatId)?.peerSource, 'auto');
|
|
3450
|
+
assert.equal(store.get(chatId)?.lastModel, `${oldPeer.peerId}@gpt-5`);
|
|
3451
|
+
// The next turn routes to the newly selected model.
|
|
3452
|
+
attempts.length = 0;
|
|
3453
|
+
const next = await invokeProxy(proxy, makeProxyRequest({
|
|
3454
|
+
headers,
|
|
3455
|
+
body: { model: 'antseed', messages: [{ role: 'user', content: 'after switch' }] },
|
|
3456
|
+
}));
|
|
3457
|
+
assert.equal(next.statusCode, 200);
|
|
3458
|
+
assert.deepEqual(attempts, [newPeer.peerId]);
|
|
3459
|
+
assert.equal(store.get(chatId)?.pinnedModel, `${newPeer.peerId}@claude-sonnet`);
|
|
3460
|
+
await store.flush();
|
|
3461
|
+
}
|
|
3462
|
+
finally {
|
|
3463
|
+
await rm(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
3464
|
+
}
|
|
3465
|
+
});
|
|
3361
3466
|
//# sourceMappingURL=buyer-proxy.test.js.map
|