twinclaw 1.2.3 → 1.2.5
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.
|
@@ -526,17 +526,7 @@ export class ModelRouter {
|
|
|
526
526
|
this.recordEvent('attempt', input.config, `Attempting ${input.config.model} (profile=${input.directive.profile}, severity=${input.directive.severity}).`);
|
|
527
527
|
const startedAt = this.nowFn();
|
|
528
528
|
const timeoutMs = 60000; // 60 second timeout
|
|
529
|
-
// For providers that don't support tools well, strip them from the request
|
|
530
|
-
// This includes fallback models that use OpenRouter/StepFun which have tool issues
|
|
531
|
-
const providerId = this.resolveProviderId(input.config);
|
|
532
|
-
const noToolProviders = ['stepfun', 'openrouter', 'unknown'];
|
|
533
|
-
const isFallbackModel = input.config.id === MODEL_SLOT_IDS.FALLBACK_1 || input.config.id === MODEL_SLOT_IDS.FALLBACK_2;
|
|
534
529
|
let payload = input.payload;
|
|
535
|
-
if ((noToolProviders.includes(providerId) || isFallbackModel) && input.payload.tools) {
|
|
536
|
-
payload = { ...input.payload };
|
|
537
|
-
delete payload.tools;
|
|
538
|
-
delete payload.tool_choice;
|
|
539
|
-
}
|
|
540
530
|
try {
|
|
541
531
|
const controller = new AbortController();
|
|
542
532
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -670,16 +660,7 @@ export class ModelRouter {
|
|
|
670
660
|
const responseContentParts = [];
|
|
671
661
|
const toolCalls = [];
|
|
672
662
|
// For providers that don't support tools well, strip them from the request
|
|
673
|
-
// This includes fallback models that use OpenRouter/StepFun which have tool issues
|
|
674
|
-
const providerId = this.resolveProviderId(input.config);
|
|
675
|
-
const noToolProviders = ['stepfun', 'openrouter', 'unknown'];
|
|
676
|
-
const isFallbackModel = input.config.id === MODEL_SLOT_IDS.FALLBACK_1 || input.config.id === MODEL_SLOT_IDS.FALLBACK_2;
|
|
677
663
|
let payload = input.payload;
|
|
678
|
-
if ((noToolProviders.includes(providerId) || isFallbackModel) && input.payload.tools) {
|
|
679
|
-
payload = { ...input.payload };
|
|
680
|
-
delete payload.tools;
|
|
681
|
-
delete payload.tool_choice;
|
|
682
|
-
}
|
|
683
664
|
try {
|
|
684
665
|
const controller = new AbortController();
|
|
685
666
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -1094,11 +1075,33 @@ export class ModelRouter {
|
|
|
1094
1075
|
apiKeyEnvName: 'MODAL_API_KEY',
|
|
1095
1076
|
});
|
|
1096
1077
|
}
|
|
1097
|
-
|
|
1078
|
+
// Use Groq as fallback (supports tools, fast, cheap)
|
|
1079
|
+
const groqApiKey = getConfigValue('GROQ_API_KEY');
|
|
1080
|
+
if (groqApiKey && !configModels.find((m) => m.id === MODEL_SLOT_IDS.FALLBACK_1)) {
|
|
1081
|
+
const groqInfo = PROVIDER_INFO.groq;
|
|
1082
|
+
configModels.push({
|
|
1083
|
+
id: MODEL_SLOT_IDS.FALLBACK_1,
|
|
1084
|
+
model: 'qwen/qwen3-32b',
|
|
1085
|
+
baseURL: groqInfo?.baseURL || 'https://api.groq.com/openai/v1/chat/completions',
|
|
1086
|
+
apiKeyEnvName: 'GROQ_API_KEY',
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
else if (openRouterApiKey && !configModels.find((m) => m.id === MODEL_SLOT_IDS.FALLBACK_1)) {
|
|
1090
|
+
// Use OpenRouter free models that support tools
|
|
1098
1091
|
const orInfo = PROVIDER_INFO.openrouter;
|
|
1099
1092
|
configModels.push({
|
|
1100
1093
|
id: MODEL_SLOT_IDS.FALLBACK_1,
|
|
1101
|
-
model: '
|
|
1094
|
+
model: 'arcee-ai/trinity-large-preview:free',
|
|
1095
|
+
baseURL: orInfo?.baseURL ? (orInfo.baseURL.endsWith('/chat/completions') ? orInfo.baseURL : `${orInfo.baseURL}/chat/completions`) : 'https://openrouter.ai/api/v1/chat/completions',
|
|
1096
|
+
apiKeyEnvName: 'OPENROUTER_API_KEY',
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
// Add OpenRouter free model as FALLBACK_2 if available
|
|
1100
|
+
if (openRouterApiKey && !configModels.find((m) => m.id === MODEL_SLOT_IDS.FALLBACK_2)) {
|
|
1101
|
+
const orInfo = PROVIDER_INFO.openrouter;
|
|
1102
|
+
configModels.push({
|
|
1103
|
+
id: MODEL_SLOT_IDS.FALLBACK_2,
|
|
1104
|
+
model: 'arcee-ai/trinity-mini:free',
|
|
1102
1105
|
baseURL: orInfo?.baseURL ? (orInfo.baseURL.endsWith('/chat/completions') ? orInfo.baseURL : `${orInfo.baseURL}/chat/completions`) : 'https://openrouter.ai/api/v1/chat/completions',
|
|
1103
1106
|
apiKeyEnvName: 'OPENROUTER_API_KEY',
|
|
1104
1107
|
});
|