diff options
| author | Adam Malczewski <[email protected]> | 2026-05-29 15:38:35 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-05-29 15:38:35 +0900 |
| commit | 48194753eee9c6cb8995cf52afcbd615cf115491 (patch) | |
| tree | a4aa2c22ed0db272d6848c28f755ad9950418c54 /packages/frontend/src/lib/components | |
| parent | aa230050f4edb7bfc8d3e4d59d95c68c36264b41 (diff) | |
| download | dispatch-48194753eee9c6cb8995cf52afcbd615cf115491.tar.gz dispatch-48194753eee9c6cb8995cf52afcbd615cf115491.zip | |
feat: subagent summon — catalog filter, error hints, system prompt, AgentBuilder default, SubAgent mode display
- Filter summon tool catalog to is_subagent-flagged agents only
- Return fresh subagent list in error when slug not found
- Add subagent hint to system prompt when summon tool available
- Default is_subagent checkbox to true in AgentBuilder
- Fix tab-created event to include agentSlug and agentModels
- Add SubAgent read-only mode to ModelSelector with model slider
Diffstat (limited to 'packages/frontend/src/lib/components')
3 files changed, 73 insertions, 2 deletions
diff --git a/packages/frontend/src/lib/components/AgentBuilder.svelte b/packages/frontend/src/lib/components/AgentBuilder.svelte index d85a6a3..d8ae530 100644 --- a/packages/frontend/src/lib/components/AgentBuilder.svelte +++ b/packages/frontend/src/lib/components/AgentBuilder.svelte @@ -124,7 +124,7 @@ const modelCache = new Map(); formSkills = new Set(); formTools = new Set(); formModels = []; - formIsSubagent = false; + formIsSubagent = true; editing = true; // Allow the effect to skip the initial population setTimeout(() => { formReady = true; }, 0); diff --git a/packages/frontend/src/lib/components/ModelSelector.svelte b/packages/frontend/src/lib/components/ModelSelector.svelte index 235cf3b..a752f5d 100644 --- a/packages/frontend/src/lib/components/ModelSelector.svelte +++ b/packages/frontend/src/lib/components/ModelSelector.svelte @@ -36,6 +36,8 @@ const modelCache = new Map<string, string[]>(); activeModelId = null, reasoningEffort = "max", activeAgentSlug = null, + activeTabParentId = null as string | null, + activeAgentModels = null as Array<{ key_id: string; model_id: string }> | null, workingDirectory = null, onKeyChange, onModelChange, @@ -48,6 +50,8 @@ const modelCache = new Map<string, string[]>(); activeModelId?: string | null; reasoningEffort?: string; activeAgentSlug?: string | null; + activeTabParentId?: string | null; + activeAgentModels?: Array<{ key_id: string; model_id: string }> | null; workingDirectory?: string | null; onKeyChange: (keyId: string) => void; onModelChange: (keyId: string, modelId: string) => void; @@ -91,7 +95,11 @@ const modelCache = new Map<string, string[]>(); }); let modeOverride = $state<"manual" | "agent" | null>(null); - let mode = $derived(modeOverride ?? (activeAgentSlug ? "agent" : "manual")); + let mode = $derived( + activeTabParentId && activeAgentSlug + ? "subagent" + : modeOverride ?? (activeAgentSlug ? "agent" : "manual"), + ); let agents = $state<AgentInfo[]>([]); let visibleAgents = $derived(agents.filter((a) => !a.is_subagent)); let loadingAgents = $state(false); @@ -202,6 +210,7 @@ const modelCache = new Map<string, string[]>(); <button class="btn btn-xs {mode === 'manual' ? 'btn-primary' : 'btn-ghost'}" onclick={() => { modeOverride = "manual"; onAgentChange(null); }} + disabled={mode === 'subagent'} > Manual </button> @@ -220,9 +229,16 @@ const modelCache = new Map<string, string[]>(); if (cwdEl) cwdEl.value = agentToApply.cwd ?? ""; } }} + disabled={mode === 'subagent'} > Agent </button> + <button + class="btn btn-xs {mode === 'subagent' ? 'btn-primary' : 'btn-ghost'}" + disabled={true} + > + SubAgent + </button> </div> {#if mode === "manual"} @@ -256,6 +272,55 @@ const modelCache = new Map<string, string[]>(); </select> </div> {/if} + {:else if mode === "subagent"} + <!-- SubAgent read-only info --> + {@const subModels = activeAgentModels ?? []} + {@const hasSubModels = subModels.length > 1} + {@const subActiveIdx = subModels.findIndex( + (m) => m.key_id === activeKeyId && m.model_id === activeModelId, + )} + <div class="flex flex-col gap-2"> + <div class="flex items-center justify-between"> + <span class="text-sm font-medium">SubAgent</span> + <span class="badge badge-sm">{activeAgentSlug}</span> + </div> + <div class="flex items-center justify-between"> + <span class="text-sm font-medium">Key</span> + <span class="font-mono text-xs">{activeKeyId ?? "default"}</span> + </div> + <div class="flex items-center justify-between"> + <span class="text-sm font-medium">Model</span> + <span class="font-mono text-xs">{activeModelId ?? "default"}</span> + </div> + {#if hasSubModels} + {@const displayIdx = subActiveIdx >= 0 ? subActiveIdx : 0} + <div class="mt-1 pt-2 border-t border-base-content/20"> + <div class="text-xs font-semibold mb-1">Model fallback chain</div> + <input + type="range" + min="0" + max={subModels.length - 1} + value={displayIdx} + class="range range-xs" + step="1" + disabled + /> + <div class="flex w-full justify-between px-0.5 text-xs opacity-50 mt-0.5"> + {#each subModels as _, i} + <span>{i + 1}</span> + {/each} + </div> + <div class="mt-1 flex flex-col gap-0.5"> + {#each subModels as m, i} + <div class="text-xs font-mono truncate {i === displayIdx ? 'opacity-100 font-semibold' : 'opacity-50'}"> + {i + 1}. {m.key_id} / {m.model_id} + </div> + {/each} + </div> + </div> + {/if} + <p class="text-xs text-base-content/50 mt-1">This tab was spawned by a parent agent. Settings cannot be changed.</p> + </div> {:else} <!-- Agent selection UI --> {#if loadingAgents} diff --git a/packages/frontend/src/lib/components/SidebarPanel.svelte b/packages/frontend/src/lib/components/SidebarPanel.svelte index e68781f..fca53b7 100644 --- a/packages/frontend/src/lib/components/SidebarPanel.svelte +++ b/packages/frontend/src/lib/components/SidebarPanel.svelte @@ -29,6 +29,8 @@ const { activeModelId = null, reasoningEffort = "max", activeAgentSlug = null as string | null, + activeTabParentId = null as string | null, + activeAgentModels = null as Array<{ key_id: string; model_id: string }> | null, workingDirectory = null as string | null, onKeyChange, onModelChange, @@ -45,6 +47,8 @@ const { activeModelId?: string | null; reasoningEffort?: string; activeAgentSlug?: string | null; + activeTabParentId?: string | null; + activeAgentModels?: Array<{ key_id: string; model_id: string }> | null; workingDirectory?: string | null; onKeyChange: (keyId: string) => void; onModelChange: (keyId: string, modelId: string) => void; @@ -144,6 +148,8 @@ function contentClass(selected: string): string { {onModelChange} {onReasoningChange} {activeAgentSlug} + {activeTabParentId} + {activeAgentModels} {onAgentChange} {workingDirectory} {onWorkingDirectoryChange} |
