-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Feat: Support Recipe Parameters in Goose desktop app #3155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
angiejones
merged 16 commits into
block:main
from
AaronGoldsmith:ag/feat-desktop-recipe-params
Jul 2, 2025
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
34ae360
feat: add parameter handling in recipe and chat components
AaronGoldsmith ffedce4
wip: add parameter interface
AaronGoldsmith 370cbfd
remove unused imports and fix eslint issues
AaronGoldsmith 400850c
update todo
AaronGoldsmith 3ffb6e1
feat: enhance parameter handling with logging and validation improvemβ¦
AaronGoldsmith 8e89bf4
feat: implement parameter substitution in system prompt update
AaronGoldsmith a585e97
feat: enhance ParameterInputModal with validation and cancel options
AaronGoldsmith 6f0c02c
remove todos
AaronGoldsmith 6f08a03
feat: update parameter requirement type from 'interactive' to 'user_pβ¦
AaronGoldsmith 9e4bd22
fix: update parameter handling in RecipeEditor to include prompt chanβ¦
AaronGoldsmith 2d41dd8
Merge branch 'main' into ag/feat-desktop-recipe-params
AaronGoldsmith 4ad4ea9
refactor: remove console logging from parameter substitution functions
AaronGoldsmith 8e8b042
address feedback
AaronGoldsmith 2f29d52
Removed unused js-yaml
AaronGoldsmith 04bf72c
Merge branch 'main' into ag/feat-desktop-recipe-params
AaronGoldsmith e314a58
refactor: remove success log from updateSystemPromptWithParameters
AaronGoldsmith File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| import React, { useState, useEffect } from 'react'; | ||
| import { Parameter } from '../recipe'; | ||
| import { Button } from './ui/button'; | ||
|
|
||
| interface ParameterInputModalProps { | ||
| parameters: Parameter[]; | ||
| onSubmit: (values: Record<string, string>) => void; | ||
| onClose: () => void; | ||
| } | ||
|
|
||
| const ParameterInputModal: React.FC<ParameterInputModalProps> = ({ | ||
| parameters, | ||
| onSubmit, | ||
| onClose, | ||
| }) => { | ||
| const [inputValues, setInputValues] = useState<Record<string, string>>({}); | ||
| const [validationErrors, setValidationErrors] = useState<Record<string, string>>({}); | ||
| const [showCancelOptions, setShowCancelOptions] = useState(false); | ||
|
|
||
| // Pre-fill the form with default values from the recipe | ||
| useEffect(() => { | ||
| const initialValues: Record<string, string> = {}; | ||
| parameters.forEach((param) => { | ||
| if (param.default) { | ||
| initialValues[param.key] = param.default; | ||
| } | ||
| }); | ||
| setInputValues(initialValues); | ||
| }, [parameters]); | ||
|
|
||
| const handleChange = (name: string, value: string): void => { | ||
| setInputValues((prevValues: Record<string, string>) => ({ ...prevValues, [name]: value })); | ||
| }; | ||
|
|
||
| const handleSubmit = (): void => { | ||
| // Clear previous validation errors | ||
| setValidationErrors({}); | ||
|
|
||
| // Check if all *required* parameters are filled | ||
| const requiredParams: Parameter[] = parameters.filter((p) => p.requirement === 'required'); | ||
| const errors: Record<string, string> = {}; | ||
|
|
||
| requiredParams.forEach((param) => { | ||
| const value = inputValues[param.key]?.trim(); | ||
| if (!value) { | ||
| errors[param.key] = `${param.description || param.key} is required`; | ||
| } | ||
| }); | ||
|
|
||
| if (Object.keys(errors).length > 0) { | ||
| setValidationErrors(errors); | ||
| return; | ||
| } | ||
|
|
||
| onSubmit(inputValues); | ||
| }; | ||
|
|
||
| const handleCancel = (): void => { | ||
| // Always show cancel options if recipe has any parameters (required or optional) | ||
| const hasAnyParams = parameters.length > 0; | ||
|
|
||
| if (hasAnyParams) { | ||
| setShowCancelOptions(true); | ||
| } else { | ||
| onClose(); | ||
| } | ||
| }; | ||
|
|
||
| const handleCancelOption = (option: 'new-chat' | 'back-to-form'): void => { | ||
| if (option === 'new-chat') { | ||
| // Create a new chat window without recipe config | ||
| try { | ||
| const workingDir = window.appConfig.get('GOOSE_WORKING_DIR'); | ||
| console.log(`Creating new chat window without recipe, working dir: ${workingDir}`); | ||
| window.electron.createChatWindow(undefined, workingDir as string); | ||
| // Close the current window after creating the new one | ||
| window.electron.hideWindow(); | ||
| } catch (error) { | ||
| console.error('Error creating new window:', error); | ||
| // Fallback: just close the modal | ||
| onClose(); | ||
| } | ||
| } else { | ||
| setShowCancelOptions(false); // Go back to the parameter form | ||
| } | ||
| }; | ||
|
|
||
| return ( | ||
| <div className="fixed inset-0 backdrop-blur-sm z-50 flex justify-center items-center animate-[fadein_200ms_ease-in]"> | ||
| {showCancelOptions ? ( | ||
| // Cancel options modal | ||
| <div className="bg-bgApp border border-borderSubtle rounded-xl p-8 shadow-2xl w-full max-w-md"> | ||
| <h2 className="text-xl font-bold text-textProminent mb-4">Cancel Recipe Setup</h2> | ||
| <p className="text-textStandard mb-6">What would you like to do?</p> | ||
| <div className="flex flex-col gap-3"> | ||
| <Button | ||
| onClick={() => handleCancelOption('back-to-form')} | ||
| variant="default" | ||
| size="lg" | ||
| className="w-full rounded-full" | ||
| > | ||
| Back to Parameter Form | ||
| </Button> | ||
| <Button | ||
| onClick={() => handleCancelOption('new-chat')} | ||
| variant="outline" | ||
| size="lg" | ||
| className="w-full rounded-full" | ||
| > | ||
| Start New Chat (No Recipe) | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| ) : ( | ||
| // Main parameter form | ||
| <div className="bg-bgApp border border-borderSubtle rounded-xl p-8 shadow-2xl w-full max-w-lg"> | ||
| <h2 className="text-xl font-bold text-textProminent mb-6">Recipe Parameters</h2> | ||
| <form onSubmit={handleSubmit} className="space-y-4"> | ||
| {parameters.map((param) => ( | ||
| <div key={param.key}> | ||
| <label className="block text-md font-medium text-textStandard mb-2"> | ||
| {param.description || param.key} | ||
| {param.requirement === 'required' && <span className="text-red-500 ml-1">*</span>} | ||
| </label> | ||
| <input | ||
| type="text" | ||
| value={inputValues[param.key] || ''} | ||
| onChange={(e) => handleChange(param.key, e.target.value)} | ||
| className={`w-full p-3 border rounded-lg bg-bgSubtle text-textStandard focus:outline-none focus:ring-2 ${ | ||
| validationErrors[param.key] | ||
| ? 'border-red-500 focus:ring-red-500' | ||
| : 'border-borderSubtle focus:ring-borderProminent' | ||
| }`} | ||
| placeholder={param.default || `Enter value for ${param.key}...`} | ||
| /> | ||
| {validationErrors[param.key] && ( | ||
| <p className="text-red-500 text-sm mt-1">{validationErrors[param.key]}</p> | ||
| )} | ||
| </div> | ||
| ))} | ||
| <div className="flex justify-end gap-4 pt-6"> | ||
| <Button | ||
| type="button" | ||
| onClick={handleCancel} | ||
| variant="outline" | ||
| size="default" | ||
| className="rounded-full" | ||
| > | ||
| Cancel | ||
| </Button> | ||
| <Button type="submit" variant="default" size="default" className="rounded-full"> | ||
| Start Recipe | ||
| </Button> | ||
| </div> | ||
| </form> | ||
| </div> | ||
| )} | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default ParameterInputModal; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can remove?