diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-28 10:56:26 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-28 10:56:26 +0200 |
| commit | 7a6190becf90364c6f31f401ccda745e4745081c (patch) | |
| tree | 8058b650696457dc701f2bf2f78bcff5c5da0b99 /assistant.py | |
| parent | 48211368c01599d1c173d6e3347674750976db47 (diff) | |
| download | desktop-assistant-7a6190becf90364c6f31f401ccda745e4745081c.tar.gz desktop-assistant-7a6190becf90364c6f31f401ccda745e4745081c.zip | |
Keep tool calls in history, with placeholder results
History kept only what was said, so after a few factual answers the
model saw no tool behind them and invented the next one: asked for
pending updates it made up counts without calling the tool (1/10 on a
replayed session). Keeping each turn's tool calls brings it back to
10/10. Their results are replaced by a placeholder, which scores the
same and keeps the context close to what it was; a follow-up on an old
result calls the tool again. The window is now the last 10 whole turns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'assistant.py')
| -rw-r--r-- | assistant.py | 18 |
1 files changed, 13 insertions, 5 deletions
diff --git a/assistant.py b/assistant.py index 991dfa0..2a84cd6 100644 --- a/assistant.py +++ b/assistant.py @@ -548,15 +548,17 @@ def reply(history, q, mine): log(f"you ({lang}, {time.perf_counter() - t:.2f}s): {text}") emit({"type": "state", "state": "thinking"}) question = {"role": "user", "content": text} - # ponytail: last 20 messages, summarise if long sessions need memory # The model has no clock: without the date it makes one up for tools. # Also stamped on the question itself, which history does not keep: with # the time only in the system prompt, "what time is it?" asked again an # hour later copied the old answer from history. Stamping every message # in history fixed that but lost tool arguments (account filter 0/6). now = time.strftime("%A %d %B %Y, %H:%M") - msgs = ([{"role": "system", "content": f"{CFG['system']} It is {now}."}] + history[-20:] + # ponytail: last 10 turns, summarise if long sessions need memory + msgs = ([{"role": "system", "content": f"{CFG['system']} It is {now}."}] + + [m for past in history[-10:] for m in past] + [{"role": "user", "content": f"[{now}] {text}"}]) + first = len(msgs) # this turn's tool messages start here t, said, voice, announced = time.perf_counter(), [], lang, False def say(s): @@ -607,9 +609,15 @@ def reply(history, q, mine): log("interrupted") return q.put((mine, None)) - # Tool calls stay inside the turn: history keeps only what was said. A cut - # off exchange is dropped whole, so user and assistant still alternate. - history += [question, {"role": "assistant", "content": " ".join(said)}] + # History keeps the tool calls: with only what was said, the model saw + # facts answered without tools and invented the next ones (no tool call + # 9/10 on a replayed session, 0/10 with the calls kept). Results are + # replaced by a placeholder, for context: same 10/10, and a follow-up on + # an old result calls the tool again (10/10). A cut off exchange is + # dropped whole, so user and assistant still alternate. + past = [{**m, "content": "(shown to the user at the time)"} if m["role"] == "tool" else m + for m in msgs[first:]] + history.append([question] + past + [{"role": "assistant", "content": " ".join(said)}]) log("assistant:", " ".join(said)) |
