mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
feat(desktop): mount McpServersEditor in all three agent dialogs (P3)
Wires the McpServersEditor into the global config, definition, and instance-edit dialogs — completing the UI layer for the editable MCP servers feature. - GlobalAgentConfigFields: global base-layer editor (no inherited rows) - PersonaAdvancedFields: definition-layer editor with global as inherited - AgentDefinitionDialog: state, init reset, advanced-expand gate, submit - EditAgentAdvancedFields: per-instance editor with merged global+persona inherited rows; new mcpServers/inheritedMcpServers/onMcpServersChange props - AgentInstanceEditDialog: mcpServers state, inheritedMcpServers memo (mergeMcpServersByName(global, persona)), absent-preserves submit wire, and EditAgentAdvancedFields prop threading - check-file-sizes.mjs: bump AgentInstanceEditDialog override 1180→1198 (+18 lines from load-bearing P3 prop threading)
This commit is contained in:
@@ -486,7 +486,9 @@ const overrides = new Map([
|
||||
// +2 provider-aware effort: model/provider props threaded to BuzzAgentModelTuningFields.
|
||||
// +15 provider/model dropdown fixes: useBakedBuildEnvKeysQuery + hideProviderIds
|
||||
// for Databricks v1 gate; prospectiveRuntimeId default fallback for builtins.
|
||||
["src/features/agents/ui/AgentInstanceEditDialog.tsx", 1180],
|
||||
// +18 PR3 MCP servers UI: mcpServers state, inheritedMcpServers memo,
|
||||
// submit wire, and EditAgentAdvancedFields prop threading.
|
||||
["src/features/agents/ui/AgentInstanceEditDialog.tsx", 1198],
|
||||
// AgentDefinitionDialog grew past 1000 with the following load-bearing fixes:
|
||||
// isRuntimeAutoSeededRef tracking for edit-mode seeding (Fizz shows models);
|
||||
// runtimeSupportsLlmProviderSelection guard on discovery provider (codex fix);
|
||||
|
||||
@@ -16,6 +16,7 @@ import { Textarea } from "@/shared/ui/textarea";
|
||||
import { AgentCreationPreview } from "./AgentCreationPreview";
|
||||
import { PersonaDropdownField } from "./PersonaDropdownField";
|
||||
import type { EnvVarsValue } from "./EnvVarsEditor";
|
||||
import type { McpServersValue } from "./McpServersEditor";
|
||||
import { PersonaAdvancedFields } from "./PersonaAdvancedFields";
|
||||
import { PersonaModelField } from "./PersonaModelField";
|
||||
import {
|
||||
@@ -128,6 +129,7 @@ export function AgentDefinitionDialog({
|
||||
React.useState(false);
|
||||
const [namePoolText, setNamePoolText] = React.useState("");
|
||||
const [envVars, setEnvVars] = React.useState<EnvVarsValue>({});
|
||||
const [mcpServers, setMcpServers] = React.useState<McpServersValue>([]);
|
||||
const [behaviorDraft, setBehaviorDraft] = React.useState(
|
||||
emptyPersonaBehaviorDraft,
|
||||
);
|
||||
@@ -179,14 +181,18 @@ export function AgentDefinitionDialog({
|
||||
: "";
|
||||
const nextEnvVars =
|
||||
"envVars" in initialValues ? (initialValues.envVars ?? {}) : {};
|
||||
const nextMcpServers =
|
||||
"mcpServers" in initialValues ? (initialValues.mcpServers ?? []) : [];
|
||||
const nextBehaviorDraft = draftFromBehavior(initialValues.behavior);
|
||||
behaviorSeedRef.current = draftFromBehavior(initialValues.behavior);
|
||||
setBehaviorDraft(nextBehaviorDraft);
|
||||
setNamePoolText(nextNamePoolText);
|
||||
setEnvVars(nextEnvVars);
|
||||
setMcpServers(nextMcpServers);
|
||||
setShowAdvancedFields(
|
||||
nextNamePoolText.trim().length > 0 ||
|
||||
Object.keys(nextEnvVars).length > 0 ||
|
||||
nextMcpServers.length > 0 ||
|
||||
nextBehaviorDraft.respondTo !== null ||
|
||||
nextBehaviorDraft.parallelism.trim().length > 0,
|
||||
);
|
||||
@@ -282,6 +288,7 @@ export function AgentDefinitionDialog({
|
||||
provider: providerForSubmit,
|
||||
namePool: namePoolInput,
|
||||
envVars,
|
||||
mcpServers,
|
||||
behavior: behaviorForSubmit(
|
||||
behaviorDraft,
|
||||
behaviorSeedRef.current,
|
||||
@@ -867,11 +874,14 @@ export function AgentDefinitionDialog({
|
||||
envVars={envVars}
|
||||
fileSatisfiedEnvKeys={localModeGate.fileSatisfiedEnvKeys}
|
||||
inheritedEnvVars={globalConfig.env_vars}
|
||||
inheritedMcpServers={globalConfig.mcp_servers}
|
||||
mcpServers={mcpServers}
|
||||
model={model}
|
||||
modelTuningRuntimeId={runtime}
|
||||
namePoolText={namePoolText}
|
||||
onBehaviorDraftChange={setBehaviorDraft}
|
||||
onEnvVarsChange={setEnvVars}
|
||||
onMcpServersChange={setMcpServers}
|
||||
onNamePoolTextChange={setNamePoolText}
|
||||
provider={provider}
|
||||
requiredEnvKeys={requiredEnvKeys}
|
||||
|
||||
@@ -63,6 +63,11 @@ import {
|
||||
} from "./runtimeModelProviderSelection";
|
||||
import { AgentCreationPreview } from "./AgentCreationPreview";
|
||||
import type { EnvVarsValue } from "./EnvVarsEditor";
|
||||
import {
|
||||
mergeMcpServersByName,
|
||||
serversEqual,
|
||||
type McpServersValue,
|
||||
} from "./McpServersEditor";
|
||||
import { useRequiredCredentialState } from "./useRequiredCredentialState";
|
||||
import { CreateAgentRespondToField } from "./RespondToField";
|
||||
import { PersonaDropdownField } from "./PersonaDropdownField";
|
||||
@@ -125,6 +130,9 @@ export function AgentInstanceEditDialog({
|
||||
const [isCustomProviderEditing, setIsCustomProviderEditing] =
|
||||
React.useState(false);
|
||||
const [envVars, setEnvVars] = React.useState<EnvVarsValue>(agent.envVars);
|
||||
const [mcpServers, setMcpServers] = React.useState<McpServersValue>(
|
||||
agent.mcpServers,
|
||||
);
|
||||
const [autoRestartOnConfigChange, setAutoRestartOnConfigChange] =
|
||||
React.useState(agent.autoRestartOnConfigChange);
|
||||
const personasQuery = usePersonasQuery();
|
||||
@@ -175,6 +183,7 @@ export function AgentInstanceEditDialog({
|
||||
setProvider(agent.provider ?? "");
|
||||
setIsCustomProviderEditing(false);
|
||||
setEnvVars(agent.envVars);
|
||||
setMcpServers(agent.mcpServers);
|
||||
setAutoRestartOnConfigChange(agent.autoRestartOnConfigChange);
|
||||
setRespondTo(agent.respondTo);
|
||||
setRespondToAllowlist(agent.respondToAllowlist);
|
||||
@@ -424,6 +433,17 @@ export function AgentInstanceEditDialog({
|
||||
return { ...globalConfig.env_vars, ...inheritedEnvVars };
|
||||
}, [globalConfig.env_vars, inheritedEnvVars]);
|
||||
|
||||
// Merge global + persona MCP servers for the inherited display hint in
|
||||
// McpServersEditor. Persona-layer servers override same-named global ones.
|
||||
const inheritedMcpServers = React.useMemo(
|
||||
() =>
|
||||
mergeMcpServersByName(
|
||||
globalConfig.mcp_servers,
|
||||
linkedPersona?.mcpServers ?? [],
|
||||
),
|
||||
[globalConfig.mcp_servers, linkedPersona?.mcpServers],
|
||||
);
|
||||
|
||||
// Auto-expand Advanced whenever the prospective runtime is buzz-agent so the
|
||||
// model-tuning knobs are reachable even when no required key is missing.
|
||||
// Fires once per dialog-open cycle; does not re-open if the user manually
|
||||
@@ -684,6 +704,9 @@ export function AgentInstanceEditDialog({
|
||||
envVars: envVarsChanged(submitEnvVars, agent.envVars)
|
||||
? submitEnvVars
|
||||
: undefined,
|
||||
mcpServers: serversEqual(mcpServers, agent.mcpServers)
|
||||
? undefined
|
||||
: mcpServers,
|
||||
respondTo: respondTo !== agent.respondTo ? respondTo : undefined,
|
||||
// The allowlist is preserved across mode toggles in local UI state
|
||||
// (so a user can flip away from allowlist and back without losing
|
||||
@@ -1081,8 +1104,10 @@ export function AgentInstanceEditDialog({
|
||||
: undefined
|
||||
}
|
||||
inheritedEnvVars={inheritedWithGlobal}
|
||||
inheritedMcpServers={inheritedMcpServers}
|
||||
inheritHarness={inheritHarness}
|
||||
linkedPersona={linkedPersona}
|
||||
mcpServers={mcpServers}
|
||||
model={model}
|
||||
modelTuningRuntimeId={prospectiveRuntimeId}
|
||||
parallelism={parallelism}
|
||||
@@ -1097,6 +1122,7 @@ export function AgentInstanceEditDialog({
|
||||
onAutoRestartChange={setAutoRestartOnConfigChange}
|
||||
onEnvVarsChange={setEnvVars}
|
||||
onInheritHarnessChange={setInheritHarness}
|
||||
onMcpServersChange={setMcpServers}
|
||||
onParallelismChange={setParallelism}
|
||||
onRelayUrlChange={setRelayUrl}
|
||||
onSystemPromptChange={setSystemPrompt}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { cn } from "@/shared/lib/cn";
|
||||
import { Input } from "@/shared/ui/input";
|
||||
import { Textarea } from "@/shared/ui/textarea";
|
||||
import { EnvVarsEditor, type EnvVarsValue } from "./EnvVarsEditor";
|
||||
import { McpServersEditor, type McpServersValue } from "./McpServersEditor";
|
||||
import {
|
||||
PERSONA_FIELD_CONTROL_CLASS,
|
||||
PERSONA_FIELD_SHELL_CLASS,
|
||||
@@ -21,8 +22,10 @@ export function EditAgentAdvancedFields({
|
||||
fileSatisfiedEnvKeys,
|
||||
focusKey,
|
||||
inheritedEnvVars,
|
||||
inheritedMcpServers = [],
|
||||
inheritHarness,
|
||||
linkedPersona,
|
||||
mcpServers,
|
||||
model,
|
||||
modelTuningRuntimeId,
|
||||
parallelism,
|
||||
@@ -36,6 +39,7 @@ export function EditAgentAdvancedFields({
|
||||
onAgentCommandChange,
|
||||
onEnvVarsChange,
|
||||
onInheritHarnessChange,
|
||||
onMcpServersChange,
|
||||
onParallelismChange,
|
||||
onRelayUrlChange,
|
||||
onAutoRestartChange,
|
||||
@@ -51,7 +55,11 @@ export function EditAgentAdvancedFields({
|
||||
/** When set, EnvVarsEditor scrolls and focuses this key's input on mount. */
|
||||
focusKey?: string;
|
||||
inheritedEnvVars: Record<string, string>;
|
||||
/** Read-only MCP servers inherited from the global + persona layers, merged. */
|
||||
inheritedMcpServers?: McpServersValue;
|
||||
inheritHarness: boolean;
|
||||
/** This agent instance's own MCP server layer. */
|
||||
mcpServers: McpServersValue;
|
||||
linkedPersona: AgentPersona | null;
|
||||
/** Active LLM model — forwarded to BuzzAgentModelTuningFields for effort filtering. */
|
||||
model?: string;
|
||||
@@ -73,6 +81,7 @@ export function EditAgentAdvancedFields({
|
||||
onAgentCommandChange: (value: string) => void;
|
||||
onEnvVarsChange: (value: EnvVarsValue) => void;
|
||||
onInheritHarnessChange: (value: boolean) => void;
|
||||
onMcpServersChange: (value: McpServersValue) => void;
|
||||
onParallelismChange: (value: string) => void;
|
||||
onRelayUrlChange: (value: string) => void;
|
||||
onAutoRestartChange: (value: boolean) => void;
|
||||
@@ -312,6 +321,17 @@ export function EditAgentAdvancedFields({
|
||||
value={envVars}
|
||||
/>
|
||||
|
||||
{/* MCP servers */}
|
||||
<McpServersEditor
|
||||
disabled={disabled}
|
||||
helperText="Per-instance MCP servers. Override same-named servers from the template and global layers."
|
||||
inheritedLabel="template / global defaults"
|
||||
inheritedServers={inheritedMcpServers}
|
||||
label="MCP servers"
|
||||
onChange={onMcpServersChange}
|
||||
value={mcpServers}
|
||||
/>
|
||||
|
||||
{/* Tier-1 buzz-agent model-tuning knobs — only shown for buzz-agent. */}
|
||||
{isBuzzAgentRuntime(modelTuningRuntimeId) ? (
|
||||
<BuzzAgentModelTuningFields
|
||||
|
||||
@@ -14,6 +14,10 @@ import type {
|
||||
} from "@/shared/api/types";
|
||||
import { EnvVarsEditor } from "@/features/agents/ui/EnvVarsEditor";
|
||||
import type { InheritedEnvRow } from "@/features/agents/ui/EnvVarsEditor";
|
||||
import {
|
||||
McpServersEditor,
|
||||
type McpServersValue,
|
||||
} from "@/features/agents/ui/McpServersEditor";
|
||||
import { getBakedProviderInheritLabel } from "@/features/agents/ui/bakedEnvHelpers";
|
||||
import {
|
||||
AUTO_PROVIDER_DROPDOWN_VALUE,
|
||||
@@ -142,6 +146,10 @@ export function GlobalAgentConfigFields({
|
||||
onConfigChange({ ...config, model: value || null });
|
||||
}
|
||||
|
||||
function handleMcpServersChange(next: McpServersValue) {
|
||||
onConfigChange({ ...config, mcp_servers: next });
|
||||
}
|
||||
|
||||
function handleEnvVarsChange(next: Record<string, string>) {
|
||||
const effort = config.env_vars[BUZZ_AGENT_THINKING_EFFORT];
|
||||
const merged =
|
||||
@@ -284,6 +292,16 @@ export function GlobalAgentConfigFields({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* MCP servers */}
|
||||
<div className="p-3">
|
||||
<McpServersEditor
|
||||
helperText="Global base layer — applied to all buzz-agent instances. Per-definition and per-instance servers layer on top."
|
||||
label="Global MCP servers"
|
||||
onChange={handleMcpServersChange}
|
||||
value={config.mcp_servers}
|
||||
/>
|
||||
</div>
|
||||
</SettingsOptionGroup>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Input } from "@/shared/ui/input";
|
||||
import { cn } from "@/shared/lib/cn";
|
||||
import { EnvVarsEditor, type EnvVarsValue } from "./EnvVarsEditor";
|
||||
import { McpServersEditor, type McpServersValue } from "./McpServersEditor";
|
||||
import { CreateAgentRespondToField } from "./RespondToField";
|
||||
import type { PersonaBehaviorDraft } from "./personaBehaviorDraft";
|
||||
import { isBuzzAgentRuntime } from "./buzzAgentConfig";
|
||||
@@ -16,11 +17,14 @@ export function PersonaAdvancedFields({
|
||||
disabled,
|
||||
envVars,
|
||||
inheritedEnvVars = {},
|
||||
mcpServers,
|
||||
inheritedMcpServers = [],
|
||||
model,
|
||||
modelTuningRuntimeId = "",
|
||||
namePoolText,
|
||||
onBehaviorDraftChange,
|
||||
onEnvVarsChange,
|
||||
onMcpServersChange,
|
||||
onNamePoolTextChange,
|
||||
provider,
|
||||
requiredEnvKeys = [],
|
||||
@@ -32,6 +36,10 @@ export function PersonaAdvancedFields({
|
||||
/** Env vars to display as inherited defaults in tuning-field placeholders.
|
||||
* For templates, pass `globalConfig.env_vars` (the fallback layer). */
|
||||
inheritedEnvVars?: EnvVarsValue;
|
||||
/** This definition's local-only MCP server layer. */
|
||||
mcpServers: McpServersValue;
|
||||
/** Read-only servers inherited from the global layer, already merged. */
|
||||
inheritedMcpServers?: McpServersValue;
|
||||
/** Active LLM model — forwarded to BuzzAgentModelTuningFields for effort filtering. */
|
||||
model?: string;
|
||||
/** Runtime id for the buzz-agent tuning knobs visibility gate. */
|
||||
@@ -39,6 +47,7 @@ export function PersonaAdvancedFields({
|
||||
namePoolText: string;
|
||||
onBehaviorDraftChange: (value: PersonaBehaviorDraft) => void;
|
||||
onEnvVarsChange: (value: EnvVarsValue) => void;
|
||||
onMcpServersChange: (value: McpServersValue) => void;
|
||||
onNamePoolTextChange: (value: string) => void;
|
||||
/** Active LLM provider id — forwarded to BuzzAgentModelTuningFields for effort filtering. */
|
||||
provider?: string;
|
||||
@@ -144,6 +153,16 @@ export function PersonaAdvancedFields({
|
||||
value={envVars}
|
||||
/>
|
||||
|
||||
<McpServersEditor
|
||||
disabled={disabled}
|
||||
helperText="Local-only MCP servers spawned alongside buzz-agent instances created from this definition."
|
||||
inheritedLabel="global"
|
||||
inheritedServers={inheritedMcpServers}
|
||||
label="MCP servers"
|
||||
onChange={onMcpServersChange}
|
||||
value={mcpServers}
|
||||
/>
|
||||
|
||||
{/* Tier-1 buzz-agent model-tuning knobs — only shown for buzz-agent. */}
|
||||
{isBuzzAgentRuntime(modelTuningRuntimeId) ? (
|
||||
<BuzzAgentModelTuningFields
|
||||
|
||||
Reference in New Issue
Block a user