Prima di interpellare il pianificatore, Metnos prova a riconoscere la richiesta. Se l'ha già vista e sa già come risolverla, ne riusa il path già pronto — la sequenza di executor che la porta a termine — e risponde in mezzo secondo invece che in dieci. Niente modello linguistico da consultare: basta la memoria.
Il pianificatore di Metnos è un modello linguistico locale, il tier
wise, il più capace. Ragiona bene, ma per scegliere il primo
passo di un turno ci mette una decina di secondi: per molte richieste è
un'attesa fuori misura. «Che ora è?» non chiede un modello,
chiede lo strumento get_now. E «scaricami questa pagina e
descrivimela in due righe», se la chiediamo spesso, non chiede il
pianificatore ma un path già noto: get_urls, poi
describe_entries.
Resta da capire come riconoscere una richiesta nota — e quando una soltanto somigliante è abbastanza vicina da trattarla allo stesso modo. È il compito del fast-path introvertivo, su due livelli: colgono gradi diversi di somiglianza, ma arrivano allo stesso risultato, il path giusto eseguito senza ripensarci.
I due livelli si distinguono per quanto riconoscono del path. L0 ne riconosce tutto, argomenti compresi: la stessa richiesta di prima, con gli stessi valori concreti. L1 riconosce il solo path — lo scheletro della soluzione, spogliato degli argomenti — e per questo vale per un'intera famiglia di richieste affini.
| Livello | Cosa riconosce | Come | Costo a ogni riuso |
|---|---|---|---|
| L0 | Path + argomenti. La stessa richiesta già risolta — identica o di significato molto vicino — con i suoi valori concreti (quel nome, quell'URL, quella data). | Confronto per impronta (0a) + coseno BGE-M3 (0b) | < 5 ms (impronta) / < 150 ms (coseno) |
| L1 | Solo il path. Lo scheletro generalizzato, senza argomenti, valido per un gruppo di richieste affini già confermato dall'utente. | Ricerca per intent e gruppo | ~30 ms |
L'ordine è fisso: prima si tenta L0; se non trova corrispondenza si passa a L1. Se mancano entrambi, la richiesta arriva al pianificatore (il motore), come sempre.
fastpath.py)
Il primo livello vive in runtime/engine/fastpath.py e custodisce,
in un database SQLite (fastpaths.sqlite), i piani già
eseguiti. Le voci nascono da sole: ogni volta che un turno va a buon fine
— un piano nuovo del motore, il riuso di un L1, una promozione dal coseno
0b — Metnos annota la query canonica, la sua impronta, l'embedding BGE-M3
(la forma numerica del testo, quella con cui se ne misura la vicinanza di
significato), il piano per intero (lo scheletro, o framework) e
l'intent, cioè il verbo e l'oggetto della richiesta. Nessuna
approvazione: le catene sono fatte di executor già vagliati e provati.
La ricerca avviene in due fasi:
/admin/praxis.undo_last_turn e
get_inputs non generano fastpath, perché il loro
significato dipende dal turno in corso.since_iso="2026-06-11") non si registra: rieseguirlo un
altro giorno aprirebbe una finestra temporale ormai congelata. Le date relative
(time_window="today") invece sì, perché a
ogni riesecuzione si ricalcolano da capo.autopath.py)
Il secondo livello vive in runtime/engine/autopath.py e ragiona
in modo diverso: non ripete la stessa query, ma generalizza a un
gruppo di intent affini, quello che l'utente ha approvato con un
riscontro positivo.
A ogni «✓» dell'utente, Metnos annota lo scheletro del turno, la sua impronta e il gruppo di significato a cui appartiene. Bastano poche conferme — configurabili, di base una sola — sullo stesso scheletro e gruppo perché il piano diventi un autopath riusabile: la volta dopo, un intent dello stesso gruppo lo rimette in moto senza disturbare il pianificatore.
I fastpath L0 invecchiano e muoiono per regole fisse, senza che nessun modello
ci metta mano. Ogni notte il processo task_state_reaper applica
tre regole d'invecchiamento e quattro condizioni di morte.
| Regola | Criterio | Default | Env |
|---|---|---|---|
| Mai riusato | Creato da oltre N giorni ma mai servito una seconda volta | 14 giorni | METNOS_FASTPATH_GRACE_DAYS |
| Stantio | Ultimo uso oltre N giorni fa | 30 giorni | METNOS_FASTPATH_STALE_DAYS |
| Cap LRU | Totale entry superiore al tetto; le meno recenti vengono potate | 500 | METNOS_FASTPATH_MAX |
| Codice | Causa | Eredità |
|---|---|---|
| C1 | Uno strumento del piano non esiste più nel catalogo (ritirato, rinominato, archiviato). La riesecuzione fallirebbe. | No |
| C2 provenienza | Il fastpath è stato promosso a executor sintetico (vedi §9) e quell'executor è ora nel catalogo. | Sì |
| C2 nome | Esiste un executor con nome {verbo}_{oggetto} corrispondente all'intent, ma nessuno strumento del piano appartiene a quella famiglia. Il fastpath oscurerebbe l'executor. | Sì |
| C2 pre-filtro | Per i piani a più passi: il pre-filtro di instradamento deterministico sulla query canonica indica che un singolo executor copre l'intent (anche con nome diverso). | Sì |
Quando un fastpath muore perché un executor lo ha superato (le
condizioni C2), i suoi conteggi d'uso (n_uses) passano
all'executor erede, lungo lo stesso meccanismo d'invecchiamento degli executor.
La domanda già raccolta non si butta via.
Riconoscere la richiesta è metà del lavoro. L'altra metà
è ricavarne i valori concreti: quali path, quali URL, quale data, quale
soglia. Se ne occupa un estrattore a regole (args_extractor.py),
anch'esso senza modello:
https://...), path (~/... o /..., con la
scorciatoia «home» che diventa ~/), email, numeri,
estensioni di file («file PDF» → *.pdf), date
(oggi, ieri, domani, dopodomani — in italiano e in inglese —
tradotte in formato ISO) e finestre temporali («questa settimana»,
«ultime 24 ore», «last 7 days»).
Il fast-path si regola con variabili d'ambiente METNOS_*. Per i
valori che devono restare nel tempo c'è un file TOML
(~/.config/metnos/runtime.toml); il valore scritto nel modulo
è l'ultima rete, quando tutto il resto tace.
| Variabile | Default | Significato |
|---|---|---|
METNOS_FASTPATH_STALE_DAYS | 30 | Giorni calendario dopo cui una entry non usata viene potata |
METNOS_FASTPATH_GRACE_DAYS | 14 | Giorni di grazia per entry mai riusate |
METNOS_FASTPATH_MAX | 500 | Tetto massimo righe (LRU) |
| Variabile | Default | Significato |
|---|---|---|
METNOS_AUTOPATH_MIN_OBS | 1 | Osservazioni positive minime per promuovere un autopath |
METNOS_AUTOPATH_TTL_ANTI | 2592000 (30 gg) | Durata di un'anti-autopath in secondi |
METNOS_AUTOPATH_TTL_REPEAT | 3600 (1 h) | Finestra breve per riscontri ripetuti |
| Variabile | Default | Significato |
|---|---|---|
METNOS_FP_PROMOTE_MIN_CLUSTER | 3 | Fastpath distinti minimo nel gruppo |
METNOS_FP_PROMOTE_MIN_USES | 15 | Uso cumulato minimo |
METNOS_FP_PROMOTE_MIN_AGE_DAYS | 30 | Età minima del gruppo |
METNOS_FP_PROMOTE_MAX_PER_NIGHT | 3 | Massimo di nuove proposte per notte |
METNOS_FASTPATH_AUTOPROMOTE | off | Abilita l'auto-promozione di Modalità 2 (senza approvazione) |
Quando più fastpath L0 ricorrenti condividono la stessa struttura di
piano (l'impronta dello scheletro) e lo stesso intent, ogni notte il processo
task_fastpath_promotion li soppesa come candidati a diventare un
executor sintetico a tutti gli effetti. A pesare è il gruppo, mai la
singola istanza: servono almeno tre fastpath distinti, quindici utilizzi in
tutto e trenta giorni di età. E si promuovono solo gli schemi a
più passi: quelli a passo singolo un executor ce l'hanno già, e
lì il fastpath serve a saltare l'LLM, non a comporre il piano.
/admin/changes, la vista unificata delle modifiche (ADR 0158). Con
il sì, un marcatore synt_pending/ avvia la sintesi completa
— i cinque stadi, i test, la firma, l'installazione.
Al momento della promozione, Metnos annota in una tabella
(promotions) da quali fastpath è nato il nuovo executor:
ne registra gli identificatori e le impronte. Serve a chiudere il cerchio.
Quando l'executor entra nel catalogo, i fastpath che lo hanno generato non
servono più e vengono ritirati (è la condizione di morte
«C2 provenienza» del cap. 6). Grazie a quell'annotazione il
ritiro è esatto: Metnos sa con certezza quali fastpath
togliere, perché il legame fra ciascun fastpath e il suo erede è
scritto, non indovinato dal nome.
© 2026 Roberto Brunialti · documentazione Metnos