Skip to content

Commit c17d1a8

Browse files
authored
Merge pull request #2071 from trungutt/trungutt/user-prompt-options
Add options-based selection to user_prompt tool
2 parents 5eed2fe + 176c2d3 commit c17d1a8

1 file changed

Lines changed: 36 additions & 11 deletions

File tree

pkg/tools/builtin/user_prompt.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,18 @@ var (
2323
_ tools.Instructable = (*UserPromptTool)(nil)
2424
)
2525

26+
// UserPromptOption represents a single selectable choice presented to the user.
27+
type UserPromptOption struct {
28+
Label string `json:"label" jsonschema:"Short display text for this option (1-5 words)"`
29+
Description string `json:"description" jsonschema:"Brief explanation of what this option means"`
30+
}
31+
2632
type UserPromptArgs struct {
27-
Message string `json:"message" jsonschema:"The message/question to display to the user"`
28-
Title string `json:"title,omitempty" jsonschema:"Optional title for the dialog window (defaults to 'Question')"`
29-
Schema map[string]any `json:"schema,omitempty" jsonschema:"JSON Schema defining the expected response structure. Supports object schemas with properties or primitive type schemas."`
33+
Message string `json:"message" jsonschema:"The message/question to display to the user"`
34+
Title string `json:"title,omitempty" jsonschema:"Optional title for the dialog window (defaults to 'Question')"`
35+
Schema map[string]any `json:"schema,omitempty" jsonschema:"JSON Schema defining the expected response structure. Mutually exclusive with options."`
36+
Options []UserPromptOption `json:"options,omitempty" jsonschema:"List of choices to present to the user. Each has a label and description. The user can pick from these or type a custom answer. Put recommended option first and append '(Recommended)' to its label. Mutually exclusive with schema."`
37+
Multiple bool `json:"multiple,omitempty" jsonschema:"When true and options are provided, allow the user to select multiple options. Defaults to single selection."`
3038
}
3139

3240
type UserPromptResponse struct {
@@ -47,9 +55,13 @@ func (t *UserPromptTool) userPrompt(ctx context.Context, params UserPromptArgs)
4755
return tools.ResultError("user_prompt tool is not available in this context (no elicitation handler configured)"), nil
4856
}
4957

50-
var meta mcp.Meta
58+
meta := mcp.Meta{}
5159
if params.Title != "" {
52-
meta = mcp.Meta{"cagent/title": params.Title}
60+
meta["cagent/title"] = params.Title
61+
}
62+
if len(params.Options) > 0 {
63+
meta["cagent/options"] = params.Options
64+
meta["cagent/multiple"] = params.Multiple
5365
}
5466

5567
req := &mcp.ElicitParams{
@@ -87,24 +99,37 @@ Use user_prompt to ask the user a question or gather input when you need clarifi
8799
88100
Optionally provide a "title" to label the dialog (defaults to "Question").
89101
90-
Optionally provide a JSON schema to structure the expected response (object, primitive, or enum types).
91-
If no schema is provided, the user can type a free-form response.
102+
### Presenting choices with options (preferred for decisions)
103+
104+
Provide "options" — a list of {label, description} objects — to present clickable choices.
105+
The user can select from the list or type a custom answer.
106+
- Put the recommended option first and append "(Recommended)" to its label.
107+
- Set "multiple": true to allow selecting more than one option.
108+
- Do NOT include catch-all options like "Other" — a custom text input is always available.
92109
93-
Example schema for multiple choice:
94-
{"type": "string", "enum": ["option1", "option2"], "title": "Select an option"}
110+
Example with options:
111+
{"message": "Which base image strategy?", "options": [{"label": "Alpine multi-stage (Recommended)", "description": "Smallest image size, widely used"}, {"label": "Distroless runtime", "description": "No shell, minimal attack surface"}, {"label": "Scratch with static binary", "description": "Absolute minimum, requires CGO_ENABLED=0"}]}
112+
113+
### Structured input with schema (for forms)
114+
115+
Provide a JSON "schema" to collect structured data (object, primitive, or enum types).
116+
If neither options nor schema is provided, the user can type a free-form response.
95117
96118
Example schema for structured input:
97119
{"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]}
98120
99-
Response contains "action" (accept/decline/cancel) and "content" (user data, only when accepted).`
121+
### Response format
122+
123+
Response contains "action" (accept/decline/cancel) and "content" (user data, only when accepted).
124+
When options are used, content has "selection" (array of selected labels) or "custom" (user-typed text).`
100125
}
101126

102127
func (t *UserPromptTool) Tools(context.Context) ([]tools.Tool, error) {
103128
return []tools.Tool{
104129
{
105130
Name: ToolNameUserPrompt,
106131
Category: "user_prompt",
107-
Description: "Ask the user a question and wait for their response. Use this when you need interactive input, clarification, or confirmation from the user. Optionally provide a JSON schema to define the expected response structure.",
132+
Description: "Ask the user a question and wait for their response. Use this when you need interactive input, clarification, or confirmation from the user. Provide 'options' to present a list of choices, or a JSON 'schema' for structured input.",
108133
Parameters: tools.MustSchemaFor[UserPromptArgs](),
109134
OutputSchema: tools.MustSchemaFor[UserPromptResponse](),
110135
Handler: tools.NewHandler(t.userPrompt),

0 commit comments

Comments
 (0)