@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
|
@@ -35,7 +35,7 @@ import { TeeControl } from './tee-control.js';
|
|
|
35
35
|
import { ChainReadCache } from './chain-read-cache.js';
|
|
36
36
|
import { isClientCredentialHeader } from './credential-headers.js';
|
|
37
37
|
import { loadConfig } from '../config/loader.js';
|
|
38
|
-
import { ModelRoutingClient } from '@antseed/router-core';
|
|
38
|
+
import { InvalidRouterOptionsError, ModelRoutingClient, routingClientAdapter, routingProtocolOfTarget, validateRouterOptions } from '@antseed/router-core';
|
|
39
39
|
import { GATEWAY_CONTROL_HEADER, GATEWAY_CONTROL_SECRET_ENV, GATEWAY_CONTROL_SECRET_FILE, ROUTING_POLICY_HEADER, decodePolicyHeader, findModelRoute, meaningfulPolicy, narrowPolicy, normalizePeerId as normalizePolicyPeerId, policyAllowsModel, policyModelKey, } from '../routing-policy/policy.js';
|
|
40
40
|
import { buyerConfigReason, buyerHardPolicy, buyerPreferencePolicy, orderByPolicy, pinnedPeerExclusionReasons, policyExclusionReasons, preferenceExclusionReasons, rankingPreferences, secretsMatch, routingServicePolicy, } from './route-policy.js';
|
|
41
41
|
// Re-export for backward compatibility (used by tests and other consumers)
|
|
@@ -1654,14 +1654,33 @@ export class BuyerProxy {
|
|
|
1654
1654
|
if (!value.service)
|
|
1655
1655
|
throw new Error('Select an exact routing-service target');
|
|
1656
1656
|
}
|
|
1657
|
-
/** Parses the `router` field of `POST /_antseed/route` (`{ service,
|
|
1657
|
+
/** Parses the `router` field of `POST /_antseed/route` (`{ service, options?, allowedModels? }`). */
|
|
1658
1658
|
_parseDefaultRouter(value) {
|
|
1659
1659
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
1660
|
-
throw new Error('router must be { service,
|
|
1660
|
+
throw new Error('router must be { service, options?, allowedModels? }');
|
|
1661
1661
|
const selection = { ...value, kind: 'router' };
|
|
1662
1662
|
this._validateRouterSelection(selection);
|
|
1663
1663
|
return structuredClone(selection);
|
|
1664
1664
|
}
|
|
1665
|
+
/**
|
|
1666
|
+
* Check a router selection's options against the protocol its router advertises, when the
|
|
1667
|
+
* router is in the peer cache; throws `InvalidRouterOptionsError`. An unknown router is
|
|
1668
|
+
* checked again before each ranking.
|
|
1669
|
+
*/
|
|
1670
|
+
async _checkRouterOptions(selection) {
|
|
1671
|
+
if (!selection.service || selection.options === undefined)
|
|
1672
|
+
return;
|
|
1673
|
+
let peers;
|
|
1674
|
+
try {
|
|
1675
|
+
peers = await this._getPeers();
|
|
1676
|
+
}
|
|
1677
|
+
catch {
|
|
1678
|
+
return; // Discovery is unavailable: the options are checked again before each ranking.
|
|
1679
|
+
}
|
|
1680
|
+
const protocol = routingProtocolOfTarget(peers, selection.service);
|
|
1681
|
+
if (protocol)
|
|
1682
|
+
validateRouterOptions(routingClientAdapter(protocol).options, selection.options);
|
|
1683
|
+
}
|
|
1665
1684
|
/** The default router in its wire form, without the internal `kind` tag. */
|
|
1666
1685
|
get _defaultRouterJson() {
|
|
1667
1686
|
if (!this._defaultRouter)
|
|
@@ -2354,6 +2373,7 @@ export class BuyerProxy {
|
|
|
2354
2373
|
if (model.length > 0)
|
|
2355
2374
|
throw new Error('Set model or router, not both');
|
|
2356
2375
|
router = this._parseDefaultRouter(body.router);
|
|
2376
|
+
await this._checkRouterOptions(router);
|
|
2357
2377
|
}
|
|
2358
2378
|
if (model.length > 0 && !isValidRoutedModelTarget(model)) {
|
|
2359
2379
|
throw new Error('model must be "<service>", "<peerId>@<service>", or empty to clear');
|
|
@@ -2440,8 +2460,10 @@ export class BuyerProxy {
|
|
|
2440
2460
|
try {
|
|
2441
2461
|
if ('pinnedModel' in parsed)
|
|
2442
2462
|
throw new Error('Update routingSelection or pinnedModel, not both');
|
|
2443
|
-
if (parsed.routingSelection !== null)
|
|
2463
|
+
if (parsed.routingSelection !== null) {
|
|
2444
2464
|
this._validateRouterSelection(parsed.routingSelection);
|
|
2465
|
+
await this._checkRouterOptions(parsed.routingSelection);
|
|
2466
|
+
}
|
|
2445
2467
|
}
|
|
2446
2468
|
catch (error) {
|
|
2447
2469
|
res.writeHead(400, { 'content-type': 'application/json' });
|
|
@@ -2877,6 +2899,8 @@ export class BuyerProxy {
|
|
|
2877
2899
|
...(service.sellerName ? { displayName: service.sellerName } : {}),
|
|
2878
2900
|
provider: service.provider,
|
|
2879
2901
|
serviceId: service.serviceId,
|
|
2902
|
+
protocol: service.protocol,
|
|
2903
|
+
options: service.options,
|
|
2880
2904
|
model: `${service.peerId}@${service.serviceId}`,
|
|
2881
2905
|
priceUsdPerRequest: Number.isFinite(price) ? price / 1_000_000 : null,
|
|
2882
2906
|
models,
|
|
@@ -3162,15 +3186,16 @@ export class BuyerProxy {
|
|
|
3162
3186
|
if (useModelRouter && systemRoutedAsAlias) {
|
|
3163
3187
|
serializedReq = withRoutedModel(serializedReq, ROUTED_MODEL_ALIAS);
|
|
3164
3188
|
}
|
|
3165
|
-
// A request without `routing` uses the saved router settings (
|
|
3166
|
-
// model allow list) when it pins the router those settings belong to
|
|
3189
|
+
// A request without `routing` uses the saved router settings (options,
|
|
3190
|
+
// model allow list) when it pins the router those settings belong to;
|
|
3191
|
+
// a request's own `routing` options override the saved ones key by key.
|
|
3167
3192
|
const savedRouter = this._defaultRouter;
|
|
3168
3193
|
const savedForPinned = pinnedRouter && savedRouter && sameRoutingServiceTarget(savedRouter.service, pinnedRouter.service)
|
|
3169
3194
|
? structuredClone(savedRouter)
|
|
3170
3195
|
: null;
|
|
3171
3196
|
const baseSelection = pinnedRouter ? savedForPinned ?? pinnedRouter : routerSelection;
|
|
3172
|
-
const activeSelection = baseSelection && routingOptions.
|
|
3173
|
-
? { ...baseSelection,
|
|
3197
|
+
const activeSelection = baseSelection && Object.keys(routingOptions).length > 0
|
|
3198
|
+
? { ...baseSelection, options: { ...baseSelection.options, ...routingOptions } }
|
|
3174
3199
|
: baseSelection;
|
|
3175
3200
|
const context = {
|
|
3176
3201
|
request: serializedReq, requiredParameters, requestPolicy, signal: clientAbortController.signal,
|
|
@@ -3232,6 +3257,10 @@ export class BuyerProxy {
|
|
|
3232
3257
|
catch (error) {
|
|
3233
3258
|
// Report routing failures rather than silently choosing a model for the user.
|
|
3234
3259
|
const message = error instanceof Error ? error.message : String(error);
|
|
3260
|
+
if (error instanceof InvalidRouterOptionsError) {
|
|
3261
|
+
sendJson(res, 400, { error: { type: 'invalid_request_error', code: 'invalid_routing', message, param: 'routing' } });
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
3235
3264
|
writeDispatchFailure(res, error instanceof NoEligibleCandidatesError
|
|
3236
3265
|
? dispatchFailure(422, { 'content-type': 'application/json' }, JSON.stringify({
|
|
3237
3266
|
error: { type: 'invalid_request_error', code: 'no_eligible_candidates', message },
|