@votadev/tooncode 2.2.3 → 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.
- package/package.json +1 -1
- package/tooncode.py +44 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@votadev/tooncode",
|
|
3
|
-
"version": "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.
|
|
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,21 +5342,21 @@ def main(_initial_prompt=None):
|
|
|
5312
5342
|
)
|
|
5313
5343
|
_last_errors.clear()
|
|
5314
5344
|
_post_bosshelp = True
|
|
5315
|
-
#
|
|
5345
|
+
# MUST append tool_results first (API requires it after tool_use)
|
|
5316
5346
|
messages.append({"role": "user", "content": tool_results})
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
fix_instructions
|
|
5320
|
-
fix_instructions += "
|
|
5321
|
-
fix_instructions += "
|
|
5322
|
-
fix_instructions += "
|
|
5323
|
-
fix_instructions += "
|
|
5324
|
-
fix_instructions += "
|
|
5325
|
-
|
|
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."}]})
|
|
5326
5356
|
messages.append({"role": "user", "content": [{"type": "text", "text":
|
|
5327
5357
|
fix_instructions,
|
|
5328
5358
|
"cache_control": {"type": "ephemeral"}}]})
|
|
5329
|
-
continue
|
|
5359
|
+
continue
|
|
5330
5360
|
else:
|
|
5331
5361
|
# Successful tool = reset error tracking
|
|
5332
5362
|
_last_errors.clear()
|