| 1 | <html> |
| 2 | <head> |
| 3 | <title>Agent Editor</title> |
| 4 | <script type="module"> |
| 5 | import { store } from "/plugins/_agent_editor/webui/agent-editor-store.js"; |
| 6 | </script> |
| 7 | </head> |
| 8 | <body> |
| 9 | <div x-data class="agent-editor" x-init="await $store.agentEditor.mount($el)" |
| 10 | @keydown.ctrl.s.prevent="$store.agentEditor.save(false)" |
| 11 | @keydown.meta.s.prevent="$store.agentEditor.save(false)"> |
| 12 | <template x-if="$store.agentEditor.error"> |
| 13 | <div class="agent-editor-error" role="alert"> |
| 14 | <x-icon name="error"></x-icon> |
| 15 | <span x-text="$store.agentEditor.error"></span> |
| 16 | <button type="button" class="button icon" aria-label="Dismiss error" @click="$store.agentEditor.error = ''"><x-icon name="close"></x-icon></button> |
| 17 | </div> |
| 18 | </template> |
| 19 | |
| 20 | <template x-if="$store.agentEditor.loading"> |
| 21 | <div class="agent-editor-loading" role="status"> |
| 22 | <x-icon class="spinning" name="progress_activity"></x-icon> |
| 23 | <span>Loading agent…</span> |
| 24 | </div> |
| 25 | </template> |
| 26 | |
| 27 | <template x-if="!$store.agentEditor.loading && $store.agentEditor.view === 'manage'"> |
| 28 | <section class="agent-manager" aria-label="Manage agents"> |
| 29 | <div class="agent-scope-selector"> |
| 30 | <label class="agent-scope-field"> |
| 31 | <span>Project</span> |
| 32 | <select x-model="$store.agentEditor.projectName" |
| 33 | x-init="$nextTick(() => $el.value = $store.agentEditor.projectName)" |
| 34 | @change="$store.agentEditor.onScopeChanged()"> |
| 35 | <option value="">Global</option> |
| 36 | <template x-for="project in $store.agentEditor.projects" :key="project.key"> |
| 37 | <option :value="project.key" x-text="project.label"></option> |
| 38 | </template> |
| 39 | </select> |
| 40 | </label> |
| 41 | </div> |
| 42 | <div class="agent-manager-list-header"> |
| 43 | <template x-if="$store.agentEditor.activeProfile()"> |
| 44 | <div class="active-agent-display"> |
| 45 | <span class="active-agent-summary"> |
| 46 | <span>Active:</span> |
| 47 | <span class="active-agent-avatar" aria-hidden="true" :style="`background:${$store.agentEditor.profileVisual($store.agentEditor.activeProfile()).color}`"> |
| 48 | <img x-show="$store.agentEditor.profileVisual($store.agentEditor.activeProfile()).url" :src="$store.agentEditor.profileVisual($store.agentEditor.activeProfile()).url" alt=""> |
| 49 | <span x-show="!$store.agentEditor.profileVisual($store.agentEditor.activeProfile()).url" x-text="$store.agentEditor.profileVisual($store.agentEditor.activeProfile()).initials"></span> |
| 50 | </span> |
| 51 | <strong x-text="$store.agentEditor.activeProfile().title || $store.agentEditor.activeProfile().id"></strong> |
| 52 | </span> |
| 53 | <button type="button" class="button icon-button" x-show="$store.agentEditor.activeProfile().id !== 'default'" title="Edit" :aria-label="`Edit ${$store.agentEditor.activeProfile().title || $store.agentEditor.activeProfile().id}`" @click="$store.agentEditor.loadEditor($store.agentEditor.activeProfile().id, false)"><x-icon class="icon" name="edit"></x-icon></button> |
| 54 | </div> |
| 55 | </template> |
| 56 | <button type="button" class="button agent-manager-create" @click="$store.agentEditor.loadEditor('new-agent', true)"><x-icon class="icon" name="add"></x-icon>Create agent</button> |
| 57 | </div> |
| 58 | <div class="agent-manager-list"> |
| 59 | <template x-for="profile in $store.agentEditor.visibleProfiles" :key="profile.id"> |
| 60 | <article class="agent-manager-card"> |
| 61 | <div class="agent-manager-avatar" :style="`background:${$store.agentEditor.profileVisual(profile).color}`"> |
| 62 | <img x-show="$store.agentEditor.profileVisual(profile).url" :src="$store.agentEditor.profileVisual(profile).url" :alt="`${profile.title || profile.id} avatar`"> |
| 63 | <span x-show="!$store.agentEditor.profileVisual(profile).url" x-text="$store.agentEditor.profileVisual(profile).initials"></span> |
| 64 | </div> |
| 65 | <div class="agent-manager-copy"> |
| 66 | <div class="agent-manager-name"> |
| 67 | <strong x-text="profile.title || profile.id"></strong> |
| 68 | <span class="agent-origin" x-text="profile.origin"></span> |
| 69 | </div> |
| 70 | <p x-text="profile.description || 'No description'"></p> |
| 71 | <button type="button" class="text-button agent-manager-inline-action" |
| 72 | :disabled="!!$store.agentEditor.duplicatingProfile" |
| 73 | :aria-label="`Duplicate ${profile.title || profile.id}`" |
| 74 | @click="$store.agentEditor.duplicateProfile(profile)"> |
| 75 | <x-icon name="content_copy"></x-icon><span>Duplicate</span> |
| 76 | </button> |
| 77 | <button type="button" class="text-button agent-manager-inline-action" |
| 78 | x-show="profile.scope_has_overrides && !profile.deletable" |
| 79 | :disabled="$store.agentEditor.saving" |
| 80 | :aria-label="`Reset ${profile.title || profile.id} to default`" |
| 81 | @click="$store.agentEditor.restoreProfile(profile)"> |
| 82 | <x-icon name="restore"></x-icon><span>Reset to default</span> |
| 83 | </button> |
| 84 | </div> |
| 85 | <div class="agent-manager-actions"> |
| 86 | <label class="toggle agent-profile-availability" |
| 87 | :title="`${profile.enabled ? 'Make unavailable' : 'Make available'} in ${$store.agentEditor.scopeLabel}`"> |
| 88 | <input type="checkbox" |
| 89 | :checked="profile.enabled" |
| 90 | :disabled="$store.agentEditor.profileAvailabilitySaving" |
| 91 | :aria-label="`${profile.enabled ? 'Disable' : 'Enable'} ${profile.title || profile.id} in ${$store.agentEditor.scopeLabel}`" |
| 92 | @change="$store.agentEditor.setProfileEnabled(profile, $event.target.checked)" |
| 93 | @click.stop> |
| 94 | <span class="toggler"></span> |
| 95 | </label> |
| 96 | <button type="button" class="button icon-button" title="Edit" :aria-label="`Edit ${profile.title || profile.id}`" @click="$store.agentEditor.loadEditor(profile.id, false)"><x-icon class="icon" name="edit"></x-icon></button> |
| 97 | <button type="button" class="button cancel icon-button" x-show="profile.deletable" title="Delete" :aria-label="`Delete ${profile.title || profile.id}`" @click="$store.agentEditor.deleteProfile(profile.id)"><x-icon class="icon" name="delete"></x-icon></button> |
| 98 | </div> |
| 99 | </article> |
| 100 | </template> |
| 101 | </div> |
| 102 | </section> |
| 103 | </template> |
| 104 | |
| 105 | <template x-if="!$store.agentEditor.loading && $store.agentEditor.view === 'editor' && $store.agentEditor.draft"> |
| 106 | <div class="agent-editor-workspace"> |
| 107 | <header class="agent-editor-topbar"> |
| 108 | <div class="agent-editor-heading"> |
| 109 | <button type="button" class="button icon" x-show="$store.agentEditor.intent.view === 'manage'" aria-label="Back to agents" @click="$store.agentEditor.showManager()"><x-icon name="arrow_back"></x-icon></button> |
| 110 | <label class="agent-scope-field agent-editor-scope"> |
| 111 | <span>Project</span> |
| 112 | <select x-model="$store.agentEditor.projectName" |
| 113 | x-init="$nextTick(() => $el.value = $store.agentEditor.projectName)" |
| 114 | @change="$store.agentEditor.onScopeChanged()"> |
| 115 | <option value="">Global</option> |
| 116 | <template x-for="project in $store.agentEditor.projects" :key="project.key"> |
| 117 | <option :value="project.key" x-text="project.label"></option> |
| 118 | </template> |
| 119 | </select> |
| 120 | </label> |
| 121 | <div class="agent-editor-subtitle" x-show="$store.agentEditor.dirty"> |
| 122 | <span class="agent-status-badge is-unsaved"><x-icon name="edit_note"></x-icon><span>Unsaved changes</span></span> |
| 123 | </div> |
| 124 | </div> |
| 125 | <div class="agent-editor-topbar-actions"> |
| 126 | <div class="agent-mode-switch" role="group" aria-label="Editor mode"> |
| 127 | <button type="button" :class="{ active: $store.agentEditor.mode === 'easy' }" :aria-pressed="$store.agentEditor.mode === 'easy'" @click="$store.agentEditor.setMode('easy')">Easy</button> |
| 128 | <button type="button" :class="{ active: $store.agentEditor.mode === 'advanced' }" :aria-pressed="$store.agentEditor.mode === 'advanced'" @click="$store.agentEditor.setMode('advanced')">Advanced</button> |
| 129 | </div> |
| 130 | </div> |
| 131 | </header> |
| 132 | |
| 133 | <main class="agent-easy" x-show="$store.agentEditor.mode === 'easy'"> |
| 134 | <section class="agent-easy-identity"> |
| 135 | <div class="agent-avatar-wrap"> |
| 136 | <div class="agent-avatar" :style="`background:${$store.agentEditor.avatarColor()}`"> |
| 137 | <img x-show="$store.agentEditor.draft.avatar?.kind === 'image' && $store.agentEditor.draft.avatarPreview" :src="$store.agentEditor.draft.avatarPreview" alt="Avatar crop preview"> |
| 138 | <span x-show="$store.agentEditor.draft.avatar?.kind !== 'image' || !$store.agentEditor.draft.avatarPreview" x-text="$store.agentEditor.initials()"></span> |
| 139 | <div class="avatar-progress" x-show="$store.agentEditor.avatarUploading" aria-label="Uploading avatar"><x-icon class="spinning" name="progress_activity"></x-icon></div> |
| 140 | </div> |
| 141 | <div class="agent-avatar-actions"> |
| 142 | <label class="avatar-action-icon avatar-color-action" title="Choose color"><x-icon name="palette"></x-icon><span class="sr-only">Choose color</span><input type="color" :value="$store.agentEditor.avatarColor()" @input="$store.agentEditor.chooseAvatarColor($event.target.value)" aria-label="Choose avatar color"></label> |
| 143 | <label class="avatar-action-icon avatar-upload-action" title="Upload image"><x-icon name="add_photo_alternate"></x-icon><span class="sr-only">Upload image</span><input type="file" accept="image/png,image/jpeg,image/webp" @change="$store.agentEditor.uploadAvatar($event)" aria-label="Upload avatar image"></label> |
| 144 | <button type="button" class="text-button" x-show="$store.agentEditor.state.profile.metadata.avatar.has_override || $store.agentEditor.draft.avatar" @click="$store.agentEditor.resetAvatar()">Reset</button> |
| 145 | </div> |
| 146 | </div> |
| 147 | <div class="agent-easy-identity-fields"> |
| 148 | <div class="agent-field agent-name-field"> |
| 149 | <label for="agent-editor-name" class="agent-field-label">Agent name</label> |
| 150 | <input id="agent-editor-name" type="text" x-model="$store.agentEditor.draft.title" @input="$store.agentEditor.onNameInput(); $store.agentEditor.markMetadataSet('title')" required autocomplete="off" :aria-invalid="$store.agentEditor.fieldIssue('name') ? 'true' : null" :aria-describedby="$store.agentEditor.fieldIssue('name') ? 'agent-editor-name-error' : null"> |
| 151 | <div class="agent-id-feedback" x-show="$store.agentEditor.fieldIssue('name')"> |
| 152 | <span id="agent-editor-name-error" class="field-error" role="alert" x-text="$store.agentEditor.fieldIssue('name')?.message"></span> |
| 153 | <button type="button" class="text-button" x-show="$store.agentEditor.profileConflict" @click="$store.agentEditor.openConflictingProfile()">Open existing agent</button> |
| 154 | </div> |
| 155 | </div> |
| 156 | <div class="agent-field agent-model-preset"> |
| 157 | <label for="agent-editor-easy-model-preset" class="agent-field-label">Model preset</label> |
| 158 | <div class="agent-model-preset-picker"> |
| 159 | <select id="agent-editor-easy-model-preset" x-model="$store.agentEditor.draft.modelPreset" x-effect="$nextTick(() => { $el.value = $store.agentEditor.draft.modelPreset })"> |
| 160 | <option value="" x-text="`Use current preset (${$store.agentEditor.state.model_preset.effective})`"></option> |
| 161 | <template x-for="preset in $store.agentEditor.state.model_presets" :key="preset.name"> |
| 162 | <option :value="preset.name" x-text="preset.name"></option> |
| 163 | </template> |
| 164 | </select> |
| 165 | <button type="button" class="button" @click="$store.agentEditor.openPresetManager()"><x-icon class="icon" name="tune"></x-icon>Edit Presets</button> |
| 166 | </div> |
| 167 | </div> |
| 168 | </div> |
| 169 | </section> |
| 170 | |
| 171 | <section class="agent-easy-field"> |
| 172 | <div class="agent-field-heading"> |
| 173 | <div><label for="agent-editor-instructions" class="agent-field-label">Instructions</label><p>What should this agent do, and how should it behave?</p></div> |
| 174 | </div> |
| 175 | <div> |
| 176 | <textarea id="agent-editor-instructions" rows="9" x-model="$store.agentEditor.instructions.value" @input="$store.agentEditor.markPromptSet('agent.system.main.specifics.md')" placeholder="Research technical topics, verify important claims with reliable sources, and return concise reports with links." :aria-invalid="$store.agentEditor.fieldIssue('instructions') ? 'true' : null" :aria-describedby="$store.agentEditor.fieldIssue('instructions') ? 'agent-editor-instructions-error' : null"></textarea> |
| 177 | <span id="agent-editor-instructions-error" class="field-error" role="alert" x-show="$store.agentEditor.fieldIssue('instructions')" x-text="$store.agentEditor.fieldIssue('instructions')?.message"></span> |
| 178 | <button type="button" class="text-button restore-action" x-show="$store.agentEditor.instructions.has_override && !$store.agentEditor.instructions.reset" @click="$store.agentEditor.restoreInstructions()"><x-icon name="restart_alt"></x-icon><span>Reset to default</span></button> |
| 179 | </div> |
| 180 | </section> |
| 181 | |
| 182 | <section class="agent-easy-field agent-easy-capabilities"> |
| 183 | <div class="agent-field-heading"><div><div class="agent-field-label">Capabilities</div><p>Choose the default access, or set individual items On or Off.</p></div></div> |
| 184 | <div class="capability-policy-group"> |
| 185 | <div class="future-policy-control"><strong>Allow tools by default</strong><label class="toggle"><input type="checkbox" :checked="$store.agentEditor.policyDefault('tool') === 'allow'" @change="$store.agentEditor.setPolicyDefault('tool', $event.target.checked ? 'allow' : 'block')" aria-label="Allow tools by default"><span class="toggler"></span></label></div> |
| 186 | <details class="capability-accordion"> |
| 187 | <summary><span>Choose individual tools</span><x-icon name="expand_more"></x-icon></summary> |
| 188 | <div class="policy-items" role="list" aria-label="Tools this agent can use"> |
| 189 | <template x-for="tool in $store.agentEditor.standardToolCatalog" :key="tool.id"> |
| 190 | <div class="policy-item" role="listitem"><div class="policy-item-copy"><strong x-text="tool.label"></strong><p class="policy-item-description" x-show="tool.description" x-text="tool.description"></p></div><div class="policy-state-control" role="group" :aria-label="`${tool.label} access`"><button type="button" :class="{ active: $store.agentEditor.policyItemState('tool', tool.id) === 'allow' }" :aria-pressed="$store.agentEditor.policyItemState('tool', tool.id) === 'allow'" @click="$store.agentEditor.setPolicyItem('tool', tool.id, 'allow')">On</button><button type="button" :class="{ active: $store.agentEditor.policyItemState('tool', tool.id) === 'default' }" :aria-pressed="$store.agentEditor.policyItemState('tool', tool.id) === 'default'" @click="$store.agentEditor.setPolicyItem('tool', tool.id, 'default')" x-text="`Default (${$store.agentEditor.policyDefault('tool') === 'allow' ? 'on' : 'off'})`"></button><button type="button" :class="{ active: $store.agentEditor.policyItemState('tool', tool.id) === 'block' }" :aria-pressed="$store.agentEditor.policyItemState('tool', tool.id) === 'block'" @click="$store.agentEditor.setPolicyItem('tool', tool.id, 'block')">Off</button></div></div> |
| 191 | </template> |
| 192 | <p class="policy-empty" x-show="!$store.agentEditor.standardToolCatalog.length">No configurable tools are available.</p> |
| 193 | </div> |
| 194 | </details> |
| 195 | </div> |
| 196 | |
| 197 | <div class="capability-policy-group"> |
| 198 | <div class="future-policy-control"><strong>Allow MCPs by default</strong><label class="toggle"><input type="checkbox" :checked="$store.agentEditor.policyDefault('mcp') === 'allow'" @change="$store.agentEditor.setPolicyDefault('mcp', $event.target.checked ? 'allow' : 'block')" aria-label="Allow MCPs by default"><span class="toggler"></span></label></div> |
| 199 | <details class="capability-accordion"> |
| 200 | <summary><span>Choose individual MCPs</span><x-icon name="expand_more"></x-icon></summary> |
| 201 | <div class="policy-items" role="list" aria-label="MCP tools this agent can use"> |
| 202 | <template x-for="tool in $store.agentEditor.mcpCatalog" :key="tool.id"> |
| 203 | <div class="policy-item" role="listitem"><div class="policy-item-copy"><strong x-text="tool.label"></strong><p class="policy-item-description" x-show="tool.description" x-text="tool.description"></p></div><div class="policy-state-control" role="group" :aria-label="`${tool.label} access`"><button type="button" :class="{ active: $store.agentEditor.policyItemState('mcp', tool.id) === 'allow' }" :aria-pressed="$store.agentEditor.policyItemState('mcp', tool.id) === 'allow'" @click="$store.agentEditor.setPolicyItem('mcp', tool.id, 'allow')">On</button><button type="button" :class="{ active: $store.agentEditor.policyItemState('mcp', tool.id) === 'default' }" :aria-pressed="$store.agentEditor.policyItemState('mcp', tool.id) === 'default'" @click="$store.agentEditor.setPolicyItem('mcp', tool.id, 'default')" x-text="`Default (${$store.agentEditor.policyDefault('mcp') === 'allow' ? 'on' : 'off'})`"></button><button type="button" :class="{ active: $store.agentEditor.policyItemState('mcp', tool.id) === 'block' }" :aria-pressed="$store.agentEditor.policyItemState('mcp', tool.id) === 'block'" @click="$store.agentEditor.setPolicyItem('mcp', tool.id, 'block')">Off</button></div></div> |
| 204 | </template> |
| 205 | <p class="policy-empty" x-show="!$store.agentEditor.mcpCatalog.length">No MCP tools are available.</p> |
| 206 | </div> |
| 207 | </details> |
| 208 | </div> |
| 209 | |
| 210 | <div class="capability-policy-group"> |
| 211 | <div class="future-policy-control"><strong>Allow skills by default</strong><label class="toggle"><input type="checkbox" :checked="$store.agentEditor.policyDefault('skill') === 'allow'" @change="$store.agentEditor.setPolicyDefault('skill', $event.target.checked ? 'allow' : 'block')" aria-label="Allow skills by default"><span class="toggler"></span></label></div> |
| 212 | <details class="capability-accordion"> |
| 213 | <summary><span>Choose individual skills</span><x-icon name="expand_more"></x-icon></summary> |
| 214 | <div class="policy-items" role="list" aria-label="Skills this agent can use"> |
| 215 | <template x-for="skill in $store.agentEditor.skillCatalog" :key="skill.path"> |
| 216 | <div class="policy-item" role="listitem"><div class="policy-item-copy"><strong x-text="skill.name"></strong><p class="policy-item-description" x-show="skill.description" x-text="skill.description"></p><em x-show="$store.agentEditor.skillWarnings(skill).length" x-text="`Expects blocked tool: ${$store.agentEditor.skillWarnings(skill).join(', ')}`"></em></div><div class="policy-state-control" role="group" :aria-label="`${skill.name} access`"><button type="button" :class="{ active: $store.agentEditor.policyItemState('skill', skill.name) === 'allow' }" :aria-pressed="$store.agentEditor.policyItemState('skill', skill.name) === 'allow'" @click="$store.agentEditor.setPolicyItem('skill', skill.name, 'allow')">On</button><button type="button" :class="{ active: $store.agentEditor.policyItemState('skill', skill.name) === 'default' }" :aria-pressed="$store.agentEditor.policyItemState('skill', skill.name) === 'default'" @click="$store.agentEditor.setPolicyItem('skill', skill.name, 'default')" x-text="`Default (${$store.agentEditor.policyDefault('skill') === 'allow' ? 'on' : 'off'})`"></button><button type="button" :class="{ active: $store.agentEditor.policyItemState('skill', skill.name) === 'block' }" :aria-pressed="$store.agentEditor.policyItemState('skill', skill.name) === 'block'" @click="$store.agentEditor.setPolicyItem('skill', skill.name, 'block')">Off</button></div></div> |
| 217 | </template> |
| 218 | <p class="policy-empty" x-show="!$store.agentEditor.skillCatalog.length">No configurable skills are available.</p> |
| 219 | </div> |
| 220 | </details> |
| 221 | </div> |
| 222 | </section> |
| 223 | </main> |
| 224 | |
| 225 | <div class="agent-advanced" x-show="$store.agentEditor.mode === 'advanced'"> |
| 226 | <nav class="agent-advanced-nav" aria-label="Advanced editor sections"> |
| 227 | <template x-for="item in [{id:'1',label:'Identity'},{id:'2',label:'Prompt files'},{id:'3',label:'Tools'},{id:'4',label:'MCPs'},{id:'5',label:'Skills'},{id:'6',label:'Review'}]" :key="item.id"> |
| 228 | <button type="button" :class="{ active: $store.agentEditor.section === item.id }" :aria-current="$store.agentEditor.section === item.id ? 'step' : null" @click="$store.agentEditor.setSection(item.id)"> |
| 229 | <span class="section-number" x-text="item.id"></span><span x-text="item.label"></span> |
| 230 | <span class="agent-status-badge compact" :class="$store.agentEditor.sectionIssues(item.id).length ? 'is-error' : 'is-unsaved'" x-show="$store.agentEditor.sectionIssues(item.id).length || $store.agentEditor.sectionDirty(item.id)"><x-icon :name="$store.agentEditor.sectionIssues(item.id).length ? 'error' : 'edit_note'"></x-icon><span x-text="$store.agentEditor.sectionIssues(item.id).length ? 'Needs attention' : 'Changed'"></span></span> |
| 231 | </button> |
| 232 | </template> |
| 233 | </nav> |
| 234 | |
| 235 | <div class="agent-advanced-content"> |
| 236 | <section x-show="$store.agentEditor.section === '1'" data-agent-editor-section="1" tabindex="-1" aria-labelledby="agent-section-1-title"> |
| 237 | <header class="advanced-section-heading"><h3 id="agent-section-1-title">Identity</h3><p>Set the agent’s identity, delegation guidance, and model preset.</p></header> |
| 238 | <div class="origin-row"> |
| 239 | <span class="agent-origin" x-text="$store.agentEditor.state.profile.origin"></span> |
| 240 | <span class="agent-status-badge is-customized" x-show="$store.agentEditor.state.profile.scope_has_overrides"><x-icon name="edit_note"></x-icon><span>Customized by you</span></span> |
| 241 | </div> |
| 242 | <p class="built-in-note" x-show="$store.agentEditor.state.profile.built_in">Your changes override the built-in profile. The original files stay unchanged.</p> |
| 243 | <div class="advanced-identity-grid"> |
| 244 | <div class="agent-avatar-wrap advanced-avatar"> |
| 245 | <div class="agent-avatar" :style="`background:${$store.agentEditor.avatarColor()}`"> |
| 246 | <img x-show="$store.agentEditor.draft.avatar?.kind === 'image' && $store.agentEditor.draft.avatarPreview" :src="$store.agentEditor.draft.avatarPreview" alt="Avatar crop preview"> |
| 247 | <span x-show="$store.agentEditor.draft.avatar?.kind !== 'image' || !$store.agentEditor.draft.avatarPreview" x-text="$store.agentEditor.initials()"></span> |
| 248 | </div> |
| 249 | <div class="agent-avatar-actions"> |
| 250 | <label class="avatar-action-icon avatar-color-action" title="Choose color"><x-icon name="palette"></x-icon><span class="sr-only">Choose color</span><input type="color" :value="$store.agentEditor.avatarColor()" @input="$store.agentEditor.chooseAvatarColor($event.target.value)" aria-label="Choose avatar color"></label> |
| 251 | <label class="avatar-action-icon avatar-upload-action" title="Upload image"><x-icon name="add_photo_alternate"></x-icon><span class="sr-only">Upload image</span><input type="file" accept="image/png,image/jpeg,image/webp" @change="$store.agentEditor.uploadAvatar($event)" aria-label="Upload avatar image"></label> |
| 252 | <button type="button" class="text-button" x-show="$store.agentEditor.state.profile.metadata.avatar.has_override || $store.agentEditor.draft.avatar" @click="$store.agentEditor.resetAvatar()">Reset</button> |
| 253 | </div> |
| 254 | </div> |
| 255 | <div class="identity-fields"> |
| 256 | <div class="agent-field"><label for="agent-editor-advanced-name" class="agent-field-label">Agent name</label><input id="agent-editor-advanced-name" type="text" x-model="$store.agentEditor.draft.title" @input="$store.agentEditor.onNameInput(); $store.agentEditor.markMetadataSet('title')" :aria-invalid="$store.agentEditor.fieldIssue('name') ? 'true' : null" :aria-describedby="$store.agentEditor.fieldIssue('name') ? 'agent-editor-advanced-name-error' : null"><span id="agent-editor-advanced-name-error" class="field-error" role="alert" x-show="$store.agentEditor.fieldIssue('name')" x-text="$store.agentEditor.fieldIssue('name')?.message"></span><small class="field-provenance" x-show="$store.agentEditor.metadataProvenance('title')" x-text="$store.agentEditor.metadataProvenance('title')"></small><button type="button" class="text-button" x-show="$store.agentEditor.canResetMetadata('title')" @click="$store.agentEditor.resetMetadata('title')">Reset to default</button><small class="field-status" x-show="$store.agentEditor.metadataResetPending('title')">Will reset to default on save.</small></div> |
| 257 | <label class="agent-field"><span class="agent-field-label">Profile ID</span><input type="text" :value="$store.agentEditor.draft.profileId" readonly aria-describedby="profile-id-help"><small id="profile-id-help">Used as the profile folder name. Existing IDs do not change when the display name changes.</small></label> |
| 258 | <div class="agent-field wide"><label for="agent-editor-description" class="agent-field-label">Description</label><textarea id="agent-editor-description" rows="2" x-model="$store.agentEditor.draft.description" @input="$store.agentEditor.markMetadataSet('description')"></textarea><small>Short summary shown in profile lists.</small><button type="button" class="text-button" x-show="$store.agentEditor.canResetMetadata('description')" @click="$store.agentEditor.resetMetadata('description')">Reset to default</button><small class="field-status" x-show="$store.agentEditor.metadataResetPending('description')">Will reset to default on save.</small></div> |
| 259 | <div class="agent-field wide agent-model-preset"> |
| 260 | <label for="agent-editor-model-preset" class="agent-field-label">Model preset</label> |
| 261 | <div class="agent-model-preset-picker"> |
| 262 | <select id="agent-editor-model-preset" x-model="$store.agentEditor.draft.modelPreset" x-effect="$nextTick(() => { $el.value = $store.agentEditor.draft.modelPreset })"> |
| 263 | <option value="" x-text="`Use current preset (${$store.agentEditor.state.model_preset.effective})`"></option> |
| 264 | <template x-for="preset in $store.agentEditor.state.model_presets" :key="preset.name"> |
| 265 | <option :value="preset.name" x-text="preset.name"></option> |
| 266 | </template> |
| 267 | </select> |
| 268 | <button type="button" class="button" @click="$store.agentEditor.openPresetManager()"><x-icon class="icon" name="tune"></x-icon>Edit Presets</button> |
| 269 | </div> |
| 270 | <small>Use the current preset or choose another setup for this agent.</small> |
| 271 | </div> |
| 272 | <div class="agent-field wide"><label for="agent-editor-context" class="agent-field-label">When should other agents use this agent?</label><textarea id="agent-editor-context" rows="3" x-model="$store.agentEditor.draft.context" @input="$store.agentEditor.markMetadataSet('context')"></textarea><small>Helps Agent Zero decide when to delegate work; leaving this empty may reduce delegation quality.</small><button type="button" class="text-button" x-show="$store.agentEditor.canResetMetadata('context')" @click="$store.agentEditor.resetMetadata('context')">Reset to default</button><small class="field-status" x-show="$store.agentEditor.metadataResetPending('context')">Will reset to default on save.</small></div> |
| 273 | </div> |
| 274 | </div> |
| 275 | </section> |
| 276 | |
| 277 | <section x-show="$store.agentEditor.section === '2'" data-agent-editor-section="2" tabindex="-1" aria-labelledby="agent-section-2-title"> |
| 278 | <header class="advanced-section-heading"><h3 id="agent-section-2-title">Prompt files</h3><p>Choose a file and edit its prompt.</p></header> |
| 279 | <div class="prompt-workspace"> |
| 280 | <aside class="prompt-browser"> |
| 281 | <label class="compact-search"><span class="sr-only">Search prompt files</span><x-icon name="search"></x-icon><input type="search" x-model="$store.agentEditor.promptFileSearch" placeholder="Search files"></label> |
| 282 | <div class="prompt-file-list" role="region" aria-label="Prompt file list" tabindex="0"> |
| 283 | <template x-for="group in $store.agentEditor.promptGroups" :key="group.id"> |
| 284 | <section class="prompt-file-group" x-show="$store.agentEditor.filteredPromptFiles(group.id).length"> |
| 285 | <h4 x-text="group.label"></h4> |
| 286 | <template x-for="prompt in $store.agentEditor.filteredPromptFiles(group.id)" :key="prompt.filename"> |
| 287 | <button type="button" :class="{ active: $store.agentEditor.selectedPrompt === prompt.filename }" @click="$store.agentEditor.selectPrompt(prompt.filename)"> |
| 288 | <span class="prompt-file-name" x-text="prompt.filename"></span><span class="prompt-file-state" x-text="$store.agentEditor.promptDisplayState(prompt)"></span> |
| 289 | </button> |
| 290 | </template> |
| 291 | </section> |
| 292 | </template> |
| 293 | <p class="prompt-empty" x-show="!$store.agentEditor.filteredPromptFiles().length">No prompt files match your search.</p> |
| 294 | </div> |
| 295 | </aside> |
| 296 | <div class="prompt-editor" role="region" aria-label="Selected prompt file" tabindex="0" x-show="$store.agentEditor.selectedPromptDraft"> |
| 297 | <div class="prompt-editor-header"> |
| 298 | <div class="prompt-file-heading"> |
| 299 | <strong x-text="$store.agentEditor.selectedPrompt"></strong> |
| 300 | <div class="prompt-customization-path"><code x-text="$store.agentEditor.promptCustomizationPath()"></code><button type="button" class="button" title="Copy customization path" aria-label="Copy customization path" @click="$store.agentEditor.copyPromptPath()"><x-icon name="content_copy"></x-icon></button></div> |
| 301 | </div> |
| 302 | <div class="prompt-actions"> |
| 303 | <button type="button" class="btn btn-action-header cancel" x-show="$store.agentEditor.promptEditPending($store.agentEditor.selectedPromptDraft)" title="Discard current edit" aria-label="Discard current edit" @click="$store.agentEditor.discardPromptEdit($store.agentEditor.selectedPrompt)"><x-icon name="close"></x-icon></button> |
| 304 | <button type="button" class="btn btn-action-header confirm" x-show="$store.agentEditor.promptEditPending($store.agentEditor.selectedPromptDraft)" title="Accept current edit" aria-label="Accept current edit" @click="$store.agentEditor.acceptPromptEdit($store.agentEditor.selectedPrompt)"><x-icon name="check"></x-icon></button> |
| 305 | <button type="button" class="button" x-show="$store.agentEditor.selectedPromptDraft.has_override || $store.agentEditor.promptDirty($store.agentEditor.selectedPromptDraft)" @click="$store.agentEditor.resetPrompt($store.agentEditor.selectedPrompt)">Reset to default</button> |
| 306 | </div> |
| 307 | </div> |
| 308 | <div class="agent-editor-note" x-show="$store.agentEditor.selectedPromptDraft.dynamic_processor">This file is generated dynamically at runtime. Python processors are read-only and are not executed by the editor.</div> |
| 309 | <div id="agent-editor-prompt-ace" class="prompt-ace" :aria-invalid="$store.agentEditor.selectedPrompt === 'agent.system.main.specifics.md' && $store.agentEditor.fieldIssue('instructions') ? 'true' : null" :aria-describedby="$store.agentEditor.selectedPrompt === 'agent.system.main.specifics.md' && $store.agentEditor.fieldIssue('instructions') ? 'agent-editor-prompt-error' : null"></div> |
| 310 | <div class="agent-editor-note" role="alert" x-show="$store.agentEditor.aceUnavailable">Prompt editor is unavailable. Reload Agent Zero and try again.</div> |
| 311 | <span id="agent-editor-prompt-error" class="field-error" role="alert" x-show="$store.agentEditor.selectedPrompt === 'agent.system.main.specifics.md' && $store.agentEditor.fieldIssue('instructions')" x-text="$store.agentEditor.fieldIssue('instructions')?.message"></span> |
| 312 | </div> |
| 313 | </div> |
| 314 | </section> |
| 315 | |
| 316 | <section x-show="$store.agentEditor.section === '3'" data-agent-editor-section="3" tabindex="-1" aria-labelledby="agent-section-3-title"> |
| 317 | <header class="advanced-section-heading"><h3 id="agent-section-3-title">Tools</h3><p>Choose which tools this agent can use.</p></header> |
| 318 | <div class="future-policy-control"><strong>Allow tools by default</strong><label class="toggle"><input type="checkbox" :checked="$store.agentEditor.policyDefault('tool') === 'allow'" @change="$store.agentEditor.setPolicyDefault('tool', $event.target.checked ? 'allow' : 'block')" aria-label="Allow tools by default"><span class="toggler"></span></label></div> |
| 319 | <div class="policy-filters tools"><label class="policy-search"><x-icon name="search"></x-icon><span class="sr-only">Search tools</span><input type="search" x-model="$store.agentEditor.toolSearch" placeholder="Search tools"></label><label>Origin <select x-model="$store.agentEditor.toolOrigin"><option value="all">All</option><template x-for="origin in $store.agentEditor.toolOrigins" :key="origin"><option :value="origin" x-text="origin"></option></template></select></label></div> |
| 320 | <section class="policy-group" aria-labelledby="tools-title"><header><h4 id="tools-title">Tools</h4><span x-text="$store.agentEditor.filteredTools('tool').length"></span></header><div class="policy-items"><p class="policy-empty" x-show="!$store.agentEditor.filteredTools('tool').length">No tools match these filters.</p><template x-for="tool in $store.agentEditor.filteredTools('tool')" :key="tool.id"><div class="policy-item"><div class="policy-item-copy"><strong x-text="tool.label"></strong><small x-text="tool.id"></small><p class="policy-item-description" x-show="tool.description" x-text="tool.description"></p><em x-show="tool.available === false">Unavailable — kept in your settings</em></div><div class="policy-state-control" role="group" :aria-label="`${tool.label} access`"><button type="button" :class="{ active: $store.agentEditor.policyItemState('tool', tool.id) === 'allow' }" :aria-pressed="$store.agentEditor.policyItemState('tool', tool.id) === 'allow'" @click="$store.agentEditor.setPolicyItem('tool', tool.id, 'allow')">On</button><button type="button" :class="{ active: $store.agentEditor.policyItemState('tool', tool.id) === 'default' }" :aria-pressed="$store.agentEditor.policyItemState('tool', tool.id) === 'default'" @click="$store.agentEditor.setPolicyItem('tool', tool.id, 'default')" x-text="`Default (${$store.agentEditor.policyDefault('tool') === 'allow' ? 'on' : 'off'})`"></button><button type="button" :class="{ active: $store.agentEditor.policyItemState('tool', tool.id) === 'block' }" :aria-pressed="$store.agentEditor.policyItemState('tool', tool.id) === 'block'" @click="$store.agentEditor.setPolicyItem('tool', tool.id, 'block')">Off</button></div></div></template></div></section> |
| 321 | </section> |
| 322 | |
| 323 | <section x-show="$store.agentEditor.section === '4'" data-agent-editor-section="4" tabindex="-1" aria-labelledby="agent-section-4-title"> |
| 324 | <header class="advanced-section-heading"><h3 id="agent-section-4-title">MCPs</h3><p>Choose which MCP tools this agent can use.</p></header> |
| 325 | <div class="future-policy-control"><strong>Allow MCPs by default</strong><label class="toggle"><input type="checkbox" :checked="$store.agentEditor.policyDefault('mcp') === 'allow'" @change="$store.agentEditor.setPolicyDefault('mcp', $event.target.checked ? 'allow' : 'block')" aria-label="Allow MCPs by default"><span class="toggler"></span></label></div> |
| 326 | <div class="policy-filters tools"><label class="policy-search"><x-icon name="search"></x-icon><span class="sr-only">Search MCPs</span><input type="search" x-model="$store.agentEditor.toolSearch" placeholder="Search MCPs"></label><label>Origin <select x-model="$store.agentEditor.toolOrigin"><option value="all">All</option><template x-for="origin in $store.agentEditor.toolOrigins" :key="origin"><option :value="origin" x-text="origin"></option></template></select></label></div> |
| 327 | <section class="policy-group" aria-labelledby="mcps-title"><header><h4 id="mcps-title">MCPs</h4><span x-text="$store.agentEditor.filteredTools('mcp').length"></span></header><div class="policy-items"><p class="policy-empty" x-show="!$store.agentEditor.filteredTools('mcp').length">No MCP tools match these filters.</p><template x-for="tool in $store.agentEditor.filteredTools('mcp')" :key="tool.id"><div class="policy-item"><div class="policy-item-copy"><strong x-text="tool.label"></strong><small x-text="tool.id"></small><p class="policy-item-description" x-show="tool.description" x-text="tool.description"></p><em x-show="tool.available === false">Unavailable — kept in your settings</em></div><div class="policy-state-control" role="group" :aria-label="`${tool.label} access`"><button type="button" :class="{ active: $store.agentEditor.policyItemState('mcp', tool.id) === 'allow' }" :aria-pressed="$store.agentEditor.policyItemState('mcp', tool.id) === 'allow'" @click="$store.agentEditor.setPolicyItem('mcp', tool.id, 'allow')">On</button><button type="button" :class="{ active: $store.agentEditor.policyItemState('mcp', tool.id) === 'default' }" :aria-pressed="$store.agentEditor.policyItemState('mcp', tool.id) === 'default'" @click="$store.agentEditor.setPolicyItem('mcp', tool.id, 'default')" x-text="`Default (${$store.agentEditor.policyDefault('mcp') === 'allow' ? 'on' : 'off'})`"></button><button type="button" :class="{ active: $store.agentEditor.policyItemState('mcp', tool.id) === 'block' }" :aria-pressed="$store.agentEditor.policyItemState('mcp', tool.id) === 'block'" @click="$store.agentEditor.setPolicyItem('mcp', tool.id, 'block')">Off</button></div></div></template></div></section> |
| 328 | </section> |
| 329 | |
| 330 | <section x-show="$store.agentEditor.section === '5'" data-agent-editor-section="5" tabindex="-1" aria-labelledby="agent-section-5-title"> |
| 331 | <header class="advanced-section-heading"><h3 id="agent-section-5-title">Skills</h3><p>Choose which skills this agent can find and use.</p></header> |
| 332 | <div class="future-policy-control"><strong>Allow skills by default</strong><label class="toggle"><input type="checkbox" :checked="$store.agentEditor.policyDefault('skill') === 'allow'" @change="$store.agentEditor.setPolicyDefault('skill', $event.target.checked ? 'allow' : 'block')" aria-label="Allow skills by default"><span class="toggler"></span></label></div> |
| 333 | <div class="policy-filters skills"><label class="policy-search"><x-icon name="search"></x-icon><span class="sr-only">Search skills</span><input type="search" x-model="$store.agentEditor.skillSearch" placeholder="Search skills"></label><label>Origin <select x-model="$store.agentEditor.skillOrigin"><option value="all">All</option><template x-for="origin in $store.agentEditor.skillOrigins" :key="origin"><option :value="origin" x-text="origin"></option></template></select></label></div> |
| 334 | <section class="policy-group" aria-labelledby="skills-title"><header><h4 id="skills-title">Skills</h4><span x-text="$store.agentEditor.filteredSkills().length"></span></header><div class="policy-items"><p class="policy-empty" x-show="!$store.agentEditor.filteredSkills().length">No skills match these filters.</p><template x-for="skill in $store.agentEditor.filteredSkills()" :key="skill.path"><div class="policy-item"><div class="policy-item-copy"><strong x-text="skill.name"></strong><small x-text="skill.origin"></small><p class="policy-item-description" x-show="skill.description" x-text="skill.description"></p><em x-show="skill.available === false">Unavailable — kept in your settings</em><em x-show="$store.agentEditor.skillWarnings(skill).length" x-text="`Expects blocked tool: ${$store.agentEditor.skillWarnings(skill).join(', ')}`"></em></div><div class="policy-state-control" role="group" :aria-label="`${skill.name} access`"><button type="button" :class="{ active: $store.agentEditor.policyItemState('skill', skill.name) === 'allow' }" :aria-pressed="$store.agentEditor.policyItemState('skill', skill.name) === 'allow'" @click="$store.agentEditor.setPolicyItem('skill', skill.name, 'allow')">On</button><button type="button" :class="{ active: $store.agentEditor.policyItemState('skill', skill.name) === 'default' }" :aria-pressed="$store.agentEditor.policyItemState('skill', skill.name) === 'default'" @click="$store.agentEditor.setPolicyItem('skill', skill.name, 'default')" x-text="`Default (${$store.agentEditor.policyDefault('skill') === 'allow' ? 'on' : 'off'})`"></button><button type="button" :class="{ active: $store.agentEditor.policyItemState('skill', skill.name) === 'block' }" :aria-pressed="$store.agentEditor.policyItemState('skill', skill.name) === 'block'" @click="$store.agentEditor.setPolicyItem('skill', skill.name, 'block')">Off</button></div></div></template></div></section> |
| 335 | </section> |
| 336 | |
| 337 | <section x-show="$store.agentEditor.section === '6'" data-agent-editor-section="6" tabindex="-1" aria-labelledby="agent-section-6-title"> |
| 338 | <header class="advanced-section-heading"><h3 id="agent-section-6-title">Review</h3><p>Saving will change exactly these files — nothing else.</p></header> |
| 339 | <div class="review-plan-status" role="status" x-show="$store.agentEditor.planStatus === 'loading'"><x-icon class="spinning" name="progress_activity"></x-icon><span>Computing the exact change plan…</span></div> |
| 340 | <div class="review-plan-status" x-show="$store.agentEditor.planStatus === 'error'"><span>The change plan could not be computed.</span><button type="button" class="text-button" @click="$store.agentEditor.previewPlan()">Retry</button></div> |
| 341 | <div class="review-blocked" role="alert" x-show="$store.agentEditor.planStatus === 'blocked'"> |
| 342 | <x-icon name="error"></x-icon> |
| 343 | <div><strong x-text="`Fix ${$store.agentEditor.validationIssues().length} ${$store.agentEditor.validationIssues().length === 1 ? 'issue' : 'issues'} to see the change plan`"></strong> |
| 344 | <ul><template x-for="issue in $store.agentEditor.validationIssues()" :key="`${issue.section}-${issue.field}-${issue.message}`"><li><button type="button" class="text-button" @click="$store.agentEditor.showValidationIssue(issue)" x-text="`${issue.label}: ${issue.message} — fix`"></button></li></template></ul> |
| 345 | </div> |
| 346 | </div> |
| 347 | <section class="review-identity" aria-label="Agent identity" x-show="$store.agentEditor.planStatus === 'ready'"> |
| 348 | <div class="review-identity-avatar" aria-hidden="true" :style="`background:${$store.agentEditor.avatarColor()}`"><img x-show="$store.agentEditor.draft.avatar?.kind === 'image' && $store.agentEditor.draft.avatarPreview" :src="$store.agentEditor.draft.avatarPreview" alt=""><span x-show="$store.agentEditor.draft.avatar?.kind !== 'image' || !$store.agentEditor.draft.avatarPreview" x-text="$store.agentEditor.initials()"></span></div> |
| 349 | <div><strong x-text="$store.agentEditor.draft.title || $store.agentEditor.draft.profileId"></strong><p x-text="$store.agentEditor.draft.description || 'No description'"></p></div> |
| 350 | </section> |
| 351 | <div class="change-plan" aria-live="polite" x-show="$store.agentEditor.planStatus === 'ready'"> |
| 352 | <section><h4>Will create or update</h4><template x-if="!$store.agentEditor.plan.written?.length"><p>None</p></template><ul><template x-for="path in $store.agentEditor.plan.written || []" :key="path"><li><code x-text="path"></code></li></template></ul></section> |
| 353 | <section><h4>Will delete</h4><template x-if="!$store.agentEditor.plan.deleted?.length"><p>None</p></template><ul><template x-for="path in $store.agentEditor.plan.deleted || []" :key="path"><li><code x-text="path"></code></li></template></ul></section> |
| 354 | <template x-if="$store.agentEditor.plan.warnings?.length"><section><h4>Notices</h4><ul><template x-for="warning in $store.agentEditor.plan.warnings" :key="warning"><li x-text="warning"></li></template></ul></section></template> |
| 355 | </div> |
| 356 | <div class="review-actions" x-show="$store.agentEditor.pendingMutation"><button type="button" class="button danger" @click="$store.agentEditor.applyPendingMutation()"><x-icon name="delete"></x-icon>Apply removal plan</button><button type="button" class="text-button" @click="$store.agentEditor.pendingMutation = null; $store.agentEditor.previewPlan()">Cancel removal</button></div> |
| 357 | <div class="profile-maintenance" x-show="!$store.agentEditor.pendingMutation && !$store.agentEditor.draft.creating && $store.agentEditor.state.profile.scope_has_overrides && !$store.agentEditor.state.profile.deletable"> |
| 358 | <h4>Customized by you</h4><p x-text="`Remove only the customizations shown in this editor from ${$store.agentEditor.scopeLabel}. Other files stay in place.`"></p><button type="button" class="button danger" @click="$store.agentEditor.planRemoval(false)"><x-icon name="delete_sweep"></x-icon>Remove my changes</button> |
| 359 | <details><summary x-text="`Delete all customizations in ${$store.agentEditor.scopeLabel}`"></summary><p>This removes every customization saved in this scope after showing each affected file. Inherited files remain untouched.</p><button type="button" class="button danger" @click="$store.agentEditor.planRemoval(true)"><x-icon name="delete_forever"></x-icon>Review files to delete</button></details> |
| 360 | </div> |
| 361 | <div class="profile-maintenance" x-show="!$store.agentEditor.pendingMutation && !$store.agentEditor.draft.creating && $store.agentEditor.state.profile.deletable"><h4>Delete custom agent</h4><p>Projects and open chats that use this agent are shown before confirmation, together with its files and settings.</p><button type="button" class="button danger" @click="$store.agentEditor.deleteProfile($store.agentEditor.draft.profileId)">Delete agent</button></div> |
| 362 | </section> |
| 363 | </div> |
| 364 | </div> |
| 365 | |
| 366 | </div> |
| 367 | </template> |
| 368 | |
| 369 | <div class="modal-footer agent-editor-footer" data-modal-footer x-show="!$store.agentEditor.loading && $store.agentEditor.view === 'editor' && !$store.agentEditor.pendingMutation"> |
| 370 | <div class="footer-left"> |
| 371 | <button type="button" class="btn btn-cancel agent-reset-profile" |
| 372 | x-show="$store.agentEditor.draft && !$store.agentEditor.draft.creating && $store.agentEditor.state?.profile && !$store.agentEditor.state.profile.deletable" |
| 373 | :disabled="$store.agentEditor.saving || !$store.agentEditor.state?.profile?.scope_has_overrides" |
| 374 | @click="$store.agentEditor.restoreProfile($store.agentEditor.state.profile)">Reset to default</button> |
| 375 | </div> |
| 376 | <div class="footer-actions"> |
| 377 | <button type="button" class="btn agent-editor-secondary-action" x-show="$store.agentEditor.view === 'editor' && !$store.agentEditor.draft?.creating" @click="$store.agentEditor.save(true)" :disabled="$store.agentEditor.saving || $store.agentEditor.validationIssues().length > 0">Save & test</button> |
| 378 | <button type="button" class="btn btn-ok" x-show="$store.agentEditor.view === 'editor'" @click="$store.agentEditor.save(false)" :disabled="$store.agentEditor.saving || $store.agentEditor.avatarUploading || $store.agentEditor.validationIssues().length > 0" :title="$store.agentEditor.validationIssues().length ? 'Fix the highlighted issues before saving' : ''"><span x-text="$store.agentEditor.saving ? 'Saving…' : $store.agentEditor.draft?.creating ? 'Create agent' : 'Save changes'"></span></button> |
| 379 | </div> |
| 380 | </div> |
| 381 | </div> |
| 382 | |
| 383 | <style> |
| 384 | .agent-editor { |
| 385 | --color-text-secondary: var(--color-text-muted); |
| 386 | --color-error: var(--color-error-text); |
| 387 | --color-warning: var(--color-warning-text); |
| 388 | --agent-editor-action: var(--color-highlight); |
| 389 | --agent-editor-change: var(--color-warning-text); |
| 390 | --agent-editor-danger: var(--color-error-text); |
| 391 | color: var(--color-text); |
| 392 | min-height: 12rem; |
| 393 | min-width: 0; |
| 394 | } |
| 395 | .agent-editor h2,.agent-editor h3,.agent-editor h4,.agent-editor p { margin: 0; } |
| 396 | .agent-editor button,.agent-editor input,.agent-editor textarea,.agent-editor select { font: inherit; } |
| 397 | .agent-editor input[type="search"],.agent-editor select { min-width:0; min-height:2.25rem; box-sizing:border-box; padding:.5rem .6rem; border:1px solid var(--color-border); border-radius:7px; background:var(--color-input); color:var(--color-text); } |
| 398 | .agent-editor input[type="radio"] { appearance:none; flex:0 0 auto; width:1.5rem; height:1.5rem; margin:.05rem 0; border:1px solid var(--color-border); background:var(--color-input); } |
| 399 | .agent-editor input[type="radio"] { border-radius:50%; } |
| 400 | .agent-editor input[type="radio"]:checked { border-color:var(--agent-editor-action); box-shadow:inset 0 0 0 4px var(--color-input); background:var(--agent-editor-action); } |
| 401 | .agent-editor-error { display:flex; gap:.55rem; align-items:flex-start; margin:0 0 .8rem; padding:.7rem .8rem; border:1px solid color-mix(in srgb,var(--agent-editor-danger) 55%,var(--color-border)); border-radius:8px; background:color-mix(in srgb,var(--agent-editor-danger) 10%,var(--color-panel)); } |
| 402 | .agent-editor-error span { flex:1; white-space:pre-wrap; } |
| 403 | .agent-editor-loading { min-height:20rem; display:grid; place-content:center; justify-items:center; gap:.65rem; color:var(--color-text-secondary); } |
| 404 | .agent-editor-topbar { display:flex; align-items:center; justify-content:space-between; gap:1rem; margin-bottom:1rem; } |
| 405 | .agent-editor-heading { display:flex; flex:1 1 auto; flex-wrap:wrap; align-items:center; gap:.6rem; min-width:0; } |
| 406 | .agent-editor-subtitle { margin-top:.2rem; font-size:.78rem; color:var(--color-text-secondary); } |
| 407 | .agent-editor-topbar-actions { display:flex; align-items:center; gap:.75rem; margin-left:auto; } |
| 408 | .agent-editor .agent-reset-profile { --agent-editor-action:var(--color-primary); gap:.25rem; white-space:nowrap; } |
| 409 | .agent-status-badge { display:inline-flex; align-items:center; gap:.25rem; max-width:100%; padding:.2rem .45rem; border:1px solid var(--color-border); border-radius:999px; font-size:.7rem; font-weight:500; line-height:1.2; white-space:normal; } |
| 410 | .agent-status-badge x-icon { flex:0 0 auto; font-size:.85rem; } |
| 411 | .agent-status-badge.is-customized,.agent-status-badge.is-unsaved { color:var(--agent-editor-change); border-color:color-mix(in srgb,var(--agent-editor-change) 44%,var(--color-border)); background:color-mix(in srgb,var(--agent-editor-change) 8%,transparent); } |
| 412 | .agent-status-badge.is-error { color:var(--agent-editor-danger); border-color:color-mix(in srgb,var(--agent-editor-danger) 48%,var(--color-border)); background:color-mix(in srgb,var(--agent-editor-danger) 8%,transparent); } |
| 413 | .agent-status-badge.compact { justify-self:end; padding:.15rem .35rem; font-size:.64rem; } |
| 414 | .agent-mode-switch { display:flex; margin-left:auto; padding:3px; border:1px solid var(--color-border); border-radius:9px; background:var(--color-input); } |
| 415 | .agent-mode-switch button { border:0; border-radius:6px; padding:.42rem .8rem; color:var(--color-text-secondary); background:transparent; } |
| 416 | .agent-mode-switch button.active { color:var(--color-text); background:var(--color-panel); box-shadow:0 1px 4px rgba(0,0,0,.2); } |
| 417 | .agent-easy { max-width:43rem; margin:0 auto; display:flex; flex-direction:column; gap:1.35rem; padding:.25rem .25rem 1rem; } |
| 418 | .agent-easy-identity { position:relative; display:grid; grid-template-columns:7.2rem 1fr; gap:1rem; align-items:start; } |
| 419 | .agent-easy-identity-fields { width:100%; min-width:0; display:flex; flex-direction:column; gap:.9rem; } |
| 420 | .agent-avatar-wrap { display:flex; flex-direction:column; align-items:center; gap:.45rem; } |
| 421 | .agent-avatar { width:5rem; aspect-ratio:1; position:relative; display:grid; place-items:center; border-radius:16px; overflow:hidden; color:white; font-size:1.35rem; font-weight:700; box-shadow:inset 0 0 0 1px rgba(255,255,255,.15); } |
| 422 | .agent-avatar img { width:100%; height:100%; object-fit:cover; } |
| 423 | .avatar-progress { position:absolute; inset:0; display:grid; place-items:center; background:rgba(0,0,0,.5); } |
| 424 | .agent-avatar-actions { --agent-editor-action:var(--color-primary); display:flex; align-items:center; justify-content:center; gap:.35rem; font-size:.76rem; white-space:nowrap; } |
| 425 | .avatar-color-action,.avatar-upload-action { position:relative; cursor:pointer; } |
| 426 | .avatar-action-icon { display:grid; place-items:center; width:1.75rem; height:1.75rem; border-radius:6px; color:var(--agent-editor-action); } |
| 427 | .avatar-action-icon x-icon { font-size:1.05rem; } |
| 428 | .avatar-color-action input,.avatar-upload-action input { position:absolute; width:1px; height:1px; opacity:0; pointer-events:none; } |
| 429 | .agent-field { display:flex; flex-direction:column; gap:.35rem; min-width:0; } |
| 430 | .agent-name-field { width:100%; } |
| 431 | .agent-field-label { font-weight:650; font-size:.92rem; } |
| 432 | .agent-field input,.agent-field textarea,.agent-easy textarea,.policy-filters input,.policy-filters select,.compact-search input { width:100%; box-sizing:border-box; } |
| 433 | .agent-field small,.agent-field-heading p,.field-status { color:var(--color-text-secondary); font-size:.79rem; } |
| 434 | .field-count { color:var(--color-text-secondary); font-size:.79rem; font-weight:400; } |
| 435 | .field-status { display:block; margin-top:.15rem; } |
| 436 | .field-error { display:block; color:var(--color-text); font-size:.79rem; font-weight:600; line-height:1.35; } |
| 437 | .agent-id-feedback { display:flex; flex-wrap:wrap; align-items:center; gap:.35rem .65rem; } |
| 438 | .agent-easy-field .field-error { margin-top:.35rem; } |
| 439 | .agent-field-heading { display:flex; justify-content:space-between; gap:1rem; align-items:flex-start; margin-bottom:.5rem; } |
| 440 | .agent-editor .text-button { display:inline-flex; align-items:center; min-height:1.5rem; border:0; padding:0; background:transparent; color:var(--agent-editor-action); cursor:pointer; font-size:.82rem; text-align:left; } |
| 441 | .agent-editor .text-button:hover { text-decoration:underline; } |
| 442 | .agent-easy textarea { min-height:11rem; resize:vertical; } |
| 443 | .restore-action { --agent-editor-action:var(--color-primary); display:inline-flex; align-items:center; gap:.25rem; margin-top:.4rem; } |
| 444 | .agent-easy-capabilities { display:flex; flex-direction:column; gap:.65rem; } |
| 445 | .future-policy-control { display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:.45rem .2rem; } |
| 446 | .capability-policy-group + .capability-policy-group { border-top:1px solid var(--color-border); padding-top:.55rem; } |
| 447 | .capability-accordion summary { display:flex; align-items:center; justify-content:space-between; gap:.75rem; padding:.65rem .2rem .75rem; cursor:pointer; color:var(--color-text-secondary); font-weight:500; } |
| 448 | .capability-accordion summary x-icon { color:var(--color-text-secondary); transition:transform .15s ease; } |
| 449 | .capability-accordion[open] summary x-icon { transform:rotate(180deg); } |
| 450 | .capability-accordion .policy-items { max-height:none; overflow:visible; padding:0 0 .45rem; } |
| 451 | .agent-advanced { flex:1 1 auto; display:grid; grid-template-columns:14rem minmax(0,1fr); gap:1rem; min-height:0; } |
| 452 | .agent-advanced-nav { display:flex; flex-direction:column; gap:.3rem; padding:.45rem; border:1px solid var(--color-border); border-radius:10px; background:var(--color-input); align-self:start; position:sticky; top:0; } |
| 453 | .agent-advanced-nav button { display:grid; grid-template-columns:1.7rem 1fr auto; align-items:center; gap:.45rem; border:0; border-radius:7px; padding:.65rem; color:var(--color-text-secondary); background:transparent; text-align:left; } |
| 454 | .agent-advanced-nav button.active { color:var(--color-text); background:var(--color-panel); } |
| 455 | .section-number { display:grid; place-items:center; width:1.55rem; height:1.55rem; border:1px solid var(--color-border); border-radius:50%; font-size:.75rem; } |
| 456 | .agent-advanced-content,.agent-editor-workspace,.agent-manager { min-width:0; } |
| 457 | .agent-advanced-content { min-height:0; overflow:auto; } |
| 458 | .agent-advanced-content > section { outline:none; display:flex; flex-direction:column; gap:1rem; } |
| 459 | .agent-advanced-content > section[data-agent-editor-section="2"] { height:100%; min-height:0; } |
| 460 | .advanced-section-heading { display:flex; flex-direction:column; gap:.25rem; padding-bottom:.8rem; border-bottom:1px solid var(--color-border); } |
| 461 | .advanced-section-heading h3 { font-size:1.2rem; } |
| 462 | .advanced-section-heading p { max-width:48rem; color:var(--color-text-secondary); font-size:.84rem; } |
| 463 | .origin-row { display:flex; flex-wrap:wrap; align-items:center; gap:.6rem; } |
| 464 | .built-in-note,.field-provenance { color:var(--color-text-secondary); font-size:.76rem; } |
| 465 | .agent-origin { padding:.2rem .45rem; border:1px solid var(--color-border); border-radius:999px; font-size:.72rem; color:var(--color-text-secondary); } |
| 466 | .agent-editor-note { padding:.55rem .7rem; border-left:3px solid var(--color-warning); background:color-mix(in srgb,var(--color-warning) 8%,transparent); color:var(--color-text-secondary); font-size:.8rem; } |
| 467 | .advanced-identity-grid { display:grid; grid-template-columns:9rem minmax(0,1fr); gap:1.2rem; } |
| 468 | .advanced-avatar { align-self:start; } |
| 469 | .identity-fields { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:.9rem; } |
| 470 | .identity-fields .agent-field.wide { grid-column:1/-1; } |
| 471 | .agent-model-preset-picker { width:100%; display:grid; grid-template-columns:minmax(13rem,18rem) auto; align-items:center; justify-content:space-between; gap:1rem; } |
| 472 | .agent-model-preset-picker select { width:100%; } |
| 473 | .agent-model-preset-picker > .button { display:inline-flex; align-items:center; gap:.35rem; } |
| 474 | .prompt-workspace { flex:1 1 auto; display:grid; grid-template-columns:minmax(13rem,16rem) minmax(0,1fr); gap:.8rem; min-width:0; min-height:0; } |
| 475 | .prompt-browser { display:flex; flex-direction:column; min-width:0; min-height:0; height:100%; border:1px solid var(--color-border); border-radius:10px; overflow:hidden; } |
| 476 | .compact-search,.policy-search { display:grid; grid-template-columns:1.25rem minmax(0,1fr); align-items:center; gap:.3rem; min-width:0; height:2.125rem; padding:0 .45rem; border:1px solid color-mix(in srgb,var(--color-border) 42%,transparent); border-radius:7px; background:color-mix(in srgb,var(--color-text) 10%,transparent); color:var(--color-text-secondary); } |
| 477 | .compact-search { margin:.45rem; } |
| 478 | .compact-search:focus-within,.policy-search:focus-within { border-color:color-mix(in srgb,var(--color-primary) 46%,var(--color-border)); background:color-mix(in srgb,var(--color-text) 13%,transparent); } |
| 479 | .agent-editor .compact-search input,.agent-editor .policy-search input { height:100%; min-height:0; padding:0; border:0; outline:0; appearance:none; background:transparent; } |
| 480 | .prompt-file-list { flex:1; overflow:auto; padding:.35rem; } |
| 481 | .prompt-file-group { min-width:0; margin-bottom:.55rem; } |
| 482 | .prompt-file-group h4 { padding:.35rem .5rem .25rem; color:var(--color-text-secondary); font-size:.7rem; font-weight:650; letter-spacing:.03em; text-transform:uppercase; } |
| 483 | .prompt-file-list button { width:100%; display:grid; grid-template-columns:minmax(0,1fr) auto; gap:.15rem .4rem; padding:.5rem; border:0; border-radius:6px; background:transparent; color:var(--color-text); text-align:left; } |
| 484 | .prompt-file-list button.active { background:var(--color-input); } |
| 485 | .prompt-file-name { grid-column:1/-1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-family:monospace; font-size:.76rem; } |
| 486 | .prompt-file-state { color:var(--color-text-secondary); font-size:.7rem; } |
| 487 | .prompt-empty { padding:.65rem; color:var(--color-text-secondary); font-size:.78rem; } |
| 488 | .prompt-editor { display:flex; flex-direction:column; gap:.55rem; min-width:0; min-height:0; max-width:100%; overflow:hidden; } |
| 489 | .prompt-editor-header { display:flex; justify-content:space-between; gap:.7rem; align-items:flex-start; } |
| 490 | .prompt-editor-header > div:first-child { min-width:0; overflow-wrap:anywhere; } |
| 491 | .prompt-file-heading { display:flex; flex-direction:column; gap:.25rem; } |
| 492 | .prompt-actions { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:.35rem; min-width:0; } |
| 493 | .prompt-actions .button { max-width:100%; white-space:normal; overflow-wrap:anywhere; } |
| 494 | .prompt-customization-path { display:flex; align-items:center; gap:.4rem; min-width:0; } |
| 495 | .prompt-customization-path code { min-width:0; color:var(--color-text-secondary); font-size:.72rem; overflow-wrap:anywhere; } |
| 496 | .prompt-customization-path .button { width:2.125rem; height:2.125rem; flex:0 0 auto; padding:0; } |
| 497 | .prompt-ace { flex:1; min-height:0; border:1px solid var(--color-border); border-radius:8px; overflow:hidden; font:13px/1.55 ui-monospace,SFMono-Regular,Consolas,monospace; } |
| 498 | .profile-maintenance summary { display:flex; align-items:center; min-height:1.5rem; cursor:pointer; } |
| 499 | .policy-filters { display:grid; grid-template-columns:minmax(12rem,1fr) minmax(8rem,auto); gap:.6rem; } |
| 500 | .policy-filters.skills { grid-template-columns:minmax(12rem,1fr) minmax(8rem,auto); } |
| 501 | .policy-filters label { display:flex; align-items:center; gap:.35rem; font-size:.78rem; color:var(--color-text-secondary); } |
| 502 | .policy-filters select { flex:1; } |
| 503 | .policy-group { display:flex; flex-direction:column; min-width:0; border:1px solid var(--color-border); border-radius:10px; overflow:hidden; } |
| 504 | .policy-group header { display:flex; align-items:center; justify-content:space-between; gap:.5rem; padding:.65rem .8rem; border-bottom:1px solid var(--color-border); background:var(--color-input); } |
| 505 | .policy-group header span { color:var(--color-text-secondary); font-size:.72rem; } |
| 506 | .policy-items { flex:1; max-height:24rem; overflow:auto; padding:.35rem; } |
| 507 | .policy-item { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:.75rem; align-items:start; padding:.55rem; border-radius:7px; } |
| 508 | .policy-item:hover { background:var(--color-input); } |
| 509 | .policy-item-copy { display:flex; flex-direction:column; gap:.15rem; min-width:0; } |
| 510 | .policy-items small { color:var(--color-text-secondary); overflow-wrap:anywhere; } |
| 511 | .policy-items em { color:var(--color-warning); font-size:.72rem; font-style:normal; } |
| 512 | .policy-item-description { margin:0; color:var(--color-text-secondary); font-size:.75rem; white-space:pre-wrap; overflow-wrap:anywhere; } |
| 513 | .policy-state-control { display:inline-flex; align-self:center; overflow:hidden; border:1px solid var(--color-border); border-radius:var(--border-radius-sm); background:var(--color-input); } |
| 514 | .policy-state-control button { min-height:2rem; padding:.35rem .6rem; border:0; border-left:1px solid var(--color-border); border-radius:0; background:transparent; color:var(--color-text-secondary); cursor:pointer; font-size:.74rem; white-space:nowrap; } |
| 515 | .policy-state-control button:first-child { border-left:0; } |
| 516 | .policy-state-control button.active { color:var(--color-text); background:#2196f3; box-shadow:0 1px 4px rgba(0,0,0,.2); } |
| 517 | .policy-empty { padding:1rem .7rem; color:var(--color-text-secondary); font-size:.8rem; text-align:center; } |
| 518 | .review-identity { display:grid; grid-template-columns:3.25rem minmax(0,1fr); align-items:center; gap:.8rem; padding:.8rem; border-bottom:1px solid var(--color-border); } |
| 519 | .review-identity-avatar { width:3.25rem; aspect-ratio:1; display:grid; place-items:center; overflow:hidden; border-radius:10px; color:#fff; font-weight:700; } |
| 520 | .review-identity-avatar img { width:100%; height:100%; object-fit:cover; } |
| 521 | .review-identity > div:last-child { display:flex; flex-direction:column; gap:.15rem; min-width:0; } |
| 522 | .review-identity strong,.review-identity p { min-width:0; overflow-wrap:anywhere; } |
| 523 | .review-identity p { color:var(--color-text-secondary); font-size:.8rem; } |
| 524 | .change-plan { display:grid; grid-template-columns:1fr 1fr; gap:.8rem; } |
| 525 | .change-plan section { padding:.85rem; border:1px solid var(--color-border); border-radius:9px; background:var(--color-input); min-width:0; } |
| 526 | .change-plan ul { margin:.55rem 0 0; padding-left:1.2rem; } |
| 527 | .change-plan code { overflow-wrap:anywhere; } |
| 528 | .review-blocked { display:flex; align-items:flex-start; gap:.65rem; padding:.8rem; border:1px solid color-mix(in srgb,var(--agent-editor-danger) 55%,var(--color-border)); border-radius:9px; background:color-mix(in srgb,var(--agent-editor-danger) 8%,var(--color-panel)); } |
| 529 | .review-blocked > x-icon { flex:0 0 auto; color:var(--agent-editor-danger); } |
| 530 | .review-blocked ul { margin:.45rem 0 0; padding-left:1.1rem; } |
| 531 | .review-plan-status { display:flex; flex-wrap:wrap; align-items:center; gap:.45rem; color:var(--color-text-secondary); font-size:.82rem; } |
| 532 | .review-actions { display:flex; flex-wrap:wrap; align-items:center; gap:.65rem; } |
| 533 | .profile-maintenance { display:flex; flex-direction:column; align-items:flex-start; gap:.55rem; margin-top:.5rem; padding:1rem; border:1px solid var(--color-border); border-radius:9px; } |
| 534 | .profile-maintenance p { color:var(--color-text-secondary); font-size:.82rem; } |
| 535 | .profile-maintenance details { width:100%; padding-top:.6rem; border-top:1px solid var(--color-border); } |
| 536 | .profile-maintenance details p { margin:.5rem 0; } |
| 537 | .agent-editor-footer { --agent-editor-action:var(--color-highlight); width:100%; display:flex; justify-content:space-between; gap:.7rem; } |
| 538 | .footer-actions { display:flex; gap:.5rem; margin-left:auto; } |
| 539 | .agent-editor-footer .btn-cancel,.agent-editor-secondary-action { border:1px solid var(--color-border); background:transparent; color:var(--color-text); } |
| 540 | .agent-editor-footer .btn-cancel:hover,.agent-editor-secondary-action:hover { border-color:color-mix(in srgb,var(--agent-editor-action) 50%,var(--color-border)); background:color-mix(in srgb,var(--agent-editor-action) 10%,transparent); color:var(--color-text); } |
| 541 | .agent-editor-secondary-action { display:inline-flex; align-items:center; } |
| 542 | .agent-editor .button.danger { display:inline-flex; align-items:center; gap:.35rem; border-color:color-mix(in srgb,var(--agent-editor-danger) 60%,var(--color-border)); color:var(--agent-editor-danger); background:color-mix(in srgb,var(--agent-editor-danger) 7%,var(--color-panel)); } |
| 543 | .agent-editor .button.danger:hover { background:color-mix(in srgb,var(--agent-editor-danger) 15%,var(--color-panel)); } |
| 544 | .agent-manager { display:flex; flex-direction:column; gap:1rem; } |
| 545 | .agent-scope-selector { padding:.75rem 1rem; border:1px solid var(--color-border); border-radius:4px; } |
| 546 | .agent-scope-field { display:flex; flex:1 1 0; align-items:center; gap:.5rem; min-width:12rem; margin:0; } |
| 547 | .agent-scope-field span { color:var(--color-text-secondary); font-weight:600; white-space:nowrap; } |
| 548 | .agent-scope-field select { flex:1 1 auto; min-width:0; } |
| 549 | .agent-editor-scope { flex:0 1 24rem; } |
| 550 | .agent-manager-copy p { color:var(--color-text-secondary); font-size:.82rem; } |
| 551 | .agent-manager-list-header { display:flex; align-items:center; justify-content:flex-end; gap:1rem; } |
| 552 | .active-agent-display { display:flex; align-items:center; gap:.5rem; min-width:0; margin-right:auto; padding:.5rem; border:1px solid var(--color-highlight); border-radius:.5rem; } |
| 553 | .active-agent-summary { display:flex; align-items:center; gap:.5rem; min-width:0; } |
| 554 | .active-agent-summary strong { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; } |
| 555 | .active-agent-avatar { width:1.5rem; aspect-ratio:1; display:grid; flex:0 0 auto; place-items:center; overflow:hidden; border-radius:6px; color:#fff; font-size:.65rem; font-weight:700; } |
| 556 | .active-agent-avatar img { width:100%; height:100%; object-fit:cover; } |
| 557 | .agent-manager-create { flex:0 0 auto; display:inline-flex; align-items:center; gap:.35rem; } |
| 558 | .agent-manager-list { display:flex; flex-direction:column; } |
| 559 | .agent-manager-card { display:grid; grid-template-columns:3rem minmax(0,1fr) auto; gap:.75rem; align-items:center; padding:.65rem .25rem; } |
| 560 | .agent-manager-card + .agent-manager-card { border-top:1px solid var(--color-border); } |
| 561 | .agent-manager-avatar { width:3rem; aspect-ratio:1; display:grid; place-items:center; border-radius:10px; color:white; font-weight:700; overflow:hidden; } |
| 562 | .agent-manager-avatar img { width:100%; height:100%; object-fit:cover; } |
| 563 | .agent-manager-copy { min-width:0; } |
| 564 | .agent-manager-name { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem; } |
| 565 | .agent-manager-name strong,.agent-manager-copy p { overflow-wrap:anywhere; } |
| 566 | .agent-editor .agent-manager-inline-action { gap:.25rem; margin-top:.15rem; color:var(--color-message-text); opacity:.7; } |
| 567 | .agent-editor .agent-manager-inline-action + .agent-manager-inline-action { margin-left:.5rem; } |
| 568 | .agent-editor .agent-manager-inline-action:hover:not(:disabled) { background:transparent; color:var(--color-text); text-decoration:none; opacity:1; } |
| 569 | .agent-manager-actions { display:flex; flex-wrap:wrap; align-items:center; gap:.4rem; } |
| 570 | .agent-profile-availability input { width:0; height:0; margin:0; border:0; } |
| 571 | .sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; } |
| 572 | .agent-editor :focus-visible { outline:2px solid var(--agent-editor-action); outline-offset:2px; } |
| 573 | .modal-inner.agent-editor-easy { width:min(720px,calc(100vw - 2rem)); max-width:720px; } |
| 574 | .modal-inner.agent-editor-advanced { width:92vw; max-width:none; height:min(calc(100vh - 4rem),80rem); max-height:calc(100vh - 4rem); } |
| 575 | .modal-inner.agent-editor-advanced .modal-scroll,.modal-inner.agent-editor-advanced .modal-bd,.modal-inner.agent-editor-advanced .agent-editor,.modal-inner.agent-editor-advanced .agent-editor-workspace { display:flex; flex:1 1 auto; min-height:0; } |
| 576 | .modal-inner.agent-editor-advanced .modal-scroll { max-height:none; } |
| 577 | .modal-inner.agent-editor-advanced .agent-editor,.modal-inner.agent-editor-advanced .agent-editor-workspace { flex-direction:column; } |
| 578 | @media (max-width: 760px) { |
| 579 | .modal-inner.agent-editor-easy,.modal-inner.agent-editor-advanced { width:100vw; max-width:none; height:100vh; max-height:none; border-radius:0; } |
| 580 | .agent-editor-topbar { align-items:flex-start; flex-wrap:wrap; } |
| 581 | .agent-editor-heading { width:100%; } |
| 582 | .agent-editor-topbar-actions { width:100%; flex-wrap:wrap; justify-content:flex-end; } |
| 583 | .agent-editor-scope { flex:1 1 14rem; } |
| 584 | .agent-easy-identity { grid-template-columns:1fr; justify-items:center; padding-top:1.8rem; } |
| 585 | .agent-id-feedback { width:100%; } |
| 586 | .agent-advanced { grid-template-columns:1fr; } |
| 587 | .agent-advanced-nav { position:static; flex-direction:row; overflow-x:auto; } |
| 588 | .agent-advanced-nav button { grid-template-columns:auto auto auto; white-space:nowrap; } |
| 589 | .agent-model-preset-picker { grid-template-columns:minmax(0,1fr) auto; gap:.5rem; } |
| 590 | .prompt-workspace { grid-template-columns:1fr; } |
| 591 | .prompt-browser { height:22rem; max-height:22rem; } |
| 592 | .prompt-editor { max-height:none; overflow:visible; } |
| 593 | .prompt-ace { min-height:18rem; } |
| 594 | .change-plan,.advanced-identity-grid,.identity-fields { grid-template-columns:1fr; } |
| 595 | .identity-fields .agent-field.wide { grid-column:1; } |
| 596 | .policy-filters { grid-template-columns:1fr; } |
| 597 | .future-policy-control { align-items:flex-start; } |
| 598 | .policy-item { grid-template-columns:1fr; } |
| 599 | .policy-state-control { width:100%; align-self:stretch; } |
| 600 | .policy-state-control button { flex:1; } |
| 601 | .agent-manager-list-header { flex-wrap:wrap; } |
| 602 | .active-agent-display { width:100%; } |
| 603 | .agent-manager-create { margin-left:auto; } |
| 604 | .agent-manager-card { grid-template-columns:3rem minmax(0,1fr) auto; align-items:start; } |
| 605 | .agent-manager-actions { grid-column:auto; align-self:stretch; display:grid; grid-template-columns:auto auto; align-content:space-between; justify-content:end; justify-items:end; } |
| 606 | .agent-manager-actions .agent-profile-availability { grid-column:1/-1; } |
| 607 | .agent-scope-field { flex-basis:100%; min-width:0; } |
| 608 | .agent-editor-footer { flex-wrap:wrap; } |
| 609 | .footer-actions { width:auto; max-width:100%; flex-wrap:wrap; justify-content:flex-end; } |
| 610 | .footer-actions .btn { flex:0 1 auto; text-align:center; } |
| 611 | } |
| 612 | </style> |
| 613 | </body> |
| 614 | </html> |