Files
tai/taicpp/CHANGELOG.md
T
retoorandClaude Sonnet 5.5 1611f3baeb whatsapp: fix link/login 401, add image send, contact sync and search; harden failover
Root causes, each reproduced against the live server or endpoint:
- Server-only JIDs decoded as "@s.whatsapp.net" and pairing replies copied them
  into `to`, so the device was never registered and every login returned 401.
  Decoder/encoder fixed, replies use s.whatsapp.net, ADV hosted prefixes follow
  whatsmeow. The link wizard now waits for the restart, logs in, uploads prekeys
  and retries once with a fresh device on 401/403.
- Closed sockets made every receive loop spin until its deadline (the 7 minute
  CPU burn). Loops stop on a closed stream.
- whatsapp_send had no image argument and send_image was a stub. Added WaMedia
  (byte-exact against 8 wa-go golden vectors), media_conn upload, image send and
  the DeviceSentMessage copy for the user's other devices.
- Phone contacts never reached the client: added app-state sync (WaAppState,
  WaReceiver, LTHash and MAC checks verified against a whatsmeow-built oracle)
  and the historySyncConfig declaration at registration.
- Contact lookup: FTS5 trigram plus fuzzy ranking, ambiguity is reported and
  never guessed, global search lists contacts. Send caps (10/min, 200/day) are
  enforced and survive unlink.

Failover and agent:
- Every failed backend candidate is printed the moment it fails.
- muse runs with low reasoning effort, an empty preset and one stable workspace
  (36.5s down to 2.8s on the real prompt); Ctrl-C no longer counts as a backend
  failure; CLI backends use the circuit breaker; opencode runs are capped at 30s.
- Orphan tool results are dropped before sending (devplace HTTP 400, reproduced);
  compaction no longer starts its window on a tool result.
- Terminal art pasted as a prompt is refused before any model call.

Tests: whatsapp_test, muse_flags_test, llm_history_test; full suite 40 steps
(agent.e2e reads live tmux panes and is flaky, green on re-run).
Research archived under research/whatsapp-automation.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-27 21:32:38 +01:00

8.6 KiB

Changelog

[1.44.3] - 2026-10-25

  • Bump to 1.44.3

[Unreleased] - 2026-10-25

  • Verified the static build still works (make static exit 0, 29 MB build/detz-static, --version prints tai 1.44.3); stamped in docs/embed.md.
  • Docs: docs/whatsapp.md now states up front what whatsmeow is (the upstream Go reference library, MPL-2.0) and how this tree uses it (behavior referee for the native C++ port, not a linked dependency).
  • WhatsApp link, image and contacts (docs/whatsapp.md section 15): pairing replies now address s.whatsapp.net (the decoder printed server-only JIDs as @s.whatsapp.net, the root cause of every post-link 401); the link wizard waits for the restart, logs in, uploads prekeys and retries once with a fresh device on 401/403; closed sockets no longer spin the CPU; whatsapp_send takes image (PNG/JPEG up to 16 MB, WaMedia, own devices get the DeviceSentMessage copy) and enforces 10/minute and 200/day; contacts sync from the phone (app-state, historySyncConfig now declared at registration) and are searched with FTS5 trigram plus fuzzy ranking, also from the global search tool; ambiguous names are reported instead of guessed.
  • clean_history drops orphan tool results (and logs it), and compaction no longer starts its kept window on a tool result: reproduced the devplace HTTP 400 No function call found for function call output against the live endpoint. Test: build/llm_history_test.
  • Terminal art (QR codes, boxed screens) pasted as a prompt is refused before any model call; a failed Ctrl-C no longer counts against backend health; muse runs in one stable workspace per home; the provider probe accepts bare JSON lists (pollinations) and prints the start of a bad body.
  • WhatsApp native protocol core (docs/whatsapp.md, src/whatsapp/, namespace detz::wa): a from-scratch C++ implementation of WhatsApp Web's multi-device wire protocol, built on OpenSSL plus a vendored public-domain ed25519 ref10 (third_party/ed25519, zlib) for XEdDSA, with no new runtime dependency. WaCrypto (X25519, AES-GCM/CTR/CBC, HKDF, PBKDF2, SHA, XEdDSA), WaBinary (binary-XML codec + token dict v3), WaProto (hand-written protobuf + the messages the 1:1 text/image client needs), WaNoise (Noise XX handshake + transport), WaSignal (X3DH + Double Ratchet, AES-CBC+HMAC). Verified byte-for-byte against golden vectors captured from the real Baileys client (tests/whatsapp_data/, from jfelipesjc/wa-go, MIT): HKDF/PBKDF2 RFC vectors, XEdDSA roundtrips, codec battery 19/19, ClientPayload byte-exact, the full Noise handshake, and a 4-exchange Signal session byte-exact. Test: build/whatsapp_test (16/16), step whatsapp.unit in run_all. The live socket/pairing/send/receive layer and the --whatsapp-link wizard and agent tools are not built yet; the live path is unverified (needs a linked phone). Research: research/whatsapp-automation.
  • Terminal screenshots (docs/termshot.md): new tool terminal_screenshot writes a PNG of the current tmux or native multiplexer pane on a headless server (capture-pane -e, TuiVtScreen replay, embedded Spleen 8x16 font, zlib PNG; no new dependency). detz-only tools now live in src/agent/detz_tools.*; agent.diff and agent.e2e turn them off to keep comparing with tai.py. Test: build/termshot_test. Research: research/terminal-screenshot-rendering (99 sources, 2 conclusions).
  • WhatsApp research and build spec: docs/whatsapp.md (no native Python library exists, no browser needed, native C++ detz::wa transpiled from wa-go with whatsmeow as referee, no new dependencies, build vs deep-research table, caps, tests, phases, a whatsapp-mcp shortcut). Research: research/whatsapp-automation (70 sources, 3 conclusions). Nothing built.
  • LLM failover is no longer silent: every failed candidate prints x provider/model failed after N.Ns: reason to stderr the moment it fails (before, errors only reached the debug log until a whole round failed, so a 73 s turn showed only "thinking"). The line clears the spinner row first on a tty.
  • muse: muse exec now runs with --reasoning-effort low, --preset empty and --no-foreign-personal-context (consts kMuseReasoningEffort). Measured on the real 16 KB tai prompt: 36.5 s at the default effort, 2.8 s at low, 2.4 s with the empty preset too; the default let muse reason 4.5k tokens about conflicting tool sets and call its own read_skill, which failed with step_limit after 34 s. That failure now reads "muse tried to call its own tools instead of answering".
  • Circuit breaker (3 consecutive failures, 300 s) now also applies to CLI backends (muse, opencode, grok, claude, codex, gemini); before, they were appended to the candidate list regardless of health.
  • opencode runs are capped at kCliFallbackTimeout = 30 s each (they sit in the fallback chain and rotate through free models). Test: build/muse_flags_test.
  • --install: the native version reader now returns nothing when the target file is absent, so a fresh install reports installed instead of refreshed X -> X. Documented the install target and its gaps in docs/misc.md.
  • Documentation: new docs/cap-agents.md (agents, models, probes, @agent resolution, errors, limits, troubleshooting), rewritten docs/fuzzy.md (algorithm, constants, measured worked examples) and docs/orchestration.md (protocol with examples, layout, lifecycle, state machine, formatter, event mapping, supervision, collection, caps, measurements, verification, gaps), feed panes in docs/mplex.md, README overview; make docs checks the new pages; drift tests keep the constant tables in step with the code.
  • Orchestration on the multiplexer screen (docs/orchestration.md): every sub agent (fork worker, CAP session, @agent mention) gets a live, word-wrapped panel; the main pane stays left at full height and sub agents stack on the right (1, 2, 3 ... up to what fits at 6 rows each). New: feed panes in the multiplexer (vpane_* control commands, MplexVpanes), src/orch/ (OrchBoard, OrchPanel, OrchFormatter, OrchTransport, OrchCapAdapter), Agent::observer and cancel flag, supervision (idle warn 60 s, idle cancel 300 s, soft cancel then close after 5 s, closing the pane cancels the job), CAP answers collected through the spill path. Tests: build/orch_test, tests/orch_mplex_e2e.py with build/orch_live. Measured: about 64 frames/s, median 12.9 ms between frames, p90 25 ms with three agents streaming 500 tokens/s each.
  • Generic detz::FuzzyMatcher (src/util/fuzzy.*, docs/fuzzy.md, tests/fuzzy_test.cpp): subsequence DP with fzf constants, Damerau-Levenshtein, per-token typo and trigram signals; @agent / @model mentions now always pick the most related candidate (floor 0.3, ties shorter then earlier, a note shows what was resolved). Research: research/fuzzy-matching-selectors.
  • @agent, @agent:model and bare @model mentions resolve against CAP agents via the new CapModelCatalog (manifest [models] list or --cap-models probe); turns run through CapMention; failures print a per-agent report of status, binary and models. Test: build/capmcp/cap_model_catalog_test. Spec: docs/cap.md.
  • Build and test integration after the parallel module ports. Not released: make test is not green (see below), so VERSION stays 1.44.2 and no tag was made.
  • Makefile rewritten: objects in build/obj, archive build/libdetz.a (no main.cpp), one test binary per delivered test source (foundation, store, cli, util/config, agent diff/e2e/sched, shell, cap/mcp unit/probe/cli, misc, tui spec/shot/script/rows/chat/grr, mplex x11), make test, make lint (real -Werror -fsyntax-only over src, main.cpp and tests, no || true), make parity, make parity-check (docs/wiring/verify.md).
  • tests/run_all.py: runs all 32 steps (C++ unit binaries plus the python differential drivers), logs to build/test-logs/, prints a summary table, exits 1 on any failure.
  • -I for moloapp now searched in ../../moloapp/src, the worktree-relative path and $HOME/projects/moloapp/src (MOLOAPP_SRC= overrides); src/cli needs tenancy/strategy.h from it.
  • Removed the obsolete store_test rule, the unused per-module *.mk files and tests/foundation.mk, tests/misc.mk.
  • tests/test_main.cpp replaced by tests/util_config_test.cpp: its shell section is covered by shell_test.cpp, its cli section by cli_test.cpp, its llm section tested the removed placeholder llm API (ChatClient/ModelHealth/Opencode); the util and config checks and the --help run are kept.