Archived
feat(ui): add model and thinking selector actions
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@jmfederico/pi-web": patch
|
||||
---
|
||||
|
||||
Add action-palette commands for selecting a session's model and thinking level, with support for assigning custom shortcuts in Settings.
|
||||
@@ -1791,6 +1791,8 @@ export class PiWebApp extends LitElement {
|
||||
configureAuth: () => this.auth.openLogin(),
|
||||
logoutAuth: () => this.auth.openLogout(),
|
||||
openThemePicker: () => { this.openThemeDialog(); },
|
||||
openModelPicker: () => this.openModelDialog(),
|
||||
openThinkingLevelPicker: () => this.openThinkingDialog(),
|
||||
selectMainView: (view) => { this.selectMainView(view); },
|
||||
selectWorkspaceTool: (tool) => { this.openWorkspaceTool(tool); },
|
||||
openTerminal: (options) => { this.openTerminal(options); },
|
||||
|
||||
@@ -167,6 +167,22 @@ export function createCoreActions(): PluginAction[] {
|
||||
enabled: hasWorkspace,
|
||||
run: (context) => context.startSession(),
|
||||
},
|
||||
{
|
||||
id: "model.select",
|
||||
title: "Select Model",
|
||||
description: "Choose the model for the selected session",
|
||||
group: "Session",
|
||||
enabled: hasSelectableSession,
|
||||
run: (context) => context.openModelPicker(),
|
||||
},
|
||||
{
|
||||
id: "thinking.select",
|
||||
title: "Select Thinking Level",
|
||||
description: "Choose the thinking level for the selected session",
|
||||
group: "Session",
|
||||
enabled: hasSelectableSession,
|
||||
run: (context) => context.openThinkingLevelPicker(),
|
||||
},
|
||||
{
|
||||
id: "session.archive",
|
||||
title: "Archive Session",
|
||||
@@ -216,6 +232,11 @@ function hasDeletableWorkspace(context: { state: AppState }): boolean {
|
||||
return workspace !== undefined && workspace.isGitWorktree && !workspace.isMain && !isWorkspaceDeletionPending(context.state, workspace);
|
||||
}
|
||||
|
||||
function hasSelectableSession(context: { state: AppState }): boolean {
|
||||
const session = context.state.selectedSession;
|
||||
return session !== undefined && session.archived !== true;
|
||||
}
|
||||
|
||||
function hasArchivableSession(context: { state: AppState }): boolean {
|
||||
return isArchivableSessionInfo(context.state.selectedSession, context.state.status, sessionPersistenceOptions(context.state));
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ function createContext(statePatch: Partial<AppState> = {}) {
|
||||
configureAuth: vi.fn(() => { calls.push("configureAuth"); }),
|
||||
logoutAuth: vi.fn(() => { calls.push("logoutAuth"); }),
|
||||
openThemePicker: vi.fn(() => { calls.push("openThemePicker"); }),
|
||||
openModelPicker: vi.fn(() => { calls.push("openModelPicker"); }),
|
||||
openThinkingLevelPicker: vi.fn(() => { calls.push("openThinkingLevelPicker"); }),
|
||||
selectMainView: vi.fn((view: AppState["mainView"]) => { calls.push(`selectMainView:${view}`); }),
|
||||
selectWorkspaceTool: vi.fn((tool: AppState["workspaceTool"]) => { calls.push(`selectWorkspaceTool:${tool}`); }),
|
||||
openTerminal: vi.fn((options?: { terminalId?: string | undefined }) => { calls.push(`openTerminal:${options?.terminalId ?? ""}`); }),
|
||||
@@ -290,6 +292,34 @@ describe("PluginRegistry", () => {
|
||||
expect(calls).toEqual(["deleteCachedNewSession"]);
|
||||
});
|
||||
|
||||
it("exposes model and thinking selectors as configurable actions for writable sessions", () => {
|
||||
const registry = new PluginRegistry();
|
||||
registry.register({ id: "core", plugin: corePlugin });
|
||||
|
||||
const unavailable = registry.getActions(createContext().context);
|
||||
expect(unavailable.find((action) => action.id === "core:model.select")?.enabled).toBe(false);
|
||||
expect(unavailable.find((action) => action.id === "core:thinking.select")?.enabled).toBe(false);
|
||||
|
||||
const archivedSession = { ...testSession(), archived: true, archivedAt: "2026-05-20T00:00:00.000Z" };
|
||||
const archived = registry.getActions(createContext({ selectedSession: archivedSession }).context);
|
||||
expect(archived.find((action) => action.id === "core:model.select")?.enabled).toBe(false);
|
||||
expect(archived.find((action) => action.id === "core:thinking.select")?.enabled).toBe(false);
|
||||
|
||||
const { context, calls } = createContext({ selectedSession: testSession() });
|
||||
const actions = registry.getActions(context);
|
||||
const modelAction = actions.find((action) => action.id === "core:model.select");
|
||||
const thinkingAction = actions.find((action) => action.id === "core:thinking.select");
|
||||
expect(modelAction).toMatchObject({ title: "Select Model", enabled: true });
|
||||
expect(modelAction?.shortcut).toBeUndefined();
|
||||
expect(thinkingAction).toMatchObject({ title: "Select Thinking Level", enabled: true });
|
||||
expect(thinkingAction?.shortcut).toBeUndefined();
|
||||
|
||||
if (modelAction !== undefined) void modelAction.run();
|
||||
if (thinkingAction !== undefined) void thinkingAction.run();
|
||||
|
||||
expect(calls).toEqual(["openModelPicker", "openThinkingLevelPicker"]);
|
||||
});
|
||||
|
||||
it("routes refresh current to the active core workspace panel", () => {
|
||||
const registry = new PluginRegistry();
|
||||
registry.register({ id: "core", plugin: corePlugin });
|
||||
|
||||
@@ -106,6 +106,8 @@ export interface PluginRuntimeContext {
|
||||
configureAuth: () => void | Promise<void>;
|
||||
logoutAuth: () => void | Promise<void>;
|
||||
openThemePicker: () => void;
|
||||
openModelPicker: () => void | Promise<void>;
|
||||
openThinkingLevelPicker: () => void | Promise<void>;
|
||||
selectMainView: (view: AppState["mainView"]) => void;
|
||||
selectWorkspaceTool: (tool: QualifiedContributionId) => void;
|
||||
openTerminal: (options?: { terminalId?: string | undefined }) => void;
|
||||
|
||||
Reference in New Issue
Block a user