mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-02 22:52:58 +00:00
Draft commands read the state captured at render, so a plugin's
`await setProvider(); await setModel()` acted on a stale provider. The draft
form and options are now plain stores that commands read live, and
`setProvider`/`setModel` reject an unavailable provider or a model the loaded
catalog does not list. Draft `options` include the plugin's pending edits.
Shared composer controls own the pending state and show a rejected command as
an error toast, like the built-in controls. Callback payloads are objects
(`{ value }`, `onPress(event)`) so they can grow without breaking plugins.
The overflow sheet's content portals to the app root and lost the composer's
agent, input, toast and query contexts, so plugin items drew nothing in it.
`useComposerSheetBridge` carries them across.
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { useCallback } from "react";
|
|
import { useComposer } from "@getpaseo/plugin/client";
|
|
import { Action, Select, Toggle } from "@getpaseo/plugin/client/ui";
|
|
|
|
type ContextLength = "short" | "long";
|
|
|
|
const CONTEXT_OPTIONS = [
|
|
{ value: "short", label: "Short", description: "Answer from the files you name." },
|
|
{ value: "long", label: "Long", description: "Read the surrounding code first." },
|
|
] as const;
|
|
|
|
const CONTEXT_KEY = "composer-controls.contextLength";
|
|
const REVIEW_KEY = "composer-controls.needsReview";
|
|
|
|
/** Reads and writes agent metadata, so the choice is saved with the agent. */
|
|
export function ContextLength() {
|
|
const composer = useComposer();
|
|
const current: ContextLength = composer.agent.metadata[CONTEXT_KEY] === "long" ? "long" : "short";
|
|
const change = useCallback(
|
|
({ value }: { value: ContextLength }) => composer.setMetadata({ [CONTEXT_KEY]: value }),
|
|
[composer],
|
|
);
|
|
return (
|
|
<Select
|
|
title="Context length"
|
|
icon="Gauge"
|
|
value={current}
|
|
options={CONTEXT_OPTIONS}
|
|
onValueChange={change}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function ReviewFlag() {
|
|
const composer = useComposer();
|
|
const change = useCallback(
|
|
({ value }: { value: boolean }) => composer.setMetadata({ [REVIEW_KEY]: value ? true : null }),
|
|
[composer],
|
|
);
|
|
return (
|
|
<Toggle
|
|
title="Needs review"
|
|
icon="Flag"
|
|
value={composer.agent.metadata[REVIEW_KEY] === true}
|
|
onValueChange={change}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Changes a provider option. Only Codex reports `plan_mode`, so the control is disabled for
|
|
* other providers. The promise it returns keeps the control pending, and a rejection reaches the
|
|
* user as a toast.
|
|
*/
|
|
export function PlanFirst() {
|
|
const composer = useComposer();
|
|
const change = useCallback(
|
|
({ value }: { value: boolean }) => composer.setOptions({ plan_mode: value }),
|
|
[composer],
|
|
);
|
|
return (
|
|
<Toggle
|
|
title="Plan first"
|
|
icon="ListTodo"
|
|
disabled={composer.agent.provider !== "codex"}
|
|
value={composer.agent.options.plan_mode === true}
|
|
onValueChange={change}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** Works the same in the agent, draft and New workspace composers. */
|
|
export function Checklist() {
|
|
const composer = useComposer();
|
|
const insert = useCallback(() => composer.insertText("- [ ] Tests\n- [ ] Docs\n"), [composer]);
|
|
return <Action title="Insert checklist" icon="ListChecks" onPress={insert} />;
|
|
}
|