From 97e465181a9bfb58a3e0b1c6ddf6e6854635aa39 Mon Sep 17 00:00:00 2001 From: team3 Date: Mon, 12 Oct 2026 15:29:34 +0200 Subject: [PATCH] =?UTF-8?q?Hinweise=20und=20Spezialisierung=20je=20Version?= =?UTF-8?q?:=20im=20Lauf=20sichtbar,=20bei=20=E2=80=9ENeue=20Version?= =?UTF-8?q?=E2=80=9C=20=C3=A4nderbar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Eingaben liegen jetzt in vN/state.json; alte Versionen ohne eigene Eingaben nehmen die des Themas. „Neue Version“ öffnet ein Formular mit den bisherigen Werten, Thema bleibt fest. Zurücksetzen behält die Eingaben. Co-Authored-By: Claude Fable 5.1 --- API.md | 6 +++--- backend/main.py | 15 +++++++++++---- backend/pipeline.py | 3 ++- backend/state.py | 29 ++++++++++++++++++++++++----- frontend/src/App.vue | 6 +++--- frontend/src/api.js | 2 +- frontend/src/components/Lauf.vue | 24 +++++++++++++++++++++--- frontend/src/style.css | 5 +++++ 8 files changed, 70 insertions(+), 20 deletions(-) diff --git a/API.md b/API.md index befeb3e..5ae7f76 100644 --- a/API.md +++ b/API.md @@ -18,7 +18,7 @@ Ohne `v2` gilt die neueste Version. – `hinweise`: wie das Thema zu verstehen ist (fügt hinzu); `spezialisierung`: Grenze des Umfangs, nur was dafür gebraucht wird (nimmt weg) - `GET /api/themen/{slug}` → Thema wie oben - `DELETE /api/themen/{slug}` – ganzes Thema -- `POST /api/themen/{slug}/versionen` → `{"v": N}` – nächste Version, gleiche Eingaben, ohne Start +- `POST /api/themen/{slug}/versionen` `{hinweise?, spezialisierung?}` → `{"v": N}` – nächste Version ohne Start; fehlende Felder übernimmt sie von der neuesten Version - `DELETE /api/themen/{slug}/v{N}` – nur diese Version - `POST /api/themen/{slug}/v{N}/start` – startet oder setzt fort (resümiert an der offenen Stufe) - `POST /api/themen/{slug}/v{N}/pause` – bricht laufende Agenten ab; Neustart mit `start` @@ -38,7 +38,7 @@ Alte Zustände ohne diese Stufe bekommen sie beim Laden nachgetragen. ```json { - "slug": "godot-4", "name": "Godot 4", "version": 1, "titel": "Godot 4", "hinweise": "…", "spezialisierung": "", + "slug": "godot-4", "name": "Godot 4", "version": 1, "titel": "Godot 4", "hinweise": "…", "spezialisierung": "", // Eingaben dieser Version "status": "laeuft", "grund": "", "stufe": "schreiben", "angelegt": "2026-09-28T10:00:00Z", "deutung": {"titel": "Godot 4", "untertitel": "…", "deutung": "…", "buchtyp": "werkzeug|wissen", "zielgruppe": "…"}, "stufen": [ @@ -94,7 +94,7 @@ Solange ein Lauf läuft, enthält `buch` die bereits geschriebenen Kapitel (Stat storage// thema.json {name, slug, titel, hinweise, spezialisierung, angelegt} v1/, v2/, … je Version: - state.json Zustand wie oben (ohne Buch) + state.json Zustand wie oben (ohne Buch), mit hinweise und spezialisierung der Version deutung.json vom Recherche-Agenten position.json Leseposition quellen/ QUELLEN.md + geklonte/geladene Quellen diff --git a/backend/main.py b/backend/main.py index 9102da8..79d2ca6 100644 --- a/backend/main.py +++ b/backend/main.py @@ -32,6 +32,11 @@ class ThemaNeu(BaseModel): spezialisierung: str = "" +class VersionNeu(BaseModel): + hinweise: str | None = None # None: wie die bisherige Version + spezialisierung: str | None = None + + class Position(BaseModel): abschnitt: str | None = None lesemodus: str | int | None = None # neu: key des Bildschirms, alt: Index @@ -104,9 +109,10 @@ async def thema_loeschen(slug: str): @app.post("/api/themen/{slug}/versionen") -async def version_anlegen(slug: str): - """Neue Version: gleiche Eingaben, frischer Lauf, ohne Wissen über die Vorgänger.""" - key = state.version_anlegen(_thema(slug)["name"]) +async def version_anlegen(slug: str, body: VersionNeu | None = None): + """Neue Version: frischer Lauf ohne Wissen über die Vorgänger; Hinweise und Spezialisierung wahlweise geändert.""" + b = body or VersionNeu() + key = state.version_anlegen(_thema(slug)["name"], b.hinweise, b.spezialisierung) return {"v": int(key.rsplit("/v", 1)[1])} @@ -115,7 +121,8 @@ async def zustand(slug: str, n: int): key = _key(slug, n) t = _thema(slug) st = state.zustand(key) - return {"slug": slug, "name": t["name"], "version": n, "titel": t["titel"], "hinweise": t.get("hinweise", ""), "spezialisierung": t.get("spezialisierung", ""), **st, + h, sp = state.eingaben(key) + return {"slug": slug, "name": t["name"], "version": n, "titel": t["titel"], **st, "hinweise": h, "spezialisierung": sp, "deutung": st.get("deutung") or state.deutung(key), "ereignisse": st["ereignisse"][-100:]} diff --git a/backend/pipeline.py b/backend/pipeline.py index c1c62fb..b791400 100644 --- a/backend/pipeline.py +++ b/backend/pipeline.py @@ -73,8 +73,9 @@ def _offen(name: str) -> None: def _thema(name: str) -> tuple[str, str, str]: + """Titel, Hinweise, Spezialisierung – die Eingaben gelten je Version.""" t = state.thema(name) or {} - return t.get("titel") or name, t.get("hinweise", ""), t.get("spezialisierung", "") + return (t.get("titel") or name, *state.eingaben(name)) def _kapitel(name: str) -> list[dict]: diff --git a/backend/state.py b/backend/state.py index 0eddcf3..266dc44 100644 --- a/backend/state.py +++ b/backend/state.py @@ -55,16 +55,34 @@ def name_von_slug(sl: str) -> str | None: return next((t["name"] for t in themen() if t.get("slug") == sl), None) -def version_anlegen(name: str) -> str: - n = (versionen(name) or [0])[-1] + 1 - key = f"{name}/v{n}" +def version_anlegen(name: str, hinweise: str | None = None, spezialisierung: str | None = None) -> str: + """Neue Version; ohne Angabe übernimmt sie Hinweise und Spezialisierung der neuesten Version (bzw. des Themas).""" + vs = versionen(name) + alt_h, alt_s = eingaben(f"{name}/v{vs[-1]}") if vs else _eingaben_thema(name) + key = f"{name}/v{(vs or [0])[-1] + 1}" v = verzeichnis(key) for u in ("quellen", "buch", "berichte", "arbeit"): (v / u).mkdir(parents=True) - _schreiben(v / "state.json", leerer_zustand()) + st = leerer_zustand() + st["hinweise"] = (alt_h if hinweise is None else hinweise).strip() + st["spezialisierung"] = (alt_s if spezialisierung is None else spezialisierung).strip() + _schreiben(v / "state.json", st) return key +def _eingaben_thema(name: str) -> tuple[str, str]: + t = thema(name) or {} + return t.get("hinweise", ""), t.get("spezialisierung", "") + + +def eingaben(key: str) -> tuple[str, str]: + """Hinweise und Spezialisierung einer Version; alte Versionen ohne eigene Eingaben nehmen die des Themas.""" + st = zustand(key) + if "hinweise" in st: + return st["hinweise"], st.get("spezialisierung", "") + return _eingaben_thema(key) + + def version_loeschen(key: str) -> None: _cache.pop(key, None) shutil.rmtree(verzeichnis(key), ignore_errors=True) @@ -138,13 +156,14 @@ def loeschen(name: str) -> None: def zuruecksetzen(key: str) -> None: v = verzeichnis(key) + h, s = eingaben(key) _cache.pop(key, None) for u in ("quellen", "buch", "berichte", "arbeit"): shutil.rmtree(v / u, ignore_errors=True) (v / u).mkdir() for f in ("deutung.json", "log.jsonl", "state.json", "position.json"): (v / f).unlink(missing_ok=True) - _schreiben(v / "state.json", leerer_zustand()) + _schreiben(v / "state.json", {**leerer_zustand(), "hinweise": h, "spezialisierung": s}) def thema(key: str) -> dict | None: diff --git a/frontend/src/App.vue b/frontend/src/App.vue index cdf343a..e542346 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -113,10 +113,10 @@ async function anlegen() { themaWaehlen(t.slug) } catch (e) { fehler.value = String(e.message || e) } } -// Neue Version: gleiche Eingaben, frischer Lauf; die alte Version bleibt samt Leseposition erhalten. -async function neueVersion() { +// Neue Version: frischer Lauf mit ggf. geänderten Hinweisen/Spezialisierung; die alte Version bleibt samt Leseposition erhalten. +async function neueVersion(eingaben) { try { - const r = await api.versionAnlegen(slug.value) + const r = await api.versionAnlegen(slug.value, eingaben) await topicsLaden() geheZu({ v: r.v, tab: 'lauf' }) await aktion(() => api.start(slug.value, r.v)) diff --git a/frontend/src/api.js b/frontend/src/api.js index 5cadd76..a14fbaa 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -20,7 +20,7 @@ export const api = { themen: () => req('/themen'), anlegen: (name, hinweise = '', spezialisierung = '') => req('/themen', { method: 'POST', body: { name, hinweise, spezialisierung } }), loeschen: (slug) => req(`/themen/${e(slug)}`, { method: 'DELETE' }), - versionAnlegen: (slug) => req(`/themen/${e(slug)}/versionen`, { method: 'POST' }), + versionAnlegen: (slug, eingaben) => req(`/themen/${e(slug)}/versionen`, { method: 'POST', body: eingaben }), versionLoeschen: (slug, n) => req(v(slug, n), { method: 'DELETE' }), state: (slug, n) => req(v(slug, n)), start: (slug, n) => req(v(slug, n) + '/start', { method: 'POST' }), diff --git a/frontend/src/components/Lauf.vue b/frontend/src/components/Lauf.vue index 1042f86..527e598 100644 --- a/frontend/src/components/Lauf.vue +++ b/frontend/src/components/Lauf.vue @@ -1,5 +1,5 @@