Archived
feat(settings): add Ask Questions toggle
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { PiWebConfigResponse } from "../../api";
|
||||
import { SettingsSessiondPanel } from "./SettingsSessiondPanel";
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.replaceChildren();
|
||||
});
|
||||
|
||||
describe("SettingsSessiondPanel Ask Questions setting", () => {
|
||||
it("lets the user disable ask_user with a daemon config patch", async () => {
|
||||
const panel = new SettingsSessiondPanel();
|
||||
const onSave = vi.fn();
|
||||
panel.configResponse = configResponse(true);
|
||||
panel.onSave = onSave;
|
||||
document.body.append(panel);
|
||||
await panel.updateComplete;
|
||||
|
||||
const toggle = askUserToggle(panel);
|
||||
expect(toggle.checked).toBe(true);
|
||||
expect(toggle.disabled).toBe(false);
|
||||
|
||||
toggle.click();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(onSave).toHaveBeenCalledWith({ askUser: false });
|
||||
});
|
||||
|
||||
it("keeps an environment-overridden setting read-only", async () => {
|
||||
const panel = new SettingsSessiondPanel();
|
||||
panel.configResponse = configResponse(true, true);
|
||||
document.body.append(panel);
|
||||
await panel.updateComplete;
|
||||
|
||||
const toggle = askUserToggle(panel);
|
||||
expect(toggle.checked).toBe(true);
|
||||
expect(toggle.disabled).toBe(true);
|
||||
});
|
||||
|
||||
it("does not offer an unsupported setting from an older selected machine", async () => {
|
||||
const panel = new SettingsSessiondPanel();
|
||||
panel.configResponse = configResponse(undefined);
|
||||
document.body.append(panel);
|
||||
await panel.updateComplete;
|
||||
|
||||
const toggle = askUserToggle(panel);
|
||||
expect(toggle.checked).toBe(false);
|
||||
expect(toggle.disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function askUserToggle(panel: SettingsSessiondPanel): HTMLInputElement {
|
||||
const toggle = panel.shadowRoot?.querySelector<HTMLInputElement>('input[aria-label="Enable Ask Questions"]');
|
||||
if (toggle === undefined || toggle === null) throw new Error("Ask Questions toggle was not rendered");
|
||||
return toggle;
|
||||
}
|
||||
|
||||
function configResponse(askUser: boolean | undefined, askUserOverride = false): PiWebConfigResponse {
|
||||
const askUserConfig = askUser === undefined ? {} : { askUser };
|
||||
return {
|
||||
path: "/tmp/pi-web/config.json",
|
||||
exists: true,
|
||||
config: askUserConfig,
|
||||
effectiveConfig: askUserConfig,
|
||||
envOverrides: {
|
||||
host: false,
|
||||
port: false,
|
||||
allowedHosts: false,
|
||||
spawnSessions: false,
|
||||
subsessions: false,
|
||||
askUser: askUserOverride,
|
||||
agentCommand: false,
|
||||
agentDir: false,
|
||||
agentSessionDir: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import "./SettingsPanelFrame";
|
||||
import type { SettingsNotice } from "./SettingsPanelFrame";
|
||||
import { agentProfileConfigPatchFromDraft, agentProfileDraftFromConfig, agentProfileDraftMatchesConfig, emptyAgentProfileConfigDraft, type AgentProfileConfigDraft } from "./settingsConfigDraft";
|
||||
import type { AgentProfileSettingsSupport } from "./settingsMachineTarget";
|
||||
import { agentDirFieldOverridden, agentProfileActivationState, spawnSessionsConfigPatch, subsessionsConfigPatch } from "./settingsSessiondConfig";
|
||||
import { agentDirFieldOverridden, agentProfileActivationState, askUserConfigPatch, spawnSessionsConfigPatch, subsessionsConfigPatch } from "./settingsSessiondConfig";
|
||||
|
||||
@customElement("settings-sessiond-panel")
|
||||
export class SettingsSessiondPanel extends LitElement {
|
||||
@@ -47,6 +47,11 @@ export class SettingsSessiondPanel extends LitElement {
|
||||
const subsessionsOverridden = config?.envOverrides.subsessions === true;
|
||||
// Beta, off by default; also requires spawn to be enabled.
|
||||
const effectiveSubsessions = config?.effectiveConfig.subsessions === true && effectiveSpawn;
|
||||
// Current servers always resolve this on-by-default setting. Absence means
|
||||
// an older selected machine cannot persist it yet.
|
||||
const askUserSupported = config?.effectiveConfig.askUser !== undefined;
|
||||
const askUserOverridden = config?.envOverrides.askUser === true;
|
||||
const effectiveAskUser = config?.effectiveConfig.askUser === true;
|
||||
const agentCommandOverridden = config?.envOverrides.agentCommand === true;
|
||||
const profileEditingSupported = this.agentProfileSupport.state === "supported";
|
||||
const draftCommand = agentCommandOverridden ? (config.effectiveConfig.agent?.command ?? this.agentDraft.command) : this.agentDraft.command;
|
||||
@@ -141,6 +146,25 @@ export class SettingsSessiondPanel extends LitElement {
|
||||
</label>
|
||||
<small>Beta: agents can start child sessions they stay attached to (<code>spawn_subsession</code>, <code>list_subsessions</code>, <code>check_subsession</code>, <code>read_subsession</code>) and are notified when a child finishes. Requires "Allow agents to start sessions". Off by default.</small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<span class="field-heading">
|
||||
<span>Allow agents to ask questions</span>
|
||||
${askUserOverridden ? html`<span class="override-badge">environment override</span>` : null}
|
||||
</span>
|
||||
<label class="toggle">
|
||||
<input
|
||||
type="checkbox"
|
||||
aria-label="Enable Ask Questions"
|
||||
.checked=${effectiveAskUser}
|
||||
?disabled=${this.loading || this.saving || askUserOverridden || !askUserSupported}
|
||||
@change=${(event: Event) => { void this.toggleAskUser(event); }}
|
||||
>
|
||||
<span>Enable the <code>ask_user</code> tool</span>
|
||||
</label>
|
||||
<small>${askUserSupported
|
||||
? html`Agents can post a structured question form and pause until the user responds. On by default.`
|
||||
: html`This machine does not expose the Ask Questions setting. Update and restart PI WEB on that machine to configure it.`}</small>
|
||||
</div>
|
||||
<section class="effective-card" aria-label="Desired and active session daemon configuration summary">
|
||||
<h3>Desired after environment overrides</h3>
|
||||
<dl>
|
||||
@@ -151,6 +175,7 @@ export class SettingsSessiondPanel extends LitElement {
|
||||
<div><dt>Profile status</dt><dd>${profileActivationLabel(profileActivation)}</dd></div>
|
||||
<div><dt>Spawn sessions</dt><dd>${effectiveSpawn ? "Enabled" : html`<span class="muted">Disabled</span>`}</dd></div>
|
||||
<div><dt>Subsessions</dt><dd>${effectiveSubsessions ? "Enabled" : html`<span class="muted">Disabled</span>`}</dd></div>
|
||||
<div><dt>Ask questions</dt><dd>${!askUserSupported ? html`<span class="muted">Unavailable</span>` : effectiveAskUser ? "Enabled" : html`<span class="muted">Disabled</span>`}</dd></div>
|
||||
</dl>
|
||||
</section>
|
||||
`}
|
||||
@@ -198,6 +223,11 @@ export class SettingsSessiondPanel extends LitElement {
|
||||
await this.onSave?.(subsessionsConfigPatch(enabled));
|
||||
}
|
||||
|
||||
private async toggleAskUser(event: Event): Promise<void> {
|
||||
const enabled = event.target instanceof HTMLInputElement && event.target.checked;
|
||||
await this.onSave?.(askUserConfigPatch(enabled));
|
||||
}
|
||||
|
||||
static override styles = css`
|
||||
:host { display: block; }
|
||||
h3 { margin: 0; font-size: 13px; line-height: 1.3; }
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { ActiveAgentProfileDescriptor, PiWebConfigResponse, PiWebConfigValues } from "../../api";
|
||||
import { agentDirFieldOverridden, agentProfileActivationState, mergeSelectedMachineSessiondConfig, spawnSessionsConfigPatch, subsessionsConfigPatch } from "./settingsSessiondConfig";
|
||||
import { agentDirFieldOverridden, agentProfileActivationState, askUserConfigPatch, mergeSelectedMachineSessiondConfig, spawnSessionsConfigPatch, subsessionsConfigPatch } from "./settingsSessiondConfig";
|
||||
|
||||
describe("session daemon settings config helpers", () => {
|
||||
it("builds daemon-only save patches for the sessiond toggles", () => {
|
||||
expect(spawnSessionsConfigPatch(false)).toEqual({ spawnSessions: false });
|
||||
expect(subsessionsConfigPatch(true)).toEqual({ subsessions: true });
|
||||
expect(askUserConfigPatch(false)).toEqual({ askUser: false });
|
||||
});
|
||||
|
||||
it("compares the desired effective profile with the daemon-owned active profile", () => {
|
||||
|
||||
@@ -11,6 +11,10 @@ export function subsessionsConfigPatch(enabled: boolean): PiWebConfigValues {
|
||||
return { subsessions: enabled };
|
||||
}
|
||||
|
||||
export function askUserConfigPatch(enabled: boolean): PiWebConfigValues {
|
||||
return { askUser: enabled };
|
||||
}
|
||||
|
||||
export function agentProfileActivationState(
|
||||
config: PiWebConfigResponse | undefined,
|
||||
activeProfile: ActiveAgentProfileDescriptor | undefined,
|
||||
|
||||
Reference in New Issue
Block a user