Native WhatsApp Web multi-device client in C++ (src/whatsapp/, namespace detz::wa), built on OpenSSL plus a vendored public-domain ed25519 ref10 (third_party/ed25519, zlib) for XEdDSA and the nayuki QR generator (third_party/qrcodegen, MIT); no new runtime dependency. - WaCrypto, WaBinary, WaProto, WaNoise, WaSignal, WaDevice, WaSocket, WaClient, WaStore, WaQr, WaWizard. - Verified offline 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 Noise handshake, and a 4-exchange Signal session byte-exact. Unit test build/whatsapp_test (16/16), run_all step whatsapp.unit. - Verified live against web.whatsapp.com: `detz --whatsapp-link` connects, completes the Noise handshake, receives pair-device, renders a scannable QR in the terminal, and persists the device to the vault (whatsapp/<profile>.db). Also --whatsapp-status / --whatsapp-unlink. - Agent tools whatsapp_send and whatsapp_contacts (detz-only, in DetzTools). - Pairing completion after the phone scans, and the message send path (usync + prekey fetch + Signal encrypt + send node), are ported faithfully from whatsmeow but unverified in-tree (no linked account in development). send_image and own-device fan-out are not wired yet. See docs/whatsapp.md. Also in this snapshot: the terminal-screenshot tool (src/termshot/, terminal_screenshot, docs/termshot.md, research/terminal-screenshot-rendering) and a concurrent session's in-progress llm/muse failover changes carried along in the shared files. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
30 lines
2.4 KiB
Markdown
30 lines
2.4 KiB
Markdown
# llm: providers, ChatClient, JSON, Python semantics
|
|
|
|
Port of tai.py 6957-8650 (backends, ModelHealth, ChatClient) plus the helpers they need. Namespace `detz::llm` (`detz::py` for Python semantics, `detz::json` for JSON). The old placeholder API (openai/anthropic providers) is removed: tai.py has no such providers.
|
|
|
|
| File | tai.py origin |
|
|
|---|---|
|
|
| `json.cpp` | `json.dumps/loads/raw_decode` byte-exact (ensure_ascii, separators, float repr, JSONDecodeError text, big ints) |
|
|
| `py.cpp` | code-point `len/slice`, `strip/lower/upper/split`, `str/repr/int/float`, datetime (`_fromisoformat`, fold-aware naive local), sha1/sha256, `utf8_replace` |
|
|
| `helpers.cpp` | `BackendError`, `truncate`, `estimate_tokens`, `clean_history`, `tool_args_*`, `action_signature`, `conversation_tokens` |
|
|
| `model_health.cpp` | `ModelHealth`, reward and weight functions |
|
|
| `models.cpp` | `split_models`, `parse_backends`, `fetch_model_ids`, `fetch_pollinations_free`, `is_free_*`, `prefer_muse`, `openrouter_free_tier` |
|
|
| `cli_backends.cpp` | opencode/grok/claude/codex/gemini prompts, parsers, runners, health, `probe_backend`, `opencode_headers` |
|
|
| `muse.cpp` | muse session map, flock+thread locks, `muse_run` streaming runner |
|
|
| `chat_client.cpp` | `ChatClient` (candidates, ordering, pins, retry rounds, single shot, streaming, `update_models`, `models_report`) |
|
|
| `http_transport.cpp` | libcurl transport with an injectable fake (`set_transport`) |
|
|
| `proc.cpp` | `subprocess.run/Popen`, `shutil.which` |
|
|
| `ports.h` | `LlmConfig`, `LogSink`, `BoxPort` |
|
|
| `unicode_data.cpp` (generated) | case maps, whitespace, digits from Python |
|
|
|
|
`--update-models` is `agent::update_models_command(config)`.
|
|
|
|
Gaps: see docs/agent.md. Unit tests never touch the network; the libcurl transport itself is only exercised by compile/link, not against a live server.
|
|
|
|
## Failover visibility and CLI caps
|
|
|
|
- Each failed candidate prints `x provider/model failed after N.Ns: reason` on stderr immediately (`ChatClient::announce_failure`), in addition to the debug log event.
|
|
- `muse_argv` always passes `--reasoning-effort low` (`kMuseReasoningEffort`), `--preset empty`, `--no-foreign-personal-context`. Measured on a 16 KB tai prompt: 36.5 s default, 2.8 s low, 2.4 s low + empty preset. Gap: only one prompt was measured, on one machine.
|
|
- `ordered_candidates` drops CLI candidates whose circuit is open (3 consecutive failures, 300 s) unless none remain.
|
|
- opencode runs are capped at `kCliFallbackTimeout` (30 s).
|