Carry the source transcript into forks and cross-link fork points
This commit is contained in:
+1
-1
@@ -451,7 +451,7 @@ The cut point comes from `vendor_uuid`: every top-level `agent.message`, `agent.
|
||||
|
||||
A fork of a workflow stage task gets a copy of the source's frozen workflow, brief, run and stage, not the library's current workflow, so the fork is another attempt at that stage of the same run in its own worktree; when it finishes, the stages after it start from it unless they already have tasks (see "Workflows").
|
||||
|
||||
The fork's session guidance gets one more line (`forkGuidance` in `internal/agents/guidance.go`) naming the source task, the snapshot, the fork's branch and worktree and the source's worktree, telling the agent that everything before the fork happened in the other worktree and to work only in its own. Claude Code can reuse the system prompt recorded for the source conversation on a fork, the source's cwd included, so the `UserPromptSubmit` hook's copy is what reliably tells it. The fork's transcript starts with a note from its `task.created` event, "forked this task from <source> at snapshot #n", linking the source while it is active; the lead's signal for it reads "<task> was forked by <user> from <source> at snapshot n", and `list_tasks` notes the source. The fork's transcript shows only its own events, not the source's history.
|
||||
The fork's session guidance gets one more line (`forkGuidance` in `internal/agents/guidance.go`) naming the source task, the snapshot, the fork's branch and worktree and the source's worktree, telling the agent that everything before the fork happened in the other worktree and to work only in its own. Claude Code can reuse the system prompt recorded for the source conversation on a fork, the source's cwd included, so the `UserPromptSubmit` hook's copy is what reliably tells it. A fork carries the source's transcript up to the fork point. `GET /api/tasks/{id}/events` and the task SSE stream's backfill (`Store.TranscriptEvents`) return, besides the task's own events, the source's events up to and including the `snapshot.created` event of the snapshot it was forked at, and so on up the chain for a fork of a fork; those events keep their own `task_id`, and the stream's live part sends only the task's own. The lead's `read_transcript`, `forkPoint` and everything else reading `Store.TaskEvents` see only the task's own events. In the app (`loadHistory` in `mac/Sources/Byre/Store.swift`) the inherited events are the history's leading run whose `task_id` isn't the task's (`Feed.inherited`); `Store.transcript`, which the Changes tab, the Board and the latest-review lookup read, is only the task's own (`Feed.own`). The transcript renders the inherited events like its own, each row carrying the event's task, so its links and its **fork** button act on the source; inherited snapshot rows have no **changes** button, an inherited question that was still open at the fork shows closed ("unanswered when this task was forked"), and inherited questions, findings and ready calls are never attention items. The fork point in the fork is the note from its `task.created` event right after the inherited part, "forked this task here from <source> at snapshot #n", linking the source while it is active. In the source, the same transaction records `task.forked` (`fork`, `forked_at`) on the source task, and its transcript shows "forked as <fork>" on that snapshot's row (a note, when the row isn't shown). The lead's signal for the fork reads "<task> was forked by <user> from <source> at snapshot n", and `list_tasks` notes the source.
|
||||
|
||||
An answered question can be answered again. Expanding an answered question's bubble in the transcript shows an **Answer again** button when the question is `answered` (the transcript's copy of the question comes from its `inbox.*` events, which carry no `snapshot_n`, so the server is what checks for one); it reopens the card's choices, Other box and "Let the agent decide", with Cancel in place of Ignore, and sending posts the new answer, an `InboxResponseCreate`, to `POST /api/inbox/answer-again` (`AnswerAgain` in `internal/agents/fork.go`) instead of `respondInbox`. byre checks the answer against the question as if it were open, forks the question's task at the answer's `snapshot_n` exactly as the **fork** button does, and files in the fork a copy of the question (same payload, its own id and thread) already `answered` with the new response, in one transaction (`Store.CreateAnsweredItem`), whose `inbox.created` event carries the answered item and the human as actor. `Deliver` then hands that answer to the fork's idle session as its first turn, the usual delivery message, so the forked conversation, cut just before the original answer reached the agent, continues with the new one. The app opens the fork; the original task and its question are untouched. An `inbox.created` for an item that isn't open raises no notification, and the lead's signal for it reads as an answer, not a question. Refused (409) when the question isn't `answered` or its answer has no `snapshot_n`, and for anything the fork refuses; 400 for an answer that doesn't fit the question.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user