Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
1
vendor/ruvector/npm/packages/agentic-synth/src/routing/index.d.ts.map
vendored
Normal file
1
vendor/ruvector/npm/packages/agentic-synth/src/routing/index.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAEpE,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,aAAa,CAAC;IAC/B,YAAY,EAAE;QACZ,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,aAAa,CAAC,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,MAAM,CAA0B;gBAE5B,MAAM,EAAE,YAAY;IAMhC,OAAO,CAAC,gBAAgB;IAsDxB;;OAEG;IACH,WAAW,CAAC,YAAY,EAAE;QACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,EAAE,aAAa,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,UAAU;IAoDd;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,UAAU,EAAE;IA8BnD;;OAEG;IACH,SAAS,IAAI,UAAU,EAAE;IAIzB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAKjC;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG;QACjC,QAAQ,EAAE,aAAa,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;CAOF;AAED,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC"}
|
||||
1
vendor/ruvector/npm/packages/agentic-synth/src/routing/index.js.map
vendored
Normal file
1
vendor/ruvector/npm/packages/agentic-synth/src/routing/index.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
||||
207
vendor/ruvector/npm/packages/agentic-synth/src/routing/index.ts
vendored
Normal file
207
vendor/ruvector/npm/packages/agentic-synth/src/routing/index.ts
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Model routing logic for Gemini and OpenRouter
|
||||
*/
|
||||
|
||||
import { ModelProvider, ModelRoute, SynthError } from '../types.js';
|
||||
|
||||
export interface RouterConfig {
|
||||
defaultProvider: ModelProvider;
|
||||
providerKeys: {
|
||||
gemini?: string;
|
||||
openrouter?: string;
|
||||
};
|
||||
fallbackChain?: ModelProvider[];
|
||||
customRoutes?: ModelRoute[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Model router for intelligent provider selection
|
||||
*/
|
||||
export class ModelRouter {
|
||||
private config: RouterConfig;
|
||||
private routes: Map<string, ModelRoute>;
|
||||
|
||||
constructor(config: RouterConfig) {
|
||||
this.config = config;
|
||||
this.routes = new Map();
|
||||
this.initializeRoutes();
|
||||
}
|
||||
|
||||
private initializeRoutes(): void {
|
||||
// Default Gemini models
|
||||
const geminiRoutes: ModelRoute[] = [
|
||||
{
|
||||
provider: 'gemini',
|
||||
model: 'gemini-2.0-flash-exp',
|
||||
priority: 10,
|
||||
capabilities: ['text', 'json', 'streaming', 'fast']
|
||||
},
|
||||
{
|
||||
provider: 'gemini',
|
||||
model: 'gemini-1.5-pro',
|
||||
priority: 8,
|
||||
capabilities: ['text', 'json', 'complex', 'reasoning']
|
||||
},
|
||||
{
|
||||
provider: 'gemini',
|
||||
model: 'gemini-1.5-flash',
|
||||
priority: 9,
|
||||
capabilities: ['text', 'json', 'fast', 'efficient']
|
||||
}
|
||||
];
|
||||
|
||||
// Default OpenRouter models
|
||||
const openrouterRoutes: ModelRoute[] = [
|
||||
{
|
||||
provider: 'openrouter',
|
||||
model: 'anthropic/claude-3.5-sonnet',
|
||||
priority: 10,
|
||||
capabilities: ['text', 'json', 'reasoning', 'complex']
|
||||
},
|
||||
{
|
||||
provider: 'openrouter',
|
||||
model: 'openai/gpt-4-turbo',
|
||||
priority: 9,
|
||||
capabilities: ['text', 'json', 'reasoning']
|
||||
},
|
||||
{
|
||||
provider: 'openrouter',
|
||||
model: 'meta-llama/llama-3.1-70b-instruct',
|
||||
priority: 7,
|
||||
capabilities: ['text', 'json', 'fast']
|
||||
}
|
||||
];
|
||||
|
||||
// Add all routes
|
||||
[...geminiRoutes, ...openrouterRoutes, ...(this.config.customRoutes || [])].forEach(
|
||||
route => {
|
||||
const key = `${route.provider}:${route.model}`;
|
||||
this.routes.set(key, route);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select best model for given requirements
|
||||
*/
|
||||
selectModel(requirements: {
|
||||
capabilities?: string[];
|
||||
provider?: ModelProvider;
|
||||
preferredModel?: string;
|
||||
}): ModelRoute {
|
||||
const { capabilities = [], provider, preferredModel } = requirements;
|
||||
|
||||
// If specific model requested, try to use it
|
||||
if (provider && preferredModel) {
|
||||
const key = `${provider}:${preferredModel}`;
|
||||
const route = this.routes.get(key);
|
||||
if (route) {
|
||||
return route;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by provider if specified
|
||||
let candidates = Array.from(this.routes.values());
|
||||
if (provider) {
|
||||
candidates = candidates.filter(r => r.provider === provider);
|
||||
} else {
|
||||
// Use default provider
|
||||
candidates = candidates.filter(r => r.provider === this.config.defaultProvider);
|
||||
}
|
||||
|
||||
// Filter by capabilities
|
||||
if (capabilities.length > 0) {
|
||||
candidates = candidates.filter(route =>
|
||||
capabilities.every(cap => route.capabilities.includes(cap))
|
||||
);
|
||||
}
|
||||
|
||||
// Sort by priority (highest first)
|
||||
candidates.sort((a, b) => b.priority - a.priority);
|
||||
|
||||
if (candidates.length === 0) {
|
||||
throw new SynthError(
|
||||
'No suitable model found for requirements',
|
||||
'NO_MODEL_FOUND',
|
||||
{ requirements }
|
||||
);
|
||||
}
|
||||
|
||||
// Safe to access: we've checked length > 0
|
||||
const selectedRoute = candidates[0];
|
||||
if (!selectedRoute) {
|
||||
throw new SynthError(
|
||||
'Unexpected error: no route selected despite candidates',
|
||||
'ROUTE_SELECTION_ERROR',
|
||||
{ candidates }
|
||||
);
|
||||
}
|
||||
|
||||
return selectedRoute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fallback chain for resilience
|
||||
*/
|
||||
getFallbackChain(primary: ModelRoute): ModelRoute[] {
|
||||
const chain: ModelRoute[] = [primary];
|
||||
|
||||
if (this.config.fallbackChain) {
|
||||
// Only require essential capabilities for fallback models
|
||||
// Filter out optimization flags like 'streaming', 'fast', 'efficient'
|
||||
const essentialCapabilities = primary.capabilities.filter(
|
||||
cap => !['streaming', 'fast', 'efficient', 'complex', 'reasoning'].includes(cap)
|
||||
);
|
||||
|
||||
for (const provider of this.config.fallbackChain) {
|
||||
try {
|
||||
const fallback = this.selectModel({
|
||||
provider,
|
||||
capabilities: essentialCapabilities.length > 0 ? essentialCapabilities : undefined
|
||||
});
|
||||
|
||||
if (fallback.model !== primary.model) {
|
||||
chain.push(fallback);
|
||||
}
|
||||
} catch (error) {
|
||||
// Skip this fallback provider if no suitable model found
|
||||
console.warn(`No suitable fallback model found for provider ${provider}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available routes
|
||||
*/
|
||||
getRoutes(): ModelRoute[] {
|
||||
return Array.from(this.routes.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom route
|
||||
*/
|
||||
addRoute(route: ModelRoute): void {
|
||||
const key = `${route.provider}:${route.model}`;
|
||||
this.routes.set(key, route);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get model configuration
|
||||
*/
|
||||
getModelConfig(route: ModelRoute): {
|
||||
provider: ModelProvider;
|
||||
model: string;
|
||||
apiKey?: string;
|
||||
} {
|
||||
return {
|
||||
provider: route.provider,
|
||||
model: route.model,
|
||||
apiKey: this.config.providerKeys[route.provider]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export { ModelProvider, ModelRoute };
|
||||
148
vendor/ruvector/npm/packages/agentic-synth/src/routing/model-router.js
vendored
Normal file
148
vendor/ruvector/npm/packages/agentic-synth/src/routing/model-router.js
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Model Router for intelligent model selection
|
||||
*/
|
||||
|
||||
export class ModelRouter {
|
||||
constructor(options = {}) {
|
||||
this.models = options.models || [];
|
||||
this.strategy = options.strategy || 'round-robin';
|
||||
this.currentIndex = 0;
|
||||
this.modelStats = new Map();
|
||||
|
||||
// Initialize stats for provided models
|
||||
this.models.forEach(model => {
|
||||
this.modelStats.set(model.id, {
|
||||
requests: 0,
|
||||
errors: 0,
|
||||
totalLatency: 0,
|
||||
avgLatency: 0
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Route request to appropriate model
|
||||
* @param {Object} request - Request object
|
||||
* @returns {string} Selected model ID
|
||||
*/
|
||||
route(request) {
|
||||
if (this.models.length === 0) {
|
||||
throw new Error('No models available for routing');
|
||||
}
|
||||
|
||||
switch (this.strategy) {
|
||||
case 'round-robin':
|
||||
return this._roundRobin();
|
||||
case 'least-latency':
|
||||
return this._leastLatency();
|
||||
case 'cost-optimized':
|
||||
return this._costOptimized(request);
|
||||
case 'capability-based':
|
||||
return this._capabilityBased(request);
|
||||
default:
|
||||
return this.models[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register model
|
||||
*/
|
||||
registerModel(model) {
|
||||
if (!model.id || !model.endpoint) {
|
||||
throw new Error('Model must have id and endpoint');
|
||||
}
|
||||
|
||||
this.models.push(model);
|
||||
this.modelStats.set(model.id, {
|
||||
requests: 0,
|
||||
errors: 0,
|
||||
totalLatency: 0,
|
||||
avgLatency: 0
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Record model performance
|
||||
*/
|
||||
recordMetrics(modelId, latency, success = true) {
|
||||
const stats = this.modelStats.get(modelId);
|
||||
if (!stats) return;
|
||||
|
||||
stats.requests++;
|
||||
if (!success) stats.errors++;
|
||||
stats.totalLatency += latency;
|
||||
stats.avgLatency = stats.totalLatency / stats.requests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get model statistics
|
||||
*/
|
||||
getStats(modelId = null) {
|
||||
if (modelId) {
|
||||
return this.modelStats.get(modelId);
|
||||
}
|
||||
return Object.fromEntries(this.modelStats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Round-robin routing
|
||||
* @private
|
||||
*/
|
||||
_roundRobin() {
|
||||
const model = this.models[this.currentIndex];
|
||||
this.currentIndex = (this.currentIndex + 1) % this.models.length;
|
||||
return model.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Route to model with least latency
|
||||
* @private
|
||||
*/
|
||||
_leastLatency() {
|
||||
let bestModel = this.models[0];
|
||||
let lowestLatency = Infinity;
|
||||
|
||||
for (const model of this.models) {
|
||||
const stats = this.modelStats.get(model.id);
|
||||
if (stats && stats.avgLatency < lowestLatency) {
|
||||
lowestLatency = stats.avgLatency;
|
||||
bestModel = model;
|
||||
}
|
||||
}
|
||||
|
||||
return bestModel.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cost-optimized routing
|
||||
* @private
|
||||
*/
|
||||
_costOptimized(request) {
|
||||
const requestSize = JSON.stringify(request).length;
|
||||
|
||||
// Route small requests to cheaper models
|
||||
if (requestSize < 1000) {
|
||||
return this.models[0].id;
|
||||
}
|
||||
|
||||
return this.models[this.models.length - 1].id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Capability-based routing
|
||||
* @private
|
||||
*/
|
||||
_capabilityBased(request) {
|
||||
const requiredCapability = request.capability || 'general';
|
||||
|
||||
const capableModels = this.models.filter(model =>
|
||||
model.capabilities?.includes(requiredCapability)
|
||||
);
|
||||
|
||||
if (capableModels.length === 0) {
|
||||
return this.models[0].id;
|
||||
}
|
||||
|
||||
return capableModels[0].id;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user