twinclaw 1.2.3 → 1.2.4

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,23 @@ export class ModelRouter {
1094
1075
  apiKeyEnvName: 'MODAL_API_KEY',
1095
1076
  });
1096
1077
  }
1097
- if (openRouterApiKey && !configModels.find((m) => m.id === MODEL_SLOT_IDS.FALLBACK_1)) {
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: 'llama-3.3-70b-versatile',
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
+ // Only use OpenRouter if Groq is not available - use a model that supports tools
1098
1091
  const orInfo = PROVIDER_INFO.openrouter;
1099
1092
  configModels.push({
1100
1093
  id: MODEL_SLOT_IDS.FALLBACK_1,
1101
- model: 'stepfun/step-3.5-flash:free',
1094
+ model: 'meta-llama/llama-3.3-70b-instruct',
1102
1095
  baseURL: orInfo?.baseURL ? (orInfo.baseURL.endsWith('/chat/completions') ? orInfo.baseURL : `${orInfo.baseURL}/chat/completions`) : 'https://openrouter.ai/api/v1/chat/completions',
1103
1096
  apiKeyEnvName: 'OPENROUTER_API_KEY',
1104
1097
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twinclaw",
3
- "version": "1.2.3",
3
+ "version": "1.2.4",
4
4
  "description": "Eagle-eyed agentic AI gateway with multi-modal hooks and proactive memory.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {