@antseed/router-core 0.1.46 → 0.1.48
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 +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/model-routing-client.d.ts +34 -0
- package/dist/model-routing-client.d.ts.map +1 -0
- package/dist/model-routing-client.js +202 -0
- package/dist/model-routing-client.js.map +1 -0
- package/dist/peer-scorer.d.ts.map +1 -1
- package/dist/peer-scorer.js +2 -2
- package/dist/peer-scorer.js.map +1 -1
- 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/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,7 @@
|
|
|
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 { candidatePricing, ModelRoutingClient, RouterCannotRankError, type ModelRoutingClientApi } from './model-routing-client.js';
|
|
5
|
+
export { CacheObservations } from './cache-observations.js';
|
|
6
|
+
export { routerModelResolver } from './router-model-names.js';
|
|
4
7
|
//# 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,gBAAgB,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACnI,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
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 { candidatePricing, ModelRoutingClient, RouterCannotRankError } from './model-routing-client.js';
|
|
5
|
+
export { CacheObservations } from './cache-observations.js';
|
|
6
|
+
export { routerModelResolver } from './router-model-names.js';
|
|
4
7
|
//# 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,gBAAgB,EAAE,kBAAkB,EAAE,qBAAqB,EAA8B,MAAM,2BAA2B,CAAA;AACnI,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type PeerInfo, type RouteCandidate, type RouteRecommendation, type RouteSelectionContext, type RoutingModelsContext, type RoutingModelEntryV1, type RoutingPricingV1, type RoutingServiceTarget, type RoutingUsageObservation, type SerializedHttpRequest } from '@antseed/node';
|
|
2
|
+
import { CacheObservations } from './cache-observations.js';
|
|
3
|
+
/** IRP 422: no candidate could be scored. The host may refresh the model list and retry once. */
|
|
4
|
+
export declare class RouterCannotRankError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* IRP candidate `id`: `provider:model@peer`, readable in buyer and router logs. IDs longer than
|
|
9
|
+
* 128 characters become a SHA-256 of the same string. The buyer always maps IDs back through the
|
|
10
|
+
* candidates it sent and never parses them.
|
|
11
|
+
*/
|
|
12
|
+
/** IRP candidate pricing; sellers without a cached-input price bill cache reads at the input price. */
|
|
13
|
+
export declare function candidatePricing(candidate: Pick<RouteCandidate, 'inputUsdPerMillion' | 'outputUsdPerMillion' | 'cachedInputUsdPerMillion'>): RoutingPricingV1;
|
|
14
|
+
export declare function routingCandidateId(candidate: Pick<RouteCandidate, 'peerId' | 'provider' | 'serviceId'>): string;
|
|
15
|
+
/**
|
|
16
|
+
* Buyer side of `model-routing`, AntSeed's binding of Inference Routing Protocol suggest-only mode:
|
|
17
|
+
* - `listModels`: free `GET /v1/routing/models`; the models the router can score, with any `max_pricing`.
|
|
18
|
+
* - `selectRoute`: paid `POST /v1/routing/rank` once per user turn; the router orders the buyer's allowed candidates.
|
|
19
|
+
* - `recordUsage`: observed prompt-cache reuse, sent to the router with later candidates.
|
|
20
|
+
* It never sends inference; the buyer proxy dispatches the returned recommendations.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ModelRoutingClient {
|
|
23
|
+
private readonly lastRoutes;
|
|
24
|
+
readonly observations: CacheObservations;
|
|
25
|
+
recordUsage(observation: RoutingUsageObservation): void;
|
|
26
|
+
listModels(target: RoutingServiceTarget, peers: PeerInfo[], context: RoutingModelsContext): Promise<RoutingModelEntryV1[]>;
|
|
27
|
+
selectRoute(request: SerializedHttpRequest, peers: PeerInfo[], context: RouteSelectionContext): Promise<RouteRecommendation[] | null>;
|
|
28
|
+
private buildRankRequest;
|
|
29
|
+
/** The paid call. Keeps only ranked entries naming a sent candidate, in the router's order. */
|
|
30
|
+
private rank;
|
|
31
|
+
}
|
|
32
|
+
/** The `ModelRoutingClient` surface the buyer proxy calls; tests can supply a stand-in. */
|
|
33
|
+
export type ModelRoutingClientApi = Pick<ModelRoutingClient, 'listModels' | 'selectRoute'> & Partial<Pick<ModelRoutingClient, 'recordUsage'>>;
|
|
34
|
+
//# 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":"AACA,OAAO,EAWL,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAE1B,KAAK,oBAAoB,EAEzB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAErB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAiF3D,iGAAiG;AACjG,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;GAIG;AACH,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,oBAAoB,GAAG,qBAAqB,GAAG,0BAA0B,CAAC,GAAG,gBAAgB,CAM7J;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG,MAAM,CAG/G;AAED;;;;;;GAMG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAiC;IAC5D,QAAQ,CAAC,YAAY,oBAA0B;IAE/C,WAAW,CAAC,WAAW,EAAE,uBAAuB,GAAG,IAAI;IAIjD,UAAU,CAAC,MAAM,EAAE,oBAAoB,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAW1H,WAAW,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,mBAAmB,EAAE,GAAG,IAAI,CAAC;IA4B3I,OAAO,CAAC,gBAAgB;IAqBxB,+FAA+F;YACjF,IAAI;CAiBnB;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,202 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { MAX_ROUTING_CANDIDATE_ID_LENGTH, MODEL_ROUTING_MODELS_PATH, MODEL_ROUTING_PROTOCOL, MODEL_ROUTING_RANK_PATH, detectRequestServiceApiProtocol, parseRoutingModelEntries, parseRoutingProblem, renderRequestBodyAsOpenAIChat, validateRoutingRankRequest, validateRoutingRankResponse, } from '@antseed/node';
|
|
3
|
+
import { CacheObservations } from './cache-observations.js';
|
|
4
|
+
const MAX_CACHED_CONVERSATIONS = 500;
|
|
5
|
+
const decodeJson = (body) => JSON.parse(new TextDecoder().decode(body));
|
|
6
|
+
const encodeJson = (value) => new TextEncoder().encode(JSON.stringify(value));
|
|
7
|
+
function contentText(content) {
|
|
8
|
+
if (typeof content === 'string')
|
|
9
|
+
return content;
|
|
10
|
+
if (!Array.isArray(content))
|
|
11
|
+
return '';
|
|
12
|
+
return content.map(block => typeof block?.text === 'string' ? block.text : '').join('\n');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The latest user-written text in a Chat Completions, Messages or Responses body. User messages
|
|
16
|
+
* without text (e.g. Anthropic `tool_result`-only turns) are skipped, so a tool loop keeps
|
|
17
|
+
* resolving to the prompt that started it.
|
|
18
|
+
*/
|
|
19
|
+
function latestUserText(body) {
|
|
20
|
+
const messages = Array.isArray(body.messages) ? body.messages : Array.isArray(body.input) ? body.input : [];
|
|
21
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
22
|
+
const message = messages[index];
|
|
23
|
+
if (message?.role !== 'user')
|
|
24
|
+
continue;
|
|
25
|
+
const text = contentText(message.content);
|
|
26
|
+
if (text.trim())
|
|
27
|
+
return text;
|
|
28
|
+
}
|
|
29
|
+
return typeof body.input === 'string' ? body.input : '';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The request being routed as an OpenAI Chat Completions body. Anthropic Messages and Responses
|
|
33
|
+
* bodies run through the same adapters used for dispatch. `model` and `stream` are dropped:
|
|
34
|
+
* routers ignore them and never forward the request.
|
|
35
|
+
*/
|
|
36
|
+
function routingInferenceRequest(request, body) {
|
|
37
|
+
const protocol = detectRequestServiceApiProtocol(request);
|
|
38
|
+
const chat = protocol ? renderRequestBodyAsOpenAIChat(protocol, body) : null;
|
|
39
|
+
if (!chat)
|
|
40
|
+
throw new Error('Routing supports Chat Completions, Anthropic Messages and Responses requests');
|
|
41
|
+
delete chat.model;
|
|
42
|
+
delete chat.stream;
|
|
43
|
+
delete chat.stream_options;
|
|
44
|
+
if (!Array.isArray(chat.messages) || chat.messages.length === 0)
|
|
45
|
+
throw new Error('Routing requires at least one message');
|
|
46
|
+
return chat;
|
|
47
|
+
}
|
|
48
|
+
/** The selected router peer, checked to advertise this exact model-routing service. */
|
|
49
|
+
function findRouterPeer(peers, target) {
|
|
50
|
+
const peer = peers.find(entry => entry.peerId === target.peerId);
|
|
51
|
+
if (peer && !Array.isArray(peer.metadata?.providers)) {
|
|
52
|
+
throw new Error('Selected router metadata is not available yet. Wait for discovery or restart the router.');
|
|
53
|
+
}
|
|
54
|
+
const provider = peer?.metadata?.providers.find(entry => entry.provider === target.provider && entry.services.includes(target.serviceId));
|
|
55
|
+
if (!peer || !provider)
|
|
56
|
+
throw new Error('Selected routing service is not advertised by the selected peer');
|
|
57
|
+
if (!provider.serviceApiProtocols?.[target.serviceId]?.includes(MODEL_ROUTING_PROTOCOL)) {
|
|
58
|
+
throw new Error('Selected service does not advertise model-routing');
|
|
59
|
+
}
|
|
60
|
+
// IRP paths carry no service name, so a router peer must offer exactly one routing service.
|
|
61
|
+
const routingServices = peer.metadata.providers.flatMap(entry => entry.services
|
|
62
|
+
.filter(service => entry.serviceApiProtocols?.[service]?.includes(MODEL_ROUTING_PROTOCOL)));
|
|
63
|
+
if (routingServices.length !== 1)
|
|
64
|
+
throw new Error('Selected peer advertises more than one model-routing service');
|
|
65
|
+
return peer;
|
|
66
|
+
}
|
|
67
|
+
/** Error text for a non-2xx router response, using IRP problem details when present. */
|
|
68
|
+
function routerFailure(action, statusCode, body) {
|
|
69
|
+
let problem = null;
|
|
70
|
+
try {
|
|
71
|
+
problem = parseRoutingProblem(decodeJson(body));
|
|
72
|
+
}
|
|
73
|
+
catch { /* not JSON */ }
|
|
74
|
+
const detail = problem?.detail ?? problem?.title;
|
|
75
|
+
const suffix = detail ? `: ${detail}` : '';
|
|
76
|
+
switch (statusCode) {
|
|
77
|
+
case 400: return new Error(`Router rejected the ${action} request${suffix}`);
|
|
78
|
+
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.');
|
|
79
|
+
case 422: return new RouterCannotRankError(`Router cannot rank any allowed candidate. Update the allowed models or choose another router${suffix}`);
|
|
80
|
+
case 503: return new Error(`Router is temporarily unavailable${suffix}`);
|
|
81
|
+
default: return new Error(`Routing ${action} failed (${statusCode})${suffix}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** IRP 422: no candidate could be scored. The host may refresh the model list and retry once. */
|
|
85
|
+
export class RouterCannotRankError extends Error {
|
|
86
|
+
constructor(message) {
|
|
87
|
+
super(message);
|
|
88
|
+
this.name = 'RouterCannotRankError';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* IRP candidate `id`: `provider:model@peer`, readable in buyer and router logs. IDs longer than
|
|
93
|
+
* 128 characters become a SHA-256 of the same string. The buyer always maps IDs back through the
|
|
94
|
+
* candidates it sent and never parses them.
|
|
95
|
+
*/
|
|
96
|
+
/** IRP candidate pricing; sellers without a cached-input price bill cache reads at the input price. */
|
|
97
|
+
export function candidatePricing(candidate) {
|
|
98
|
+
return {
|
|
99
|
+
input: candidate.inputUsdPerMillion,
|
|
100
|
+
cache_read: candidate.cachedInputUsdPerMillion ?? candidate.inputUsdPerMillion,
|
|
101
|
+
output: candidate.outputUsdPerMillion,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function routingCandidateId(candidate) {
|
|
105
|
+
const id = `${candidate.provider}:${candidate.serviceId}@${candidate.peerId}`;
|
|
106
|
+
return id.length <= MAX_ROUTING_CANDIDATE_ID_LENGTH ? id : `sha256:${createHash('sha256').update(id).digest('hex')}`;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Buyer side of `model-routing`, AntSeed's binding of Inference Routing Protocol suggest-only mode:
|
|
110
|
+
* - `listModels`: free `GET /v1/routing/models`; the models the router can score, with any `max_pricing`.
|
|
111
|
+
* - `selectRoute`: paid `POST /v1/routing/rank` once per user turn; the router orders the buyer's allowed candidates.
|
|
112
|
+
* - `recordUsage`: observed prompt-cache reuse, sent to the router with later candidates.
|
|
113
|
+
* It never sends inference; the buyer proxy dispatches the returned recommendations.
|
|
114
|
+
*/
|
|
115
|
+
export class ModelRoutingClient {
|
|
116
|
+
lastRoutes = new Map();
|
|
117
|
+
observations = new CacheObservations();
|
|
118
|
+
recordUsage(observation) {
|
|
119
|
+
this.observations.record(observation);
|
|
120
|
+
}
|
|
121
|
+
async listModels(target, peers, context) {
|
|
122
|
+
const response = await context.sendRequest(findRouterPeer(peers, target), {
|
|
123
|
+
requestId: randomUUID(), method: 'GET', path: MODEL_ROUTING_MODELS_PATH,
|
|
124
|
+
headers: { accept: 'application/json' },
|
|
125
|
+
body: new Uint8Array(),
|
|
126
|
+
});
|
|
127
|
+
context.signal.throwIfAborted();
|
|
128
|
+
if (response.statusCode < 200 || response.statusCode >= 300)
|
|
129
|
+
throw routerFailure('models', response.statusCode, response.body);
|
|
130
|
+
return parseRoutingModelEntries(decodeJson(response.body));
|
|
131
|
+
}
|
|
132
|
+
async selectRoute(request, peers, context) {
|
|
133
|
+
context.signal.throwIfAborted();
|
|
134
|
+
const body = decodeJson(request.body);
|
|
135
|
+
const text = latestUserText(body);
|
|
136
|
+
if (!text.trim())
|
|
137
|
+
throw new Error('Routing requires user text in messages or Responses input');
|
|
138
|
+
if (!context.candidates.length)
|
|
139
|
+
throw new Error('No eligible candidates supported by this router');
|
|
140
|
+
const rankRequest = this.buildRankRequest(routingInferenceRequest(request, body), context);
|
|
141
|
+
validateRoutingRankRequest(rankRequest);
|
|
142
|
+
// Tool-loop continuations repeat the same user turn: reuse its recommendation instead of paying
|
|
143
|
+
// again, even when the candidate set changed in between (a peer refresh reorders, adds or drops
|
|
144
|
+
// sellers). A new ranking is bought only when none of the saved picks is still usable.
|
|
145
|
+
const key = context.conversationKey;
|
|
146
|
+
const fingerprint = JSON.stringify([context.routingService, context.costQualityTradeoff ?? null]);
|
|
147
|
+
const cached = key ? this.lastRoutes.get(key) : undefined;
|
|
148
|
+
if (cached?.text === text && cached.fingerprint === fingerprint && context.acceptRecommendations(cached.routes)) {
|
|
149
|
+
return structuredClone(cached.routes);
|
|
150
|
+
}
|
|
151
|
+
if (key)
|
|
152
|
+
this.lastRoutes.delete(key);
|
|
153
|
+
const routes = await this.rank(rankRequest, findRouterPeer(peers, context.routingService), context);
|
|
154
|
+
if (key) {
|
|
155
|
+
this.lastRoutes.set(key, { text, fingerprint, routes: structuredClone(routes) });
|
|
156
|
+
if (this.lastRoutes.size > MAX_CACHED_CONVERSATIONS)
|
|
157
|
+
this.lastRoutes.delete(this.lastRoutes.keys().next().value);
|
|
158
|
+
}
|
|
159
|
+
return routes;
|
|
160
|
+
}
|
|
161
|
+
buildRankRequest(inference, context) {
|
|
162
|
+
// Rough prompt size (characters / 4), used only to cap expected cache reuse.
|
|
163
|
+
const estimatedTokens = Math.ceil(encodeJson(inference.messages).length / 4);
|
|
164
|
+
return {
|
|
165
|
+
request: inference,
|
|
166
|
+
routing: {
|
|
167
|
+
...(context.costQualityTradeoff !== undefined ? { cost_quality_tradeoff: context.costQualityTradeoff } : {}),
|
|
168
|
+
candidates: context.candidates.map((candidate) => {
|
|
169
|
+
const cacheReadTokens = this.observations.expectedCachedInputTokens(context.conversationKey, candidate, estimatedTokens);
|
|
170
|
+
return {
|
|
171
|
+
id: routingCandidateId(candidate),
|
|
172
|
+
model: candidate.routerModel ?? candidate.serviceId,
|
|
173
|
+
pricing: candidatePricing(candidate),
|
|
174
|
+
// Absent means 0, so only send what was observed.
|
|
175
|
+
...(cacheReadTokens > 0 ? { expected_usage: { cache_read_tokens: cacheReadTokens } } : {}),
|
|
176
|
+
};
|
|
177
|
+
}),
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/** The paid call. Keeps only ranked entries naming a sent candidate, in the router's order. */
|
|
182
|
+
async rank(rankRequest, routerPeer, context) {
|
|
183
|
+
const response = await context.sendRequest(routerPeer, {
|
|
184
|
+
requestId: randomUUID(), method: 'POST', path: MODEL_ROUTING_RANK_PATH,
|
|
185
|
+
headers: { 'content-type': 'application/json' },
|
|
186
|
+
body: encodeJson(rankRequest),
|
|
187
|
+
}, { signal: context.signal });
|
|
188
|
+
context.signal.throwIfAborted();
|
|
189
|
+
if (response.statusCode < 200 || response.statusCode >= 300)
|
|
190
|
+
throw routerFailure('rank', response.statusCode, response.body);
|
|
191
|
+
const candidates = rankRequest.routing.candidates;
|
|
192
|
+
const byId = new Map(candidates.map((candidate, index) => [candidate.id, context.candidates[index]]));
|
|
193
|
+
const routes = validateRoutingRankResponse(decodeJson(response.body), candidates).map((entry) => {
|
|
194
|
+
const { serviceId, peerId, provider } = byId.get(entry.candidate_id);
|
|
195
|
+
return { serviceId, peerId, provider, ...(entry.reasoning_effort ? { reasoningEffort: entry.reasoning_effort } : {}) };
|
|
196
|
+
});
|
|
197
|
+
if (!context.acceptRecommendations(routes))
|
|
198
|
+
throw new Error('Router returned no usable recommendation');
|
|
199
|
+
return routes;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
//# 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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer-scorer.d.ts","sourceRoot":"","sources":["../src/peer-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"peer-scorer.d.ts","sourceRoot":"","sources":["../src/peer-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7E,MAAM,WAAW,yBAAyB;IACxC,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,wBAAwB,CAAC,EAAE,MAAM,CAAA;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,eAAO,MAAM,eAAe,EAAE,cAO7B,CAAA;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,yBAAyB,CAAA;IAChC,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,yBAAyB,CAAA;IAChC,OAAO,EAAE,WAAW,CAAA;CACrB;AAED,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,EAAE,MAAM,CAAA;IACrB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;CAClC;AA6CD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,cAAc,EAAE,EAC5B,OAAO,EAAE,cAAc,GACtB,eAAe,EAAE,CAkFnB"}
|
package/dist/peer-scorer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizedModelReputationScore } from '@antseed/node';
|
|
2
2
|
export const DEFAULT_WEIGHTS = {
|
|
3
3
|
price: 0.30,
|
|
4
4
|
latency: 0.25,
|
|
@@ -14,7 +14,7 @@ function normalizedInverted(value, min, range) {
|
|
|
14
14
|
return 1 - (value - min) / range;
|
|
15
15
|
}
|
|
16
16
|
function effectiveReputation(p) {
|
|
17
|
-
return
|
|
17
|
+
return normalizedModelReputationScore(p) ?? 0;
|
|
18
18
|
}
|
|
19
19
|
function availableCapacity(p) {
|
|
20
20
|
const max = p.maxConcurrency ?? 1;
|
package/dist/peer-scorer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"peer-scorer.js","sourceRoot":"","sources":["../src/peer-scorer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"peer-scorer.js","sourceRoot":"","sources":["../src/peer-scorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RoutingModelEntryV1, type RoutingPricingV1 } from '@antseed/node';
|
|
2
|
+
/**
|
|
3
|
+
* Translate seller service IDs into the model names a router lists in `GET /v1/routing/models`.
|
|
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 `max_pricing` 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 RoutingModelEntryV1[]): (serviceId: string, pricing?: RoutingPricingV1) => 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,EAAiD,KAAK,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAG9H;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,mBAAmB,EAAE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,KAAK,MAAM,GAAG,SAAS,CAoBlJ"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { MODEL_ROUTING_ANY_MODEL, withinRoutingPricing } 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 `GET /v1/routing/models`.
|
|
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 `max_pricing` 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 === MODEL_ROUTING_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 && !withinRoutingPricing(pricing, entry.max_pricing)))
|
|
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,uBAAuB,EAAE,oBAAoB,EAAmD,MAAM,eAAe,CAAA;AAC9H,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA;AAEhE;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAuC;IACzE,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAA;IACpD,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAA;IACpD,IAAI,QAAyC,CAAA;IAC7C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,EAAE,KAAK,uBAAuB,EAAE,CAAC;YACzC,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,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;YAAE,OAAO,SAAS,CAAA;QAC9F,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACrC,CAAC,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antseed/router-core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.48",
|
|
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.141"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"prebuild": "node ../../scripts/remove-paths.mjs dist",
|