Skip to content

feat(safari): steer follow-ups into a running turn and watch the session - #249

Merged
ysyneu merged 1 commit into
mainfrom
feat/safari-session-watch
Nov 11, 2026
Merged

ysyneu merged 1 commit into
mainfrom
feat/safari-session-watch

Conversation

@ysyneu

@ysyneu ysyneu commented Nov 11, 2026

Copy link
Copy Markdown
Contributor

What

A follow-up sent while the session's turn is still running no longer waits for that turn to finish.

  • safari send: for an existing session it reads turn_in_flight from session/get and sets steering only then. The running turn takes the message in at its next step and answers it. An idle session still runs the message as a turn of its own, so its model input is unchanged.
  • safari watch follows the session, not one invocation: the answer to a steered message comes from the running turn, under that turn's invocation.
    • --root-invocation-id marks where output starts (the request's first frame) and which request must settle before the watch can end. Replies from every turn after that point are printed.
    • A turn that does not answer through the reply tool (one started from the web console) has its final answer, named by the settle's final_event_id, printed as a result reply.
    • A steered settle is written before the running turn answers, so it never ends the watch. The next non-steered settle with no standing tasks, followed by an idle session/get, does.
    • Re-arming with --root-invocation-id and --since replays the session from its start and skips everything up to the cursor silently, so the request's own settle is still seen. A done candidate inside the skipped part only ends the watch when nothing new follows it.

Requires go-flashduty v0.16.1 (SessionMessageRequest.Steering).

Older CLI versions never send steering, so their behaviour is unchanged.

Tests

  • Unit tests:
    • the watch starts at the request, then follows the session;
    • a steered request is answered by the running turn;
    • the final answer is printed for a non-reply turn and skipped for reply-only and undeliverable turns;
    • quiet resume prints nothing twice;
    • a quiet settle does not end the replay;
    • an all-quiet replay ends;
    • the watch waits for the turn that took the message in, and does not stop reading at the steered settle;
    • send sets steering only into a running turn.
  • Live against production (cloud environment, two sleep 30 steps):
    • A follow-up sent between the steps settled as steered.
    • The running turn answered it before step 2.
    • Watching the follow-up printed the answer, step 2 and the final result, then exited 0 after the turn completed.
    • A follow-up to an idle session ran its own turn and exited 0, without printing earlier history.
  • make check passes (golangci-lint v2.11.4: 0 issues; go test -race ./...; build), as does make check-cards.

A message sent while the session's turn is still running no longer waits
for that turn to finish. `safari send` reads turn_in_flight from
session/get and sets steering only then, so the running turn takes the
message in at its next step and answers it; an idle session still runs
the message as a turn of its own.

The answer to a steered message comes from the running turn, under that
turn's invocation, so `safari watch` now follows the session instead of
one invocation:

- --root-invocation-id marks where output starts (the request's first
  frame) and which request must settle before the watch can end; replies
  from every turn after that point are printed.
- A turn that does not answer through the reply tool (one started from
  the web console) has its final answer, named by the settle's
  final_event_id, printed as a result reply.
- A steered settle is written before the running turn answers, so it
  never ends the watch; the next non-steered settle with no standing
  tasks, followed by an idle session/get, does.
- Re-arming with --root-invocation-id and --since replays the session
  from its start and skips everything up to the cursor silently, so the
  request's own settle is still seen. A done candidate inside the skipped
  part only ends the watch when nothing new follows it.

Requires go-flashduty v0.16.1 for SessionMessageRequest.Steering.
@ysyneu
ysyneu merged commit 74a8d07 into main Nov 11, 2026
12 checks passed
@ysyneu
ysyneu deleted the feat/safari-session-watch branch November 11, 2026 02:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant