@sagmans/dsh-tui 0.6.0 → 0.8.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.
- package/.agents/skills/dsh-tui-dogfood/SKILL.md +83 -0
- package/.agents/skills/dsh-tui-dogfood/references/home-state.md +78 -0
- package/.agents/skills/dsh-tui-dogfood/scripts/clone-links.mjs +133 -0
- package/.agents/skills/dsh-tui-dogfood/scripts/run-plugin-from-worktree.sh +417 -0
- package/.agents/skills/dsh-tui-update-models/SKILL.md +199 -0
- package/.agents/skills/dsh-tui-update-models/references/model-wiring.md +292 -0
- package/.agents/skills/dsh-tui-update-models/scripts/dump-model-catalog.mjs +314 -0
- package/README.md +154 -27
- package/lib/agent/present.d.ts.map +1 -1
- package/lib/agent/present.js +2 -1
- package/lib/agent/present.js.map +1 -1
- package/lib/cards/composition.d.ts +68 -0
- package/lib/cards/composition.d.ts.map +1 -0
- package/lib/cards/composition.js +117 -0
- package/lib/cards/composition.js.map +1 -0
- package/lib/cards/presenter.d.ts +23 -0
- package/lib/cards/presenter.d.ts.map +1 -0
- package/lib/cards/presenter.js +394 -0
- package/lib/cards/presenter.js.map +1 -0
- package/lib/cards/preview.d.ts +42 -0
- package/lib/cards/preview.d.ts.map +1 -0
- package/lib/cards/preview.js +51 -0
- package/lib/cards/preview.js.map +1 -0
- package/lib/cards.d.ts +12 -120
- package/lib/cards.d.ts.map +1 -1
- package/lib/cards.js +4 -556
- package/lib/cards.js.map +1 -1
- package/lib/compat/section.d.ts +29 -0
- package/lib/compat/section.d.ts.map +1 -0
- package/lib/compat/section.js +82 -0
- package/lib/compat/section.js.map +1 -0
- package/lib/config.d.ts +27 -2
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +61 -1
- package/lib/config.js.map +1 -1
- package/lib/contracts.d.ts +28 -0
- package/lib/contracts.d.ts.map +1 -1
- package/lib/fold-cursor.d.ts +8 -0
- package/lib/fold-cursor.d.ts.map +1 -1
- package/lib/fold-cursor.js +18 -0
- package/lib/fold-cursor.js.map +1 -1
- package/lib/gates/question-card.d.ts +77 -0
- package/lib/gates/question-card.d.ts.map +1 -0
- package/lib/gates/question-card.js +113 -0
- package/lib/gates/question-card.js.map +1 -0
- package/lib/gates/questions.d.ts +127 -0
- package/lib/gates/questions.d.ts.map +1 -0
- package/lib/gates/questions.js +418 -0
- package/lib/gates/questions.js.map +1 -0
- package/lib/gates.d.ts +1 -113
- package/lib/gates.d.ts.map +1 -1
- package/lib/gates.js +1 -484
- package/lib/gates.js.map +1 -1
- package/lib/herdr/client.d.ts +8 -0
- package/lib/herdr/client.d.ts.map +1 -1
- package/lib/herdr/client.js +13 -1
- package/lib/herdr/client.js.map +1 -1
- package/lib/herdr/constants.d.ts +18 -0
- package/lib/herdr/constants.d.ts.map +1 -1
- package/lib/herdr/constants.js +18 -0
- package/lib/herdr/constants.js.map +1 -1
- package/lib/herdr/reporter.d.ts +20 -4
- package/lib/herdr/reporter.d.ts.map +1 -1
- package/lib/herdr/reporter.js +70 -20
- package/lib/herdr/reporter.js.map +1 -1
- package/lib/herdr/state.d.ts +10 -0
- package/lib/herdr/state.d.ts.map +1 -1
- package/lib/herdr/state.js +21 -4
- package/lib/herdr/state.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +348 -2602
- package/lib/index.js.map +1 -1
- package/lib/input/action-catalog.d.ts +74 -0
- package/lib/input/action-catalog.d.ts.map +1 -0
- package/lib/input/action-catalog.js +137 -0
- package/lib/input/action-catalog.js.map +1 -0
- package/lib/input/actions.d.ts +5 -81
- package/lib/input/actions.d.ts.map +1 -1
- package/lib/input/actions.js +4 -625
- package/lib/input/actions.js.map +1 -1
- package/lib/input/completion.d.ts +1 -1
- package/lib/input/completion.d.ts.map +1 -1
- package/lib/input/completion.js +2 -1
- package/lib/input/completion.js.map +1 -1
- package/lib/input/file-index.d.ts +40 -0
- package/lib/input/file-index.d.ts.map +1 -0
- package/lib/input/file-index.js +141 -0
- package/lib/input/file-index.js.map +1 -0
- package/lib/input/file-search.d.ts +1 -38
- package/lib/input/file-search.d.ts.map +1 -1
- package/lib/input/file-search.js +1 -487
- package/lib/input/file-search.js.map +1 -1
- package/lib/input/key-press.d.ts +57 -0
- package/lib/input/key-press.d.ts.map +1 -0
- package/lib/input/key-press.js +218 -0
- package/lib/input/key-press.js.map +1 -0
- package/lib/input/keymap-conflicts.d.ts +59 -0
- package/lib/input/keymap-conflicts.d.ts.map +1 -0
- package/lib/input/keymap-conflicts.js +292 -0
- package/lib/input/keymap-conflicts.js.map +1 -0
- package/lib/input/keymap-settings.js +1 -1
- package/lib/input/keymap-settings.js.map +1 -1
- package/lib/input/keymap.d.ts.map +1 -1
- package/lib/input/keymap.js +3 -1
- package/lib/input/keymap.js.map +1 -1
- package/lib/input/workspace-files.d.ts +10 -0
- package/lib/input/workspace-files.d.ts.map +1 -0
- package/lib/input/workspace-files.js +359 -0
- package/lib/input/workspace-files.js.map +1 -0
- package/lib/install-skills.d.ts +39 -0
- package/lib/install-skills.d.ts.map +1 -0
- package/lib/install-skills.js +273 -0
- package/lib/install-skills.js.map +1 -0
- package/lib/keys-command.d.ts +2 -1
- package/lib/keys-command.d.ts.map +1 -1
- package/lib/keys-command.js +2 -1
- package/lib/keys-command.js.map +1 -1
- package/lib/model-list.d.ts +37 -0
- package/lib/model-list.d.ts.map +1 -0
- package/lib/model-list.js +60 -0
- package/lib/model-list.js.map +1 -0
- package/lib/startup.d.ts +8 -0
- package/lib/startup.d.ts.map +1 -1
- package/lib/startup.js +120 -24
- package/lib/startup.js.map +1 -1
- package/lib/subagents.d.ts +7 -3
- package/lib/subagents.d.ts.map +1 -1
- package/lib/subagents.js +28 -4
- package/lib/subagents.js.map +1 -1
- package/lib/surface/appearance-preferences.d.ts +26 -0
- package/lib/surface/appearance-preferences.d.ts.map +1 -0
- package/lib/surface/appearance-preferences.js +139 -0
- package/lib/surface/appearance-preferences.js.map +1 -0
- package/lib/surface/appearance.d.ts +87 -0
- package/lib/surface/appearance.d.ts.map +1 -0
- package/lib/surface/appearance.js +353 -0
- package/lib/surface/appearance.js.map +1 -0
- package/lib/surface/background-work.d.ts +51 -0
- package/lib/surface/background-work.d.ts.map +1 -0
- package/lib/surface/background-work.js +172 -0
- package/lib/surface/background-work.js.map +1 -0
- package/lib/surface/commands.d.ts +82 -0
- package/lib/surface/commands.d.ts.map +1 -0
- package/lib/surface/commands.js +370 -0
- package/lib/surface/commands.js.map +1 -0
- package/lib/surface/modal-input.d.ts +59 -0
- package/lib/surface/modal-input.d.ts.map +1 -0
- package/lib/surface/modal-input.js +243 -0
- package/lib/surface/modal-input.js.map +1 -0
- package/lib/surface/model-choice.d.ts +54 -0
- package/lib/surface/model-choice.d.ts.map +1 -0
- package/lib/surface/model-choice.js +325 -0
- package/lib/surface/model-choice.js.map +1 -0
- package/lib/surface/preset-choice.d.ts +78 -0
- package/lib/surface/preset-choice.d.ts.map +1 -0
- package/lib/surface/preset-choice.js +163 -0
- package/lib/surface/preset-choice.js.map +1 -0
- package/lib/surface/prompt-input.d.ts +97 -0
- package/lib/surface/prompt-input.d.ts.map +1 -0
- package/lib/surface/prompt-input.js +215 -0
- package/lib/surface/prompt-input.js.map +1 -0
- package/lib/surface/prompt-memory.d.ts +76 -0
- package/lib/surface/prompt-memory.d.ts.map +1 -0
- package/lib/surface/prompt-memory.js +167 -0
- package/lib/surface/prompt-memory.js.map +1 -0
- package/lib/surface/session-lifecycle.d.ts +120 -0
- package/lib/surface/session-lifecycle.d.ts.map +1 -0
- package/lib/surface/session-lifecycle.js +324 -0
- package/lib/surface/session-lifecycle.js.map +1 -0
- package/lib/surface/session-picker.d.ts +39 -0
- package/lib/surface/session-picker.d.ts.map +1 -0
- package/lib/surface/session-picker.js +107 -0
- package/lib/surface/session-picker.js.map +1 -0
- package/lib/surface/session-view.d.ts +86 -0
- package/lib/surface/session-view.d.ts.map +1 -0
- package/lib/surface/session-view.js +215 -0
- package/lib/surface/session-view.js.map +1 -0
- package/lib/surface/staged-turns.d.ts +81 -0
- package/lib/surface/staged-turns.d.ts.map +1 -0
- package/lib/surface/staged-turns.js +206 -0
- package/lib/surface/staged-turns.js.map +1 -0
- package/lib/surface/terminal-lifecycle.d.ts +76 -0
- package/lib/surface/terminal-lifecycle.d.ts.map +1 -0
- package/lib/surface/terminal-lifecycle.js +222 -0
- package/lib/surface/terminal-lifecycle.js.map +1 -0
- package/lib/terminal-text/scan.d.ts +44 -0
- package/lib/terminal-text/scan.d.ts.map +1 -0
- package/lib/terminal-text/scan.js +195 -0
- package/lib/terminal-text/scan.js.map +1 -0
- package/lib/terminal-text/sgr.d.ts +32 -0
- package/lib/terminal-text/sgr.d.ts.map +1 -0
- package/lib/terminal-text/sgr.js +203 -0
- package/lib/terminal-text/sgr.js.map +1 -0
- package/lib/terminal-text.d.ts +1 -1
- package/lib/terminal-text.d.ts.map +1 -1
- package/lib/terminal-text.js +2 -379
- package/lib/terminal-text.js.map +1 -1
- package/lib/theme-command.js +2 -1
- package/lib/theme-command.js.map +1 -1
- package/lib/theme-defaults.d.ts +64 -0
- package/lib/theme-defaults.d.ts.map +1 -0
- package/lib/theme-defaults.js +248 -0
- package/lib/theme-defaults.js.map +1 -0
- package/lib/theme-files.d.ts +1 -1
- package/lib/theme-files.d.ts.map +1 -1
- package/lib/theme-files.js +1 -1
- package/lib/theme-files.js.map +1 -1
- package/lib/theme-resolver.d.ts +36 -0
- package/lib/theme-resolver.d.ts.map +1 -0
- package/lib/theme-resolver.js +112 -0
- package/lib/theme-resolver.js.map +1 -0
- package/lib/theme-schema.d.ts.map +1 -1
- package/lib/theme-schema.js +3 -2
- package/lib/theme-schema.js.map +1 -1
- package/lib/theme-settings.d.ts +5 -7
- package/lib/theme-settings.d.ts.map +1 -1
- package/lib/theme-settings.js +37 -21
- package/lib/theme-settings.js.map +1 -1
- package/lib/theme-tokens.d.ts +0 -89
- package/lib/theme-tokens.d.ts.map +1 -1
- package/lib/theme-tokens.js +0 -356
- package/lib/theme-tokens.js.map +1 -1
- package/lib/theme.d.ts +1 -1
- package/lib/theme.d.ts.map +1 -1
- package/lib/theme.js +2 -1
- package/lib/theme.js.map +1 -1
- package/lib/tool-display.d.ts.map +1 -1
- package/lib/tool-display.js +2 -1
- package/lib/tool-display.js.map +1 -1
- package/lib/transcript/message-content.d.ts +21 -0
- package/lib/transcript/message-content.d.ts.map +1 -0
- package/lib/transcript/message-content.js +61 -0
- package/lib/transcript/message-content.js.map +1 -0
- package/lib/transcript/tool-calls.d.ts +106 -0
- package/lib/transcript/tool-calls.d.ts.map +1 -0
- package/lib/transcript/tool-calls.js +254 -0
- package/lib/transcript/tool-calls.js.map +1 -0
- package/lib/transcript.d.ts +14 -55
- package/lib/transcript.d.ts.map +1 -1
- package/lib/transcript.js +31 -253
- package/lib/transcript.js.map +1 -1
- package/lib/ui/dock.d.ts +14 -2
- package/lib/ui/dock.d.ts.map +1 -1
- package/lib/ui/dock.js +52 -10
- package/lib/ui/dock.js.map +1 -1
- package/lib/ui/editor.d.ts.map +1 -1
- package/lib/ui/editor.js +2 -1
- package/lib/ui/editor.js.map +1 -1
- package/lib/ui/keymap-picker.d.ts +2 -1
- package/lib/ui/keymap-picker.d.ts.map +1 -1
- package/lib/ui/keymap-picker.js +1 -0
- package/lib/ui/keymap-picker.js.map +1 -1
- package/lib/ui/view/gate-card.d.ts +21 -0
- package/lib/ui/view/gate-card.d.ts.map +1 -0
- package/lib/ui/view/gate-card.js +104 -0
- package/lib/ui/view/gate-card.js.map +1 -0
- package/lib/ui/view/tool-card.d.ts +149 -0
- package/lib/ui/view/tool-card.d.ts.map +1 -0
- package/lib/ui/view/tool-card.js +429 -0
- package/lib/ui/view/tool-card.js.map +1 -0
- package/lib/ui/view/transcript-message.d.ts +62 -0
- package/lib/ui/view/transcript-message.d.ts.map +1 -0
- package/lib/ui/view/transcript-message.js +158 -0
- package/lib/ui/view/transcript-message.js.map +1 -0
- package/lib/ui/view.d.ts +105 -223
- package/lib/ui/view.d.ts.map +1 -1
- package/lib/ui/view.js +132 -679
- package/lib/ui/view.js.map +1 -1
- package/package.json +3 -1
- package/themes/violet-orbit.yaml +7 -5
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { ApprovalGate } from "../gates.js";
|
|
2
|
+
import { QuestionGate, toGateQuestions } from "../gates/questions.js";
|
|
3
|
+
import { GATE_WAIT_KEY } from "../herdr/constants.js";
|
|
4
|
+
import { PickerPopup, POPUP_MAX_HEIGHT, popupWidth } from "../ui/picker-card.js";
|
|
5
|
+
/**
|
|
6
|
+
* The one modal interaction a terminal can be in: a gate or a picker.
|
|
7
|
+
*
|
|
8
|
+
* Both take the keyboard and give it back the same way, and both can be
|
|
9
|
+
* cancelled by something other than a press (an aborted request, a settled
|
|
10
|
+
* list), so the focus, submission flag and popup lifetime belong to one owner
|
|
11
|
+
* rather than to every feature that opens a list. The blocked Herdr row is the
|
|
12
|
+
* gate's alone: see `openPicker`.
|
|
13
|
+
*/
|
|
14
|
+
export function createModalInput(ctx, ports) {
|
|
15
|
+
let pending;
|
|
16
|
+
let pendingPicker;
|
|
17
|
+
/** A pick being vetted owns the list, not the keyboard: filtering stays live while its verdict is read. */
|
|
18
|
+
let vetting = false;
|
|
19
|
+
const openGate = (next) => {
|
|
20
|
+
pending = next;
|
|
21
|
+
// The card's own title names the decision, which is what a reader glancing
|
|
22
|
+
// at a wall of panes needs in order to know which one to open.
|
|
23
|
+
ports.herdr.block(GATE_WAIT_KEY, next.gate.card().title);
|
|
24
|
+
// A gate owns the keyboard: the editor must not collect the decision keys.
|
|
25
|
+
ports.editor.disableSubmit = true;
|
|
26
|
+
ports.tui.setFocus(null);
|
|
27
|
+
// A question is answered in this editor, which the gate draws under the row
|
|
28
|
+
// being answered, so the hardware cursor belongs to it while it is borrowed.
|
|
29
|
+
// It is set after the focus is cleared, which unmarks the component it left.
|
|
30
|
+
ports.editor.focused = next.kind === 'question';
|
|
31
|
+
ports.tui.requestRender();
|
|
32
|
+
};
|
|
33
|
+
const closeGate = () => {
|
|
34
|
+
pending = undefined;
|
|
35
|
+
ports.herdr.unblock(GATE_WAIT_KEY);
|
|
36
|
+
ports.editor.disableSubmit = false;
|
|
37
|
+
// The question is answered or skipped, so the reader gets their prompt back
|
|
38
|
+
// in the bar they left it in, with the menu the prompt bar offered.
|
|
39
|
+
ports.promptBar.giveBack();
|
|
40
|
+
ports.refreshCompletion();
|
|
41
|
+
ports.tui.setFocus(ports.editor);
|
|
42
|
+
ports.tui.requestRender();
|
|
43
|
+
};
|
|
44
|
+
/** Give the keyboard back to the editor and answer whoever opened the picker. */
|
|
45
|
+
const settlePicker = (id) => {
|
|
46
|
+
const settle = pendingPicker?.settle;
|
|
47
|
+
// The screen goes back before the keyboard does: a box left behind a settled
|
|
48
|
+
// list would sit over the transcript until something else repainted.
|
|
49
|
+
pendingPicker?.release?.();
|
|
50
|
+
pendingPicker = undefined;
|
|
51
|
+
ports.editor.disableSubmit = false;
|
|
52
|
+
ports.tui.setFocus(ports.editor);
|
|
53
|
+
settle?.(id);
|
|
54
|
+
ports.tui.requestRender();
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Take the keyboard for a picker and answer with the id it settled on.
|
|
58
|
+
*
|
|
59
|
+
* Where the list is drawn is the caller's decision, because it is a decision
|
|
60
|
+
* about the reader's attention. A list that is the destination — a session to
|
|
61
|
+
* open, a model to switch to — joins the transcript and is read with it. A
|
|
62
|
+
* list that is a reference for the work in front of the reader is drawn over
|
|
63
|
+
* that work instead, so looking something up does not cost them their place.
|
|
64
|
+
* The keyboard is owned the same way either way.
|
|
65
|
+
*/
|
|
66
|
+
const openPicker = (picker, vet, placement = 'inline') => new Promise(resolve => {
|
|
67
|
+
const overlay = placement === 'popup'
|
|
68
|
+
? ports.tui.showOverlay(new PickerPopup(rows => picker.card(rows), () => ports.terminal.rows, ports.theme), {
|
|
69
|
+
width: popupWidth(ports.terminal.columns),
|
|
70
|
+
maxHeight: POPUP_MAX_HEIGHT,
|
|
71
|
+
anchor: 'center',
|
|
72
|
+
margin: 1,
|
|
73
|
+
// The surface's own listener reads every press before a focused
|
|
74
|
+
// component does, so the box needs no focus to be driven; taking it
|
|
75
|
+
// would only move focus away from where the reader left it.
|
|
76
|
+
nonCapturing: true,
|
|
77
|
+
})
|
|
78
|
+
: undefined;
|
|
79
|
+
pendingPicker = {
|
|
80
|
+
picker,
|
|
81
|
+
settle: resolve,
|
|
82
|
+
vet,
|
|
83
|
+
card: overlay === undefined ? () => picker.card() : undefined,
|
|
84
|
+
release: overlay === undefined ? undefined : () => overlay.hide(),
|
|
85
|
+
};
|
|
86
|
+
// A picker is not reported as a wait, though it owns the keyboard exactly
|
|
87
|
+
// as a gate does: the reader opened this menu themselves and is looking at
|
|
88
|
+
// it, while Herdr answers a transition into `blocked` with a
|
|
89
|
+
// needs-attention notification and its sound — in the foreground pane too.
|
|
90
|
+
// Claiming a wait for every menu would ring for the reader's own
|
|
91
|
+
// navigation, and would read as an agent stuck on a decision it never asked
|
|
92
|
+
// for. A gate is the opposite case: the agent asked, and may have asked
|
|
93
|
+
// somebody who walked away.
|
|
94
|
+
ports.editor.disableSubmit = true;
|
|
95
|
+
ports.tui.setFocus(null);
|
|
96
|
+
ports.tui.requestRender();
|
|
97
|
+
});
|
|
98
|
+
/**
|
|
99
|
+
* Read one press while a modal interaction owns the keyboard.
|
|
100
|
+
*
|
|
101
|
+
* The gate and picker branches keep their original priority: a key arrives as
|
|
102
|
+
* a press and a release once the terminal reports key events, and the caller
|
|
103
|
+
* drops the release for the focused component, so this only ever sees the
|
|
104
|
+
* press the surface is meant to act on.
|
|
105
|
+
*/
|
|
106
|
+
const handleKey = (data) => {
|
|
107
|
+
if (pending !== undefined) {
|
|
108
|
+
if (pending.kind === 'approval') {
|
|
109
|
+
const outcome = pending.gate.handleKey(data);
|
|
110
|
+
if (outcome === undefined)
|
|
111
|
+
ports.tui.requestRender();
|
|
112
|
+
else {
|
|
113
|
+
pending.settle(outcome);
|
|
114
|
+
closeGate();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const answers = pending.gate.handleKey(data);
|
|
119
|
+
if (answers === undefined)
|
|
120
|
+
ports.tui.requestRender();
|
|
121
|
+
else {
|
|
122
|
+
pending.settle(answers);
|
|
123
|
+
closeGate();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (pendingPicker !== undefined) {
|
|
129
|
+
const action = pendingPicker.picker.handleKey(data);
|
|
130
|
+
if (action === undefined) {
|
|
131
|
+
ports.tui.requestRender();
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
if (vetting) {
|
|
135
|
+
// A refusal check must not take the keyboard with it: the reader keeps
|
|
136
|
+
// filtering and can still leave, while a second pick waits for the
|
|
137
|
+
// first verdict rather than racing it.
|
|
138
|
+
if (action.kind === 'cancel')
|
|
139
|
+
settlePicker(undefined);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
if (action.kind === 'cancel') {
|
|
143
|
+
settlePicker(undefined);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
const vet = pendingPicker.vet;
|
|
147
|
+
if (vet === undefined) {
|
|
148
|
+
settlePicker(action.id);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
vetting = true;
|
|
152
|
+
void (async () => {
|
|
153
|
+
let reason;
|
|
154
|
+
try {
|
|
155
|
+
reason = await vet(action.id);
|
|
156
|
+
}
|
|
157
|
+
finally {
|
|
158
|
+
// A check that fails must not take the keyboard with it.
|
|
159
|
+
vetting = false;
|
|
160
|
+
}
|
|
161
|
+
if (pendingPicker === undefined)
|
|
162
|
+
return;
|
|
163
|
+
if (reason === undefined) {
|
|
164
|
+
settlePicker(action.id);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
pendingPicker.picker.setNote(reason);
|
|
168
|
+
ports.tui.requestRender();
|
|
169
|
+
})();
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
return false;
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
gateCard: () => pending?.gate.card(),
|
|
176
|
+
pickerCard: () => pendingPicker?.card?.(),
|
|
177
|
+
openPicker,
|
|
178
|
+
handleKey,
|
|
179
|
+
requestListeners: () => [
|
|
180
|
+
// Answering these two waterfalls is what makes a terminal surface usable at
|
|
181
|
+
// all: without an answerer every gated tool fails closed, and the model's
|
|
182
|
+
// questions never reach the human.
|
|
183
|
+
ctx.on('approval/request', (request, next) => {
|
|
184
|
+
if (request.agent.id !== ports.activeSession())
|
|
185
|
+
return next();
|
|
186
|
+
return new Promise(resolve => {
|
|
187
|
+
const gate = new ApprovalGate(request.toolName, request.reason, ports.keymap);
|
|
188
|
+
request.signal?.addEventListener('abort', () => {
|
|
189
|
+
gate.cancel();
|
|
190
|
+
if (pending?.gate === gate)
|
|
191
|
+
closeGate();
|
|
192
|
+
resolve('cancelled');
|
|
193
|
+
}, { once: true });
|
|
194
|
+
openGate({ kind: 'approval', gate, settle: resolve });
|
|
195
|
+
});
|
|
196
|
+
}),
|
|
197
|
+
ctx.on('user-questions/request', (request, next) => {
|
|
198
|
+
const agentId = request.agent?.id;
|
|
199
|
+
if (agentId !== undefined && agentId !== ports.activeSession())
|
|
200
|
+
return next();
|
|
201
|
+
const questions = toGateQuestions(request);
|
|
202
|
+
if (questions.length === 0)
|
|
203
|
+
return next();
|
|
204
|
+
return new Promise(resolve => {
|
|
205
|
+
const gate = ports.promptBar.borrow(() => {
|
|
206
|
+
// The bar is an answer's for as long as the gate holds it, so the menu
|
|
207
|
+
// it once offered commands through is replaced before a key can reach it.
|
|
208
|
+
const built = new QuestionGate(questions, ports.editor, ports.keymap);
|
|
209
|
+
ports.refreshCompletion();
|
|
210
|
+
return built;
|
|
211
|
+
});
|
|
212
|
+
// The seam takes mutable selection arrays and an optional custom field, so
|
|
213
|
+
// the read-only gate answer is copied into that exact shape here.
|
|
214
|
+
const settle = (answers) => {
|
|
215
|
+
request.signal?.removeEventListener('abort', onAbort);
|
|
216
|
+
resolve({
|
|
217
|
+
answers: answers.map(answer => ({
|
|
218
|
+
id: answer.id,
|
|
219
|
+
selected: [...answer.selected],
|
|
220
|
+
...(answer.custom === undefined ? {} : { custom: answer.custom }),
|
|
221
|
+
})),
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
// A question whose caller is gone has no reader, so the gate must release
|
|
225
|
+
// the keyboard instead of collecting an answer the aborted call discards.
|
|
226
|
+
const onAbort = () => {
|
|
227
|
+
gate.cancel();
|
|
228
|
+
if (pending?.gate === gate)
|
|
229
|
+
closeGate();
|
|
230
|
+
settle([]);
|
|
231
|
+
};
|
|
232
|
+
openGate({ kind: 'question', gate, settle });
|
|
233
|
+
request.signal?.addEventListener('abort', onAbort, { once: true });
|
|
234
|
+
// A signal that aborted before the listener existed never emits, so the
|
|
235
|
+
// state has to be read once after subscribing.
|
|
236
|
+
if (request.signal?.aborted === true)
|
|
237
|
+
onAbort();
|
|
238
|
+
});
|
|
239
|
+
}),
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=modal-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modal-input.js","sourceRoot":"","sources":["../../src/surface/modal-input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import { type ModelChoice as ChosenRoute } from '../agent/model.ts';
|
|
3
|
+
import type { Keymap } from '../input/actions.ts';
|
|
4
|
+
import type { StatusFacts } from '../ui/status.ts';
|
|
5
|
+
import type { Picker } from './modal-input.ts';
|
|
6
|
+
/**
|
|
7
|
+
* What the route owner needs from the surface that composes it.
|
|
8
|
+
*
|
|
9
|
+
* The facts are settings-backed and read at call time: the composition default
|
|
10
|
+
* this owner adopts before the first turn, and reports when the reader named no
|
|
11
|
+
* route, exists only once the settings document has been read. The keys move
|
|
12
|
+
* with a settings edit, so they are read per press, and the screen, the notice
|
|
13
|
+
* and the keyboard lifetime belong to the surface that owns them.
|
|
14
|
+
*/
|
|
15
|
+
export interface ModelChoicePorts {
|
|
16
|
+
readonly statusFacts: () => StatusFacts;
|
|
17
|
+
readonly keymap: () => Keymap;
|
|
18
|
+
/** Take the keyboard for a list and answer with the pick id it settled on. */
|
|
19
|
+
readonly openPicker: (picker: Picker) => Promise<string | undefined>;
|
|
20
|
+
readonly notice: (message: string) => void;
|
|
21
|
+
readonly render: () => void;
|
|
22
|
+
}
|
|
23
|
+
/** The reads and operations the composing surface routes to the route owner. */
|
|
24
|
+
export interface ModelChoice {
|
|
25
|
+
/** The route the next step would use, which is what the status line states. */
|
|
26
|
+
readonly current: () => ChosenRoute | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Compose the switch into an agent's own scope, where its waterfalls dispatch.
|
|
29
|
+
*
|
|
30
|
+
* The scope arrives as an argument because it belongs to the agent being
|
|
31
|
+
* opened: the surface has no handle to it until that agent has started, and
|
|
32
|
+
* the route has to be in force from its first step.
|
|
33
|
+
*/
|
|
34
|
+
readonly setup: (agentCtx: Context) => void;
|
|
35
|
+
/** Put the deployment default in force, unless the reader already named a route. */
|
|
36
|
+
readonly adoptDefault: () => void;
|
|
37
|
+
/** Show the route in force, or switch to another one. */
|
|
38
|
+
readonly runModelCommand: (argument: string) => void;
|
|
39
|
+
/** Offer the levels the route in force advertises. */
|
|
40
|
+
readonly openEffortPicker: () => void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Which model and reasoning effort this session runs with, and the two pickers
|
|
44
|
+
* that change them.
|
|
45
|
+
*
|
|
46
|
+
* The switch and the catalog are one owner because a choice only means
|
|
47
|
+
* something against the directory it was read from: the rows of the model list
|
|
48
|
+
* stream in as each provider's adapter answers, and the levels belong to the
|
|
49
|
+
* exact route. The route in force is resolved against the status facts as much
|
|
50
|
+
* as against the switch, because a session that has chosen nothing runs the
|
|
51
|
+
* settings-backed default the footer states.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createModelChoice(ctx: Context, ports: ModelChoicePorts): ModelChoice;
|
|
54
|
+
//# sourceMappingURL=model-choice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-choice.d.ts","sourceRoot":"","sources":["../../src/surface/model-choice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAOL,KAAK,WAAW,IAAI,WAAW,EAGhC,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAGjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAM9C;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,WAAW,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAA;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IACpE,QAAQ,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAA;CAC5B;AAED,gFAAgF;AAChF,MAAM,WAAW,WAAW;IAC1B,+EAA+E;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,WAAW,GAAG,SAAS,CAAA;IAC/C;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAC3C,oFAAoF;IACpF,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAA;IACjC,yDAAyD;IACzD,QAAQ,CAAC,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACpD,sDAAsD;IACtD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,IAAI,CAAA;CACtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,gBAAgB,GAAG,WAAW,CAqTpF"}
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { ModelSwitch, createModelCatalog, parseModelArgument, readModelRouteKey, } from "../agent/model.js";
|
|
2
|
+
import { stripControlCharacters } from "../text.js";
|
|
3
|
+
import { EffortPicker, ModelPicker, PROVIDER_DEFAULT_EFFORT_ID, effortChoices } from "../ui/picker.js";
|
|
4
|
+
// Adapter errors may contain credentials or request bodies, even in their messages.
|
|
5
|
+
const MODEL_DISCOVERY_FAILURE = 'could not list models; check provider configuration and credentials, then retry /model';
|
|
6
|
+
const PROVIDER_DISCOVERY_FAILURE = 'could not list providers; check provider configuration, then retry /model';
|
|
7
|
+
/**
|
|
8
|
+
* Which model and reasoning effort this session runs with, and the two pickers
|
|
9
|
+
* that change them.
|
|
10
|
+
*
|
|
11
|
+
* The switch and the catalog are one owner because a choice only means
|
|
12
|
+
* something against the directory it was read from: the rows of the model list
|
|
13
|
+
* stream in as each provider's adapter answers, and the levels belong to the
|
|
14
|
+
* exact route. The route in force is resolved against the status facts as much
|
|
15
|
+
* as against the switch, because a session that has chosen nothing runs the
|
|
16
|
+
* settings-backed default the footer states.
|
|
17
|
+
*/
|
|
18
|
+
export function createModelChoice(ctx, ports) {
|
|
19
|
+
const modelSwitch = new ModelSwitch();
|
|
20
|
+
const catalog = createModelCatalog(ctx);
|
|
21
|
+
const runModelCommand = (argument) => {
|
|
22
|
+
if (catalog === undefined) {
|
|
23
|
+
ports.notice('this profile has no llm service, so models cannot be listed or switched');
|
|
24
|
+
ports.render();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let providers;
|
|
28
|
+
try {
|
|
29
|
+
providers = catalog.providers();
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
ports.notice(PROVIDER_DISCOVERY_FAILURE);
|
|
33
|
+
ports.render();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const command = parseModelArgument(argument, providers, modelSwitch.current());
|
|
37
|
+
switch (command.kind) {
|
|
38
|
+
case 'current':
|
|
39
|
+
// Choosing by eye is the point of a terminal selector; the picker
|
|
40
|
+
// heads itself with the route the next step will actually use.
|
|
41
|
+
void openModelPicker(providers);
|
|
42
|
+
return;
|
|
43
|
+
case 'list-models':
|
|
44
|
+
void catalog.models(command.provider).then(entries => {
|
|
45
|
+
ports.notice(entries.length === 0
|
|
46
|
+
? `${command.provider} advertises no models; an id may still work`
|
|
47
|
+
: `${command.provider}: ${entries.map(entry => entry.id).join(' ')}`);
|
|
48
|
+
ports.render();
|
|
49
|
+
}).catch(() => {
|
|
50
|
+
ports.notice(`${stripControlCharacters(command.provider)}: ${MODEL_DISCOVERY_FAILURE}`);
|
|
51
|
+
ports.render();
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
case 'switch': {
|
|
55
|
+
const choice = command.choice;
|
|
56
|
+
if (choice.reasoningEffort === undefined) {
|
|
57
|
+
// Naming no level still leaves one in force, and the model the reader
|
|
58
|
+
// is moving to decides whether it can take it: a level the request
|
|
59
|
+
// path would refuse makes an otherwise usable model look broken.
|
|
60
|
+
void (async () => {
|
|
61
|
+
const carried = await carriedEffort(choice.provider, choice.model);
|
|
62
|
+
modelSwitch.choose({
|
|
63
|
+
provider: choice.provider,
|
|
64
|
+
model: choice.model,
|
|
65
|
+
...(carried.effort === undefined ? {} : { reasoningEffort: carried.effort }),
|
|
66
|
+
});
|
|
67
|
+
ports.notice(`model set to ${choice.provider}/${choice.model} for the next step${droppedClause(carried.dropped)}`);
|
|
68
|
+
ports.render();
|
|
69
|
+
})();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// The route decides which efforts exist, so an explicit one is checked
|
|
73
|
+
// against the adapter before it is put in force: a typo must not become
|
|
74
|
+
// a request the provider rejects.
|
|
75
|
+
void (async () => {
|
|
76
|
+
try {
|
|
77
|
+
const info = await catalog.efforts(choice.provider, choice.model);
|
|
78
|
+
const efforts = info?.efforts ?? [];
|
|
79
|
+
if (!efforts.some(effort => effort.id === choice.reasoningEffort)) {
|
|
80
|
+
ports.notice(efforts.length === 0
|
|
81
|
+
? `/model: ${choice.provider}/${choice.model} advertises no reasoning efforts`
|
|
82
|
+
: `/model: ${choice.provider}/${choice.model} does not offer reasoning effort "${choice.reasoningEffort}" — offers: ${efforts.map(effort => effort.id).join(' ')}`);
|
|
83
|
+
ports.render();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
modelSwitch.choose(choice);
|
|
87
|
+
ports.notice(`model set to ${choice.provider}/${choice.model} (${choice.reasoningEffort}) for the next step`);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
ports.notice(`/model: could not read reasoning efforts: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
+
}
|
|
92
|
+
ports.render();
|
|
93
|
+
})();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
case 'invalid':
|
|
97
|
+
ports.notice(`/model: ${command.reason}`);
|
|
98
|
+
ports.render();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
/** Whether a route's effort list is being read, so a second key cannot race it. */
|
|
103
|
+
let openingEfforts = false;
|
|
104
|
+
/** Put the reader's effort choice in force for the next step. */
|
|
105
|
+
const applyEffort = (provider, modelId, effortId) => {
|
|
106
|
+
modelSwitch.choose(effortId === PROVIDER_DEFAULT_EFFORT_ID
|
|
107
|
+
? { provider, model: modelId }
|
|
108
|
+
: { provider, model: modelId, reasoningEffort: effortId });
|
|
109
|
+
ports.notice(`reasoning effort for ${provider}/${modelId} set to ${effortId === PROVIDER_DEFAULT_EFFORT_ID ? 'provider default' : effortId} for the next step`);
|
|
110
|
+
ports.render();
|
|
111
|
+
};
|
|
112
|
+
/** Whether a model picker's catalog is being read, so a second key cannot race it. */
|
|
113
|
+
let openingModels = false;
|
|
114
|
+
/**
|
|
115
|
+
* The route the next step would actually use.
|
|
116
|
+
*
|
|
117
|
+
* Without a choice of its own the surface reports the composition default,
|
|
118
|
+
* not that it has no opinion: the picker's heading and its marked row have to
|
|
119
|
+
* agree with the status line about the route in force.
|
|
120
|
+
*/
|
|
121
|
+
const effectiveRoute = () => {
|
|
122
|
+
const chosen = modelSwitch.current();
|
|
123
|
+
if (chosen !== undefined)
|
|
124
|
+
return chosen;
|
|
125
|
+
const facts = ports.statusFacts();
|
|
126
|
+
if (facts.provider === undefined || facts.model === undefined)
|
|
127
|
+
return undefined;
|
|
128
|
+
return {
|
|
129
|
+
provider: facts.provider,
|
|
130
|
+
model: facts.model,
|
|
131
|
+
...facts.effort === undefined ? {} : { reasoningEffort: facts.effort },
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* The effort a switch may carry onto the route it lands on.
|
|
136
|
+
*
|
|
137
|
+
* The levels belong to the exact route, so the level in force is checked
|
|
138
|
+
* against the model the reader moves to: the request path refuses an
|
|
139
|
+
* unsupported level before the provider sees it, and that refusal reads as
|
|
140
|
+
* the chosen model being broken. The model's own default is the fallback the
|
|
141
|
+
* picker's provider-default row also produces, and the level given up is
|
|
142
|
+
* named because silence would leave the reader reading a level that is no
|
|
143
|
+
* longer in force.
|
|
144
|
+
*/
|
|
145
|
+
const carriedEffort = async (provider, modelId) => {
|
|
146
|
+
const inForce = effectiveRoute()?.reasoningEffort;
|
|
147
|
+
if (inForce === undefined || catalog === undefined)
|
|
148
|
+
return {};
|
|
149
|
+
try {
|
|
150
|
+
const efforts = (await catalog.efforts(provider, modelId))?.efforts ?? [];
|
|
151
|
+
return efforts.some(effort => effort.id === inForce) ? { effort: inForce } : { dropped: inForce };
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
// The directory is advisory here: a switch the reader asked for must not
|
|
155
|
+
// fail on it, and a route's default is the one state every model accepts.
|
|
156
|
+
return {};
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
/** The clause a switch adds when the effort in force could not travel with it. */
|
|
160
|
+
const droppedClause = (dropped) => dropped === undefined
|
|
161
|
+
? ''
|
|
162
|
+
: ` — dropped reasoning effort "${dropped}" because this model does not offer it`;
|
|
163
|
+
/** Put the reader's route choice in force for the next step. */
|
|
164
|
+
const applyRoute = async (route) => {
|
|
165
|
+
const carried = await carriedEffort(route.provider, route.model);
|
|
166
|
+
modelSwitch.choose({
|
|
167
|
+
provider: route.provider,
|
|
168
|
+
model: route.model,
|
|
169
|
+
...(carried.effort === undefined ? {} : { reasoningEffort: carried.effort }),
|
|
170
|
+
});
|
|
171
|
+
ports.notice(`model set to ${route.provider}/${route.model} for the next step${droppedClause(carried.dropped)}`);
|
|
172
|
+
ports.render();
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Offer the levels a route advertises, after the route is already in force.
|
|
176
|
+
*
|
|
177
|
+
* Cancelling the list is a real choice — the reader keeps the model with the
|
|
178
|
+
* provider's own default — which is why the route is applied first. The list
|
|
179
|
+
* is read before the picker opens because the rows are the route's own
|
|
180
|
+
* metadata; a menu painted before that arrived could offer a level the
|
|
181
|
+
* request would then be refused for.
|
|
182
|
+
*/
|
|
183
|
+
const offerRouteEfforts = async (route) => {
|
|
184
|
+
if (catalog === undefined)
|
|
185
|
+
return;
|
|
186
|
+
try {
|
|
187
|
+
const info = await catalog.efforts(route.provider, route.model);
|
|
188
|
+
const efforts = info?.efforts ?? [];
|
|
189
|
+
if (efforts.length === 0)
|
|
190
|
+
return;
|
|
191
|
+
const current = effectiveRoute();
|
|
192
|
+
const effective = current !== undefined && current.provider === route.provider && current.model === route.model
|
|
193
|
+
? current.reasoningEffort
|
|
194
|
+
: undefined;
|
|
195
|
+
const picked = await ports.openPicker(new EffortPicker(() => effortChoices(efforts, effective), `reasoning effort · ${route.provider}/${route.model}`, ports.keymap));
|
|
196
|
+
if (picked !== undefined)
|
|
197
|
+
applyEffort(route.provider, route.model, picked);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
ports.notice(`could not read reasoning efforts: ${error instanceof Error ? error.message : String(error)}`);
|
|
201
|
+
}
|
|
202
|
+
ports.render();
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Offer every model the configured routes advertise.
|
|
206
|
+
*
|
|
207
|
+
* Rows come from the routes the llm service registered — the providers this
|
|
208
|
+
* deployment configured — and each provider's models join the open list as
|
|
209
|
+
* its catalog resolves, so the picker is filterable before the slowest
|
|
210
|
+
* adapter answers. A route whose catalog cannot be read stays reachable by
|
|
211
|
+
* name through the text form; a notice explains why its rows are missing.
|
|
212
|
+
*/
|
|
213
|
+
const openModelPicker = async (providers) => {
|
|
214
|
+
if (catalog === undefined) {
|
|
215
|
+
ports.notice('this profile has no llm service, so models cannot be listed or switched');
|
|
216
|
+
ports.render();
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (providers.length === 0) {
|
|
220
|
+
ports.notice('no provider is configured; add one before choosing a model');
|
|
221
|
+
ports.render();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (openingModels)
|
|
225
|
+
return;
|
|
226
|
+
openingModels = true;
|
|
227
|
+
try {
|
|
228
|
+
const routes = [];
|
|
229
|
+
for (const provider of providers) {
|
|
230
|
+
void catalog.models(provider.id).then(entries => {
|
|
231
|
+
if (entries.length === 0)
|
|
232
|
+
return;
|
|
233
|
+
routes.push(...entries.map(entry => ({ provider: provider.id, model: entry.id, name: entry.name })));
|
|
234
|
+
ports.render();
|
|
235
|
+
}).catch(() => {
|
|
236
|
+
ports.notice(`${stripControlCharacters(provider.id)}: ${MODEL_DISCOVERY_FAILURE}`);
|
|
237
|
+
ports.render();
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
const picked = await ports.openPicker(new ModelPicker(() => routes, effectiveRoute, ports.keymap));
|
|
241
|
+
if (picked === undefined)
|
|
242
|
+
return;
|
|
243
|
+
const route = readModelRouteKey(picked);
|
|
244
|
+
if (route === undefined)
|
|
245
|
+
return;
|
|
246
|
+
await applyRoute(route);
|
|
247
|
+
await offerRouteEfforts(route);
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
openingModels = false;
|
|
251
|
+
ports.render();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Offer the efforts the route in force advertises.
|
|
256
|
+
*
|
|
257
|
+
* The list is read before the picker opens because the rows are the route's
|
|
258
|
+
* own metadata; a menu painted before that arrived could offer a level the
|
|
259
|
+
* request would then be refused for.
|
|
260
|
+
*/
|
|
261
|
+
const openEffortPicker = async () => {
|
|
262
|
+
if (catalog === undefined) {
|
|
263
|
+
ports.notice('this profile has no llm service, so reasoning efforts cannot be read');
|
|
264
|
+
ports.render();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const facts = ports.statusFacts();
|
|
268
|
+
if (facts.provider === undefined || facts.model === undefined) {
|
|
269
|
+
ports.notice('no model route is in use; /model <provider>/<model> picks one first');
|
|
270
|
+
ports.render();
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (openingEfforts)
|
|
274
|
+
return;
|
|
275
|
+
openingEfforts = true;
|
|
276
|
+
try {
|
|
277
|
+
const info = await catalog.efforts(facts.provider, facts.model);
|
|
278
|
+
const efforts = info?.efforts ?? [];
|
|
279
|
+
if (efforts.length === 0) {
|
|
280
|
+
ports.notice(`${facts.provider}/${facts.model} advertises no reasoning efforts`);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const picked = await ports.openPicker(new EffortPicker(() => effortChoices(efforts, facts.effort), `reasoning effort · ${facts.provider}/${facts.model}`, ports.keymap));
|
|
284
|
+
if (picked !== undefined)
|
|
285
|
+
applyEffort(facts.provider, facts.model, picked);
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
ports.notice(`could not read reasoning efforts: ${error instanceof Error ? error.message : String(error)}`);
|
|
289
|
+
}
|
|
290
|
+
finally {
|
|
291
|
+
openingEfforts = false;
|
|
292
|
+
ports.render();
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Put the deployment default in force before the first turn.
|
|
297
|
+
*
|
|
298
|
+
* The agent is created before the settings file has been read, so the route
|
|
299
|
+
* its loop captured is the composition placeholder; the reader's default —
|
|
300
|
+
* effort included — only exists by the time they can type. Adopting it here
|
|
301
|
+
* is what makes the status line's route the one the request actually uses.
|
|
302
|
+
*/
|
|
303
|
+
const adoptDefault = () => {
|
|
304
|
+
if (modelSwitch.current() !== undefined)
|
|
305
|
+
return;
|
|
306
|
+
const facts = ports.statusFacts();
|
|
307
|
+
if (facts.provider === undefined || facts.model === undefined)
|
|
308
|
+
return;
|
|
309
|
+
modelSwitch.adopt({
|
|
310
|
+
provider: facts.provider,
|
|
311
|
+
model: facts.model,
|
|
312
|
+
...(facts.effort === undefined ? {} : { reasoningEffort: facts.effort }),
|
|
313
|
+
});
|
|
314
|
+
};
|
|
315
|
+
return {
|
|
316
|
+
current: () => modelSwitch.current(),
|
|
317
|
+
setup: agentCtx => modelSwitch.install(agentCtx),
|
|
318
|
+
adoptDefault,
|
|
319
|
+
runModelCommand,
|
|
320
|
+
openEffortPicker: () => {
|
|
321
|
+
void openEffortPicker();
|
|
322
|
+
},
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
//# sourceMappingURL=model-choice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-choice.js","sourceRoot":"","sources":["../../src/surface/model-choice.ts"],"names":[],"mappings":"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"}
|