feat(combos): wire capacity adapter into chat handler routing
- detectRequiredCapabilities: infer audioInput/videoInput from block type and embedded mime, not just vision/pdf - handleChat / handleSingleModelChat: augment combo and single-model routing with capacity-adapter models when the target lacks a required capability, wrapped with history stripping for the adapter model's context window
This commit is contained in:
@@ -14,7 +14,8 @@ import { DEFAULT_HEADROOM_URL } from "@/lib/headroom/detect";
|
||||
import { getTransform as getPxpipeTransform } from "@/lib/pxpipe/loader.js";
|
||||
import { appendPxpipeEvent } from "@/lib/pxpipe/events.js";
|
||||
import { errorResponse, unavailableResponse } from "open-sse/utils/error.js";
|
||||
import { handleComboChat, handleFusionChat } from "open-sse/services/combo.js";
|
||||
import { handleComboChat, handleFusionChat, detectRequiredCapabilities } from "open-sse/services/combo.js";
|
||||
import { augmentModelsWithCapacityAdapter, withCapacityAdapterStripping, getActiveAdapterStrategy } from "open-sse/services/capacityAdapter.js";
|
||||
import { handleBypassRequest } from "open-sse/utils/bypassHandler.js";
|
||||
import { HTTP_STATUS } from "open-sse/config/runtimeConfig.js";
|
||||
import { detectFormatByEndpoint } from "open-sse/translator/formats.js";
|
||||
@@ -83,6 +84,8 @@ export async function handleChat(request, clientRawRequest = null) {
|
||||
const bypassResponse = handleBypassRequest(body, modelStr, userAgent, !!settings.ccFilterNaming);
|
||||
if (bypassResponse) return bypassResponse.response || bypassResponse;
|
||||
|
||||
const requiredCapabilities = detectRequiredCapabilities(body);
|
||||
|
||||
// Check if model is a combo (has multiple models with fallback)
|
||||
const comboModels = await getComboModels(modelStr);
|
||||
if (comboModels) {
|
||||
@@ -90,6 +93,8 @@ export async function handleChat(request, clientRawRequest = null) {
|
||||
const comboStrategies = settings.comboStrategies || {};
|
||||
const comboSpecificStrategy = comboStrategies[modelStr]?.fallbackStrategy;
|
||||
const comboStrategy = comboSpecificStrategy || settings.comboStrategy || "fallback";
|
||||
const augmentedModels = augmentModelsWithCapacityAdapter(comboModels, requiredCapabilities, settings);
|
||||
const adapterAdded = augmentedModels.filter((m) => !comboModels.includes(m));
|
||||
|
||||
if (comboStrategy === "fusion") {
|
||||
log.info("CHAT", `Combo "${modelStr}" with ${comboModels.length} models (strategy: fusion)`);
|
||||
@@ -112,11 +117,14 @@ export async function handleChat(request, clientRawRequest = null) {
|
||||
}
|
||||
|
||||
const comboStickyLimit = settings.comboStickyRoundRobinLimit;
|
||||
log.info("CHAT", `Combo "${modelStr}" with ${comboModels.length} models (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);
|
||||
log.info("CHAT", `Combo "${modelStr}" with ${augmentedModels.length} models (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);
|
||||
return handleComboChat({
|
||||
body,
|
||||
models: comboModels,
|
||||
handleSingleModel: (b, m) => handleSingleModelChat(b, m, clientRawRequest, request, apiKey),
|
||||
models: augmentedModels,
|
||||
handleSingleModel: withCapacityAdapterStripping(
|
||||
(b, m) => handleSingleModelChat(b, m, clientRawRequest, request, apiKey),
|
||||
adapterAdded
|
||||
),
|
||||
log,
|
||||
comboName: modelStr,
|
||||
comboStrategy,
|
||||
@@ -124,7 +132,25 @@ export async function handleChat(request, clientRawRequest = null) {
|
||||
});
|
||||
}
|
||||
|
||||
// Single model request
|
||||
// Single model request — may still switch to a capacity-adapter model if the
|
||||
// target lacks a capability the request needs (e.g. no vision, request has an image).
|
||||
const soloAugmented = augmentModelsWithCapacityAdapter([modelStr], requiredCapabilities, settings);
|
||||
if (soloAugmented.length > 1) {
|
||||
const adapterAdded = soloAugmented.filter((m) => m !== modelStr);
|
||||
log.info("CHAT", `Capacity adapter for [${[...requiredCapabilities].join(",")}] on "${modelStr}" → trying ${soloAugmented.join(", ")}`);
|
||||
return handleComboChat({
|
||||
body,
|
||||
models: soloAugmented,
|
||||
handleSingleModel: withCapacityAdapterStripping(
|
||||
(b, m) => handleSingleModelChat(b, m, clientRawRequest, request, apiKey),
|
||||
adapterAdded
|
||||
),
|
||||
log,
|
||||
comboName: modelStr,
|
||||
comboStrategy: getActiveAdapterStrategy(requiredCapabilities, settings)
|
||||
});
|
||||
}
|
||||
|
||||
return handleSingleModelChat(body, modelStr, clientRawRequest, request, apiKey);
|
||||
}
|
||||
|
||||
@@ -143,6 +169,9 @@ async function handleSingleModelChat(body, modelStr, clientRawRequest = null, re
|
||||
const comboStrategies = chatSettings.comboStrategies || {};
|
||||
const comboSpecificStrategy = comboStrategies[modelStr]?.fallbackStrategy;
|
||||
const comboStrategy = comboSpecificStrategy || chatSettings.comboStrategy || "fallback";
|
||||
const requiredCapabilities = detectRequiredCapabilities(body);
|
||||
const augmentedModels = augmentModelsWithCapacityAdapter(comboModels, requiredCapabilities, chatSettings);
|
||||
const adapterAdded = augmentedModels.filter((m) => !comboModels.includes(m));
|
||||
|
||||
if (comboStrategy === "fusion") {
|
||||
log.info("CHAT", `Combo "${modelStr}" with ${comboModels.length} models (strategy: fusion)`);
|
||||
@@ -165,11 +194,14 @@ async function handleSingleModelChat(body, modelStr, clientRawRequest = null, re
|
||||
}
|
||||
|
||||
const comboStickyLimit = chatSettings.comboStickyRoundRobinLimit;
|
||||
log.info("CHAT", `Combo "${modelStr}" with ${comboModels.length} models (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);
|
||||
log.info("CHAT", `Combo "${modelStr}" with ${augmentedModels.length} models (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);
|
||||
return handleComboChat({
|
||||
body,
|
||||
models: comboModels,
|
||||
handleSingleModel: (b, m) => handleSingleModelChat(b, m, clientRawRequest, request, apiKey),
|
||||
models: augmentedModels,
|
||||
handleSingleModel: withCapacityAdapterStripping(
|
||||
(b, m) => handleSingleModelChat(b, m, clientRawRequest, request, apiKey),
|
||||
adapterAdded
|
||||
),
|
||||
log,
|
||||
comboName: modelStr,
|
||||
comboStrategy,
|
||||
|
||||
Reference in New Issue
Block a user