Pro Quelle ein Feld sources.fetch_strategy (default | googlebot | paywall | skip):
- default: normaler UA, Retry mit Googlebot bei 403/406/429.
- googlebot: direkt mit Googlebot-UA (fuer SEO-freundliche Sites).
- paywall: Anfrage via removepaywalls.com (fuer Spiegel+/SZ+/FT etc.).
- skip: Health-Check ueberspringen (bekannte unerreichbare Quellen wie Login-only).
Pre-Flagging in der Migration: FT/WSJ/NZZ/Handelsblatt/WiWo -> paywall,
Rheinische Post/Verfassungsschutz -> googlebot.
(Test mit den vier prominent fehlerhaften Quellen zeigt: FT/RP/Verfassungsschutz
sind besonders streng, gehen auch nicht ueber Googlebot/removepaywalls durch.
Fuer milder restriktive Quellen wirkt der Retry-Mechanismus.)
Telegram-Quellen mit url=t.me/kanal (ohne https:// Prefix) liessen httpx
mit "ValueError: unknown url type" crashen. Fix: vor dem Request
https:// vorne anhaengen wenn kein Schema vorhanden ist.
Beobachtet auf Live: 110 Health-Errors, davon einige Telegram-Kanaele
mit "ValueError: unknown url type:" als Fehlermeldung.
Phase 2 hatte die Verbesserungen nur in der Verwaltung
(src/shared/services/source_health.py). Der Daily-Health-Check laeuft aber
im Monitor-Backend (Cron 04:00 UTC) und nutzte deshalb weiter den alten
Code - Folge:
- Tenant-Quellen wurden NIE gecheckt (0 Eintraege in source_health_checks
fuer tenant_id IS NOT NULL).
- source_health_history blieb leer.
Diese Aenderung holt die Phase-2-Logik in den Monitor:
- services/source_health.py: Verwaltung-Version 1:1 uebernommen
(tenant_id-Filter weg + History-Save vor DELETE + UA/Timeout aus config).
- config.py: HEALTH_CHECK_USER_AGENT + HEALTH_CHECK_TIMEOUT_S ergaenzt.
Manueller Test auf Staging-Monitor:
283 Quellen geprueft, 253 Issues, 61 davon Tenant-Quellen.
History 0 -> 458 Eintraege.
Damit ist die shared/-LOCKED-FILES-Markierung in der Verwaltung obsolet -
beide Repos haben jetzt den gleichen Code.
Beim Anlegen einer neuen Lage ist der Schalter "Internationale Quellen einbeziehen"
ab jetzt standardmaessig DEAKTIVIERT.
Hintergrund: Bei lokalen DACH-Ereignissen (Tier-/Personenstoryen wie
"Buckelwal timmy") hat der "international=True"-Default zu schlechteren
Treffern gefuehrt, weil Claude in Deutsch UND Englisch suchte und die
englische Berichterstattung haeufig fehlt. Excluded-Sources- und
Boulevard-Filter haben das Problem zusaetzlich verschaerft.
Aenderungen:
- src/models.py IncidentCreate.international_sources: bool=True -> False
(nur das Pydantic-Default beim Create-Endpoint - IncidentResponse/Incident
bleiben True, weil das die DB-Werte bestehender Lagen reflektiert)
- src/static/dashboard.html: <input id="inc-international" checked> -> ohne checked
(UI-Default ist jetzt unchecked, User muss bewusst aktivieren fuer
internationale Lagen)
- Tooltip-Text ergaenzt: "Deaktiviert (Standard): ... empfohlen fuer DACH-Lagen."
Bestandslagen sind nicht betroffen - DB-Schema-Default INTEGER DEFAULT 1
bleibt unveraendert, fuer alle existierenden Lagen behaelt international
seinen aktuellen Wert.
Damit ist die Buckelwal-Diagnose komplett geloest:
- Bug 1 (rss_parser min_matches adaptiv) seit a08df3d auf main
- Bug 2 (Eigennamen-Pflicht-Keywords) seit e83f80d auf main
- Bug 3 (international-Default) jetzt auf develop, gleich Cherry-pick auf main
KEYWORD_EXTRACTION_PROMPT explizit erweitert:
- Eigennamen/Tiernamen/Personennamen aus dem THEMA als ZWINGEND markiert.
- Hinweis dass DE und EN identisch sein duerfen (Eigennamen).
- Klar gesagt: bei spezifischen Begriffen (>=7 Zeichen) reicht 1 Treffer in
RSS-Headlines (passt zu rss_parser.py adaptive Schwelle aus a08df3d).
Code-Post-Processing (researcher.py _extract_keywords):
- Nach dem Parser werden Lagentitel-Woerter (>=4 Zeichen, nicht in Stopwords)
ggf. in die Keyword-Liste injiziert, falls Haiku sie weggelassen hat.
- Verhindert konkret den "Buckelwal timmy"-Bug: "timmy" fehlte in Haikus
Liste, damit fielen Headlines mit nur "Buckelwal" durch das min_matches.
Hintergrund: Memory-Eintrag rss_match_und_keyword_bug.md, Bug 2 von 3.
Bug 1 (rss_parser min_matches adaptiv) ist seit Commit a08df3d auf Live.
Bug 3 (international=True default) bleibt offen, ist primaer UX-Frage.
Beide Files hatten Doppel-Encoded UTF-8 in Docstrings, Kommentaren und
Prompt-Strings (z.B. "prüft" statt "prüft", "Vorschläge" statt
"Vorschläge"). ftfy hat das automatisch repariert.
Hauptauswirkungen:
- Logs sind jetzt mit echten Umlauten lesbar
- Claude/Haiku-Prompts in source_suggester.py (Quellen-Vorschlaege via KI)
bekommen jetzt korrekte deutsche Umlaute - sollte bessere Antworten geben
Daneben hat ftfy line-endings normalisiert, daher der grosse Diff in
source_health.py - inhaltlich nur Mojibake-Reparatur.
Verifiziert mit:
grep -cE "ä|ö|ü|ß|Ä|Ö|Ü" src/services/*.py
-> 0 Treffer
Beim User-Cancel wurde nur refresh_log auf cancelled gesetzt, der zuletzt
aktive refresh_pipeline_steps-Eintrag blieb verwaist. Der
/api/incidents/<id>/pipeline-Endpoint liefert daraus dauerhaft
"Schritt X laeuft" an die UI, auch lange nach dem Cancel.
- pipeline_tracker.cancel_active_steps(): neuer Bulk-Helper, setzt alle
noch active-Schritte eines refresh_log_id auf cancelled mit completed_at
- _mark_refresh_cancelled holt die refresh_log_id, macht das refresh_log-
Update wie bisher und ruft danach cancel_active_steps auf
Reproduziert bei Lage 80 (Bjoern Hoecke), refresh_log 1273. Frontend-
CSS kennt status-cancelled nicht, faellt auf den neutralen Default-Style
zurueck (kein Spinner mehr, kein Haken, korrekt ent-hangen).
Ueber die ENV-Variable TRANSLATOR_ENABLED (default true) kann der
Translator-Agent komplett deaktiviert werden. Wenn false:
- translate_articles steigt mit return [] aus, ohne Claude-Calls
- Fremdsprachige Artikel bleiben unuebersetzt (headline_de/content_de NULL)
Hintergrund: Bei Lage 6 Irankonflikt sind 10.210 Artikel ohne DE-Uebersetzung
aufgelaufen. Pro Refresh werden 2042 Batches sequentiell gestreamt
(~25s/Batch -> 13.5h Gesamtdauer pro Refresh), was den Pipeline-Step
factcheck blockiert und die Queue lahmlegt. Bis das Performance-Thema
geloest ist (Parallelisierung, Relevanz-Filter, Hard-Cap), wird der
Agent live deaktiviert. Zustand spaeter ueber .env wieder aktivierbar.
Live-.env wurde mit TRANSLATOR_ENABLED=false ergaenzt.
- main.py: Auto-Refresh-Filter beruecksichtigt jetzt auch cancelled und error
- orchestrator.py: Queue-Cancels schreiben jetzt einen cancelled-Eintrag ins
refresh_log via _log_queued_cancellation
Wirkung: Nach Cancel oder Error startet die Lage erst beim naechsten
regulaeren Slot wieder. refresh_mode bleibt unveraendert.
(Identisch zu Commit auf main, develop nachgezogen.)
Der Auto-Refresh-Scheduler hat seinen letzten relevanten refresh_log-Eintrag
bisher mit Filter status IN (completed, running) gesucht. Cancelled- und
Error-Laeufe wurden ignoriert, der davor liegende Completed wurde genommen.
Ergebnis: Direkt nach Cancel oder Error wurde der Slot als faellig gesehen
und nach 60 Sekunden wieder eingereiht (Endlos-Loop bei Iran-Konflikt heute,
4x error in Folge ohne Pause).
- main.py: Filter erweitert auf status IN (completed, running, cancelled, error)
- orchestrator.py: Queue-Cancels schreiben jetzt auch einen cancelled-Eintrag
ins refresh_log via _log_queued_cancellation (vorher: stiller Discard,
kein Fingerabdruck im Log -> Auto-Refresh erkannte den Cancel nie)
Wirkung: Nach Cancel oder Error startet die Lage erst beim naechsten
regulaeren Slot wieder. refresh_mode bleibt unveraendert.
Wenn der User in der Sidebar auf eine Lage klickt, die schon in Queue
wartet, ruft bindToIncident() die API auf und kriegt den letzten
gespeicherten Pipeline-Stand (alles done = gruen). Das ist falsch fuer
queued-Status.
Fix: nach API-Load pruefen, ob die Lage in App._refreshingIncidents ist
UND in UI._progressState mit step=queued -> beginQueue() selbst ausloesen.
Damit zeigt die Pipeline grau, sobald man auf die queued-Lage wechselt.
Bisher hing der Titel nur an state.isFirst -> stand auch "Aktualisierung
laeuft" wenn die Lage tatsaechlich noch in der Queue wartete.
Jetzt:
- queued -> "In Warteschlange" (mit Position #N falls vorhanden)
- cancelling -> "Wird abgebrochen…"
- isFirst -> "Erste Recherche laeuft"
- sonst -> "Aktualisierung laeuft"
beginQueue() und _restoreSnapshot() haben bisher nur _render() aufgerufen,
aber NICHT _renderMini(). Daher blieben die kleinen Pipeline-Icons im
"Aktualisierung laeuft"-Modal gruen, obwohl die Lage in Queue war.
Fix: an beiden Stellen auch _renderMini() aufrufen.
Vorher:
- Lage refreshen -> Lage geht in Queue, aber Pipeline-Icons bleiben gruen
mit Haekchen vom letzten Refresh (suggeriert faelschlich "alles fertig")
- Cancel/Error -> Pipeline bleibt im Mix-Zustand (teils active, teils pending)
Nachher:
- pipeline.beginQueue(id): macht Snapshot des aktuellen _stateByKey und
setzt alle Steps auf pending. Ausgeloest aus app.js handleRefresh()
und _restoreRefreshingState() (auch nach F5).
- _onRefreshDoneSuccess: Snapshot verwerfen + API-Reload (wie bisher).
- _onRefreshDoneCancel: Snapshot zurueckspielen -> vorheriger gruener
Stand sichtbar.
- _onRefreshDoneError: gleiches Verhalten wie Cancel.
- bindToIncident: Snapshot mitloeschen (lagen-spezifisch).
- Bei zweitem Refresh ohne Cancel dazwischen wird Snapshot bewusst
ueberschrieben.
Bisher haben translations als Teil der Analyzer-JSON-Antwort gelebt
("translations": [...]). Bei vielen Artikeln pro Refresh hat das LLM die
Translations regelmaessig weggelassen (Output-Token-Druck), insbesondere
content_de (lange Texte werden zuerst gestrichen). Folge: viele englische
Artikel ohne deutsche Headline/Inhalt im Frontend.
Aenderungen:
- Neuer Agent src/agents/translator.py:
* translate_articles_batch / translate_articles
* Nutzt CLAUDE_MODEL_FAST (Haiku) - billig
* Batch-Size 5 (mit Reserve gegen Output-Truncate)
* Robustes JSON-Parsing: Markdown-Codefence, Truncate-Fallback,
extrahiert auch unvollstaendige Antworten
* Idempotent: Caller filtert auf fehlende headline_de/content_de
- analyzer.py: translations aus 4 Prompt-Templates entfernt (adhoc/research
x analyze/enhance) und Fallback-Return-Dict bereinigt -> Analyzer-Output
wird kompakter und zuverlaessiger
- orchestrator.py:
* Alter Translation-INSERT-Block entfernt (analysis.translations wird
nicht mehr genutzt)
* Nach Analyse + db.commit + cancel-check neuer Translator-Call:
SELECT WHERE language!=de AND (headline_de OR content_de fehlt),
translate_articles, normalize_german_umlauts, COALESCE-UPDATE
* Vor post_refresh_qc -> normalize_umlaut_articles greift auch frische
Uebersetzungen
* Failure-tolerant: Translator-Fehler bricht Refresh nicht ab
Backfill: migrations/migrate_translations_2026-05-03.py im Verwaltungs-Repo.
Fix fuer ASCII-Umlaute in Headlines/Inhalten (Gespraeche statt Gespraeche).
Zwei Quellen des Problems:
1. Quellen wie dpa-AFX, Telegram TASS/RIA liefern Headlines schon ASCII-fiziert
2. LLM-Uebersetzungen drift en gelegentlich zu ae/oe/ue trotz Prompt
Aenderungen:
- rss_parser.py: nach html_to_text auch normalize_german_umlauts auf
title und summary anwenden (sicher, hunspell-Dict ignoriert englische
Woerter wie Boeing/Business)
- orchestrator.py:1418 Translation-INSERT: headline_de und content_de
durch normalize_german_umlauts schicken (LLM-Drift abfangen)
- post_refresh_qc.py: neue Funktion normalize_umlaut_articles als Sicher-
heitsnetz analog zu normalize_umlaut_fields. Behandelt headline_de und
content_de aller Artikel des Incidents; bei language=de zusaetzlich
headline und content_original. Wird in run_post_refresh_qc nach
normalize_umlaut_fields aufgerufen.
Backfill: migrations/migrate_umlauts_2026-05-03.py (im Verwaltungs-Repo)
Ursache des Bugs: feedparser.entry.summary liefert bei vielen Quellen
(Guardian, AP, Sueddeutsche, Golem, Bellingcat, ...) HTML-kodierten Text
(<p>, <a>, <ul>, ...). Der Parser hat diesen 1:1 in articles.content_original
und content_de gespeichert. Folge:
- UI rendert HTML-Tags als Text in Timeline-Karten
- KI-Agenten (analyzer, entity_extractor, factchecker) bekommen HTML-Muell
als Analyse-Input -> schwaechere Ergebnisse
- _is_german-Sprachheuristik wird durch Tags verzerrt
- 1000-Zeichen-Cap wird durch Tags + Tracking-URLs verbraucht
Fix: html_to_text aus feeds/transcript_extractors/_common.py wiederverwenden,
strippt Tags + decodiert HTML-Entities (inkl. dt. Umlaute) + normalisiert
Whitespace. Wird auf summary direkt nach entry.get angewandt -> betrifft
sowohl Match-Logik (text-Variable) als auch INSERT (content_original/de).
Backfill-Migration: migrations/migrate_html_strip_2026-05-03.py im
Verwaltungs-Repo, behandelt bestehende DB-Eintraege rueckwirkend.
Wenn STAGING_MODE=1 (oder true/yes) in der .env gesetzt ist:
- check_license() liefert immer unlimited_budget=True -> kein Token-Budget-Hard-Stop,
egal was in der DB steht.
- /api/auth/me liefert is_global_admin=False -> Frontend ruft _initOrgSwitcher
nicht auf, Org-Switcher-Section bleibt versteckt.
Nur in ~/AegisSight-Monitor-staging/.env gesetzt; Live-.env hat das Flag
nicht, daher dort unverändertes Produktiv-Verhalten.
- check_license() liefert jetzt unlimited_budget, credits_total, credits_used,
read_only_reason. Bei nicht-unlimited UND credits_used >= credits_total wird
status=budget_exceeded, read_only=True gesetzt.
- require_writable_license blockiert mit 403 + X-License-Status-Header je nach Reason.
- /api/auth/me liefert read_only_reason und unlimited_budget; credits_percent_used
wird nicht mehr auf 100 gekappt (echte Prozente).
- Frontend: Banner-Text dynamisch je nach reason (budget_exceeded/expired/...).
Refresh-Button bei read_only deaktiviert + Tooltip. Globaler 403-Handler in
api.js: bei X-License-Status -> Banner + Toast aktualisieren.
Jinja2, weasyprint und python-docx waren auf Live manuell ins venv
installiert, fehlten aber in requirements.txt — Folge: auf Staging waren
sie nicht installiert, Bericht-Export warf 500 (ModuleNotFoundError).
Jetzt im Repo dokumentiert, beim Aufsetzen neuer Umgebungen ist alles
vollständig.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1. Faktencheck immer vollständig
PDF-Export hatte im scope=report einen [:20]-Cap, der vollständige
Faktencheck wurde nur bei scope=full gerendert. Jetzt ungekürzt
überall, sortiert chronologisch absteigend (DB-Sortierung).
2. Status-Labels aus Frontend übernommen
FC_STATUS_LABELS hatte nur 4 Werte; in der DB existieren aber 7+
(confirmed/unconfirmed/contradicted/developing/established/
unverified/disputed). Folge: "contradicted" und drei weitere
wurden auf englisch ausgegeben. Jetzt 1:1 vom Monitor-UI:
contradicted → "Widerlegt"
developing → "Unklar"
established → "Gesichert"
unverified → "Ungeprüft"
3. Adhoc-Export: Neueste Entwicklungen statt Executive Summary
Bei Live-Monitoring-Lagen ist die generische Executive Summary
weniger aussagekräftig als die kompakten "Neueste Entwicklungen"-
Bullets. Endpoint nutzt jetzt:
- adhoc + latest_developments vorhanden → latest_developments
(Markdown -> HTML konvertiert)
- adhoc + leer → cached/generierte Executive Summary (Fallback)
- research → unverändert Executive Summary
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Beim ersten Schritt (sources_review) eines neuen Refreshs werden alle
nachfolgenden Schritte sichtbar auf "pending" (grau) zurückgesetzt.
Vorher hingen sie weiterhin als "done" vom letzten Refresh in grün
herum, während die Pipeline schon einen neuen Durchlauf zeigte.
- Bedingung in pipeline.js entschärft: nicht mehr nur bei
pass_number > 1 (Multi-Pass), sondern bei jedem ersten Schritt-Active
- Bei Reset wird das ganze Stage neu gezeichnet (nicht nur der einzelne
Block), damit die zurückgesetzten Schritte tatsächlich grau erscheinen
- Greift sowohl bei normalem Refresh als auch bei Multi-Pass-Wechsel
einer Research-Lage
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reihenfolge in der Pipeline-Anzeige getauscht — passt zur perspektivischen
Backend-Umstellung (Faktencheck-Output soll als Kontext ins Lagebild
einfließen, statt parallel zu generieren). Backend läuft aktuell noch
parallel; sobald die sequenzielle Variante mit Kontext-Übergabe steht,
stimmt die Anzeige mit dem realen Flow überein.
Im 3x3-Snake-Layout liegt jetzt:
Reihe 2: Relevanz bewerten → Orte erkennen → Fakten prüfen
Reihe 3: Lagebild verfassen → Qualitätscheck → Benachrichtigen
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Die Reputation-Map nutzte veraltete Schlüssel (presseagenturen,
behoerden, nachrichten_de/int), die nirgends in der DB vorkamen — die
DB hat nachrichtenagentur, behoerde, oeffentlich-rechtlich,
qualitaetszeitung, think-tank, regional, telegram, boulevard. Folge
war ein stiller Bug: alle hochwertigen Quellen (Reuters, ZDF,
tagesschau, Spiegel, FAZ, BMI etc.) bekamen den Default-Score 0.4 wie
"sonstige" und wurden in der Relevanz-Sortierung nicht bevorzugt.
Map jetzt vollständig auf aktuelle Kategorie-Werte:
- nachrichtenagentur, behoerde: 1.00
- oeffentlich-rechtlich: 0.95
- qualitaetszeitung, think-tank: 0.85
- fachmedien: 0.80
- international: 0.75
- regional: 0.65
- telegram: 0.50
- sonstige: 0.40
- boulevard: 0.30
Test mit 200 zufälligen Artikeln aus der Live-DB:
155 besser bewertet, 0 schlechter, 45 unverändert.
Stärkster Effekt bei ÖR (+0.165), Nachrichtenagenturen (+0.18),
Qualitätszeitungen (+0.135).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Statt einer eigenen Nummerierung (1., 2., ...) wird jetzt die echte
Lagebild-Quellennummer im Format [N] angezeigt — also exakt das, was im
Lagebild-Text als Zitat erscheint. Match per exakter source_url, mit
Quellen-Name als Fallback.
Artikel ohne Match (nicht im Lagebild zitiert) bekommen einen dezenten
Strich "—" mit Tooltip "Nicht im Lagebild zitiert", damit sichtbar ist
welche Belege Claude überhaupt verwendet hat und welche nicht.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aufklapp-Liste pro Quelle zeigt jetzt:
1. fortlaufende Nummer (gold, monospace)
2. Datum + Uhrzeit (klein, dezent grau, monospace)
3. Headline als Link zum Originalartikel
Drei-Spalten-Grid (Nummer | Datum | Headline). Auf schmalem Viewport
(<600px) klappt das Datum unter die Nummer. Bei research-Lagen wird
published_at bevorzugt, sonst collected_at.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Quellen-Boxen waren bisher reine Anzeige. Jetzt sind sie klickbar:
beim Klick erscheint direkt unter der Box (über die volle Grid-Breite)
eine Liste der Artikel-Headlines dieser Quelle, jede mit Link zum
Originalartikel. Mutual-exclusive — Klick auf eine andere Quelle
schließt die vorherige automatisch.
- components.js: Item bekommt data-source, onclick + Tastatur-Support
(Enter/Space), aria-expanded.
- app.js: toggleSourceOverviewDetail filtert _currentArticles nach
Quelle, sortiert chronologisch absteigend, fügt das Detail-Element
via insertAdjacentElement direkt nach dem geklickten Item ein.
- CSS: aktiver Item-Status (Glow + Tint), Detail-Block mit
grid-column 1/-1 (volle Breite) + max-height 320px scrollbar bei
vielen Artikeln + dezente Slide-In-Animation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bisher musste eine Headline mindestens 2 der dynamisch generierten
Suchworte enthalten, um den Match-Filter zu passieren. Bei thematisch
engen Lagen (Bsp. "Buckelwal timmy") fielen damit echte Treffer wie
"Transport mit Buckelwal erreicht dänische Gewässer..." durch, weil
nur 1 Keyword (buckelwal) gematcht hat.
Neue Heuristik: enthält der Text mindestens ein spezifisches Keyword
(>=7 Zeichen, also keine kurzen Akteursnamen wie "iran" oder "trump"),
reicht 1 Treffer. Bei nur kurzen, generischen Keywords gilt weiter die
alte Schwelle (halb der Wörter, max. 2). Topic-Filter danach (Haiku)
fängt False Positives.
Damit kommen ZDF/tagesschau/n-tv-Headlines mit nur einem starken
Begriff durch — der Hauptgrund, warum Lage 8 Buckelwal mit ZDF-Quelle
am ersten Refresh 0 Artikel hatte.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bisher hatten Quellen vom Typ web_source keine praktische Wirkung auf
die Recherche - sie lagen nur als Marker in der DB. Jetzt werden sie
aktiv in den Recherche-Prompt eingebunden.
Ablauf:
1. Vor dem Hauptaufruf an Opus prüft ein günstiger Haiku-Call alle
aktiven Web-Quellen des Tenants (plus globale) und wählt die
thematisch passenden aus. Leere Selektion ist ausdrücklich erlaubt.
2. Die ausgewählten Domains werden dem Recherche-Prompt als
"EINGETRAGENE WEB-QUELLEN" Block beigegeben mit der Empfehlung,
gezielt mit "site:domain query" zu suchen, falls thematisch passend.
3. site: ist Empfehlung, kein Zwang - Claude bleibt flexibel und
ergänzt seine sonstige Recherche.
- source_rules.get_feeds_with_metadata: SELECT um notes-Feld erweitert,
damit der Selektor besseren Kontext zur Quelle hat.
- ResearcherAgent.select_relevant_web_sources: neuer Helper analog zu
select_relevant_feeds, mit Skip-Optimierung wenn ≤3 Quellen.
- WEB_SOURCE_SELECTION_PROMPT: explizite Regel "lieber leer als
pauschal alle", verhindert Token-Verschwendung.
- ResearcherAgent.search: neuer Parameter preferred_sources, beide
Templates (RESEARCH + DEEP_RESEARCH) bekommen optionalen
preferred_sources_block.
- Orchestrator._web_search_pipeline: Vorselektion vor researcher.search,
Token-Usage in usage_acc, Logging der gewählten Domains.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der Pfeil überschattete das darunter liegende Stunden-Label. Goldener
Balken mit Glow + scaleY reicht als visuelles Aktiv-Signal.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>