Skip to content

Add 'Something else' option to human input cards#825

Merged
larryro merged 2 commits into
mainfrom
feat/human-input-other-option
Mar 21, 2026
Merged

Add 'Something else' option to human input cards#825
larryro merged 2 commits into
mainfrom
feat/human-input-other-option

Conversation

@larryro
Copy link
Copy Markdown
Collaborator

@larryro larryro commented Mar 21, 2026

Summary

  • Adds an automatic "Something else" free-text option to all single_select and multi_select human input cards, letting users provide custom responses beyond the predefined options
  • Refactors the tool schema to use a discriminated union (z.discriminatedUnion) for stricter per-format validation instead of a flat object with optional fields
  • Improves workflow context handling: sets generationStatus on response submission so the frontend shows a loading indicator, adds deadline timeout, and skips onResponseSubmitted callback in workflow contexts
  • Updates tool description to guide the AI agent away from including manual "Other" options (the UI handles it automatically)

Test plan

  • Verify single_select cards show "Something else" option with dashed border
  • Select "Something else", confirm textarea appears with autofocus
  • Submit with empty textarea — should show validation error
  • Submit with text — should send the custom text as the response
  • Verify multi_select cards also show "Something else" with checkbox
  • Confirm selecting "Something else" + other options sends mixed array
  • Verify yes_no cards still default to Yes/No when no custom options provided
  • Verify workflow context approvals show loading indicator after submission

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Other" option support for single/multi-select and yes/no input flows, allowing users to provide custom text responses.
  • Improvements

    • Enhanced validation to require non-empty custom text when selecting "Other" option.
    • Improved tool documentation with updated usage constraints and examples.

…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
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 21, 2026

📝 Walkthrough

Walkthrough

This 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 wfExecutionId), the response submission callback is skipped to avoid duplicate processing. Supporting changes include refactoring the backend tool schema to use discriminated unions for per-format validation, updating workflow thread metadata with generation status and stream IDs, and extending UI message strings for the new "Other" functionality.

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 HumanInputRequestCard and request_human_input_tool.ts files contain significant logic changes and new validation patterns requiring careful reasoning for each area.

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main feature addition: an 'Other'/'Something else' option for human input cards, which is the primary change across the component, hook, and backend logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/human-input-other-option

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can customize the tone of the review comments and chat replies.

Configure the tone_instructions setting to customize the tone of the review comments and chat replies. For example, you can set the tone to Act like a strict teacher, Act like a pirate and more.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 | 🟠 Major

Keep yes_no approvals binary.

The shared branches at Lines 72-86 and Lines 168-265 now inject Something else and submit arbitrary free text for yes_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. Split yes_no back out so only single_select and multi_select get 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

📥 Commits

Reviewing files that changed from the base of the PR and between 57a2157 and 100af1a.

⛔ Files ignored due to path filters (2)
  • services/platform/convex/_generated/api.d.ts is excluded by !**/_generated/**
  • services/platform/convex/betterAuth/_generated/component.ts is excluded by !**/_generated/**
📒 Files selected for processing (6)
  • services/platform/app/features/chat/components/approval-card-renderer.tsx
  • services/platform/app/features/chat/components/human-input-request-card.tsx
  • services/platform/app/features/chat/hooks/queries.ts
  • services/platform/convex/agent_tools/human_input/mutations.ts
  • services/platform/convex/agent_tools/human_input/request_human_input_tool.ts
  • services/platform/messages/en.json

Comment on lines +144 to +154
// 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,
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +46 to +82
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.',
),
}),
]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.
@larryro larryro merged commit f395e98 into main Mar 21, 2026
17 checks passed
@larryro larryro deleted the feat/human-input-other-option branch March 21, 2026 05:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant