cb3fa143fb
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
169 lines
7.9 KiB
Markdown
169 lines
7.9 KiB
Markdown
# AP-A Token-Tracking Fundament – Zusammenfassung
|
||
|
||
Dieses Dokument fasst alle Klassen, Methoden und Dateien zusammen, die im Zuge
|
||
von AP-A (Token- und Kosten-Tracking-Fundament der V3.3-Spezifikation, #74)
|
||
neu erstellt oder substanziell erweitert wurden.
|
||
|
||
## Schema-Migration
|
||
|
||
- `pdf-umbenenner-adapter-out/src/main/resources/db/migration/V2__token_tracking.sql`
|
||
- Sechs neue Spalten in `processing_attempt`:
|
||
`input_tokens`, `output_tokens`,
|
||
`cache_creation_input_tokens`, `cache_read_input_tokens`,
|
||
`price_input_per_token_nano_usd`, `price_output_per_token_nano_usd`.
|
||
- Neue Tabelle `model_price` mit Composite Primary Key
|
||
`(provider, model_name)`, NOT-NULL-Preisen, Currency-CHECK auf `'USD'`,
|
||
`updated_at`-Spalte.
|
||
- Zwei zusätzliche Indizes auf `processing_attempt`:
|
||
`idx_processing_attempt_started_at_provider_fp_model`,
|
||
`idx_processing_attempt_run_id_provider_model`.
|
||
- Default-Preise für gpt-4o-mini, gpt-4o, gpt-4.1*, gpt-5*, claude-haiku-4-5,
|
||
claude-sonnet-4-6 und claude-opus-4-7 (`ON CONFLICT DO NOTHING`).
|
||
|
||
## Application-Modul
|
||
|
||
### DTOs (`application/dto`)
|
||
- `AiUsageMetadata` – Token-Verbrauchsmetadaten mit `empty()`,
|
||
`hasAnyTokenData()`, `hasCacheTokens()`.
|
||
- `ModelPriceEntry` – Schreib-/Validierungs-DTO mit Wertgrenzen-Validierung im
|
||
Konstruktor.
|
||
- `ModelPriceView` – Lese-/Anzeige-DTO mit nullable `updatedAt` und
|
||
`invalidUpdatedAt`-Flag.
|
||
- `ModelPriceKey` – Composite-Key für Löschungen.
|
||
- `ModelPriceChangeSet` – atomarer Block aus Upserts und Deletions, defensive
|
||
Listen-Kopie.
|
||
|
||
### Cost-Komponenten (`application/cost`)
|
||
- `CostResult` – interpretierte Kosten-Anzeige mit Status-Flags.
|
||
- `CostCalculator` – `formatRow(...)` und `calculateAttempt(...)` (echt
|
||
implementiert), `formatTotal(...)` als Stub für AP-B.
|
||
|
||
### Ports (`application/port/out`)
|
||
- `ModelPriceRepository` – `findAll`, `findByProviderAndModelName`, `upsert`,
|
||
`delete`, `saveAllChanges`.
|
||
- `AiInvocationSuccess` (erweitert) – neues Feld `usageMetadata`.
|
||
|
||
### Use Cases (`application/usecase`)
|
||
- `DefaultManageModelPricesUseCase` – CRUD-Fassade mit ChangeSet-Konflikt-
|
||
validierung (vier Regeln) und Provider-Whitelist beim Upsert.
|
||
- `ModelPriceValidationException` – deutsche Validierungsfehler-Exception.
|
||
|
||
### Application-Service-Anpassungen
|
||
- `AiNamingService` (erweitert) – reicht `AiUsageMetadata` aus dem
|
||
`AiInvocationSuccess` als Token-Felder in den `AiAttemptContext` weiter.
|
||
- `DocumentProcessingCoordinator` (erweitert) –
|
||
- neuer optionaler Konstruktor mit `ModelPriceRepository` und
|
||
`headlessMode`-Flag.
|
||
- `loadPriceSnapshot(modelName)` lädt Snapshot-Preis pro Versuch; Lookup-
|
||
Fehler liefern leeren Snapshot ohne Attempt-Verlust.
|
||
- `buildAttempt(...)` befüllt jetzt Token- und Preis-Snapshot-Felder im
|
||
`ProcessingAttempt`.
|
||
|
||
### Domain-Anpassungen
|
||
- `AiAttemptContext` (erweitert) – vier nullable Token-Felder
|
||
(`inputTokens`, `outputTokens`, `cacheCreationInputTokens`,
|
||
`cacheReadInputTokens`); Backward-compatible Convenience-Konstruktor.
|
||
- `ProcessingAttempt` (erweitert) – sechs nullable Token-/Preis-Snapshot-
|
||
Felder; Convenience-Konstruktor und `withoutAiFields(...)` ohne Verhaltens-
|
||
änderung.
|
||
|
||
## Adapter-Out-Modul
|
||
|
||
- `SqliteConnectionFactory` (neu) – zentrale Connection-Factory; setzt
|
||
`PRAGMA journal_mode=WAL` und `PRAGMA busy_timeout=5000`.
|
||
Foreign-Key-Pragma wird bewusst nicht implizit gesetzt (Verhalten der
|
||
bisherigen `DriverManager.getConnection`-Stellen erhalten).
|
||
- `SqliteUnitOfWorkAdapter`, `SqliteProcessingAttemptRepositoryAdapter`,
|
||
`SqliteHistoryQueryAdapter`, `SqliteDocumentRecordRepositoryAdapter`
|
||
(jeweils geändert) – nutzen die neue Factory.
|
||
- `SqliteProcessingAttemptRepositoryAdapter.save()` (erweitert) –
|
||
INSERT um sechs neue Spalten erweitert, neue Hilfsmethode
|
||
`setNullableLong(...)`.
|
||
- `SqliteHistoryQueryAdapter.mapToProcessingAttempt(...)` (erweitert) –
|
||
liest die sechs neuen Spalten via `readNullableLong(...)`.
|
||
- `SqliteSchemaInitializationAdapter` (geändert) – erwartete Spalten/Indizes
|
||
bleiben am V1-Zielschema; Doc-Klarstellung, dass V2 additiv auf der Baseline
|
||
arbeitet.
|
||
- `SqliteModelPriceRepositoryAdapter` (neu) – `findAll`,
|
||
`findByProviderAndModelName`, `upsert`, `delete`, `saveAllChanges`
|
||
(UPSERT via `ON CONFLICT(provider, model_name) DO UPDATE`, transaktionaler
|
||
Batch). Lese-Mapping behandelt `DateTimeParseException` als
|
||
`invalidUpdatedAt`.
|
||
- `ModelPriceRepositoryException` (neu) – technischer JDBC-Fehler.
|
||
|
||
### KI-Adapter
|
||
- `AnthropicClaudeHttpAdapter` (geändert) – neue Methode
|
||
`extractTokenUsageFromResponse(JSONObject)` für `usage.input_tokens`,
|
||
`usage.output_tokens`, `usage.cache_creation_input_tokens`,
|
||
`usage.cache_read_input_tokens` mit Validierung (negativ, > 10 Mio.,
|
||
nicht-numerisch → NULL + WARN).
|
||
- `OpenAiHttpAdapter` (geändert) – analoge Methode mit Mapping
|
||
`prompt_tokens → input_tokens`, `completion_tokens → output_tokens`;
|
||
Cache-Felder bleiben null.
|
||
|
||
## GUI-Modul
|
||
|
||
### Neuer Tab "Modell-Preise"
|
||
- `adapter-in-gui/modelprices/GuiModelPriceManagementPort` (neu) –
|
||
Bridge-Port für GUI-Zugriff auf Modell-Preise.
|
||
- `adapter-in-gui/modelprices/GuiModelPricesTab` (neu) – TableView mit
|
||
editierbaren Preisspalten (`In/1M USD`, `Out/1M USD`), Lösch-Button mit
|
||
Bestätigungsdialog, Add-Dialog mit Provider-Auswahl, Speichern-Aktion über
|
||
`ModelPriceChangeSet`. Konvertierung Nano-USD ↔ `$/1M Tokens` mit
|
||
HALF-UP-Rundung; unbekannte Provider werden read-only mit Tooltip
|
||
angezeigt; `updatedAt = null` als "ungueltig".
|
||
|
||
### Anbindung im Workspace
|
||
- `GuiConfigurationEditorWorkspace` (geändert) – sechster Tab "Modell-
|
||
Preise" wird angelegt; neue Methode `warnIfActiveModelHasNoPriceEntry()`
|
||
zeigt vor dem Speichern eine deutsche Warnung an, wenn das aktuell
|
||
ausgewählte Modell keinen Preis-Eintrag besitzt.
|
||
- `GuiStartupContext` (geändert) – neues optionales Feld
|
||
`modelPriceManagementPort` mit Backward-Kompatibilität.
|
||
- `BootstrapRunner` (geändert) – neue Methode
|
||
`buildGuiModelPriceManagementPort()` und Helfer für die Verdrahtung;
|
||
Coordinator wird mit `ModelPriceRepository` und `headlessMode`-Flag
|
||
versorgt.
|
||
|
||
### History-Tab
|
||
- `GuiHistoryTab` (geändert) – drei zusätzliche Spalten in der
|
||
Versuchstabelle: Input-Tokens, Output-Tokens, Kosten. Cache-only-Versuche
|
||
zeigen "nur Cache-Tokens, keine Standardkosten"; fehlender Preis-Snapshot
|
||
führt zu "Preis fehlt"; Mikrobeträge als "< $0.0001"; Cache-Beteiligung
|
||
ergänzt Suffix "(ohne Cache-Anteil)".
|
||
|
||
### Summary-Banner
|
||
- `BatchRunSummaryBanner` (geändert) – aus einzeiliger HBox wurde eine
|
||
vierzeilige VBox: Status-Zeile, Token-Zeile, Kosten-Zeile, optionale
|
||
Cache-only-Zeile. Neue Record-Klasse `BatchRunTokenSummary` mit
|
||
`empty()`-Default; bestehende `update(Map)`-Aufrufer bleiben funktionsfähig.
|
||
|
||
## Testanpassungen
|
||
|
||
- `pdf-umbenenner-application/.../service/AiNamingServiceTest` und
|
||
`pdf-umbenenner-bootstrap/.../e2e/StubAiInvocationPort` – alte
|
||
`AiInvocationSuccess`-Konstruktoraufrufe um `AiUsageMetadata.empty()`
|
||
ergänzt.
|
||
- `SqliteSchemaInitializationAdapterTest.fall1_leereDb_processingAttemptHatAlleErwartetenSpalten`
|
||
prüft jetzt zusätzlich die sechs Token-/Preis-Spalten.
|
||
- `GuiAdapterSmokeTest.editorWorkspace_startStateShowsEmptyHeaderDefaultsAndOneTab`
|
||
erwartet jetzt sechs Tabs inkl. "Modell-Preise".
|
||
|
||
## Build und Verifizierung
|
||
|
||
- `mvn clean verify` läuft auf dem Reactor `pdf-umbenenner-parent` durch
|
||
(Tests grün auf allen Modulen).
|
||
- Commit `08ec021` auf `main` gepusht.
|
||
|
||
## Bewusst ausgesparte Bereiche (für AP-B / AP-C)
|
||
|
||
- `CostCalculator.formatTotal(...)` ist ein Stub und wirft
|
||
`UnsupportedOperationException`.
|
||
- `TokenStatisticsReadModelPort`, `QueryCostAnalysisFullUseCase`,
|
||
`QueryCostAnalysisHeaderOnlyUseCase`, `QueryRunSummaryUseCase`,
|
||
`SqliteTokenStatisticsReadModelAdapter` sind nicht enthalten.
|
||
- Summary-Banner zeigt aktuell `0/0` Tokens und `$0.0000` Kosten, da das
|
||
Read-Model erst in AP-B verdrahtet wird.
|
||
- CLI-Befehle für Modell-Preise (#99) und Modell-Combobox-Filter (#98)
|
||
sind AP-C.
|