@antseed/router-core 0.1.49 → 0.1.50
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/cache-observations.d.ts +11 -0
- package/dist/cache-observations.d.ts.map +1 -0
- package/dist/cache-observations.js +41 -0
- package/dist/cache-observations.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/model-routing-client.d.ts +27 -0
- package/dist/model-routing-client.d.ts.map +1 -0
- package/dist/model-routing-client.js +124 -0
- package/dist/model-routing-client.js.map +1 -0
- package/dist/router-model-names.d.ts +11 -0
- package/dist/router-model-names.d.ts.map +1 -0
- package/dist/router-model-names.js +34 -0
- package/dist/router-model-names.js.map +1 -0
- package/dist/routing-adapters/index.d.ts +8 -0
- package/dist/routing-adapters/index.d.ts.map +1 -0
- package/dist/routing-adapters/index.js +16 -0
- package/dist/routing-adapters/index.js.map +1 -0
- package/dist/routing-adapters/irp.d.ts +16 -0
- package/dist/routing-adapters/irp.d.ts.map +1 -0
- package/dist/routing-adapters/irp.js +122 -0
- package/dist/routing-adapters/irp.js.map +1 -0
- package/dist/routing-adapters/types.d.ts +64 -0
- package/dist/routing-adapters/types.d.ts.map +1 -0
- package/dist/routing-adapters/types.js +54 -0
- package/dist/routing-adapters/types.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RouteCandidate, RoutingUsageObservation } from '@antseed/node';
|
|
2
|
+
/** Per-conversation prompt-cache reuse observed from completed inference responses. */
|
|
3
|
+
export declare class CacheObservations {
|
|
4
|
+
private readonly now;
|
|
5
|
+
private readonly conversations;
|
|
6
|
+
constructor(now?: () => number);
|
|
7
|
+
record(observation: RoutingUsageObservation): void;
|
|
8
|
+
/** Expected cached input tokens for one exact peer/provider/model in this conversation. */
|
|
9
|
+
expectedCachedInputTokens(conversationKey: string | null, candidate: Pick<RouteCandidate, 'peerId' | 'provider' | 'serviceId'>, promptTokens: number): number;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=cache-observations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-observations.d.ts","sourceRoot":"","sources":["../src/cache-observations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAK7E,uFAAuF;AACvF,qBAAa,iBAAiB;IAGhB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAFhC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmC;gBAEpC,GAAG,GAAE,MAAM,MAAiB;IAEzD,MAAM,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI;IAoBlD,2FAA2F;IAC3F,yBAAyB,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,WAAW,CAAC,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;CAM9J"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** Per-conversation prompt-cache reuse observed from completed inference responses. */
|
|
2
|
+
export class CacheObservations {
|
|
3
|
+
now;
|
|
4
|
+
conversations = new Map();
|
|
5
|
+
constructor(now = Date.now) {
|
|
6
|
+
this.now = now;
|
|
7
|
+
}
|
|
8
|
+
record(observation) {
|
|
9
|
+
const { conversationKey, requestId, peerId, provider, serviceId, inputTokens, cachedInputTokens } = observation;
|
|
10
|
+
if (!conversationKey || !requestId || !Number.isSafeInteger(inputTokens) || inputTokens <= 0
|
|
11
|
+
|| !Number.isSafeInteger(cachedInputTokens) || cachedInputTokens < 0 || cachedInputTokens > inputTokens)
|
|
12
|
+
return;
|
|
13
|
+
const conversation = this.conversations.get(conversationKey) ?? { offers: new Map(), requests: new Set() };
|
|
14
|
+
const requestKey = JSON.stringify([requestId, peerId, provider, serviceId]);
|
|
15
|
+
if (conversation.requests.has(requestKey))
|
|
16
|
+
return;
|
|
17
|
+
conversation.requests.add(requestKey);
|
|
18
|
+
if (conversation.requests.size > 512)
|
|
19
|
+
conversation.requests.delete(conversation.requests.values().next().value);
|
|
20
|
+
const key = JSON.stringify([peerId, provider, serviceId]);
|
|
21
|
+
const previous = conversation.offers.get(key);
|
|
22
|
+
const ratio = cachedInputTokens / inputTokens;
|
|
23
|
+
conversation.offers.delete(key);
|
|
24
|
+
conversation.offers.set(key, { ratio: previous ? previous.ratio * 0.5 + ratio * 0.5 : ratio, inputTokens, at: this.now() });
|
|
25
|
+
if (conversation.offers.size > 64)
|
|
26
|
+
conversation.offers.delete(conversation.offers.keys().next().value);
|
|
27
|
+
this.conversations.delete(conversationKey);
|
|
28
|
+
this.conversations.set(conversationKey, conversation);
|
|
29
|
+
if (this.conversations.size > 500)
|
|
30
|
+
this.conversations.delete(this.conversations.keys().next().value);
|
|
31
|
+
}
|
|
32
|
+
/** Expected cached input tokens for one exact peer/provider/model in this conversation. */
|
|
33
|
+
expectedCachedInputTokens(conversationKey, candidate, promptTokens) {
|
|
34
|
+
const conversation = conversationKey ? this.conversations.get(conversationKey) : undefined;
|
|
35
|
+
const observation = conversation?.offers.get(JSON.stringify([candidate.peerId, candidate.provider, candidate.serviceId]));
|
|
36
|
+
if (!observation || this.now() - observation.at > 3 * 60_000)
|
|
37
|
+
return 0;
|
|
38
|
+
return Math.max(0, Math.round(Math.min(observation.inputTokens * observation.ratio, promptTokens)));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cache-observations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache-observations.js","sourceRoot":"","sources":["../src/cache-observations.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export { scoreCandidates, DEFAULT_WEIGHTS, type ScoringWeights, type ScoredCandidate, type TokenPricingUsdPerMillion, type PeerMetrics, } from './peer-scorer.js';
|
|
2
2
|
export { PeerMetricsTracker, computeFailureCooldownMs, DEFAULT_MAX_FAILURES, DEFAULT_FAILURE_COOLDOWN_MS, MAX_COOLDOWN_DOUBLINGS, type PeerMetricsTrackerConfig, type FailureCooldownOptions, } from './peer-metrics.js';
|
|
3
3
|
export { WELL_KNOWN_TOOL_HINTS, formatToolHints, type ToolHint, } from './tool-hints.js';
|
|
4
|
+
export { ModelRoutingClient, routingProtocolOfTarget, type ModelRoutingClientApi } from './model-routing-client.js';
|
|
5
|
+
export { candidatePricing, findRoutingClientAdapter, InvalidRouterOptionsError, irpCandidateId, irpSuggestAdapter, RouterCannotRankError, routingClientAdapter, validateRouterOptions, type RankCandidate, type RouterOptionSpec, type RoutingClientAdapter, } from './routing-adapters/index.js';
|
|
6
|
+
export { CacheObservations } from './cache-observations.js';
|
|
7
|
+
export { routerModelResolver } from './router-model-names.js';
|
|
4
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,KAAK,QAAQ,GACd,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,eAAe,EACf,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,yBAAyB,EAC9B,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,GAC5B,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,KAAK,QAAQ,GACd,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACnH,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export { scoreCandidates, DEFAULT_WEIGHTS, } from './peer-scorer.js';
|
|
2
2
|
export { PeerMetricsTracker, computeFailureCooldownMs, DEFAULT_MAX_FAILURES, DEFAULT_FAILURE_COOLDOWN_MS, MAX_COOLDOWN_DOUBLINGS, } from './peer-metrics.js';
|
|
3
3
|
export { WELL_KNOWN_TOOL_HINTS, formatToolHints, } from './tool-hints.js';
|
|
4
|
+
export { ModelRoutingClient, routingProtocolOfTarget } from './model-routing-client.js';
|
|
5
|
+
export { candidatePricing, findRoutingClientAdapter, InvalidRouterOptionsError, irpCandidateId, irpSuggestAdapter, RouterCannotRankError, routingClientAdapter, validateRouterOptions, } from './routing-adapters/index.js';
|
|
6
|
+
export { CacheObservations } from './cache-observations.js';
|
|
7
|
+
export { routerModelResolver } from './router-model-names.js';
|
|
4
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,eAAe,GAKhB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,GAGvB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,qBAAqB,EACrB,eAAe,GAEhB,MAAM,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,eAAe,GAKhB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,2BAA2B,EAC3B,sBAAsB,GAGvB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EACL,qBAAqB,EACrB,eAAe,GAEhB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAA8B,MAAM,2BAA2B,CAAA;AACnH,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,GAItB,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type PeerInfo, type RouteRecommendation, type RouterModelEntry, type RouterOptions, type RouteSelectionContext, type RoutingModelsContext, type RoutingProtocol, type RoutingServiceTarget, type RoutingUsageObservation, type SerializedHttpRequest } from '@antseed/node';
|
|
2
|
+
import { CacheObservations } from './cache-observations.js';
|
|
3
|
+
import { type RoutingClientAdapter } from './routing-adapters/types.js';
|
|
4
|
+
/** The routing protocol a target service advertises on its peer. */
|
|
5
|
+
export declare function routingProtocolOfTarget(peers: PeerInfo[], target: RoutingServiceTarget): RoutingProtocol | null;
|
|
6
|
+
/**
|
|
7
|
+
* Buyer side of routing services, independent of any routing protocol:
|
|
8
|
+
* - `listModels`: the models the router can rank (free).
|
|
9
|
+
* - `selectRoute`: one paid ranking per user turn; the router orders the buyer's allowed candidates.
|
|
10
|
+
* - `recordUsage`: observed prompt-cache reuse, given to the router with later candidates.
|
|
11
|
+
* The router's advertised protocol picks the adapter that speaks its wire format
|
|
12
|
+
* (`routing-adapters/`). It never sends inference; the buyer proxy dispatches the result.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ModelRoutingClient {
|
|
15
|
+
private readonly lastRoutes;
|
|
16
|
+
readonly observations: CacheObservations;
|
|
17
|
+
recordUsage(observation: RoutingUsageObservation): void;
|
|
18
|
+
/** The adapter for a target's routing protocol, e.g. to read the options it accepts. */
|
|
19
|
+
adapterFor(target: RoutingServiceTarget, peers: PeerInfo[]): RoutingClientAdapter;
|
|
20
|
+
/** Validate router options for a target before any ranking is bought; throws `InvalidRouterOptionsError`. */
|
|
21
|
+
validateOptions(target: RoutingServiceTarget, peers: PeerInfo[], options: RouterOptions | undefined): RouterOptions;
|
|
22
|
+
listModels(target: RoutingServiceTarget, peers: PeerInfo[], context: RoutingModelsContext): Promise<RouterModelEntry[]>;
|
|
23
|
+
selectRoute(request: SerializedHttpRequest, peers: PeerInfo[], context: RouteSelectionContext): Promise<RouteRecommendation[] | null>;
|
|
24
|
+
}
|
|
25
|
+
/** The `ModelRoutingClient` surface the buyer proxy calls; tests can supply a stand-in. */
|
|
26
|
+
export type ModelRoutingClientApi = Pick<ModelRoutingClient, 'listModels' | 'selectRoute'> & Partial<Pick<ModelRoutingClient, 'recordUsage'>>;
|
|
27
|
+
//# sourceMappingURL=model-routing-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-routing-client.d.ts","sourceRoot":"","sources":["../src/model-routing-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAE3D,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAgC9F,oEAAoE;AACpE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,oBAAoB,GAAG,eAAe,GAAG,IAAI,CAI/G;AAqBD;;;;;;;GAOG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiC;IAC5D,QAAQ,CAAC,YAAY,oBAA0B;IAE/C,WAAW,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI;IAIvD,wFAAwF;IACxF,UAAU,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,oBAAoB;IAIjF,6GAA6G;IAC7G,eAAe,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa;IAI7G,UAAU,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAKvH,WAAW,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,EAAE,GAAG,IAAI,CAAC;CAmC5I;AAED,2FAA2F;AAC3F,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,kBAAkB,EAAE,YAAY,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { routingProtocolOf, routingWireProtocol, } from '@antseed/node';
|
|
2
|
+
import { CacheObservations } from './cache-observations.js';
|
|
3
|
+
import { routingClientAdapter } from './routing-adapters/index.js';
|
|
4
|
+
import { validateRouterOptions } from './routing-adapters/types.js';
|
|
5
|
+
const MAX_CACHED_CONVERSATIONS = 500;
|
|
6
|
+
const decodeJson = (body) => JSON.parse(new TextDecoder().decode(body));
|
|
7
|
+
const encodeJson = (value) => new TextEncoder().encode(JSON.stringify(value));
|
|
8
|
+
function contentText(content) {
|
|
9
|
+
if (typeof content === 'string')
|
|
10
|
+
return content;
|
|
11
|
+
if (!Array.isArray(content))
|
|
12
|
+
return '';
|
|
13
|
+
return content.map(block => typeof block?.text === 'string' ? block.text : '').join('\n');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The latest user-written text in a Chat Completions, Messages or Responses body. User messages
|
|
17
|
+
* without text (e.g. Anthropic `tool_result`-only turns) are skipped, so a tool loop keeps
|
|
18
|
+
* resolving to the prompt that started it.
|
|
19
|
+
*/
|
|
20
|
+
function latestUserText(body) {
|
|
21
|
+
const messages = Array.isArray(body.messages) ? body.messages : Array.isArray(body.input) ? body.input : [];
|
|
22
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
23
|
+
const message = messages[index];
|
|
24
|
+
if (message?.role !== 'user')
|
|
25
|
+
continue;
|
|
26
|
+
const text = contentText(message.content);
|
|
27
|
+
if (text.trim())
|
|
28
|
+
return text;
|
|
29
|
+
}
|
|
30
|
+
return typeof body.input === 'string' ? body.input : '';
|
|
31
|
+
}
|
|
32
|
+
/** The routing protocol a target service advertises on its peer. */
|
|
33
|
+
export function routingProtocolOfTarget(peers, target) {
|
|
34
|
+
const peer = peers.find(entry => entry.peerId === target.peerId);
|
|
35
|
+
const provider = peer?.metadata?.providers?.find(entry => entry.provider === target.provider && entry.services.includes(target.serviceId));
|
|
36
|
+
return routingProtocolOf(provider?.serviceApiProtocols?.[target.serviceId]);
|
|
37
|
+
}
|
|
38
|
+
/** The selected router peer, checked to advertise this exact routing service, and its protocol. */
|
|
39
|
+
function findRouterPeer(peers, target) {
|
|
40
|
+
const peer = peers.find(entry => entry.peerId === target.peerId);
|
|
41
|
+
if (peer && !Array.isArray(peer.metadata?.providers)) {
|
|
42
|
+
throw new Error('Selected router metadata is not available yet. Wait for discovery or restart the router.');
|
|
43
|
+
}
|
|
44
|
+
const provider = peer?.metadata?.providers?.find(entry => entry.provider === target.provider && entry.services.includes(target.serviceId));
|
|
45
|
+
if (!peer || !provider)
|
|
46
|
+
throw new Error('Selected routing service is not advertised by the selected peer');
|
|
47
|
+
const protocol = routingProtocolOf(provider.serviceApiProtocols?.[target.serviceId]);
|
|
48
|
+
if (!protocol)
|
|
49
|
+
throw new Error('Selected service does not advertise a routing protocol');
|
|
50
|
+
// Protocols whose paths name no service need the router peer to offer exactly one service of that protocol.
|
|
51
|
+
if (routingWireProtocol(protocol).oneServicePerSeller) {
|
|
52
|
+
const sameProtocol = peer.metadata.providers.flatMap(entry => entry.services
|
|
53
|
+
.filter(service => routingProtocolOf(entry.serviceApiProtocols?.[service]) === protocol));
|
|
54
|
+
if (sameProtocol.length !== 1)
|
|
55
|
+
throw new Error(`Selected peer advertises more than one ${protocol} routing service`);
|
|
56
|
+
}
|
|
57
|
+
return { peer, protocol };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Buyer side of routing services, independent of any routing protocol:
|
|
61
|
+
* - `listModels`: the models the router can rank (free).
|
|
62
|
+
* - `selectRoute`: one paid ranking per user turn; the router orders the buyer's allowed candidates.
|
|
63
|
+
* - `recordUsage`: observed prompt-cache reuse, given to the router with later candidates.
|
|
64
|
+
* The router's advertised protocol picks the adapter that speaks its wire format
|
|
65
|
+
* (`routing-adapters/`). It never sends inference; the buyer proxy dispatches the result.
|
|
66
|
+
*/
|
|
67
|
+
export class ModelRoutingClient {
|
|
68
|
+
lastRoutes = new Map();
|
|
69
|
+
observations = new CacheObservations();
|
|
70
|
+
recordUsage(observation) {
|
|
71
|
+
this.observations.record(observation);
|
|
72
|
+
}
|
|
73
|
+
/** The adapter for a target's routing protocol, e.g. to read the options it accepts. */
|
|
74
|
+
adapterFor(target, peers) {
|
|
75
|
+
return routingClientAdapter(findRouterPeer(peers, target).protocol);
|
|
76
|
+
}
|
|
77
|
+
/** Validate router options for a target before any ranking is bought; throws `InvalidRouterOptionsError`. */
|
|
78
|
+
validateOptions(target, peers, options) {
|
|
79
|
+
return validateRouterOptions(this.adapterFor(target, peers).options, options);
|
|
80
|
+
}
|
|
81
|
+
async listModels(target, peers, context) {
|
|
82
|
+
const { peer, protocol } = findRouterPeer(peers, target);
|
|
83
|
+
return routingClientAdapter(protocol).listModels(peer, context);
|
|
84
|
+
}
|
|
85
|
+
async selectRoute(request, peers, context) {
|
|
86
|
+
context.signal.throwIfAborted();
|
|
87
|
+
const { peer: router, protocol } = findRouterPeer(peers, context.routingService);
|
|
88
|
+
const adapter = routingClientAdapter(protocol);
|
|
89
|
+
const options = validateRouterOptions(adapter.options, context.options);
|
|
90
|
+
const body = decodeJson(request.body);
|
|
91
|
+
const text = latestUserText(body);
|
|
92
|
+
if (!text.trim())
|
|
93
|
+
throw new Error('Routing requires user text in messages or Responses input');
|
|
94
|
+
if (!context.candidates.length)
|
|
95
|
+
throw new Error('No eligible candidates supported by this router');
|
|
96
|
+
// Tool-loop continuations repeat the same user turn: reuse its recommendation instead of paying
|
|
97
|
+
// again, even when the candidate set changed in between (a peer refresh reorders, adds or drops
|
|
98
|
+
// sellers). A new ranking is bought only when none of the saved picks is still usable.
|
|
99
|
+
const key = context.conversationKey;
|
|
100
|
+
const fingerprint = JSON.stringify([context.routingService, Object.entries(options).sort(([a], [b]) => a.localeCompare(b))]);
|
|
101
|
+
const cached = key ? this.lastRoutes.get(key) : undefined;
|
|
102
|
+
if (cached?.text === text && cached.fingerprint === fingerprint && context.acceptRecommendations(cached.routes)) {
|
|
103
|
+
return structuredClone(cached.routes);
|
|
104
|
+
}
|
|
105
|
+
if (key)
|
|
106
|
+
this.lastRoutes.delete(key);
|
|
107
|
+
// Rough prompt size (characters / 4), used only to cap expected cache reuse.
|
|
108
|
+
const estimatedTokens = Math.ceil(encodeJson(body.messages ?? body.input ?? '').length / 4);
|
|
109
|
+
const candidates = context.candidates.map(candidate => ({
|
|
110
|
+
...candidate,
|
|
111
|
+
expectedCachedInputTokens: this.observations.expectedCachedInputTokens(context.conversationKey, candidate, estimatedTokens),
|
|
112
|
+
}));
|
|
113
|
+
const routes = await adapter.rank({ request, body, router, candidates, options, context });
|
|
114
|
+
if (!context.acceptRecommendations(routes))
|
|
115
|
+
throw new Error('Router returned no usable recommendation');
|
|
116
|
+
if (key) {
|
|
117
|
+
this.lastRoutes.set(key, { text, fingerprint, routes: structuredClone(routes) });
|
|
118
|
+
if (this.lastRoutes.size > MAX_CACHED_CONVERSATIONS)
|
|
119
|
+
this.lastRoutes.delete(this.lastRoutes.keys().next().value);
|
|
120
|
+
}
|
|
121
|
+
return routes;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=model-routing-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-routing-client.js","sourceRoot":"","sources":["../src/model-routing-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RouterModelEntry, type RouterPricing } from '@antseed/node';
|
|
2
|
+
/**
|
|
3
|
+
* Translate seller service IDs into the model names a router lists in its model catalog.
|
|
4
|
+
* An exact name match wins; otherwise names are compared by canonical model key (the same
|
|
5
|
+
* matching the savings baselines use), and the first listed router model wins a tie.
|
|
6
|
+
* When the router lists `*`, unmatched service IDs pass through unchanged.
|
|
7
|
+
* With `pricing`, a candidate priced above the matched entry's `maxPricing` is dropped.
|
|
8
|
+
* Returns `undefined` when the router lists no matching model and no `*`, or the price is over the limit.
|
|
9
|
+
*/
|
|
10
|
+
export declare function routerModelResolver(entries: readonly RouterModelEntry[]): (serviceId: string, pricing?: RouterPricing) => string | undefined;
|
|
11
|
+
//# sourceMappingURL=router-model-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-model-names.d.ts","sourceRoot":"","sources":["../src/router-model-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAA;AAGhH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAoB5I"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ROUTER_ANY_MODEL, withinRouterPricing } from '@antseed/node';
|
|
2
|
+
import { canonicalModelKey } from '@antseed/node/model-identity';
|
|
3
|
+
/**
|
|
4
|
+
* Translate seller service IDs into the model names a router lists in its model catalog.
|
|
5
|
+
* An exact name match wins; otherwise names are compared by canonical model key (the same
|
|
6
|
+
* matching the savings baselines use), and the first listed router model wins a tie.
|
|
7
|
+
* When the router lists `*`, unmatched service IDs pass through unchanged.
|
|
8
|
+
* With `pricing`, a candidate priced above the matched entry's `maxPricing` is dropped.
|
|
9
|
+
* Returns `undefined` when the router lists no matching model and no `*`, or the price is over the limit.
|
|
10
|
+
*/
|
|
11
|
+
export function routerModelResolver(entries) {
|
|
12
|
+
const exact = new Map();
|
|
13
|
+
const byKey = new Map();
|
|
14
|
+
let anyModel;
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
if (entry.id === ROUTER_ANY_MODEL) {
|
|
17
|
+
anyModel = entry;
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
exact.set(entry.id, entry);
|
|
21
|
+
const key = canonicalModelKey(entry.id);
|
|
22
|
+
if (key && !byKey.has(key))
|
|
23
|
+
byKey.set(key, entry);
|
|
24
|
+
}
|
|
25
|
+
return (serviceId, pricing) => {
|
|
26
|
+
const key = canonicalModelKey(serviceId);
|
|
27
|
+
const named = exact.get(serviceId) ?? (key ? byKey.get(key) : undefined);
|
|
28
|
+
const entry = named ?? anyModel;
|
|
29
|
+
if (!entry || (pricing && !withinRouterPricing(pricing, entry.maxPricing)))
|
|
30
|
+
return undefined;
|
|
31
|
+
return named ? named.id : serviceId;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=router-model-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-model-names.js","sourceRoot":"","sources":["../src/router-model-names.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAA6C,MAAM,eAAe,CAAA;AAChH,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAEhE;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAoC;IACtE,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAA;IACjD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA4B,CAAA;IACjD,IAAI,QAAsC,CAAA;IAC1C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,EAAE,KAAK,gBAAgB,EAAE,CAAC;YAClC,QAAQ,GAAG,KAAK,CAAA;YAChB,SAAQ;QACV,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QAC1B,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACvC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACnD,CAAC;IACD,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE;QAC5B,MAAM,GAAG,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QACxE,MAAM,KAAK,GAAG,KAAK,IAAI,QAAQ,CAAA;QAC/B,IAAI,CAAC,KAAK,IAAI,CAAC,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;YAAE,OAAO,SAAS,CAAA;QAC5F,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACrC,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RoutingProtocol } from '@antseed/node';
|
|
2
|
+
import type { RoutingClientAdapter } from './types.js';
|
|
3
|
+
export declare function routingClientAdapter(protocol: RoutingProtocol): RoutingClientAdapter;
|
|
4
|
+
/** The adapter for a protocol string, or null when it is not a routing protocol this buyer speaks. */
|
|
5
|
+
export declare function findRoutingClientAdapter(protocol: string | null | undefined): RoutingClientAdapter | null;
|
|
6
|
+
export { irpSuggestAdapter, irpCandidateId } from './irp.js';
|
|
7
|
+
export { candidatePricing, InvalidRouterOptionsError, RouterCannotRankError, validateRouterOptions, type RankCandidate, type RouterOptionSpec, type RoutingClientAdapter, } from './types.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing-adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA;AAEvE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAOtD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,oBAAoB,CAEpF;AAED,sGAAsG;AACtG,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,oBAAoB,GAAG,IAAI,CAEzG;AAED,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC5D,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isRoutingProtocol } from '@antseed/node';
|
|
2
|
+
import { irpSuggestAdapter } from './irp.js';
|
|
3
|
+
/** One buyer adapter per routing protocol. None is preferred: the router's advertised protocol picks it. */
|
|
4
|
+
const ROUTING_CLIENT_ADAPTERS = {
|
|
5
|
+
'irp-suggest': irpSuggestAdapter,
|
|
6
|
+
};
|
|
7
|
+
export function routingClientAdapter(protocol) {
|
|
8
|
+
return ROUTING_CLIENT_ADAPTERS[protocol];
|
|
9
|
+
}
|
|
10
|
+
/** The adapter for a protocol string, or null when it is not a routing protocol this buyer speaks. */
|
|
11
|
+
export function findRoutingClientAdapter(protocol) {
|
|
12
|
+
return isRoutingProtocol(protocol) ? ROUTING_CLIENT_ADAPTERS[protocol] : null;
|
|
13
|
+
}
|
|
14
|
+
export { irpSuggestAdapter, irpCandidateId } from './irp.js';
|
|
15
|
+
export { candidatePricing, InvalidRouterOptionsError, RouterCannotRankError, validateRouterOptions, } from './types.js';
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routing-adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAwB,MAAM,eAAe,CAAA;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAG5C,4GAA4G;AAC5G,MAAM,uBAAuB,GAAkD;IAC7E,aAAa,EAAE,iBAAiB;CACjC,CAAA;AAED,MAAM,UAAU,oBAAoB,CAAC,QAAyB;IAC5D,OAAO,uBAAuB,CAAC,QAAQ,CAAC,CAAA;AAC1C,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,wBAAwB,CAAC,QAAmC;IAC1E,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC/E,CAAC;AAED,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAC5D,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,GAItB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RouteCandidate } from '@antseed/node';
|
|
2
|
+
import { type RoutingClientAdapter } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* IRP candidate `id`: `provider:model@peer`, readable in buyer and router logs. IDs longer than
|
|
5
|
+
* 128 characters become a SHA-256 of the same string. The buyer always maps IDs back through the
|
|
6
|
+
* candidates it sent and never parses them.
|
|
7
|
+
*/
|
|
8
|
+
export declare function irpCandidateId(candidate: Pick<RouteCandidate, 'peerId' | 'provider' | 'serviceId'>): string;
|
|
9
|
+
/**
|
|
10
|
+
* `irp-suggest`: Inference Routing Protocol suggest-only mode.
|
|
11
|
+
* - catalog: free `GET /v1/routing/models`; `*` means any model, with optional `max_pricing`.
|
|
12
|
+
* - rank: paid `POST /v1/routing/rank`; the router orders the buyer's allowed candidates.
|
|
13
|
+
* - options: `cost_quality_tradeoff`, 0 (best quality) to 10 (cheapest), router default 5.
|
|
14
|
+
*/
|
|
15
|
+
export declare const irpSuggestAdapter: RoutingClientAdapter;
|
|
16
|
+
//# sourceMappingURL=irp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"irp.d.ts","sourceRoot":"","sources":["../../src/routing-adapters/irp.ts"],"names":[],"mappings":"AACA,OAAO,EAkBL,KAAK,cAAc,EAKpB,MAAM,eAAe,CAAA;AACtB,OAAO,EAA2C,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAK/F;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG,MAAM,CAG3G;AA8CD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,oBAuD/B,CAAA"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { IRP_ANY_MODEL, IRP_DEFAULT_COST_QUALITY_TRADEOFF, IRP_MAX_CANDIDATE_ID_LENGTH, IRP_MODELS_PATH, IRP_RANK_PATH, IRP_SUGGEST_PROTOCOL, ROUTER_ANY_MODEL, detectRequestServiceApiProtocol, parseIrpModelEntries, parseIrpProblem, renderRequestBodyAsOpenAIChat, validateIrpRankRequest, validateIrpRankResponse, } from '@antseed/node';
|
|
3
|
+
import { candidatePricing, RouterCannotRankError } from './types.js';
|
|
4
|
+
const decodeJson = (body) => JSON.parse(new TextDecoder().decode(body));
|
|
5
|
+
const encodeJson = (value) => new TextEncoder().encode(JSON.stringify(value));
|
|
6
|
+
/**
|
|
7
|
+
* IRP candidate `id`: `provider:model@peer`, readable in buyer and router logs. IDs longer than
|
|
8
|
+
* 128 characters become a SHA-256 of the same string. The buyer always maps IDs back through the
|
|
9
|
+
* candidates it sent and never parses them.
|
|
10
|
+
*/
|
|
11
|
+
export function irpCandidateId(candidate) {
|
|
12
|
+
const id = `${candidate.provider}:${candidate.serviceId}@${candidate.peerId}`;
|
|
13
|
+
return id.length <= IRP_MAX_CANDIDATE_ID_LENGTH ? id : `sha256:${createHash('sha256').update(id).digest('hex')}`;
|
|
14
|
+
}
|
|
15
|
+
function toIrpPricing(pricing) {
|
|
16
|
+
return { input: pricing.inputUsdPerMillion, cache_read: pricing.cachedInputUsdPerMillion, output: pricing.outputUsdPerMillion };
|
|
17
|
+
}
|
|
18
|
+
function fromIrpPricing(pricing) {
|
|
19
|
+
return {
|
|
20
|
+
...(pricing.input !== undefined ? { inputUsdPerMillion: pricing.input } : {}),
|
|
21
|
+
...(pricing.cache_read !== undefined ? { cachedInputUsdPerMillion: pricing.cache_read } : {}),
|
|
22
|
+
...(pricing.output !== undefined ? { outputUsdPerMillion: pricing.output } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The request being routed as an OpenAI Chat Completions body (IRP `request`). Anthropic Messages
|
|
27
|
+
* and Responses bodies run through the same adapters used for dispatch. `model` and `stream` are
|
|
28
|
+
* dropped: routers ignore them and never forward the request.
|
|
29
|
+
*/
|
|
30
|
+
function irpInferenceRequest(request, body) {
|
|
31
|
+
const protocol = detectRequestServiceApiProtocol(request);
|
|
32
|
+
const chat = protocol ? renderRequestBodyAsOpenAIChat(protocol, body) : null;
|
|
33
|
+
if (!chat)
|
|
34
|
+
throw new Error('Routing supports Chat Completions, Anthropic Messages and Responses requests');
|
|
35
|
+
delete chat.model;
|
|
36
|
+
delete chat.stream;
|
|
37
|
+
delete chat.stream_options;
|
|
38
|
+
if (!Array.isArray(chat.messages) || chat.messages.length === 0)
|
|
39
|
+
throw new Error('Routing requires at least one message');
|
|
40
|
+
return chat;
|
|
41
|
+
}
|
|
42
|
+
/** Error text for a non-2xx router response, using IRP problem details when present. */
|
|
43
|
+
function routerFailure(action, statusCode, body) {
|
|
44
|
+
let problem = null;
|
|
45
|
+
try {
|
|
46
|
+
problem = parseIrpProblem(decodeJson(body));
|
|
47
|
+
}
|
|
48
|
+
catch { /* not JSON */ }
|
|
49
|
+
const detail = problem?.detail ?? problem?.title;
|
|
50
|
+
const suffix = detail ? `: ${detail}` : '';
|
|
51
|
+
switch (statusCode) {
|
|
52
|
+
case 400: return new Error(`Router rejected the ${action} request${suffix}`);
|
|
53
|
+
case 402: return new Error('Routing payment could not be completed. The channel may have unpaid or disputed work. Select a model or another router.');
|
|
54
|
+
// IRP 422: no candidate could be scored; the buyer's model list may be stale.
|
|
55
|
+
case 422: return new RouterCannotRankError(`Router cannot rank any allowed candidate. Update the allowed models or choose another router${suffix}`);
|
|
56
|
+
case 503: return new Error(`Router is temporarily unavailable${suffix}`);
|
|
57
|
+
default: return new Error(`Routing ${action} failed (${statusCode})${suffix}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `irp-suggest`: Inference Routing Protocol suggest-only mode.
|
|
62
|
+
* - catalog: free `GET /v1/routing/models`; `*` means any model, with optional `max_pricing`.
|
|
63
|
+
* - rank: paid `POST /v1/routing/rank`; the router orders the buyer's allowed candidates.
|
|
64
|
+
* - options: `cost_quality_tradeoff`, 0 (best quality) to 10 (cheapest), router default 5.
|
|
65
|
+
*/
|
|
66
|
+
export const irpSuggestAdapter = {
|
|
67
|
+
protocol: IRP_SUGGEST_PROTOCOL,
|
|
68
|
+
options: [{
|
|
69
|
+
key: 'cost_quality_tradeoff',
|
|
70
|
+
type: 'integer',
|
|
71
|
+
label: 'Cost vs. quality',
|
|
72
|
+
description: '0 picks the best quality regardless of price; 10 picks the cheapest acceptable model.',
|
|
73
|
+
minimum: 0,
|
|
74
|
+
maximum: 10,
|
|
75
|
+
default: IRP_DEFAULT_COST_QUALITY_TRADEOFF,
|
|
76
|
+
}],
|
|
77
|
+
async listModels(router, context) {
|
|
78
|
+
const response = await context.sendRequest(router, {
|
|
79
|
+
requestId: randomUUID(), method: 'GET', path: IRP_MODELS_PATH,
|
|
80
|
+
headers: { accept: 'application/json' },
|
|
81
|
+
body: new Uint8Array(),
|
|
82
|
+
});
|
|
83
|
+
context.signal.throwIfAborted();
|
|
84
|
+
if (response.statusCode < 200 || response.statusCode >= 300)
|
|
85
|
+
throw routerFailure('models', response.statusCode, response.body);
|
|
86
|
+
return parseIrpModelEntries(decodeJson(response.body)).map((entry) => ({
|
|
87
|
+
id: entry.id === IRP_ANY_MODEL ? ROUTER_ANY_MODEL : entry.id,
|
|
88
|
+
...(entry.max_pricing ? { maxPricing: fromIrpPricing(entry.max_pricing) } : {}),
|
|
89
|
+
}));
|
|
90
|
+
},
|
|
91
|
+
async rank({ request, body, router, candidates, options, context }) {
|
|
92
|
+
const sent = candidates.map((candidate) => ({
|
|
93
|
+
id: irpCandidateId(candidate),
|
|
94
|
+
model: candidate.routerModel ?? candidate.serviceId,
|
|
95
|
+
pricing: toIrpPricing(candidatePricing(candidate)),
|
|
96
|
+
// Absent means 0, so only send what was observed.
|
|
97
|
+
...(candidate.expectedCachedInputTokens > 0 ? { expected_usage: { cache_read_tokens: candidate.expectedCachedInputTokens } } : {}),
|
|
98
|
+
}));
|
|
99
|
+
const rankRequest = {
|
|
100
|
+
request: irpInferenceRequest(request, body),
|
|
101
|
+
routing: {
|
|
102
|
+
...(typeof options.cost_quality_tradeoff === 'number' ? { cost_quality_tradeoff: options.cost_quality_tradeoff } : {}),
|
|
103
|
+
candidates: sent,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
validateIrpRankRequest(rankRequest);
|
|
107
|
+
const response = await context.sendRequest(router, {
|
|
108
|
+
requestId: randomUUID(), method: 'POST', path: IRP_RANK_PATH,
|
|
109
|
+
headers: { 'content-type': 'application/json' },
|
|
110
|
+
body: encodeJson(rankRequest),
|
|
111
|
+
}, { signal: context.signal });
|
|
112
|
+
context.signal.throwIfAborted();
|
|
113
|
+
if (response.statusCode < 200 || response.statusCode >= 300)
|
|
114
|
+
throw routerFailure('rank', response.statusCode, response.body);
|
|
115
|
+
const byId = new Map(sent.map((candidate, index) => [candidate.id, candidates[index]]));
|
|
116
|
+
return validateIrpRankResponse(decodeJson(response.body), sent).map((entry) => {
|
|
117
|
+
const { serviceId, peerId, provider } = byId.get(entry.candidate_id);
|
|
118
|
+
return { serviceId, peerId, provider, ...(entry.reasoning_effort ? { reasoningEffort: entry.reasoning_effort } : {}) };
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=irp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"irp.js","sourceRoot":"","sources":["../../src/routing-adapters/irp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { PeerInfo, RouteCandidate, RouteRecommendation, RouterModelEntry, RouterOptions, RouterPricing, RoutingModelsContext, RoutingProtocol, RouteSelectionContext, SerializedHttpRequest } from '@antseed/node';
|
|
2
|
+
/**
|
|
3
|
+
* One setting a router accepts with each ranking, described so a host (CLI, desktop) can
|
|
4
|
+
* validate it and render a control for it without knowing the routing protocol.
|
|
5
|
+
*/
|
|
6
|
+
export type RouterOptionSpec = {
|
|
7
|
+
key: string;
|
|
8
|
+
label: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
} & ({
|
|
11
|
+
type: 'integer' | 'number';
|
|
12
|
+
minimum?: number;
|
|
13
|
+
maximum?: number;
|
|
14
|
+
default?: number;
|
|
15
|
+
} | {
|
|
16
|
+
type: 'boolean';
|
|
17
|
+
default?: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'string';
|
|
20
|
+
values?: readonly string[];
|
|
21
|
+
default?: string;
|
|
22
|
+
});
|
|
23
|
+
/** A candidate the buyer allows, with the prompt-cache reuse it observed for it. */
|
|
24
|
+
export type RankCandidate = RouteCandidate & {
|
|
25
|
+
expectedCachedInputTokens: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Buyer side of one routing protocol. The protocol-neutral `ModelRoutingClient` picks the
|
|
29
|
+
* adapter by the protocol the router advertises; adding a routing API means adding an adapter
|
|
30
|
+
* here, its wire binding in `@antseed/protocol/routing`, and a provider plugin for sellers.
|
|
31
|
+
*/
|
|
32
|
+
export interface RoutingClientAdapter {
|
|
33
|
+
readonly protocol: RoutingProtocol;
|
|
34
|
+
/** Settings this protocol accepts with each ranking. Unknown keys are rejected. */
|
|
35
|
+
readonly options: readonly RouterOptionSpec[];
|
|
36
|
+
/** The models the router can rank: a free control-plane request. */
|
|
37
|
+
listModels(router: PeerInfo, context: RoutingModelsContext): Promise<RouterModelEntry[]>;
|
|
38
|
+
/**
|
|
39
|
+
* The paid ranking. Returns allowed candidates in the router's order, each at most once;
|
|
40
|
+
* a router can never name a destination the buyer did not send.
|
|
41
|
+
*/
|
|
42
|
+
rank(args: {
|
|
43
|
+
request: SerializedHttpRequest;
|
|
44
|
+
/** `request.body`, decoded. */
|
|
45
|
+
body: Record<string, unknown>;
|
|
46
|
+
router: PeerInfo;
|
|
47
|
+
candidates: readonly RankCandidate[];
|
|
48
|
+
options: RouterOptions;
|
|
49
|
+
context: RouteSelectionContext;
|
|
50
|
+
}): Promise<RouteRecommendation[]>;
|
|
51
|
+
}
|
|
52
|
+
/** The router says none of the candidates can be ranked; the host may refresh the model list and retry once. */
|
|
53
|
+
export declare class RouterCannotRankError extends Error {
|
|
54
|
+
constructor(message: string);
|
|
55
|
+
}
|
|
56
|
+
/** Router settings that the router's protocol does not accept; nothing was paid. */
|
|
57
|
+
export declare class InvalidRouterOptionsError extends Error {
|
|
58
|
+
constructor(message: string);
|
|
59
|
+
}
|
|
60
|
+
/** Check `options` against a protocol's option specs; throws `InvalidRouterOptionsError`. */
|
|
61
|
+
export declare function validateRouterOptions(specs: readonly RouterOptionSpec[], options: RouterOptions | undefined): RouterOptions;
|
|
62
|
+
/** Candidate pricing for a router; sellers without a cached-input price bill cache reads at the input price. */
|
|
63
|
+
export declare function candidatePricing(candidate: Pick<RouteCandidate, 'inputUsdPerMillion' | 'outputUsdPerMillion' | 'cachedInputUsdPerMillion'>): RouterPricing;
|
|
64
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing-adapters/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,qBAAqB,EACrB,qBAAqB,EACtB,MAAM,eAAe,CAAA;AAEtB;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,CACA;IAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACpF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CACnE,CAAA;AAED,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG;IAAE,yBAAyB,EAAE,MAAM,CAAA;CAAE,CAAA;AAElF;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAA;IAClC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAA;IAC7C,oEAAoE;IACpE,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;IACxF;;;OAGG;IACH,IAAI,CAAC,IAAI,EAAE;QACT,OAAO,EAAE,qBAAqB,CAAA;QAC9B,+BAA+B;QAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7B,MAAM,EAAE,QAAQ,CAAA;QAChB,UAAU,EAAE,SAAS,aAAa,EAAE,CAAA;QACpC,OAAO,EAAE,aAAa,CAAA;QACtB,OAAO,EAAE,qBAAqB,CAAA;KAC/B,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAA;CACnC;AAED,gHAAgH;AAChH,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,oFAAoF;AACpF,qBAAa,yBAA0B,SAAQ,KAAK;gBACtC,OAAO,EAAE,MAAM;CAI5B;AAED,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,SAAS,GAAG,aAAa,CAwB3H;AAED,gHAAgH;AAChH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,oBAAoB,GAAG,qBAAqB,GAAG,0BAA0B,CAAC,GAAG,aAAa,CAM1J"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** The router says none of the candidates can be ranked; the host may refresh the model list and retry once. */
|
|
2
|
+
export class RouterCannotRankError extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = 'RouterCannotRankError';
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Router settings that the router's protocol does not accept; nothing was paid. */
|
|
9
|
+
export class InvalidRouterOptionsError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'InvalidRouterOptionsError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Check `options` against a protocol's option specs; throws `InvalidRouterOptionsError`. */
|
|
16
|
+
export function validateRouterOptions(specs, options) {
|
|
17
|
+
if (options === undefined)
|
|
18
|
+
return {};
|
|
19
|
+
const byKey = new Map(specs.map(spec => [spec.key, spec]));
|
|
20
|
+
const unknown = Object.keys(options).filter(key => !byKey.has(key));
|
|
21
|
+
if (unknown.length) {
|
|
22
|
+
const supported = specs.map(spec => spec.key).join(', ') || 'none';
|
|
23
|
+
throw new InvalidRouterOptionsError(`Unknown router option(s): ${unknown.join(', ')}. Supported: ${supported}.`);
|
|
24
|
+
}
|
|
25
|
+
for (const [key, value] of Object.entries(options)) {
|
|
26
|
+
const spec = byKey.get(key);
|
|
27
|
+
const fail = (expected) => { throw new InvalidRouterOptionsError(`Router option ${key} must be ${expected}.`); };
|
|
28
|
+
if (spec.type === 'boolean') {
|
|
29
|
+
if (typeof value !== 'boolean')
|
|
30
|
+
fail('true or false');
|
|
31
|
+
}
|
|
32
|
+
else if (spec.type === 'string') {
|
|
33
|
+
if (typeof value !== 'string' || (spec.values && !spec.values.includes(value)))
|
|
34
|
+
fail(spec.values ? `one of ${spec.values.join(', ')}` : 'a string');
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const range = spec.minimum !== undefined && spec.maximum !== undefined ? ` from ${spec.minimum} to ${spec.maximum}` : '';
|
|
38
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || (spec.type === 'integer' && !Number.isInteger(value))
|
|
39
|
+
|| (spec.minimum !== undefined && value < spec.minimum) || (spec.maximum !== undefined && value > spec.maximum)) {
|
|
40
|
+
fail(`${spec.type === 'integer' ? 'an integer' : 'a number'}${range}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { ...options };
|
|
45
|
+
}
|
|
46
|
+
/** Candidate pricing for a router; sellers without a cached-input price bill cache reads at the input price. */
|
|
47
|
+
export function candidatePricing(candidate) {
|
|
48
|
+
return {
|
|
49
|
+
inputUsdPerMillion: candidate.inputUsdPerMillion,
|
|
50
|
+
cachedInputUsdPerMillion: candidate.cachedInputUsdPerMillion ?? candidate.inputUsdPerMillion,
|
|
51
|
+
outputUsdPerMillion: candidate.outputUsdPerMillion,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/routing-adapters/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antseed/router-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.50",
|
|
4
4
|
"description": "Shared router infrastructure for Antseed plugins",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"devDependencies": {
|
|
15
15
|
"typescript": "^5.5.0",
|
|
16
16
|
"vitest": "^2.0.0",
|
|
17
|
-
"@antseed/node": "0.2.
|
|
17
|
+
"@antseed/node": "0.2.143"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"prebuild": "node ../../scripts/remove-paths.mjs dist",
|