@sagmans/dsh-tui 0.1.2 → 0.3.0

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 (158) hide show
  1. package/README.md +196 -17
  2. package/cordis.patch.yml +4 -2
  3. package/lib/agent/host.d.ts +14 -0
  4. package/lib/agent/host.d.ts.map +1 -1
  5. package/lib/agent/host.js +20 -4
  6. package/lib/agent/host.js.map +1 -1
  7. package/lib/agent/model.d.ts +50 -0
  8. package/lib/agent/model.d.ts.map +1 -1
  9. package/lib/agent/model.js +87 -1
  10. package/lib/agent/model.js.map +1 -1
  11. package/lib/agent/present.d.ts +7 -1
  12. package/lib/agent/present.d.ts.map +1 -1
  13. package/lib/agent/present.js +33 -4
  14. package/lib/agent/present.js.map +1 -1
  15. package/lib/agent/presets.d.ts +7 -1
  16. package/lib/agent/presets.d.ts.map +1 -1
  17. package/lib/agent/presets.js +7 -3
  18. package/lib/agent/presets.js.map +1 -1
  19. package/lib/agent/status.d.ts +10 -0
  20. package/lib/agent/status.d.ts.map +1 -1
  21. package/lib/agent/status.js +2 -0
  22. package/lib/agent/status.js.map +1 -1
  23. package/lib/cards.d.ts +127 -7
  24. package/lib/cards.d.ts.map +1 -1
  25. package/lib/cards.js +381 -52
  26. package/lib/cards.js.map +1 -1
  27. package/lib/export.d.ts +5 -4
  28. package/lib/export.d.ts.map +1 -1
  29. package/lib/export.js +62 -13
  30. package/lib/export.js.map +1 -1
  31. package/lib/fold-cursor.d.ts +23 -0
  32. package/lib/fold-cursor.d.ts.map +1 -0
  33. package/lib/fold-cursor.js +31 -0
  34. package/lib/fold-cursor.js.map +1 -0
  35. package/lib/gates.d.ts +145 -2
  36. package/lib/gates.d.ts.map +1 -1
  37. package/lib/gates.js +335 -40
  38. package/lib/gates.js.map +1 -1
  39. package/lib/index.d.ts +7 -1
  40. package/lib/index.d.ts.map +1 -1
  41. package/lib/index.js +651 -92
  42. package/lib/index.js.map +1 -1
  43. package/lib/input/actions.d.ts +136 -0
  44. package/lib/input/actions.d.ts.map +1 -0
  45. package/lib/input/actions.js +740 -0
  46. package/lib/input/actions.js.map +1 -0
  47. package/lib/input/keymap-settings.d.ts +21 -0
  48. package/lib/input/keymap-settings.d.ts.map +1 -0
  49. package/lib/input/keymap-settings.js +28 -0
  50. package/lib/input/keymap-settings.js.map +1 -0
  51. package/lib/input/keymap.d.ts +91 -0
  52. package/lib/input/keymap.d.ts.map +1 -0
  53. package/lib/input/keymap.js +170 -0
  54. package/lib/input/keymap.js.map +1 -0
  55. package/lib/input/match.d.ts +10 -0
  56. package/lib/input/match.d.ts.map +1 -0
  57. package/lib/input/match.js +83 -0
  58. package/lib/input/match.js.map +1 -0
  59. package/lib/input/submission.d.ts +8 -1
  60. package/lib/input/submission.d.ts.map +1 -1
  61. package/lib/input/submission.js +9 -2
  62. package/lib/input/submission.js.map +1 -1
  63. package/lib/input.d.ts +17 -0
  64. package/lib/input.d.ts.map +1 -0
  65. package/lib/input.js +27 -0
  66. package/lib/input.js.map +1 -0
  67. package/lib/keys-command.d.ts +16 -0
  68. package/lib/keys-command.d.ts.map +1 -0
  69. package/lib/keys-command.js +60 -0
  70. package/lib/keys-command.js.map +1 -0
  71. package/lib/queue.d.ts +6 -0
  72. package/lib/queue.d.ts.map +1 -0
  73. package/lib/queue.js +68 -0
  74. package/lib/queue.js.map +1 -0
  75. package/lib/settings-notice.d.ts +19 -0
  76. package/lib/settings-notice.d.ts.map +1 -0
  77. package/lib/settings-notice.js +30 -0
  78. package/lib/settings-notice.js.map +1 -0
  79. package/lib/terminal/warning-screen.d.ts +8 -0
  80. package/lib/terminal/warning-screen.d.ts.map +1 -0
  81. package/lib/terminal/warning-screen.js +66 -0
  82. package/lib/terminal/warning-screen.js.map +1 -0
  83. package/lib/theme-capability.d.ts +36 -0
  84. package/lib/theme-capability.d.ts.map +1 -0
  85. package/lib/theme-capability.js +190 -0
  86. package/lib/theme-capability.js.map +1 -0
  87. package/lib/theme-command.d.ts +10 -0
  88. package/lib/theme-command.d.ts.map +1 -0
  89. package/lib/theme-command.js +61 -0
  90. package/lib/theme-command.js.map +1 -0
  91. package/lib/theme-settings.d.ts +196 -0
  92. package/lib/theme-settings.d.ts.map +1 -0
  93. package/lib/theme-settings.js +229 -0
  94. package/lib/theme-settings.js.map +1 -0
  95. package/lib/theme-tokens.d.ts +110 -0
  96. package/lib/theme-tokens.d.ts.map +1 -0
  97. package/lib/theme-tokens.js +427 -0
  98. package/lib/theme-tokens.js.map +1 -0
  99. package/lib/theme.d.ts +32 -35
  100. package/lib/theme.d.ts.map +1 -1
  101. package/lib/theme.js +112 -63
  102. package/lib/theme.js.map +1 -1
  103. package/lib/tokens.d.ts +15 -0
  104. package/lib/tokens.d.ts.map +1 -0
  105. package/lib/tokens.js +29 -0
  106. package/lib/tokens.js.map +1 -0
  107. package/lib/transcript.d.ts +26 -1
  108. package/lib/transcript.d.ts.map +1 -1
  109. package/lib/transcript.js +153 -25
  110. package/lib/transcript.js.map +1 -1
  111. package/lib/ui/dock.d.ts.map +1 -1
  112. package/lib/ui/dock.js +67 -28
  113. package/lib/ui/dock.js.map +1 -1
  114. package/lib/ui/editor.d.ts +51 -0
  115. package/lib/ui/editor.d.ts.map +1 -0
  116. package/lib/ui/editor.js +159 -0
  117. package/lib/ui/editor.js.map +1 -0
  118. package/lib/ui/frame.d.ts +54 -0
  119. package/lib/ui/frame.d.ts.map +1 -0
  120. package/lib/ui/frame.js +79 -0
  121. package/lib/ui/frame.js.map +1 -0
  122. package/lib/ui/gate-input.d.ts +20 -0
  123. package/lib/ui/gate-input.d.ts.map +1 -0
  124. package/lib/ui/gate-input.js +96 -0
  125. package/lib/ui/gate-input.js.map +1 -0
  126. package/lib/ui/markdown.d.ts +19 -2
  127. package/lib/ui/markdown.d.ts.map +1 -1
  128. package/lib/ui/markdown.js +37 -6
  129. package/lib/ui/markdown.js.map +1 -1
  130. package/lib/ui/mermaid.d.ts +44 -0
  131. package/lib/ui/mermaid.d.ts.map +1 -0
  132. package/lib/ui/mermaid.js +178 -0
  133. package/lib/ui/mermaid.js.map +1 -0
  134. package/lib/ui/picker.d.ts +66 -7
  135. package/lib/ui/picker.d.ts.map +1 -1
  136. package/lib/ui/picker.js +112 -19
  137. package/lib/ui/picker.js.map +1 -1
  138. package/lib/ui/prompt.d.ts +30 -0
  139. package/lib/ui/prompt.d.ts.map +1 -0
  140. package/lib/ui/prompt.js +45 -0
  141. package/lib/ui/prompt.js.map +1 -0
  142. package/lib/ui/queue.d.ts +24 -0
  143. package/lib/ui/queue.d.ts.map +1 -0
  144. package/lib/ui/queue.js +57 -0
  145. package/lib/ui/queue.js.map +1 -0
  146. package/lib/ui/status.d.ts +7 -1
  147. package/lib/ui/status.d.ts.map +1 -1
  148. package/lib/ui/status.js +84 -24
  149. package/lib/ui/status.js.map +1 -1
  150. package/lib/ui/view.d.ts +65 -2
  151. package/lib/ui/view.d.ts.map +1 -1
  152. package/lib/ui/view.js +319 -59
  153. package/lib/ui/view.js.map +1 -1
  154. package/lib/work.d.ts +48 -0
  155. package/lib/work.d.ts.map +1 -1
  156. package/lib/work.js +44 -0
  157. package/lib/work.js.map +1 -1
  158. package/package.json +5 -2
package/README.md CHANGED
@@ -88,6 +88,7 @@ Two facts explain most failures.
88
88
  | `dsh: cannot resolve profile bundle "@sagmans/dsh-tui" ...` | the linked checkout moved or was deleted | `dsh plugin --profile tui add "$PLUGIN_CHECKOUT"` |
89
89
  | `dsh --profile tui` prints nothing and never exits | the bundle left `dsh.profile.bundles`, usually after a broken link and a `plugin install` | confirm the layer list, then run the `add` command again |
90
90
  | `dsh-tui: both stdin and stdout must be TTYs` | stdin or stdout is a pipe, a file, or a CI runner | run the command from a terminal |
91
+ | Node warnings, such as `ExperimentalWarning: stripTypeScriptTypes …`, appear after exit | the TUI holds runtime warnings until it returns the terminal to your shell; startup warnings remain visible before the TUI starts | read the warnings in your shell after exit; no warning-suppression flag is needed |
91
92
  | Changes under `src/` have no effect | a linked profile loads `lib/`, not `src/` | `pnpm run build` in the plugin checkout |
92
93
  | `pnpm dsh --profile tui` exits before the surface appears | pnpm's dependency check fails on the harness checkout's own postinstall | see [Launching from a harness checkout](#launching-from-a-harness-checkout) |
93
94
  | `--preset <id>` is refused, because the session's agent preset is fixed | a session keeps the mode that composed it, and this session already took a turn | `/preset <id>` before the first turn, or resume without `--preset` |
@@ -110,32 +111,43 @@ node -p "require((process.env.DSH_HOME ?? require('node:os').homedir() + '/.dsh'
110
111
  dsh --profile tui # new session in the current directory
111
112
  dsh --profile tui --resume # pick a stored session, titled by its first prompt
112
113
  dsh --profile tui --resume <session-id>
113
- dsh --profile tui --preset ptc # start in one of the shipped agent modes
114
+ dsh --profile tui --preset minimal # start in a shipped mode other than the default (PTC)
114
115
  dsh --profile tui --model deepseek-chat
115
116
  dsh --profile tui --no-color
116
117
  dsh --profile tui --no-bell # do not ring when a long turn finishes
117
118
  ```
118
119
 
120
+ Every key below is a shipped default. `/keys` lists every action the surface
121
+ and its library can perform with the keys in force, and the `keys:` section
122
+ moves any of them — see [Keys](#keys).
123
+
119
124
  | Key | Action |
120
125
  |---|---|
121
- | Enter | submit the prompt |
126
+ | Enter / Shift+Enter | break the line: a prompt is written before it is sent |
127
+ | Ctrl+Enter / Alt+Enter / Ctrl+S | submit the prompt |
122
128
  | Ctrl+C | interrupt the running turn, or leave when idle |
123
- | Ctrl+O | show every line of the tool cards instead of their preview |
124
- | Ctrl+T | show the reasoning behind an answer instead of its summary |
129
+ | Ctrl+O | open every tool card: its header plus every retained row. Folded, a card is one line, and a shell card keeps its command plus the last 20 rows of output with a hint naming what it dropped |
130
+ | Ctrl+Y | show or hide the calls a PTC program dispatched: one two-space-indented entry per call under its `run_code` card, named and argued from the tool's own header and wrapped at the screen edge; shown by default |
131
+ | Shift+Tab | expand or fold the reasoning behind an answer: folded, the row names itself, its token count, and the key; opened, it adds the thought |
132
+ | Ctrl+T | pick the reasoning effort for the next step |
133
+ | Ctrl+X then M | open the model picker |
134
+ | Ctrl+X then Y | copy the last answer to the clipboard |
125
135
  | `y` / `n` / Esc | allow once, reject, or cancel a pending approval |
126
- | digits / space / ↑↓ / Enter / Esc | answer a question: pick or toggle, confirm, or skip one |
136
+ | digits / space / ↑↓ / Enter / Esc | answer a question: pick or toggle, confirm, or skip one; `0` answers with your own text in the input bar |
137
+ | typing in any picker or question | narrow the rows by fragment (`glm53` finds `GLM-5.3`); backspace widens, `esc` or Ctrl+C leaves |
127
138
  | `/` then Tab | complete commands, including every command this session registered |
128
139
  | `@` or a path then Tab | complete workspace file references |
129
140
  | `ctrl+shift+f` | search the transcript (`enter` next, `shift+enter` previous, `esc` close) |
130
141
  | `home` / `end` | jump to the start or the end of the transcript |
131
142
  | `ctrl+down` | jump to the next prompt |
132
- | `ctrl+b` | leave a child's conversation and return to this session |
143
+ | `ctrl+b` | leave a child's conversation and return to this session (the status line names the key you have now) |
133
144
  | mouse wheel, drag | scroll, and copy a selection through OSC 52 |
134
145
  | `/help` | list registered and local commands |
135
146
  | `/status` | show the session id, model, permissions, context, and directory |
136
- | `/model` | show the route the next step will use, and the providers available |
147
+ | `/model` | open the picker for the configured providers and their models; it heads itself with the route the next step will use, and typing filters it by fragment (`glm53` finds `GLM-5.3`) |
137
148
  | `/model <provider>` | list that provider's advertised models |
138
149
  | `/model <provider>/<model>` | use that route from the next step on (session only, nothing is written to settings) |
150
+ | `/model <provider>/<model>/<effort>` | use that route and reasoning effort (the effort must be one the route advertises) |
139
151
  | `/preset` | pick the agent mode for this session from the roster |
140
152
  | `/preset <id>` | switch to that mode, while the session is still blank |
141
153
  | `/jobs` | list background jobs with their state and duration |
@@ -148,10 +160,156 @@ dsh --profile tui --no-bell # do not ring when a long turn finishes
148
160
  | `/export [path]` | write the visible transcript as markdown (default `dsh-session-<id>.md`) |
149
161
  | `/resume` | open another stored session without leaving the terminal |
150
162
  | `/clear` | clear the visible transcript |
163
+ | `/theme` | list every styled element and the value in force |
164
+ | `/keys` | list every action and the keys in force; `/keys <layer>` narrows it (see [Keys](#keys)) |
151
165
  | `/quit` | leave and print the resume command |
152
166
 
167
+ `Ctrl+X` starts a chord. For the next two seconds the footer leads with the
168
+ prefix alone — enough to say that a key is waiting, without reciting the map —
169
+ and a key that finishes nothing is typed as usual rather than swallowed, so a
170
+ prefix pressed by accident costs nothing; `/help` lists the chords, `m` for the
171
+ model picker, `p` for plan mode, and `y` for the last answer.
172
+ `keys.chord.prefix: alt+x` starts the chord with another key — or with a list of
173
+ them, as so many ways in — and `prefixWindow: 0` waits for the next key instead
174
+ of lapsing; every second key is a row of its own (`chord.model`, `chord.plan`,
175
+ `chord.copy`), so a chord can be respelled whole. A prefix that is not a modifier chord, that
176
+ the surface or the prompt bar already answers (`ctrl+c`, `ctrl+s`), or that the
177
+ terminal keeps (`ctrl+q`) is refused with the reason, and the shipped keymap
178
+ stays in force. The chords themselves are the commands they stand for: `m`, `p`,
179
+ and `y` ask the same dispatcher `/model`, `/plan`, and `/copy` do. Plan mode is
180
+ the one pair that cannot share a name: `/plan` only enters, so the chord names
181
+ `/plan off` instead when the agent is in plan mode — or is waiting for the turn
182
+ boundary to become so — and reads that state from the plan package rather than
183
+ from the dock.
184
+
185
+ An approval or a question draws inline above the editor and takes the keyboard. A question that lists options always adds row `0. other — type your own answer`: type or paste an answer the model did not offer, and the seam receives it as that question's free text — replacing a single-select choice, or supplementing a multi-select one. `0`, or `↓` past the last option, reaches the row; `↑` walks back to the list with the text kept, and `esc` does the same from that row, because a question skipped by accident is a question answered twice — an escape from the list skips it. Free text is written in the prompt bar's own editor, drawn under that row: movement, word and line deletion, undo, completion, and multi-line paste are all the editor the reader already uses, and the prompt bar steps aside while a question is open, so a prompt written but not sent comes back untouched once the question is answered. No question hides its answer — the reader is the one who has to check what they are about to send. Every gate row wraps at the screen edge under its own label, so a long option or question is readable rather than cut.
186
+
187
+ While a turn runs, a prompt submitted into the editor waits in the agent's own inbox instead of disappearing: it is drawn above the editor in the input bar's own frame, faint and italic, and moves into the transcript when the agent takes it — where it keeps that frame in the prompt's own mint shade, so what the reader typed is never mistaken for what the agent said. `editor.queued` and `editor.queued.more` restyle or hide the waiting rows; `transcript.user` restyles the submitted prompt.
188
+
153
189
  Any other `/command` goes to the command registry, so `/plan`, `/compact`, `/goal`, and `/feedback` behave as they do on the other surfaces.
154
190
 
191
+ ## Settings
192
+
193
+ Every styled element is a named token with a shipped default, and every key is
194
+ an action with one, so the surface can be restyled and rebound without touching
195
+ code. Preferences live in the same user-settings document as every other
196
+ (`$DSH_HOME/settings.yaml`), under a `dsh-tui:` section:
197
+
198
+ ```yaml
199
+ dsh-tui:
200
+ subcalls: collapsed # fold the calls a PTC program dispatched (default inline)
201
+ mermaid: streaming # draw a reply's mermaid fences: off, final, or streaming (default streaming)
202
+ prefixWindow: 2 # seconds a chord waits for its second key; 0 waits for the next key instead
203
+ keys:
204
+ chord.prefix: ctrl+x # the key that starts a chord; "prefix:" is the older spelling of this row
205
+ prompt.submit: [ctrl+enter, alt+enter, ctrl+s]
206
+ surface.effort: ctrl+t # one key, or a list of them
207
+ tui.editor.yank: ctrl+y # any action the library draws, by the id /keys prints
208
+ palette:
209
+ muted: '#5c5c5c' # one shade quiets every receding element
210
+ tokens:
211
+ transcript.reasoning.body:
212
+ fg: '#7a7a7a'
213
+ italic: true
214
+ tool.title:
215
+ fg: accent # a palette name, a hex value, or an index 0-255
216
+ bold: true
217
+ dock.jobs.heading:
218
+ hidden: true # the element renders nothing at all
219
+ ```
220
+
221
+ Every field is optional, so a section that changes one shade is enough. The
222
+ document is hot-reloaded: an edit restyles a running session and re-arms the
223
+ keymap on the next press, and `/theme` shows each element's effective value and
224
+ whether it came from an override, the palette, or the default.
225
+
226
+
227
+ The section is not only shades. By default every session draws the calls a PTC
228
+ program dispatched under their card, and `subcalls: collapsed` starts with the
229
+ card alone instead. `Ctrl+Y` toggles the same choice for the current session,
230
+ and an edit to the document re-seeds it. An unknown key or value is
231
+ refused with a notice naming it, so a typo cannot quietly do nothing.
232
+
233
+ A reply whose fenced block names `mermaid` is drawn as terminal box art instead
234
+ of source, laid out at the width the transcript has. `mermaid: streaming` (the
235
+ default) draws a diagram while the reply is still arriving, `final` waits for
236
+ the turn to end, and `off` leaves every fence exactly as written. A diagram
237
+ wider than the terminal, one the renderer cannot draw at all, or one whose source
238
+ is larger than a frame can lay out stays as the source fence rather than being
239
+ truncated; a settled diagram whose source was only partly readable keeps the
240
+ fence and names what was dropped. The drawing is
241
+ restyleable like anything else through `markdown.diagram.border`,
242
+ `.text`, `.edge`, `.edgeLabel`, `.title`, and `.warning`, so `/theme`
243
+ lists it with the rest. Nothing is lost by drawing: `/export` and the session
244
+ file keep the reply exactly as the model wrote it.
245
+
246
+ `fg` and `bg` accept `#rrggbb`, a palette name (`default`, `muted`, `accent`,
247
+ `arg`, `warn`, `added`, `removed`, `user`, `assistant`), or an index. A colour is
248
+ emitted as 24-bit when the terminal advertises it (`COLORTERM`) and degraded to
249
+ the nearest 256-colour entry or 16-colour slot otherwise; a hue keeps its family
250
+ there, so an addition stays green instead of collapsing to black. Muted elements
251
+ name the palette rather than a terminal slot, so on anything but a 16-colour
252
+ terminal their contrast does not depend on what the reader's colour scheme maps
253
+ slot 8 to. `arg` is the pale blue a card gives the argument it was called with,
254
+ so `tool.args` is restyled on its own and stays distinct from the tool's own
255
+ label and from its output. `user` is the mint a submitted prompt takes, so a
256
+ reader's own turns stand apart from the reply without reading either.
257
+
258
+ `NO_COLOR` and `--no-color` disable styling entirely, attributes included, and
259
+ outrank everything in this section. A token or palette name the surface does not
260
+ have is refused with the offending name, and the surface prints the refusal as a
261
+ notice when the document loads, so a typo cannot quietly paint nothing.
262
+
263
+ ### Keys
264
+
265
+ Every press the surface answers is an action with an id and a shipped key.
266
+ `/keys` prints all of them with the keys in force, marks the rows you wrote,
267
+ names the keys your map took from the library, and ends with a sample `keys:`
268
+ section rather than a whole one; the table above it is the complete account.
269
+ `/keys prompt`, `surface`, `chord`, `gate`, `question`,
270
+ `picker`, and `library` narrow that list to one part of the surface.
271
+
272
+ An entry is one key or a list of them. A key is a modifier chord
273
+ (`ctrl`/`alt`/`shift` joined by `+`, written in that order), a named key
274
+ (`enter`, `escape`, `tab`, `space`, `backspace`, `delete`, `home`, `end`,
275
+ `pageUp`, `pageDown`, the arrows, `f1`–`f12`), or a bare character where the
276
+ layer reads one: `y` and `n` for an approval, or a chord's second key. Ids
277
+ beginning `tui.` are pi-tui's own actions, so the editor, the search, and the
278
+ transcript move where you tell them to.
279
+
280
+ Refused, with the reason in a notice and the shipped map left in force: an
281
+ action the surface does not have, a key no terminal reports, `ctrl+q` (the
282
+ terminal keeps it), a bare character outside the chord and gate layers, two
283
+ actions of one layer on one press, a key the library already answers on a row you
284
+ never wrote, a key the viewport reads before the surface sees it, whichever of the
285
+ two the map moved onto it (`pageUp`, or `tui.altScreen.search` moved onto a
286
+ surface key), a `chord.prefix` that is not a modifier chord or that takes a key
287
+ the surface or the prompt bar answers, and `prefix:` beside
288
+ `keys.chord.prefix:`, which are the same row under two names.
289
+
290
+ Two rows count as one press when some sequence reaches both, not merely when they
291
+ are spelled alike, because one press can arrive as several bytes and one byte can
292
+ spell several keys. A bare terminal reports Return for `enter` and `ctrl+m`, a
293
+ line feed for `ctrl+j` and, without the keyboard protocol, Return as well, one
294
+ control byte carries both `ctrl+-` and `ctrl+_`, and an escape with a letter
295
+ reaches `alt+up` as readily as `alt+p`.
296
+
297
+ A key the surface or a chord answers is a key the library never sees: that is
298
+ how `ctrl+y` shows nested calls instead of yanking a line in the editor.
299
+ `/keys` names every shadow your map introduces, and moving the surface key
300
+ hands the library its own key back.
301
+
302
+ Left alone, because they are typing rather than commands: the keys a question's
303
+ filter narrows with and the ones that leave its free-text row, the digits and
304
+ row `0` that name an option, and the mouse.
305
+
306
+ One residual escapes that promise, and it is not the surface's to close. After a
307
+ component returns its rows, the framework appends a reset to each row and closes
308
+ the hyperlink it wraps them in, so a session can still receive a bare `ESC[0m`
309
+ with colour off. It paints nothing. It is recorded here because "no escapes at
310
+ all" is otherwise the claim, and because the surface cannot make good on it
311
+ alone.
312
+
155
313
  ## Modes
156
314
 
157
315
  A mode is an **agent preset**: the plugin composition an agent's own scope joins. It decides that agent's tools, prompt sections, skills, and planning rows, which is why a mode is fixed once a session has produced a turn — it is what composed the agent that answered.
@@ -160,8 +318,8 @@ Four ship, under the ids a session log records:
160
318
 
161
319
  | `--preset` | Mode | What the agent gets |
162
320
  |---|---|---|
321
+ | `ptc` | PTC (default) | the same agent, reaching its tools through one TypeScript program |
163
322
  | `standard` | standard | full agent: editing, shell, search, skills, planning, goals, subagents, workflows |
164
- | `ptc` | PTC | the same agent, reaching its tools through one TypeScript program |
165
323
  | `minimal` | minimal | one tool: a persistent shell |
166
324
  | `cordis` | creator | harness authoring: runtime inspection and composition guidance |
167
325
 
@@ -169,7 +327,7 @@ A session takes its mode from the first of these that applies:
169
327
 
170
328
  1. `--preset <id>`, refused before the terminal is taken over when the roster does not ship that id.
171
329
  2. `/preset` while the session is still blank: a bare command opens the picker, `/preset <id>` switches directly, and the choice is written to the log.
172
- 3. The roster's default, `standard`, when nobody names one.
330
+ 3. The roster's default, `ptc`, when nobody names one.
173
331
 
174
332
  The mode is re-read rather than remembered: resuming mounts what that session's own log recorded, resuming with a `--preset` that disagrees with it is refused instead of silently ignored, and forking inherits the mode of the conversation being branched. The status line names the mode, and `/status` lists it with the rest.
175
333
 
@@ -182,8 +340,16 @@ The package is a Cordis plugin bundle that stacks over `@deepseek-ai/dsh-base`:
182
340
  - `@deepseek-ai/dsh-code-runtime-worker-thread` and `@deepseek-ai/dsh-cordis-host-runner` are the host machinery PTC mode and creator mode need; only the Web bundle shipped them, so a terminal profile has to mount them to offer those modes at all.
183
341
  - `@sagmans/dsh-tui` owns the terminal: it creates or resumes one agent through `ctx.agents`, folds `session/event` into transcript rows and work state, renders them with `@earendil-works/pi-tui`, and releases the terminal on exit, on a boot failure, and on a signal.
184
342
 
343
+ A question whose id ends in `:secret` declares its typed answer a credential: the bar hides everything but its first and last four characters, and the free-text row a question with options offers is labelled `API KEY`. Wording is not a declaration, because hiding every question that mentions a key would hide answers their authors meant to be read.
344
+
185
345
  The fold is durable-only: the live stream decorates the row that is still being written, and everything else — cards, reasoning, work state, compaction markers — comes from the log, so a resumed session renders what the live one did. Subagent start and finish are the exception: they arrive as service events, and the transcript shows them as decoration because the durable record of a delegation is the tool call that asked for it.
186
346
 
347
+ Tool cards are folded by default: a card draws its header and nothing else, so a long read, diff, or search cannot bury the conversation. A shell card is the exception, because its output is the answer the reader asked for: it names the tool in its header, always shows the command that ran, keeps the last 20 output rows, and adds a hint naming the rows it dropped. `Ctrl+O` opens every card to its header plus every retained row.
348
+
349
+ A PTC card is the one card with children: every call the `run_code` program dispatched hangs off the card that made it, and each draws under the header as the tool's own name and argument, wrapping rather than being cut. `Ctrl+Y` folds them away again, and `subcalls: collapsed` starts every session folded; see [Settings](#settings).
350
+
351
+ A card's header names the tool, then the argument the call was made with — a path or a command — in the `tool.args` colour, then the facts the result measured: a read reports its line range, line count, and token size; a file change that carried no prior content to compare against reports its lines and tokens; one that did reports added, changed, and removed lines as `+n ~n -n` in green, yellow, and red. Each stat is its own token, so any of them can be recoloured or hidden independently.
352
+
187
353
  The bundle also takes the base's global agent rows out of the composition, twenty-three of them. Every one is a row the shipped modes supply per session instead, so leaving it mounted registers the same tool names in two layers and doubles each prompt section it owns. What stays mounted is the host: sessions, storage, models, permissions, jobs, and the command registry.
188
354
 
189
355
  ## Development
@@ -227,13 +393,24 @@ The automated checks drive a real PTY, but they run on this machine's terminal.
227
393
  | `NO_COLOR=1 dsh --profile tui` | no styling anywhere, layout unchanged |
228
394
  | `dsh --profile tui --no-bell` | a turn that runs for minutes still ends silently |
229
395
  | `dsh --profile tui --preset ptc`, then a turn | the status line names `ptc`, and the agent reaches its tools through one TypeScript program rather than one shell call at a time |
396
+ | a PTC turn | one entry per dispatched call draws two spaces indented under the `run_code` header, from the first frame and with no keypress |
397
+ | that turn in a terminal narrower than a call's own argument | the argument wraps onto continuation rows indented to the same two spaces, with no ellipsis |
398
+ | that same turn, then `ctrl+y` | the lines fold away; `ctrl+y` again draws them back |
399
+ | `dsh-tui: { subcalls: collapsed }` in `$DSH_HOME/settings.yaml`, then a PTC turn | the card arrives alone, and editing the document to `inline` unfolds a running session |
400
+ | a reply carrying a mermaid fence | it draws as box art at the transcript width, with the prose around it untouched |
401
+ | that reply in a terminal narrower than the drawing | the fence stays source, and widening the window draws it without a new turn |
402
+ | `dsh-tui: { mermaid: off }` in `$DSH_HOME/settings.yaml`, then a mermaid reply | the fence stays source; editing the value to `streaming` draws a settled reply without a restart |
403
+ | `/model` on a configured profile | the picker lists only the configured providers' advertised models, heads itself with the route in force, and typing filters it while later rows stream in; `esc` or Ctrl+C leaves without changing the route, and `enter` chains into the route's reasoning efforts |
230
404
  | `/preset` on a fresh session | the picker lists four modes, marks the current one, and the switch survives a resume |
231
405
  | `/preset minimal` after a turn | refused, naming the reason; the session keeps the mode it composed with |
232
406
  | `--resume --preset <mode>` and then picking a session that runs another mode | the list stays open and says why that row cannot be taken; `esc` leaves the picker |
233
407
  | `dsh --profile tui --preset nope` | exits non-zero naming the modes that do exist, before the alternate screen appears |
234
408
  | arrow keys in a picker, or on a question's options, in a terminal that reports key events (Kitty, WezTerm, Ghostty, iTerm2) | one press moves one row, and holding a key still repeats; a terminal that sends only the legacy sequence behaves the same |
235
409
  | resize the window mid-turn | the transcript rewraps; the dock, editor, and status row stay put |
236
- | a 40-column terminal | rows end in `…` instead of wrapping into the next line |
410
+ | a 40-column terminal | transcript and card rows end in `…` instead of wrapping into the next line |
411
+ | a question with a long option at 40 columns | the option wraps onto rows indented under its label, and `0. other — type your own answer` sits under the list |
412
+ | press `0` on a question, type an answer, press Enter | the editor under row `0` shows the text as it is edited, and the model receives it as that question's answer |
413
+ | type a prompt without sending it, then answer a question | the prompt bar steps aside while the question is open and holds the same prompt again afterwards |
237
414
  | `echo hi \| dsh --profile tui` | refuses with a non-zero exit and a message naming the TTY requirement |
238
415
  | `/quit`, Ctrl+C while idle, `kill -TERM <pid>` | the shell returns with cursor, echo, mouse, and title restored |
239
416
 
@@ -241,25 +418,27 @@ The automated checks drive a real PTY, but they run on this machine's terminal.
241
418
 
242
419
  Published artefacts carry a provenance attestation, which only a CI provider can issue, so releases ship from the tag workflow rather than a laptop.
243
420
 
244
- 1. Bump `version` in `package.json`, land it on `main` through a reviewed PR, and wait for CI to pass on the merged SHA.
421
+ 1. Bump `version` in `package.json` and move `CHANGELOG.md`'s `Unreleased` section to that version, land both on `main` through a reviewed PR, and wait for CI to pass on the merged SHA.
245
422
  2. Tag that SHA with a signed tag and push it. The tag ruleset admits repository admins only.
246
423
  3. `.github/workflows/release.yml` re-runs typecheck, tests, and the package smoke; the publish job then waits for a maintainer's approval on the `npm-release` environment before it publishes with OIDC trusted publishing and automatic provenance.
247
424
 
248
- The workflow stores no npm token: the registry trusts `release.yml` on the `npm-release` environment, and [`scripts/npm/release.py`](scripts/npm/release.py) creates both the environment and that trust. The full runbook is [RELEASE.md](RELEASE.md).
425
+ The workflow stores no npm token: the registry trusts `release.yml` on the `npm-release` environment, and [`scripts/npm/release.py`](scripts/npm/release.py) creates both the environment and that trust. The full runbook is [RELEASE.md](RELEASE.md); the user-visible history is [CHANGELOG.md](CHANGELOG.md).
249
426
 
250
427
  ## Limitations
251
428
 
252
429
  - Two different things are called a preset. The agent mode (`--preset`, `/preset`) is fixed once a session has produced a turn; the permission preset (`/permission <preset>`, named in the status line) can change at any time.
253
- - `/model` changes the route for the running session only. Catalog membership is advisory — an adapter may accept an id it does not advertise.
430
+ - `/model` changes the route and reasoning effort for the running session only. Catalog membership is advisory — an adapter may accept an id it does not advertise, while an explicit effort is checked against the route's own levels before it is applied. The picker offers the routes this deployment configured, not the ones it can prove credentialed: a provider whose key or sign-in is still missing appears like any other, and its first request names the missing credential.
254
431
  - Scrolling is the mouse wheel, or the terminal's own scrollback keys where it offers them.
255
432
  - A turn that ran longer than ten seconds rings the terminal bell when it ends, because the reader may have walked away; `--no-bell` turns that off.
256
- - The dock shows the goal, plan mode, the todo list, and any background job still running; the transcript marks where older history was compacted away. `/plan` toggles plan mode; `/plan <message>` also steers that message, which is the base command's own behaviour.
433
+ - The dock shows the goal, plan mode, the todo items still to do, and any background job or delegation still running; a settled item leaves rather than turns into a completed row. The transcript marks where older history was compacted away. `/plan` toggles plan mode; `/plan <message>` also steers that message, which is the base command's own behaviour.
257
434
  - Background jobs and subagent runs are live process state, not durable events: they disappear when the run ends, and a resumed session starts with an empty board and roster.
258
- - Reading a child's conversation does not move the terminal: commands, approvals, and the status line stay with the session you launched, and the transcript is the only thing that switches.
435
+ - A card reads its tool's own render intent through the agent whose session is on screen, so a stored session with no live agent — one this process is not running, or a child that has already finished — folds to the generic card instead of the tool's own.
436
+ - Reading a child's conversation does not move the terminal: commands, approvals, and the status line stay with the session you launched, and the transcript is the only thing that switches. The status line carries the way back, read from the map in force, so a remap shows up without reopening the view.
259
437
  - Delete is unimplemented: the session store exposes no delete, and the surface does not reach around that seam into its files. `/fork` covers the case that needs it — it branches into a new session and leaves the original alone.
260
- - Approvals and questions render inline and take the keyboard; a question batch is answered in order.
261
- - Styling uses the standard 16 ANSI colors and terminal defaults, so light and dark terminals follow their own theme.
438
+ - Approvals and questions render inline and take the keyboard; a question batch is answered in order, and a question that lists options can always be answered with free text on row `0`.
439
+ - Styling is per element and overridable; see [Settings](#settings). Shipped defaults are emitted as 24-bit colour where the terminal advertises it and degraded to 256 or 16 colours otherwise, so a light or dark terminal still follows its own palette where it has one.
262
440
  - Tool text, model text, and file content are escaped before rendering, so a hostile result cannot inject terminal control sequences; the cost is that a literal tab shows as \x09.
441
+ - Mermaid fences draw in assistant replies only, and only at the top level of one: a fence nested in a list, quoted inside another fence, or carried by a prompt, a thought, or a tool card stays source. Author `:::class` styling and diagram links are ignored — the renderer reports what each run is, and the theme decides how it looks.
263
442
 
264
443
  ## License
265
444
 
package/cordis.patch.yml CHANGED
@@ -98,11 +98,13 @@
98
98
  bell: !!js ctx.tuiStartup.bell
99
99
 
100
100
  # The roster of agent compositions, and the mode a session starts in when
101
- # nobody names one. A profile patch may override this row's config.
101
+ # nobody names one. PTC leads because a flagless run should reach every tool
102
+ # through one program rather than one shell call at a time. A profile patch
103
+ # may override this row's config.
102
104
  - id: agent-presets
103
105
  name: '@deepseek-ai/dsh-agent-presets'
104
106
  config:
105
- default: standard
107
+ default: ptc
106
108
 
107
109
  # A preset's subagent tool samples its delegation model from this host-owned
108
110
  # settings row. It is host machinery rather than agent plane, which is why
@@ -1,6 +1,7 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import type { Agent } from '@deepseek-ai/dsh-agent';
3
3
  import { type SessionId } from '@deepseek-ai/dsh-session';
4
+ import { ReasoningEffortId } from '@deepseek-ai/dsh-llm';
4
5
  /** Everything the terminal surface needs to own one interactive agent. */
5
6
  export interface TuiAgent {
6
7
  readonly sessionId: SessionId;
@@ -47,6 +48,19 @@ export interface StartAgentOptions {
47
48
  */
48
49
  readonly preset?: string | undefined;
49
50
  }
51
+ /**
52
+ * The route an agent starts on.
53
+ *
54
+ * A launch flag is explicit, so it stands alone; otherwise the deployment
55
+ * default supplies the whole selection, effort included. The effort has to
56
+ * travel with the route here because an absent one is what the reader sees in
57
+ * the status line but never reaches a request.
58
+ */
59
+ export declare function agentRoute(ctx: Context, options: Pick<StartAgentOptions, 'model' | 'provider'>): {
60
+ provider?: string;
61
+ model?: string;
62
+ reasoningEffort?: ReasoningEffortId;
63
+ };
50
64
  /**
51
65
  * Create or resume the one agent this surface drives.
52
66
  *
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/agent/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAG9F,0EAA0E;AAC1E,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,0DAA0D;IAC1D,SAAS,IAAI,IAAI,CAAA;IACjB,6CAA6C;IAC7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;CACpC;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5C,iFAAiF;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,CAAA;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC;AAiBD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkC5F"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/agent/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AACnD,OAAO,EAAuC,KAAK,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAC9F,OAAO,EAAE,iBAAiB,EAAqB,MAAM,sBAAsB,CAAA;AAE3E,0EAA0E;AAC1E,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,8DAA8D;IAC9D,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,0DAA0D;IAC1D,SAAS,IAAI,IAAI,CAAA;IACjB,6CAA6C;IAC7C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED,gEAAgE;AAChE,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAA;CACpC;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC5C,iFAAiF;IACjF,QAAQ,CAAC,IAAI,CAAC,EAAE,eAAe,CAAA;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,UAAU,CAAC,GACrD;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,iBAAiB,CAAA;CAAE,CAiB5E;AAMD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkC5F"}
package/lib/agent/host.js CHANGED
@@ -1,6 +1,14 @@
1
1
  import { SessionLogOffset } from '@deepseek-ai/dsh-session';
2
- import { createUserMessage } from '@deepseek-ai/dsh-llm';
3
- function routeOf(ctx, options) {
2
+ import { ReasoningEffortId, createUserMessage } from '@deepseek-ai/dsh-llm';
3
+ /**
4
+ * The route an agent starts on.
5
+ *
6
+ * A launch flag is explicit, so it stands alone; otherwise the deployment
7
+ * default supplies the whole selection, effort included. The effort has to
8
+ * travel with the route here because an absent one is what the reader sees in
9
+ * the status line but never reaches a request.
10
+ */
11
+ export function agentRoute(ctx, options) {
4
12
  if (options.model !== undefined || options.provider !== undefined) {
5
13
  return {
6
14
  ...(options.provider === undefined ? {} : { provider: options.provider }),
@@ -8,7 +16,15 @@ function routeOf(ctx, options) {
8
16
  };
9
17
  }
10
18
  const selection = ctx.get('agentDefaultModel')?.currentSelection();
11
- return selection === undefined ? {} : { provider: selection.provider, model: selection.model };
19
+ return selection === undefined
20
+ ? {}
21
+ : {
22
+ provider: selection.provider,
23
+ model: selection.model,
24
+ ...(selection.reasoningEffort === undefined
25
+ ? {}
26
+ : { reasoningEffort: ReasoningEffortId(selection.reasoningEffort) }),
27
+ };
12
28
  }
13
29
  function userMessage(text) {
14
30
  return createUserMessage({ content: [{ type: 'text', text }], source: { kind: 'user' } });
@@ -21,7 +37,7 @@ function userMessage(text) {
21
37
  * session is not an error the user should see, so creation is the fallback.
22
38
  */
23
39
  export async function startAgent(ctx, options) {
24
- const agentOptions = routeOf(ctx, options);
40
+ const agentOptions = agentRoute(ctx, options);
25
41
  const meta = { cwd: options.cwd };
26
42
  const setup = options.setup === undefined ? {} : { setup: options.setup };
27
43
  // A branch inherits a prefix of its parent's log, so the child is marked as
@@ -1 +1 @@
1
- {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/agent/host.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../../src/agent/host.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
+ import type { PickerRow } from '../ui/picker.ts';
2
3
  /** The route a reader chose for the next step. */
3
4
  export interface ModelChoice {
4
5
  readonly provider: string;
@@ -10,6 +11,13 @@ export interface ProviderEntry {
10
11
  readonly id: string;
11
12
  readonly name: string;
12
13
  }
14
+ /** One route a configured provider advertises, as the picker lists it. */
15
+ export interface ModelRoute {
16
+ readonly provider: string;
17
+ readonly model: string;
18
+ /** The adapter's display name; the id stays the value a request names. */
19
+ readonly name: string;
20
+ }
13
21
  /** What a `/model` argument asks the surface to do. */
14
22
  export type ModelCommand = {
15
23
  readonly kind: 'current';
@@ -30,8 +38,30 @@ export type ModelCommand = {
30
38
  * lists that provider's models, `provider/model` switches, and anything else is
31
39
  * taken as a model id inside the route already in use, because a reader
32
40
  * switching between two models of one provider should not have to repeat it.
41
+ * A complete route may carry one more segment, the reasoning effort, so
42
+ * `provider/model/effort` selects both at once: the last segment is the effort
43
+ * and the model is everything between it and the provider, which reads a model
44
+ * id containing a slash as an effort the adapters in use do not mint.
33
45
  */
34
46
  export declare function parseModelArgument(argument: string, providers: readonly ProviderEntry[], current: ModelChoice | undefined): ModelCommand;
47
+ /** The picker's stable id for one route. */
48
+ export declare function modelRouteKey(route: {
49
+ readonly provider: string;
50
+ readonly model: string;
51
+ }): string;
52
+ /** Read a route key back; undefined for a string this surface never minted. */
53
+ export declare function readModelRouteKey(key: string): {
54
+ provider: string;
55
+ model: string;
56
+ } | undefined;
57
+ /**
58
+ * How one advertised route appears in the picker.
59
+ *
60
+ * The name leads because it is what a reader recognizes, and the id follows
61
+ * only when it says something the name does not; the route in force carries
62
+ * its effort, since that is the other half of the choice on screen.
63
+ */
64
+ export declare function describeModelRoute(route: ModelRoute, current: ModelChoice | undefined): PickerRow;
35
65
  /**
36
66
  * Own the reader's model choice for one session.
37
67
  *
@@ -46,10 +76,29 @@ export declare class ModelSwitch {
46
76
  install(agentCtx: Context): void;
47
77
  choose(choice: ModelChoice): void;
48
78
  current(): ModelChoice | undefined;
79
+ /**
80
+ * Take the deployment default as this session's route, unless the reader
81
+ * already named one.
82
+ *
83
+ * The default is settings-backed and only trustworthy once it is read, which
84
+ * is after the agent was created; adopting it here is what makes the effort
85
+ * the status line shows reach the request, and a reader's own `/model` or
86
+ * picker choice must never be overwritten by it.
87
+ */
88
+ adopt(choice: ModelChoice): void;
49
89
  /** Forget the choice, so the session returns to the composition default. */
50
90
  reset(): void;
51
91
  dispose(): void;
52
92
  }
93
+ /** The reasoning levels one exact route offers, described structurally. */
94
+ export interface ModelEfforts {
95
+ readonly efforts: readonly {
96
+ readonly id: string;
97
+ readonly name: string;
98
+ readonly description?: string;
99
+ }[];
100
+ readonly defaultEffort?: string;
101
+ }
53
102
  /** Read the advisory catalog of routes this composition can reach. */
54
103
  export declare function createModelCatalog(ctx: Context): {
55
104
  providers(): readonly ProviderEntry[];
@@ -57,5 +106,6 @@ export declare function createModelCatalog(ctx: Context): {
57
106
  readonly id: string;
58
107
  readonly name: string;
59
108
  }[]>;
109
+ efforts(provider: string, model: string): Promise<ModelEfforts | undefined>;
60
110
  } | undefined;
61
111
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/agent/model.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AAED,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,uDAAuD;AACvD,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GAC5B;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,SAAS,aAAa,EAAE,EACnC,OAAO,EAAE,WAAW,GAAG,SAAS,GAC/B,YAAY,CAgBd;AAED;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkE;IAC5F,OAAO,CAAC,SAAS,CAA0B;IAE3C,sFAAsF;IACtF,OAAO,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKhC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAUjC,OAAO,IAAI,WAAW,GAAG,SAAS;IAUlC,4EAA4E;IAC5E,KAAK,IAAI,IAAI;IAKb,OAAO,IAAI,IAAI;CAIhB;AAQD,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG;IAChD,SAAS,IAAI,SAAS,aAAa,EAAE,CAAA;IACrC,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAA;CAC7F,GAAG,SAAS,CAeZ"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../src/agent/model.ts"],"names":[],"mappings":"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"}