@oh-my-pi/pi-coding-agent 17.0.0 → 17.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +128 -0
- package/dist/cli.js +4006 -3966
- package/dist/types/advisor/advise-tool.d.ts +5 -2
- package/dist/types/advisor/config.d.ts +14 -6
- package/dist/types/advisor/runtime.d.ts +20 -11
- package/dist/types/autolearn/controller.d.ts +1 -0
- package/dist/types/cli-commands.d.ts +14 -1
- package/dist/types/config/model-discovery.d.ts +17 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/model-resolver.d.ts +6 -2
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/models-config.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +32 -7
- package/dist/types/config/settings.d.ts +50 -0
- package/dist/types/cursor.d.ts +11 -0
- package/dist/types/discovery/helpers.d.ts +5 -2
- package/dist/types/discovery/substitute-plugin-root.d.ts +20 -7
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/extensibility/extensions/managed-timers.d.ts +15 -0
- package/dist/types/extensibility/extensions/runner.d.ts +7 -0
- package/dist/types/extensibility/extensions/types.d.ts +18 -0
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +40 -0
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/extensibility/utils.d.ts +2 -2
- package/dist/types/internal-urls/agent-protocol.d.ts +1 -0
- package/dist/types/lib/xai-http.d.ts +11 -0
- package/dist/types/mcp/transports/stdio.d.ts +13 -1
- package/dist/types/modes/acp/acp-agent.d.ts +3 -0
- package/dist/types/modes/acp/acp-mode.d.ts +6 -2
- package/dist/types/modes/components/advisor-config.d.ts +8 -1
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/custom-editor-plugin-ctor.test.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +23 -1
- package/dist/types/modes/components/hook-editor.d.ts +16 -2
- package/dist/types/modes/components/login-dialog.test.d.ts +1 -0
- package/dist/types/modes/components/model-hub.d.ts +5 -2
- package/dist/types/modes/components/session-selector.d.ts +4 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -1
- package/dist/types/modes/components/tool-execution.test.d.ts +1 -0
- package/dist/types/modes/controllers/command-controller.d.ts +8 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
- package/dist/types/modes/interactive-mode.d.ts +6 -0
- package/dist/types/modes/noninteractive-dispose.test.d.ts +1 -0
- package/dist/types/modes/print-mode.d.ts +1 -1
- package/dist/types/modes/types.d.ts +10 -0
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +2 -2
- package/dist/types/modes/warp-events.d.ts +24 -0
- package/dist/types/modes/warp-events.test.d.ts +1 -0
- package/dist/types/plan-mode/model-transition.d.ts +47 -0
- package/dist/types/plan-mode/model-transition.test.d.ts +1 -0
- package/dist/types/registry/agent-lifecycle.d.ts +26 -1
- package/dist/types/sdk.d.ts +13 -2
- package/dist/types/session/agent-session.d.ts +43 -11
- package/dist/types/session/session-history-format.d.ts +10 -0
- package/dist/types/session/session-manager.d.ts +14 -0
- package/dist/types/session/streaming-output.d.ts +2 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +9 -0
- package/dist/types/slash-commands/types.d.ts +4 -4
- package/dist/types/system-prompt.d.ts +1 -1
- package/dist/types/task/label.d.ts +1 -1
- package/dist/types/telemetry-export.d.ts +34 -9
- package/dist/types/tools/approval.d.ts +8 -0
- package/dist/types/tools/bash.d.ts +2 -0
- package/dist/types/tools/browser/registry.d.ts +7 -3
- package/dist/types/tools/browser/tab-supervisor.d.ts +2 -0
- package/dist/types/tools/essential-tools.d.ts +29 -0
- package/dist/types/tools/image-gen.d.ts +2 -1
- package/dist/types/tools/index.d.ts +4 -1
- package/dist/types/tools/manage-skill.d.ts +2 -0
- package/dist/types/tools/xdev.d.ts +11 -2
- package/dist/types/utils/title-generator.d.ts +2 -1
- package/dist/types/web/search/index.d.ts +2 -0
- package/dist/types/web/search/providers/base.d.ts +3 -0
- package/dist/types/web/search/providers/kimi.d.ts +4 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +21 -16
- package/src/advisor/__tests__/advisor.test.ts +1358 -86
- package/src/advisor/__tests__/config.test.ts +58 -2
- package/src/advisor/advise-tool.ts +7 -3
- package/src/advisor/config.ts +76 -24
- package/src/advisor/runtime.ts +445 -92
- package/src/autolearn/controller.ts +23 -28
- package/src/cli/bench-cli.ts +4 -1
- package/src/cli/grep-cli.ts +2 -1
- package/src/cli-commands.ts +57 -23
- package/src/cli.ts +5 -1
- package/src/config/model-discovery.ts +81 -21
- package/src/config/model-registry.ts +34 -6
- package/src/config/model-resolver.ts +57 -12
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +43 -6
- package/src/config/settings.ts +405 -25
- package/src/cursor.ts +20 -3
- package/src/debug/report-bundle.ts +40 -4
- package/src/discovery/codex.ts +14 -4
- package/src/discovery/helpers.ts +28 -5
- package/src/discovery/substitute-plugin-root.ts +23 -7
- package/src/exec/bash-executor.ts +14 -5
- package/src/export/html/template.js +2 -0
- package/src/extensibility/custom-tools/loader.ts +3 -3
- package/src/extensibility/custom-tools/wrapper.ts +2 -1
- package/src/extensibility/extensions/loader.ts +3 -3
- package/src/extensibility/extensions/managed-timers.ts +83 -0
- package/src/extensibility/extensions/runner.ts +26 -0
- package/src/extensibility/extensions/types.ts +18 -0
- package/src/extensibility/extensions/wrapper.ts +2 -1
- package/src/extensibility/hooks/loader.ts +3 -3
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +96 -1
- package/src/extensibility/plugins/legacy-pi-compat.ts +225 -22
- package/src/extensibility/plugins/manager.ts +2 -2
- package/src/extensibility/shared-events.ts +6 -0
- package/src/extensibility/utils.ts +91 -25
- package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +73 -0
- package/src/internal-urls/agent-protocol.ts +73 -39
- package/src/irc/bus.ts +22 -3
- package/src/launch/broker.ts +3 -2
- package/src/launch/client.ts +2 -2
- package/src/launch/presence.ts +2 -2
- package/src/lib/xai-http.ts +28 -2
- package/src/lsp/client.ts +1 -1
- package/src/main.ts +11 -8
- package/src/mcp/manager.ts +9 -3
- package/src/mcp/transports/stdio.ts +103 -23
- package/src/modes/acp/acp-agent.ts +28 -9
- package/src/modes/acp/acp-event-mapper.ts +8 -0
- package/src/modes/acp/acp-mode.ts +18 -4
- package/src/modes/components/advisor-config.ts +65 -3
- package/src/modes/components/ask-dialog.ts +1 -1
- package/src/modes/components/assistant-message.ts +35 -14
- package/src/modes/components/chat-transcript-builder.ts +2 -0
- package/src/modes/components/custom-editor-plugin-ctor.test.ts +36 -0
- package/src/modes/components/custom-editor.ts +62 -1
- package/src/modes/components/hook-editor.ts +35 -5
- package/src/modes/components/login-dialog.test.ts +56 -0
- package/src/modes/components/login-dialog.ts +7 -3
- package/src/modes/components/model-hub.ts +138 -42
- package/src/modes/components/plan-review-overlay.ts +51 -10
- package/src/modes/components/session-selector.ts +10 -0
- package/src/modes/components/status-line/component.test.ts +1 -0
- package/src/modes/components/status-line/component.ts +2 -4
- package/src/modes/components/status-line/segments.ts +21 -6
- package/src/modes/components/tool-execution.test.ts +101 -0
- package/src/modes/components/tool-execution.ts +117 -9
- package/src/modes/components/transcript-container.ts +30 -2
- package/src/modes/controllers/command-controller-shared.ts +1 -1
- package/src/modes/controllers/command-controller.ts +168 -48
- package/src/modes/controllers/event-controller.ts +6 -0
- package/src/modes/controllers/extension-ui-controller.ts +4 -22
- package/src/modes/controllers/input-controller.ts +12 -12
- package/src/modes/controllers/selector-controller.ts +208 -46
- package/src/modes/interactive-mode.ts +205 -65
- package/src/modes/noninteractive-dispose.test.ts +60 -0
- package/src/modes/print-mode.ts +10 -5
- package/src/modes/rpc/host-tools.ts +2 -1
- package/src/modes/rpc/rpc-mode.ts +31 -7
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/types.ts +10 -0
- package/src/modes/utils/interactive-context-helpers.ts +3 -1
- package/src/modes/utils/transcript-render-helpers.ts +3 -2
- package/src/modes/warp-events.test.ts +794 -0
- package/src/modes/warp-events.ts +232 -0
- package/src/plan-mode/model-transition.test.ts +60 -0
- package/src/plan-mode/model-transition.ts +51 -0
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/registry/agent-lifecycle.ts +133 -18
- package/src/sdk.ts +227 -44
- package/src/session/agent-session.ts +1364 -382
- package/src/session/session-history-format.ts +20 -5
- package/src/session/session-listing.ts +6 -5
- package/src/session/session-loader.ts +9 -0
- package/src/session/session-manager.ts +48 -0
- package/src/session/session-persistence.ts +11 -0
- package/src/session/streaming-output.ts +3 -1
- package/src/slash-commands/builtin-registry.ts +9 -0
- package/src/slash-commands/helpers/active-oauth-account.ts +16 -0
- package/src/slash-commands/types.ts +4 -4
- package/src/system-prompt.ts +2 -2
- package/src/task/executor.ts +1 -1
- package/src/task/label.ts +2 -0
- package/src/telemetry-export.ts +453 -97
- package/src/tools/approval.ts +11 -0
- package/src/tools/bash.ts +71 -38
- package/src/tools/browser/registry.ts +9 -2
- package/src/tools/browser/tab-supervisor.ts +65 -10
- package/src/tools/browser.ts +4 -3
- package/src/tools/essential-tools.ts +45 -0
- package/src/tools/eval.ts +3 -0
- package/src/tools/gh.ts +169 -2
- package/src/tools/image-gen.ts +624 -513
- package/src/tools/index.ts +10 -6
- package/src/tools/manage-skill.ts +5 -3
- package/src/tools/output-meta.ts +7 -0
- package/src/tools/path-utils.ts +8 -5
- package/src/tools/read.ts +48 -3
- package/src/tools/write.ts +22 -4
- package/src/tools/xdev.ts +14 -3
- package/src/utils/title-generator.ts +15 -4
- package/src/web/search/index.ts +21 -6
- package/src/web/search/providers/base.ts +3 -0
- package/src/web/search/providers/kimi.ts +18 -12
- package/src/web/search/providers/xai.ts +40 -9
- package/src/web/search/types.ts +6 -1
|
@@ -13,7 +13,11 @@ import {
|
|
|
13
13
|
saveWatchdogConfigFile,
|
|
14
14
|
} from "../../advisor";
|
|
15
15
|
import { reset as resetCapabilities } from "../../capability";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
formatModelSelectorValue,
|
|
18
|
+
resolveAdvisorRoleSelection,
|
|
19
|
+
resolveModelRoleValue,
|
|
20
|
+
} from "../../config/model-resolver";
|
|
17
21
|
import { getRoleInfo } from "../../config/model-roles";
|
|
18
22
|
import { settings } from "../../config/settings";
|
|
19
23
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
@@ -46,7 +50,12 @@ import {
|
|
|
46
50
|
type ResetUsageAccount,
|
|
47
51
|
toResetUsageAccounts,
|
|
48
52
|
} from "../../slash-commands/helpers/reset-usage";
|
|
49
|
-
import {
|
|
53
|
+
import {
|
|
54
|
+
AUTO_THINKING,
|
|
55
|
+
type ConfiguredThinkingLevel,
|
|
56
|
+
concreteThinkingLevel,
|
|
57
|
+
parseConfiguredThinkingLevel,
|
|
58
|
+
} from "../../thinking";
|
|
50
59
|
import {
|
|
51
60
|
isImageProviderPreference,
|
|
52
61
|
isSearchProviderId,
|
|
@@ -68,7 +77,7 @@ import { ExtensionDashboard } from "../components/extensions";
|
|
|
68
77
|
import { HistorySearchComponent } from "../components/history-search";
|
|
69
78
|
import { LoginDialogComponent } from "../components/login-dialog";
|
|
70
79
|
import { LogoutAccountSelectorComponent } from "../components/logout-account-selector";
|
|
71
|
-
import { ModelHubComponent } from "../components/model-hub";
|
|
80
|
+
import { ModelHubComponent, type ModelRoleSelectionScope } from "../components/model-hub";
|
|
72
81
|
import { ModelPickerComponent } from "../components/model-picker";
|
|
73
82
|
import { OAuthSelectorComponent } from "../components/oauth-selector";
|
|
74
83
|
import { PluginSelectorComponent } from "../components/plugin-selector";
|
|
@@ -83,10 +92,19 @@ import { UserMessageSelectorComponent } from "../components/user-message-selecto
|
|
|
83
92
|
import type { SessionObserverRegistry } from "../session-observer-registry";
|
|
84
93
|
import { buildCopyTargets } from "../utils/copy-targets";
|
|
85
94
|
|
|
86
|
-
const
|
|
95
|
+
const MANUAL_LOGIN_PROMPT = "Paste the authorization code (or full redirect URL), then press Enter:";
|
|
87
96
|
|
|
88
97
|
export class SelectorController {
|
|
89
98
|
constructor(private ctx: InteractiveModeContext) {}
|
|
99
|
+
#defaultRoleMutationTail = Promise.resolve();
|
|
100
|
+
|
|
101
|
+
async #acquireDefaultRoleMutation(): Promise<() => void> {
|
|
102
|
+
const previous = this.#defaultRoleMutationTail;
|
|
103
|
+
const { promise, resolve } = Promise.withResolvers<void>();
|
|
104
|
+
this.#defaultRoleMutationTail = previous.then(() => promise);
|
|
105
|
+
await previous;
|
|
106
|
+
return resolve;
|
|
107
|
+
}
|
|
90
108
|
|
|
91
109
|
async #refreshOAuthProviderAuthState(): Promise<void> {
|
|
92
110
|
const oauthProviders = getOAuthProviders();
|
|
@@ -188,6 +206,7 @@ export class SelectorController {
|
|
|
188
206
|
onPluginsChanged: async () => {
|
|
189
207
|
const projectPath = await resolveActiveProjectRegistryPath(this.ctx.sessionManager.getCwd());
|
|
190
208
|
clearPluginRootsAndCaches(projectPath ? [projectPath] : undefined);
|
|
209
|
+
await this.ctx.refreshSkillState();
|
|
191
210
|
await this.ctx.refreshSlashCommandState();
|
|
192
211
|
resetCapabilities();
|
|
193
212
|
this.ctx.ui.requestRender();
|
|
@@ -279,6 +298,13 @@ export class SelectorController {
|
|
|
279
298
|
close: done,
|
|
280
299
|
requestRender: () => this.ctx.ui.requestRender(),
|
|
281
300
|
notify: message => this.ctx.showStatus(message),
|
|
301
|
+
getAdvisorStats: () => this.ctx.session.getAdvisorStats().advisors,
|
|
302
|
+
getUsageReports: async () => this.ctx.session.fetchUsageReports?.() ?? null,
|
|
303
|
+
resolveActiveAccount: (provider, sessionId) =>
|
|
304
|
+
this.ctx.session.modelRegistry.authStorage.getOAuthAccountIdentity(
|
|
305
|
+
provider,
|
|
306
|
+
sessionId ?? this.ctx.session.sessionId,
|
|
307
|
+
),
|
|
282
308
|
});
|
|
283
309
|
overlayHandle = this.ctx.ui.showOverlay(overlay, {
|
|
284
310
|
anchor: "bottom-center",
|
|
@@ -709,55 +735,173 @@ export class SelectorController {
|
|
|
709
735
|
this.ctx.session.modelRegistry,
|
|
710
736
|
this.ctx.session.scopedModels,
|
|
711
737
|
{
|
|
712
|
-
onAssign: async (model, role, thinkingLevel, selector) => {
|
|
738
|
+
onAssign: async (model, role, thinkingLevel, selector, scope?: ModelRoleSelectionScope) => {
|
|
739
|
+
const releaseDefaultMutation = role === "default" ? await this.#acquireDefaultRoleMutation() : undefined;
|
|
740
|
+
const configuredStorage = this.ctx.settings.get("modelRoleStorage");
|
|
741
|
+
const targetScope = configuredStorage === "project" ? (scope ?? "project") : "global";
|
|
713
742
|
// `auto` is session-global: never baked into a per-role model value
|
|
714
743
|
// (it can't round-trip through `model:<level>`). Apply it to the session
|
|
715
744
|
// separately and persist via `defaultThinkingLevel`.
|
|
716
745
|
const isAuto = thinkingLevel === AUTO_THINKING;
|
|
717
746
|
const concreteThinking = isAuto || thinkingLevel === undefined ? undefined : thinkingLevel;
|
|
718
747
|
const selectorValue = selector ?? `${model.provider}/${model.id}`;
|
|
748
|
+
const scopeLabel =
|
|
749
|
+
configuredStorage === "project" ? `${targetScope === "project" ? "Project" : "Global"} ` : "";
|
|
750
|
+
const defaultStatusLabel = configuredStorage === "project" ? `${scopeLabel}default` : "Default";
|
|
719
751
|
try {
|
|
720
752
|
if (role === "default") {
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
753
|
+
const effectiveProvenance = this.ctx.settings.getModelRoleProvenance("default");
|
|
754
|
+
const shadowedGlobal =
|
|
755
|
+
configuredStorage === "project" &&
|
|
756
|
+
targetScope === "global" &&
|
|
757
|
+
(effectiveProvenance === "project" ||
|
|
758
|
+
effectiveProvenance === "overlay" ||
|
|
759
|
+
(effectiveProvenance === "runtime" &&
|
|
760
|
+
this.ctx.settings.isProjectModelRoleRuntimeOverrideActive("default")));
|
|
761
|
+
const shadowedProject =
|
|
762
|
+
configuredStorage === "project" &&
|
|
763
|
+
targetScope === "project" &&
|
|
764
|
+
effectiveProvenance === "overlay";
|
|
765
|
+
if (shadowedGlobal) {
|
|
766
|
+
this.ctx.settings.setModelRole(
|
|
767
|
+
"default",
|
|
768
|
+
formatModelSelectorValue(selectorValue, concreteThinking),
|
|
769
|
+
);
|
|
770
|
+
if (isAuto) {
|
|
731
771
|
this.ctx.settings.set("defaultThinkingLevel", AUTO_THINKING);
|
|
732
772
|
}
|
|
733
|
-
} else if (
|
|
734
|
-
this.ctx.
|
|
735
|
-
|
|
736
|
-
|
|
773
|
+
} else if (shadowedProject) {
|
|
774
|
+
this.ctx.settings.setProjectModelRole(
|
|
775
|
+
"default",
|
|
776
|
+
formatModelSelectorValue(selectorValue, concreteThinking),
|
|
777
|
+
);
|
|
778
|
+
if (isAuto) {
|
|
779
|
+
this.ctx.settings.set("defaultThinkingLevel", AUTO_THINKING);
|
|
780
|
+
}
|
|
781
|
+
} else {
|
|
782
|
+
const { switched } = await this.ctx.session.setModel(model, role, {
|
|
783
|
+
selector,
|
|
784
|
+
thinkingLevel: isAuto ? ThinkingLevel.Inherit : concreteThinking,
|
|
785
|
+
persist: targetScope === "global",
|
|
786
|
+
currentContextTokens,
|
|
787
|
+
});
|
|
788
|
+
if (!switched) return;
|
|
789
|
+
if (targetScope === "project") {
|
|
790
|
+
this.ctx.settings.setProjectModelRole(
|
|
791
|
+
"default",
|
|
792
|
+
formatModelSelectorValue(selectorValue, concreteThinking),
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
if (isAuto) {
|
|
796
|
+
this.ctx.session.setThinkingLevel(AUTO_THINKING, true);
|
|
797
|
+
} else if (concreteThinking && concreteThinking !== ThinkingLevel.Inherit) {
|
|
798
|
+
this.ctx.session.setThinkingLevel(concreteThinking);
|
|
799
|
+
}
|
|
737
800
|
this.ctx.statusLine.invalidate();
|
|
738
801
|
this.ctx.updateEditorBorderColor();
|
|
739
802
|
}
|
|
740
|
-
this.ctx.showStatus(
|
|
803
|
+
this.ctx.showStatus(`${defaultStatusLabel} model: ${selector ?? model.id}`);
|
|
741
804
|
} else {
|
|
742
805
|
// Other roles (smol, slow, custom): update settings, not the current model.
|
|
743
|
-
|
|
806
|
+
const modelRoleValue = formatModelSelectorValue(selectorValue, concreteThinking);
|
|
807
|
+
if (targetScope === "project") {
|
|
808
|
+
this.ctx.settings.setProjectModelRole(role, modelRoleValue);
|
|
809
|
+
} else {
|
|
810
|
+
this.ctx.settings.setModelRole(role, modelRoleValue);
|
|
811
|
+
}
|
|
744
812
|
if (isAuto) {
|
|
745
813
|
this.ctx.session.setThinkingLevel(AUTO_THINKING, true);
|
|
746
814
|
}
|
|
747
815
|
const roleInfo = getRoleInfo(role, settings);
|
|
748
|
-
this.ctx.showStatus(
|
|
816
|
+
this.ctx.showStatus(
|
|
817
|
+
`${scopeLabel}${roleInfo?.tag ?? roleInfo?.name ?? role} model: ${selector ?? model.id}`,
|
|
818
|
+
);
|
|
749
819
|
}
|
|
750
820
|
} catch (error) {
|
|
751
821
|
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
822
|
+
} finally {
|
|
823
|
+
releaseDefaultMutation?.();
|
|
824
|
+
hub?.refreshAfterExternalMutation();
|
|
752
825
|
}
|
|
753
826
|
},
|
|
754
|
-
onUnassign: role => {
|
|
827
|
+
onUnassign: async (role, scope?: ModelRoleSelectionScope) => {
|
|
828
|
+
const releaseDefaultMutation = role === "default" ? await this.#acquireDefaultRoleMutation() : undefined;
|
|
829
|
+
const configuredStorage = this.ctx.settings.get("modelRoleStorage");
|
|
830
|
+
const targetScope = configuredStorage === "project" ? (scope ?? "project") : "global";
|
|
831
|
+
const scopeLabel =
|
|
832
|
+
configuredStorage === "project" ? `${targetScope === "project" ? "Project" : "Global"} ` : "";
|
|
755
833
|
try {
|
|
756
|
-
|
|
834
|
+
const previousEffectiveRoleValue =
|
|
835
|
+
role === "default" ? this.ctx.settings.getModelRole("default") : undefined;
|
|
836
|
+
if (targetScope === "project") {
|
|
837
|
+
this.ctx.settings.clearProjectModelRole(role);
|
|
838
|
+
} else {
|
|
839
|
+
this.ctx.settings.setModelRole(role, undefined);
|
|
840
|
+
}
|
|
757
841
|
const roleInfo = getRoleInfo(role, settings);
|
|
758
|
-
this.ctx.showStatus(
|
|
842
|
+
this.ctx.showStatus(
|
|
843
|
+
`${scopeLabel}${roleInfo?.tag ?? roleInfo?.name ?? role} role cleared — auto-selection applies`,
|
|
844
|
+
);
|
|
845
|
+
// Clearing either persisted scope can also remove a captured
|
|
846
|
+
// runtime override. When that changes the effective default,
|
|
847
|
+
// resolve the newly exposed persisted layer and switch the live
|
|
848
|
+
// session without writing it back to global settings. Overlay
|
|
849
|
+
// and runtime provenance remain authoritative and session-neutral.
|
|
850
|
+
if (role === "default") {
|
|
851
|
+
const fallbackRoleValue = this.ctx.settings.getModelRole("default");
|
|
852
|
+
const fallbackProvenance = this.ctx.settings.getModelRoleProvenance("default");
|
|
853
|
+
const exposesPersistedFallback =
|
|
854
|
+
fallbackProvenance === "project" || fallbackProvenance === "global";
|
|
855
|
+
if (
|
|
856
|
+
fallbackRoleValue &&
|
|
857
|
+
fallbackRoleValue !== previousEffectiveRoleValue &&
|
|
858
|
+
exposesPersistedFallback
|
|
859
|
+
) {
|
|
860
|
+
const scopedModels = this.ctx.session.scopedModels.map(sm => sm.model);
|
|
861
|
+
const availableModels =
|
|
862
|
+
scopedModels.length > 0 ? scopedModels : this.ctx.session.getAvailableModels();
|
|
863
|
+
const resolved = resolveModelRoleValue(fallbackRoleValue, availableModels, {
|
|
864
|
+
settings: this.ctx.settings,
|
|
865
|
+
});
|
|
866
|
+
if (resolved.model) {
|
|
867
|
+
const fallbackModel = resolved.model;
|
|
868
|
+
const isAuto = resolved.thinkingLevel === AUTO_THINKING;
|
|
869
|
+
let concreteThinking = concreteThinkingLevel(resolved.thinkingLevel);
|
|
870
|
+
let isAutoFromDefault = false;
|
|
871
|
+
if (!resolved.explicitThinkingLevel && !concreteThinking) {
|
|
872
|
+
const defaultLevel = parseConfiguredThinkingLevel(
|
|
873
|
+
this.ctx.settings.get("defaultThinkingLevel"),
|
|
874
|
+
);
|
|
875
|
+
if (defaultLevel === AUTO_THINKING) {
|
|
876
|
+
isAutoFromDefault = true;
|
|
877
|
+
} else if (defaultLevel) {
|
|
878
|
+
concreteThinking = defaultLevel;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const effectiveIsAuto = isAuto || isAutoFromDefault;
|
|
882
|
+
const { switched } = await this.ctx.session.setModel(fallbackModel, "default", {
|
|
883
|
+
persist: false,
|
|
884
|
+
thinkingLevel: effectiveIsAuto
|
|
885
|
+
? ThinkingLevel.Inherit
|
|
886
|
+
: (concreteThinking ?? ThinkingLevel.Inherit),
|
|
887
|
+
currentContextTokens,
|
|
888
|
+
});
|
|
889
|
+
if (!switched) return;
|
|
890
|
+
if (effectiveIsAuto) {
|
|
891
|
+
this.ctx.session.setThinkingLevel(AUTO_THINKING, true);
|
|
892
|
+
} else if (concreteThinking && concreteThinking !== ThinkingLevel.Inherit) {
|
|
893
|
+
this.ctx.session.setThinkingLevel(concreteThinking);
|
|
894
|
+
}
|
|
895
|
+
this.ctx.statusLine.invalidate();
|
|
896
|
+
this.ctx.updateEditorBorderColor();
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
759
900
|
} catch (error) {
|
|
760
901
|
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
902
|
+
} finally {
|
|
903
|
+
releaseDefaultMutation?.();
|
|
904
|
+
hub?.refreshAfterExternalMutation();
|
|
761
905
|
}
|
|
762
906
|
},
|
|
763
907
|
onFallbackChainChange: (role, chain) => {
|
|
@@ -772,8 +916,8 @@ export class SelectorController {
|
|
|
772
916
|
const roleInfo = getRoleInfo(role, settings);
|
|
773
917
|
this.ctx.showStatus(
|
|
774
918
|
chain.length > 0
|
|
775
|
-
? `${roleInfo?.name ?? role} fallbacks: ${chain.join(" → ")}`
|
|
776
|
-
: `${roleInfo?.name ?? role} fallbacks cleared`,
|
|
919
|
+
? `${roleInfo?.tag ?? roleInfo?.name ?? role} fallbacks: ${chain.join(" → ")}`
|
|
920
|
+
: `${roleInfo?.tag ?? roleInfo?.name ?? role} fallbacks cleared`,
|
|
777
921
|
);
|
|
778
922
|
} catch (error) {
|
|
779
923
|
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
@@ -1109,12 +1253,10 @@ export class SelectorController {
|
|
|
1109
1253
|
// every project's history when the cwd has nothing to resume. See #3099.
|
|
1110
1254
|
const historyStorage = this.ctx.historyStorage;
|
|
1111
1255
|
const historyMatcher = historyStorage ? (query: string) => historyStorage.matchingSessionIds(query) : undefined;
|
|
1112
|
-
//
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1115
|
-
//
|
|
1116
|
-
// directly to a rendered line (the overlay paints from screen row 0), and
|
|
1117
|
-
// `fillHeight` pads the body so the footer pins to the screen bottom.
|
|
1256
|
+
// Keep the fullscreen picker on the alternate buffer while a selected
|
|
1257
|
+
// session is loaded and its transcript is rebuilt. Closing it first exposes
|
|
1258
|
+
// the stale normal buffer for the entire async switch on terminals without
|
|
1259
|
+
// effective synchronized output.
|
|
1118
1260
|
let overlayHandle: OverlayHandle | undefined;
|
|
1119
1261
|
const done = () => {
|
|
1120
1262
|
overlayHandle?.hide();
|
|
@@ -1124,8 +1266,18 @@ export class SelectorController {
|
|
|
1124
1266
|
const selector = new SessionSelectorComponent(
|
|
1125
1267
|
sessions,
|
|
1126
1268
|
async (session: SessionInfo) => {
|
|
1127
|
-
|
|
1128
|
-
|
|
1269
|
+
selector.lockInput();
|
|
1270
|
+
let keepOpen = false;
|
|
1271
|
+
try {
|
|
1272
|
+
const success = await this.handleResumeSession(session.path);
|
|
1273
|
+
if (!success) {
|
|
1274
|
+
keepOpen = true;
|
|
1275
|
+
selector.unlockInput();
|
|
1276
|
+
this.ctx.ui.requestRender();
|
|
1277
|
+
}
|
|
1278
|
+
} finally {
|
|
1279
|
+
if (!keepOpen) done();
|
|
1280
|
+
}
|
|
1129
1281
|
},
|
|
1130
1282
|
() => {
|
|
1131
1283
|
done();
|
|
@@ -1202,13 +1354,23 @@ export class SelectorController {
|
|
|
1202
1354
|
return true;
|
|
1203
1355
|
}
|
|
1204
1356
|
|
|
1205
|
-
async handleResumeSession(sessionPath: string): Promise<
|
|
1206
|
-
this.ctx.clearTransientSessionUi();
|
|
1207
|
-
|
|
1357
|
+
async handleResumeSession(sessionPath: string, options?: { settingsFlushed?: boolean }): Promise<boolean> {
|
|
1208
1358
|
const previousCwd = this.ctx.sessionManager.getCwd();
|
|
1359
|
+
// Flush pending settings writes before switching sessions so a save
|
|
1360
|
+
// failure leaves the session, process project dir, and Settings in the
|
|
1361
|
+
// source scope — the switch below mutates the SessionManager cwd.
|
|
1362
|
+
if (!options?.settingsFlushed) {
|
|
1363
|
+
try {
|
|
1364
|
+
await this.ctx.settings.flush();
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
this.ctx.showError(`Failed to save pending settings: ${err instanceof Error ? err.message : String(err)}`);
|
|
1367
|
+
return false;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1209
1370
|
// Switch session via AgentSession (emits hook and tool session events). The
|
|
1210
1371
|
// SessionManager adopts the resumed session's own cwd when it differs.
|
|
1211
1372
|
await this.ctx.session.switchSession(sessionPath);
|
|
1373
|
+
this.ctx.clearTransientSessionUi();
|
|
1212
1374
|
const newCwd = this.ctx.sessionManager.getCwd();
|
|
1213
1375
|
const movedProject = normalizePathForComparison(newCwd) !== normalizePathForComparison(previousCwd);
|
|
1214
1376
|
if (movedProject) {
|
|
@@ -1223,6 +1385,7 @@ export class SelectorController {
|
|
|
1223
1385
|
this.ctx.renderInitialMessages({ clearTerminalHistory: true });
|
|
1224
1386
|
await this.ctx.reloadTodos();
|
|
1225
1387
|
this.ctx.showStatus(movedProject ? `Resumed session in ${shortenPath(newCwd)}` : "Resumed session");
|
|
1388
|
+
return true;
|
|
1226
1389
|
}
|
|
1227
1390
|
|
|
1228
1391
|
async handleSessionDeleteCommand(): Promise<void> {
|
|
@@ -1272,7 +1435,6 @@ export class SelectorController {
|
|
|
1272
1435
|
*/
|
|
1273
1436
|
async #handleOAuthLogin(providerId: string): Promise<boolean> {
|
|
1274
1437
|
this.ctx.showStatus(`Logging in to ${providerId}…`);
|
|
1275
|
-
const manualInput = this.ctx.oauthManualInput;
|
|
1276
1438
|
const useManualInput = PASTE_CODE_LOGIN_PROVIDERS.has(providerId);
|
|
1277
1439
|
let restored = false;
|
|
1278
1440
|
const restoreEditor = () => {
|
|
@@ -1300,16 +1462,19 @@ export class SelectorController {
|
|
|
1300
1462
|
// The dialog renders the full URL (SSH-safe copy target) and
|
|
1301
1463
|
// opens the browser best-effort.
|
|
1302
1464
|
dialog.showAuth(info.url, info.instructions, info.launchUrl);
|
|
1303
|
-
if (useManualInput) {
|
|
1304
|
-
dialog.showProgress(MANUAL_LOGIN_TIP);
|
|
1305
|
-
}
|
|
1306
1465
|
},
|
|
1307
1466
|
onPrompt: (prompt: { message: string; placeholder?: string }) =>
|
|
1308
1467
|
dialog.showPrompt(prompt.message, prompt.placeholder),
|
|
1309
1468
|
onProgress: (message: string) => {
|
|
1310
1469
|
dialog.showProgress(message);
|
|
1311
1470
|
},
|
|
1312
|
-
|
|
1471
|
+
// Paste-code providers (e.g. Codex) may need the user to paste the
|
|
1472
|
+
// fallback redirect URL when the loopback callback can't complete
|
|
1473
|
+
// (headless/remote/Windows). Mount a focused input in the dialog so
|
|
1474
|
+
// the paste lands somewhere the OAuth flow consumes — the hidden
|
|
1475
|
+
// editor's `/login <url>` path is unreachable while the dialog holds
|
|
1476
|
+
// focus (#5339).
|
|
1477
|
+
onManualCodeInput: useManualInput ? () => dialog.showManualInput(MANUAL_LOGIN_PROMPT) : undefined,
|
|
1313
1478
|
});
|
|
1314
1479
|
this.ctx.session.modelRegistry.refreshInBackground();
|
|
1315
1480
|
const block = new TranscriptBlock();
|
|
@@ -1338,9 +1503,6 @@ export class SelectorController {
|
|
|
1338
1503
|
this.ctx.showError(`Login failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1339
1504
|
return false;
|
|
1340
1505
|
} finally {
|
|
1341
|
-
if (useManualInput) {
|
|
1342
|
-
manualInput.clear(`Manual OAuth input cleared for ${providerId}`);
|
|
1343
|
-
}
|
|
1344
1506
|
restoreEditor();
|
|
1345
1507
|
}
|
|
1346
1508
|
}
|