twinclaw 1.2.2 → 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,15 +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
- const providerId = this.resolveProviderId(input.config);
531
- const noToolProviders = ['stepfun', 'openrouter'];
532
529
  let payload = input.payload;
533
- if (noToolProviders.includes(providerId) && input.payload.tools) {
534
- payload = { ...input.payload };
535
- delete payload.tools;
536
- delete payload.tool_choice;
537
- }
538
530
  try {
539
531
  const controller = new AbortController();
540
532
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -668,14 +660,7 @@ export class ModelRouter {
668
660
  const responseContentParts = [];
669
661
  const toolCalls = [];
670
662
  // For providers that don't support tools well, strip them from the request
671
- const providerId = this.resolveProviderId(input.config);
672
- const noToolProviders = ['stepfun', 'openrouter'];
673
663
  let payload = input.payload;
674
- if (noToolProviders.includes(providerId) && input.payload.tools) {
675
- payload = { ...input.payload };
676
- delete payload.tools;
677
- delete payload.tool_choice;
678
- }
679
664
  try {
680
665
  const controller = new AbortController();
681
666
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -1090,11 +1075,23 @@ export class ModelRouter {
1090
1075
  apiKeyEnvName: 'MODAL_API_KEY',
1091
1076
  });
1092
1077
  }
1093
- 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
1094
1091
  const orInfo = PROVIDER_INFO.openrouter;
1095
1092
  configModels.push({
1096
1093
  id: MODEL_SLOT_IDS.FALLBACK_1,
1097
- model: 'stepfun/step-3.5-flash:free',
1094
+ model: 'meta-llama/llama-3.3-70b-instruct',
1098
1095
  baseURL: orInfo?.baseURL ? (orInfo.baseURL.endsWith('/chat/completions') ? orInfo.baseURL : `${orInfo.baseURL}/chat/completions`) : 'https://openrouter.ai/api/v1/chat/completions',
1099
1096
  apiKeyEnvName: 'OPENROUTER_API_KEY',
1100
1097
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twinclaw",
3
- "version": "1.2.2",
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": {