feat: drawer edits for edge_trust / edge_summary / memory_pov_summary / knowledge_facts (T72.1)
Adds the four POST routes whose state-layer support was already dispatched by the manual_edit projector (edge_trust, edge_summary, memory_pov_summary) plus a new edge_knowledge_fact dispatch branch for add/remove fact list manipulation. Drawer template gains editable textareas, sliders, and add/remove fact controls. Remove semantics on knowledge_fact match by string (not index) so concurrent edge_update events appending facts between drawer renders don't desync the form.
This commit is contained in:
@@ -6,7 +6,7 @@ be reversed by emitting an inverse ``manual_edit`` later. This module
|
||||
applies the new value to the appropriate target table; the snapshot of
|
||||
``prior_value`` is taken by the route handler before this fires.
|
||||
|
||||
Phase 1 covers four target kinds:
|
||||
Phase 1 covers five target kinds:
|
||||
- ``edge_affinity`` and ``edge_trust`` — slider edits on a specific edge,
|
||||
clamped to 0..100.
|
||||
- ``memory_significance`` — dropdown edit, clamped to 0..3.
|
||||
@@ -17,8 +17,12 @@ Phase 1 covers four target kinds:
|
||||
field. Driven by T27 from the classifier's ``relationship_summary``
|
||||
output combined with the prior summary.
|
||||
|
||||
Other §6.4 editable fields (activity verb / attention / posture,
|
||||
knowledge_facts list manipulation) are deferred to Phase 1.5.
|
||||
T72.1 (Phase 2.5) adds one list-shaped edit:
|
||||
- ``edge_knowledge_fact`` — add/remove a single fact on an edge's
|
||||
``knowledge_json`` list. Payload carries an ``action`` of ``"add"`` or
|
||||
``"remove"`` and a ``fact`` string; remove matches the first occurrence
|
||||
by string equality so the route handler doesn't have to track fact
|
||||
indices across re-renders.
|
||||
|
||||
Pin toggles intentionally use the existing ``memory_pin_changed`` event
|
||||
(registered in :mod:`chat.state.memory`) rather than ``manual_edit`` so
|
||||
@@ -27,6 +31,7 @@ the projection writes both ``pinned`` and ``auto_pinned`` atomically.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from sqlite3 import Connection
|
||||
|
||||
from chat.eventlog.log import Event
|
||||
@@ -87,5 +92,33 @@ def _apply_manual_edit(conn: Connection, e: Event) -> None:
|
||||
target_id["target_id"],
|
||||
),
|
||||
)
|
||||
elif kind == "edge_knowledge_fact":
|
||||
# T72.1: add or remove a single fact on an edge's knowledge list.
|
||||
# ``target_id`` is the {"source_id", "target_id"} edge pair;
|
||||
# ``new_value`` carries ``{"action": "add"|"remove", "fact": str}``.
|
||||
# Remove matches by string equality (first occurrence) so callers
|
||||
# don't have to thread a fact_index through re-rendered drawers.
|
||||
action = new_value["action"]
|
||||
fact = str(new_value["fact"])
|
||||
row = conn.execute(
|
||||
"SELECT knowledge_json FROM edges "
|
||||
"WHERE source_id = ? AND target_id = ?",
|
||||
(target_id["source_id"], target_id["target_id"]),
|
||||
).fetchone()
|
||||
if row is not None:
|
||||
knowledge = json.loads(row[0])
|
||||
if action == "add":
|
||||
knowledge.append(fact)
|
||||
elif action == "remove" and fact in knowledge:
|
||||
knowledge.remove(fact)
|
||||
conn.execute(
|
||||
"UPDATE edges SET knowledge_json = ? "
|
||||
"WHERE source_id = ? AND target_id = ?",
|
||||
(
|
||||
json.dumps(knowledge),
|
||||
target_id["source_id"],
|
||||
target_id["target_id"],
|
||||
),
|
||||
)
|
||||
# Unknown target_kind: silently no-op for v1. Future kinds (activity
|
||||
# fields, knowledge_facts list manipulation) extend the dispatch above.
|
||||
# fields, etc.) extend the dispatch above.
|
||||
|
||||
Reference in New Issue
Block a user