diff --git a/api/openapi.yaml b/api/openapi.yaml index 1927ca5..cc3809b 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -61,6 +61,23 @@ paths: schema: { $ref: "#/components/schemas/User" } "400": { $ref: "#/components/responses/Error" } + /api/me/review-models: + put: + operationId: updateReviewModels + description: Sets the models that review the calling user's tasks. + requestBody: + required: true + content: + application/json: + schema: { $ref: "#/components/schemas/ReviewModels" } + responses: + "200": + description: The updated user. + content: + application/json: + schema: { $ref: "#/components/schemas/User" } + "400": { $ref: "#/components/responses/Error" } + /api/me/lead/sessions: get: operationId: listLeadSessions @@ -1122,7 +1139,7 @@ components: User: type: object - required: [login, display_name, git_name, git_email, notification_prefs, default_model] + required: [login, display_name, git_name, git_email, notification_prefs, default_model, review_model, second_review_model] properties: login: { type: string } display_name: { type: string } @@ -1130,6 +1147,8 @@ components: git_email: { type: string } notification_prefs: { $ref: "#/components/schemas/NotificationPrefs" } default_model: { type: string, description: The model the app starts new tasks on. } + review_model: { type: string, description: The model that reviews this user's tasks, unless it wrote the work under review. } + second_review_model: { type: string, description: The model that reviews this user's tasks when review_model wrote the work under review. } DefaultModel: type: object @@ -1137,6 +1156,13 @@ components: properties: model: { type: string } + ReviewModels: + type: object + required: [review_model, second_review_model] + properties: + review_model: { type: string } + second_review_model: { type: string } + NotificationPrefs: type: object description: Which new questions, finished turns, errors and rate limits notify this user in their open byre pages. diff --git a/docs/operations.md b/docs/operations.md index 5088de9..ed55937 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -321,7 +321,7 @@ The running macOS app posts a notification for each new question, error and rate - **Clearing.** A delivered notification leaves Notification Center once it is dealt with anywhere, on this Mac, another one or by the lead: an `inbox.updated` event whose item is no longer `open` removes the item's notification (`clearInbox`), and a `summary.read` event removes that task's `turn-` notifications up to its `seq` (`clearTurns`). - **Clicking** a notification activates the app, shows its window and points the right pane at the item's task. -The left pane's **Settings** tab asks macOS for notification permission and edits the preferences, and also holds the Default model menu (see "Agent sessions"). +The left pane's **Settings** tab asks macOS for notification permission and edits the preferences, and also holds the Default model menu (see "Agent sessions") and the two Review models menus (see "Reviews"). Each question also shows in the task's transcript where it was asked, as a bubble (`QuestionBubble` in `mac/Sources/Byre/Chat.swift`) holding its `question` text and its state: "waiting for your answer" in the warn colours while it is open, then who chose which options or the first line of who answered what, "dismissed by" whoever dismissed it, or "withdrawn by the agent". The transcript builds it from the item's `inbox.created` event and updates it from each later `inbox.updated` event of the same item. Clicking a bubble shows that question in the Questions tab (`Store.showQuestion`, held in `Store.question` with its task id), open or not. An item that is no longer open shows read-only: its header adds its state, its chosen options are marked "chosen", its answers are listed under it, and it has no Other, Let the agent decide or Submit. The item comes from `Store.inbox` while it is open and otherwise from its latest `inbox.created` or `inbox.updated` event in the task's feed (`Store.questionItem`). Switching tab or task in any other way, including clicking the Questions tab itself, clears the pick, so the tab goes back to the task's oldest open item; answering the picked question clears it too. @@ -412,7 +412,7 @@ The fork's session guidance gets one more line (`forkGuidance` in `internal/agen Every new snapshot of a task gets a review: a separate agent session on the vendor the task's agent doesn't use reads the change and reports on it (`internal/agents/review.go`, `internal/store/review.go`). A turn that changes no files makes no snapshot and so no review, an interrupted turn makes no snapshot (see "Snapshots"), and a snapshot whose change (the diff below) has no files runs no reviewer: it gets a `reviews` row in state `skipped`, with no session, vendor or model. The snapshot at the end of a Merge turn that finishes into the squash (the turn ended cleanly with `merging_by` still set, read by `turnEnded` before it asks for the snapshot) gets no review and no `reviews` row at all, since the task closes a moment later; a Merge turn that errors or calls `stop_merge` is reviewed as usual. Besides `take_snapshot` (see "Snapshots"), nothing else starts a review, and nothing waits for one: reviews ride along for the human to look at when they want. -- **Starting.** After `takeSnapshot` creates a snapshot, `afterSnapshot` runs `startReviewer`: it picks the vendor opposite the task's latest implementer session (`reviewVendor`: Claude Code for a Codex implementer, Codex for the others) and that vendor's model in `reviewModels`; when that vendor's CLI (`vendorCommands`: `claude`, `codex`, `agy`) isn't on the service's `PATH`, it uses the implementer's own vendor and model instead (`reviewerModel`). It then checks the snapshot's commit out detached at `worktrees//review-`, creates an `agent_sessions` row with `role` `reviewer` on the task (created by the task's creator), a `reviews` row (`running`, one per snapshot), and sends `reviewPrompt` as its first turn (actor `byre`): all of the task's work as `git diff` from the merge-base of the snapshot and the default branch, with its changed files, and the task's first message to its agent. Every review covers the whole task against the default branch, not only what changed since the previous snapshot, and a snapshot with no changes against it is `skipped`. +- **Starting.** After `takeSnapshot` creates a snapshot, `afterSnapshot` runs `startReviewer`: it picks the model from the task creator's `users.review_model` and `users.second_review_model` (`reviewerModel`): the second review model when the task's latest implementer session runs exactly the review model, the review model otherwise, and the vendor follows from the model. They are returned as `review_model` and `second_review_model` on `GET /api/me`, set together with `PUT /api/me/review-models` from the Settings tab's Review models menus, and record `user.updated`. A model whose vendor's CLI isn't on the service's `PATH` fails the review with the start error. It then checks the snapshot's commit out detached at `worktrees//review-`, creates an `agent_sessions` row with `role` `reviewer` on the task (created by the task's creator), a `reviews` row (`running`, one per snapshot), and sends `reviewPrompt` as its first turn (actor `byre`): all of the task's work as `git diff` from the merge-base of the snapshot and the default branch, with its changed files, and the task's first message to its agent. Every review covers the whole task against the default branch, not only what changed since the previous snapshot, and a snapshot with no changes against it is `skipped`. - **Running.** Reviewer sessions get `reviewGuidance` and only the `submit_review` tool, whose arguments (`reviewSchema`: `change`, a few sentences of Markdown on what the change does, required and non-empty; a Markdown `summary`, which the guidance and schema require to be exactly "No significant findings." when there are no findings and otherwise a bulleted list with one line per finding; `findings`, each with `severity`, `category`, `title`, `detail`, `path`, `line`, `end_line` and `images`; and top-level `images`) become the review's `result` and mark it `done`. The guidance encourages, without requiring, Mermaid blocks for a data flow, call graph, state machine or schema the change alters, and screenshots when the change alters something visible. - **Forwarding.** When a submitted review has findings, byre sends them to the task's live agent as a `byre` message (`forwardFindings` and `findingsMessage` in `internal/agents/review.go`): each finding's severity, title, location and detail, under a preamble asking the agent to check each one against the code and its brief, act on those that hold up, and say in its final message which it acted on and which it left and why. It goes through `Manager.Message`, so it is queued like any message while the agent is mid-turn. A task with no live agent session gets nothing, and the log says `review findings not forwarded`. Forwarding doesn't set any finding's state; **fix** and **ignore** stay available. - **Screenshots.** Reviewer sessions also get the Playwright MCP server (`playwrightMCP` in `internal/agents/review.go`: `npx @playwright/mcp` at a pinned version, headless Chrome, isolated profile, absolute file paths), passed to Claude as a `stdio` entry in `--mcp-config` and to Codex as `mcp_servers` in the thread's `config`. Its automatically named files go to `worktrees//review--media`, removed with the checkout. Each `images` entry is `{path, caption}`, the path absolute or relative to the checkout; at `submit_review` byre reads every one, refuses the whole submission (nothing recorded) for a missing file or one that isn't one of `store.ImageTypes` within `store.MaxBlobBytes`, then stores each as a blob and replaces its `path` with `blob`, since the files are deleted with the checkout. They run without the Stop-hook bounce, mid-turn delivery, end-of-turn commit, snapshots or turn summaries, and their `user.message` events carry no `head`. When the reviewer's turn ends byre completes its session, kills its process and removes the worktree; a review still `running` then fails with why (no submission, with the final message; an error; an interrupt). A process that exits mid-turn fails the review the same way. `StopReview` (`POST /api/reviews/{reviewId}/stop`, the Stop button on a running review's card) ends the reviewer the same way and fails the review ("the reviewer was stopped"), and `Watch` calls it for a reviewer whose process the health check finds `stuck` (no stream event for `StuckAfter`), which is how a reviewer whose connection died while the machine slept gets cleared. Merging or discarding the task fails its running reviews ("the task was closed") and ends their reviewers. On startup, a running reviewer resumes like any session, and a running review whose reviewer isn't `running` fails. diff --git a/internal/agents/lead.go b/internal/agents/lead.go index 6e6637d..21cf3e4 100644 --- a/internal/agents/lead.go +++ b/internal/agents/lead.go @@ -29,7 +29,7 @@ const leadGuidance = `You are the human's lead agent in byre, shown in the left - Questions from task agents: answer one yourself with answer_question only when the answer is clear, for example the agent's recommendation is plainly right given what the human has said, the human already decided it, or one of your notes settles it outright. Otherwise show it to the human with your recommendation and wait. When the human tells you an answer, give it with answer_question. Say which questions you answered and how, naming the note by its id when one decided it. - Notes: you learn how the human works and keep it with remember, forget and list_notes. byre adds every note to your instructions at the start of each lead session, so they outlast compaction; the human can read and delete them in the Settings tab. Write a note when the human shows a priority, a preference or the reasoning behind a choice that will recur: an answer that departs from the agent's recommendation (the answered signal shows both), a correction or overrule of you or a task agent, or a statement of how they want things done. Record the choice and the why, in their terms, general enough to apply to the next case and specific enough to act on, for example "Prefers replacing a state label over adding a tag beside it: keeps the picker uncluttered." File each note under the project it is about with project_id when it concerns that project's code, UI, docs or process, and with no project_id only when it holds for how the human works everywhere; apply a project's notes only to that project's tasks. Task agents start with their creator's every-project notes and their project's, and suggest new ones with suggest_note, which reaches you as a signal: save a suggestion only when it holds and your notes don't already cover it, choosing its project yourself, and otherwise drop it; neither needs a word to the human. Don't note one-off facts about a single task, and don't duplicate: update an existing note with remember and its id instead. When the human contradicts a note, update it or forget it. Before recommending anything, check your notes, and when one shaped the recommendation, cite its id. - Finished turns: read them and show the human only what matters: work finished and ready to merge, problems, decisions made. Stay quiet about routine progress. -- Reviews: after each new snapshot of a task, a reviewer agent from the other vendor reviews the change. The results are on the task's reviews tab, and read_transcript shows each review's findings. They are for the human to look at when they want; mention one only when its findings matter to what the human is deciding. +- Reviews: after each new snapshot of a task, a reviewer agent reviews the change, on the human's review model, or their second review model when the review model wrote the work. The results are on the task's reviews tab, and read_transcript shows each review's findings. They are for the human to look at when they want; mention one only when its findings matter to what the human is deciding. - Dig into context with list_tasks, read_transcript, read_inbox and read_status (vendor rate limits and agent health), and with your own Read, Grep and Bash on a task's worktree path (from list_tasks). Don't edit files in task worktrees; ask the task's agent with send_message. - You can create tasks, start TODO items, message, interrupt and compact task agents, and merge or discard tasks. Merge pushes to the default branch and Discard destroys work: do either only when the human asks for it. - Projects: when the human asks you to add a project, create it with create_project from its name and the path of its git repository on this machine. diff --git a/internal/agents/review.go b/internal/agents/review.go index f7a0d71..1870b1c 100644 --- a/internal/agents/review.go +++ b/internal/agents/review.go @@ -8,7 +8,6 @@ import ( "log/slog" "net/http" "os" - "os/exec" "path/filepath" "strings" "time" @@ -17,12 +16,11 @@ import ( "g.fc.run/ai/byre/internal/git" "g.fc.run/ai/byre/internal/mcp" "g.fc.run/ai/byre/internal/store" + "g.fc.run/ai/byre/internal/workflow" ) const maxReviewFiles = 200 -var reviewModels = map[api.AgentSessionVendor]string{api.Claude: "claude-opus-5-5", api.Codex: "gpt-6.1-sol"} - var severities = []string{"critical", "high", "medium", "low", "info"} const reviewGuidance = `You are a reviewer running inside byre. Another agent is doing a task; you review all of its work so far, and a human may read your review in byre's app. @@ -116,32 +114,19 @@ func playwrightMCP(outputDir string) mcp.Stdio { } } -var vendorCommands = map[api.AgentSessionVendor]string{api.Claude: "claude", api.Codex: "codex", api.Antigravity: "agy"} - -func (m *Manager) implementerModel(ctx context.Context, taskID string) (api.AgentSessionVendor, string) { - sessions, err := m.store.ListSessions(ctx, taskID) - if err != nil || len(sessions) == 0 { - return api.Claude, reviewModels[api.Claude] - } - last := sessions[len(sessions)-1] - return last.Vendor, last.Model -} - -func reviewVendor(implementer api.AgentSessionVendor) api.AgentSessionVendor { - if implementer == api.Codex { - return api.Claude - } - return api.Codex -} - -func (m *Manager) reviewerModel(ctx context.Context, taskID string) (api.AgentSessionVendor, string) { - implVendor, implModel := m.implementerModel(ctx, taskID) - vendor := reviewVendor(implVendor) - _, err := exec.LookPath(vendorCommands[vendor]) +func (m *Manager) reviewerModel(ctx context.Context, task api.Task) (string, error) { + creator, err := m.store.GetUser(ctx, task.CreatedBy) if err != nil { - return implVendor, implModel + return "", err } - return vendor, reviewModels[vendor] + sessions, err := m.store.ListSessions(ctx, task.Id) + if err != nil { + return "", err + } + if len(sessions) > 0 && sessions[len(sessions)-1].Model == creator.ReviewModel { + return creator.SecondReviewModel, nil + } + return creator.ReviewModel, nil } func (m *Manager) startReviewer(ctx context.Context, task api.Task, snap api.Snapshot) error { @@ -149,7 +134,11 @@ func (m *Manager) startReviewer(ctx context.Context, task api.Task, snap api.Sna if err != nil { return err } - vendor, model := m.reviewerModel(ctx, task.Id) + model, err := m.reviewerModel(ctx, task) + if err != nil { + return err + } + vendor := workflow.VendorOf(model) prompt, err := m.reviewPrompt(ctx, task, project, snap) if err != nil { return err diff --git a/internal/api/api.gen.go b/internal/api/api.gen.go index 1b1c0ef..6ec29b0 100644 --- a/internal/api/api.gen.go +++ b/internal/api/api.gen.go @@ -1095,6 +1095,12 @@ type Review struct { // ReviewState skipped: the snapshot's step changed no files, so no reviewer ran. type ReviewState string +// ReviewModels defines model for ReviewModels. +type ReviewModels struct { + ReviewModel string `json:"review_model"` + SecondReviewModel string `json:"second_review_model"` +} + // SessionCreate defines model for SessionCreate. type SessionCreate struct { // Images Blob ids from uploadBlob, sent to the agent as images alongside the prompt. @@ -1412,6 +1418,12 @@ type User struct { // NotificationPrefs Which new questions, finished turns, errors and rate limits notify this user in their open byre pages. NotificationPrefs NotificationPrefs `json:"notification_prefs"` + + // ReviewModel The model that reviews this user's tasks + ReviewModel string `json:"review_model"` + + // SecondReviewModel The model that reviews this user's tasks when review_model wrote the work under review. + SecondReviewModel string `json:"second_review_model"` } // UserUpdate defines model for UserUpdate. @@ -1586,6 +1598,9 @@ type UpdateNotificationPrefsJSONRequestBody = NotificationPrefs // SetPaneFocusJSONRequestBody defines body for SetPaneFocus for application/json ContentType. type SetPaneFocusJSONRequestBody = PaneFocus +// UpdateReviewModelsJSONRequestBody defines body for UpdateReviewModels for application/json ContentType. +type UpdateReviewModelsJSONRequestBody = ReviewModels + // CreateProjectJSONRequestBody defines body for CreateProject for application/json ContentType. type CreateProjectJSONRequestBody = ProjectCreate @@ -1688,6 +1703,9 @@ type ServerInterface interface { // (PUT /api/me/pane-focus) SetPaneFocus(w http.ResponseWriter, r *http.Request) + // (PUT /api/me/review-models) + UpdateReviewModels(w http.ResponseWriter, r *http.Request) + // (GET /api/me/summary-reads) GetSummaryReads(w http.ResponseWriter, r *http.Request) @@ -2352,6 +2370,20 @@ func (siw *ServerInterfaceWrapper) SetPaneFocus(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } +// UpdateReviewModels operation middleware +func (siw *ServerInterfaceWrapper) UpdateReviewModels(w http.ResponseWriter, r *http.Request) { + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateReviewModels(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // GetSummaryReads operation middleware func (siw *ServerInterfaceWrapper) GetSummaryReads(w http.ResponseWriter, r *http.Request) { @@ -3776,6 +3808,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/api/me", wrapper.UpdateMe) m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/api/me/notifications", wrapper.UpdateNotificationPrefs) m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/api/me/default-model", wrapper.UpdateDefaultModel) + m.HandleFunc(http.MethodPut+" "+options.BaseURL+"/api/me/review-models", wrapper.UpdateReviewModels) m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/me/lead/sessions", wrapper.ListLeadSessions) m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/api/me/lead/events", wrapper.ListLeadEvents) m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/api/me/lead/messages", wrapper.MessageLead) @@ -3847,263 +3880,266 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H // const string: with thousands of chunks the chained `+` fold is several // times slower for the Go compiler than parsing a slice literal. var swaggerSpec = []string{ - "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", } // decodeSpec returns the embedded OpenAPI spec as raw JSON bytes, diff --git a/internal/server/notifications.go b/internal/server/notifications.go index c267712..a9e620b 100644 --- a/internal/server/notifications.go +++ b/internal/server/notifications.go @@ -40,3 +40,22 @@ func (s *Server) UpdateDefaultModel(w http.ResponseWriter, r *http.Request) { } writeJSON(w, http.StatusOK, u) } + +func (s *Server) UpdateReviewModels(w http.ResponseWriter, r *http.Request) { + req := api.ReviewModels{} + if !readJSON(w, r, &req) { + return + } + + if strings.TrimSpace(req.ReviewModel) == "" || strings.TrimSpace(req.SecondReviewModel) == "" { + writeError(w, http.StatusBadRequest, errors.New("review_model and second_review_model are required")) + return + } + + u, err := s.store.UpdateReviewModels(r.Context(), actor(r), req.ReviewModel, req.SecondReviewModel) + if err != nil { + writeStoreError(w, err) + return + } + writeJSON(w, http.StatusOK, u) +} diff --git a/internal/store/migrations/058-add-user-review-models.sql b/internal/store/migrations/058-add-user-review-models.sql new file mode 100644 index 0000000..31ac0fa --- /dev/null +++ b/internal/store/migrations/058-add-user-review-models.sql @@ -0,0 +1,2 @@ +ALTER TABLE users ADD COLUMN review_model TEXT NOT NULL DEFAULT 'gpt-6.1-sol'; +ALTER TABLE users ADD COLUMN second_review_model TEXT NOT NULL DEFAULT 'claude-opus-5-5'; diff --git a/internal/store/notifications.go b/internal/store/notifications.go index 0accfb8..a0a6be5 100644 --- a/internal/store/notifications.go +++ b/internal/store/notifications.go @@ -39,3 +39,17 @@ func (s *Store) UpdateDefaultModel(ctx context.Context, login, model string) (ap } return s.GetUser(ctx, login) } + +func (s *Store) UpdateReviewModels(ctx context.Context, login, model, second string) (api.User, error) { + err := s.write(ctx, func(tx *sql.Tx, emit emitFunc) error { + _, err := tx.ExecContext(ctx, `UPDATE users SET review_model = ?, second_review_model = ? WHERE login = ?`, model, second, login) + if err != nil { + return err + } + return emit(api.Event{Kind: "user.updated", Actor: login, Payload: map[string]any{"login": login}}) + }) + if err != nil { + return api.User{}, err + } + return s.GetUser(ctx, login) +} diff --git a/internal/store/store.go b/internal/store/store.go index bf193cc..98b96df 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -218,8 +218,8 @@ func (s *Store) EnsureUser(ctx context.Context, login, displayName string) (api. func (s *Store) GetUser(ctx context.Context, login string) (api.User, error) { u := api.User{} prefs := "" - err := s.db.QueryRowContext(ctx, `SELECT login, display_name, git_name, git_email, notification_prefs, default_model FROM users WHERE login = ?`, login). - Scan(&u.Login, &u.DisplayName, &u.GitName, &u.GitEmail, &prefs, &u.DefaultModel) + err := s.db.QueryRowContext(ctx, `SELECT login, display_name, git_name, git_email, notification_prefs, default_model, review_model, second_review_model FROM users WHERE login = ?`, login). + Scan(&u.Login, &u.DisplayName, &u.GitName, &u.GitEmail, &prefs, &u.DefaultModel, &u.ReviewModel, &u.SecondReviewModel) if errors.Is(err, sql.ErrNoRows) { return u, ErrNotFound } diff --git a/mac/Sources/Byre/Settings.swift b/mac/Sources/Byre/Settings.swift index 9b718f4..ccfb536 100644 --- a/mac/Sources/Byre/Settings.swift +++ b/mac/Sources/Byre/Settings.swift @@ -34,7 +34,21 @@ struct SettingsView: View { Text("New tasks you start from byre run on this model.") .foregroundStyle(Palette.muted) .fixedSize(horizontal: false, vertical: true) - DefaultModelMenu() + ModelMenu(current: store.defaultModel, help: "Model for new tasks") { m in + try await store.api.client.updateDefaultModel(body: .json(.init(model: m))).ok.body.json + } + if let me = store.me { + heading("Review models") + Text("The first model reviews your tasks' work. The second reviews work the first model wrote.") + .foregroundStyle(Palette.muted) + .fixedSize(horizontal: false, vertical: true) + ModelMenu(current: me.reviewModel, help: "Model that reviews your tasks") { m in + try await store.api.client.updateReviewModels(body: .json(.init(reviewModel: m, secondReviewModel: me.secondReviewModel))).ok.body.json + } + ModelMenu(current: me.secondReviewModel, help: "Model that reviews work the first review model wrote") { m in + try await store.api.client.updateReviewModels(body: .json(.init(reviewModel: me.reviewModel, secondReviewModel: m))).ok.body.json + } + } heading("This Mac's permissions") Text("The macOS privacy grants byre's app needs for agents to see and control this Mac. Checking asks macOS for any that are missing.") .foregroundStyle(Palette.muted) @@ -172,7 +186,10 @@ private struct PrefsBox: View { } } -private struct DefaultModelMenu: View { +private struct ModelMenu: View { + let current: String + let help: String + let pick: (String) async throws -> User @Environment(Store.self) private var store @Environment(Overlays.self) private var overlays @@ -182,7 +199,7 @@ private struct DefaultModelMenu: View { Button(m) { Task { do { - store.me = try await store.api.client.updateDefaultModel(body: .json(.init(model: m))).ok.body.json + store.me = try await pick(m) } catch { overlays.showAlert(errorText(error)) } @@ -191,7 +208,7 @@ private struct DefaultModelMenu: View { } } label: { HStack(spacing: 8) { - Text(store.defaultModel) + Text(current) Image(systemName: "chevron.up.chevron.down") .font(.system(size: 9, weight: .semibold)) } @@ -203,7 +220,7 @@ private struct DefaultModelMenu: View { .buttonStyle(.plain) .menuIndicator(.hidden) .fixedSize() - .help("Model for new tasks") + .help(help) .padding(.top, 8) } }