Implement comprehensive tool call rendering with state persistence
- Implement tool-specific rendering for all 14 tool types (read, edit, write, bash, webfetch, todowrite, task, etc.) - Each tool shows contextually relevant information (file previews, diffs, command output, todo lists) - Add metadata-driven content display using preview, diff, output, and todos from tool state - Implement status-based rendering (pending, running, completed, error) with animations - Create global state store for expandable items (tool calls and reasoning sections) - Fix state persistence: expanded tool calls and reasoning sections remain expanded when new messages arrive - Fix scroll position preservation during live message updates - Fix reasoning toggle loop by replacing native details element with custom expandable - Add comprehensive documentation in TOOL_CALL_IMPLEMENTATION.md - Reduce font sizes for better readability in expanded tool content - Add proper keying to For loops to prevent component recreation - Match TUI patterns for tool names, actions, and content formatting
This commit is contained in:
79
src/components/prompt-input.tsx
Normal file
79
src/components/prompt-input.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createSignal, Show } from "solid-js"
|
||||
|
||||
interface PromptInputProps {
|
||||
instanceId: string
|
||||
sessionId: string
|
||||
onSend: (prompt: string) => Promise<void>
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export default function PromptInput(props: PromptInputProps) {
|
||||
const [prompt, setPrompt] = createSignal("")
|
||||
const [sending, setSending] = createSignal(false)
|
||||
let textareaRef: HTMLTextAreaElement | undefined
|
||||
|
||||
function handleKeyDown(e: KeyboardEvent) {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
handleSend()
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSend() {
|
||||
const text = prompt().trim()
|
||||
if (!text || sending() || props.disabled) return
|
||||
|
||||
setSending(true)
|
||||
try {
|
||||
await props.onSend(text)
|
||||
setPrompt("")
|
||||
|
||||
if (textareaRef) {
|
||||
textareaRef.style.height = "auto"
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to send message:", error)
|
||||
alert("Failed to send message: " + (error instanceof Error ? error.message : String(error)))
|
||||
} finally {
|
||||
setSending(false)
|
||||
textareaRef?.focus()
|
||||
}
|
||||
}
|
||||
|
||||
function handleInput(e: Event) {
|
||||
const target = e.target as HTMLTextAreaElement
|
||||
setPrompt(target.value)
|
||||
|
||||
target.style.height = "auto"
|
||||
target.style.height = Math.min(target.scrollHeight, 200) + "px"
|
||||
}
|
||||
|
||||
const canSend = () => prompt().trim().length > 0 && !sending() && !props.disabled
|
||||
|
||||
return (
|
||||
<div class="prompt-input-container">
|
||||
<div class="prompt-input-wrapper">
|
||||
<textarea
|
||||
ref={textareaRef}
|
||||
class="prompt-input"
|
||||
placeholder="Type your message or /command..."
|
||||
value={prompt()}
|
||||
onInput={handleInput}
|
||||
onKeyDown={handleKeyDown}
|
||||
disabled={sending() || props.disabled}
|
||||
rows={1}
|
||||
/>
|
||||
<button class="send-button" onClick={handleSend} disabled={!canSend()} aria-label="Send message">
|
||||
<Show when={sending()} fallback={<span class="send-icon">▶</span>}>
|
||||
<span class="spinner-small" />
|
||||
</Show>
|
||||
</button>
|
||||
</div>
|
||||
<div class="prompt-input-hints">
|
||||
<span class="hint">
|
||||
<kbd>Enter</kbd> to send, <kbd>Shift+Enter</kbd> for new line
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user