Files
echo-core/config.json
Marius Mutu 747afbaf9d feat(steering): mesaje mid-tur + /stop pe turul în zbor
Un al doilea mesaj trimis cât Claude încă lucra aștepta până se termina
turul 1 — corecția „stai, nu în master" ajungea după ce greșeala era gata.
Verificat în producție înainte de commit: mesajul 2 stătea 25s blocat în
lock, apoi pornea ca tur separat.

Acum canalele de chat pot ține un proces `claude` viu per canal, cu stdin
deschis, și al doilea mesaj intră în ACELAȘI tur.

- `src/claude_runner.py` — ClaudeProcess (steering, respawn cu --resume,
  drenare stderr, respawn la comutarea OpenRouter) + RunnerRegistry
  (max_live, reaper pe inactivitate, stop_all la shutdown)
- `src/stream_json.py` — parser stream-json partajat cu `_run_claude`;
  pur, nu aruncă niciodată pe is_error (PlanningSession retrimite pe
  error_max_turns și depinde de asta)
- `src/sentinels.py` — un singur loc pentru __AUDIO__/__STEERED__, în loc
  de 4 verificări copiate; repară și bug-ul preexistent prin care
  WhatsApp posta literal `__AUDIO__:/cale`
- dispecer în `send_message`: lock.acquire(blocking=False) — eșecul de a
  lua lock-ul ESTE „rulează un tur", ceea ce elimină flagul inflight din
  decizie și cursa TOCTOU odată cu el
- `/stop` oprește turul, nu sesiunea — active.json rămâne valid
- rate limit prin proces persistent vine ca result.is_error, nu ca exit
  code; convertit înapoi în același RuntimeError, altfel fallback-ul
  local nu s-ar mai declanșa niciodată, în tăcere

Steering-ul nu face niciodată cross-adapter (un mesaj text nu intră
într-un tur voice: împart același channel_id). Mesajele steered dintr-un
tur care pică sunt re-livrate, nu pierdute.

Testat live cu CLI-ul real: corecție la secunda 10 dintr-un tur de 24s,
un singur result, num_turns=2. Notă: mesajele steered sunt împachetate în
[EXTERNAL CONTENT], deci o corecție formulată ca override agresiv poate
fi refuzată ca prompt injection — pentru oprire folosește /stop.

Suită: 1199 passed, 12 failed (toate pre-existente pe HEAD curat).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SiJGsZVSEGjRHZEJiXaxCC
2026-09-02 11:05:58 +00:00

137 lines
2.9 KiB
JSON

{
"bot": {
"name": "Echo",
"default_model": "sonnet",
"owner": "949388626146517022",
"admins": [
"5040014994"
]
},
"channels": {
"echo-core": {
"id": "1471916752119009432",
"default_model": "sonnet"
},
"echo-work": {
"id": "1466726254312030259",
"default_model": "sonnet"
},
"echo-sprijin": {
"id": "1466739361503772864",
"default_model": "sonnet"
},
"echo-self": {
"id": "1466739112747864175",
"default_model": "sonnet"
}
},
"telegram_channels": {},
"whatsapp": {
"enabled": true,
"bridge_url": "http://127.0.0.1:8098",
"owner": "40723197939",
"admins": []
},
"whatsapp_channels": {
"echo-test": {
"id": "120363424350922235@g.us",
"default_model": "sonnet"
}
},
"heartbeat": {
"enabled": false,
"interval_minutes": 120,
"channel": "echo-core",
"model": "haiku",
"quiet_hours": [
23,
7
],
"checks": {
"email": true,
"calendar": true,
"kb_index": true,
"git": false
},
"cooldowns": {
"email": 1800,
"calendar": 1800,
"kb_index": 14400,
"git": 14400
}
},
"allowed_tools": [
"Read",
"Edit",
"Write",
"Glob",
"Grep",
"WebFetch",
"WebSearch",
"Bash(python3 *)",
"Bash(.venv/bin/python3 *)",
"Bash(pip *)",
"Bash(pytest *)",
"Bash(git *)",
"Bash(npm *)",
"Bash(node *)",
"Bash(npx *)",
"Bash(systemctl --user *)",
"Bash(trash *)",
"Bash(mkdir *)",
"Bash(cp *)",
"Bash(mv *)",
"Bash(ls *)",
"Bash(cat *)",
"Bash(chmod *)",
"Bash(docker *)",
"Bash(docker-compose *)",
"Bash(docker compose *)",
"Bash(ssh *@10.0.20.*)",
"Bash(ssh root@10.0.20.*)",
"Bash(ssh echo@10.0.20.*)",
"Bash(scp *10.0.20.*)",
"Bash(rsync *10.0.20.*)"
],
"discord": {
"email_webhook_url": "https://discord.com/api/webhooks/1496421990846697583/OM8z1eBsJC6-UB9-Zi5RkHP23NNv9UrEznRMx4Y3wSWOFmLazPoi-8_iEKMp0Qgsqr-m"
},
"ollama": {
"url": "http://10.0.20.161:11434"
},
"local_fallback": {
"url": "http://10.0.20.161:8091/v1/chat/completions",
"enabled": true
},
"voice": {
"allowed_user_ids": [
"949388626146517022"
],
"user_name": "Marius",
"default_voice": "Marius 4",
"auto_leave_minutes": 5,
"stt_model": "/home/moltbot/echo-core/models/whisper-small-ro-cv11-int8"
},
"paths": {
"personality": "personality/",
"tools": "tools/",
"memory": "memory/",
"logs": "logs/",
"sessions": "sessions/"
},
"roa2web": {
"base_url": "https://roa2web.romfast.ro/roa2web/api",
"default_company": "114",
"default_company_name": "ROMFAST SRL"
},
"tts": {
"default_engine": "pockettts",
"pockettts_url": "http://127.0.0.1:7789"
},
"steering": {
"enabled": true,
"idle_minutes": 20,
"max_live": 2
}
}