@votadev/tooncode 2.2.2 → 2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tooncode.py +45 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@votadev/tooncode",
3
- "version": "2.2.2",
3
+ "version": "2.2.5",
4
4
  "description": "Free AI Coding Agent CLI — Claude Code alternative powered by free models. 20 tools, multi-agent team, browser automation, MCP servers.",
5
5
  "author": "VotaLab",
6
6
  "license": "MIT",
package/tooncode.py CHANGED
@@ -8,7 +8,7 @@ Usage:
8
8
  python tooncode.py
9
9
  """
10
10
 
11
- VERSION = "2.2.2"
11
+ VERSION = "2.2.5"
12
12
 
13
13
  import httpx
14
14
  import json
@@ -2915,10 +2915,40 @@ def _get_current_api_url() -> str:
2915
2915
  return _get_api_url()
2916
2916
 
2917
2917
 
2918
+ def _validate_messages(messages: list):
2919
+ """Fix message ordering issues before sending to API."""
2920
+ # Rule: tool_result must follow assistant with tool_use
2921
+ # Rule: alternating user/assistant (with tool_result counting as user)
2922
+ fixed = []
2923
+ for i, msg in enumerate(messages):
2924
+ role = msg.get("role", "")
2925
+ # Skip empty messages
2926
+ content = msg.get("content", [])
2927
+ if not content:
2928
+ continue
2929
+ # Prevent consecutive same-role messages (except tool_result after user)
2930
+ if fixed:
2931
+ prev_role = fixed[-1].get("role", "")
2932
+ if role == prev_role and role == "user":
2933
+ # Check if this is tool_result (allowed after tool_use response)
2934
+ is_tool_result = isinstance(content, list) and any(
2935
+ b.get("type") == "tool_result" for b in content if isinstance(b, dict))
2936
+ if not is_tool_result:
2937
+ fixed.append({"role": "assistant", "content": [{"type": "text", "text": "(continuing)"}]})
2938
+ elif role == prev_role and role == "assistant":
2939
+ fixed.append({"role": "user", "content": [{"type": "text", "text": "(continue)"}]})
2940
+ fixed.append(msg)
2941
+ messages.clear()
2942
+ messages.extend(fixed)
2943
+
2944
+
2918
2945
  def stream_response(messages: list, renderer: StreamRenderer) -> dict:
2919
2946
  """Send request and stream the response, returning parsed content blocks."""
2920
2947
  global total_input_tokens, total_output_tokens, last_input_tokens
2921
2948
 
2949
+ # Validate message ordering
2950
+ _validate_messages(messages)
2951
+
2922
2952
  system_prompt = build_system_prompt()
2923
2953
  body = {
2924
2954
  "model": MODEL,
@@ -3285,7 +3315,7 @@ Be specific. Give copy-paste ready solutions."""
3285
3315
  console.print("[bold magenta][bosshelp] Asking Claude Code...[/bold magenta]")
3286
3316
  try:
3287
3317
  result = subprocess.run(
3288
- [claude_cmd, "--print"],
3318
+ [claude_cmd, "--print", "--dangerously-skip-permissions"],
3289
3319
  input=help_prompt,
3290
3320
  capture_output=True, text=True, cwd=CWD, timeout=180,
3291
3321
  encoding="utf-8", errors="replace",
@@ -4197,7 +4227,7 @@ OUTPUT THE JSON ARRAY NOW:"""
4197
4227
  console.print("[dim]Using Claude Code CLI...[/dim]")
4198
4228
  try:
4199
4229
  result = subprocess.run(
4200
- [claude_cmd, "--print"],
4230
+ [claude_cmd, "--print", "--dangerously-skip-permissions"],
4201
4231
  input=boss_prompt,
4202
4232
  capture_output=True, text=True, cwd=CWD, timeout=180,
4203
4233
  encoding="utf-8", errors="replace",
@@ -5312,16 +5342,21 @@ def main(_initial_prompt=None):
5312
5342
  )
5313
5343
  _last_errors.clear()
5314
5344
  _post_bosshelp = True
5315
- # Inject boss answer as a separate user message after tool results
5345
+ # MUST append tool_results first (API requires it after tool_use)
5316
5346
  messages.append({"role": "user", "content": tool_results})
5317
- messages.append({"role": "assistant", "content": [{"type": "text", "text": "I'm stuck. Let me check the boss's advice."}]})
5347
+ # Then add bosshelp as assistant+user pair
5348
+ fix_instructions = f"[BOSSHELP]\n{boss_answer}\n\n"
5349
+ fix_instructions += "APPLY THIS FIX NOW:\n"
5350
+ fix_instructions += "1. Read each file mentioned\n"
5351
+ fix_instructions += "2. Use edit tool to apply changes\n"
5352
+ fix_instructions += "3. Run commands if needed\n"
5353
+ fix_instructions += "4. Verify the fix works\n"
5354
+ fix_instructions += "USE TOOLS. Do NOT explain."
5355
+ messages.append({"role": "assistant", "content": [{"type": "text", "text": "Let me apply the fix."}]})
5318
5356
  messages.append({"role": "user", "content": [{"type": "text", "text":
5319
- f"[BOSSHELP from Claude Code - APPLY THIS FIX]\n{boss_answer}\n\n"
5320
- f"IMPORTANT: You MUST use tools (edit, write, bash) to apply this fix RIGHT NOW. "
5321
- f"Do NOT just explain what to do. Do NOT repeat the same approach that failed. "
5322
- f"Read the fix above and execute it step by step using your tools.",
5357
+ fix_instructions,
5323
5358
  "cache_control": {"type": "ephemeral"}}]})
5324
- continue # Skip the normal append below
5359
+ continue
5325
5360
  else:
5326
5361
  # Successful tool = reset error tracking
5327
5362
  _last_errors.clear()