skill: subagent-supervision, ottimizzazione del consumo di contesto
Aggiunge la sezione 4b: dove vanno i token (system prompt, output strumenti, messaggi del supervisore, storia riletta a ogni turno), le sei leve ordinate per efficacia reale (sub-agente come firewall di contesto, stabilità del prefisso per non invalidare la cache del prompt, report invece di trascrizione, disciplina sugli output degli strumenti, mai rileggere, concisione del supervisore) e le tre regole di compattazione: non compattare presto né durante il lavoro, usare customInstructions per conservare decisioni e numeri scartando il ragionamento intermedio, scrivere il report prima di compattare così la summarization può essere aggressiva senza perdere valore. Include la regola di misurare la trascrizione per categoria prima di tagliare.
This commit is contained in:
@@ -1,204 +1,200 @@
|
||||
---
|
||||
name: subagent-supervision
|
||||
description: Avvia, supervisiona e controlla sotto-agenti pi (sub-agents) in finestre TUI separate, con un canale di controllo locale (HTTP su loopback + mailbox su file) per iniettare input e leggerne i risultati. Usare quando si parla di sotto-agenti, sub-agents, agenti paralleli, delegare un task a una sessione pi separata, leggere o impostare il contesto di un'altra sessione, o controllare una sessione pi in corso.
|
||||
description: Avvia, supervisiona e controlla sotto-agenti pi (sub-agents) in finestre TUI separate, con un canale di controllo locale (HTTP su loopback + mailbox su file) per iniettare input, seguirne gli eventi, gestirne contesto e costo e leggerne i risultati. Usare quando si parla di sotto-agenti, sub-agents, agenti paralleli, delegare un task a una sessione pi separata, leggere o impostare il contesto di un'altra sessione, controllare una sessione pi in corso, o chiuderla.
|
||||
---
|
||||
|
||||
# Supervisione di sotto-agenti pi
|
||||
|
||||
Un sotto-agente e' una **sessione pi separata con la sua TUI**, in una finestra o tab
|
||||
propria: l'utente la vede e la supervisiona direttamente, e l'agente supervisore la
|
||||
controlla tramite il canale locale dell'estensione `subagent-control`.
|
||||
**Skill = protocollo. Estensione = canale.** Una skill da sola non può parlare con un
|
||||
altro processo: l'iniezione la fa l'estensione `subagent-control` (repo privato
|
||||
`git.enne2.net/enne2/subagent-control`). Un sotto-agente è una **sessione pi con la
|
||||
sua TUI**: l'utente la vede e la supervisiona, il supervisore la controlla via canale.
|
||||
|
||||
Skill = protocollo (questa procedura). Estensione = canale (il codice che inietta).
|
||||
Una skill da sola **non** puo' parlare con un altro processo: l'iniezione la fa
|
||||
l'estensione.
|
||||
|
||||
## Canale di controllo
|
||||
|
||||
Ogni sessione che carica `subagent-control` registra se stessa:
|
||||
## 1. Avviare un sotto-agente
|
||||
|
||||
```
|
||||
~/.pi/agent/subagents/<id>.json {id, pid, port, token, cwd, started, hasUI,
|
||||
ready, busy, turns, injected, lastEvent, lastEventAt} (0600)
|
||||
~/.pi/agent/subagents/<id>.inbox mailbox: una riga = un messaggio iniettato
|
||||
1. BRIEF → file `TASK-<nome>.md`: obiettivo, fatti già verificati (non da ridimostrare),
|
||||
protocollo di misura, vincoli duri, cosa NON fare, deliverable continui.
|
||||
PUNTA ai documenti esistenti (CHANGES.md, report) invece di duplicarli:
|
||||
duplicare contesto si paga due volte.
|
||||
2. LAUNCH → setsid konsole -e bash -lc "cd <dir> && exec pi --name <nome> \
|
||||
--provider <p> --model <m> --thinking <livello> @TASK-<nome>.md '<primo prompt>'"
|
||||
3. VERIFICA→ attesa ATTIVA del registry (polling, mai sleep), poi /status, poi etichetta,
|
||||
poi il modello EFFETTIVO dalla trascrizione (vedi §8).
|
||||
```
|
||||
|
||||
**Il registry e' il segnale di prontezza**: viene scritto a fine avvio sessione, quindi
|
||||
**si polla il file, mai `sleep` a indovinare**. E viene riscritto a ogni cambio di stato,
|
||||
quindi un semplice `cat` dice gia' se la sessione e' occupata (`busy`).
|
||||
**Scelta del modello**: `--thinking high` per ottimizzazione e diagnosi; `medium` per
|
||||
misurazione, ricerca e manutenzione meccanica. Costo e ragionamento vanno allineati al
|
||||
tipo di lavoro, non al prestigio. `GET /models` dice quali livelli ogni modello
|
||||
supporta davvero (`thinkingLevelMap`, null = non supportato) e `costFullContext`.
|
||||
|
||||
Endpoint (bind solo su loopback, token obbligatorio):
|
||||
## 2. Canale di controllo
|
||||
|
||||
```bash
|
||||
curl -s -H "X-Pi-Token: $TOKEN" http://127.0.0.1:$PORT/status
|
||||
curl -s -H "X-Pi-Token: $TOKEN" -d '{"text":"nuovo contesto: ..."}' http://127.0.0.1:$PORT/say
|
||||
curl -s -H "X-Pi-Token: $TOKEN" -d '{"text":"...","requestId":"step-7"}' http://127.0.0.1:$PORT/say
|
||||
curl -s -m 130 -H "X-Pi-Token: $TOKEN" -d '{}' "http://127.0.0.1:$PORT/wait?timeout=120"
|
||||
curl -N -H "X-Pi-Token: $TOKEN" "http://127.0.0.1:$PORT/events?since=0"
|
||||
echo "input dalla mailbox" >> ~/.pi/agent/subagents/<id>.inbox
|
||||
```
|
||||
~/.pi/agent/subagents/<id>.json {id,pid,port,token,cwd,started,hasUI,ready,busy,turns,
|
||||
injected,label,heartbeatAt,lastEvent,lastEventAt} (0600)
|
||||
~/.pi/agent/subagents/<id>.inbox mailbox: una riga = un messaggio
|
||||
```
|
||||
|
||||
### Contesto, compattazione, ciclo di vita (v0.5)
|
||||
Endpoint (127.0.0.1, header `X-Pi-Token`; 403 token errato, 400 body, 404 route, 409 rifiutato):
|
||||
`GET /status`, `/context`, `/sessions[?prune=1]`, `/models`, `/events` (SSE, `?since`,
|
||||
ring buffer 200, heartbeat `: ping` 15 s); `POST /say`, `/wait`, `/model`, `/label`,
|
||||
`/compact`, `/abort`, `/shutdown`.
|
||||
|
||||
```bash
|
||||
# quanto e' pieno il contesto (tokens, contextWindow, percent, pending)
|
||||
curl -s -H "X-Pi-Token: $TOKEN" http://127.0.0.1:$PORT/context
|
||||
**Il registry è il segnale di prontezza** (scritto a fine avvio, riscritto a ogni cambio
|
||||
di stato e ogni heartbeat di 10 s): si **polla il file**, mai `sleep` a indovinare. Un
|
||||
`cat` dice già se la sessione è occupata.
|
||||
|
||||
# compattazione su richiesta (NON bloccante: risposta 202 + evento compaction_done)
|
||||
curl -s -H "X-Pi-Token: $TOKEN" -d '{}' http://127.0.0.1:$PORT/compact
|
||||
curl -s -H "X-Pi-Token: $TOKEN" -d '{"customInstructions":"tieni solo le decisioni e i percorsi file"}' http://127.0.0.1:$PORT/compact
|
||||
## 3. Attesa: quali confini contano
|
||||
|
||||
# fermare la direzione sbagliata / terminare in modo pulito
|
||||
curl -s -X POST -H "X-Pi-Token: $TOKEN" http://127.0.0.1:$PORT/abort
|
||||
curl -s -X POST -H "X-Pi-Token: $TOKEN" http://127.0.0.1:$PORT/shutdown
|
||||
```
|
||||
| evento | significato | attendibile? |
|
||||
|---|---|---|
|
||||
| `turn_end` | **turno intermedio** (7 in un solo run) | ❌ |
|
||||
| `agent_end` | run finito, ma possono seguire retry/continuazioni | ⚠️ |
|
||||
| `settled` | *sta per* assestarsi (evento azionabile) | ⚠️ quasi |
|
||||
| `agent_settled` | assestato **definitivamente** | ✅ (non ancora emesso: gap noto) |
|
||||
|
||||
Il messaggio iniettato **appare nella TUI come messaggio utente** e fa partire un turno:
|
||||
l'utente vede cosa sta facendo il sotto-agente mentre accade.
|
||||
**Protocollo race-free**: leggere `seq` da `/status` → iniettare → `POST /wait?since=<seq>`
|
||||
(long-poll che ritorna sul `settled`). Da bash è **una chiamata** che ritorna quando il
|
||||
lavoro è finito: meglio di un `curl -N` in background da presidiare. `GET /events` serve
|
||||
per la supervisione continua, non per il ciclo "inietta e aspetta".
|
||||
Prima di agire, verifica **tre cose insieme**: `busy == false` e `lastEvent` di settle e
|
||||
heartbeat fresco.
|
||||
|
||||
### Attesa: come si sa che ha finito
|
||||
## 4. Contesto e costo (la parte che si dimentica)
|
||||
|
||||
Non si polla la trascrizione e non si aspetta a tempo. Il canale emette eventi (SSE,
|
||||
con `id:` per riconnettersi via `since`):
|
||||
- **Ogni risposta JSON porta il blocco `context`** (`tokens`, `contextWindow`, `percent`,
|
||||
`pending`, `lastResponse`): l'orchestratore conosce lo stato **senza chiamare `/context`**.
|
||||
Monitorare non deve costare una chiamata.
|
||||
- `tokens: null` subito dopo una compattazione significa "non ancora noto", **non errore**.
|
||||
- **Soglia ~60%**: `POST /compact` (202, non bloccante) → attendere `compaction_done` →
|
||||
`POST /wait` sul `settled` → **solo allora** iniettare. Compattare molto prima è un
|
||||
costo, non un risparmio; compattare durante il lavoro lo interrompe.
|
||||
- `fromExtension: true` distingue le compattazioni che hai innescato tu.
|
||||
- **`cacheRead`** dice quanto costa davvero: se è alto, il prompt caching sta pagando.
|
||||
- **REPORT OBBLIGATORIO**: imporre al sotto-agente un file `REPORT-<nome>.md` aggiornato
|
||||
**a ogni passo** (stato, numeri, prossimo passo, contesto). È la leva di costo più
|
||||
efficace: leggere un report costa cento volte meno che ricostruire lo stato dalla
|
||||
trascrizione, e permette di sapere cosa ha concluso **senza interromperlo**.
|
||||
- **qmem**: far registrare i risultati (inclusi quelli negativi) e far correggere i
|
||||
record sbagliati.
|
||||
|
||||
| evento | significato |
|
||||
|---|---|
|
||||
| `ready` | canale in ascolto |
|
||||
| `injected` | input accettato (source, requestId, deliverAs) |
|
||||
| `turn_start` | l'agente e' occupato |
|
||||
| `turn_end` | un turno e' finito, ma puo' seguirne altro |
|
||||
| **`settled`** | **l'agente non continuera' da solo: e' inattivo e pronto a nuovo input** |
|
||||
## 4b. Ottimizzare il consumo (dove vanno i token, e come tagliarli)
|
||||
|
||||
**Regola operativa (a prova di race)**: leggere il `seq` da `/status`, **poi** iniettare,
|
||||
**poi** attendere con `POST /wait?since=<seq>&timeout=N`: il long-poll ritorna sul
|
||||
prossimo `settled` successivo a quel cursore. Senza `since` il cursore e' l'istante
|
||||
della chiamata e un evento gia' passato puo' essere perso (si finirebbe in timeout).
|
||||
Da bash e' **una sola chiamata** che ritorna quando il lavoro e' finito: meglio di un
|
||||
`curl -N` in background da presidiare. `GET /events` serve solo per supervisione
|
||||
continua (o per una UI), non per il ciclo "inietta e aspetta".
|
||||
**Quattro secchi**: (1) system prompt + AGENTS.md + skill caricate; (2) **output degli
|
||||
strumenti** (spesso il più grande, e resta in contesto per sempre); (3) i tuoi messaggi
|
||||
(generati *e* riletti a ogni turno); (4) la storia riletta ogni turno = tutto quanto sopra
|
||||
moltiplicato per i turni.
|
||||
|
||||
### Idempotenza
|
||||
**Leve, in ordine di efficacia reale:**
|
||||
|
||||
Un input iniettato due volte e' un doppio lavoro: passare sempre un `requestId` stabile
|
||||
(es. `step-7`). Ripetere la stessa richiesta con lo stesso `requestId` e' sicuro: il
|
||||
secondo invio torna `{"ok":true,"duplicate":true}` senza iniettare.
|
||||
1. **Il sotto-agente è un firewall di contesto.** Assorbe letture file, misure e
|
||||
fallimenti; al supervisore tornano poche centinaia di token. Nel caso reale: tre
|
||||
agenti hanno bruciato 121k+72k+109k token, il supervisore ne ha letti ~2k. Fai girare
|
||||
il lavoro pesante su modelli **più economici**: l'agenzia si prende il volume, tu la
|
||||
decisione.
|
||||
2. **Stabilità del prefisso = cache.** Misurato: `cacheRead` 47k su 47k e 110k su 121k →
|
||||
**98-99% dell'input servito da cache**. Ogni modifica a `AGENTS.md`, alle skill o alle
|
||||
estensioni **invalida il prefisso per tutti i turni successivi**: è il costo nascosto
|
||||
più caro. Non toccare quei file a metà sessione.
|
||||
3. **Report invece di trascrizione.** Leggere un report costa centinaia di token,
|
||||
ricostruire lo stato dalla trascrizione migliaia. **Documenti che puntano, non che
|
||||
duplicano**: un brief che dice "leggi CHANGES.md" costa 200 token, uno che lo ripete 5k.
|
||||
4. **Disciplina sugli strumenti**: `head`/`tail`/`grep -c` invece di dump; `-o md` per
|
||||
tabelle compatte; mai `cat` di file grandi. Ogni byte entra e non esce più.
|
||||
5. **Mai rileggere** lo stesso file, né ridedurre fatti già in `CHANGES.md` o in qmem.
|
||||
6. **Concisione del supervisore**: i messaggi lunghi restano in contesto e si rileggono a
|
||||
ogni turno. Tabelle e numeri, non prosa.
|
||||
|
||||
### Modalita' di consegna
|
||||
**Compattazione — tre regole:**
|
||||
|
||||
`deliverAs` (valori verificati nell'API): assente = accoda e fa partire un turno se
|
||||
inattivo; `steer` = corregge il turno in corso; `followUp` = consegna dopo il turno
|
||||
corrente; `nextTurn` = tiene per il turno successivo. Usare `steer` per fermare una
|
||||
direzione sbagliata senza uccidere la sessione.
|
||||
- **Non compattare presto, mai durante il lavoro.** Al 20% è un costo (paghi una
|
||||
summarization per buttare via dettaglio che ti serve). Soglia ~60%, e solo dopo il
|
||||
confine definitivo.
|
||||
- **`customInstructions` per compattare bene** (conserva l'utilità, taglia di più):
|
||||
`POST /compact {"customInstructions":"conserva decisioni, percorsi file, numeri misurati e comandi esatti; scarta il ragionamento intermedio e le ipotesi superate"}`
|
||||
- **Prima il report, poi la compattazione.** Il sotto-agente scrive la sintesi in
|
||||
`REPORT-*.md` **prima** di compattare: allora la summarization può essere aggressiva
|
||||
senza perdere nulla, perché il valore è già fuori dal contesto. `tokens: null` subito
|
||||
dopo significa "non ancora noto", non errore.
|
||||
|
||||
## Avviare un sotto-agente visibile
|
||||
**Prima di tagliare, misura**: se non sai quale dei quattro secchi pesa, stai ottimizzando
|
||||
a caso. Aggrega la trascrizione per categoria (byte per system prompt, output strumenti,
|
||||
messaggi) e taglia quello che pesa davvero.
|
||||
|
||||
```bash
|
||||
cd <progetto> && setsid konsole -e bash -lc \
|
||||
'cd <progetto> && exec pi --name "<nome breve>" "@<file-di-contesto>" "<primo task>"'
|
||||
```
|
||||
## 5. Iniezione di input
|
||||
|
||||
- Contesto iniziale: file di handover/prompt passati con `@file` (o `--append-system-prompt <file>`).
|
||||
- Aggiungere `--session-id <id-stabile>` se la sessione va ripresa in seguito.
|
||||
- **Non** usare `--mode rpc` se serve la TUI: il mode rpc *sostituisce* l'interfaccia
|
||||
terminale con un flusso JSONL su stdin/stdout.
|
||||
- **Sempre un `requestId` stabile**: un ritento torna `duplicate:true` invece di
|
||||
iniettare due volte.
|
||||
- **`409` = "aspetta", non "riprova"**: arriva quando la sessione è occupata (`busy`) o
|
||||
ha messaggi in coda (`pending`). Per accodare di proposito: `deliverAs`
|
||||
(`steer` corregge il turno in corso, `followUp` consegna dopo, `nextTurn` tiene per
|
||||
dopo) oppure `force:true`.
|
||||
- Un'iniezione **appare nella TUI come messaggio utente**: l'utente vede cosa accade.
|
||||
Questo è il motivo per cui si inietta *messaggi* e non si riscrive il system prompt.
|
||||
- Mailbox (`>> <id>.inbox`) per sessioni occupate o input lunghi.
|
||||
|
||||
## Elencare e ripulire
|
||||
## 6. Ciclo di vita
|
||||
|
||||
Il canale elenca da solo tutte le sessioni aperte, con porta e verdetto di
|
||||
sopravvivenza, tramite heartbeat (non serve piu' globare i file):
|
||||
- **Chiudere con `POST /shutdown`** (graceful: termina e rimuove il record). `kill <pid>`
|
||||
solo se il canale non risponde.
|
||||
- **`GET /sessions?prune=1` rimuove SOLO i morti** (heartbeat stantio > 30 s). Un
|
||||
heartbeat vecchio significa morta **anche se il processo esiste** (hang): `kill -0` da
|
||||
solo non lo distingue.
|
||||
- **Mai toccare sessioni che non sono tue.** Un record senza etichetta può essere di
|
||||
un'altra persona o di un altro lavoro in corso: si chiede, non si pota e non si uccide.
|
||||
Se una sessione è `busy` e non sai di chi sia, non toccarla **e dichiaralo**.
|
||||
|
||||
```bash
|
||||
curl -s -H "X-Pi-Token: $TOKEN" http://127.0.0.1:$PORT/sessions
|
||||
curl -s -H "X-Pi-Token: $TOKEN" "http://127.0.0.1:$PORT/sessions?prune=1" # rimuove solo i morti
|
||||
```
|
||||
## 7. Disciplina di lettura
|
||||
|
||||
Ogni record include `alive`, `pidAlive`, `heartbeatFresh` e `heartbeatAgeMs`.
|
||||
Un heartbeat piu' vecchio di 30 s significa sessione morta **anche se il processo
|
||||
esiste**: e' il caso che `kill -0` da solo non sa distinguere (processo vivo ma
|
||||
bloccato). La freschezza protegge una sessione appena avviata: non viene mai
|
||||
potata d'ufficio.
|
||||
La trascrizione JSONL cresce (sessioni reali: > 100k token). **Mai leggerla intera**:
|
||||
coda + filtro sui soli messaggi `assistant`, 1-3 messaggi, troncati. I `toolResult` si
|
||||
ignorano. Per lo stato si usa `/status`, non la trascrizione. Il **report** è la fonte
|
||||
che il sotto-agente deve tenere aggiornata: leggi quello.
|
||||
|
||||
Per terminare un sotto-agente usare **`POST /shutdown`** (chiusura *graceful*,
|
||||
che rimuove anche il record dal registry): `kill <pid>` resta solo come ultima
|
||||
risorsa se il canale non risponde.
|
||||
## 8. Trappole (tutte pagate almeno una volta)
|
||||
|
||||
```bash
|
||||
curl -s -X POST -H "X-Pi-Token: $TOKEN" http://127.0.0.1:$PORT/shutdown
|
||||
```
|
||||
1. **Dopo aver modificato l'estensione, una sessione già avviata esegue il CODICE
|
||||
VECCHIO** → riavviarla prima di testare. Sintomo diagnostico: due casi simili si
|
||||
comportano diversamente (possibile solo col codice precedente). Stessa classe della
|
||||
trappola `.glsl`/shader e delle build dir copiate.
|
||||
2. **`pkill -f "<pattern>"` uccide la propria shell** se il pattern compare nella command
|
||||
line stessa → terminare per **PID** letti dal registry.
|
||||
3. **`--mode rpc` sostituisce la TUI**: per TUI + controllo serve l'estensione, non rpc.
|
||||
4. **`@file` è rifiutato in rpc mode**: il contesto va iniettato con `--append-system-prompt`.
|
||||
5. **Il modello effettivo si verifica dalla trascrizione** (`model_change`), non da
|
||||
`/status` (che può non avere il modello) né dal comando di lancio: un agente può
|
||||
cambiare modello da sé o essere cambiato dalla TUI. I file di sessione hanno **nome in
|
||||
UTC**, non in ora locale.
|
||||
6. **`-r N` non è "N invocazioni"**: la dispersione si misura fra invocazioni separate.
|
||||
7. **I flag si verificano con `--help`**: `-c` non esiste in `llama-bench`, `-ckv` non
|
||||
esiste affatto. Due volte pagato.
|
||||
|
||||
## Leggere i risultati (disciplina obbligatoria)
|
||||
## 9. Economia della delega — cosa delegare e cosa pretendere
|
||||
|
||||
La trascrizione e' un JSONL in `~/.pi/agent/sessions/--<cwd-con-/-->--/<timestamp>_<id>.jsonl`.
|
||||
**Non leggere il file intero**: cresce in fretta (una sessione di lavoro reale ha
|
||||
superato i 500 KB). Leggere la coda e filtrare:
|
||||
- **Delega bene**: misurazioni ripetitive, esplorazioni con criterio, ottimizzazioni con
|
||||
un protocollo chiaro, ricerche su fonti esterne, manutenzione. **Delega male**: decisioni
|
||||
architetturali (le prendi tu), giudizi di priorità, e qualunque cosa richieda il
|
||||
contesto di tutta la sessione.
|
||||
- **Pretendi sempre**: (a) report aggiornato; (b) **dispersione, non numeri singoli**
|
||||
(media, deviazione, span su 3+ invocazioni); (c) **esiti negativi registrati**; (d)
|
||||
gate di correttezza **prima** della velocità; (e) una modifica alla volta; (f) nessun
|
||||
download e nessuna modifica di configurazione senza approvazione; (g) mai push su
|
||||
GitHub, solo su gitea.
|
||||
- **Giudica contro lo span misurato, non contro una soglia fissa**: la stessa baseline
|
||||
dava span 2,4% su una macchina e 0,2% su un'altra; e un candidato con span 5,98% ha
|
||||
ucciso un "+3,3%" che sembrava reale. Non scegliere lo span storico più stretto per
|
||||
rivendicare un guadagno: usa quello misurato adesso.
|
||||
- **Il valore non sta dove sembra**: su questa macchina la speculazione ha dato +42-148%,
|
||||
mentre il tetto della micro-ottimizzazione dei kernel era ~1,26×. Prima di delegare ore
|
||||
di tuning, chiedersi se esiste una leva strutturale (speculazione, architettura, MoE).
|
||||
|
||||
```bash
|
||||
F=<trascrizione>
|
||||
python3 - "$F" <<'PY'
|
||||
import json,sys
|
||||
msgs=[]
|
||||
for line in open(sys.argv[1]):
|
||||
try: d=json.loads(line)
|
||||
except Exception: continue
|
||||
m=d.get("message") or {}
|
||||
if d.get("type")=="message" and m.get("role")=="assistant":
|
||||
c=m.get("content")
|
||||
t=" ".join(x.get("text","") for x in c if isinstance(x,dict)) if isinstance(c,list) else str(c)
|
||||
if t.strip(): msgs.append(t)
|
||||
print("\n---\n".join(msgs[-2:])[:3000])
|
||||
PY
|
||||
```
|
||||
## 10. Errori tipici
|
||||
|
||||
Regole: solo i messaggi `assistant`, solo gli ultimi 1-3, troncati; i `toolResult`
|
||||
si ignorano (sono rumore per il supervisore). Per lo stato operativo usare `/status`,
|
||||
non il transcript.
|
||||
|
||||
## Best practice di interazione (v0.5)
|
||||
|
||||
1. **Prima di assegnare un nuovo task, leggi `/context`.** Se `percent` e' alto,
|
||||
compatta **prima** di iniettare il prompt successivo: una sessione lunga che
|
||||
va in overflow a meta' lavoro perde il filo e ti fa perdere il lavoro.
|
||||
2. **Ciclo di compattazione**: `POST /compact` (risposta 202, non bloccante) →
|
||||
attendi l'evento `compaction_done` (o `compaction_failed`) → poi `POST /wait`
|
||||
sul `settled` → **solo allora** inietti il prompt.
|
||||
`tokens` puo' risultare `null` subito dopo: significa "non ancora noto", non errore.
|
||||
3. **`fromExtension` distingue le compattazioni**: se e' `false` la compattazione
|
||||
e' arrivata da soglia automatica o da `/compact` dell'utente — non attribuirtela.
|
||||
4. **`steer` vs `abort`**: `steer` corregge la direzione lasciando lavorare;
|
||||
`abort` ferma l'operazione in corso. Usa `abort` quando il lavoro sta andando
|
||||
nella direzione sbagliata e vuoi ripartire da un contesto pulito.
|
||||
5. **Controlla `pending` prima di iniettare**: se ci sono messaggi gia' in coda,
|
||||
un altro input si accoda dietro invece di essere eseguito subito.
|
||||
6. **Termina con `/shutdown`**, non con `kill`: chiude in modo pulito e rimuove il
|
||||
record dal registry, quindi le liste restano veritiere.
|
||||
7. **Il contesto arriva dentro ogni risposta** (blocco `context`, con anche
|
||||
`lastResponse`: token di input/output dell'ultima risposta): non serve chiamare
|
||||
`/context` a parte — leggilo dal risultato di `/say` o di `/wait`.
|
||||
8. **`/say` rifiuta con 409 se c'e' gia' input in coda** (`pending`): per accodare
|
||||
di proposito servono `deliverAs` (steer/followUp/nextTurn) o `force:true`.
|
||||
Un 409 non e' un errore da ritentare: significa che devi prima attendere.
|
||||
7. **Una sola fonte di verita' per lo stato**: `/status` (stato + contesto) — non
|
||||
dedurre lo stato dalla trascrizione.
|
||||
|
||||
## Errori tipici
|
||||
|
||||
- **Modifica all'estensione + sessione gia' avviata = stai testando il codice vecchio.**
|
||||
La sessione carica l'estensione all'avvio: dopo un edit va **terminata e riavviata**,
|
||||
altrimenti la misura non riguarda la patch (stessa classe della trappola `.glsl` degli
|
||||
shader Vulkan). Sintomo tipico che lo smaschera: due casi simili si comportano
|
||||
diversamente, cosa possibile solo con il codice precedente.
|
||||
- **`pkill -f "<pattern>"` uccide la propria shell** se il pattern compare nella
|
||||
command line del comando stesso. Usare i PID (`kill <pid>`) letti dal registry.
|
||||
- Sessione occupata: `/say` inietta comunque (accodato); la mailbox e' la scelta
|
||||
sicura per input lunghi o multipli.
|
||||
- Se `/status` non risponde: la sessione non ha l'estensione caricata, oppure e'
|
||||
stata chiusa (voce stale nel registry).
|
||||
|
||||
## Ciclo di vita consigliato
|
||||
|
||||
1. Preparare il file di contesto del sotto-agente (obiettivo, vincoli, comandi, criterio di verifica).
|
||||
2. Avviarlo in una tab konsole con `@contesto` e il primo task.
|
||||
3. Supervisionare: `/status` per lo stato, mailbox o `/say` per correggere la rotta.
|
||||
4. Alla fine: leggere gli ultimi messaggi `assistant`, riportare all'utente, ripulire le voci stale.
|
||||
5. Se il lavoro produce modifiche al codice: **committare e pushare** prima di chiudere
|
||||
(un albero non versionato e' a rischio).
|
||||
- Attendere un tempo fisso invece di pollare il registry, o usare `turn_end` come "finito".
|
||||
- Compattare a contesto basso (costo) o durante il lavoro (interruzione).
|
||||
- Iniettare senza `requestId`, poi ritentare e iniettare due volte.
|
||||
- Interpretare un `409` come errore da ritentare.
|
||||
- Terminare con `kill` ciò che si poteva chiudere con `/shutdown`.
|
||||
- Toccare sessioni non proprie, o fidarsi di un record senza heartbeat.
|
||||
- Ricostruire lo stato leggendo la trascrizione invece del report che avevi imposto.
|
||||
|
||||
Reference in New Issue
Block a user