Add AI ask tool + use new timeout on AI tool - #440
Conversation
|
|
Make sure ask tool has a cancel button |
| !store.hasAllLoaded(moduleIds) | ||
| ) { | ||
| React.use(store.waitForLoad(moduleIds)); | ||
| console.log("->", valOverlayContext.enabled, store?.hasAllLoaded(moduleIds)); |
| }: { | ||
| params: Promise<{ blog: string }>; | ||
| }) { | ||
| console.log("here"); |
| const blog = useValRoute(blogsVal, params); | ||
| const authors = useVal(authorsVal); | ||
| if (!blog) { | ||
| console.log("not found"); |
| chat: { | ||
| experimental: { | ||
| enable: false, | ||
| enable: true, |
There was a problem hiding this comment.
Revert back to false
| _toolCallId: string, | ||
| answers: AskUserQuestionAnswer[], | ||
| ) => { | ||
| console.log("Submitted answers:", answers); |
There was a problem hiding this comment.
Pull request overview
This PR extends the Val UI AI chat/tooling layer by introducing a new ask_user_question tool (with a question-card UI) and by adding support for per-tool server-side timeouts via timeoutMs in the tool definition schema.
Changes:
- Added
ask_user_questionas a first-class AI tool, including UI rendering for structured single-/multi-select questions and callbacks to submit/cancel answers. - Extended the AI tool schema to optionally include a server-side
timeoutMsand setask_user_questionto wait indefinitely (null) while the user is interacting. - Adjusted some UI wiring (overlay/tools menu) and made
useValConfigtolerate missing provider contexts (e.g. Storybook).
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ui/spa/utils/toolNames.ts | Adds ask_user_question to the tool-name union for type-safe UI/tool mappings. |
| packages/ui/spa/hooks/useAIWebSocket.ts | Extends the AITool schema with optional timeoutMs for server-side waiting behavior. |
| packages/ui/spa/hooks/useAI.ts | Registers the new tool, routes tool calls to the UI question card, and adds answer/cancel APIs. |
| packages/ui/spa/components/ValOverlay.tsx | Wires the new answer/cancel handlers from useAI into AIChat. |
| packages/ui/spa/components/ToolsMenu.tsx | Wires the new answer/cancel handlers into AIChat for the tools menu variant. |
| packages/ui/spa/components/AIChat.tsx | Implements the question card UI, stores answers/cancel state, and updates tool activity rendering. |
| packages/ui/spa/components/AIChat.stories.tsx | Adds Storybook demos for pending/answered/cancelled question flows. |
| packages/ui/spa/components/ValFieldProvider.tsx | Makes useValConfig() resilient when rendered without ValFieldProvider. |
| packages/next/src/client/initValClient.ts | Adds debug logging in useValStega suspense gating (should be removed). |
| examples/next/val.config.ts | Enables experimental AI chat in the example config for demoing the feature. |
| examples/next/app/blogs/[blog]/page.tsx | Switches the blog example page to client/hooks usage but includes debug logs + now-unused imports. |
Comments suppressed due to low confidence (1)
packages/next/src/client/initValClient.ts:53
- Remove debug logging from the suspense gate; logging moduleIds during render can be noisy and expose internal module structure.
console.log("suspending", moduleIds);
| return; | ||
| }, | ||
| ); | ||
| console.log("->", valOverlayContext.enabled, store?.hasAllLoaded(moduleIds)); |
| "use server"; | ||
| "use client"; | ||
| import { notFound } from "next/navigation"; | ||
| import { fetchVal, fetchValRoute } from "../../../val/rsc"; |
| console.log("here"); | ||
| const blog = useValRoute(blogsVal, params); | ||
| const authors = useVal(authorsVal); | ||
| if (!blog) { | ||
| console.log("not found"); | ||
| return notFound(); | ||
| } |
| // Reject any pending ask_user_question tool calls so the server-side | ||
| // conversation doesn't keep a dangling tool call open. | ||
| for (const toolCallId of pendingQuestionToolCallIdsRef.current) { | ||
| sendWsMessage({ | ||
| type: "ai_tool_result", |
| <button | ||
| key={oi} | ||
| type="button" | ||
| disabled={submitted} | ||
| onClick={() => toggleOption(qi, oi, multiSelect)} | ||
| className={cn( |
No description provided.