Skip to content

feat(settings): full-screen agent definition editor with integrated prompt tab#589

Merged
zbigniewsobiecki merged 5 commits intodevfrom
feature/fullscreen-agent-definition-editor
Mar 1, 2026
Merged

feat(settings): full-screen agent definition editor with integrated prompt tab#589
zbigniewsobiecki merged 5 commits intodevfrom
feature/fullscreen-agent-definition-editor

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 1, 2026

Summary

  • Replace the narrow AgentDefinitionFormDialog modal with a new full-screen AgentDefinitionEditor component following the same full-page takeover pattern used by the existing PromptEditor
  • Add a System Prompt tab directly in the definition editor (edit mode only), so users can manage the agent's prompt without navigating to a separate tab
  • Remove the separate Prompts tab from the definitions page — prompt editing is now integrated into the editor; only Definitions and Partials tabs remain
  • Update AgentDefinitionsTable to accept an onEdit callback instead of managing its own internal dialog state

Key decisions

  • AgentDefinitionEditor is a plain <div> full-screen component (not a dialog), consistent with how PromptEditor works for partials/templates
  • Three tabs: "Definition" (form fields), "System Prompt" (edit-mode only, with its own Save/Reset), "Raw JSON" — main Save button is hidden on System Prompt tab since it has its own save flow
  • useDefinitionEditor hook extracted to keep the main component's cognitive complexity within the linter's allowed threshold
  • ReferencePanel exported from prompt-editor.tsx so it can be reused in SystemPromptPanel without duplication

Test plan

  • Navigate to Settings → Agent Definitions → click pencil icon on a definition → verify full-screen editor opens (no modal)
  • Verify three tabs visible: Definition, System Prompt, Raw JSON
  • Edit definition form fields → Save → verify update persisted
  • Click System Prompt tab → edit prompt → Save Prompt → verify custom badge appears
  • Click Reset to Default on System Prompt tab → verify revert works
  • Click Raw JSON tab → edit JSON → Save → verify update persisted
  • Click New Definition → verify editor opens with only Definition + Raw JSON tabs (no System Prompt tab in create mode)
  • Navigate to Partials tab → click pencil on a partial → verify partial editor still works
  • Verify "Prompts" tab is gone from the definitions page

Trello card: https://trello.com/c/69a41ed41d3e2867e47feeb2

🤖 Generated with Claude Code

Cascade Bot and others added 2 commits March 1, 2026 11:24
Replace the narrow AgentDefinitionFormDialog modal with a full-page
AgentDefinitionEditor component that follows the existing PromptEditor
pattern. The editor has three tabs: Definition (form fields), System
Prompt (prompt editing, edit mode only), and Raw JSON. Remove the
separate Prompts tab from the definitions page since prompt editing is
now integrated into the editor. Update AgentDefinitionsTable to accept
an onEdit callback instead of managing internal dialog state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…xity

Extract the editor state and mutations into a dedicated hook so the
AgentDefinitionEditor component stays within the complexity limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nhopeatall
Copy link
Copy Markdown
Collaborator

nhopeatall commented Mar 1, 2026

✨ On it — checking the fullscreen agent definition editor PR


Progress: [█░░░░░░░░░] 9% (iteration 6/70)

🔍 Code Review Update (1 min)

I've started reviewing PR #589, focusing on understanding the existing AgentDefinitionFormDialog and identifying any remaining references to it. I've used grep and glob to locate relevant files and am currently examining the PR diff. My next step is to verify my findings and then submit the review.

Last updated: iteration 6 · review

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Good architectural shift from modal dialog to full-screen editor, consistent with the existing PromptEditor pattern. However, the PR leaves dead code behind and introduces significant code duplication that should be addressed before merging.

Architecture & Design

  • [SHOULD_FIX] Dead code — agent-definition-form.tsx: The old AgentDefinitionFormDialog component in web/src/components/settings/agent-definition-form.tsx is no longer imported anywhere but remains in the repo. It should be deleted in this PR since this is the change that replaces it.

  • [SHOULD_FIX] Dead code — TemplateEditor in prompt-editor.tsx: The Prompts tab was removed from definitions.tsx, meaning PromptEditor is now only ever called with target.type === 'partial'. The TemplateEditor component (lines 21–176 of prompt-editor.tsx) is now unreachable dead code and should be cleaned up. The EditTarget type's template variant is also dead.

  • [SHOULD_FIX] Code duplication — SystemPromptPanel vs TemplateEditor: SystemPromptPanel (lines 513–665 of agent-definition-editor.tsx) is a near-verbatim copy of TemplateEditor (lines 21–176 of prompt-editor.tsx). Both implement the same save/reset/validate mutation pattern, the same useEffect for content loading, and the same UI layout. The main differences are cosmetic (header text, textarea height). Since TemplateEditor is now dead code, the simplest path is to delete it. But if prompt editing is needed as a standalone in the future, consider extracting a shared usePromptEditor hook to avoid re-duplication.

Code Issues

Should Fix

  • agent-definition-editor.tsx:513-516SystemPromptPanel is missing isDirty state tracking. The original TemplateEditor tracked isDirty (set on content change, cleared on save/reset). This was used to indicate unsaved changes. The new SystemPromptPanel doesn't track this, so users get no visual feedback about unsaved prompt changes. While there's no unsaved-changes guard in either version, dropping the tracking makes it harder to add one later and loses a useful UX signal.

  • definitions.tsx:140-142PartialEditorWrapper is a trivial pass-through wrapper (return <PromptEditor target={{ type: 'partial', name }} onClose={onClose} />). The comment says "Lazy import to avoid circular dep" but this is not a lazy import — it's a regular function call. If there's no actual circular dependency issue, inline this at the call site. If there is, use React.lazy() for an actual lazy import.

@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 1, 2026

Looking into the dead code and duplication now


Progress: [░░░░░░░░░░] 3% (iteration 2/70)

🔧 Review Response Update (1 min)

I've started addressing the code review feedback. My initial focus is on identifying and deleting dead code, specifically agent-definition-form.tsx and the TemplateEditor component within prompt-editor.tsx. I'm currently analyzing these files to ensure their safe removal.

Last updated: iteration 2 · respond-to-review

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Review already submitted above (REQUEST_CHANGES). See review comment for full details.

…acking

- Delete agent-definition-form.tsx (no longer imported)
- Remove TemplateEditor component and template variant from prompt-editor.tsx
- Add isDirty state tracking to SystemPromptPanel
- Inline PartialEditorWrapper in definitions.tsx

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 1, 2026

Review Feedback Addressed ✅

All review issues have been addressed:

Changes Made

  1. ✅ Deleted dead code - agent-definition-form.tsx: Removed the old AgentDefinitionFormDialog component that was no longer imported.

  2. ✅ Deleted dead code - TemplateEditor: Removed the unreachable TemplateEditor component (lines 21-176) and the template variant from the EditTarget type in prompt-editor.tsx, since the Prompts tab was removed.

  3. ✅ Added isDirty tracking: Added isDirty state to SystemPromptPanel in agent-definition-editor.tsx:

    • Sets isDirty(true) when content changes
    • Clears isDirty(false) in saveMutation.onSuccess and resetMutation.onSuccess
    • Sets isDirty(true) when loading default content
      This provides visual feedback for unsaved changes and makes it easier to add an unsaved-changes guard in the future.
  4. ✅ Inlined PartialEditorWrapper: Removed the trivial pass-through wrapper function and inlined the PromptEditor call directly at the call site in definitions.tsx.

Verification

  • ✅ All tests passing (3557 tests)
  • ✅ TypeScript type checking passing
  • ✅ Linter passing
  • ✅ Pre-commit hooks passing

@nhopeatall
Copy link
Copy Markdown
Collaborator

nhopeatall commented Mar 1, 2026

✨ On it — checking the fullscreen agent definition editor PR


Progress: [░░░░░░░░░░] 3% (iteration 2/70)

🔍 Code Review Update (1 min)

I've started reviewing the pull request by listing the files in web/src/components/settings/ to understand the scope of changes. My next step is to analyze the changed files and the architectural patterns to ensure quality and correctness.

Last updated: iteration 2 · review

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Solid refactoring — replacing the modal with a full-screen editor is a clear UX improvement, and integrating the system prompt tab reduces navigation friction. The extraction of useDefinitionEditor is clean, and the component decomposition is well done. A few things to consider:

Should Fix

  • agent-definition-editor.tsx:881 — The required attribute on the Agent Type <Input> is a leftover from the old <form> + onSubmit pattern. Since the form was replaced with a plain <div> and save uses onClickhandleSave(), native form validation never runs. A user can create a definition with an empty agent type string. Either add a manual check in handleSave (e.g. if (!agentType.trim()) return;) or wrap in a <form> again.

  • agent-definition-editor.tsx:517isDirty state in SystemPromptPanel is tracked (set on edit, cleared on save/reset) but never consumed for any purpose — no unsaved-changes warning, no conditional UI. It's dead state. Either remove it or use it (e.g. disable the Cancel/Back button, or show a confirmation before navigating away).

Nitpick

  • agent-definition-editor.tsx:744handleTabChange silently swallows JSON parse errors when switching from the "json" tab back to "definition" — the catch block just leaves the form as-is with no feedback to the user. The user could have invalid JSON, switch to the Definition tab, and not realize their JSON edits were lost. Consider showing a brief toast or keeping the user on the JSON tab with the error displayed.

value={agentType}
onChange={(e) => setAgentType(e.target.value)}
placeholder="e.g. implementation, review, debug"
required
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The required attribute here is a no-op since this is no longer inside a <form> element. handleSave() is triggered via onClick, so native HTML validation never fires. A user can create a definition with an empty agentType.

Consider adding a guard in handleSave:

if (!isEdit && !agentType.trim()) return;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. Removed the no-op required attribute and added a guard at the top of handleSave: if (!isEdit && !agentType.trim()) return; — this prevents saving with an empty agent type in create mode.

const queryClient = useQueryClient();
const [content, setContent] = useState('');
const [validationStatus, setValidationStatus] = useState<string | null>(null);
const [isDirty, setIsDirty] = useState(false);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

isDirty is set on edit and cleared on save/reset, but its value is never read anywhere — no unsaved-changes guard, no conditional UI. This is dead state that should either be removed or put to use (e.g., warn before navigating away via the Back/Cancel buttons).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. Removed the dead isDirty state entirely — it was being set but never read anywhere. The mutation callbacks and the loadDefault/onChange handlers no longer reference it.

try {
setDef(JSON.parse(jsonText) as AgentDefinition);
setJsonError(null);
} catch {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Minor: when the user has invalid JSON and switches to the Definition tab, the parse error is silently swallowed and their JSON edits are discarded. Consider keeping the user on the JSON tab with a visible error, similar to what handleSave does (line 758-759).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed. handleTabChange now catches the JSON parse error, sets jsonError with the error message, and returns early — keeping the user on the JSON tab so they can see and fix the error instead of silently swallowing it.

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

LGTM with minor suggestions — see inline comments on earlier review.

@zbigniewsobiecki
Copy link
Copy Markdown
Member

@aaight address code review concerns

@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 1, 2026

Request Addressed

What was asked

Address the remaining code review concerns from @nhopeatall's inline comments.

Changes Made

  • Empty agentType guard: Added if (!isEdit && !agentType.trim()) return; at the top of handleSave and removed the no-op required attribute (not inside a <form>, so native validation never fired)
  • Dead isDirty state removed: Removed isDirty state and all its setters from SystemPromptPanel — it was being tracked but never read anywhere
  • JSON parse error surfaced on tab switch: handleTabChange now catches invalid JSON, displays the error via jsonError, and keeps the user on the JSON tab (matching handleSave behavior) instead of silently swallowing the error

Verification

  • Biome lint: passing (0 errors)
  • TypeScript: passing (0 errors)
  • Unit tests: passing
  • Pre-commit hooks (lint + typecheck + commitlint): all passed

- Add guard in handleSave to prevent saving with empty agentType in create mode
- Remove no-op `required` attribute from Agent Type input (not in a <form>)
- Remove dead `isDirty` state from SystemPromptPanel (was set but never read)
- Show JSON parse error and keep user on JSON tab when switching to Definition
  tab with invalid JSON, instead of silently swallowing the error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nhopeatall
Copy link
Copy Markdown
Collaborator

nhopeatall commented Mar 1, 2026

✨ On it — checking the fullscreen agent definition editor PR


Progress: [░░░░░░░░░░] 3% (iteration 2/70)

🔍 Code Review Update (1 min)

I've started by reviewing the pull request changes to understand the modifications. I'm currently examining the diff and will specifically check for any import path issues, as a file rename was involved. My next step is to ensure the changes are correct and maintain code quality.

Last updated: iteration 2 · review

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Clean refactoring that lifts the agent definition editor from a modal dialog to a full-screen view and integrates system prompt editing inline. The architecture is improved: state management is better separated via useDefinitionEditor, the table component is properly decoupled from the editor via the onEdit callback, and the user flow is more consistent (definitions, prompts, and partials all use the same full-screen editing pattern).

Should Fix

  • agent-definition-editor.tsx:877 — The required attribute was removed from the Agent Type <Input> in create mode. While handleSave silently bails with if (!isEdit && !agentType.trim()) return, the user gets no feedback — the save button appears clickable but nothing happens. Consider either restoring required (with a wrapping <form> for native validation) or adding an inline error message when the field is empty.

Minor Suggestions

  • prompt-editor.tsx:7EditTarget is now a single-variant type ({ type: 'partial'; name: string }). The type discriminator is vestigial since the template variant was removed and PromptEditor just delegates to PartialEditor directly. Consider simplifying the interface to accept { name: string } instead — though this can wait for a follow-up.

  • agent-definition-editor.tsx:737 — The handleTabChange bidirectional JSON↔form sync is a nice improvement over the old one-way sync. Good catch adding the JSON→form direction.

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Clean refactoring that lifts the agent definition editor from a modal dialog to a full-screen view and integrates system prompt editing inline. The architecture is improved: state management is better separated via useDefinitionEditor, the table component is properly decoupled via the onEdit callback, and the user flow is more consistent.

Should Fix

  • agent-definition-editor.tsx:877 — The required attribute was removed from the Agent Type Input in create mode. While handleSave silently bails with if (!isEdit && !agentType.trim()) return, the user gets no feedback — the save button appears clickable but nothing happens. Consider restoring required or adding an inline error message.

Minor Suggestions

  • prompt-editor.tsx:7 — EditTarget is now a single-variant type. The type discriminator is vestigial. Consider simplifying to accept { name: string } in a follow-up.

@zbigniewsobiecki
Copy link
Copy Markdown
Member

@aaight address code review concerns

@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 1, 2026

Request Addressed

What was asked

Address the remaining code review concerns from @nhopeatall's latest review round.

Changes Made

  • Empty agent type feedback: handleSave now shows an inline error message and highlights the input with a destructive border when agentType is empty, instead of silently returning. The error clears when the user starts typing.
  • Simplified EditTarget type: Removed the vestigial type: 'partial' discriminator from the single-variant EditTarget type in prompt-editor.tsx, and updated the call site in definitions.tsx.

Verification

  • Biome lint passing (0 errors)
  • TypeScript typecheck passing (no new errors)
  • All unit tests passing
  • Pre-commit hooks (lint, typecheck, commitlint) all passed

- Show inline error message when user tries to save with empty agent type
  in create mode, instead of silently bailing out
- Highlight the input field with destructive border on validation error
- Clear the error when user starts typing
- Remove vestigial `type` discriminator from single-variant EditTarget type

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Mar 1, 2026

Addressed the remaining review concerns from @nhopeatall's latest review:

  1. Empty agent type feedback (agent-definition-editor.tsx:877) — handleSave no longer silently bails when agentType is empty. It now sets an agentTypeError state that:

    • Shows an inline error message ("Agent type is required.") below the input
    • Highlights the input with a destructive (red) border
    • Clears automatically when the user starts typing
  2. Vestigial EditTarget type (prompt-editor.tsx:7) — Simplified the single-variant EditTarget type by removing the type: 'partial' discriminator. The type is now just { name: string }, and the call site in definitions.tsx was updated accordingly.

Commit: 8460986

@nhopeatall
Copy link
Copy Markdown
Collaborator

nhopeatall commented Mar 1, 2026

✨ On it — checking the fullscreen agent definition editor PR


Progress: [░░░░░░░░░░] 3% (iteration 2/70)

🔍 Code Review Update (1 min)

I've successfully loaded all necessary context from the pre-loaded data. I'm now beginning a systematic analysis of the pull request. My initial assessment is that the PR replaces a modal dialog (AgentDefinitionFormDialog) with a full-page component.

Last updated: iteration 2 · review

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

Clean implementation of a full-screen agent definition editor with integrated system prompt tab. Previous review feedback has been addressed. The architecture is consistent with the existing PromptEditor full-page takeover pattern, and the component decomposition is well done.

Notes

  • The useDefinitionEditor hook extraction is a good way to manage complexity, keeping the main component focused on rendering.
  • ReferencePanel reuse from prompt-editor.tsx avoids duplication — good call exporting it rather than duplicating.
  • Tab synchronization between form/JSON views is correctly handled — JSON parse errors block the tab switch and show an error, matching the PR description.
  • The existing?.agentType ?? '' fallback on line 961 is safe since it's guarded by isEdit (which is !!existing).
  • All prior review comments (no-op required attribute, dead isDirty state, silent JSON error swallowing) have been addressed in follow-up commits.
  • CI checks all pass.

No blocking or should-fix issues found.

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

LGTM - Clean implementation consistent with existing patterns. All prior review feedback addressed.

@zbigniewsobiecki zbigniewsobiecki merged commit e158393 into dev Mar 1, 2026
6 checks passed
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.

3 participants