mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Add inline subtitles to menu items and field descriptions (#276)
This commit is contained in:
@@ -22,6 +22,7 @@ export function CreateAgentBasicsFields({
|
||||
Agent name
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-name"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
data-testid="agent-name-input"
|
||||
@@ -31,7 +32,7 @@ export function CreateAgentBasicsFields({
|
||||
spellCheck={false}
|
||||
value={name}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<p className="text-xs text-muted-foreground" id="help-agent-name">
|
||||
Used as the local label and synced to the agent profile display name
|
||||
when the relay accepts the create-time auth.
|
||||
</p>
|
||||
@@ -139,11 +140,19 @@ export function CreateAgentRuntimeFields({
|
||||
Relay URL
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-relay-url"
|
||||
id="agent-relay-url"
|
||||
onChange={(event) => onRelayUrlChange(event.target.value)}
|
||||
placeholder="Leave blank to use the desktop relay"
|
||||
value={relayUrl}
|
||||
/>
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-relay-url"
|
||||
>
|
||||
WebSocket URL of the relay this agent connects to. Leave blank to
|
||||
use the built-in desktop relay.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
@@ -151,10 +160,18 @@ export function CreateAgentRuntimeFields({
|
||||
ACP command
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-acp-command"
|
||||
id="agent-acp-command"
|
||||
onChange={(event) => onAcpCommandChange(event.target.value)}
|
||||
value={acpCommand}
|
||||
/>
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-acp-command"
|
||||
>
|
||||
The sprout-acp binary path or alias used to launch the ACP harness
|
||||
process.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -167,10 +184,18 @@ export function CreateAgentRuntimeFields({
|
||||
Custom agent runtime command
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-runtime-command"
|
||||
id="agent-runtime-command"
|
||||
onChange={(event) => onAgentCommandChange(event.target.value)}
|
||||
value={agentCommand}
|
||||
/>
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-runtime-command"
|
||||
>
|
||||
Full path or shell command for the agent binary when no known ACP
|
||||
runtime was detected.
|
||||
</p>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -180,13 +205,17 @@ export function CreateAgentRuntimeFields({
|
||||
Agent runtime args
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-runtime-args"
|
||||
id="agent-runtime-args"
|
||||
onChange={(event) => onAgentArgsChange(event.target.value)}
|
||||
placeholder="Comma-separated"
|
||||
value={agentArgs}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
`sprout-acp` splits args on commas, matching the testing guide.
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-runtime-args"
|
||||
>
|
||||
sprout-acp splits args on commas, matching the testing guide.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -195,10 +224,18 @@ export function CreateAgentRuntimeFields({
|
||||
MCP command
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-mcp-command"
|
||||
id="agent-mcp-command"
|
||||
onChange={(event) => onMcpCommandChange(event.target.value)}
|
||||
value={mcpCommand}
|
||||
/>
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-mcp-command"
|
||||
>
|
||||
Command the ACP harness uses to start the MCP tool server for this
|
||||
agent.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
@@ -206,11 +243,15 @@ export function CreateAgentRuntimeFields({
|
||||
Turn timeout
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-timeout"
|
||||
id="agent-timeout"
|
||||
onChange={(event) => onTurnTimeoutChange(event.target.value)}
|
||||
placeholder="300"
|
||||
value={turnTimeoutSeconds}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground" id="help-agent-timeout">
|
||||
Seconds before an agent turn is cancelled. Defaults to 300.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
@@ -218,6 +259,7 @@ export function CreateAgentRuntimeFields({
|
||||
Parallelism
|
||||
</label>
|
||||
<Input
|
||||
aria-describedby="help-agent-parallelism"
|
||||
data-testid="agent-parallelism-input"
|
||||
id="agent-parallelism"
|
||||
inputMode="numeric"
|
||||
@@ -229,8 +271,11 @@ export function CreateAgentRuntimeFields({
|
||||
type="number"
|
||||
value={parallelism}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Number of ACP worker subprocesses. `sprout-acp` allows 1-32.
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-parallelism"
|
||||
>
|
||||
Number of ACP worker subprocesses. sprout-acp allows 1-32.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -240,15 +285,18 @@ export function CreateAgentRuntimeFields({
|
||||
System prompt override
|
||||
</label>
|
||||
<Textarea
|
||||
aria-describedby="help-agent-system-prompt"
|
||||
data-testid="agent-system-prompt-input"
|
||||
id="agent-system-prompt"
|
||||
onChange={(event) => onSystemPromptChange(event.target.value)}
|
||||
placeholder="Leave blank to send no ACP system prompt"
|
||||
value={systemPrompt}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Blank means no override. `sprout-acp` will not add a `[System]`
|
||||
prompt.
|
||||
<p
|
||||
className="text-xs text-muted-foreground"
|
||||
id="help-agent-system-prompt"
|
||||
>
|
||||
Blank means no override. sprout-acp will not add a [System] prompt.
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
@@ -302,7 +350,7 @@ export function CreateAgentOptionToggles({
|
||||
<p className="mt-1 text-sm text-foreground/70">
|
||||
{prereqs !== null && !isMintSupported
|
||||
? `Unavailable until ${prereqs.admin.command} is installed.`
|
||||
: "Use `sprout-admin` to create a bearer token for this agent."}
|
||||
: "Use sprout-admin to create a bearer token for this agent."}
|
||||
</p>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -321,14 +321,26 @@ function AgentActionsMenu({
|
||||
onClick={() => onStart(agent.pubkey)}
|
||||
>
|
||||
<Play className="h-4 w-4" />
|
||||
{isActive ? "Redeploy" : "Deploy"}
|
||||
<div className="flex flex-col">
|
||||
<span>{isActive ? "Redeploy" : "Deploy"}</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
{isActive
|
||||
? "Push a new deployment to the provider"
|
||||
: "Deploy this agent to the provider"}
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={isActionPending}
|
||||
onClick={() => onStop(agent.pubkey)}
|
||||
>
|
||||
<Square className="h-4 w-4" />
|
||||
Shutdown
|
||||
<div className="flex flex-col">
|
||||
<span>Shutdown</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Stop the provider deployment and free its resources
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
) : isActive ? (
|
||||
@@ -337,7 +349,12 @@ function AgentActionsMenu({
|
||||
onClick={() => onStop(agent.pubkey)}
|
||||
>
|
||||
<Square className="h-4 w-4" />
|
||||
Stop
|
||||
<div className="flex flex-col">
|
||||
<span>Stop</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Stop the running ACP harness process
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
<DropdownMenuItem
|
||||
@@ -345,7 +362,12 @@ function AgentActionsMenu({
|
||||
onClick={() => onStart(agent.pubkey)}
|
||||
>
|
||||
<Play className="h-4 w-4" />
|
||||
Spawn
|
||||
<div className="flex flex-col">
|
||||
<span>Spawn</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Launch the local ACP harness process for this agent
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
@@ -354,7 +376,13 @@ function AgentActionsMenu({
|
||||
onClick={() => onAddToChannel(agent)}
|
||||
>
|
||||
<UserPlus className="h-4 w-4" />
|
||||
Add to channel
|
||||
<div className="flex flex-col">
|
||||
<span>Add to channel</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Invite this agent to a channel so it can participate in
|
||||
conversations
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
@@ -362,20 +390,36 @@ function AgentActionsMenu({
|
||||
onClick={() => onMintToken(agent.pubkey, agent.name)}
|
||||
>
|
||||
<KeyRound className="h-4 w-4" />
|
||||
Mint token
|
||||
<div className="flex flex-col">
|
||||
<span>Mint token</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Generate a bearer token this agent uses to authenticate with the
|
||||
relay
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={() => navigator.clipboard.writeText(agent.pubkey)}
|
||||
>
|
||||
<Clipboard className="h-4 w-4" />
|
||||
Copy pubkey
|
||||
<div className="flex flex-col">
|
||||
<span>Copy pubkey</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Copy the agent's public key to the clipboard
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
|
||||
{agent.backend.type === "local" ? (
|
||||
<DropdownMenuItem onClick={() => onOpenLogs(agent.pubkey)}>
|
||||
<FileText className="h-4 w-4" />
|
||||
View logs
|
||||
<div className="flex flex-col">
|
||||
<span>View logs</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Show the ACP harness stdout/stderr log inline
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
|
||||
@@ -387,9 +431,18 @@ function AgentActionsMenu({
|
||||
}
|
||||
>
|
||||
<Power className="h-4 w-4" />
|
||||
{agent.startOnAppLaunch
|
||||
? "Disable auto-start"
|
||||
: "Enable auto-start"}
|
||||
<div className="flex flex-col">
|
||||
<span>
|
||||
{agent.startOnAppLaunch
|
||||
? "Disable auto-start"
|
||||
: "Enable auto-start"}
|
||||
</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
{agent.startOnAppLaunch
|
||||
? "Stop launching this agent automatically when the desktop app starts"
|
||||
: "Launch this agent automatically every time the desktop app starts"}
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
|
||||
@@ -401,7 +454,12 @@ function AgentActionsMenu({
|
||||
onClick={() => onDelete(agent.pubkey)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Delete
|
||||
<div className="flex flex-col">
|
||||
<span>Delete</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Permanently remove this agent profile from the desktop app
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -155,7 +155,13 @@ export function PersonasSection({
|
||||
onClick={() => onEdit(persona)}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
Edit
|
||||
<div className="flex flex-col">
|
||||
<span>Edit</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Edit this persona's name, avatar, and system
|
||||
prompt
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
<DropdownMenuItem
|
||||
@@ -163,14 +169,26 @@ export function PersonasSection({
|
||||
onClick={() => onDuplicate(persona)}
|
||||
>
|
||||
<CopyPlus className="h-4 w-4" />
|
||||
Duplicate
|
||||
<div className="flex flex-col">
|
||||
<span>Duplicate</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Create a copy of this persona you can customize
|
||||
independently
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={isPending}
|
||||
onClick={() => onExport(persona)}
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
Export
|
||||
<div className="flex flex-col">
|
||||
<span>Export</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Save this persona as a .persona.json file you can
|
||||
share or back up
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
{persona.isBuiltIn ? (
|
||||
<DropdownMenuItem
|
||||
@@ -179,7 +197,12 @@ export function PersonasSection({
|
||||
onClick={() => onDeactivate(persona)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Remove from My Agents
|
||||
<div className="flex flex-col">
|
||||
<span>Remove from My Agents</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Remove this built-in persona from your agent library
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
) : (
|
||||
<DropdownMenuItem
|
||||
@@ -188,7 +211,12 @@ export function PersonasSection({
|
||||
onClick={() => onDelete(persona)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Delete
|
||||
<div className="flex flex-col">
|
||||
<span>Delete</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Permanently delete this persona
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
|
||||
@@ -202,7 +202,12 @@ export function TeamsSection({
|
||||
onClick={() => onAddToChannel(team)}
|
||||
>
|
||||
<Rocket className="h-4 w-4" />
|
||||
Deploy to channel
|
||||
<div className="flex flex-col">
|
||||
<span>Deploy to channel</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Add all personas in this team to a channel at once
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
@@ -210,21 +215,39 @@ export function TeamsSection({
|
||||
onClick={() => onEdit(team)}
|
||||
>
|
||||
<Pencil className="h-4 w-4" />
|
||||
Edit
|
||||
<div className="flex flex-col">
|
||||
<span>Edit</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Edit this team's name, description, and persona
|
||||
membership
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={isPending || hasMissingPersonas}
|
||||
onClick={() => onDuplicate(team)}
|
||||
>
|
||||
<CopyPlus className="h-4 w-4" />
|
||||
Duplicate
|
||||
<div className="flex flex-col">
|
||||
<span>Duplicate</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Create a copy of this team you can customize
|
||||
independently
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
disabled={isPending || hasMissingPersonas}
|
||||
onClick={() => onExport(team)}
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
Export
|
||||
<div className="flex flex-col">
|
||||
<span>Export</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Save this team as a .team.json file you can share or
|
||||
back up
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
@@ -233,7 +256,12 @@ export function TeamsSection({
|
||||
onClick={() => onDelete(team)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Delete
|
||||
<div className="flex flex-col">
|
||||
<span>Delete</span>
|
||||
<span className="text-xs font-normal text-muted-foreground">
|
||||
Permanently delete this team
|
||||
</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
Reference in New Issue
Block a user