Commit Graph

7 Commits

Author SHA1 Message Date
Adriano ba4eb09a71 feat(phase-2.5): Task 6 cost_kind attribution + fees_eat_alpha threshold CLI
Task 6 del piano Phase 2.5 (deferito → ora completato):
- CostRecord: nuovo campo call_kind (default "hypothesis")
- CostTracker.record: accetta call_kind opzionale, summary include
  by_call_kind breakdown (hypothesis vs mutation)
- Schema cost_records: aggiunta colonna call_kind TEXT NOT NULL DEFAULT
  'hypothesis' + migration soft via ALTER TABLE in init_schema (silently
  catched per DB pre-Task 6)
- Repository.save_cost_record: nuova arg call_kind opzionale
- mutate_prompt_llm: accetta cost_tracker/repo/run_id opzionali e logga
  la call mutator con call_kind="mutation" quando sink presente
- weighted_random_mutate, next_generation: propagano cost sink
- orchestrator.run_phase1: passa cost_tracker+repo+run_id a
  next_generation solo se prompt_mutation_weight > 0

Esposto fees_eat_alpha_threshold come parametro AdversarialAgent
(default 0.5 = comportamento Phase 1.5 invariato), propagato via
RunConfig.fees_eat_alpha_threshold e flag CLI
--fees-eat-alpha-threshold. Abilita ablation con soglia 0.7-0.8 senza
modificare codice — adversarial finding dominante in tutti i run
Phase 2/2.5 (50+ HIGH per run).

Tests (+4 → 186 totale):
- test_cost_tracker: default call_kind="hypothesis"; breakdown
  by_call_kind con hypothesis+mutation
- test_mutation_prompt_llm: logging mutation cost con sink completo;
  backward compat senza sink (no errore)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 10:42:13 +02:00
Adriano c38311e5fa feat(phase-2.5): mutate_prompt_llm operator + weighted dispatcher + GA wiring
Implementazione completa Phase 2.5 (LLM prompt mutator) seguendo il piano in
docs/superpowers/plans/2026-05-11-mutate-prompt-llm-phase-2-5.md.

Nuovo modulo src/multi_swarm/genome/mutation_prompt_llm.py:
- 6 mutation instructions (tighten_threshold, swap_comparator, add_condition,
  remove_condition, change_timeframe, add_temporal_gate)
- mutate_prompt_llm(g, llm, rng, mutator_tier=ModelTier.B): clona genome con
  tier B per la call mutator, costruisce system+user prompt con istruzione
  scelta random, estrae prompt da tag <prompt>...</prompt>, valida
- is_valid_prompt(): 3 check (lunghezza >= 50, keyword tecnica, diff > 5%
  Levenshtein-like via difflib.SequenceMatcher)
- Fallback random_mutate su qualsiasi validation fail O LLM exception

Esteso src/multi_swarm/genome/mutation.py con weighted_random_mutate dispatcher:
con probabilità prompt_mutation_weight invoca mutate_prompt_llm, altrimenti
random_mutate. Backward compat: llm=None oppure weight=0 → solo scalare.

Integrazione GA loop + RunConfig:
- GAConfig.prompt_mutation_weight: float = 0.0 (default off)
- next_generation(llm=...) propagato all'invocazione mutator
- RunConfig.prompt_mutation_weight con stesso default
- run_phase1: passa llm a next_generation solo se weight > 0
- scripts/run_phase1.py: flag CLI --prompt-mutation-weight

Tests (+18, 175 totale):
- tests/unit/test_mutation_prompt_llm.py (12): extract_prompt, is_valid_prompt
  3 check, operator success + fallback su 3 modi (invalid/identical/exception),
  tier B per LLM call, istruzione scelta dal pool
- tests/unit/test_mutation_dispatcher.py (4): weight 0/1/None + distribuzione
  30/70 su 1000 estrazioni con tolleranza ±5%
- tests/integration/test_ga_loop_with_prompt_mutator.py (2): loop con
  weight=1.0 produce prompt evoluti; backward compat weight=0 invariato

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 23:49:46 +02:00
Adriano 370acb4893 refactor(data): replace ccxt OHLCV loader with CerberoOHLCVLoader (deribit default)
Cerbero MCP diventa unica fonte di verità per dati di mercato Phase 1.
Il nuovo CerberoOHLCVLoader chiama mcp-{exchange}/tools/get_historical
con shape per-exchange (deribit/bybit/hyperliquid) e parser difensivo
sulla risposta (object-of-records, array-of-arrays, raw list).

- src/multi_swarm/data/cerbero_ohlcv.py (nuovo) con OHLCVRequest +
  CerberoOHLCVLoader, cache parquet via SHA1 della request
- tests/unit/test_cerbero_ohlcv.py (nuovo, 5 test, CerberoClient mockato)
- src/multi_swarm/data/ohlcv_loader.py + test ccxt rimossi
- scripts/run_phase1.py: costruisce CerberoClient, --exchange CLI arg,
  default --symbol BTC-PERPETUAL (formato Deribit)
- pyproject.toml: rimosso ccxt>=4.4 (uv sync ha rimosso 16 transitivi)
- .env.example: CERBERO_BASE_URL=https://cerbero-mcp.tielogic.xyz +
  nota su MAINNET vs TESTNET token

Schema confermato via OpenAPI di Cerbero (instrument/start_date/end_date
+ resolution opzionale). Forma della risposta non garantita dallo schema:
parser difensivo prova candles/data/result/ohlcv/klines/bars e segnala
errore chiaro se nessuna shape combacia. Live verification skippata
(nessun token in .env).

Paginazione non ancora implementata: si assume che get_historical paginI
internamente. Da rivedere se una live call mostra cap (~1000 candele).

Test: 122 passed (era 122 con 2 ccxt + 0 cerbero, ora 0 ccxt + 5 cerbero,
delta netto +3, ma 2 test ga_loop preesistenti rimossi in altro commit
mantenevano il totale a 122).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 10:58:16 +02:00
Adriano 4dad8be36b refactor(llm): route all tiers via OpenRouter, drop Anthropic SDK
Tutti i tier (S/A/B/C/D) ora passano per OpenRouter via OpenAI SDK.
Modelli Anthropic raggiungibili via prefisso `anthropic/...`.

- pyproject: rimosso `anthropic>=0.39` da deps + uv.lock
- config: rimosso `anthropic_api_key` field
- LLMClient: dispatch unico, single client OpenAI con base_url OpenRouter
- defaults S/A/B → `anthropic/claude-{opus-4-7,sonnet-4-6}`
- retry exceptions: solo openai.* (drop anthropic.*)
- test rinominati e adattati: tier S/A/B mockano OpenAI con prefisso `anthropic/`
- rimosso test `tier_S_without_anthropic_key_raises` (non più rilevante)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:39:23 +02:00
Adriano 33d8e275e7 feat(llm): full multi-tier S/A/B/C/D with routing + pricing
Estende ModelTier a 5 livelli (S/A/B/C/D) con routing automatico:
S/A/B via Anthropic SDK, C/D via OpenRouter (OpenAI SDK). Aggiunge
prezzi per tier S (Opus), A (Sonnet placeholder) e D (Llama). Refactor
LLMClient.complete con dispatch tramite tier_models map e helper
_call_anthropic / _call_openrouter. Settings esposte per tutti e 5
i modelli env-configurabili.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:18:57 +02:00
Adriano 7482600146 feat(llm): make tier-C/tier-B model + OpenRouter URL configurable from .env
LLM_MODEL_TIER_C, LLM_MODEL_TIER_B e OPENROUTER_BASE_URL ora override-abili
via env. Default invariati (back-compat). LLMClient accetta i tre valori
come kwargs opzionali; run_phase1 li propaga da Settings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 09:13:14 +02:00
Adriano 846c68d2f5 feat(scripts): Phase 1 runner CLI entry point
Aggiunge scripts/run_phase1.py come entry point CLI per eseguire un run
end-to-end di Phase 1 con parametri configurabili via argparse (popolazione,
generazioni, simbolo, finestra temporale, fees, seed). Aggiunge marker
py.typed al package multi_swarm per esporre i tipi a consumatori esterni
(scripts/) sotto mypy --strict.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 20:37:38 +02:00