|
| 1 | +# v0.4.97 — Cloud tool dialect: keep JSON + accept Qwen `<function=` |
| 2 | + |
| 3 | +Status: **SHIPPED v0.4.97** — operator go 2026-09-26; CI Windows CUDA only for this tag. |
| 4 | + |
| 5 | +## Problem (user words) |
| 6 | + |
| 7 | +Cipher sometimes emits JSON tool calls, sometimes Qwen-native `<function=…>` / `<parameter=…>`. Last fail leaked XML and stopped with `toolsParsed=0`. Shipping takes hours — this deploy must cover both dialects and the prompt hole from the last ship. |
| 8 | + |
| 9 | +## Log evidence (v0.4.96) |
| 10 | + |
| 11 | +``` |
| 12 | +20:48:55 round end iter=0 stopReason=stop toolsParsed=0 proseChars=142 |
| 13 | +20:48:55 ai-chat DONE: toolCallCount=0 |
| 14 | +``` |
| 15 | + |
| 16 | +UI showed mangled `<function=list_directory>` / `<parameter=…>`. Not Ship A (no tools had run). Not length-stop. |
| 17 | + |
| 18 | +## Correction (operator): we did have tool examples |
| 19 | + |
| 20 | +Correct. Through **v0.4.89** Secrypt Cloud used `mcpToolServer.getCompactToolHint(...)`, which starts with `getAgentToolPromptHeader({ compact: true })` — JSON fence format + concrete `read_file` / `write_file` / `edit_file` / `run_command` examples. |
| 21 | + |
| 22 | +**v0.4.94** (`c9ffc6f`) replaced that with bare `buildCloudToolListing` — name list only, **no** format header/examples. **v0.4.95** Ship E only truncated descriptions to 100 chars on that already-stripped listing. |
| 23 | + |
| 24 | +| Piece | v0.4.89 Cloud (working pattern) | Live 0.4.96 | |
| 25 | +|--------|----------------------------------|-------------| |
| 26 | +| Tool catalog | `getCompactToolHint` + compactDescriptions | `buildCloudToolListing` name list | |
| 27 | +| JSON format + examples | **Yes** (compact header) | **Removed in 0.4.94** | |
| 28 | +| Desc length | compactDescriptions | slice 100 | |
| 29 | + |
| 30 | +So the examples were stripped in **0.4.94**, not invented-missing forever. Model fell back to Qwen `<function=` — host still does not parse that dialect. |
| 31 | + |
| 32 | +## Proposed change (both required in one ship) |
| 33 | + |
| 34 | +### A — Prompt: restore Cloud compact tool catalog (prefer JSON) |
| 35 | + |
| 36 | +Replace `buildCloudToolListing(...)` with the **0.4.89 Secrypt path**: |
| 37 | + |
| 38 | +```js |
| 39 | +toolPrompt = mcpToolServer.getCompactToolHint('default', { |
| 40 | + toolDefs: filteredDefs, |
| 41 | + planning: mode.planning, |
| 42 | + compactDescriptions: true, |
| 43 | +}).join(''); |
| 44 | +``` |
| 45 | + |
| 46 | +That restores the JSON fence header + examples. Settings tool filter (`filteredDefs`) stays. Do **not** document `<function=` as preferred. |
| 47 | + |
| 48 | +Optional: drop the separate thin `buildCloudToolListing` or keep it unused — prefer delete if nothing else imports it. |
| 49 | + |
| 50 | +### B — Parser: additive dialects (never break JSON) |
| 51 | + |
| 52 | +In `tools/toolParser.js` **add** Method for: |
| 53 | + |
| 54 | +``` |
| 55 | +<function=TOOL_NAME> |
| 56 | +<parameter=KEY>VALUE</parameter> |
| 57 | +… |
| 58 | +</function> |
| 59 | +``` |
| 60 | + |
| 61 | +- Map tool name via existing aliases / VALID_TOOLS. |
| 62 | +- Params object from parameter tags (trim values). |
| 63 | +- Run **alongside** existing JSON / fence / tool_code paths (order: existing first or XML first — either OK if dedupe by signature). |
| 64 | +- `looksLikeToolAttempt`: also true on `/<function\s*=/i`. |
| 65 | +- `stripToolCallText` + streaming hold: remove `<function=…</function>` (and orphan open) so UI never shows markup. |
| 66 | + |
| 67 | +Malformed mashups (screenshot: command fragment between tags): parse what is well-formed; if zero valid tools but `<function=` present → existing repair retry (`looksLikeToolAttempt` true). |
| 68 | + |
| 69 | +### C — Tests (must pass before tag) |
| 70 | + |
| 71 | +1. Pure JSON fence → still parses (regression). |
| 72 | +2. Pure `<function=list_directory><parameter=dirPath>.</parameter></function>` → one call. |
| 73 | +3. Screenshot-shaped mangled string → `looksLikeToolAttempt` true; strip leaves prose; best-effort parse ≥0 tools. |
| 74 | +4. Mixed prose + JSON unchanged. |
| 75 | +5. Cloud tool prompt (via getCompactToolHint) includes ```json and example `{"tool":`. |
| 76 | +6. Regression: Settings-filtered toolDefs still only list enabled tools. |
| 77 | + |
| 78 | +### D — Ship |
| 79 | + |
| 80 | +Bump **0.4.97**, commit, tag, CI green. |
| 81 | + |
| 82 | +## What this ship does NOT do |
| 83 | + |
| 84 | +- Force tools after clean prose. |
| 85 | +- Change 27B/2B weights or sampler. |
| 86 | +- Teach the model to prefer `<function=` (JSON remains the instructed format). |
| 87 | +- Touch FileShot / other platforms’ 2B chatbot prompts. |
| 88 | + |
| 89 | +## Validation |
| 90 | + |
| 91 | +- Unit suite above. |
| 92 | +- Manual after install: SaaS-style agent prompt → log `toolsParsed≥1`, tool cards, **no** raw `<function=` in chat; a second turn that already used JSON still works. |
| 93 | + |
| 94 | +## Execute order |
| 95 | + |
| 96 | +1. A prompt header restore |
| 97 | +2. B parser + strip + looksLike |
| 98 | +3. C tests |
| 99 | +4. D release |
0 commit comments