@meistrari/remy-cli 1.22.0-rc.0 → 1.22.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +15 -3
  2. package/dist/remy.js +592 -153
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -62,7 +62,7 @@ In a session, `Esc` dismisses open command/path suggestions or help before it ca
62
62
 
63
63
  Every terminal follow-up is appended as an explicit **Steer**, so it targets the work currently in progress. Queuing a message for a later turn (**Next**) is Web-only for now. Remy can replay sessions containing queued-message dispatch, withdrawal, and failure events. Messages withdrawn or failed before reaching Remy show an activity notice; an active submission ends as cancelled or failed instead of waiting for a turn that never started.
64
64
 
65
- Use Up/Down to select a session in the dashboard, Left/Right to load the adjacent page, and `Enter` to open it. Remy loads the complete retained conversation before showing the session view, then streams new activity as it arrives. Press `s` to search the loaded page by session ID, title, or number; `Enter` keeps the search active and `Esc` clears it. Press `f` to filter sessions by lifecycle status or `a` to filter by author. Both pickers use checkboxes: Up/Down or `j`/`k` moves, `Space` toggles, Right/`l` checks, Left/`h` clears, `G` and `gg` jump to the last and first option, and `Enter` applies every checked value. An empty picker means all values. Press `s` inside either picker to fuzzy-search its options; `Enter` keeps the matching list and `Esc` cancels the search. Press `Esc` outside search to discard staged checkbox changes. Filters apply to the complete remote result set and reset pagination to its first page. After the dashboard list or repository-review list has focus, Vim keys work too: `j`/`k` move, `h`/`l` go to the previous/next dashboard page (or clear/mark a repository), `G` goes to the last row, and `gg` goes to the first row. Press `Shift+L` in the dashboard to start a logout confirmation. In any message composer, plain `Enter` and `Shift+Enter` submit; `Option+Enter` on macOS (`Alt+Enter` elsewhere) inserts a newline. `Ctrl+J` also inserts a newline for terminals that do not report the Option/Alt modifier. The conversation header keeps the numbered session title on its first line and repository, pull request, work state, elapsed time, and connection state on its second line. The header also keeps the last provider-reported context observation across reconnects, such as `Context 50% left · 62,000 used`; when the provider does not report a context window, it shows only used tokens. This is an observation, not a live occupancy guarantee or billing total.
65
+ Use Up/Down to select a session in the dashboard, Left/Right to load the adjacent page, and `Enter` to open it. Remy loads the complete retained conversation before showing the session view, then streams new activity as it arrives. Press `s` to search the loaded page by session ID, title, or number; `Enter` keeps the search active and `Esc` clears it. Press `f` to filter sessions by lifecycle status or `a` to filter by author. Both pickers use checkboxes: Up/Down or `j`/`k` moves, `Space` toggles, Right/`l` checks, Left/`h` clears, `G` and `gg` jump to the last and first option, and `Enter` applies every checked value. An empty picker means all values. Press `s` inside either picker to fuzzy-search its options; `Enter` keeps the matching list and `Esc` cancels the search. Press `Esc` outside search to discard staged checkbox changes. Filters apply to the complete remote result set and reset pagination to its first page. After the dashboard list or repository-review list has focus, Vim keys work too: `j`/`k` move, `h`/`l` go to the previous/next dashboard page (or clear/mark a repository), `G` goes to the last row, and `gg` goes to the first row. Press `Shift+L` in the dashboard to start a logout confirmation. In any message composer, plain `Enter` and `Shift+Enter` submit; `Option+Enter` on macOS (`Alt+Enter` elsewhere) inserts a newline. `Ctrl+J` also inserts a newline for terminals that do not report the Option/Alt modifier. The conversation header keeps the numbered session title on its first line and repository, pull request, work state, elapsed time, connection state, and the agent's current `Harness · Model · Effort` on its second line. The header also keeps the last provider-reported context observation across reconnects, such as `Context 50% left · 62,000 used`; when the provider does not report a context window, it shows only used tokens. This is an observation, not a live occupancy guarantee or billing total.
66
66
 
67
67
  If a connected session loses its activity stream, Remy retries for up to two minutes and resumes from the last received event. After the live stream stays connected for at least 30 seconds, the next disconnect starts a fresh retry window. Connections that drop sooner share the existing window and backoff. While a submitted message is still awaiting its outcome, retries continue beyond that window.
68
68
 
@@ -86,6 +86,8 @@ Terminal previews show up to 50 content blocks and 8,000 characters per block, w
86
86
 
87
87
  Command and attachment feedback share progress, success, failure, and attention indicators. Failed stop requests show the reason and `esc` retry; failed complete/cancel requests restore the message prompt and show the retry command. Logout shows a confirmation with `y` to confirm and `Esc` to cancel.
88
88
 
89
+ **Change the model or effort:** enter `/model` or `/effort` to pick a new model or reasoning effort for your next message. The model list contains only the session's harness (a Claude session offers Claude models, a Codex session Codex models), in the same order and with the same labels as the new-session wizard. Arrows move, `Enter` stages the pick, and `Esc` closes the picker without changing what is already staged. Nothing is sent until you send a message: the change travels with it and stays the session's setting afterward. Because every terminal follow-up is a Steer, a change sent while Remy is working switches the running turn from its next model request; otherwise it applies from the turn your message starts. The header shows the staged change as `→ Sonnet 5 · High (next message)`, then `(switching…)` until the runtime applies it. The timeline then records `Switched to Sonnet 5 · High` right after your message, or `Switched to Sonnet 5 · High (from next turn)` when the running turn could not switch; its details (`Ctrl+O`) then show the provider's reason when one was given. Picking the current value removes it from the staged change.
90
+
89
91
  Enter `/compact` to admit a durable main-thread context compaction control without sending a human message. Remy reports request admission immediately and shows the eventual completed, no-op, failed, or unknown provider result in retained activity. Compaction waits for a safe point and does not interrupt active work or jump ahead of an earlier Next message. While admission is pending, you can keep editing or open other commands; repeated `/compact` invocations do not send another request.
90
92
 
91
93
  Drag to select visible text in any Remy view; Remy copies it to the local clipboard and emits OSC 52 for terminal or remote-session clipboard support, then clears the selection highlight. Published file artifacts show their filename and muted, full web preview URL; open the URL in a browser to select that artifact in its session. Tela Page rows retain their canonical Page URL. Downloads are explicit through `/files`; artifact bytes are never printed in the terminal. When the conversation has focus, press `Tab` to return to the composer.
@@ -96,6 +98,8 @@ Drag to select visible text in any Remy view; Remy copies it to the local clipbo
96
98
  | `/complete` | Complete an open session after its active turn stops. |
97
99
  | `/cancel` | Cancel the current session, including an active turn. |
98
100
  | `/compact` | Admit a main-thread context compaction request without sending a message; the provider result appears in retained activity. |
101
+ | `/model` | Pick a model of the session's harness for your next message. |
102
+ | `/effort` | Pick a reasoning effort for your next message. |
99
103
  | `/sessions` | Return to the dashboard. |
100
104
  | `/new` | Start another new-session flow. |
101
105
  | `/logout` | Sign out of Remy after confirmation. |
@@ -126,7 +130,7 @@ The interactive dashboard is the recommended path. Use these commands when a scr
126
130
  remy new --repository owner/repository "Add a health check endpoint"
127
131
  ```
128
132
 
129
- Repeat `--repository` to select more repositories from the same GitHub installation. If you do not select a repository, supply `--installation <github-installation-id>`. Repeat `--attach <path>` to upload files or directories; the 20 MiB per-attachment limit is measured directly for a file and across all regular files before compressing a directory. Remy sends each accepted directory as a gzip-compressed tar archive. Direct creation uses `medium` reasoning unless `--reasoning-effort` overrides it; omit `--model` to use the server's `gpt-6-astra` default. `remy new` creates the session from the prompt and flags, then opens it when the terminal is interactive.
133
+ Repeat `--repository` to select more repositories from the same GitHub installation. If you do not select a repository, supply `--installation <github-installation-id>`. Repeat `--attach <path>` to upload files or directories; the 20 MiB per-attachment limit is measured directly for a file and across all regular files before compressing a directory. Remy sends each accepted directory as a gzip-compressed tar archive. Direct creation uses `medium` reasoning unless `--reasoning-effort` overrides it; omit `--model` to use the server's Codex `gpt-6-astra` default. `--model` accepts a Codex model (`gpt-6-astra`, `gpt-6-sol`, `gpt-6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-5.6-luna`, `gpt-5.5`) or a Claude model (`claude-opus-5-5`, `claude-sonnet-5`, `claude-fable-5-1`); the model chooses the session's harness, which stays fixed for the session. For example, `remy new --model claude-opus-5-5 --repository owner/repository "Add a health check endpoint"` starts a Claude session. In the interactive wizard, press `m` on the confirm step to cycle through every harness's models, shown as `Codex · GPT 6.0 Astra` or `Claude · Opus 5.5`. `remy new` creates the session from the prompt and flags, then opens it when the terminal is interactive.
130
134
 
131
135
  The branch-suggestion flow belongs to the interactive new-session wizard (`remy`, then `n`). Direct `remy new` creation does not analyze continuation references.
132
136
 
@@ -144,6 +148,14 @@ remy --session <session-id> "Add regression coverage for that fix"
144
148
 
145
149
  Remy sends the prompt as **Steer**, then opens the conversation. Omitting the prompt only attaches. An explicitly empty prompt is rejected. Use `--` before a prompt beginning with `--` to treat it as text.
146
150
 
151
+ To change the model or reasoning effort, pass `--model <name>`, `--reasoning-effort <low|medium|high|xhigh>`, or both with the prompt:
152
+
153
+ ```bash
154
+ remy --session <session-id> --model claude-sonnet-5 --reasoning-effort high "Finish the migration"
155
+ ```
156
+
157
+ The change travels with that message and stays the session's setting for later messages. A running turn switches from its next model request; otherwise the change applies from the turn the prompt starts. Either flag without a prompt is rejected, because settings only change with a message. The session keeps its harness, so `--model` must name one of that harness's models; Remy checks this against the session before sending and names the harness's models when it does not match. Omit both flags to keep the current settings.
158
+
147
159
  ### Automate a session
148
160
 
149
161
  `remy new` and `remy --session` use JSON Lines output automatically when standard input or output is not a terminal. Pass `--no-tui` to choose that mode explicitly; `--json` also selects it.
@@ -201,7 +213,7 @@ remy update
201
213
  remy --version | -v
202
214
  remy dashboard
203
215
  remy new [--repository <owner/name> ... --installation <id> --model <name> --reasoning-effort <low|medium|high|xhigh> --attach <path> ... --no-tui --json] <prompt>
204
- remy --session <session-id> [--no-tui] [--json] [prompt]
216
+ remy --session <session-id> [--model <name> --reasoning-effort <low|medium|high|xhigh> --no-tui --json] [prompt]
205
217
  ```
206
218
 
207
219
  Run `remy <command> --help` for flags and command-specific usage. `remy whoami` prints the saved signed-in identity and organization.
package/dist/remy.js CHANGED
@@ -32161,6 +32161,51 @@ var agentPromptSchema = zod_default2.object({
32161
32161
  blocks: zod_default2.array(wireAgentInputBlockSchema).min(1)
32162
32162
  });
32163
32163
 
32164
+ // ../../packages/agents-protocol/src/agent-model.ts
32165
+ var codexModelIds = [
32166
+ "gpt-6-astra",
32167
+ "gpt-6-sol",
32168
+ "gpt-6-luna",
32169
+ "gpt-5.6-sol",
32170
+ "gpt-5.6-terra",
32171
+ "gpt-5.6-luna",
32172
+ "gpt-5.5",
32173
+ "gpt-5.4",
32174
+ "gpt-5.4-mini",
32175
+ "gpt-5.2"
32176
+ ];
32177
+ var claudeModelIds = [
32178
+ "claude-opus-5-5",
32179
+ "claude-sonnet-5",
32180
+ "claude-fable-5-1",
32181
+ "claude-opus-5",
32182
+ "claude-fable-5",
32183
+ "sonnet",
32184
+ "claude-opus-4-8",
32185
+ "opus",
32186
+ "haiku",
32187
+ "claude-opus-4-7",
32188
+ "claude-mythos-preview",
32189
+ "claude-opus-4-6",
32190
+ "claude-sonnet-4-6",
32191
+ "claude-haiku-4-5",
32192
+ "claude-haiku-4-5-20251001",
32193
+ "claude-opus-4-5",
32194
+ "claude-opus-4-5-20251101",
32195
+ "claude-sonnet-4-5",
32196
+ "claude-sonnet-4-5-20250929",
32197
+ "claude-opus-4-1",
32198
+ "claude-opus-4-1-20250805",
32199
+ "claude-opus-4-0",
32200
+ "claude-opus-4-20250514",
32201
+ "claude-sonnet-4-0",
32202
+ "claude-sonnet-4-20250514",
32203
+ "claude-3-haiku-20240307"
32204
+ ];
32205
+ var codexModelIdSchema = zod_default2.enum(codexModelIds);
32206
+ var claudeModelIdSchema = zod_default2.enum(claudeModelIds);
32207
+ var agentModelIdSchema = zod_default2.union([codexModelIdSchema, claudeModelIdSchema]);
32208
+
32164
32209
  // ../../packages/agents-protocol/src/agent-provider.ts
32165
32210
  var agentProviderIdSchema = zod_default2.enum(["codex", "claude"]);
32166
32211
 
@@ -32346,6 +32391,12 @@ function objectRejectingKeys(shape, rejectedKeys) {
32346
32391
  // ../../packages/agents-protocol/src/agent-command.ts
32347
32392
  var agentReasoningEffortSchema = zod_default2.enum(["low", "medium", "high", "xhigh", "max"]);
32348
32393
  var agentPromptModeSchema = zod_default2.enum(["next", "steer"]);
32394
+ var agentSettingsChangeSchema = zod_default2.strictObject({
32395
+ model: agentModelIdSchema.optional(),
32396
+ reasoningEffort: agentReasoningEffortSchema.optional()
32397
+ }).refine((settings) => settings.model !== undefined || settings.reasoningEffort !== undefined, {
32398
+ message: "A settings change needs a model or a reasoning effort."
32399
+ });
32349
32400
  var agentAuthorSchema = zod_default2.object({
32350
32401
  name: zod_default2.string().min(1),
32351
32402
  email: zod_default2.string().min(1).optional(),
@@ -32363,7 +32414,8 @@ var sendPromptCommandSchema = runningCommandBaseSchema.extend({
32363
32414
  origin: zod_default2.enum(["user", "supervisor"]).default("user"),
32364
32415
  prompt: agentPromptSchema,
32365
32416
  commandId: commandIdSchema,
32366
- author: agentAuthorSchema.optional()
32417
+ author: agentAuthorSchema.optional(),
32418
+ settings: agentSettingsChangeSchema.optional()
32367
32419
  });
32368
32420
  var agentNotifyCommandSchema = runningCommandBaseSchema.extend({
32369
32421
  type: zod_default2.literal("agent.notify"),
@@ -32412,44 +32464,180 @@ var agentCommandSchema = zod_default2.union([
32412
32464
  stopAgentCommandSchema,
32413
32465
  respondUserInputAgentCommandSchema
32414
32466
  ]);
32415
- // ../../packages/agents-protocol/src/agent-model.ts
32416
- var codexModelIds = [
32467
+
32468
+ // ../../packages/agents-protocol/src/agent-presentation.ts
32469
+ var CODEX_CONTEXT_WINDOW = 272000;
32470
+ var codexModelPresentation = {
32471
+ "gpt-6-astra": {
32472
+ label: "GPT 6.0 Astra",
32473
+ description: "Frontier intelligence for the most demanding work.",
32474
+ relativeCost: 5,
32475
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32476
+ isMultiModal: true
32477
+ },
32478
+ "gpt-6-sol": {
32479
+ label: "GPT 6.0 Sol",
32480
+ description: "Workhorse model for coding and everyday work.",
32481
+ relativeCost: 4,
32482
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32483
+ isMultiModal: true
32484
+ },
32485
+ "gpt-6-luna": {
32486
+ label: "GPT 6.0 Luna",
32487
+ description: "Fast and affordable model for easier tasks.",
32488
+ relativeCost: 2,
32489
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32490
+ isMultiModal: true
32491
+ },
32492
+ "gpt-5.6-sol": {
32493
+ label: "GPT 5.6 Sol",
32494
+ description: "Older coding model for complex work.",
32495
+ relativeCost: 5,
32496
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32497
+ isMultiModal: true
32498
+ },
32499
+ "gpt-5.6-terra": {
32500
+ label: "GPT 5.6 Terra",
32501
+ description: "Older balanced model for straightforward work.",
32502
+ relativeCost: 3,
32503
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32504
+ isMultiModal: true
32505
+ },
32506
+ "gpt-5.6-luna": {
32507
+ label: "GPT 5.6 Luna",
32508
+ description: "Older fast and efficient model.",
32509
+ relativeCost: 2,
32510
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32511
+ isMultiModal: true
32512
+ },
32513
+ "gpt-5.5": {
32514
+ label: "GPT 5.5",
32515
+ description: "Legacy coding model.",
32516
+ relativeCost: 4,
32517
+ maxInputTokens: CODEX_CONTEXT_WINDOW,
32518
+ isMultiModal: true
32519
+ }
32520
+ };
32521
+ var CLAUDE_CONTEXT_WINDOW = 1e6;
32522
+ var claudeModelPresentation = {
32523
+ "claude-opus-5-5": {
32524
+ label: "Opus 5.5",
32525
+ description: "Best for everyday, complex tasks.",
32526
+ relativeCost: 4,
32527
+ maxInputTokens: CLAUDE_CONTEXT_WINDOW,
32528
+ maxOutputTokens: 128000,
32529
+ isMultiModal: true
32530
+ },
32531
+ "claude-sonnet-5": {
32532
+ label: "Sonnet 5",
32533
+ description: "Efficient for routine coding tasks.",
32534
+ relativeCost: 2,
32535
+ maxInputTokens: CLAUDE_CONTEXT_WINDOW,
32536
+ maxOutputTokens: 64000,
32537
+ isMultiModal: true
32538
+ },
32539
+ "claude-fable-5-1": {
32540
+ label: "Fable 5.1",
32541
+ description: "Most intelligent generally available Claude model.",
32542
+ relativeCost: 5,
32543
+ maxInputTokens: CLAUDE_CONTEXT_WINDOW,
32544
+ maxOutputTokens: 64000,
32545
+ isMultiModal: true
32546
+ }
32547
+ };
32548
+ var agentReasoningEffortPresentation = {
32549
+ low: { label: "Low", description: "Fast responses with lighter reasoning" },
32550
+ medium: { label: "Medium", description: "Balances speed and reasoning depth for everyday tasks" },
32551
+ high: { label: "High", description: "Greater reasoning depth for complex problems" },
32552
+ xhigh: { label: "Extra high", description: "Extra high reasoning depth for complex problems" },
32553
+ max: { label: "Max", description: "Maximum reasoning depth for the hardest problems" }
32554
+ };
32555
+ var selectableAgentReasoningEfforts = ["low", "medium", "high", "xhigh"];
32556
+
32557
+ // ../../packages/agents-protocol/src/agent-catalog.ts
32558
+ var selectableCodexModelIds = [
32417
32559
  "gpt-6-astra",
32560
+ "gpt-6-sol",
32561
+ "gpt-6-luna",
32418
32562
  "gpt-5.6-sol",
32419
32563
  "gpt-5.6-terra",
32420
32564
  "gpt-5.6-luna",
32421
- "gpt-5.5",
32422
- "gpt-5.4",
32423
- "gpt-5.4-mini",
32424
- "gpt-5.2"
32565
+ "gpt-5.5"
32425
32566
  ];
32426
- var claudeModelIds = [
32427
- "sonnet",
32428
- "claude-opus-4-8",
32429
- "opus",
32430
- "haiku",
32431
- "claude-opus-4-7",
32432
- "claude-mythos-preview",
32433
- "claude-opus-4-6",
32434
- "claude-sonnet-4-6",
32435
- "claude-haiku-4-5",
32436
- "claude-haiku-4-5-20251001",
32437
- "claude-opus-4-5",
32438
- "claude-opus-4-5-20251101",
32439
- "claude-sonnet-4-5",
32440
- "claude-sonnet-4-5-20250929",
32441
- "claude-opus-4-1",
32442
- "claude-opus-4-1-20250805",
32443
- "claude-opus-4-0",
32444
- "claude-opus-4-20250514",
32445
- "claude-sonnet-4-0",
32446
- "claude-sonnet-4-20250514",
32447
- "claude-3-haiku-20240307"
32567
+ var selectableClaudeModelIds = [
32568
+ "claude-opus-5-5",
32569
+ "claude-sonnet-5",
32570
+ "claude-fable-5-1"
32448
32571
  ];
32449
- var codexModelIdSchema = zod_default2.enum(codexModelIds);
32450
- var claudeModelIdSchema = zod_default2.enum(claudeModelIds);
32451
- var agentModelIdSchema = zod_default2.union([codexModelIdSchema, claudeModelIdSchema]);
32452
-
32572
+ var agentHarnesses = {
32573
+ codex: {
32574
+ provider: "codex",
32575
+ label: "Codex",
32576
+ models: selectableCodexModelIds,
32577
+ defaultModel: "gpt-6-astra",
32578
+ modelPresentation: codexModelPresentation
32579
+ },
32580
+ claude: {
32581
+ provider: "claude",
32582
+ label: "Claude",
32583
+ models: selectableClaudeModelIds,
32584
+ defaultModel: "claude-opus-5-5",
32585
+ modelPresentation: claudeModelPresentation
32586
+ }
32587
+ };
32588
+ var agentHarnessOrder = ["codex", "claude"];
32589
+ var codexAgentSelectionSchema = zod_default2.strictObject({
32590
+ provider: zod_default2.literal("codex"),
32591
+ model: zod_default2.enum(selectableCodexModelIds),
32592
+ reasoningEffort: agentReasoningEffortSchema
32593
+ });
32594
+ var claudeAgentSelectionSchema = zod_default2.strictObject({
32595
+ provider: zod_default2.literal("claude"),
32596
+ model: zod_default2.enum(selectableClaudeModelIds),
32597
+ reasoningEffort: agentReasoningEffortSchema
32598
+ });
32599
+ var agentSelectionSchema = zod_default2.discriminatedUnion("provider", [
32600
+ codexAgentSelectionSchema,
32601
+ claudeAgentSelectionSchema
32602
+ ]);
32603
+ var storedAgentSelectionSchema = zod_default2.discriminatedUnion("provider", [
32604
+ zod_default2.strictObject({
32605
+ provider: zod_default2.literal("codex"),
32606
+ model: codexModelIdSchema,
32607
+ reasoningEffort: agentReasoningEffortSchema
32608
+ }),
32609
+ zod_default2.strictObject({
32610
+ provider: zod_default2.literal("claude"),
32611
+ model: claudeModelIdSchema,
32612
+ reasoningEffort: agentReasoningEffortSchema
32613
+ })
32614
+ ]);
32615
+ var wireModelIdsByProvider = {
32616
+ codex: new Set(codexModelIds),
32617
+ claude: new Set(claudeModelIds)
32618
+ };
32619
+ var defaultAgentSelection = {
32620
+ provider: "codex",
32621
+ model: "gpt-6-astra",
32622
+ reasoningEffort: "medium"
32623
+ };
32624
+ var selectableModelIdsByProvider = {
32625
+ codex: new Set(selectableCodexModelIds),
32626
+ claude: new Set(selectableClaudeModelIds)
32627
+ };
32628
+ function agentHarnessForModel(model) {
32629
+ return agentHarnessOrder.find((provider) => isSelectableAgentModel(provider, model));
32630
+ }
32631
+ function isSelectableAgentModel(provider, model) {
32632
+ return selectableModelIdsByProvider[provider].has(model);
32633
+ }
32634
+ var selectableModelPresentationById = new Map([
32635
+ ...selectableCodexModelIds.map((model) => [model, codexModelPresentation[model]]),
32636
+ ...selectableClaudeModelIds.map((model) => [model, claudeModelPresentation[model]])
32637
+ ]);
32638
+ function selectableAgentModelPresentation(model) {
32639
+ return selectableModelPresentationById.get(model);
32640
+ }
32453
32641
  // ../../packages/agents-protocol/src/agent-metadata.ts
32454
32642
  var metadataShape = {
32455
32643
  sessionId: zod_default2.string().min(1),
@@ -32723,6 +32911,19 @@ var sessionConfiguredAgentEventSchema = agentSessionEventBaseSchema.extend({
32723
32911
  environment: zod_default2.record(zod_default2.string().min(1), zod_default2.literal("[REDACTED]"))
32724
32912
  })
32725
32913
  });
32914
+ var agentSettingsAppliesFromSchema = zod_default2.enum(["current_turn", "next_turn"]);
32915
+ var currentTurnUnavailableReasonMaxLength = 300;
32916
+ var sessionSettingsChangedAgentEventSchema = agentSessionEventBaseSchema.extend({
32917
+ type: zod_default2.literal("session.settings.changed"),
32918
+ payload: zod_default2.object({
32919
+ model: zod_default2.string().min(1),
32920
+ reasoningEffort: zod_default2.string().min(1).optional(),
32921
+ commandId: zod_default2.string().min(1),
32922
+ turnId: zod_default2.string().min(1).optional(),
32923
+ appliesFrom: agentSettingsAppliesFromSchema,
32924
+ currentTurnUnavailableReason: zod_default2.string().min(1).max(currentTurnUnavailableReasonMaxLength).optional()
32925
+ })
32926
+ });
32726
32927
  var sessionSkillsUpdatedAgentEventSchema = agentSessionEventBaseSchema.extend({
32727
32928
  type: zod_default2.literal("session.skills.updated"),
32728
32929
  payload: zod_default2.object({
@@ -32971,6 +33172,7 @@ var errorAgentEventSchema = agentSessionEventBaseSchema.extend({
32971
33172
  var agentEventSchema = zod_default2.discriminatedUnion("type", [
32972
33173
  sessionStartedAgentEventSchema,
32973
33174
  sessionConfiguredAgentEventSchema,
33175
+ sessionSettingsChangedAgentEventSchema,
32974
33176
  sessionSkillsUpdatedAgentEventSchema,
32975
33177
  sessionStateChangedAgentEventSchema,
32976
33178
  sessionEndedAgentEventSchema,
@@ -33000,74 +33202,6 @@ var agentEventSchema = zod_default2.discriminatedUnion("type", [
33000
33202
  errorAgentEventSchema
33001
33203
  ]);
33002
33204
  var agentEventTypes = agentEventSchema.options.map((schema) => schema.shape.type.value);
33003
- // ../../packages/agents-protocol/src/agent-presentation.ts
33004
- var CODEX_CONTEXT_WINDOW = 272000;
33005
- var codexModelPresentation = {
33006
- "gpt-6-astra": {
33007
- label: "GPT 6.0 Astra",
33008
- description: "Our most capable model for complex, demanding work.",
33009
- relativeCost: 5,
33010
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33011
- isMultiModal: true
33012
- },
33013
- "gpt-5.6-sol": {
33014
- label: "GPT 5.6 Sol",
33015
- description: "Reliable agentic workhorse for everyday tasks.",
33016
- relativeCost: 5,
33017
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33018
- isMultiModal: true
33019
- },
33020
- "gpt-5.6-terra": {
33021
- label: "GPT 5.6 Terra",
33022
- description: "Balanced agentic coding model for everyday work.",
33023
- relativeCost: 3,
33024
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33025
- isMultiModal: true
33026
- },
33027
- "gpt-5.6-luna": {
33028
- label: "GPT 5.6 Luna",
33029
- description: "Fast and affordable agentic coding model.",
33030
- relativeCost: 2,
33031
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33032
- isMultiModal: true
33033
- },
33034
- "gpt-5.5": {
33035
- label: "GPT 5.5",
33036
- description: "Proven previous-generation model for coding and general work.",
33037
- relativeCost: 4,
33038
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33039
- isMultiModal: true
33040
- },
33041
- "gpt-5.4": {
33042
- label: "GPT 5.4",
33043
- description: "Strong model for everyday coding.",
33044
- relativeCost: 3,
33045
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33046
- isMultiModal: true
33047
- },
33048
- "gpt-5.4-mini": {
33049
- label: "GPT 5.4 Mini",
33050
- description: "Small, fast, and cost-efficient model for simpler coding tasks.",
33051
- relativeCost: 2,
33052
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33053
- isMultiModal: true
33054
- },
33055
- "gpt-5.2": {
33056
- label: "GPT-5.2",
33057
- description: "Optimized for professional work and long-running agents.",
33058
- relativeCost: 3,
33059
- maxInputTokens: CODEX_CONTEXT_WINDOW,
33060
- isMultiModal: true
33061
- }
33062
- };
33063
- var agentReasoningEffortPresentation = {
33064
- low: { label: "Low", description: "Fast responses with lighter reasoning" },
33065
- medium: { label: "Medium", description: "Balances speed and reasoning depth for everyday tasks" },
33066
- high: { label: "High", description: "Greater reasoning depth for complex problems" },
33067
- xhigh: { label: "Extra high", description: "Extra high reasoning depth for complex problems" },
33068
- max: { label: "Max", description: "Maximum reasoning depth for the hardest problems" }
33069
- };
33070
- var selectableAgentReasoningEfforts = ["low", "medium", "high", "xhigh"];
33071
33205
  // ../../packages/coding-agent-client/src/sessions.ts
33072
33206
  var reasoningEffortSchema = exports_external2.enum(selectableAgentReasoningEfforts);
33073
33207
  var sessionStatusSchema = exports_external2.enum(["open", "completed", "failed", "cancelled"]);
@@ -33145,7 +33279,12 @@ var sessionConnectionSchema = exports_external2.discriminatedUnion("status", [
33145
33279
  target: exports_external2.strictObject({ channel_id: exports_external2.string().min(1), thread_ts: exports_external2.string().min(1) })
33146
33280
  })
33147
33281
  ]);
33148
- var createCodexSessionInputSchema = exports_external2.strictObject({
33282
+ var createSessionAgentInputSchema = exports_external2.strictObject({
33283
+ provider: agentProviderIdSchema,
33284
+ model: exports_external2.string().min(1).optional(),
33285
+ reasoningEffort: reasoningEffortSchema.optional()
33286
+ }).refine((agent) => agent.model === undefined || isSelectableAgentModel(agent.provider, agent.model), { message: "model must be a selectable model of the selected provider", path: ["model"] });
33287
+ var createSessionInputSchema = exports_external2.strictObject({
33149
33288
  installationId: exports_external2.string().min(1),
33150
33289
  repositoryIds: exports_external2.array(exports_external2.string().min(1)),
33151
33290
  repositoryBranchOverrides: exports_external2.array(exports_external2.strictObject({
@@ -33154,8 +33293,7 @@ var createCodexSessionInputSchema = exports_external2.strictObject({
33154
33293
  })).optional(),
33155
33294
  prompt: exports_external2.string().refine((value) => value.trim().length > 0),
33156
33295
  fileIds: exports_external2.array(exports_external2.string().min(1)),
33157
- model: codexModelIdSchema.optional(),
33158
- reasoningEffort: reasoningEffortSchema.optional(),
33296
+ agent: createSessionAgentInputSchema.optional(),
33159
33297
  mcps: exports_external2.array(exports_external2.string().min(1)).optional(),
33160
33298
  idempotencyKey: exports_external2.string().min(1).max(128)
33161
33299
  });
@@ -33168,12 +33306,17 @@ var createSessionResponseSchema = exports_external2.strictObject({
33168
33306
  messages: exports_external2.tuple([sessionMessageSchema]),
33169
33307
  connections: exports_external2.array(sessionConnectionSchema).max(1)
33170
33308
  });
33309
+ var appendSessionMessageAgentInputSchema = exports_external2.strictObject({
33310
+ model: exports_external2.string().min(1).optional(),
33311
+ reasoningEffort: agentReasoningEffortSchema.optional()
33312
+ }).refine((agent) => agent.model !== undefined || agent.reasoningEffort !== undefined, { message: "agent must change the model, the reasoning effort, or both" });
33171
33313
  var appendSessionMessageInputSchema = exports_external2.strictObject({
33172
33314
  sessionId: exports_external2.string().min(1),
33173
33315
  text: exports_external2.string().refine((value) => value.trim().length > 0),
33174
33316
  fileIds: exports_external2.array(exports_external2.string().min(1)),
33175
33317
  idempotencyKey: exports_external2.string().min(1).max(128),
33176
- mode: exports_external2.enum(["next", "steer"]).optional()
33318
+ mode: exports_external2.enum(["next", "steer"]).optional(),
33319
+ agent: appendSessionMessageAgentInputSchema.optional()
33177
33320
  });
33178
33321
  var appendSessionMessageResponseSchema = exports_external2.strictObject({
33179
33322
  message: sessionMessageSchema
@@ -33227,7 +33370,17 @@ var sessionDetailResponseSchema = exports_external2.object({
33227
33370
  full_name: exports_external2.string()
33228
33371
  })),
33229
33372
  connections: exports_external2.array(sessionConnectionSchema).max(1),
33230
- artifacts: exports_external2.array(sessionArtifactSchema)
33373
+ artifacts: exports_external2.array(sessionArtifactSchema),
33374
+ agent: exports_external2.object({
33375
+ provider: exports_external2.string().min(1),
33376
+ model: exports_external2.string(),
33377
+ reasoning: exports_external2.string().nullable()
33378
+ }).nullable().optional(),
33379
+ agent_pending: exports_external2.object({
33380
+ model: exports_external2.string(),
33381
+ reasoning_effort: exports_external2.string().nullable(),
33382
+ message_id: exports_external2.string()
33383
+ }).nullable().optional()
33231
33384
  }).passthrough();
33232
33385
  var sessionSourceSchema = exports_external2.discriminatedUnion("provider", [
33233
33386
  exports_external2.object({
@@ -33280,11 +33433,11 @@ var sessionListResponseSchema = exports_external2.strictObject({
33280
33433
  next_cursor: exports_external2.string().nullable(),
33281
33434
  total: exports_external2.number().int().nonnegative()
33282
33435
  });
33283
- async function createCodexSession({
33436
+ async function createSession({
33284
33437
  client,
33285
33438
  input
33286
33439
  }) {
33287
- const parsedInput = createCodexSessionInputSchema.parse(input);
33440
+ const parsedInput = createSessionInputSchema.parse(input);
33288
33441
  const response = await client.request("/v1/sessions", {
33289
33442
  method: "POST",
33290
33443
  headers: {
@@ -33293,11 +33446,11 @@ async function createCodexSession({
33293
33446
  },
33294
33447
  body: JSON.stringify({
33295
33448
  github_installation_id: parsedInput.installationId,
33296
- ...parsedInput.model || parsedInput.reasoningEffort ? {
33449
+ ...parsedInput.agent ? {
33297
33450
  agent: {
33298
- provider: "codex",
33299
- ...parsedInput.model ? { model: parsedInput.model } : {},
33300
- ...parsedInput.reasoningEffort ? { reasoning_effort: parsedInput.reasoningEffort } : {}
33451
+ provider: parsedInput.agent.provider,
33452
+ ...parsedInput.agent.model ? { model: parsedInput.agent.model } : {},
33453
+ ...parsedInput.agent.reasoningEffort ? { reasoning_effort: parsedInput.agent.reasoningEffort } : {}
33301
33454
  }
33302
33455
  } : {},
33303
33456
  repositories: parsedInput.repositoryIds.map((repositoryId) => {
@@ -33330,7 +33483,13 @@ async function appendSessionMessage({
33330
33483
  body: JSON.stringify({
33331
33484
  text: parsedInput.text,
33332
33485
  file_ids: parsedInput.fileIds,
33333
- ...parsedInput.mode === undefined ? {} : { mode: parsedInput.mode }
33486
+ ...parsedInput.mode === undefined ? {} : { mode: parsedInput.mode },
33487
+ ...parsedInput.agent === undefined ? {} : {
33488
+ agent: {
33489
+ ...parsedInput.agent.model === undefined ? {} : { model: parsedInput.agent.model },
33490
+ ...parsedInput.agent.reasoningEffort === undefined ? {} : { reasoning_effort: parsedInput.agent.reasoningEffort }
33491
+ }
33492
+ }
33334
33493
  })
33335
33494
  });
33336
33495
  return parseAppendSessionMessageResponse(await parseJson2(response, "Session message append response was not valid JSON."));
@@ -34237,7 +34396,7 @@ function formatSessionJson({
34237
34396
  `;
34238
34397
  }
34239
34398
  // src/version.ts
34240
- var remyCliVersion = "1.22.0-rc.0";
34399
+ var remyCliVersion = "1.22.0-rc.2";
34241
34400
 
34242
34401
  // src/self-update.ts
34243
34402
  import { spawn } from "child_process";
@@ -34374,16 +34533,57 @@ async function confirmCliUpdate({ version: version5, signal, interrupt }) {
34374
34533
 
34375
34534
  // src/session-agent-options.ts
34376
34535
  function newSessionModelLabel(model) {
34377
- return codexModelPresentation[model].label;
34536
+ const provider = newSessionModelHarness(model);
34537
+ return `${agentHarnesses[provider].label} \xB7 ${agentModelLabel(model)}`;
34378
34538
  }
34379
34539
  function newSessionReasoningEffortLabel(effort) {
34380
34540
  return agentReasoningEffortPresentation[effort].label;
34381
34541
  }
34382
- var newSessionModels = codexModelIds;
34542
+ function newSessionModelHarness(model) {
34543
+ const provider = agentHarnessForModel(model);
34544
+ if (!provider)
34545
+ throw new Error(`Model ${model} is not offered by any harness.`);
34546
+ return provider;
34547
+ }
34548
+ var newSessionModels = agentHarnessOrder.flatMap((provider) => agentHarnesses[provider].models);
34383
34549
  var newSessionReasoningEfforts = selectableAgentReasoningEfforts;
34550
+ function parseNewSessionModel(value) {
34551
+ return newSessionModels.find((model) => model === value);
34552
+ }
34553
+ function parseNewSessionReasoningEffort(value) {
34554
+ return newSessionReasoningEfforts.find((effort) => effort === value);
34555
+ }
34556
+ function sessionAgentChange({ model, reasoningEffort }) {
34557
+ if (model !== undefined)
34558
+ return { model, ...reasoningEffort === undefined ? {} : { reasoningEffort } };
34559
+ if (reasoningEffort !== undefined)
34560
+ return { reasoningEffort };
34561
+ return;
34562
+ }
34563
+ function sessionHarnessModels(provider) {
34564
+ const parsed = agentProviderIdSchema.safeParse(provider);
34565
+ return parsed.success ? agentHarnesses[parsed.data].models : [];
34566
+ }
34567
+ function agentHarnessLabel(provider) {
34568
+ const parsed = agentProviderIdSchema.safeParse(provider);
34569
+ return parsed.success ? agentHarnesses[parsed.data].label : provider;
34570
+ }
34571
+ function agentModelLabel(model) {
34572
+ return selectableAgentModelPresentation(model)?.label ?? model;
34573
+ }
34574
+ function agentModelDescription(model) {
34575
+ return selectableAgentModelPresentation(model)?.description ?? "";
34576
+ }
34577
+ function agentReasoningEffortLabel(effort) {
34578
+ const parsed = agentReasoningEffortSchema.safeParse(effort);
34579
+ return parsed.success ? agentReasoningEffortPresentation[parsed.data].label : effort;
34580
+ }
34581
+ function agentReasoningEffortDescription(effort) {
34582
+ return agentReasoningEffortPresentation[effort].description;
34583
+ }
34384
34584
  var defaultNewSessionAgent = {
34385
- model: "gpt-6-astra",
34386
- reasoningEffort: "medium"
34585
+ model: defaultAgentSelection.model,
34586
+ reasoningEffort: defaultAgentSelection.reasoningEffort
34387
34587
  };
34388
34588
 
34389
34589
  // src/sessions/session-controller.ts
@@ -34398,6 +34598,9 @@ var wrappedSessionStartedAgentEventSchema = sessionStartedAgentEventSchema.exten
34398
34598
  var wrappedSessionConfiguredAgentEventSchema = sessionConfiguredAgentEventSchema.extend({
34399
34599
  type: zod_default2.literal("agent.session.configured")
34400
34600
  });
34601
+ var wrappedSessionSettingsChangedAgentEventSchema = sessionSettingsChangedAgentEventSchema.extend({
34602
+ type: zod_default2.literal("agent.session.settings.changed")
34603
+ });
34401
34604
  var wrappedSessionSkillsUpdatedAgentEventSchema = sessionSkillsUpdatedAgentEventSchema.extend({
34402
34605
  type: zod_default2.literal("agent.session.skills.updated")
34403
34606
  });
@@ -34482,6 +34685,7 @@ var wrappedErrorAgentEventSchema = errorAgentEventSchema.extend({
34482
34685
  var wrappedAgentEventSchema = zod_default2.discriminatedUnion("type", [
34483
34686
  wrappedSessionStartedAgentEventSchema,
34484
34687
  wrappedSessionConfiguredAgentEventSchema,
34688
+ wrappedSessionSettingsChangedAgentEventSchema,
34485
34689
  wrappedSessionSkillsUpdatedAgentEventSchema,
34486
34690
  wrappedSessionStateChangedAgentEventSchema,
34487
34691
  wrappedSessionEndedAgentEventSchema,
@@ -34671,6 +34875,8 @@ function createSessionViewState({ detail, activeMessageId }) {
34671
34875
  ...detail.agentStatus === undefined ? {} : { agentStatus: detail.agentStatus },
34672
34876
  connectionStatus: "connected",
34673
34877
  pullRequest: toSessionPullRequest(detail),
34878
+ agent: toSessionAgentSettings(detail.agent),
34879
+ agentPending: toSessionAgentPendingSettings(detail.agent_pending),
34674
34880
  ...activeMessageId !== undefined ? { activeMessageId } : {},
34675
34881
  seenRetainedEventIds: {},
34676
34882
  transcript: [],
@@ -34678,6 +34884,7 @@ function createSessionViewState({ detail, activeMessageId }) {
34678
34884
  connectionPreviews: toConnectionPreviews(detail),
34679
34885
  previews: { assistantText: "", reasoningText: "" },
34680
34886
  commandAuthorLabels: {},
34887
+ commandMessageIds: {},
34681
34888
  work: { items: [] },
34682
34889
  workTurnBaselines: {},
34683
34890
  messageTurns: {},
@@ -34707,6 +34914,8 @@ function updateSessionDetail({ state, detail }) {
34707
34914
  aggregateStatus: detail.status,
34708
34915
  ...detail.agentStatus === undefined ? {} : { agentStatus: detail.agentStatus },
34709
34916
  pullRequest: toSessionPullRequest(detail),
34917
+ ...detail.agent === undefined ? {} : { agent: toSessionAgentSettings(detail.agent) },
34918
+ ...detail.agent_pending === undefined ? {} : { agentPending: toSessionAgentPendingSettings(detail.agent_pending) },
34710
34919
  connectionPreviews: toConnectionPreviews(detail)
34711
34920
  };
34712
34921
  }
@@ -34911,6 +35120,7 @@ function projectSessionMessageCreated({ state, event, occurredAt }) {
34911
35120
  return {
34912
35121
  ...state,
34913
35122
  commandAuthorLabels: { ...state.commandAuthorLabels, [event.payload.commandId]: creatorLabel },
35123
+ commandMessageIds: { ...state.commandMessageIds, [event.payload.commandId]: event.payload.messageId },
34914
35124
  transcript: [...state.transcript, {
34915
35125
  kind: "message",
34916
35126
  messageId: event.payload.messageId,
@@ -35024,6 +35234,12 @@ function projectDurableAgentEvent({ state, event, occurredAt, retainedEventId, e
35024
35234
  return projectAgentMessageEnded({ state, event: agentEvent, occurredAt, retainedEventId, eventUrl });
35025
35235
  if (agentEvent.type === "agent.context.updated")
35026
35236
  return state;
35237
+ if (agentEvent.type === "agent.session.configured" || agentEvent.type === "agent.session.settings.changed") {
35238
+ const agent = { provider: agentEvent.provider, model: agentEvent.payload.model, reasoningEffort: agentEvent.payload.reasoningEffort ?? null };
35239
+ const stateWithAgent = { ...state, agent };
35240
+ const card2 = toAgentActivityCard(agentEvent);
35241
+ return agentEvent.type === "agent.session.settings.changed" ? placeActivityAfterCommandMessage({ state: stateWithAgent, commandId: agentEvent.payload.commandId, retainedEventId, occurredAt, card: card2, eventUrl }) : appendActivity({ state: stateWithAgent, retainedEventId, occurredAt, card: card2, eventUrl });
35242
+ }
35027
35243
  if (agentEvent.type === "agent.work.observed" && agentEvent.actor.type === "main")
35028
35244
  return projectAgentWorkObserved({ state, event: agentEvent, occurredAt });
35029
35245
  const stateWithTurnStart = agentEvent.type === "agent.turn.started" && agentEvent.actor.type === "main" ? {
@@ -35150,8 +35366,21 @@ function projectAgentMessageEnded({ state, event, occurredAt, retainedEventId, e
35150
35366
  transcript: [...state.transcript, { kind: "message", messageId, occurredAt, author, text: displayedText, attachments: [] }]
35151
35367
  };
35152
35368
  }
35153
- function appendActivity({ state, retainedEventId, occurredAt, card, eventUrl }) {
35154
- return { ...state, transcript: [...state.transcript, { kind: "activity", activityId: `activity:${retainedEventId}`, occurredAt, card, ...eventUrl === undefined ? {} : { eventUrl } }] };
35369
+ function activityItem({ retainedEventId, occurredAt, card, eventUrl }) {
35370
+ return { kind: "activity", activityId: `activity:${retainedEventId}`, occurredAt, card, ...eventUrl === undefined ? {} : { eventUrl } };
35371
+ }
35372
+ function appendActivity({ state, ...activity }) {
35373
+ return { ...state, transcript: [...state.transcript, activityItem(activity)] };
35374
+ }
35375
+ function placeActivityAfterCommandMessage({ state, commandId, ...activity }) {
35376
+ const messageId = state.commandMessageIds[commandId];
35377
+ const messageIndex = messageId === undefined ? -1 : state.transcript.findIndex((item) => item.kind === "message" && item.messageId === messageId);
35378
+ if (messageIndex === -1)
35379
+ return appendActivity({ state, ...activity });
35380
+ return {
35381
+ ...state,
35382
+ transcript: [...state.transcript.slice(0, messageIndex + 1), activityItem(activity), ...state.transcript.slice(messageIndex + 1)]
35383
+ };
35155
35384
  }
35156
35385
  function toAgentActivityCard(event) {
35157
35386
  const identity = childActivityIdentity(event);
@@ -35165,6 +35394,21 @@ function toMainAgentActivityCard(event) {
35165
35394
  return { kind: "lifecycle", weight: "noise", title: "Remy session started", summary: "Session is ready." };
35166
35395
  case "agent.session.configured":
35167
35396
  return { kind: "lifecycle", weight: "noise", title: "Remy session configured", summary: `Model ${event.payload.model}.` };
35397
+ case "agent.session.settings.changed": {
35398
+ const settings = [agentModelLabel(event.payload.model), ...event.payload.reasoningEffort === undefined ? [] : [agentReasoningEffortLabel(event.payload.reasoningEffort)]];
35399
+ const switched = `Switched to ${terminalSafeSingleLine(settings.join(" \xB7 "))}`;
35400
+ if (event.payload.appliesFrom === "current_turn")
35401
+ return { kind: "lifecycle", weight: "signal", title: switched, summary: switched };
35402
+ const title = `${switched} (from next turn)`;
35403
+ const reason = event.payload.currentTurnUnavailableReason;
35404
+ return {
35405
+ kind: "lifecycle",
35406
+ weight: "signal",
35407
+ title,
35408
+ summary: title,
35409
+ ...reason === undefined ? {} : { detail: `The running turn kept its settings: ${terminalSafeSingleLine(reason)}` }
35410
+ };
35411
+ }
35168
35412
  case "agent.session.skills.updated":
35169
35413
  return { kind: "lifecycle", weight: "noise", title: "Remy skills updated", summary: "Available skills updated." };
35170
35414
  case "agent.session.state.changed":
@@ -35325,6 +35569,7 @@ Background outcome: ${event.payload.output.success ? "completed" : "failed"}`,
35325
35569
  return createChildActivityCard({ identity, activityTitle: "Needs input", card: { kind: "approval-question", weight: "signal", summary: providerText(event.payload.prompt, "Subagent needs input."), detail: jsonDetail(event.payload.questions) } });
35326
35570
  case "agent.session.started":
35327
35571
  case "agent.session.configured":
35572
+ case "agent.session.settings.changed":
35328
35573
  case "agent.session.skills.updated":
35329
35574
  case "agent.session.state.changed":
35330
35575
  case "agent.session.ended":
@@ -35741,6 +35986,12 @@ function providerText(raw, fallback) {
35741
35986
  const cleaned = stripAnsi(raw ?? "").trim();
35742
35987
  return cleaned.length > 0 ? cleaned : fallback;
35743
35988
  }
35989
+ function toSessionAgentSettings(agent) {
35990
+ return agent ? { provider: agent.provider, model: agent.model, reasoningEffort: agent.reasoning } : null;
35991
+ }
35992
+ function toSessionAgentPendingSettings(pending) {
35993
+ return pending ? { model: pending.model, reasoningEffort: pending.reasoning_effort, messageId: pending.message_id } : null;
35994
+ }
35744
35995
  function toConnectionPreviews(detail) {
35745
35996
  return detail.connections.map((connection) => ({ provider: connection.provider, status: connection.status }));
35746
35997
  }
@@ -36112,7 +36363,7 @@ function createRemoteSessionController(dependencies) {
36112
36363
  await writeCache();
36113
36364
  cachedLastRetainedEventId = projectedState.lastRetainedEventId;
36114
36365
  }
36115
- if (frame.kind === "retained" && frame.data.event.type === "session.title.generated" && !previousState.seenRetainedEventIds[frame.id]) {
36366
+ if (frame.kind === "retained" && !previousState.seenRetainedEventIds[frame.id] && (frame.data.event.type === "session.title.generated" || settlesAgentSettings({ previousState, projectedState, frame }))) {
36116
36367
  try {
36117
36368
  await refreshDetail();
36118
36369
  } catch {}
@@ -36232,9 +36483,16 @@ function createRemoteSessionController(dependencies) {
36232
36483
  waitUntilReady,
36233
36484
  waitForTurn,
36234
36485
  recordActiveMessage,
36235
- updateDetail
36486
+ updateDetail,
36487
+ refreshDetail
36236
36488
  };
36237
36489
  }
36490
+ function settlesAgentSettings({ previousState, projectedState, frame }) {
36491
+ if (frame.data.event.type === "agent.session.settings.changed")
36492
+ return true;
36493
+ const pending = previousState.agentPending;
36494
+ return pending !== null && sessionTurnOutcome({ state: previousState, sessionMessageId: pending.messageId }).status !== "ended" && sessionTurnOutcome({ state: projectedState, sessionMessageId: pending.messageId }).status === "ended";
36495
+ }
36238
36496
  function resolveSessionCachePath({
36239
36497
  environment,
36240
36498
  sessionId
@@ -37911,7 +38169,7 @@ async function createNewSessionWizard({
37911
38169
  const attachmentStatus = attachmentFeedback ? renderAttachmentFeedback(attachmentFeedback) : undefined;
37912
38170
  if (step === "prompt") {
37913
38171
  const parts = [
37914
- new StyledText7([stepHeader("New remote Codex session")]),
38172
+ new StyledText7([stepHeader("New remote session")]),
37915
38173
  stringToStyledText3("Describe the work you want Remy to do. Press Enter to continue; Esc back.")
37916
38174
  ];
37917
38175
  if (attachmentText.chunks.length > 0)
@@ -39130,6 +39388,8 @@ var composerSlashCommands = [
39130
39388
  { value: "/complete", description: "Finish this session" },
39131
39389
  { value: "/cancel", description: "Cancel this session" },
39132
39390
  { value: "/compact", description: "Compact main-thread context" },
39391
+ { value: "/model", description: "Change the model from your next message" },
39392
+ { value: "/effort", description: "Change reasoning effort from your next message" },
39133
39393
  { value: "/new", description: "Start a new session" },
39134
39394
  { value: "/logout", description: "Sign out of Remy" },
39135
39395
  { value: "/files", description: "Download artifacts and user attachments" },
@@ -39192,6 +39452,45 @@ async function createSessionTui({
39192
39452
  const steps = currentTurnActivityCount();
39193
39453
  const stepText = steps === 0 ? "" : `${steps} step${steps === 1 ? "" : "s"} \xB7 `;
39194
39454
  return renderer.width < 76 ? `${stepText}ctrl+o \xB7 esc stop` : `${stepText}ctrl+o full detail \xB7 esc to stop`;
39455
+ }, openAgentSettingsPicker = function(kind) {
39456
+ const target = agentSettingsTarget({ state: latestState, staged: composerDraft.agent });
39457
+ if (kind === "effort") {
39458
+ agentSettingsPicker = { kind, index: Math.max(0, newSessionReasoningEfforts.findIndex((effort) => effort === target.reasoningEffort)) };
39459
+ } else {
39460
+ const provider = latestState.agent?.provider;
39461
+ const models = provider === undefined ? [] : sessionHarnessModels(provider);
39462
+ if (provider === undefined || models.length === 0) {
39463
+ composerFeedback = {
39464
+ kind: "failure",
39465
+ message: provider === undefined ? "This session has not reported its harness yet, so its model cannot change." : `Remy does not offer model changes for the ${terminalSafeText(agentHarnessLabel(provider))} harness.`
39466
+ };
39467
+ render();
39468
+ return;
39469
+ }
39470
+ agentSettingsPicker = { kind, provider, models, index: Math.max(0, models.findIndex((model) => model === target.model)) };
39471
+ }
39472
+ composerFeedback = undefined;
39473
+ slashCompletions = [];
39474
+ helpVisible = false;
39475
+ pathCompletionMenuOpen = false;
39476
+ render();
39477
+ }, moveAgentSettingsPicker = function(step) {
39478
+ if (!agentSettingsPicker)
39479
+ return;
39480
+ const length = agentSettingsPicker.kind === "model" ? agentSettingsPicker.models.length : newSessionReasoningEfforts.length;
39481
+ agentSettingsPicker = { ...agentSettingsPicker, index: (agentSettingsPicker.index + step + length) % length };
39482
+ render();
39483
+ }, chooseAgentSetting = function() {
39484
+ const picker = agentSettingsPicker;
39485
+ if (!picker)
39486
+ return;
39487
+ agentSettingsPicker = undefined;
39488
+ const pick3 = picker.kind === "model" ? { model: picker.models[picker.index] } : { reasoningEffort: newSessionReasoningEfforts[picker.index] };
39489
+ const agent = stageAgentChange({ state: latestState, staged: composerDraft.agent, pick: pick3 });
39490
+ composerDraft = { text: composerDraft.text, attachments: composerDraft.attachments, ...agent ? { agent } : {} };
39491
+ const target = agentSettingsTarget({ state: latestState, staged: agent });
39492
+ composerFeedback = agent ? { kind: "info", message: `${terminalSafeText(agentSettingsLabel(target))} applies from your next message.` } : { kind: "info", message: "No model or effort change is staged." };
39493
+ render();
39195
39494
  }, composerAtVisualEdge = function(direction) {
39196
39495
  const cursor = composer.visualCursor;
39197
39496
  const visualRow = composer.scrollY + cursor.visualRow;
@@ -39239,7 +39538,7 @@ async function createSessionTui({
39239
39538
  const working = isRemyWorking(latestState);
39240
39539
  const startedAt = workingTurnStartedAt(latestState);
39241
39540
  const elapsedMs = startedAt === undefined ? 0 : Math.max(0, now3() - Date.parse(startedAt));
39242
- statusBand.content = renderStatusBand({ state: latestState, working, elapsedMs, stopState, lifecycleRequestState, repositoryLabel });
39541
+ statusBand.content = renderStatusBand({ state: latestState, working, elapsedMs, stopState, lifecycleRequestState, repositoryLabel, stagedAgent: composerDraft.agent });
39243
39542
  const liveIndicator = lifecycleRequestState.kind === "pending" ? renderWorkingIndicator({ frame: SPINNER_FRAMES[spinnerFrameIndex], elapsedMs: 0, mode: lifecycleRequestState.operation }) : working ? renderWorkingIndicator({
39244
39543
  frame: SPINNER_FRAMES[spinnerFrameIndex],
39245
39544
  elapsedMs,
@@ -39257,6 +39556,7 @@ async function createSessionTui({
39257
39556
  const submissionStatus = renderComposerStatus({ admittedSubmissions, width: renderer.width - 2 });
39258
39557
  const completionMenu = pathCompletionMenuOpen ? renderPathCompletionMenu({ completions: pathCompletions, selectedIndex: completionIndex, width: renderer.width - 2, maxRows: completionMenuRows(renderer.height) }) : undefined;
39259
39558
  const commandMenu = renderSlashCommandMenu({ commands: slashCompletions, selectedIndex: slashCompletionIndex, width: renderer.width - 2, maxRows: completionMenuRows(renderer.height) });
39559
+ const agentSettingsMenu = agentSettingsPicker && latestState.aggregateStatus === "open" ? renderAgentSettingsPicker({ picker: agentSettingsPicker, width: renderer.width - 2, maxRows: completionMenuRows(renderer.height) }) : undefined;
39260
39560
  const composerStatus = [
39261
39561
  attachmentFeedback ? renderAttachmentFeedback(attachmentFeedback) : undefined,
39262
39562
  composerFeedback ? renderFeedback(composerFeedback) : undefined,
@@ -39264,6 +39564,7 @@ async function createSessionTui({
39264
39564
  lifecycleRequestState.kind === "failed" ? renderFeedback({ kind: "failure", message: `Could not ${lifecycleRequestState.operation} the session: ${lifecycleRequestState.message}` }) : undefined,
39265
39565
  submissionStatus,
39266
39566
  commandMenu,
39567
+ agentSettingsMenu,
39267
39568
  completionMenu
39268
39569
  ].filter((part) => part !== undefined && part.chunks.length > 0);
39269
39570
  status.content = logoutConfirmationOpen ? renderFeedback({ kind: "attention", message: "Log out of Remy?" }) : composerStatus.length > 0 ? joinStyled(composerStatus, `
@@ -39296,6 +39597,7 @@ async function createSessionTui({
39296
39597
  pathCompletionMenuOpen = false;
39297
39598
  slashCompletions = [];
39298
39599
  helpVisible = false;
39600
+ agentSettingsPicker = undefined;
39299
39601
  composer.blur();
39300
39602
  root.visible = false;
39301
39603
  resourceRoot.visible = true;
@@ -39455,6 +39757,7 @@ async function createSessionTui({
39455
39757
  let pathCompletionMenuOpen = false;
39456
39758
  let slashCompletions = [];
39457
39759
  let slashCompletionIndex = 0;
39760
+ let agentSettingsPicker;
39458
39761
  let composerFeedback = initialFeedback ? { kind: "info", message: initialFeedback } : undefined;
39459
39762
  let attachmentFeedback;
39460
39763
  const localPromptHistory = [];
@@ -39553,6 +39856,12 @@ async function createSessionTui({
39553
39856
  }
39554
39857
  return;
39555
39858
  }
39859
+ if (agentSettingsPicker && key.name === "escape") {
39860
+ key.preventDefault();
39861
+ agentSettingsPicker = undefined;
39862
+ render();
39863
+ return;
39864
+ }
39556
39865
  if (resourceMode) {
39557
39866
  key.preventDefault();
39558
39867
  const choices = resourceChoices();
@@ -39664,6 +39973,14 @@ async function createSessionTui({
39664
39973
  key.preventDefault();
39665
39974
  return;
39666
39975
  }
39976
+ if (agentSettingsPicker) {
39977
+ key.preventDefault();
39978
+ if (key.name === "up" || key.name === "down")
39979
+ moveAgentSettingsPicker(key.name === "up" ? -1 : 1);
39980
+ else if (key.name === "return" || key.name === "enter")
39981
+ chooseAgentSetting();
39982
+ return;
39983
+ }
39667
39984
  if (slashCompletions.length > 0 && (key.name === "up" || key.name === "down")) {
39668
39985
  key.preventDefault();
39669
39986
  slashCompletionIndex = (slashCompletionIndex + (key.name === "up" ? -1 : 1) + slashCompletions.length) % slashCompletions.length;
@@ -39883,6 +40200,7 @@ async function createSessionTui({
39883
40200
  idempotencyKey: crypto.randomUUID(),
39884
40201
  text: composerDraft.text,
39885
40202
  attachments: [...composerDraft.attachments],
40203
+ ...composerDraft.agent ? { agent: composerDraft.agent } : {},
39886
40204
  status: "admitting"
39887
40205
  };
39888
40206
  admittedSubmissions = [...admittedSubmissions, submission];
@@ -39935,6 +40253,12 @@ async function createSessionTui({
39935
40253
  handleCompactionRequest();
39936
40254
  return true;
39937
40255
  }
40256
+ if (command === "/model" || command === "/effort") {
40257
+ composer.setText("");
40258
+ composerDraft = { ...composerDraft, text: "" };
40259
+ openAgentSettingsPicker(command === "/model" ? "model" : "effort");
40260
+ return true;
40261
+ }
39938
40262
  if (command === "/logout") {
39939
40263
  composer.setText("");
39940
40264
  composerDraft = { ...composerDraft, text: "" };
@@ -39961,18 +40285,19 @@ async function createSessionTui({
39961
40285
  await submitMessage({
39962
40286
  text: submission.text,
39963
40287
  attachments: submission.attachments,
39964
- idempotencyKey: submission.idempotencyKey
40288
+ idempotencyKey: submission.idempotencyKey,
40289
+ ...submission.agent ? { agent: submission.agent } : {}
39965
40290
  });
39966
40291
  if (!viewIsActive())
39967
40292
  return;
39968
40293
  localPromptHistory.push(submission.text);
39969
40294
  const messageId = latestState.activeMessageId;
39970
- admittedSubmissions = messageId ? admittedSubmissions.map((candidate) => candidate.id === submission.id ? { id: candidate.id, idempotencyKey: candidate.idempotencyKey, text: candidate.text, attachments: candidate.attachments, status: "submitted", messageId } : candidate) : admittedSubmissions.filter((candidate) => candidate.id !== submission.id);
40295
+ admittedSubmissions = messageId ? admittedSubmissions.map((candidate) => candidate.id === submission.id ? { id: candidate.id, idempotencyKey: candidate.idempotencyKey, text: candidate.text, attachments: candidate.attachments, ...candidate.agent ? { agent: candidate.agent } : {}, status: "submitted", messageId } : candidate) : admittedSubmissions.filter((candidate) => candidate.id !== submission.id);
39971
40296
  composerFeedback = undefined;
39972
40297
  } catch (error93) {
39973
40298
  if (!viewIsActive())
39974
40299
  return;
39975
- admittedSubmissions = admittedSubmissions.map((candidate) => candidate.id === submission.id ? { id: candidate.id, idempotencyKey: candidate.idempotencyKey, text: candidate.text, attachments: candidate.attachments, status: "failed", error: error93 instanceof Error ? error93.message : String(error93) } : candidate);
40300
+ admittedSubmissions = admittedSubmissions.map((candidate) => candidate.id === submission.id ? { id: candidate.id, idempotencyKey: candidate.idempotencyKey, text: candidate.text, attachments: candidate.attachments, ...candidate.agent ? { agent: candidate.agent } : {}, status: "failed", error: error93 instanceof Error ? error93.message : String(error93) } : candidate);
39976
40301
  }
39977
40302
  render();
39978
40303
  }
@@ -39987,6 +40312,7 @@ async function createSessionTui({
39987
40312
  idempotencyKey: failed.idempotencyKey,
39988
40313
  text: failed.text,
39989
40314
  attachments: failed.attachments,
40315
+ ...failed.agent ? { agent: failed.agent } : {},
39990
40316
  status: "admitting"
39991
40317
  };
39992
40318
  admittedSubmissions = admittedSubmissions.map((submission) => submission.id === failed.id ? retrying : submission);
@@ -40097,6 +40423,8 @@ async function createSessionTui({
40097
40423
  }
40098
40424
  unsubscribe = controller.subscribe(({ state }) => {
40099
40425
  latestState = state;
40426
+ if (latestState.aggregateStatus !== "open")
40427
+ agentSettingsPicker = undefined;
40100
40428
  if (!isRemyWorking(latestState) && stopState.kind !== "idle") {
40101
40429
  stopState = { kind: "idle" };
40102
40430
  if (composerFeedback?.message === "Stop requested.")
@@ -40173,10 +40501,58 @@ function renderSlashCommandMenu({ commands, selectedIndex, width, maxRows }) {
40173
40501
  maxRows
40174
40502
  });
40175
40503
  }
40504
+ function renderAgentSettingsPicker({ picker, width, maxRows }) {
40505
+ const heading = picker.kind === "model" ? `Model for your next message \xB7 ${terminalSafeText(agentHarnessLabel(picker.provider))} harness` : "Reasoning effort for your next message";
40506
+ const items = picker.kind === "model" ? picker.models.map((model) => ({ label: agentModelLabel(model), description: agentModelDescription(model) })) : newSessionReasoningEfforts.map((effort) => ({ label: agentReasoningEffortLabel(effort), description: agentReasoningEffortDescription(effort) }));
40507
+ const menu = renderCompletionMenu({
40508
+ items,
40509
+ selectedIndex: picker.index,
40510
+ hints: [{ key: "\u2191\u2193", action: "select" }, { key: "Enter", action: "use for next message" }, { key: "Esc", action: "keep current" }],
40511
+ width,
40512
+ maxRows: Math.max(1, maxRows - 1)
40513
+ });
40514
+ return menu && joinStyled([new StyledText9([bold5(fg10(PALETTE.remyAccent)(heading))]), menu], `
40515
+ `);
40516
+ }
40517
+ function agentSettingsTarget({ state, staged }) {
40518
+ const requested = state.agentPending ?? state.agent;
40519
+ return {
40520
+ model: staged?.model ?? requested?.model,
40521
+ reasoningEffort: staged?.reasoningEffort ?? requested?.reasoningEffort
40522
+ };
40523
+ }
40524
+ function stageAgentChange({ state, staged, pick: pick3 }) {
40525
+ const current = agentSettingsTarget({ state, staged: undefined });
40526
+ const model = pick3.model ?? staged?.model;
40527
+ const reasoningEffort = pick3.reasoningEffort ?? staged?.reasoningEffort;
40528
+ return sessionAgentChange({
40529
+ model: model === current.model ? undefined : model,
40530
+ reasoningEffort: reasoningEffort === current.reasoningEffort ? undefined : reasoningEffort
40531
+ });
40532
+ }
40533
+ function agentSettingsLabel({ model, reasoningEffort }) {
40534
+ return [
40535
+ ...model === undefined ? [] : [agentModelLabel(model)],
40536
+ ...reasoningEffort === undefined || reasoningEffort === null ? [] : [agentReasoningEffortLabel(reasoningEffort)]
40537
+ ].join(" \xB7 ");
40538
+ }
40539
+ function renderAgentSettingsStatus({ state, stagedAgent }) {
40540
+ const applied = state.agent;
40541
+ if (!applied)
40542
+ return;
40543
+ const appliedLabel = terminalSafeText(`${agentHarnessLabel(applied.provider)} \xB7 ${agentSettingsLabel(applied)}`);
40544
+ const target = agentSettingsTarget({ state, staged: stagedAgent });
40545
+ const phase = stagedAgent ? "next message" : state.agentPending ? "switching\u2026" : undefined;
40546
+ const changes = phase !== undefined && (target.model !== applied.model || (target.reasoningEffort ?? null) !== applied.reasoningEffort);
40547
+ return new StyledText9([
40548
+ fg10(PALETTE.bodyText)(appliedLabel),
40549
+ ...changes ? [fg10(PALETTE.approvalQuestion)(` \u2192 ${terminalSafeText(agentSettingsLabel(target))} (${phase})`)] : []
40550
+ ]);
40551
+ }
40176
40552
  function hasRunningTurn(state) {
40177
40553
  return state.aggregateStatus === "open" && Object.values(state.messageTurns).some((turn) => turn.outcome === undefined);
40178
40554
  }
40179
- function renderStatusBand({ state, working, elapsedMs, stopState, lifecycleRequestState, repositoryLabel }) {
40555
+ function renderStatusBand({ state, working, elapsedMs, stopState, lifecycleRequestState, repositoryLabel, stagedAgent }) {
40180
40556
  const stopping = stopState?.kind === "stopping";
40181
40557
  const pendingOperation = lifecycleRequestState?.kind === "pending" ? lifecycleRequestState.operation : undefined;
40182
40558
  const presentation = pendingOperation ? { label: lifecycleOperationPresentParticiple(pendingOperation), color: PALETTE.approvalQuestion } : stopping ? { label: "Stopping", color: PALETTE.approvalQuestion } : sessionViewStatePresentation({ aggregateStatus: state.aggregateStatus, isWorking: working });
@@ -40185,11 +40561,13 @@ function renderStatusBand({ state, working, elapsedMs, stopState, lifecycleReque
40185
40561
  const sessionLabel = state.sessionNumber !== undefined ? `#${state.sessionNumber}` : state.sessionId;
40186
40562
  const pullRequest = state.pullRequest;
40187
40563
  const contextStatus = renderContextStatus(state.context.snapshot);
40564
+ const agentSettings = renderAgentSettingsStatus({ state, stagedAgent: state.aggregateStatus === "open" ? stagedAgent : undefined });
40188
40565
  const headerContext = [
40189
40566
  ...repositoryLabel ? [[dim7(fg10(PALETTE.dimText)(repositoryLabel))]] : [],
40190
40567
  ...pullRequest ? [[bold5(fg10(statusColor(pullRequest.status))(`PR#${pullRequest.number}`))]] : [],
40191
40568
  [bold5(fg10(presentation.color)(`${presentation.label}${elapsed}`))],
40192
40569
  connection.chunks,
40570
+ ...agentSettings ? [agentSettings.chunks] : [],
40193
40571
  ...contextStatus ? [[dim7(fg10(PALETTE.dimText)(contextStatus))]] : []
40194
40572
  ];
40195
40573
  return joinStyled([
@@ -41330,7 +41708,7 @@ async function dispatchCliCommandWithShutdown({
41330
41708
  });
41331
41709
  }
41332
41710
  if (command.name === "session")
41333
- return await attachSession({ dependencies, sessionId: command.sessionId, noTui: command.noTui, json: command.json, prompt: command.prompt });
41711
+ return await attachSession({ dependencies, sessionId: command.sessionId, noTui: command.noTui, json: command.json, followUp: command.followUp });
41334
41712
  return await createNewSession({ dependencies, command });
41335
41713
  }
41336
41714
  async function installCliUpdate({ dependencies, version: version5 }) {
@@ -42114,15 +42492,18 @@ async function createNewSession({
42114
42492
  });
42115
42493
  fileIds.push(uploaded.fileId);
42116
42494
  }
42117
- const created = await operations.createCodexSession({
42495
+ const created = await operations.createSession({
42118
42496
  client: operations.client,
42119
42497
  input: {
42120
42498
  installationId,
42121
42499
  repositoryIds: repositories.map((repository) => repository.id),
42122
42500
  prompt: command.prompt,
42123
42501
  fileIds,
42124
- ...command.model ? { model: command.model } : {},
42125
- reasoningEffort: command.reasoningEffort ?? defaultNewSessionAgent.reasoningEffort,
42502
+ agent: {
42503
+ provider: command.model ? newSessionModelHarness(command.model) : defaultAgentSelection.provider,
42504
+ ...command.model ? { model: command.model } : {},
42505
+ reasoningEffort: command.reasoningEffort ?? defaultNewSessionAgent.reasoningEffort
42506
+ },
42126
42507
  idempotencyKey: randomUUID5()
42127
42508
  }
42128
42509
  });
@@ -42174,7 +42555,7 @@ async function createFromTuiDraft({
42174
42555
  throw new Error("A non-empty prompt is required before a session can be created.");
42175
42556
  if (draft.repositories.some((repository) => repository.githubInstallationId !== draft.githubInstallationId))
42176
42557
  throw new Error("All selected repositories must belong to the same GitHub installation.");
42177
- return await operations.createCodexSession({
42558
+ return await operations.createSession({
42178
42559
  client: operations.client,
42179
42560
  input: {
42180
42561
  installationId: draft.githubInstallationId,
@@ -42182,8 +42563,11 @@ async function createFromTuiDraft({
42182
42563
  repositoryBranchOverrides: draft.repositoryBranchOverrides ?? [],
42183
42564
  prompt: draft.prompt,
42184
42565
  fileIds: draft.attachments.map((attachment) => attachment.fileId),
42185
- model: draft.model,
42186
- reasoningEffort: draft.reasoningEffort,
42566
+ agent: {
42567
+ provider: newSessionModelHarness(draft.model),
42568
+ model: draft.model,
42569
+ reasoningEffort: draft.reasoningEffort
42570
+ },
42187
42571
  idempotencyKey: randomUUID5()
42188
42572
  }
42189
42573
  });
@@ -42238,26 +42622,35 @@ async function attachSession({
42238
42622
  sessionId,
42239
42623
  noTui,
42240
42624
  json: json3,
42241
- prompt
42625
+ followUp
42242
42626
  }) {
42243
42627
  const operations = await createSessionOperations(dependencies);
42244
42628
  const detail = await operations.getSession({ client: operations.client, sessionId });
42629
+ if (followUp?.agent?.model !== undefined && detail.agent)
42630
+ assertModelInSessionHarness({ model: followUp.agent.model, provider: detail.agent.provider });
42245
42631
  const repositories = detail.repositories.map((repository) => ({ id: repository.id, fullName: repository.full_name }));
42246
42632
  const cache = await (dependencies.readSessionCache ?? readSessionCache)(resolveSessionCachePathForCommand({ dependencies, sessionId }));
42247
42633
  let activeMessageId = cache?.activeMessageId;
42248
42634
  let cacheWarningReported = false;
42249
- const onCacheError = prompt === undefined ? undefined : () => {
42635
+ const onCacheError = followUp === undefined ? undefined : () => {
42250
42636
  if (cacheWarningReported)
42251
42637
  return;
42252
42638
  cacheWarningReported = true;
42253
42639
  dependencies.output.writeStderr(`Local session cache is unavailable; continuing to observe the accepted follow-up. Do not resubmit the prompt.
42254
42640
  `);
42255
42641
  };
42256
- if (prompt !== undefined) {
42642
+ if (followUp !== undefined) {
42257
42643
  throwIfAborted2(dependencies.abortSignal);
42258
42644
  const appended = await operations.appendSessionMessage({
42259
42645
  client: operations.client,
42260
- input: { sessionId, text: prompt, fileIds: [], mode: "steer", idempotencyKey: randomUUID5() }
42646
+ input: {
42647
+ sessionId,
42648
+ text: followUp.prompt,
42649
+ fileIds: [],
42650
+ mode: "steer",
42651
+ idempotencyKey: randomUUID5(),
42652
+ ...followUp.agent === undefined ? {} : { agent: followUp.agent }
42653
+ }
42261
42654
  });
42262
42655
  activeMessageId = appended.message.id;
42263
42656
  }
@@ -42289,6 +42682,13 @@ async function attachSession({
42289
42682
  onCacheError
42290
42683
  });
42291
42684
  }
42685
+ function assertModelInSessionHarness({ model, provider }) {
42686
+ const models = sessionHarnessModels(provider);
42687
+ if (models.includes(model))
42688
+ return;
42689
+ const offered = models.length === 0 ? "Remy does not offer model changes for that harness." : `Choose one of: ${models.join(", ")}.`;
42690
+ throw new Error(`--model ${model} is not available: this session runs on the ${agentHarnessLabel(provider)} harness, which cannot change mid-session. ${offered}`);
42691
+ }
42292
42692
  async function runAttachedSession({
42293
42693
  dependencies,
42294
42694
  operations,
@@ -42385,10 +42785,15 @@ async function runAttachedSession({
42385
42785
  text: submission.text,
42386
42786
  fileIds: submission.attachments.map((attachment) => attachment.fileId),
42387
42787
  idempotencyKey: submission.idempotencyKey,
42388
- mode: "steer"
42788
+ mode: "steer",
42789
+ ...submission.agent === undefined ? {} : { agent: submission.agent }
42389
42790
  }
42390
42791
  });
42391
42792
  await controller.recordActiveMessage(result.message.id);
42793
+ if (submission.agent !== undefined)
42794
+ controller.refreshDetail().catch(() => {
42795
+ return;
42796
+ });
42392
42797
  return { messageId: result.message.id };
42393
42798
  },
42394
42799
  requestInterrupt: async ({ idempotencyKey }) => {
@@ -42519,7 +42924,7 @@ async function createSessionOperations(dependencies, { onAuthenticated } = {}) {
42519
42924
  suggestRepositories: dependencies.suggestRepositories ?? (async () => await Promise.reject(new Error("Missing remote repository suggestions operation."))),
42520
42925
  suggestBranches: dependencies.suggestBranches ?? (async () => await Promise.reject(new Error("Missing remote branch suggestions operation."))),
42521
42926
  reserveAndUploadFile: dependencies.reserveAndUploadFile ?? reserveAndUploadFile,
42522
- createCodexSession: dependencies.createCodexSession ?? createCodexSession,
42927
+ createSession: dependencies.createSession ?? createSession,
42523
42928
  appendSessionMessage: dependencies.appendSessionMessage ?? appendSessionMessage,
42524
42929
  cancelSession: dependencies.cancelSession ?? cancelSession,
42525
42930
  completeSession: dependencies.completeSession ?? completeSession,
@@ -42540,7 +42945,7 @@ async function createSessionOperations(dependencies, { onAuthenticated } = {}) {
42540
42945
  suggestRepositories: dependencies.suggestRepositories ?? createRepositorySuggester({ client }),
42541
42946
  suggestBranches: dependencies.suggestBranches ?? createBranchSuggester({ client }),
42542
42947
  reserveAndUploadFile: dependencies.reserveAndUploadFile ?? reserveAndUploadFile,
42543
- createCodexSession: dependencies.createCodexSession ?? createCodexSession,
42948
+ createSession: dependencies.createSession ?? createSession,
42544
42949
  appendSessionMessage: dependencies.appendSessionMessage ?? appendSessionMessage,
42545
42950
  cancelSession: dependencies.cancelSession ?? cancelSession,
42546
42951
  completeSession: dependencies.completeSession ?? completeSession,
@@ -42732,8 +43137,12 @@ Arguments:
42732
43137
  prompt Submit a follow-up as Steer before attaching
42733
43138
 
42734
43139
  With a prompt, JSON output waits for that message's turn result. Use -- before a prompt beginning with --.
43140
+ --model and --reasoning-effort require a prompt: the change travels with it and stays the session's setting.
43141
+ A running turn switches from its next model request; otherwise the change applies from the turn the prompt starts.
42735
43142
 
42736
43143
  Options:
43144
+ --model <name> Switch to another model of the session's harness
43145
+ --reasoning-effort <low|medium|high|xhigh> Switch agent reasoning effort
42737
43146
  --no-tui Do not open the interactive terminal view
42738
43147
  --json Write session updates as JSON
42739
43148
  --help, -h Show this help
@@ -42747,7 +43156,7 @@ Create a remote coding session from the prompt and flags. In an interactive term
42747
43156
  Options:
42748
43157
  --repository <owner/name> Select a repository; repeat for more repositories
42749
43158
  --installation <id> Select a GitHub installation
42750
- --model <name> Select an agent model
43159
+ --model <name> Select a Codex or Claude model; it sets the harness
42751
43160
  --reasoning-effort <low|medium|high|xhigh> Select agent reasoning effort
42752
43161
  --attach <path> Upload a file or directory (20 MiB max); repeat as needed
42753
43162
  --no-tui Do not open the interactive terminal view
@@ -42764,7 +43173,7 @@ Usage:
42764
43173
  Commands:
42765
43174
  remy Open interactive dashboard
42766
43175
  remy dashboard Open interactive dashboard
42767
- remy --session <session-id> [--no-tui] [--json] [prompt]
43176
+ remy --session <session-id> [--model <name> --reasoning-effort <low|medium|high|xhigh> --no-tui --json] [prompt]
42768
43177
  Attach to a session, optionally submitting a follow-up
42769
43178
  remy new [--repository <owner/name> ... --installation <id> --model <name> --reasoning-effort <low|medium|high|xhigh> --attach <path> ... --no-tui --json] <prompt>
42770
43179
  Create a session
@@ -42802,8 +43211,11 @@ function parseSessionAttach(argv) {
42802
43211
  let noTui = false;
42803
43212
  let json3 = false;
42804
43213
  let prompt;
43214
+ let model;
43215
+ let reasoningEffort;
42805
43216
  let positionalOnly = false;
42806
- for (const token of argv.slice(1)) {
43217
+ for (let index = 1;index < argv.length; index += 1) {
43218
+ const token = argv[index];
42807
43219
  if (!positionalOnly && token === "--") {
42808
43220
  positionalOnly = true;
42809
43221
  continue;
@@ -42816,6 +43228,17 @@ function parseSessionAttach(argv) {
42816
43228
  json3 = true;
42817
43229
  continue;
42818
43230
  }
43231
+ if (!positionalOnly && (token === "--model" || token === "--reasoning-effort")) {
43232
+ const value = argv[index + 1];
43233
+ if (!value || value.startsWith("--"))
43234
+ throw new Error(`${token} requires a value.`);
43235
+ index += 1;
43236
+ if (token === "--model")
43237
+ model = parseModelFlag(value);
43238
+ else
43239
+ reasoningEffort = parseReasoningEffortFlag(value);
43240
+ continue;
43241
+ }
42819
43242
  if (!positionalOnly && token.startsWith("--"))
42820
43243
  throw new Error(`Unknown --session flag ${token}.`);
42821
43244
  if (prompt !== undefined)
@@ -42824,7 +43247,28 @@ function parseSessionAttach(argv) {
42824
43247
  throw new Error("A follow-up prompt must not be empty.");
42825
43248
  prompt = token;
42826
43249
  }
42827
- return { name: "session", sessionId, noTui, json: json3, ...prompt === undefined ? {} : { prompt } };
43250
+ const agent = sessionAgentChange({ model, reasoningEffort });
43251
+ if (agent && prompt === undefined)
43252
+ throw new Error("--model and --reasoning-effort change the session with a follow-up message. Pass a prompt too.");
43253
+ return {
43254
+ name: "session",
43255
+ sessionId,
43256
+ noTui,
43257
+ json: json3,
43258
+ ...prompt === undefined ? {} : { followUp: { prompt, ...agent ? { agent } : {} } }
43259
+ };
43260
+ }
43261
+ function parseModelFlag(value) {
43262
+ const model = parseNewSessionModel(value);
43263
+ if (!model)
43264
+ throw new Error(`--model must name a supported model: ${newSessionModels.join(", ")}.`);
43265
+ return model;
43266
+ }
43267
+ function parseReasoningEffortFlag(value) {
43268
+ const reasoningEffort = parseNewSessionReasoningEffort(value);
43269
+ if (!reasoningEffort)
43270
+ throw new Error(`--reasoning-effort must be ${newSessionReasoningEfforts.slice(0, -1).join(", ")}, or ${newSessionReasoningEfforts.at(-1)}.`);
43271
+ return reasoningEffort;
42828
43272
  }
42829
43273
  function parseNewCommand(argv) {
42830
43274
  const repositories = [];
@@ -42860,16 +43304,11 @@ function parseNewCommand(argv) {
42860
43304
  } else if (token === "--attach") {
42861
43305
  attachments.push(value);
42862
43306
  } else if (token === "--model") {
42863
- const parsedModel = codexModelIdSchema.safeParse(value);
42864
- if (!parsedModel.success)
42865
- throw new Error("--model must name a supported Codex model.");
42866
- model = parsedModel.data;
43307
+ model = parseModelFlag(value);
42867
43308
  } else if (token === "--installation") {
42868
43309
  installationId = value;
42869
43310
  } else if (token === "--reasoning-effort") {
42870
- if (!selectableAgentReasoningEfforts.includes(value))
42871
- throw new Error("--reasoning-effort must be low, medium, high, or xhigh.");
42872
- reasoningEffort = value;
43311
+ reasoningEffort = parseReasoningEffortFlag(value);
42873
43312
  } else {
42874
43313
  throw new Error(`Unknown new flag ${token}.`);
42875
43314
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meistrari/remy-cli",
3
- "version": "1.22.0-rc.0",
3
+ "version": "1.22.0-rc.2",
4
4
  "description": "Remy, the Coding Agent terminal client.",
5
5
  "type": "module",
6
6
  "bin": {