Add 'Something else' option to human input cards#825
Conversation
…ool schema - Add an "Other" freetext option to single_select and multi_select cards so users can provide custom responses beyond predefined options - Refactor tool args to use discriminated union for stricter validation - Update tool description to guide the agent to always use interactive cards instead of plain-text option lists - Set generationStatus on human input response submission for loading UI - Add deadline to agent continuation after human input response - Skip onResponseSubmitted callback in workflow context
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughWalkthroughThis PR extends the human-input-request system with two key enhancements. First, it adds support for an "Other" option in single-select, multi-select, and yes/no input types, allowing users to provide custom text responses. Second, it introduces workflow-context awareness—when a human-input request originates from a workflow execution (identified by Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes The changes span six distinct files with heterogeneous concerns: frontend UI state management for "Other" option handling, prop threading with workflow context, schema refactoring using discriminated unions, validation logic updates, and workflow metadata persistence. The Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment Tip You can customize the tone of the review comments and chat replies.Configure the |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
services/platform/app/features/chat/components/human-input-request-card.tsx (1)
72-86:⚠️ Potential issue | 🟠 MajorKeep
yes_noapprovals binary.The shared branches at Lines 72-86 and Lines 168-265 now inject
Something elseand submit arbitrary free text foryes_no. That changes a binary approval into an open-ended one, which can break callers that branch on a strict yes/no response and contradicts the stated requirement to keep yes/no cards default. Splityes_noback out so onlysingle_selectandmulti_selectget the synthetic fallback option.Also applies to: 168-265
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@services/platform/app/features/chat/components/human-input-request-card.tsx` around lines 72 - 86, The code currently treats 'yes_no' the same as 'single_select' and injects OTHER_VALUE/free-text; revert that so yes_no remains binary: in human-input-request-card.tsx, update the switch/handling around the cases for 'single_select' and 'yes_no' (references: case 'single_select', case 'yes_no', selectedValue, OTHER_VALUE, otherText, setError, response) to handle only 'single_select' (and 'multi_select' in the other block mentioned) with the synthetic "Something else"/OTHER_VALUE and free-text validation, and handle 'yes_no' separately to only accept 'yes' or 'no' (no OTHER_VALUE or otherText trimming/validation). Apply the same separation to the second occurrence covering lines 168-265 so callers expecting strict yes/no continue to receive binary responses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@services/platform/convex/agent_tools/human_input/mutations.ts`:
- Around line 144-154: The patch that sets threadMetadata.generationStatus and
streamId (currently using
ctx.db.query('threadMetadata').withIndex('by_threadId').first() and
ctx.db.patch(threadMeta._id, { generationStatus: 'generating', streamId })) must
be moved so it runs before the workflow fork/early return (the branch that
returns when wfExecutionId is present); update the code to query and patch
threadMeta immediately after computing streamId and before any workflow-context
submission/return so approvals with wfExecutionId also set generationStatus for
the frontend.
In
`@services/platform/convex/agent_tools/human_input/request_human_input_tool.ts`:
- Around line 46-82: Update the requestHumanInputArgs validation so
caller-supplied options cannot use reserved labels/values ("Other", "Something
else", "__other__"): modify the option array branches in requestHumanInputArgs
(and/or optionSchema) to add a .refine or transform that rejects any option
whose label or value matches the reserved set and returns a clear validation
error; apply the same rejection to the yes_no options branch (and any other
places in this file under requestHumanInputArgs/baseFields/optionSchema that
accept options) and ensure runtime code that consumes options also treats
"__other__" as internal-only (reject on input) so callers cannot supply or
duplicate the synthetic Other slot.
---
Outside diff comments:
In `@services/platform/app/features/chat/components/human-input-request-card.tsx`:
- Around line 72-86: The code currently treats 'yes_no' the same as
'single_select' and injects OTHER_VALUE/free-text; revert that so yes_no remains
binary: in human-input-request-card.tsx, update the switch/handling around the
cases for 'single_select' and 'yes_no' (references: case 'single_select', case
'yes_no', selectedValue, OTHER_VALUE, otherText, setError, response) to handle
only 'single_select' (and 'multi_select' in the other block mentioned) with the
synthetic "Something else"/OTHER_VALUE and free-text validation, and handle
'yes_no' separately to only accept 'yes' or 'no' (no OTHER_VALUE or otherText
trimming/validation). Apply the same separation to the second occurrence
covering lines 168-265 so callers expecting strict yes/no continue to receive
binary responses.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: bd225101-6ae2-499e-be3f-46b850ec5faf
⛔ Files ignored due to path filters (2)
services/platform/convex/_generated/api.d.tsis excluded by!**/_generated/**services/platform/convex/betterAuth/_generated/component.tsis excluded by!**/_generated/**
📒 Files selected for processing (6)
services/platform/app/features/chat/components/approval-card-renderer.tsxservices/platform/app/features/chat/components/human-input-request-card.tsxservices/platform/app/features/chat/hooks/queries.tsservices/platform/convex/agent_tools/human_input/mutations.tsservices/platform/convex/agent_tools/human_input/request_human_input_tool.tsservices/platform/messages/en.json
| // Set generationStatus so the frontend shows loading indicator | ||
| const threadMeta = await ctx.db | ||
| .query('threadMetadata') | ||
| .withIndex('by_threadId', (q) => q.eq('threadId', threadId)) | ||
| .first(); | ||
| if (threadMeta) { | ||
| await ctx.db.patch(threadMeta._id, { | ||
| generationStatus: 'generating' as const, | ||
| streamId, | ||
| }); | ||
| } |
There was a problem hiding this comment.
Move the loading-state patch above the workflow fork.
Lines 144-154 only run in the chat branch. Because workflow-context submissions return at Line 129, approvals with wfExecutionId still never set threadMetadata.generationStatus here, so the frontend misses the immediate loading indicator after a workflow response.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@services/platform/convex/agent_tools/human_input/mutations.ts` around lines
144 - 154, The patch that sets threadMetadata.generationStatus and streamId
(currently using ctx.db.query('threadMetadata').withIndex('by_threadId').first()
and ctx.db.patch(threadMeta._id, { generationStatus: 'generating', streamId }))
must be moved so it runs before the workflow fork/early return (the branch that
returns when wfExecutionId is present); update the code to query and patch
threadMeta immediately after computing streamId and before any workflow-context
submission/return so approvals with wfExecutionId also set generationStatus for
the frontend.
| const requestHumanInputArgs = z.discriminatedUnion('format', [ | ||
| z.object({ | ||
| ...baseFields, | ||
| format: z.literal('single_select'), | ||
| options: z | ||
| .array(optionSchema) | ||
| .min(2) | ||
| .describe('Options for the user to choose from. At least 2 required.'), | ||
| }), | ||
| z.object({ | ||
| ...baseFields, | ||
| format: z.literal('multi_select'), | ||
| options: z | ||
| .array(optionSchema) | ||
| .min(2) | ||
| .describe('Options for the user to choose from. At least 2 required.'), | ||
| }), | ||
| z.object({ | ||
| ...baseFields, | ||
| format: z.literal('text_input'), | ||
| placeholder: z | ||
| .string() | ||
| .optional() | ||
| .describe('Placeholder text for the text input field.'), | ||
| }), | ||
| z.object({ | ||
| ...baseFields, | ||
| format: z.literal('yes_no'), | ||
| options: z | ||
| .array(optionSchema) | ||
| .length(2) | ||
| .optional() | ||
| .describe( | ||
| 'Custom Yes/No options. Must be exactly 2 if provided. Defaults to [Yes, No] if omitted.', | ||
| ), | ||
| }), | ||
| ]); |
There was a problem hiding this comment.
Reserve the synthetic Other slot in the tool schema.
Line 95 tells the model not to send a manual fallback option, but the schema and runtime path still accept caller-supplied options named/value’d Other/Something else or the __other__ sentinel the card uses internally. That will either duplicate the fallback row or make a real option impossible to select. Reject those reserved labels/values at the tool boundary instead of relying on prompt compliance.
Based on learnings, files under services/platform/convex/agent_tools should validate LLM/user-supplied inputs at the runtime boundary with descriptive errors rather than relying on type restrictions or instructions alone.
Also applies to: 94-96, 170-179
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@services/platform/convex/agent_tools/human_input/request_human_input_tool.ts`
around lines 46 - 82, Update the requestHumanInputArgs validation so
caller-supplied options cannot use reserved labels/values ("Other", "Something
else", "__other__"): modify the option array branches in requestHumanInputArgs
(and/or optionSchema) to add a .refine or transform that rejects any option
whose label or value matches the reserved set and returns a clear validation
error; apply the same rejection to the yes_no options branch (and any other
places in this file under requestHumanInputArgs/baseFields/optionSchema that
accept options) and ensure runtime code that consumes options also treats
"__other__" as internal-only (reject on input) so callers cannot supply or
duplicate the synthetic Other slot.
…prompts Add cancel/stop workflow button to human input and workflow approval cards. Remove unused placeholder field from schema and tool. Improve per-format question descriptions to guide the AI toward concise, well-structured prompts. Type wfExecutionId as Id<'wfExecutions'> on the client.
Summary
z.discriminatedUnion) for stricter per-format validation instead of a flat object with optional fieldsgenerationStatuson response submission so the frontend shows a loading indicator, adds deadline timeout, and skipsonResponseSubmittedcallback in workflow contextsTest plan
Summary by CodeRabbit
Release Notes
New Features
Improvements