tui: improve agent selection and prompt editing experience

- Filter out built-in agents from autocomplete to show only custom agents
- Add proper agent part handling when selecting agents from autocomplete
- Fix cursor positioning and part management when editing prompts with agents
This commit is contained in:
Dax Raad 2025-10-02 00:46:13 -04:00
parent 502615b98d
commit 362d137e0d
3 changed files with 43 additions and 26 deletions

View file

@ -105,17 +105,28 @@ export function Autocomplete(props: {
const agents = createMemo(() => {
if (store.index !== 0) return []
const agents = sync.data.agent
return agents.map(
(agent): AutocompleteOption => ({
display: "@" + agent.name,
onSelect: () => {
props.setPrompt((draft) => {
const append = "@" + agent.name + " "
draft.input = append
})
},
}),
)
return agents
.filter((agent) => !agent.builtIn && agent.mode !== "primary")
.map(
(agent): AutocompleteOption => ({
display: "@" + agent.name,
onSelect: () => {
props.setPrompt((draft) => {
const append = "@" + agent.name + " "
draft.input = append
draft.parts.push({
type: "agent",
source: {
start: store.index,
end: store.index + agent.name.length + 1,
value: "@" + agent.name,
},
name: agent.name,
})
})
},
}),
)
})
const session = createMemo(() => (props.sessionID ? sync.session.get(props.sessionID) : undefined))

View file

@ -5,11 +5,11 @@ import { createStore, produce } from "solid-js/store"
import { clone } from "remeda"
import { createSimpleContext } from "../../context/helper"
import { appendFile } from "fs/promises"
import type { FilePart } from "@opencode-ai/sdk"
import type { AgentPart, FilePart } from "@opencode-ai/sdk"
export type PromptInfo = {
input: string
parts: Omit<FilePart, "id" | "messageID" | "sessionID">[]
parts: (Omit<FilePart, "id" | "messageID" | "sessionID"> | Omit<AgentPart, "id" | "messageID" | "sessionID">)[]
}
export const { use: usePromptHistory, provider: PromptHistoryProvider } = createSimpleContext({

View file

@ -12,6 +12,7 @@ import { useKeybind } from "@tui/context/keybind"
import { Clipboard } from "@/util/clipboard"
import { usePromptHistory, type PromptInfo } from "./history"
import { type AutocompleteRef, Autocomplete } from "./autocomplete"
import { iife } from "@/util/iife"
export type PromptProps = {
sessionID?: string
@ -113,17 +114,17 @@ export function Prompt(props: PromptProps) {
for (let i = 0; i < draft.parts.length; i++) {
const part = draft.parts[i]
if (!part.source) continue
if (part.source.text.start >= input.cursorPosition) {
part.source.text.start += diff
part.source.text.end += diff
const source = part.type === "agent" ? part.source : part.source.text
if (source.start >= input.cursorPosition) {
source.start += diff
source.end += diff
}
const sliced = draft.input.slice(part.source.text.start, part.source.text.end)
if (sliced != part.source.text.value && diff < 0) {
diff -= part.source.text.value.length
draft.input =
draft.input.slice(0, part.source.text.start) + draft.input.slice(part.source.text.end)
const sliced = draft.input.slice(source.start, source.end)
if (sliced != source.value && diff < 0) {
diff -= source.value.length
draft.input = draft.input.slice(0, source.start) + draft.input.slice(source.end)
draft.parts.splice(i, 1)
input.cursorPosition = Math.max(0, part.source.text.start - 1)
input.cursorPosition = Math.max(0, source.start - 1)
i--
}
}
@ -160,13 +161,18 @@ export function Prompt(props: PromptProps) {
const position = input.cursorPosition
const direction = Math.sign(old - position)
for (const part of store.parts) {
if (part.source && part.source.type === "file") {
if (position >= part.source.text.start && position < part.source.text.end) {
const source = iife(() => {
if (part.type === "agent") return part.source
if (part.type === "file") return part.source?.text
return
})
if (source) {
if (position >= source.start && position < source.end) {
if (direction === 1) {
input.cursorPosition = Math.max(0, part.source.text.start - 1)
input.cursorPosition = Math.max(0, source.start - 1)
}
if (direction === -1) {
input.cursorPosition = part.source.text.end
input.cursorPosition = source.end
}
}
}