Default agent auto-run prompt modified tab now drops tabs inside of large text inputs

This commit is contained in:
Pedram Amini
2025-12-09 15:51:16 -06:00
parent 5d9191d289
commit 3c2fedaba7
7 changed files with 149 additions and 24 deletions

View File

@@ -619,6 +619,33 @@ describe('AgentPromptComposerModal', () => {
});
describe('textarea interaction', () => {
it('inserts tab character on Tab key', async () => {
// Use "HelloWorld" without space so tab insertion is clearer
renderWithLayerStack(
<AgentPromptComposerModal
isOpen={true}
onClose={vi.fn()}
theme={theme}
initialValue="HelloWorld"
onSubmit={vi.fn()}
/>
);
const textarea = screen.getByPlaceholderText(
'Enter your agent prompt... (type {{ for variables)'
) as HTMLTextAreaElement;
// Set cursor position after "Hello"
textarea.selectionStart = 5;
textarea.selectionEnd = 5;
await act(async () => {
fireEvent.keyDown(textarea, { key: 'Tab' });
});
expect(textarea.value).toBe('Hello\tWorld');
});
it('updates value when typing', async () => {
renderWithLayerStack(
<AgentPromptComposerModal

View File

@@ -354,6 +354,25 @@ describe('AutoRun', () => {
});
describe('Keyboard Shortcuts', () => {
it('inserts tab character on Tab key', async () => {
// Use "HelloWorld" without space so tab insertion is clearer
const props = createDefaultProps({ content: 'HelloWorld' });
render(<AutoRun {...props} />);
const textarea = screen.getByRole('textbox') as HTMLTextAreaElement;
fireEvent.focus(textarea);
// Set cursor position after "Hello"
textarea.selectionStart = 5;
textarea.selectionEnd = 5;
fireEvent.keyDown(textarea, { key: 'Tab' });
await waitFor(() => {
expect(textarea.value).toBe('Hello\tWorld');
});
});
it('toggles mode on Cmd+E', async () => {
const props = createDefaultProps({ mode: 'edit' });
render(<AutoRun {...props} />);

View File

@@ -495,6 +495,25 @@ describe('BatchRunnerModal', () => {
});
describe('Agent Prompt', () => {
it('inserts tab character on Tab key', async () => {
render(<BatchRunnerModal {...createDefaultProps()} />);
const textarea = screen.getByPlaceholderText('Enter the prompt for the batch agent...') as HTMLTextAreaElement;
// Clear and set a simple value (no space - "HelloWorld")
fireEvent.change(textarea, { target: { value: 'HelloWorld' } });
// Set cursor position after "Hello"
textarea.selectionStart = 5;
textarea.selectionEnd = 5;
fireEvent.keyDown(textarea, { key: 'Tab' });
await waitFor(() => {
expect(textarea.value).toBe('Hello\tWorld');
});
});
it('displays default prompt in textarea', async () => {
render(<BatchRunnerModal {...createDefaultProps()} />);

View File

@@ -104,6 +104,21 @@ export function AgentPromptComposerModal({
if (handleAutocompleteKeyDown(e)) {
return;
}
// Insert actual tab character instead of moving focus
if (e.key === 'Tab') {
e.preventDefault();
const textarea = e.currentTarget;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const newValue = value.substring(0, start) + '\t' + value.substring(end);
setValue(newValue);
// Restore cursor position after the tab
requestAnimationFrame(() => {
textarea.selectionStart = start + 1;
textarea.selectionEnd = start + 1;
});
}
};
const tokenCount = estimateTokenCount(value);

View File

@@ -1248,6 +1248,28 @@ const AutoRunInner = forwardRef<AutoRunHandle, AutoRunProps>(function AutoRunInn
return;
}
// Insert actual tab character instead of moving focus
if (e.key === 'Tab') {
e.preventDefault();
const textarea = e.currentTarget;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
// Push undo state before modifying content
pushUndoState();
const newContent = localContent.substring(0, start) + '\t' + localContent.substring(end);
setLocalContent(newContent);
lastUndoSnapshotRef.current = newContent;
// Restore cursor position after the tab
requestAnimationFrame(() => {
textarea.selectionStart = start + 1;
textarea.selectionEnd = start + 1;
});
return;
}
// Cmd+Z to undo, Cmd+Shift+Z to redo
if ((e.metaKey || e.ctrlKey) && e.key === 'z') {
e.preventDefault();

View File

@@ -17,6 +17,9 @@ Your name is **{{AGENT_NAME}}**, a Maestro-managed AI agent.
- **Git Branch:** {{GIT_BRANCH}}
- **Auto Run Folder:** {{AUTORUN_FOLDER}}
- **Loop Iteration:** {{LOOP_NUMBER}}
- **Working Folder for Temporary Files:** {{AUTORUN_FOLDER}}/Working
If you need to create the working folder, do so.
---
@@ -26,20 +29,23 @@ Your name is **{{AGENT_NAME}}**, a Maestro-managed AI agent.
Begin by reviewing CLAUDE.md (when available) in this folder to understand the project's structure, conventions, and workflow expectations.
2. Task Selection
Process the FIRST unchecked task (- [ ]) from top to bottom. Note that there may be relevant images associated with the task, analyze them, and include in your final synopsis back how many images you analyzed in preparation for solving the task.
Process the FIRST unchecked task (- [ ]) from top to bottom. Note that there may be relevant images associated with the task. If there are, analyze them, and include in your final synopsis back how many images you analyzed in preparation for solving the task.
IMPORTANT: You will only work on this single task. If it appears to have logical subtasks, treat them as one cohesive unit—but do not move on to the next top-level task.
IMPORTANT: You will only work on this single task. If it appears to have logical subtasks, treat them as one cohesive unit—but do not move on to the next major item.
3. Task Evaluation
- Fully understand the task and inspect the relevant code.
- If you determine the task should not be executed, mark it as completed anyway and record a concise explanation of why it was skipped directly in the document.
- If upon examining the code carefully you decide there is a better approach, take it, and document record a detailed explanation of why directly in the document.
- Determine which tasks you're going to work on in this run.
- There will be future runs to take care of other tasks.
- Your goal is to select enough items from the top of the unfinished list that make sense to work on within the same context window.
4. Task Implementation
Implement the task according to the project's established style, architecture, and coding norms.
- Implement the task according to the project's established style, architecture, and coding norms.
- Ensure that test cases are created, and that they pass.
- Ensure you haven't broken any existing test cases.
5. Completion + Reporting
- Mark the task as completed in the scratchpad by changing - [ ] to - [x].
- Mark the task as completed by changing "- [ ]" to "- [x]".
- CRITICAL: Your FIRST sentence MUST be a specific synopsis of what you accomplished (e.g., "Added pagination to the user list component" or "Refactored auth middleware to use JWT tokens"). Never start with generic phrases like "Task completed successfully" - always lead with the specific work done.
- Follow with any relevant details about:
- Implementation approach or key decisions made
@@ -48,16 +54,12 @@ Your name is **{{AGENT_NAME}}**, a Maestro-managed AI agent.
6. Version Control
For any code or documentation changes, if we're in a Github repo:
- Commit using a descriptive message prefixed with MAESTRO:.
- Commit using a descriptive message prefixed with "MAESTRO: ".
- Push to GitHub.
- Update CLAUDE.md, README.md, or any other top-level documentation if appropriate.
7. Exit Immediately
After completing (or skipping) the single task, EXIT. Do not proceed to additional tasks—another agent instance will handle them.
NOTE: If you see a clear issue tag like a little moniker or some short form in front of the task, then your synopsis message should start with that exact token because we're clearly using it as a unique identifier.
If there are no remaining open tasks, exit immediately and state that there is nothing left to do.
After completing (or skipping) your task, EXIT. Do not proceed to additional tasks—another agent instance will handle them. If there are no remaining open tasks, exit immediately and state that there is nothing left to do.
---
@@ -67,7 +69,7 @@ Process tasks from this document:
{{DOCUMENT_PATH}}
Save changes directly in that file.`;
Check of tasks and add any relevant notes around the completion directly within that document.`;
interface BatchRunnerModalProps {
theme: Theme;
@@ -1854,6 +1856,22 @@ export function BatchRunnerModal(props: BatchRunnerModalProps) {
ref={textareaRef}
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
onKeyDown={(e) => {
// Insert actual tab character instead of moving focus
if (e.key === 'Tab') {
e.preventDefault();
const textarea = e.currentTarget;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const newValue = prompt.substring(0, start) + '\t' + prompt.substring(end);
setPrompt(newValue);
// Restore cursor position after the tab
requestAnimationFrame(() => {
textarea.selectionStart = start + 1;
textarea.selectionEnd = start + 1;
});
}
}}
className="w-full p-4 pr-10 rounded border bg-transparent outline-none resize-none font-mono text-sm"
style={{
borderColor: theme.colors.border,

View File

@@ -468,17 +468,22 @@ ${docList}
}));
// AUTORUN LOG: Start
console.log('[AUTORUN] Logging start event');
window.maestro.logger.autorun(
`Auto Run started`,
session.name,
{
documents: documents.map(d => d.filename),
totalTasks: initialTotalTasks,
loopEnabled,
maxLoops: maxLoops ?? 'unlimited'
}
);
try {
console.log('[AUTORUN] Logging start event - calling window.maestro.logger.autorun');
window.maestro.logger.autorun(
`Auto Run started`,
session.name,
{
documents: documents.map(d => d.filename),
totalTasks: initialTotalTasks,
loopEnabled,
maxLoops: maxLoops ?? 'unlimited'
}
);
console.log('[AUTORUN] Start event logged successfully');
} catch (err) {
console.error('[AUTORUN] Error logging start event:', err);
}
// Store custom prompt for persistence
setCustomPrompts(prev => ({ ...prev, [sessionId]: prompt }));