Compare commits
No commits in common. "0a4cd53b711e4b9ca2fba761c8effc65cc874b75" and "a7786aff305ba5c5689fceeed735056ce0cf75a0" have entirely different histories.
0a4cd53b71
...
a7786aff30
1 changed files with 0 additions and 430 deletions
|
|
@ -1,430 +0,0 @@
|
|||
# CLI Feature Probe — DisClaw
|
||||
|
||||
Manuelles Sanity-Check-Script für kritische Claude Code CLI-Annahmen.
|
||||
Muss vor Phase-2-Freigabe ausgeführt und ausgefüllt werden.
|
||||
|
||||
Stand: [Datum der letzten Ausführung]
|
||||
CLI-Version: [Ausgabe von `claude --version`]
|
||||
|
||||
---
|
||||
|
||||
## Kontext
|
||||
|
||||
Dieses Dokument deckt die vier Annahmen ab, die in `docs/cli-feature-answers.md`
|
||||
als "Unsicherheit: Mittel" oder "empirisch noch nicht bestätigt" markiert sind.
|
||||
Jede Probe muss in einer sauberen Shell-Session ausgeführt werden (keine
|
||||
gespeicherten Umgebungsvariablen aus vorherigen Probes).
|
||||
|
||||
Voraussetzungen:
|
||||
- `claude` ist auf PATH (oder `CLAUDE_PATH` zeigt auf die CLI)
|
||||
- `jq` ist installiert (`jq --version` gibt etwas aus)
|
||||
- `python3` ist installiert (nur für Probe 3, als Fallback-Pretty-Printer)
|
||||
- Aktiver Claude Pro/Max-Account (die CLI benötigt eine Subscription, keinen
|
||||
separaten API-Key)
|
||||
|
||||
---
|
||||
|
||||
## Probe 1: `session_id` Top-Level-Position und Stabilität über Resume
|
||||
|
||||
### Hypothese
|
||||
|
||||
Aus `cli-feature-answers.md` Abschnitt 2:
|
||||
|
||||
> "Die Session-ID liegt als Top-Level-Feld `session_id` im
|
||||
> `--output-format json`-Result. [...] Per Default bleibt die ID beim
|
||||
> `--resume` stabil — die Session wird in der existierenden JSONL
|
||||
> fortgeschrieben."
|
||||
|
||||
Wir nehmen also an:
|
||||
|
||||
1. Der erste `claude -p` Call gibt ein JSON-Objekt zurück, in dem `.session_id`
|
||||
direkt auf Top-Level liegt (nicht unter `.result.session_id` oder ähnlichem).
|
||||
2. Ein zweiter Call mit `--resume <id>` gibt dieselbe `session_id` zurück.
|
||||
|
||||
### Kommandos
|
||||
|
||||
```bash
|
||||
# Schritt 1: Erste Session starten und session_id extrahieren
|
||||
id1=$(claude -p "antworte mit dem wort ALPHA und sonst nichts" \
|
||||
--output-format json --bare \
|
||||
| tee /tmp/probe1-run1.json \
|
||||
| jq -r '.session_id')
|
||||
|
||||
echo "id1=$id1"
|
||||
|
||||
# Schritt 2: Session fortsetzen und id aus dem Response lesen
|
||||
id2=$(claude -p "antworte mit dem wort BETA und sonst nichts" \
|
||||
--resume "$id1" \
|
||||
--output-format json --bare \
|
||||
| tee /tmp/probe1-run2.json \
|
||||
| jq -r '.session_id')
|
||||
|
||||
echo "id2=$id2"
|
||||
|
||||
# Schritt 3: Vergleich
|
||||
if [ "$id1" = "$id2" ]; then
|
||||
echo "PASS: IDs sind gleich"
|
||||
else
|
||||
echo "ABWEICHUNG: id1=$id1 id2=$id2"
|
||||
fi
|
||||
|
||||
# Schritt 4: Komplettes JSON-Top-Level zur Orientierung
|
||||
echo "--- Top-Level-Felder Run 1 ---"
|
||||
jq 'keys' /tmp/probe1-run1.json
|
||||
|
||||
echo "--- Top-Level-Felder Run 2 ---"
|
||||
jq 'keys' /tmp/probe1-run2.json
|
||||
```
|
||||
|
||||
### Erwartete Ausgabe
|
||||
|
||||
```
|
||||
id1=<uuid>
|
||||
id2=<uuid> ← gleiche UUID wie id1
|
||||
PASS: IDs sind gleich
|
||||
--- Top-Level-Felder Run 1 ---
|
||||
[
|
||||
"result",
|
||||
"session_id",
|
||||
"type",
|
||||
...
|
||||
]
|
||||
--- Top-Level-Felder Run 2 ---
|
||||
[
|
||||
"result",
|
||||
"session_id",
|
||||
"type",
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
`session_id` erscheint direkt in `keys` (Top-Level), nicht nur tief im Baum.
|
||||
Die UUID ist in beiden Runs identisch.
|
||||
|
||||
### Tatsächliche Ausgabe
|
||||
|
||||
```
|
||||
[NOCH NICHT AUSGEFÜLLT — Bitte vor Phase-2-Freigabe ausfüllen]
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
- [ ] Verifiziert
|
||||
- [ ] Abweichung gefunden:
|
||||
|
||||
### Notizen
|
||||
|
||||
Falls `id2 != id1`: Defensiv-Strategie aus `cli-feature-answers.md` Abschnitt 2
|
||||
ist relevant — nach jedem Run die `session_id` aus dem Response-JSON lesen und
|
||||
in der DB aktualisieren, unabhängig davon ob sie sich geändert hat.
|
||||
|
||||
Falls `.session_id` nicht auf Top-Level liegt: `jq 'path(.. | strings |
|
||||
select(test("^[0-9a-f-]{36}$")))' /tmp/probe1-run1.json` zeigt den tatsächlichen
|
||||
Pfad.
|
||||
|
||||
---
|
||||
|
||||
## Probe 2: `--resume` Flow — Kontext-Kontinuität
|
||||
|
||||
### Hypothese
|
||||
|
||||
Aus `cli-feature-answers.md` Abschnitt 1:
|
||||
|
||||
> "`claude -p "<neue-msg>" --resume <session-id> --output-format json` lädt die
|
||||
> existierende Session und hängt `<neue-msg>` als neuen User-Turn an."
|
||||
|
||||
Wir nehmen an:
|
||||
|
||||
1. Claude "erinnert" sich nach einem `--resume` an den Inhalt der vorherigen
|
||||
Turns dieser Session.
|
||||
2. Der `--resume`-Call schlägt nicht stillschweigend fehl (z. B. mit einer leeren
|
||||
Antwort oder einer neuen, unverbundenen Session), wenn die `session_id` gültig
|
||||
ist.
|
||||
3. Das Muster `--resume "$session_id" --output-format json --bare` ist ohne
|
||||
weitere Flags ausführbar (kein `--verbose` o. ä. erforderlich).
|
||||
|
||||
### Kommandos
|
||||
|
||||
```bash
|
||||
# Schritt 1: Session mit einem Geheimnis starten
|
||||
run1=$(claude -p "Merke dir folgendes Codewort für diese Session: XYLOPHON42. Bestätige nur mit OK." \
|
||||
--output-format json --bare)
|
||||
|
||||
sid=$(echo "$run1" | jq -r '.session_id')
|
||||
echo "session_id=$sid"
|
||||
echo "Antwort Run 1: $(echo "$run1" | jq -r '.result')"
|
||||
|
||||
# Schritt 2: In derselben Session das Geheimnis abfragen
|
||||
run2=$(claude -p "Was war das Codewort, das du dir gemerkt hast?" \
|
||||
--resume "$sid" \
|
||||
--output-format json --bare)
|
||||
|
||||
echo "Antwort Run 2: $(echo "$run2" | jq -r '.result')"
|
||||
|
||||
# Schritt 3: Prüfen ob das Codewort im Response vorkommt
|
||||
if echo "$run2" | jq -r '.result' | grep -q "XYLOPHON42"; then
|
||||
echo "PASS: Codewort in Antwort gefunden"
|
||||
else
|
||||
echo "ABWEICHUNG: Codewort fehlt in der Antwort"
|
||||
fi
|
||||
```
|
||||
|
||||
### Erwartete Ausgabe
|
||||
|
||||
```
|
||||
session_id=<uuid>
|
||||
Antwort Run 1: OK
|
||||
Antwort Run 2: Das Codewort war XYLOPHON42.
|
||||
PASS: Codewort in Antwort gefunden
|
||||
```
|
||||
|
||||
### Tatsächliche Ausgabe
|
||||
|
||||
```
|
||||
[NOCH NICHT AUSGEFÜLLT — Bitte vor Phase-2-Freigabe ausfüllen]
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
- [ ] Verifiziert
|
||||
- [ ] Abweichung gefunden:
|
||||
|
||||
### Notizen
|
||||
|
||||
Falls das Codewort fehlt: Prüfe ob `--resume` die richtige Session lädt.
|
||||
`ls ~/.claude/projects/` zeigt alle gespeicherten Projekt-Slugs. Das Verzeichnis
|
||||
für den aktuellen cwd hat den Slug `<cwd-Pfad-mit-Bindestrichen>`.
|
||||
|
||||
Falls `--resume` + `--output-format json` + `--bare` zusammen einen Exit-Code
|
||||
ungleich 0 erzeugen: Flags einzeln testen, um die Inkompatibilität einzugrenzen.
|
||||
|
||||
---
|
||||
|
||||
## Probe 3: `stream-json` Event-Typen
|
||||
|
||||
### Hypothese
|
||||
|
||||
Aus `cli-feature-answers.md` Abschnitt 4:
|
||||
|
||||
> "Relevante Typen: `system`, `assistant`, `user`, `stream_event`, `result`."
|
||||
> "Text-Deltas landen unter `.event.delta.type == "text_delta"` mit `.event.delta.text`."
|
||||
> "Für `stream-json` müssen praktisch immer `--verbose` und
|
||||
> `--include-partial-messages` mitgegeben werden, sonst gibt es keine
|
||||
> Text-Deltas, nur den Final-`result`-Block."
|
||||
|
||||
Wir nehmen an:
|
||||
|
||||
1. Mit `--output-format stream-json --verbose --include-partial-messages` erscheinen
|
||||
tatsächlich Zeilen mit `"type":"stream_event"` im Output.
|
||||
2. Mindestens ein `stream_event` hat `.event.delta.type == "text_delta"` mit einem
|
||||
nicht-leeren `.event.delta.text`.
|
||||
3. Die letzte (oder eine der letzten) Zeilen hat `"type":"result"`.
|
||||
4. Ohne `--include-partial-messages` erscheint nur `"type":"result"` (keine
|
||||
`stream_event`-Zeilen).
|
||||
|
||||
### Kommandos
|
||||
|
||||
```bash
|
||||
# Schritt 1: Stream MIT partial messages — alle Event-Typen anzeigen
|
||||
echo "=== MIT --include-partial-messages ==="
|
||||
claude -p "schreibe genau drei Saetze ueber den Mond" \
|
||||
--output-format stream-json \
|
||||
--verbose \
|
||||
--include-partial-messages \
|
||||
--bare \
|
||||
| tee /tmp/probe3-stream.ndjson \
|
||||
| jq -c '{type, subtype: .subtype?, event_type: .event.type?, delta_type: .event.delta.type?}'
|
||||
|
||||
# Schritt 2: Welche type-Werte kommen vor?
|
||||
echo "=== Vorkommende type-Werte ==="
|
||||
jq -r '.type' /tmp/probe3-stream.ndjson | sort | uniq -c | sort -rn
|
||||
|
||||
# Schritt 3: Einen text_delta-Block vollständig anzeigen
|
||||
echo "=== Erster text_delta-Block ==="
|
||||
jq -c 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | {type, text: .event.delta.text}' \
|
||||
/tmp/probe3-stream.ndjson | head -3
|
||||
|
||||
# Schritt 4: Stream OHNE partial messages zum Vergleich
|
||||
echo "=== OHNE --include-partial-messages ==="
|
||||
claude -p "antworte mit einem einzigen Wort: HALLO" \
|
||||
--output-format stream-json \
|
||||
--verbose \
|
||||
--bare \
|
||||
| jq -c '.type'
|
||||
```
|
||||
|
||||
### Erwartete Ausgabe
|
||||
|
||||
```
|
||||
=== MIT --include-partial-messages ===
|
||||
{"type":"system","subtype":"init","event_type":null,"delta_type":null}
|
||||
{"type":"stream_event","subtype":null,"event_type":"content_block_delta","delta_type":"text_delta"}
|
||||
... (mehrere text_delta-Zeilen)
|
||||
{"type":"result","subtype":null,"event_type":null,"delta_type":null}
|
||||
|
||||
=== Vorkommende type-Werte ===
|
||||
42 stream_event
|
||||
3 assistant
|
||||
2 user
|
||||
1 system
|
||||
1 result
|
||||
|
||||
=== Erster text_delta-Block ===
|
||||
{"type":"stream_event","text":"Der "}
|
||||
{"type":"stream_event","text":"Mond "}
|
||||
{"type":"stream_event","text":"ist "}
|
||||
|
||||
=== OHNE --include-partial-messages ===
|
||||
"system"
|
||||
"result"
|
||||
```
|
||||
|
||||
### Tatsächliche Ausgabe
|
||||
|
||||
```
|
||||
[NOCH NICHT AUSGEFÜLLT — Bitte vor Phase-2-Freigabe ausfüllen]
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
- [ ] Verifiziert
|
||||
- [ ] Abweichung gefunden:
|
||||
|
||||
### Notizen
|
||||
|
||||
Falls neue, unbekannte `type`-Werte auftauchen: In die Tabelle eintragen.
|
||||
Der DisClaw-Parser in Phase 5 (`src/agent/runner.ts`) muss unknown types
|
||||
silently skippen statt zu crashen.
|
||||
|
||||
Falls `stream_event` fehlt auch mit `--include-partial-messages`: Prüfe die
|
||||
CLI-Version. Möglicherweise ist der Flag in der installierten Version noch
|
||||
nicht vorhanden. `claude --help | grep partial` prüft das.
|
||||
|
||||
Falls das Feld-Layout der Text-Deltas abweicht: Den tatsächlichen Pfad mit
|
||||
`jq 'select(.type == "stream_event") | paths' /tmp/probe3-stream.ndjson | head -20`
|
||||
ermitteln und hier dokumentieren.
|
||||
|
||||
---
|
||||
|
||||
## Probe 4: `usage`-Block Pfade im JSON-Output
|
||||
|
||||
### Hypothese
|
||||
|
||||
Aus `cli-feature-answers.md` Abschnitt 7:
|
||||
|
||||
> "Der `--output-format json`-Response enthält einen `usage`-Block nach
|
||||
> Anthropic-API-Format mit `cache_read_input_tokens`, `cache_creation_input_tokens`,
|
||||
> `input_tokens`, `output_tokens`."
|
||||
> "Die **genauen JSON-Pfade** sollten aber empirisch geprüft werden —
|
||||
> wahrscheinlich `result.usage.cache_read_input_tokens` oder top-level
|
||||
> `usage.cache_read_input_tokens`."
|
||||
|
||||
Wir nehmen an:
|
||||
|
||||
1. Der `usage`-Block ist im JSON-Output vorhanden (irgendwo im Baum).
|
||||
2. Er enthält mindestens die Felder `input_tokens` und `output_tokens`.
|
||||
3. Nach einem `--resume`-Call (zweiter Turn) erscheint `cache_read_input_tokens`
|
||||
mit einem Wert größer 0.
|
||||
|
||||
### Kommandos
|
||||
|
||||
```bash
|
||||
# Schritt 1: Ersten Run durchführen und usage-Struktur suchen
|
||||
echo "=== usage-Struktur im ersten Run ==="
|
||||
run1=$(claude -p "erklaere in drei saetzen was eine linked list ist" \
|
||||
--output-format json --bare)
|
||||
|
||||
echo "$run1" | tee /tmp/probe4-run1.json | python3 -m json.tool
|
||||
|
||||
# Schritt 2: Alle Pfade finden die "token" enthalten
|
||||
echo "=== Pfade mit 'token' im Namen ==="
|
||||
jq '[path(.. | numbers?) | select(. | map(tostring) | join(".") | test("token"; "i"))]' \
|
||||
/tmp/probe4-run1.json
|
||||
|
||||
# Schritt 3: usage direkt ansprechen (alle möglichen Pfade testen)
|
||||
echo "=== usage top-level ==="
|
||||
jq '.usage // "NICHT VORHANDEN"' /tmp/probe4-run1.json
|
||||
|
||||
echo "=== result.usage ==="
|
||||
jq '.result.usage // "NICHT VORHANDEN"' /tmp/probe4-run1.json
|
||||
|
||||
# Schritt 4: Zweiten Run mit Resume — cache_read prüfen
|
||||
sid=$(jq -r '.session_id' /tmp/probe4-run1.json)
|
||||
echo "=== usage im Resume-Run (cache_read erwartet) ==="
|
||||
claude -p "fasse deine Erklaerung in einem Satz zusammen" \
|
||||
--resume "$sid" \
|
||||
--output-format json --bare \
|
||||
| tee /tmp/probe4-run2.json \
|
||||
| jq '.usage // .result.usage // "usage nicht gefunden"'
|
||||
|
||||
# Schritt 5: cache_read_input_tokens im zweiten Run prüfen
|
||||
echo "=== cache_read_input_tokens in Run 2 ==="
|
||||
jq '(.usage // .result.usage).cache_read_input_tokens // "FELD FEHLT"' \
|
||||
/tmp/probe4-run2.json
|
||||
```
|
||||
|
||||
### Erwartete Ausgabe
|
||||
|
||||
```
|
||||
=== usage top-level ===
|
||||
{
|
||||
"input_tokens": 42,
|
||||
"output_tokens": 87,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0
|
||||
}
|
||||
|
||||
=== result.usage ===
|
||||
"NICHT VORHANDEN" ← oder vice versa, je nach tatsächlichem Pfad
|
||||
|
||||
=== usage im Resume-Run (cache_read erwartet) ===
|
||||
{
|
||||
"input_tokens": 12,
|
||||
"output_tokens": 23,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 412 ← größer 0 beim Resume
|
||||
}
|
||||
|
||||
=== cache_read_input_tokens in Run 2 ===
|
||||
412
|
||||
```
|
||||
|
||||
### Tatsächliche Ausgabe
|
||||
|
||||
```
|
||||
[NOCH NICHT AUSGEFÜLLT — Bitte vor Phase-2-Freigabe ausfüllen]
|
||||
```
|
||||
|
||||
### Status
|
||||
|
||||
- [ ] Verifiziert
|
||||
- [ ] Abweichung gefunden:
|
||||
|
||||
### Notizen
|
||||
|
||||
Falls `cache_read_input_tokens` auch im zweiten Run 0 ist: Das deutet darauf
|
||||
hin, dass Prompt-Caching für kurze Prompts nicht greift (Anthropic cached erst
|
||||
ab ca. 1024 Tokens). Mit einem längeren Prompt testen oder nach mehreren
|
||||
Turns prüfen.
|
||||
|
||||
Falls der `usage`-Block gar nicht vorhanden ist: Das wäre ein signifikantes
|
||||
Problem für Phase 4/5 (Token-Stats pro Turn). Als Fallback: `null` in der
|
||||
`agent_runs`-Tabelle tolerieren.
|
||||
|
||||
Tatsächlichen Pfad hier eintragen und in `src/agent/runner.ts` als Konstante
|
||||
definieren, damit er genau einmal im Code steht und leicht geändert werden kann.
|
||||
|
||||
---
|
||||
|
||||
## Ausfüll-Checkliste
|
||||
|
||||
| Probe | Ausgeführt von | Datum | Status |
|
||||
|-------|---------------|-------|--------|
|
||||
| 1: session_id Top-Level | | | [ ] |
|
||||
| 2: --resume Flow | | | [ ] |
|
||||
| 3: stream-json Events | | | [ ] |
|
||||
| 4: usage-Block Pfade | | | [ ] |
|
||||
|
||||
Alle vier Probes müssen den Status "Verifiziert" tragen, bevor Phase 2
|
||||
(Session-Resume-Implementation) als freigegeben gilt. Abweichungen müssen
|
||||
vor dem Phase-2-Start in `docs/cli-feature-answers.md` nachgezogen werden.
|
||||
Loading…
Reference in a new issue