@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.
Files changed (42) hide show
  1. package/dist/cli/commands/seller/start.d.ts.map +1 -1
  2. package/dist/cli/commands/seller/start.js +2 -1
  3. package/dist/cli/commands/seller/start.js.map +1 -1
  4. package/dist/config/service-metadata.test.js +1 -1
  5. package/dist/config/service-metadata.test.js.map +1 -1
  6. package/dist/gateway/routing-through-gateway.test.d.ts +2 -0
  7. package/dist/gateway/routing-through-gateway.test.d.ts.map +1 -0
  8. package/dist/gateway/routing-through-gateway.test.js +177 -0
  9. package/dist/gateway/routing-through-gateway.test.js.map +1 -0
  10. package/dist/plugins/registry.d.ts.map +1 -1
  11. package/dist/plugins/registry.js +9 -3
  12. package/dist/plugins/registry.js.map +1 -1
  13. package/dist/proxy/buyer-proxy.d.ts +8 -2
  14. package/dist/proxy/buyer-proxy.d.ts.map +1 -1
  15. package/dist/proxy/buyer-proxy.js +37 -8
  16. package/dist/proxy/buyer-proxy.js.map +1 -1
  17. package/dist/proxy/buyer-proxy.test.js +51 -41
  18. package/dist/proxy/buyer-proxy.test.js.map +1 -1
  19. package/dist/proxy/conversation-store.test.js +2 -2
  20. package/dist/proxy/conversation-store.test.js.map +1 -1
  21. package/dist/proxy/gateway-policy.test.js +3 -3
  22. package/dist/proxy/gateway-policy.test.js.map +1 -1
  23. package/dist/proxy/network-models.d.ts +6 -0
  24. package/dist/proxy/network-models.d.ts.map +1 -1
  25. package/dist/proxy/network-models.js.map +1 -1
  26. package/dist/proxy/request-utils.d.ts +10 -10
  27. package/dist/proxy/request-utils.d.ts.map +1 -1
  28. package/dist/proxy/request-utils.js +8 -30
  29. package/dist/proxy/request-utils.js.map +1 -1
  30. package/dist/proxy/router-execution.d.ts +3 -3
  31. package/dist/proxy/router-execution.d.ts.map +1 -1
  32. package/dist/proxy/router-execution.js +9 -7
  33. package/dist/proxy/router-execution.js.map +1 -1
  34. package/dist/proxy/router-execution.test.js +6 -6
  35. package/dist/proxy/router-execution.test.js.map +1 -1
  36. package/dist/proxy/routing-services.d.ts +17 -6
  37. package/dist/proxy/routing-services.d.ts.map +1 -1
  38. package/dist/proxy/routing-services.js +31 -23
  39. package/dist/proxy/routing-services.js.map +1 -1
  40. package/dist/proxy/routing-services.test.js +4 -4
  41. package/dist/proxy/routing-services.test.js.map +1 -1
  42. 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, costQualityTradeoff?, allowedModels? }`). */
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, costQualityTradeoff? }');
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 (tradeoff,
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.costQualityTradeoff !== undefined
3173
- ? { ...baseSelection, costQualityTradeoff: routingOptions.costQualityTradeoff }
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 },