mirror of
https://github.com/coder/coder.git
synced 2026-06-03 13:08:25 +00:00
1cf0354f72
> This PR was authored by Mux on behalf of Mike. ## Summary - add persistent plan mode for chats and the chat-specific plan file flow - add structured planning tools such as `ask_user_question` and `propose_plan` - keep `write_file` and `edit_files` constrained to the chat-specific plan file during plan turns - allow shell exploration in plan mode, including subagents, via `execute` and `process_output` - block implementation-oriented, provider-native, MCP, dynamic, and computer-use tools during plan turns - update the chat UI, tests, and docs for the new planning flow
142 lines
3.7 KiB
Go
142 lines
3.7 KiB
Go
package chattool //nolint:testpackage // Uses internal symbols.
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestValidateAskUserQuestionArgs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
args askUserQuestionArgs
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "QuestionsRequired",
|
|
args: askUserQuestionArgs{},
|
|
wantErr: "questions is required",
|
|
},
|
|
{
|
|
name: "HeaderRequired",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: " \t ",
|
|
Question: "What should we build?",
|
|
Options: validAskUserQuestionOptions(2),
|
|
}}},
|
|
wantErr: "questions[0].header is required",
|
|
},
|
|
{
|
|
name: "QuestionRequired",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "\n\t ",
|
|
Options: validAskUserQuestionOptions(2),
|
|
}}},
|
|
wantErr: "questions[0].question is required",
|
|
},
|
|
{
|
|
name: "TooFewOptions",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: validAskUserQuestionOptions(1),
|
|
}}},
|
|
wantErr: "questions[0].options must contain 2-4 items",
|
|
},
|
|
{
|
|
name: "TooManyOptions",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: validAskUserQuestionOptions(5),
|
|
}}},
|
|
wantErr: "questions[0].options must contain 2-4 items",
|
|
},
|
|
{
|
|
name: "OptionLabelRequired",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: []askUserQuestionOption{
|
|
{Label: " ", Description: "Build the API first."},
|
|
{Label: "Frontend", Description: "Build the UI first."},
|
|
},
|
|
}}},
|
|
wantErr: "questions[0].options[0].label is required",
|
|
},
|
|
{
|
|
name: "OptionDescriptionRequired",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: []askUserQuestionOption{
|
|
{Label: "Backend", Description: "\t"},
|
|
{Label: "Frontend", Description: "Build the UI first."},
|
|
},
|
|
}}},
|
|
wantErr: "questions[0].options[0].description is required",
|
|
},
|
|
{
|
|
name: "ValidTwoOptions",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: validAskUserQuestionOptions(2),
|
|
}}},
|
|
},
|
|
{
|
|
name: "ValidFourOptions",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: validAskUserQuestionOptions(4),
|
|
}}},
|
|
},
|
|
{
|
|
name: "SecondQuestionInvalid",
|
|
args: askUserQuestionArgs{Questions: []askUserQuestion{
|
|
{
|
|
Header: "Scope",
|
|
Question: "What should we build?",
|
|
Options: validAskUserQuestionOptions(2),
|
|
},
|
|
{
|
|
Header: "Timeline",
|
|
Question: "\t ",
|
|
Options: validAskUserQuestionOptions(2),
|
|
},
|
|
}},
|
|
wantErr: "questions[1].question is required",
|
|
},
|
|
}
|
|
|
|
for _, testCase := range tests {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
err := validateAskUserQuestionArgs(testCase.args)
|
|
if testCase.wantErr == "" {
|
|
require.NoError(t, err)
|
|
return
|
|
}
|
|
|
|
require.EqualError(t, err, testCase.wantErr)
|
|
})
|
|
}
|
|
}
|
|
|
|
func validAskUserQuestionOptions(count int) []askUserQuestionOption {
|
|
options := []askUserQuestionOption{
|
|
{Label: "Backend", Description: "Build the API first."},
|
|
{Label: "Frontend", Description: "Build the UI first."},
|
|
{Label: "Docs", Description: "Write the docs first."},
|
|
{Label: "Tests", Description: "Start with tests first."},
|
|
{Label: "Research", Description: "Investigate the problem first."},
|
|
}
|
|
|
|
return append([]askUserQuestionOption(nil), options[:count]...)
|
|
}
|