@astralyn/pi 0.84.4 → 0.84.5
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/CHANGELOG.md +30 -0
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +11 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-command.d.ts.map +1 -1
- package/dist/cli/auth-command.js +5 -4
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/core/agent-session.d.ts +6 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -6
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/experimental.d.ts +4 -0
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +4 -0
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +4 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +8 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/keybindings.d.ts +29 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +4 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +1 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +2 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +4 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/project-trust.js +2 -2
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/sdk.d.ts +5 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.js +2 -2
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +6 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +12 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +2 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -0
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +2 -0
- package/dist/core/tools/write.js.map +1 -1
- package/dist/extensions/background/index.d.ts +74 -0
- package/dist/extensions/background/index.d.ts.map +1 -0
- package/dist/extensions/background/index.js +332 -0
- package/dist/extensions/background/index.js.map +1 -0
- package/dist/extensions/background/manager.d.ts +81 -0
- package/dist/extensions/background/manager.d.ts.map +1 -0
- package/dist/extensions/background/manager.js +320 -0
- package/dist/extensions/background/manager.js.map +1 -0
- package/dist/extensions/background/registry.d.ts +138 -0
- package/dist/extensions/background/registry.d.ts.map +1 -0
- package/dist/extensions/background/registry.js +358 -0
- package/dist/extensions/background/registry.js.map +1 -0
- package/dist/extensions/background/render.d.ts +26 -0
- package/dist/extensions/background/render.d.ts.map +1 -0
- package/dist/extensions/background/render.js +118 -0
- package/dist/extensions/background/render.js.map +1 -0
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +2 -0
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/subagent/activity.d.ts +0 -1
- package/dist/extensions/subagent/activity.d.ts.map +1 -1
- package/dist/extensions/subagent/activity.js +2 -5
- package/dist/extensions/subagent/activity.js.map +1 -1
- package/dist/extensions/subagent/agents-command.d.ts.map +1 -1
- package/dist/extensions/subagent/agents-command.js +308 -153
- package/dist/extensions/subagent/agents-command.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts +3 -6
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +22 -192
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +4 -5
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +11 -7
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/index.d.ts +0 -3
- package/dist/extensions/subagent/index.d.ts.map +1 -1
- package/dist/extensions/subagent/index.js +56 -188
- package/dist/extensions/subagent/index.js.map +1 -1
- package/dist/extensions/subagent/render.d.ts +1 -1
- package/dist/extensions/subagent/render.d.ts.map +1 -1
- package/dist/extensions/subagent/render.js +208 -576
- package/dist/extensions/subagent/render.js.map +1 -1
- package/dist/extensions/subagent/resolve.d.ts +2 -2
- package/dist/extensions/subagent/resolve.d.ts.map +1 -1
- package/dist/extensions/subagent/resolve.js +23 -15
- package/dist/extensions/subagent/resolve.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +1 -2
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +109 -131
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts +4 -10
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js +8 -13
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +9 -20
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/settings.d.ts +2 -2
- package/dist/extensions/subagent/settings.d.ts.map +1 -1
- package/dist/extensions/subagent/settings.js +27 -14
- package/dist/extensions/subagent/settings.js.map +1 -1
- package/dist/extensions/subagent/text.d.ts +3 -0
- package/dist/extensions/subagent/text.d.ts.map +1 -0
- package/dist/extensions/subagent/text.js +16 -0
- package/dist/extensions/subagent/text.js.map +1 -0
- package/dist/extensions/subagent/types.d.ts +13 -35
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/subagent/ui/model-list.d.ts +4 -3
- package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-list.js +10 -4
- package/dist/extensions/subagent/ui/model-list.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +5 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +8 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +77 -25
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +36 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +2 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +23 -10
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive/theme/theme.d.ts +5 -3
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +12 -2
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +4 -1
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +5 -2
- package/dist/modes/json-event.js.map +1 -1
- package/dist/package-manager-cli.js +1 -1
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/server/create-harness.d.ts.map +1 -1
- package/dist/server/create-harness.js +2 -0
- package/dist/server/create-harness.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +10 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +14 -19
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/bundled/README.md +1 -0
- package/docs/bundled/extensions/background.md +64 -0
- package/docs/bundled/extensions/subagent.md +83 -71
- package/docs/compaction.md +6 -6
- package/docs/custom-provider.md +1 -1
- package/docs/docs.json +4 -0
- package/docs/environment-variables.md +8 -2
- package/docs/extensions.md +6 -2
- package/docs/json.md +6 -4
- package/docs/keybindings.md +9 -2
- package/docs/rpc.md +15 -4
- package/docs/sdk.md +9 -0
- package/docs/settings.md +31 -0
- package/docs/terminal-setup.md +23 -2
- package/docs/themes.md +24 -3
- package/docs/tui.md +2 -2
- package/docs/usage.md +4 -3
- package/examples/README.md +1 -1
- package/examples/extensions/README.md +0 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +170 -221
- package/package.json +6 -6
- package/dist/extensions/subagent/display-name.d.ts +0 -6
- package/dist/extensions/subagent/display-name.d.ts.map +0 -1
- package/dist/extensions/subagent/display-name.js +0 -13
- package/dist/extensions/subagent/display-name.js.map +0 -1
- package/dist/extensions/subagent/ui/profile-editor.d.ts +0 -54
- package/dist/extensions/subagent/ui/profile-editor.d.ts.map +0 -1
- package/dist/extensions/subagent/ui/profile-editor.js +0 -154
- package/dist/extensions/subagent/ui/profile-editor.js.map +0 -1
- package/dist/extensions/subagent/ui/profile-picker.d.ts +0 -32
- package/dist/extensions/subagent/ui/profile-picker.d.ts.map +0 -1
- package/dist/extensions/subagent/ui/profile-picker.js +0 -149
- package/dist/extensions/subagent/ui/profile-picker.js.map +0 -1
- package/examples/extensions/subagent/README.md +0 -175
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -1009
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { clampThinkingLevel, getSupportedThinkingLevels } from "@earendil-works/pi-ai/compat";
|
|
2
|
+
import { Container, Spacer, Text, TruncatedText, } from "@earendil-works/pi-tui";
|
|
2
3
|
import { getAgentDir } from "../../config.js";
|
|
3
|
-
import {
|
|
4
|
+
import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
|
|
5
|
+
import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
|
|
6
|
+
import { AGENT_PROFILES } from "./agents.js";
|
|
4
7
|
import { THINKING_LEVELS } from "./constants.js";
|
|
5
|
-
import { displayAgentName } from "./display-name.js";
|
|
6
8
|
import { loadSubagentConfig, updateProfileOverride } from "./settings.js";
|
|
7
|
-
import {
|
|
8
|
-
import { ProfilePickerComponent } from "./ui/profile-picker.js";
|
|
9
|
+
import { ProfileModelListComponent } from "./ui/model-list.js";
|
|
9
10
|
const MODEL_REFRESH_TIMEOUT_MS = 15_000;
|
|
10
|
-
const MAX_DIAGNOSTICS = 20;
|
|
11
|
-
const MAX_DIAGNOSTIC_LENGTH = 240;
|
|
12
11
|
const MAX_REFRESH_ERROR_LENGTH = 240;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
12
|
+
// Static display titles for the two built-in profiles; agents.ts owns the
|
|
13
|
+
// model-facing copy.
|
|
14
|
+
const PROFILE_LABELS = {
|
|
15
|
+
explorer: "Explorer",
|
|
16
|
+
general: "General",
|
|
17
|
+
};
|
|
20
18
|
function modelId(model) {
|
|
21
19
|
return model ? `${model.provider}/${model.id}` : "none";
|
|
22
20
|
}
|
|
@@ -29,27 +27,18 @@ function boundText(value, limit) {
|
|
|
29
27
|
const characters = [...value];
|
|
30
28
|
return characters.length <= limit ? value : `${characters.slice(0, Math.max(0, limit - 1)).join("")}…`;
|
|
31
29
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
// Capability checks use the saved model when it is still in the catalog,
|
|
31
|
+
// falling back to the parent session model otherwise.
|
|
32
|
+
function effectiveModel(currentSessionModel, models, override) {
|
|
33
|
+
if (override?.model) {
|
|
34
|
+
const saved = findModel(models, override.model);
|
|
35
|
+
if (saved)
|
|
36
|
+
return saved;
|
|
38
37
|
}
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
function overridesEqual(override, result) {
|
|
42
|
-
return override?.model === result.model && override?.thinking === result.thinking;
|
|
38
|
+
return currentSessionModel;
|
|
43
39
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return;
|
|
47
|
-
try {
|
|
48
|
-
await updateProfileOverride(profileName, { model: result.model, thinking: result.thinking }, getAgentDir());
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
ctx.ui.notify(`Could not save ${displayAgentName(profileName)} settings: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
52
|
-
}
|
|
40
|
+
function inheritedThinking(effective, currentThinking) {
|
|
41
|
+
return effective ? clampThinkingLevel(effective, currentThinking) : currentThinking;
|
|
53
42
|
}
|
|
54
43
|
function refreshFailureMessage(providerIds) {
|
|
55
44
|
if (providerIds.length === 1)
|
|
@@ -59,162 +48,326 @@ function refreshFailureMessage(providerIds) {
|
|
|
59
48
|
const suffix = omitted > 0 ? `, +${omitted} more` : "";
|
|
60
49
|
return `Could not refresh ${providerIds.length} model catalogs (${visible.join(", ")}${suffix}); showing cached models.`;
|
|
61
50
|
}
|
|
62
|
-
|
|
51
|
+
function hint(theme, keybindings, binding, description) {
|
|
52
|
+
const key = keyLabel(binding, { keybindings });
|
|
53
|
+
return key ? `${theme.fg("dim", key)}${theme.fg("muted", ` ${description}`)}` : "";
|
|
54
|
+
}
|
|
55
|
+
function navigationHint(theme, keybindings) {
|
|
56
|
+
const keys = [keyLabel("tui.select.up", { keybindings }), keyLabel("tui.select.down", { keybindings })]
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join("/");
|
|
59
|
+
return keys ? `${theme.fg("dim", keys)}${theme.fg("muted", " navigate")}` : "";
|
|
60
|
+
}
|
|
61
|
+
/** Compact Model/Thinking settings menu for one profile; every confirm persists immediately. */
|
|
62
|
+
class ProfileSettingsMenuComponent extends Container {
|
|
63
|
+
get focused() {
|
|
64
|
+
return this._focused;
|
|
65
|
+
}
|
|
66
|
+
set focused(value) {
|
|
67
|
+
this._focused = value;
|
|
68
|
+
}
|
|
69
|
+
constructor(options) {
|
|
70
|
+
super();
|
|
71
|
+
this.selectedIndex = 0;
|
|
72
|
+
this._focused = false;
|
|
73
|
+
this.theme = options.theme;
|
|
74
|
+
this.keybindings = options.keybindings;
|
|
75
|
+
this.onDone = options.onDone;
|
|
76
|
+
const effective = effectiveModel(options.currentSessionModel, options.models, options.override);
|
|
77
|
+
this.rows = [
|
|
78
|
+
{
|
|
79
|
+
action: "model",
|
|
80
|
+
label: "Model",
|
|
81
|
+
value: options.override?.model
|
|
82
|
+
? `override — ${options.override.model}${findModel(options.models, options.override.model) ? "" : " [unavailable]"}`
|
|
83
|
+
: `inherit — ${modelId(options.currentSessionModel)}`,
|
|
84
|
+
override: options.override?.model !== undefined,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
action: "thinking",
|
|
88
|
+
label: "Thinking",
|
|
89
|
+
value: options.override?.thinking
|
|
90
|
+
? `override — ${options.override.thinking}`
|
|
91
|
+
: `inherit — ${inheritedThinking(effective, options.currentThinking)}`,
|
|
92
|
+
override: options.override?.thinking !== undefined,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
this.addChild(new DynamicBorder());
|
|
96
|
+
this.addChild(new Spacer(1));
|
|
97
|
+
this.addChild(new Text(this.theme.fg("accent", this.theme.bold(PROFILE_LABELS[options.profile.name])), 1, 0));
|
|
98
|
+
this.addChild(new Spacer(1));
|
|
99
|
+
this.listContainer = new Container();
|
|
100
|
+
this.addChild(this.listContainer);
|
|
101
|
+
this.addChild(new Spacer(1));
|
|
102
|
+
const hints = [
|
|
103
|
+
navigationHint(this.theme, options.keybindings),
|
|
104
|
+
hint(this.theme, options.keybindings, "tui.select.confirm", "select"),
|
|
105
|
+
hint(this.theme, options.keybindings, "tui.select.cancel", "back"),
|
|
106
|
+
].filter(Boolean);
|
|
107
|
+
this.addChild(new Text(hints.join(this.theme.fg("muted", " • ")), 1, 0));
|
|
108
|
+
this.addChild(new Spacer(1));
|
|
109
|
+
this.addChild(new DynamicBorder());
|
|
110
|
+
this.updateList();
|
|
111
|
+
}
|
|
112
|
+
updateList() {
|
|
113
|
+
this.listContainer.clear();
|
|
114
|
+
for (const [index, row] of this.rows.entries()) {
|
|
115
|
+
const selected = index === this.selectedIndex;
|
|
116
|
+
const prefix = selected ? this.theme.fg("accent", "→ ") : " ";
|
|
117
|
+
const label = selected ? this.theme.fg("accent", row.label) : this.theme.fg("text", row.label);
|
|
118
|
+
const value = this.theme.fg("muted", `— ${row.value}`);
|
|
119
|
+
const checkmark = row.override ? this.theme.fg("success", " ✓") : "";
|
|
120
|
+
this.listContainer.addChild(new TruncatedText(`${prefix}${label} ${value}${checkmark}`, 1, 0));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
moveSelection(offset) {
|
|
124
|
+
this.selectedIndex = (this.selectedIndex + offset + this.rows.length) % this.rows.length;
|
|
125
|
+
this.updateList();
|
|
126
|
+
}
|
|
127
|
+
handleInput(data) {
|
|
128
|
+
if (this.keybindings.matches(data, "tui.select.up")) {
|
|
129
|
+
this.moveSelection(-1);
|
|
130
|
+
}
|
|
131
|
+
else if (this.keybindings.matches(data, "tui.select.down")) {
|
|
132
|
+
this.moveSelection(1);
|
|
133
|
+
}
|
|
134
|
+
else if (this.keybindings.matches(data, "tui.select.confirm")) {
|
|
135
|
+
this.onDone(this.rows[this.selectedIndex]?.action);
|
|
136
|
+
}
|
|
137
|
+
else if (this.keybindings.matches(data, "tui.select.cancel")) {
|
|
138
|
+
this.onDone(undefined);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Standalone searchable model picker for one profile; confirm saves immediately. */
|
|
143
|
+
class ModelPickerComponent extends Container {
|
|
144
|
+
get focused() {
|
|
145
|
+
return this._focused;
|
|
146
|
+
}
|
|
147
|
+
set focused(value) {
|
|
148
|
+
this._focused = value;
|
|
149
|
+
this.modelList.focused = value;
|
|
150
|
+
}
|
|
151
|
+
constructor(options) {
|
|
152
|
+
super();
|
|
153
|
+
this.refreshAbortController = new AbortController();
|
|
154
|
+
this.closed = false;
|
|
155
|
+
this._focused = false;
|
|
156
|
+
this.tui = options.tui;
|
|
157
|
+
this.theme = options.theme;
|
|
158
|
+
this.keybindings = options.keybindings;
|
|
159
|
+
this.addChild(new DynamicBorder());
|
|
160
|
+
this.addChild(new Spacer(1));
|
|
161
|
+
this.addChild(new Text(this.theme.fg("accent", this.theme.bold(`Model — ${PROFILE_LABELS[options.profile.name]}`)), 1, 0));
|
|
162
|
+
this.addChild(new Spacer(1));
|
|
163
|
+
this.modelList = new ProfileModelListComponent({
|
|
164
|
+
theme: options.theme,
|
|
165
|
+
keybindings: options.keybindings,
|
|
166
|
+
models: options.models,
|
|
167
|
+
scopedModels: options.scopedModels,
|
|
168
|
+
currentSessionModel: options.currentSessionModel,
|
|
169
|
+
savedModelId: options.savedModelId,
|
|
170
|
+
onDone: options.onDone,
|
|
171
|
+
});
|
|
172
|
+
this.addChild(this.modelList);
|
|
173
|
+
this.addChild(new Spacer(1));
|
|
174
|
+
const hints = [
|
|
175
|
+
navigationHint(this.theme, options.keybindings),
|
|
176
|
+
options.scopedModels.length > 0 ? hint(this.theme, options.keybindings, "tui.input.tab", "scope") : "",
|
|
177
|
+
hint(this.theme, options.keybindings, "tui.select.confirm", "select"),
|
|
178
|
+
hint(this.theme, options.keybindings, "tui.select.cancel", "back"),
|
|
179
|
+
].filter(Boolean);
|
|
180
|
+
this.addChild(new Text(hints.join(this.theme.fg("muted", " • ")), 1, 0));
|
|
181
|
+
this.addChild(new Spacer(1));
|
|
182
|
+
this.addChild(new DynamicBorder());
|
|
183
|
+
}
|
|
184
|
+
get refreshSignal() {
|
|
185
|
+
return this.refreshAbortController.signal;
|
|
186
|
+
}
|
|
187
|
+
cancelRefresh() {
|
|
188
|
+
this.refreshAbortController.abort();
|
|
189
|
+
}
|
|
190
|
+
get isClosed() {
|
|
191
|
+
return this.closed;
|
|
192
|
+
}
|
|
193
|
+
dispose() {
|
|
194
|
+
this.closed = true;
|
|
195
|
+
this.refreshAbortController.abort();
|
|
196
|
+
}
|
|
197
|
+
updateModels(models) {
|
|
198
|
+
if (this.closed)
|
|
199
|
+
return;
|
|
200
|
+
this.modelList.updateModels(models);
|
|
201
|
+
this.tui.requestRender();
|
|
202
|
+
}
|
|
203
|
+
setRefreshStatus(message, tone = "muted") {
|
|
204
|
+
if (this.closed)
|
|
205
|
+
return;
|
|
206
|
+
this.modelList.setStatus(message, tone);
|
|
207
|
+
this.tui.requestRender();
|
|
208
|
+
}
|
|
209
|
+
handleInput(data) {
|
|
210
|
+
this.modelList.handleInput(data);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** Persist a single override atomically; the UI only reflects the value on success. */
|
|
214
|
+
async function persistOverride(ctx, profile, patch, current) {
|
|
215
|
+
const next = "model" in patch ? patch.model : patch.thinking;
|
|
216
|
+
if (next === current)
|
|
217
|
+
return;
|
|
218
|
+
try {
|
|
219
|
+
await updateProfileOverride(profile.name, patch, getAgentDir());
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
ctx.ui.notify(`Could not save ${PROFILE_LABELS[profile.name]} settings: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
async function refreshPickerModels(ctx, picker) {
|
|
63
226
|
let timedOut = false;
|
|
64
227
|
const timeout = setTimeout(() => {
|
|
65
228
|
timedOut = true;
|
|
66
|
-
|
|
229
|
+
picker.cancelRefresh();
|
|
67
230
|
}, MODEL_REFRESH_TIMEOUT_MS);
|
|
68
231
|
timeout.unref?.();
|
|
69
232
|
try {
|
|
70
|
-
const result = await ctx.modelRegistry.refresh({ signal:
|
|
71
|
-
if (
|
|
233
|
+
const result = await ctx.modelRegistry.refresh({ signal: picker.refreshSignal });
|
|
234
|
+
if (picker.isClosed || (picker.refreshSignal.aborted && !timedOut))
|
|
72
235
|
return;
|
|
73
|
-
|
|
236
|
+
picker.updateModels(ctx.modelRegistry.getAvailable());
|
|
74
237
|
if (result.aborted && timedOut) {
|
|
75
|
-
|
|
238
|
+
picker.setRefreshStatus("Model refresh timed out; showing cached models.", "error");
|
|
76
239
|
return;
|
|
77
240
|
}
|
|
78
241
|
const providerIds = [...result.errors.keys()];
|
|
79
242
|
if (providerIds.length > 0) {
|
|
80
|
-
|
|
243
|
+
picker.setRefreshStatus(refreshFailureMessage(providerIds), "error");
|
|
81
244
|
return;
|
|
82
245
|
}
|
|
83
246
|
const registryError = ctx.modelRegistry.getError();
|
|
84
247
|
if (registryError) {
|
|
85
|
-
|
|
248
|
+
picker.setRefreshStatus(boundText(registryError, MAX_REFRESH_ERROR_LENGTH), "error");
|
|
86
249
|
return;
|
|
87
250
|
}
|
|
88
|
-
|
|
251
|
+
picker.setRefreshStatus(undefined);
|
|
89
252
|
}
|
|
90
253
|
catch (error) {
|
|
91
|
-
if (
|
|
254
|
+
if (picker.isClosed || (picker.refreshSignal.aborted && !timedOut))
|
|
92
255
|
return;
|
|
93
256
|
const message = timedOut
|
|
94
257
|
? "Model refresh timed out; showing cached models."
|
|
95
258
|
: `Could not refresh model catalogs: ${error instanceof Error ? error.message : String(error)}`;
|
|
96
|
-
|
|
259
|
+
picker.setRefreshStatus(boundText(message, MAX_REFRESH_ERROR_LENGTH), "error");
|
|
97
260
|
}
|
|
98
261
|
finally {
|
|
99
262
|
clearTimeout(timeout);
|
|
100
263
|
}
|
|
101
264
|
}
|
|
102
|
-
async function
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
265
|
+
async function selectProfile(ctx) {
|
|
266
|
+
const labels = AGENT_PROFILES.map((profile) => PROFILE_LABELS[profile.name]);
|
|
267
|
+
const label = await ctx.ui.select("Agents", labels);
|
|
268
|
+
return label === undefined ? undefined : AGENT_PROFILES.find((profile) => PROFILE_LABELS[profile.name] === label);
|
|
269
|
+
}
|
|
270
|
+
async function showTuiSettingsMenu(ctx, profile, override, currentThinking) {
|
|
271
|
+
return ctx.ui.custom((_tui, theme, keybindings, done) => new ProfileSettingsMenuComponent({
|
|
272
|
+
theme,
|
|
273
|
+
keybindings,
|
|
274
|
+
profile,
|
|
275
|
+
override,
|
|
276
|
+
models: ctx.modelRegistry.getAvailable(),
|
|
277
|
+
currentSessionModel: ctx.model,
|
|
278
|
+
currentThinking,
|
|
279
|
+
onDone: done,
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
async function showDialogSettingsMenu(ctx, profile, override, currentThinking) {
|
|
283
|
+
const models = ctx.modelRegistry.getAvailable();
|
|
284
|
+
const effective = effectiveModel(ctx.model, models, override);
|
|
285
|
+
const modelValue = override?.model
|
|
286
|
+
? `override — ${override.model}${findModel(models, override.model) ? "" : " [unavailable]"}`
|
|
287
|
+
: `inherit — ${modelId(ctx.model)}`;
|
|
288
|
+
const thinkingValue = override?.thinking
|
|
289
|
+
? `override — ${override.thinking}`
|
|
290
|
+
: `inherit — ${inheritedThinking(effective, currentThinking)}`;
|
|
291
|
+
const options = new Map();
|
|
292
|
+
options.set(`Model — ${modelValue}`, "model");
|
|
293
|
+
options.set(`Thinking — ${thinkingValue}`, "thinking");
|
|
294
|
+
const label = await ctx.ui.select(PROFILE_LABELS[profile.name], [...options.keys()]);
|
|
295
|
+
return label === undefined ? undefined : options.get(label);
|
|
296
|
+
}
|
|
297
|
+
async function showTuiModelPicker(ctx, profile, override) {
|
|
298
|
+
const chosen = await ctx.ui.custom((tui, theme, keybindings, done) => {
|
|
299
|
+
const picker = new ModelPickerComponent({
|
|
300
|
+
tui,
|
|
301
|
+
theme,
|
|
302
|
+
keybindings,
|
|
303
|
+
profile,
|
|
304
|
+
savedModelId: override?.model,
|
|
305
|
+
models: ctx.modelRegistry.getAvailable(),
|
|
306
|
+
scopedModels: ctx.scopedModels,
|
|
307
|
+
currentSessionModel: ctx.model,
|
|
308
|
+
onDone: done,
|
|
136
309
|
});
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
310
|
+
picker.setRefreshStatus("Refreshing model catalogs…");
|
|
311
|
+
void refreshPickerModels(ctx, picker);
|
|
312
|
+
return picker;
|
|
313
|
+
});
|
|
314
|
+
return chosen === undefined ? undefined : { modelId: chosen.modelId };
|
|
315
|
+
}
|
|
316
|
+
async function showDialogModelPicker(ctx, profile, override) {
|
|
317
|
+
const models = ctx.modelRegistry.getAvailable().sort((left, right) => {
|
|
318
|
+
const provider = left.provider.localeCompare(right.provider);
|
|
319
|
+
return provider !== 0 ? provider : left.id.localeCompare(right.id);
|
|
320
|
+
});
|
|
321
|
+
const choices = new Map();
|
|
322
|
+
choices.set(`inherit (${modelId(ctx.model)})${override?.model ? "" : " ✓"}`, undefined);
|
|
323
|
+
if (override?.model && !findModel(models, override.model)) {
|
|
324
|
+
choices.set(`${override.model} [unavailable] ✓`, override.model);
|
|
140
325
|
}
|
|
326
|
+
for (const model of models) {
|
|
327
|
+
const id = modelId(model);
|
|
328
|
+
choices.set(`${id}${override?.model === id ? " ✓" : ""}`, id);
|
|
329
|
+
}
|
|
330
|
+
const label = await ctx.ui.select(`Model — ${PROFILE_LABELS[profile.name]}`, [...choices.keys()]);
|
|
331
|
+
return label === undefined ? undefined : { modelId: choices.get(label) };
|
|
141
332
|
}
|
|
142
|
-
function
|
|
143
|
-
const
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
333
|
+
async function showThinkingPicker(ctx, profile, override, currentThinking) {
|
|
334
|
+
const models = ctx.modelRegistry.getAvailable();
|
|
335
|
+
const effective = effectiveModel(ctx.model, models, override);
|
|
336
|
+
const levels = effective ? getSupportedThinkingLevels(effective) : [...THINKING_LEVELS];
|
|
337
|
+
const inherited = inheritedThinking(effective, currentThinking);
|
|
338
|
+
const choices = new Map();
|
|
339
|
+
choices.set(`inherit (${inherited})${override?.thinking ? "" : " ✓"}`, undefined);
|
|
340
|
+
for (const level of levels) {
|
|
341
|
+
choices.set(`${level}${override?.thinking === level ? " ✓" : ""}`, level);
|
|
148
342
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return [counts.get(display) === 1 ? display : `${display} (${agent.name})`, agent];
|
|
152
|
-
}));
|
|
343
|
+
const label = await ctx.ui.select(`Thinking — ${PROFILE_LABELS[profile.name]}`, [...choices.keys()]);
|
|
344
|
+
return label === undefined ? undefined : { level: choices.get(label) };
|
|
153
345
|
}
|
|
154
|
-
async function
|
|
346
|
+
async function runProfileSettings(ctx, profile, currentThinking) {
|
|
155
347
|
const agentDir = getAgentDir();
|
|
348
|
+
const isTui = ctx.mode === "tui";
|
|
156
349
|
while (true) {
|
|
157
|
-
const discovery = discoverAgents(ctx.cwd, { projectTrusted: ctx.isProjectTrusted(), agentDir });
|
|
158
|
-
const labels = uniqueProfileLabels(discovery.agents);
|
|
159
|
-
const diagnosticsLabel = discovery.diagnostics.length
|
|
160
|
-
? `View ${discovery.diagnostics.length} agent file issue${discovery.diagnostics.length === 1 ? "" : "s"}`
|
|
161
|
-
: undefined;
|
|
162
|
-
const selectedLabel = await ctx.ui.select("Agents", [
|
|
163
|
-
...labels.keys(),
|
|
164
|
-
...(diagnosticsLabel ? [diagnosticsLabel] : []),
|
|
165
|
-
]);
|
|
166
|
-
if (!selectedLabel)
|
|
167
|
-
return;
|
|
168
|
-
if (selectedLabel === diagnosticsLabel) {
|
|
169
|
-
ctx.ui.notify(formatDiagnostics(discovery.diagnostics), "warning");
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
const agent = labels.get(selectedLabel);
|
|
173
|
-
if (!agent)
|
|
174
|
-
continue;
|
|
175
350
|
const config = await loadSubagentConfig(agentDir);
|
|
176
|
-
const override = config.profiles[
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
modelChoices.set(`${id}${override?.model === id ? " ✓" : ""}`, id);
|
|
351
|
+
const override = config.profiles[profile.name];
|
|
352
|
+
const action = isTui
|
|
353
|
+
? await showTuiSettingsMenu(ctx, profile, override, currentThinking)
|
|
354
|
+
: await showDialogSettingsMenu(ctx, profile, override, currentThinking);
|
|
355
|
+
if (!action)
|
|
356
|
+
return;
|
|
357
|
+
if (action === "model") {
|
|
358
|
+
const chosen = isTui
|
|
359
|
+
? await showTuiModelPicker(ctx, profile, override)
|
|
360
|
+
: await showDialogModelPicker(ctx, profile, override);
|
|
361
|
+
if (!chosen)
|
|
362
|
+
continue;
|
|
363
|
+
await persistOverride(ctx, profile, { model: chosen.modelId }, override?.model);
|
|
190
364
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const selectedModelId = modelChoices.get(selectedModelLabel);
|
|
197
|
-
const effectiveModel = selectedModelId ? findModel(models, selectedModelId) : ctx.model;
|
|
198
|
-
const levels = effectiveModel
|
|
199
|
-
? getSupportedThinkingLevels(effectiveModel)
|
|
200
|
-
: [...THINKING_LEVELS];
|
|
201
|
-
const inheritedThinking = effectiveModel
|
|
202
|
-
? clampThinkingLevel(effectiveModel, currentThinking)
|
|
203
|
-
: currentThinking;
|
|
204
|
-
const thinkingChoices = new Map();
|
|
205
|
-
thinkingChoices.set(`inherit (${inheritedThinking})${override?.thinking ? "" : " ✓"}`, undefined);
|
|
206
|
-
for (const level of levels) {
|
|
207
|
-
thinkingChoices.set(`${level}${override?.thinking === level ? " ✓" : ""}`, level);
|
|
365
|
+
else {
|
|
366
|
+
const chosen = await showThinkingPicker(ctx, profile, override, currentThinking);
|
|
367
|
+
if (!chosen)
|
|
368
|
+
continue;
|
|
369
|
+
await persistOverride(ctx, profile, { thinking: chosen.level }, override?.thinking);
|
|
208
370
|
}
|
|
209
|
-
const selectedThinkingLabel = await ctx.ui.select(`Thinking for ${displayAgentName(agent.name)}`, [
|
|
210
|
-
...thinkingChoices.keys(),
|
|
211
|
-
]);
|
|
212
|
-
if (!selectedThinkingLabel)
|
|
213
|
-
continue;
|
|
214
|
-
await saveProfileResult(ctx, agent.name, override, {
|
|
215
|
-
model: selectedModelId,
|
|
216
|
-
thinking: thinkingChoices.get(selectedThinkingLabel),
|
|
217
|
-
});
|
|
218
371
|
}
|
|
219
372
|
}
|
|
220
373
|
export async function showAgentsCommand(ctx, currentThinking) {
|
|
@@ -222,9 +375,11 @@ export async function showAgentsCommand(ctx, currentThinking) {
|
|
|
222
375
|
ctx.ui.notify("/agents requires an interactive UI.", "warning");
|
|
223
376
|
return;
|
|
224
377
|
}
|
|
225
|
-
|
|
226
|
-
await
|
|
227
|
-
|
|
228
|
-
|
|
378
|
+
while (true) {
|
|
379
|
+
const profile = await selectProfile(ctx);
|
|
380
|
+
if (!profile)
|
|
381
|
+
return;
|
|
382
|
+
await runProfileSettings(ctx, profile, currentThinking);
|
|
383
|
+
}
|
|
229
384
|
}
|
|
230
385
|
//# sourceMappingURL=agents-command.js.map
|