mirror of
https://github.com/musistudio/claude-code-router.git
synced 2026-01-30 06:12:06 +00:00
fix docs
This commit is contained in:
@@ -50,44 +50,147 @@ async function handleTransformerEndpoint(
|
||||
);
|
||||
}
|
||||
|
||||
// Process request transformer chain
|
||||
const { requestBody, config, bypass } = await processRequestTransformers(
|
||||
body,
|
||||
provider,
|
||||
transformer,
|
||||
req.headers,
|
||||
{
|
||||
req,
|
||||
}
|
||||
);
|
||||
try {
|
||||
// Process request transformer chain
|
||||
const { requestBody, config, bypass } = await processRequestTransformers(
|
||||
body,
|
||||
provider,
|
||||
transformer,
|
||||
req.headers,
|
||||
{
|
||||
req,
|
||||
}
|
||||
);
|
||||
|
||||
// Send request to LLM provider
|
||||
const response = await sendRequestToProvider(
|
||||
requestBody,
|
||||
config,
|
||||
provider,
|
||||
fastify,
|
||||
bypass,
|
||||
transformer,
|
||||
{
|
||||
req,
|
||||
}
|
||||
);
|
||||
// Send request to LLM provider
|
||||
const response = await sendRequestToProvider(
|
||||
requestBody,
|
||||
config,
|
||||
provider,
|
||||
fastify,
|
||||
bypass,
|
||||
transformer,
|
||||
{
|
||||
req,
|
||||
}
|
||||
);
|
||||
|
||||
// Process response transformer chain
|
||||
const finalResponse = await processResponseTransformers(
|
||||
requestBody,
|
||||
response,
|
||||
provider,
|
||||
transformer,
|
||||
bypass,
|
||||
{
|
||||
req,
|
||||
}
|
||||
);
|
||||
// Process response transformer chain
|
||||
const finalResponse = await processResponseTransformers(
|
||||
requestBody,
|
||||
response,
|
||||
provider,
|
||||
transformer,
|
||||
bypass,
|
||||
{
|
||||
req,
|
||||
}
|
||||
);
|
||||
|
||||
// Format and return response
|
||||
return formatResponse(finalResponse, reply, body);
|
||||
// Format and return response
|
||||
return formatResponse(finalResponse, reply, body);
|
||||
} catch (error: any) {
|
||||
// Handle fallback if error occurs
|
||||
if (error.code === 'provider_response_error') {
|
||||
const fallbackResult = await handleFallback(req, reply, fastify, transformer, error);
|
||||
if (fallbackResult) {
|
||||
return fallbackResult;
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle fallback logic when request fails
|
||||
* Tries each fallback model in sequence until one succeeds
|
||||
*/
|
||||
async function handleFallback(
|
||||
req: FastifyRequest,
|
||||
reply: FastifyReply,
|
||||
fastify: FastifyInstance,
|
||||
transformer: any,
|
||||
error: any
|
||||
): Promise<any> {
|
||||
const scenarioType = (req as any).scenarioType || 'default';
|
||||
const fallbackConfig = fastify.configService.get<any>('fallback');
|
||||
|
||||
if (!fallbackConfig || !fallbackConfig[scenarioType]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fallbackList = fallbackConfig[scenarioType] as string[];
|
||||
if (!Array.isArray(fallbackList) || fallbackList.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
req.log.warn(`Request failed for ${(req as any).scenarioType}, trying ${fallbackList.length} fallback models`);
|
||||
|
||||
// Try each fallback model in sequence
|
||||
for (const fallbackModel of fallbackList) {
|
||||
try {
|
||||
req.log.info(`Trying fallback model: ${fallbackModel}`);
|
||||
|
||||
// Update request with fallback model
|
||||
const newBody = { ...(req.body as any) };
|
||||
const [fallbackProvider, ...fallbackModelName] = fallbackModel.split(',');
|
||||
newBody.model = fallbackModelName.join(',');
|
||||
|
||||
// Create new request object with updated provider and body
|
||||
const newReq = {
|
||||
...req,
|
||||
provider: fallbackProvider,
|
||||
body: newBody,
|
||||
};
|
||||
|
||||
const provider = fastify.providerService.getProvider(fallbackProvider);
|
||||
if (!provider) {
|
||||
req.log.warn(`Fallback provider '${fallbackProvider}' not found, skipping`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process request transformer chain
|
||||
const { requestBody, config, bypass } = await processRequestTransformers(
|
||||
newBody,
|
||||
provider,
|
||||
transformer,
|
||||
req.headers,
|
||||
{ req: newReq }
|
||||
);
|
||||
|
||||
// Send request to LLM provider
|
||||
const response = await sendRequestToProvider(
|
||||
requestBody,
|
||||
config,
|
||||
provider,
|
||||
fastify,
|
||||
bypass,
|
||||
transformer,
|
||||
{ req: newReq }
|
||||
);
|
||||
|
||||
// Process response transformer chain
|
||||
const finalResponse = await processResponseTransformers(
|
||||
requestBody,
|
||||
response,
|
||||
provider,
|
||||
transformer,
|
||||
bypass,
|
||||
{ req: newReq }
|
||||
);
|
||||
|
||||
req.log.info(`Fallback model ${fallbackModel} succeeded`);
|
||||
|
||||
// Format and return response
|
||||
return formatResponse(finalResponse, reply, newBody);
|
||||
} catch (fallbackError: any) {
|
||||
req.log.warn(`Fallback model ${fallbackModel} failed: ${fallbackError.message}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
req.log.error(`All fallback models failed for yichu ${scenarioType}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,6 +39,7 @@ declare module "fastify" {
|
||||
interface FastifyRequest {
|
||||
provider?: string;
|
||||
model?: string;
|
||||
scenarioType?: string;
|
||||
}
|
||||
interface FastifyInstance {
|
||||
_server?: Server;
|
||||
@@ -266,6 +267,7 @@ export { sessionUsageCache };
|
||||
export { router };
|
||||
export { calculateTokenCount };
|
||||
export { searchProjectBySession };
|
||||
export type { RouterScenarioType, RouterFallbackConfig } from "./utils/router";
|
||||
export { ConfigService } from "./services/config";
|
||||
export { ProviderService } from "./services/provider";
|
||||
export { TransformerService } from "./services/transformer";
|
||||
|
||||
@@ -126,7 +126,7 @@ const getUseModel = async (
|
||||
tokenCount: number,
|
||||
configService: ConfigService,
|
||||
lastUsage?: Usage | undefined
|
||||
) => {
|
||||
): Promise<{ model: string; scenarioType: RouterScenarioType }> => {
|
||||
const projectSpecificRouter = await getProjectSpecificRouter(req, configService);
|
||||
const providers = configService.get<any[]>("providers") || [];
|
||||
const Router = projectSpecificRouter || configService.get("Router");
|
||||
@@ -140,9 +140,9 @@ const getUseModel = async (
|
||||
(m: any) => m.toLowerCase() === model
|
||||
);
|
||||
if (finalProvider && finalModel) {
|
||||
return `${finalProvider.name},${finalModel}`;
|
||||
return { model: `${finalProvider.name},${finalModel}`, scenarioType: 'default' };
|
||||
}
|
||||
return req.body.model;
|
||||
return { model: req.body.model, scenarioType: 'default' };
|
||||
}
|
||||
|
||||
// if tokenCount is greater than the configured threshold, use the long context model
|
||||
@@ -156,7 +156,7 @@ const getUseModel = async (
|
||||
req.log.info(
|
||||
`Using long context model due to token count: ${tokenCount}, threshold: ${longContextThreshold}`
|
||||
);
|
||||
return Router.longContext;
|
||||
return { model: Router.longContext, scenarioType: 'longContext' };
|
||||
}
|
||||
if (
|
||||
req.body?.system?.length > 1 &&
|
||||
@@ -170,7 +170,7 @@ const getUseModel = async (
|
||||
`<CCR-SUBAGENT-MODEL>${model[1]}</CCR-SUBAGENT-MODEL>`,
|
||||
""
|
||||
);
|
||||
return model[1];
|
||||
return { model: model[1], scenarioType: 'default' };
|
||||
}
|
||||
}
|
||||
// Use the background model for any Claude Haiku variant
|
||||
@@ -181,7 +181,7 @@ const getUseModel = async (
|
||||
globalRouter?.background
|
||||
) {
|
||||
req.log.info(`Using background model for ${req.body.model}`);
|
||||
return globalRouter.background;
|
||||
return { model: globalRouter.background, scenarioType: 'background' };
|
||||
}
|
||||
// The priority of websearch must be higher than thinking.
|
||||
if (
|
||||
@@ -189,14 +189,14 @@ const getUseModel = async (
|
||||
req.body.tools.some((tool: any) => tool.type?.startsWith("web_search")) &&
|
||||
Router?.webSearch
|
||||
) {
|
||||
return Router.webSearch;
|
||||
return { model: Router.webSearch, scenarioType: 'webSearch' };
|
||||
}
|
||||
// if exits thinking, use the think model
|
||||
if (req.body.thinking && Router?.think) {
|
||||
req.log.info(`Using think model for ${req.body.thinking}`);
|
||||
return Router.think;
|
||||
return { model: Router.think, scenarioType: 'think' };
|
||||
}
|
||||
return Router?.default;
|
||||
return { model: Router?.default, scenarioType: 'default' };
|
||||
};
|
||||
|
||||
export interface RouterContext {
|
||||
@@ -205,6 +205,16 @@ export interface RouterContext {
|
||||
event?: any;
|
||||
}
|
||||
|
||||
export type RouterScenarioType = 'default' | 'background' | 'think' | 'longContext' | 'webSearch';
|
||||
|
||||
export interface RouterFallbackConfig {
|
||||
default?: string[];
|
||||
background?: string[];
|
||||
think?: string[];
|
||||
longContext?: string[];
|
||||
webSearch?: string[];
|
||||
}
|
||||
|
||||
export const router = async (req: any, _res: any, context: RouterContext) => {
|
||||
const { configService, event } = context;
|
||||
// Parse sessionId from metadata.user_id
|
||||
@@ -247,9 +257,6 @@ export const router = async (req: any, _res: any, context: RouterContext) => {
|
||||
tokenizerConfig
|
||||
);
|
||||
tokenCount = result.tokenCount;
|
||||
req.log.debug(
|
||||
`Token count: ${tokenCount} (tokenizer: ${result.tokenizerUsed}, cached: ${result.cached})`
|
||||
);
|
||||
} else {
|
||||
// Legacy fallback
|
||||
tokenCount = calculateTokenCount(
|
||||
@@ -273,13 +280,19 @@ export const router = async (req: any, _res: any, context: RouterContext) => {
|
||||
}
|
||||
}
|
||||
if (!model) {
|
||||
model = await getUseModel(req, tokenCount, configService, lastMessageUsage);
|
||||
const result = await getUseModel(req, tokenCount, configService, lastMessageUsage);
|
||||
model = result.model;
|
||||
req.scenarioType = result.scenarioType;
|
||||
} else {
|
||||
// Custom router doesn't provide scenario type, default to 'default'
|
||||
req.scenarioType = 'default';
|
||||
}
|
||||
req.body.model = model;
|
||||
} catch (error: any) {
|
||||
req.log.error(`Error in router middleware: ${error.message}`);
|
||||
const Router = configService.get("Router");
|
||||
req.body.model = Router?.default;
|
||||
req.scenarioType = 'default';
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user