diff --git a/TODO.md b/TODO.md index 259fb03..a613598 100644 --- a/TODO.md +++ b/TODO.md @@ -9,9 +9,6 @@ # M3 — Second vendor and review -- Continue on another model or vendor with Compact - Compact takes an optional `model`; the handoff is written by the old session as now, and the continuation session starts on the chosen model on either vendor, reusing `handoffPrompt` and `handoffPreamble`. Superset's "Continue with another agent" and Factory's `/handoff` do the same. It can't rescue a vendor that is rate-limited, since the old session writes the handoff. - # M4 — Merging and history # M5 — Workflows diff --git a/api/openapi.yaml b/api/openapi.yaml index 8807c1c..e6194e0 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -817,7 +817,13 @@ paths: operationId: compactSession description: > Asks the idle session's agent for a handoff (goal, decisions, state, dead ends, open questions, files). When that turn ends, - the session is completed and a new session on the same task and model starts with the handoff as its first message. + the session is completed and a new session on the same task starts with the handoff as its first message, on the requested model + or else the old session's. + requestBody: + required: true + content: + application/json: + schema: { $ref: "#/components/schemas/CompactCreate" } responses: "202": description: The handoff turn was started. @@ -1501,6 +1507,13 @@ components: type: string description: Model for this turn and later ones. When it differs from the session's model, the session switches before the message is sent. + CompactCreate: + type: object + properties: + model: + type: string + description: Model for the new session, on either vendor. The old session still writes the handoff. Defaults to the old session's model. + Blob: type: object required: [id, content_type, created_by, created_at] diff --git a/docs/macos.md b/docs/macos.md index cf6ca6a..438dfbf 100644 --- a/docs/macos.md +++ b/docs/macos.md @@ -93,7 +93,7 @@ Closing the window leaves the app running with its store and streams (`applicati ## Views -- **Transcript and Lead.** `TranscriptBuilder` is a pure function from events to a list of rows: user and agent messages, consecutive tool calls folded into one group with its summary ("Read file ×3"), subagents nested with their status, pending tool calls and running subagents (background ones included after the turn ends) outlined in the accent colour with a 0.6s fade, thinking, the byre prompt collapsed, held turns, `NO_REPLY` turns folded away, handoffs, snapshot rows with changes, fork and review, and notes for the other event kinds. It is incremental: a new batch extends the existing rows. The view is a `ScrollView` with a plain `VStack`, stuck to the bottom unless the user has scrolled more than 80 points up. The stack isn't lazy because a `LazyVStack` estimates the height of rows it hasn't shown yet and corrects it when they scroll into view, without moving the scroll offset, so scrolling up through rows not yet shown jumped by each correction; SwiftUI can't move the offset mid-scroll without stopping its momentum. While the user is scrolling (`onScrollPhaseChange`), content height changes only update whether it is stuck and never pull it back to the bottom. The lead pages back when the view comes within one screen of the top: the fetched page is held while the scroll phase is scrolling and inserted once it is idle (`ChatModel.older`, `prependOlder`), and the next geometry change moves the offset down by the height added, so the rows on screen stay put; a page that adds no rows (all folded `NO_REPLY` turns) fetches the next one at once. Each Markdown text run's `NSTextView` measures its height with one TextKit stack kept in its coordinator, and a repeat measurement at the same width and text returns the stored size. Pending sends show at the end until the server echoes them. A turn summary counts as read when its row is on screen and the app is active (`markSummaryRead`). The head carries Compact (with its context-usage fill), Sync from main, Merge and Discard. +- **Transcript and Lead.** `TranscriptBuilder` is a pure function from events to a list of rows: user and agent messages, consecutive tool calls folded into one group with its summary ("Read file ×3"), subagents nested with their status, pending tool calls and running subagents (background ones included after the turn ends) outlined in the accent colour with a 0.6s fade, thinking, the byre prompt collapsed, held turns, `NO_REPLY` turns folded away, handoffs, snapshot rows with changes, fork and review, and notes for the other event kinds. It is incremental: a new batch extends the existing rows. The view is a `ScrollView` with a plain `VStack`, stuck to the bottom unless the user has scrolled more than 80 points up. The stack isn't lazy because a `LazyVStack` estimates the height of rows it hasn't shown yet and corrects it when they scroll into view, without moving the scroll offset, so scrolling up through rows not yet shown jumped by each correction; SwiftUI can't move the offset mid-scroll without stopping its momentum. While the user is scrolling (`onScrollPhaseChange`), content height changes only update whether it is stuck and never pull it back to the bottom. The lead pages back when the view comes within one screen of the top: the fetched page is held while the scroll phase is scrolling and inserted once it is idle (`ChatModel.older`, `prependOlder`), and the next geometry change moves the offset down by the height added, so the rows on screen stay put; a page that adds no rows (all folded `NO_REPLY` turns) fetches the next one at once. Each Markdown text run's `NSTextView` measures its height with one TextKit stack kept in its coordinator, and a repeat measurement at the same width and text returns the stored size. Pending sends show at the end until the server echoes them. A turn summary counts as read when its row is on screen and the app is active (`markSummaryRead`). The head carries Compact (with its context-usage fill; a long press opens a menu of models to continue on), Sync from main, Merge and Discard. - **Composer.** A `TextEditor`, with paste and drop handled as in "Gaps in SwiftUI". Text, the model menu (filtered to the live session's vendor), Interrupt and Send. Enter sends, Shift-Enter adds a newline, and Enter during IME composition does neither. Pasted or dropped PNG, JPEG, GIF and WebP images become thumbnails with ×, uploaded to `POST /api/blobs` on send; any other image `NSBitmapImageRep` decodes, such as TIFF, is converted to PNG first, its size checked after conversion. A failed send puts the text and images back and shows the error. - **Inbox.** The selected task's oldest open item, rendered from its Markdown context with each choice's marker replaced by a clickable block (pick-one, sends at once) or checkbox (pick-any, with Submit), the "recommended" tag, image-choice grids, attachments, Let the agent decide, Other… and, for errors, Reply… and Dismiss. Arrow keys move between choices. A 409 shows its error. The Changes summary line sits above it. - **Changes, Files, Reviews, Workflow, Project, Status, Settings.** Including the pinned-snapshot stepper, open-diff memory, per-task place in Files, finding diffs with Fix and Ignore, nested subtasks, TODO Start and Discuss, rate-limit pace bars and lead notes. The Workflow tab draws its stage graph natively from the `WorkflowRun` (stages as boxes coloured by state, `after` as edges, laid out top to bottom by depth) with the layout and drawing code from "Diagrams", fed from the run's data rather than Mermaid text. diff --git a/docs/operations.md b/docs/operations.md index 9412c55..e0da471 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -173,7 +173,7 @@ curl -H 'Tailscale-User-Login: you@example.com' -H 'Tailscale-User-Name: You' ht Images: `POST /api/blobs` takes a raw image body (type sniffed from the bytes, PNG, JPEG, GIF or WebP only, at most 5 MiB; `ImageTypes` and `MaxBlobBytes` in `internal/store/blob.go`) and returns its id; `GET /api/blobs/{id}` serves it. A message or session prompt may carry `images`, a list of blob ids (unknown ids are a 400); a message may then have empty text. byre reads each blob when the turn is sent and passes it before the text: to Claude as a base64 `image` content block (`claude.Session.Send`), to Codex as an `image` input with a `data:` URL (`codex.Session.Send`). The `user.message` event records the ids as `images`. In the composer, pasting or dropping an image adds a thumbnail with a × to remove it; images upload when the message is sent, and the transcript shows them on the user's message, each linking to the full image. -Compaction is vendor-agnostic: `POST /api/sessions/{id}/compact` (the transcript's **Compact** button, always shown and enabled only while the task has an idle session) sends the agent `handoffPrompt` (`internal/agents/compact.go`) as a `byre` message, asking for a handoff covering the goal, decisions and why, current state, dead ends, open questions and files. That turn files no inbox summary and isn't bounced for questions. When it ends normally, its `turn.ended` carries `handoff: true`, the session is completed, and a new session on the same task and model starts with `handoffPreamble` plus the handoff as its first message (actor `byre`; its `user.message` carries `continuation: true`). The context meter tracks the new session. The request's `user.message` carries `handoff: true`, and from it the transcript puts the request and everything the agent does in that turn into one collapsed note reading "writing a handoff…", without streaming the agent's text; when the turn ends its summary becomes the `turn.ended` note, or "handoff not written" if the turn ended without one. The transcript never draws the new session's first message (`continuation: true`), so that note, which holds the handoff, is the only marker of the switch. If byre restarts during the handoff turn, the continuation is lost and the old session simply goes idle. +Compaction is vendor-agnostic: `POST /api/sessions/{id}/compact` (the transcript's **Compact** button, always shown and enabled only while the task has an idle session) sends the agent `handoffPrompt` (`internal/agents/compact.go`) as a `byre` message, asking for a handoff covering the goal, decisions and why, current state, dead ends, open questions and files. That turn files no inbox summary and isn't bounced for questions. When it ends normally, its `turn.ended` carries `handoff: true`, the session is completed, and a new session on the same task starts with `handoffPreamble` plus the handoff as its first message (actor `byre`; its `user.message` carries `continuation: true`). The request's optional `model` (the button's long-press menu, `compact_task`'s `model`) picks the new session's model, on either vendor; without it the new session keeps the old one's. The old session still writes the handoff, so this can't get past a vendor that is rate-limited. The chosen model is held in memory (`Manager.handoffModel`) until the handoff turn ends. The context meter tracks the new session. The request's `user.message` carries `handoff: true`, and from it the transcript puts the request and everything the agent does in that turn into one collapsed note reading "writing a handoff…", without streaming the agent's text; when the turn ends its summary becomes the `turn.ended` note, or "handoff not written" if the turn ended without one. The transcript never draws the new session's first message (`continuation: true`), so that note, which holds the handoff, is the only marker of the switch. If byre restarts during the handoff turn, the continuation is lost and the old session simply goes idle. Task agents spawn parallel work as subtasks (see "Subtasks"). diff --git a/internal/agents/compact.go b/internal/agents/compact.go index 9e8ba32..634ab27 100644 --- a/internal/agents/compact.go +++ b/internal/agents/compact.go @@ -24,15 +24,38 @@ const leadHandoffPrompt = `Write a handoff for a fresh lead agent that will take `questions you have surfaced or answered and why; what you last pointed the human's attention at; and anything you promised to do or check. ` + `Be complete: the next agent sees nothing else. Your final message is the handoff, and nothing else.` -func (m *Manager) Compact(ctx context.Context, sessionID string) (api.AgentSession, error) { +func (m *Manager) Compact(ctx context.Context, sessionID, model string) (api.AgentSession, error) { sess, err := m.store.GetSession(ctx, sessionID) if err != nil { return api.AgentSession{}, err } - if sess.Owner != "" { - return m.Send(ctx, sessionID, "byre", leadHandoffPrompt, "") + task, err := m.taskFor(ctx, sess) + if err != nil { + return api.AgentSession{}, err } - return m.Send(ctx, sessionID, "byre", handoffPrompt, "") + prompt := handoffPrompt + if sess.Owner != "" { + prompt = leadHandoffPrompt + } + err = transition(ctx, m.store, sess.Id, api.AgentSessionStateIdle, api.AgentSessionStateRunning, "byre") + if err != nil { + return api.AgentSession{}, err + } + m.mu.Lock() + m.handoffModel[sessionID] = model + m.mu.Unlock() + return m.launch(ctx, sess, task, "byre", prompt, nil) +} + +func (m *Manager) continuationModel(sess api.AgentSession) string { + m.mu.Lock() + model := m.handoffModel[sess.Id] + delete(m.handoffModel, sess.Id) + m.mu.Unlock() + if model == "" { + return sess.Model + } + return model } func isHandoffPrompt(actor, text string) bool { @@ -60,13 +83,14 @@ func (m *Manager) handoff(ctx context.Context, sessionID, handoff string) error if err != nil { return err } + model := m.continuationModel(sess) if sess.Owner != "" { err = m.retire(ctx, sess, "byre") if err != nil { return err } - _, err = m.createLead(ctx, creator, leadHandoffPreamble+handoff, sess.Model, "byre", nil) + _, err = m.createLead(ctx, creator, leadHandoffPreamble+handoff, model, "byre", nil) return err } @@ -88,7 +112,7 @@ func (m *Manager) handoff(ctx context.Context, sessionID, handoff string) error if err != nil { return err } - _, err = m.create(ctx, task, creator, handoffPreamble+handoff, sess.Model, "byre", nil) + _, err = m.create(ctx, task, creator, handoffPreamble+handoff, model, "byre", nil) if errors.Is(err, ErrConflict) { m.startDiscard(task.Id) return nil diff --git a/internal/agents/lead.go b/internal/agents/lead.go index 64e5e57..ef15811 100644 --- a/internal/agents/lead.go +++ b/internal/agents/lead.go @@ -293,7 +293,7 @@ func (m *Manager) leadTurnEnded(ctx context.Context, l *live, res endResult) err go m.continueFromHandoff(l.id, res.result) case wantCompact && finished && !compacting: go func() { - _, err := m.Compact(context.Background(), l.id) + _, err := m.Compact(context.Background(), l.id, "") if err != nil { slog.Error("compact lead", "session", l.id, "err", err) } diff --git a/internal/agents/leadtools.go b/internal/agents/leadtools.go index 13cdf3a..a0b583f 100644 --- a/internal/agents/leadtools.go +++ b/internal/agents/leadtools.go @@ -325,13 +325,24 @@ func (m *Manager) leadTools(l *live) []mcp.Tool { return "Interrupted.", nil }), - tool("compact_task", "Have a task's idle agent write a handoff and continue in a fresh session.", taskOnly, + tool("compact_task", "Have a task's idle agent write a handoff and continue in a fresh session.", + `{"type": "object", "properties": { + "task_id": {"type": "string"}, + "model": {"type": "string", "description": "Start the fresh session on this model, on either vendor; the current agent still writes the handoff. Defaults to the current model."} + }, "required": ["task_id"]}`, func(ctx context.Context, user api.User, raw json.RawMessage) (string, error) { + args := struct { + Model string `json:"model"` + }{} + err := json.Unmarshal(raw, &args) + if err != nil { + return "", err + } sess, err := m.taskSessionArg(ctx, raw) if err != nil { return "", err } - _, err = m.Compact(ctx, sess.Id) + _, err = m.Compact(ctx, sess.Id, args.Model) if err != nil { return "", err } diff --git a/internal/agents/manager.go b/internal/agents/manager.go index 8331976..f22c524 100644 --- a/internal/agents/manager.go +++ b/internal/agents/manager.go @@ -56,6 +56,7 @@ type Manager struct { startedTodo map[string]time.Time startRefused map[string]bool finishing map[string]bool + handoffModel map[string]string deliverMu sync.Mutex deliverLocks map[string]*sessionLock @@ -141,6 +142,7 @@ func New(st *store.Store, worktreeRoot, leadRoot, codexHome string, status func( startedTodo: map[string]time.Time{}, startRefused: map[string]bool{}, finishing: map[string]bool{}, + handoffModel: map[string]string{}, signals: make(chan []api.Event, 1024), snaps: map[string]*snapState{}, merges: map[string]*projectMerge{}, diff --git a/internal/api/api.gen.go b/internal/api/api.gen.go index 5efca69..40bfd92 100644 --- a/internal/api/api.gen.go +++ b/internal/api/api.gen.go @@ -714,6 +714,12 @@ type ClientRequest struct { // ClientRequestOp defines model for ClientRequest.Op. type ClientRequestOp string +// CompactCreate defines model for CompactCreate. +type CompactCreate struct { + // Model Model for the new session, on either vendor. The old session still writes the handoff. Defaults to the old session's model. + Model *string `json:"model,omitempty"` +} + // ConnectedClient defines model for ConnectedClient. type ConnectedClient struct { // Commit The git commit the app was built from @@ -1527,6 +1533,9 @@ type StartTodoItemJSONRequestBody = TodoStart // SetFindingStateJSONRequestBody defines body for SetFindingState for application/json ContentType. type SetFindingStateJSONRequestBody = FindingStateUpdate +// CompactSessionJSONRequestBody defines body for CompactSession for application/json ContentType. +type CompactSessionJSONRequestBody = CompactCreate + // SendMessageJSONRequestBody defines body for SendMessage for application/json ContentType. type SendMessageJSONRequestBody = MessageCreate @@ -3735,214 +3744,215 @@ var swaggerSpec = []string{ "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", - "QYjy5dIsb9GMnQVmB/f5vQrIfPz4fwYA", + "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", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/server/server.go b/internal/server/server.go index 9a493f2..10a8843 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -810,7 +810,15 @@ func (s *Server) WithdrawMessage(w http.ResponseWriter, r *http.Request, taskID } func (s *Server) CompactSession(w http.ResponseWriter, r *http.Request, sessionID string) { - sess, err := s.agents.Compact(r.Context(), sessionID) + req := api.CompactCreate{} + if !readJSON(w, r, &req) { + return + } + model := "" + if req.Model != nil { + model = *req.Model + } + sess, err := s.agents.Compact(r.Context(), sessionID, model) if err != nil { writeAgentError(w, err) return diff --git a/mac/Sources/Byre/Chat.swift b/mac/Sources/Byre/Chat.swift index 26da27b..e6a6241 100644 --- a/mac/Sources/Byre/Chat.swift +++ b/mac/Sources/Byre/Chat.swift @@ -470,17 +470,10 @@ struct CompactButton: View { let level = pct >= 90 ? Palette.danger : pct >= 70 ? Palette.warn : Palette.accent let detail = usage.map { u in u.window > 0 ? "\ncontext: \(u.used.formatted()) of \(u.window.formatted()) tokens\(u.model.isEmpty ? "" : " (\(u.model))")" : "" } ?? "" let disabled = sessionId == nil || state != .idle || sending - Button { - guard let sessionId else { - return - } - sending = true - Task { - do { - _ = try await store.api.client.compactSession(path: .init(sessionId: sessionId)).accepted - } catch { - overlays.showAlert(errorText(error)) - sending = false + Menu { + ForEach(models, id: \.self) { m in + Button("Continue on \(m)") { + compact(m) } } } label: { @@ -504,14 +497,34 @@ struct CompactButton: View { .overlay(RoundedRectangle(cornerRadius: 6).stroke(pct >= 70 ? level : Palette.border)) .opacity(disabled ? 0.45 : 1) .contentShape(Rectangle()) + } primaryAction: { + compact(nil) } + .menuStyle(.button) + .menuIndicator(.hidden) .buttonStyle(.plain) + .fixedSize() .disabled(disabled) - .help("Ask the agent for a handoff, then continue in a new session with a fresh context\(detail)") + .help("Ask the agent for a handoff, then continue in a new session with a fresh context; hold to continue on another model\(detail)") .onChange(of: state) { sending = false } } + + private func compact(_ model: String?) { + guard let sessionId else { + return + } + sending = true + Task { + do { + _ = try await store.api.client.compactSession(path: .init(sessionId: sessionId), body: .json(.init(model: model))).accepted + } catch { + overlays.showAlert(errorText(error)) + sending = false + } + } + } } private struct ScrollMetrics: Equatable {