Skip to content

Commit 176146b

Browse files
AVADSA25Mikarina13claude
authored
fix(observer_recall): answer conversationally, not as a machine dump (beat 20) (#263)
Recall replied like a log printer: "Here's the last 20 min (from CODEC's observer): You were in: Claude. Timeline: 12:20 Claude Files touched: best-noise-cancelling-headphones-2026.md." Accurate but robotic — CODEC should answer like someone who was watching over your shoulder. Now: "Over the last 9 minutes, you were in Claude the whole time. You touched 4 files: …" Prose adapts to what actually happened (one app / two apps / moved around a fair bit), mentions the last thing on screen, and pluralises files properly. Kept deterministic — no second LLM call — so it stays instant and, more importantly, can't invent anything (the whole point of the earlier anti-fabrication work). The honest out-of-range answer for clock-time asks is unchanged. Manifest regenerated. 52 observer tests pass, ruff clean. Co-authored-by: Mickael Farina <farina.mickael@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent ab213cc commit 176146b

2 files changed

Lines changed: 48 additions & 7 deletions

File tree

skills/.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
"network_info.py": "bd776b619cf7c18d67fe03cb0f0456cf9c4f9bf71475740a233a9ca1e6672fcd",
6363
"notes.py": "7d50d1544ea955f59917a1f0e7902d115e9dbccd3188b641057a55b6a5b2803a",
6464
"notification_reader.py": "681208ae4253dfe549512cce4c722c76ca85f2bbbdb8737e37c026ec9444c972",
65-
"observer_recall.py": "f7084d11c069603d815e648dd765628bfed6d31c1df4ac59f0dac35259aa6fe2",
65+
"observer_recall.py": "5234ab88d151003d8acb00b0e72139d668cfbcd5f091cdda52f247682698a9ff",
6666
"password_generator.py": "f11a917299e14cbd2560111da0bb748cd08792cf715cc4098c64eb62da8c54e3",
6767
"philips_hue.py": "fa831712c39dc6327c84199d8f0aeb09a169a264ce3d936cc337a5c5d6632f7e",
6868
"pilot.py": "f9967890f138bc7a48ae4abc8b4170dca13961b81659ef4e530dc619c1cf90d4",

skills/observer_recall.py

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,30 @@ def _parse_ts(entry: dict) -> datetime | None:
105105
return None
106106

107107

108+
def _fmt_span(entries: list) -> str:
109+
"""Natural opener for how long the snapshots span, e.g. "Over the last
110+
25 minutes" / "In the last couple of minutes". "" if it can't be derived."""
111+
if len(entries) < 2:
112+
return ""
113+
first, last = _parse_ts(entries[0]), _parse_ts(entries[-1])
114+
if not first or not last:
115+
return ""
116+
mins = int((last - first).total_seconds() // 60)
117+
if mins <= 1:
118+
return "In the last minute or so"
119+
if mins < 5:
120+
return "Over the last couple of minutes"
121+
return f"Over the last {mins} minutes"
122+
123+
108124
def _summarise(entries: list) -> str:
109125
"""A compact, human timeline of the entries (oldest→newest)."""
110126
if not entries:
111127
return "nothing recorded in that window."
112128

113129
lines: list[str] = []
114130
last_app = None
131+
last_title_seen = ""
115132
apps_seen: list[str] = []
116133
files_seen: set[str] = set()
117134
ocr_bits: list[str] = []
@@ -122,6 +139,8 @@ def _summarise(entries: list) -> str:
122139
win = e.get("active_window") or {}
123140
app = win.get("app")
124141
title = (win.get("title") or "").strip()
142+
if title:
143+
last_title_seen = title
125144
if app and app != last_app:
126145
label = app + (f" — {title[:60]}" if title else "")
127146
lines.append(f" {stamp} {label}")
@@ -136,15 +155,35 @@ def _summarise(entries: list) -> str:
136155
if ocr and len(ocr) > 20:
137156
ocr_bits.append(ocr[:120])
138157

158+
# Conversational prose, not a machine dump. The old format printed
159+
# "You were in: X. / Timeline: / 12:20 X / Files touched: y" — accurate but
160+
# robotic. CODEC should answer like a person who was watching over your
161+
# shoulder. Deterministic templating (no second LLM call) keeps it instant
162+
# and, crucially, keeps it from inventing anything.
139163
out = []
140164
if apps_seen:
141-
out.append("You were in: " + ", ".join(apps_seen[:6]) + ".")
142-
if lines:
143-
out.append("Timeline:\n" + "\n".join(lines[:12]))
165+
span = _fmt_span(entries)
166+
if len(apps_seen) == 1:
167+
body = f"you were in {apps_seen[0]} the whole time"
168+
elif len(apps_seen) == 2:
169+
body = f"you went back and forth between {apps_seen[0]} and {apps_seen[1]}"
170+
else:
171+
shown = apps_seen[:4]
172+
body = ("you moved around a fair bit — "
173+
+ ", ".join(shown[:-1]) + f" and {shown[-1]}")
174+
opener = f"{span}, {body}" if span else body[0].upper() + body[1:]
175+
if last_title_seen:
176+
opener += f". Last thing on screen was \"{last_title_seen[:70]}\""
177+
out.append(opener + ".")
144178
if files_seen:
145-
out.append("Files touched: " + ", ".join(sorted(files_seen)[:8]) + ".")
179+
fl = sorted(files_seen)
180+
if len(fl) == 1:
181+
out.append(f"You touched one file: {fl[0]}.")
182+
else:
183+
out.append(f"You touched {len(fl)} files: " + ", ".join(fl[:6])
184+
+ ("…" if len(fl) > 6 else "") + ".")
146185
if ocr_bits:
147-
out.append('On screen (excerpt): "' + ocr_bits[-1] + '"')
186+
out.append(f"Text on screen included: \"{ocr_bits[-1].strip()}\"")
148187
if not out:
149188
# Entries exist but carry no window/title/OCR/file content — the observer
150189
# is polling but capturing nothing. This is almost always a macOS
@@ -204,4 +243,6 @@ def run(task: str, context: str = "") -> str:
204243
return (f"Nothing in {span} — the observer keeps roughly the last 10 "
205244
f"minutes, so I can't see that far back.{depth}")
206245

207-
return f"Here's {span} (from CODEC's observer):\n{_summarise(kept)}"
246+
# _summarise already opens conversationally ("Over the last 25 minutes, you
247+
# were in Claude…"), so no robotic "Here's X (from CODEC's observer):" header.
248+
return _summarise(kept)

0 commit comments

Comments
 (0)