mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-05 16:04:43 +00:00
fix(app): a draft stops sending a toggle the model in use does not offer
A toggle made on one model stayed in the draft's edits after the form moved to a model whose controls do not include it, and was sent with the create. On a legacy daemon that key is not a feature for the new model, so it went out as a native provider option the daemon rejects. The draft now sends an edit only while the latest answer draws a control for it, and sends it again when a control for it returns.
This commit is contained in:
@@ -72,7 +72,11 @@ describe("draft options model", () => {
|
||||
|
||||
it("never pairs a manually chosen provider with the previous provider's options", () => {
|
||||
const model = openDraftOptions({ provider: "claude" });
|
||||
model.applyResolved(answer("claude", "k1", { fast_mode: true }));
|
||||
model.applyResolved(
|
||||
answer("claude", "k1", { fast_mode: true }, [
|
||||
{ type: "toggle", key: "fast_mode", label: "Fast" },
|
||||
]),
|
||||
);
|
||||
model.setOption("fast_mode", true);
|
||||
const form = { provider: "claude", cwd: "/repo" };
|
||||
expect(draftControlsRequest(model.getState(), form)).toMatchObject({
|
||||
@@ -88,6 +92,29 @@ describe("draft options model", () => {
|
||||
expect(request).toEqual({ provider: "opencode", cwd: "/repo" });
|
||||
});
|
||||
|
||||
it("stops sending a toggle once the model in use draws no control for it", () => {
|
||||
const FAST_MODE: AgentOptionControl = { type: "toggle", key: "fast_mode", label: "Fast" };
|
||||
const model = openDraftOptions({ provider: "claude", seed: { sandbox_mode: "read-only" } });
|
||||
model.applyResolved(answer("claude", "opus", { fast_mode: false }, [FAST_MODE]));
|
||||
model.setOption("fast_mode", true);
|
||||
expect(ownDraftOptions(model.getState())).toEqual({
|
||||
sandbox_mode: "read-only",
|
||||
fast_mode: true,
|
||||
});
|
||||
|
||||
// The form moves to a model without Fast; its answer lists no such control.
|
||||
model.applyResolved(answer("claude", "haiku", {}, []));
|
||||
|
||||
expect(ownDraftOptions(model.getState())).toEqual({ sandbox_mode: "read-only" });
|
||||
|
||||
// Back on the first model, the toggle is still on.
|
||||
model.applyResolved(answer("claude", "opus-again", { fast_mode: true }, [FAST_MODE]));
|
||||
expect(ownDraftOptions(model.getState())).toEqual({
|
||||
sandbox_mode: "read-only",
|
||||
fast_mode: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps a draft's seed when the first provider is chosen", () => {
|
||||
const model = openDraftOptions({ provider: null, seed: { web_search: true } });
|
||||
|
||||
|
||||
@@ -101,6 +101,8 @@ export function openDraftOptions(input: {
|
||||
/**
|
||||
* Everything the draft would create with, for the daemon to resolve. A last-used value applies
|
||||
* once the provider has told us it still draws a control for that key, and never over the seed.
|
||||
* A toggle made in this draft stops applying when the latest answer draws no control for it (the
|
||||
* model changed to one without that control) and applies again when a control for it returns.
|
||||
*/
|
||||
export function ownDraftOptions(state: DraftOptionsState): ProviderOptions | undefined {
|
||||
const controlKeys = new Set((state.resolved?.controls ?? []).map((control) => control.key));
|
||||
@@ -109,7 +111,10 @@ export function ownDraftOptions(state: DraftOptionsState): ProviderOptions | und
|
||||
([key]) => controlKeys.has(key) && !(key in state.seed),
|
||||
),
|
||||
);
|
||||
const own = { ...state.seed, ...remembered, ...state.edits };
|
||||
const edits = Object.fromEntries(
|
||||
Object.entries(state.edits).filter(([key]) => !state.resolved || controlKeys.has(key)),
|
||||
);
|
||||
const own = { ...state.seed, ...remembered, ...edits };
|
||||
return Object.keys(own).length > 0 ? own : undefined;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user