wolverine-ai 3.9.0 → 3.9.1

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wolverine-ai",
3
- "version": "3.9.0",
3
+ "version": "3.9.1",
4
4
  "description": "Self-healing Node.js server framework powered by AI. Catches crashes, diagnoses errors, generates fixes, verifies, and restarts — automatically.",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -446,6 +446,10 @@ class AgentEngine {
446
446
  return { success: false, summary: "Token budget exhausted", filesModified: this.filesModified, turnCount: this.turnCount, totalTokens: this.totalTokens };
447
447
  }
448
448
 
449
+ if (!response.choices || !response.choices[0]) {
450
+ console.log(chalk.red(` ⚠️ AI returned no choices: ${JSON.stringify(response).slice(0, 200)}`));
451
+ return { success: false, summary: "AI returned empty response", filesModified: this.filesModified, turnCount: this.turnCount, totalTokens: this.totalTokens };
452
+ }
449
453
  const choice = response.choices[0];
450
454
  const assistantMessage = choice.message || choice;
451
455
  this.messages.push(assistantMessage);
@@ -615,13 +615,27 @@ ${backupSourceCode ? `## Last Known Working Version\n\`\`\`javascript\n${backupS
615
615
  Include both if needed, or just one.`;
616
616
 
617
617
  const result = await aiCall({ model, systemPrompt, userPrompt, maxTokens: 2048, category: "coding" });
618
- const content = result.content;
619
- const cleaned = content.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "");
618
+ const content = (result.content || "").trim();
619
+
620
+ // Strip thinking tags (Gemma), markdown fences, and any prefix text
621
+ let cleaned = content
622
+ .replace(/<\|channel>.*?<channel\|>/gs, "")
623
+ .replace(/<\|think\|>[\s\S]*?<\|\/think\|>/g, "")
624
+ .replace(/^```(?:json)?\s*/gm, "")
625
+ .replace(/```\s*$/gm, "")
626
+ .trim();
627
+
628
+ // Extract JSON object from response
629
+ const jsonMatch = cleaned.match(/\{[\s\S]*"(?:explanation|changes|commands)"[\s\S]*\}/);
630
+ if (jsonMatch) cleaned = jsonMatch[0];
620
631
 
621
632
  try {
622
633
  return JSON.parse(cleaned);
623
- } catch (parseErr) {
624
- throw new Error(`Failed to parse AI response as JSON.\nRaw response:\n${content}`);
634
+ } catch {
635
+ // Last resort: try to find any JSON object
636
+ const anyJson = cleaned.match(/\{[\s\S]*\}/);
637
+ if (anyJson) try { return JSON.parse(anyJson[0]); } catch {}
638
+ throw new Error(`AI response was not valid JSON`);
625
639
  }
626
640
  }
627
641