Design for tools preview and testing in the Tools drawer, updated Sept 18, 2026, covers the default state, live invocation enabled, and the disabled toggle. It follows the tool testing design in #6710.
Hide the toggle when the caller lacks tools.execute or servers.use.
Show it disabled with the reason below it for:
checking access / permissions could not be loaded / any tool that cannot be live invoked / invalid source ID.
resolveToolLiveInvokeAvailability (ToolLiveInvokeGate.tsx:12-18) needs no new states, only a different mapping to presentation, but it does not currently receive permissionsError.
Fix needed: required arguments start in an error state, but should not. Errors are computed from the value only, with no touched state (ToolArgumentsForm.tsx:141-144), so every required field shows a red border and "Required" before any input, and the action starts disabled. -> update: implemented on the Feature/codespaces #90 branch in commit 9e58078, so verify rather than reimplement. ToolArgumentsForm now tracks touchedFields and takes a validationAttempted prop, showing an error only when validation has been attempted or the field has been touched. The action is gated on disabled={!headersValid} with onBeforeRun setting the attempted flag, so it starts enabled and validates on use. ToolArgumentsForm is shared, so this reaches the Tools drawer when Feature/codespaces #90 merges.
Fix needed: argument descriptions have no length limit. field.description is printed as is (ToolArgumentsForm.tsx:372-376). Schema descriptions are written for models, so a single argument can show a long block of instructions. Truncate the text and add a way for the user to access the rest. (@a-effort to provide a reference)
The MCP version moves from the badge in the snippet row (ToolTryItTab.tsx:296) to the start of the tool description line, as its own element rather than appended to the description string, so it still renders when a tool has no description (ToolTryItTab.tsx:215).
Add the info affordance beside the "Live invocation" label. Use a Popover, matching VisibilityInfoPopover (VisibilityInfoPopover.tsx:71-87). The content explains which mode the user is in, which nothing on screen currently does, rather than repeating the consequences printed below the toggle: "Preview: checks your arguments and resolves which source would answer, without contacting it." and "Live invocation: sends the call to the source and returns its response."
@gandhipratik203 , the design is ready. Lmk if you want to discuss real time or if there are any questions. 🙌
Feel free to pass this to @gcgoncalves / @marekdano / @vishu-bh if you're too busy to work on this during the current sprint or I can pick it up. lmk! @jonpspri (re planning)
changed the title [-][UI-REWRITE]: Apply the tool testing design to the Tools drawer[/-][+][UI-REWRITE]: Update the tool testing design to the Tools drawer[/+]on Sep 19, 2026
Item 3: the action should start enabled and validate on use. Error state should appear once there is an error to report rather than before any input, and where an error can be detected as the user types, showing it then is correct.
validateToolArguments in ToolArgumentsForm.tsx produces required, integer and number errors. The integer and number checks at lines 119 to 124 are guarded by if (empty) continue at line 118, so they only run once a value exists and already report at the right time. required at line 115 is the only error that can fire against a field the user has not touched. Defer that one until the action is used, rather than putting every error behind a touched state, which would delay the type feedback that currently works.
Because the action starts enabled, the submitted state has to be reachable from the action. The action is gated by disabled={!argsValid || !headersValid} at ToolTryItTab.tsx:306 and :313, while errors are computed inside ToolArgumentsForm. If that state stays private to the form, a failed attempt cannot reveal the errors. Either lift it into ToolTryItTab, or give ToolArgumentsForm a prop or imperative handle for it. onValidityChange only reports validity upward.
Header validity needs no equivalent change. getHeaderNameError returns null for an empty name, so header errors already appear only after input.
Items 1 and 2, and the info affordance in item 7, need preview and live invocation as a toggle with no virtual server involved. ToolTryItTab cannot express that today.
scopedMode is Boolean(serverScope) (ToolTryItTab.tsx:73 on the #90 branch), so one flag decides both how the call is addressed and which interaction model renders: the header layout, whether the toggle appears, which action and result panel render, and which snippet set is used. Only the serverId handed to the preview and invoke hooks needs the scope.
Passing a scope just to obtain the toggle would also switch the header to the Test tool layout and point the snippets at the preview route.
Worth making the mode an explicit prop and keeping serverScope for addressing, so each surface picks its interaction model independently.
#6969 Rewrite the live invocation unavailable reasons (enhancement). The disabled-toggle copy predates the toggle,
still says "Live invoke", and prints internal identifiers like tools.execute and gateway ID. Walks each availability
state and asks whether each keeps its own reason or collapses to the design's single string.
#6970 Code blocks scroll in both directions and nest borders (bug). ui/code-block.tsx hardcodes max-h-[420px]
overflow-auto on the pre and applies className to the wrapper, so no call site can change it. Long curl payloads
scroll sideways where the design wraps, and result renderers add a border around an already bordered block. Proposes
making height, wrapping and border props, plus one result wrapper shared by tools, prompts and resources.
#6971 Live invocation status line reports success wording on a tool-level error (bug). statusLabel branches only on
transport success, so an MCP error over HTTP 200 renders "Live invoke 200" in red next to an error icon. Fix is to
mirror the preview path's severity model and take icon and tone from the shared maps.
#6972 Design system text-sm is 13px where Tailwind's is 14px (chore). The token is unusable at that step, so feature
code writes text-[13px] by hand while src/components/ui uses text-sm throughout.
#6973 Preview buttons drop their icon on the rerun state (bug). Tool, prompt and resource preview buttons render Play
initially then no icon, while the invoke button beside them keeps its own, so the controls shift relative weight after
the first run.
#6974 Tool argument inputs have no placeholder, and a single argument renders at half width (enhancement). Only array
fields get a placeholder today. Proposes examples[0] then format, nothing otherwise, and explains why default should
seed the field instead.
#6975 ToolLiveInvokeGate keeps an unreachable fallback and resolves availability twice (chore). After web-ui #151,
both the caller and the gate call useAuth and resolveToolLiveInvokeAvailability, and the gate's fallback return is
reachable only for one render before an effect resets the toggle. Proposes passing narrowed availability in as a prop
so the compiler enforces the call site's contract, then deleting the fallback, the presentation prop, three locale
strings and the test that mounts the gate directly.
Activity
a-effort commented on Sep 17, 2026
When the toggle is disabled, we can show the reason underneath it using this design.
Copy / icon may be tweaked, depending on the context and if it's info or an issue (warning).
a-effort commented on Sep 19, 2026
@gandhipratik203 , the design is ready. Lmk if you want to discuss real time or if there are any questions. 🙌
Feel free to pass this to @gcgoncalves / @marekdano / @vishu-bh if you're too busy to work on this during the current sprint or I can pick it up. lmk! @jonpspri (re planning)
a-effort commented on Sep 21, 2026
Item 3: the action should start enabled and validate on use. Error state should appear once there is an error to report rather than before any input, and where an error can be detected as the user types, showing it then is correct.
validateToolArguments in ToolArgumentsForm.tsx produces required, integer and number errors. The integer and number checks at lines 119 to 124 are guarded by if (empty) continue at line 118, so they only run once a value exists and already report at the right time. required at line 115 is the only error that can fire against a field the user has not touched. Defer that one until the action is used, rather than putting every error behind a touched state, which would delay the type feedback that currently works.
Because the action starts enabled, the submitted state has to be reachable from the action. The action is gated by disabled={!argsValid || !headersValid} at ToolTryItTab.tsx:306 and :313, while errors are computed inside ToolArgumentsForm. If that state stays private to the form, a failed attempt cannot reveal the errors. Either lift it into ToolTryItTab, or give ToolArgumentsForm a prop or imperative handle for it. onValidityChange only reports validity upward.
Header validity needs no equivalent change. getHeaderNameError returns null for an empty name, so header errors already appear only after input.
a-effort commented on Sep 22, 2026
Items 1 and 2, and the info affordance in item 7, need preview and live invocation as a toggle with no virtual server involved. ToolTryItTab cannot express that today.
scopedMode is Boolean(serverScope) (ToolTryItTab.tsx:73 on the #90 branch), so one flag decides both how the call is addressed and which interaction model renders: the header layout, whether the toggle appears, which action and result panel render, and which snippet set is used. Only the serverId handed to the preview and invoke hooks needs the scope.
Passing a scope just to obtain the toggle would also switch the header to the Test tool layout and point the snippets at the preview route.
Worth making the mode an explicit prop and keeping serverScope for addressing, so each surface picks its interaction model independently.
a-effort commented on Sep 23, 2026
Follow up issues filed (kept separate from change requests for contextforge-org/contextforge-web-ui#151):
#6969 Rewrite the live invocation unavailable reasons (enhancement). The disabled-toggle copy predates the toggle,
still says "Live invoke", and prints internal identifiers like tools.execute and gateway ID. Walks each availability
state and asks whether each keeps its own reason or collapses to the design's single string.
#6970 Code blocks scroll in both directions and nest borders (bug). ui/code-block.tsx hardcodes max-h-[420px]
overflow-auto on the pre and applies className to the wrapper, so no call site can change it. Long curl payloads
scroll sideways where the design wraps, and result renderers add a border around an already bordered block. Proposes
making height, wrapping and border props, plus one result wrapper shared by tools, prompts and resources.
#6971 Live invocation status line reports success wording on a tool-level error (bug). statusLabel branches only on
transport success, so an MCP error over HTTP 200 renders "Live invoke 200" in red next to an error icon. Fix is to
mirror the preview path's severity model and take icon and tone from the shared maps.
#6972 Design system text-sm is 13px where Tailwind's is 14px (chore). The token is unusable at that step, so feature
code writes text-[13px] by hand while src/components/ui uses text-sm throughout.
#6973 Preview buttons drop their icon on the rerun state (bug). Tool, prompt and resource preview buttons render Play
initially then no icon, while the invoke button beside them keeps its own, so the controls shift relative weight after
the first run.
#6974 Tool argument inputs have no placeholder, and a single argument renders at half width (enhancement). Only array
fields get a placeholder today. Proposes examples[0] then format, nothing otherwise, and explains why default should
seed the field instead.
#6975 ToolLiveInvokeGate keeps an unreachable fallback and resolves availability twice (chore). After web-ui #151,
both the caller and the gate call useAuth and resolveToolLiveInvokeAvailability, and the gate's fallback return is
reachable only for one render before an effect resets the toggle. Proposes passing narrowed availability in as a prop
so the compiler enforces the call site's contract, then deleting the fallback, the presentation prop, three locale
strings and the test that mounts the gate directly.
a-effort commented on Sep 28, 2026
@marekdano , added reference for collapse/expand pattern: https://www.figma.com/design/H2Dr9QPvRVxCe92V8URvGT/Refiring?m=auto&node-id=6258-4999&t=ZNSmG52g3rn5zLIq-1