feat(ui/agents): add Authentication Headers section to agent create/edit form

Add a new "Authentication Headers" panel to AgentFormFields:
- Static Headers: key-value Form.List (always sent to the backend agent,
  static wins on conflict with dynamic)
- Forward Client Headers: Select[tags] of header names to extract from
  the client request and forward (extra_headers)

Update buildAgentDataFromForm to serialize both fields for the API.
Update parseAgentForForm to deserialize them back for editing.
Covers both the create wizard (add_agent_form) and the edit view (agent_info).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Sameer Kankute 2026-03-05 14:34:11 +05:30
parent fd53678898
commit 36d279ab42
2 changed files with 94 additions and 2 deletions

View file

@ -269,6 +269,23 @@ export const buildAgentDataFromForm = (values: any, existingAgent?: any) => {
agentData.litellm_params = params;
}
// static_headers: convert [{header, value}, ...] → {header: value, ...}
if (Array.isArray(values.static_headers) && values.static_headers.length > 0) {
const staticHeaders: Record<string, string> = {};
values.static_headers.forEach((entry: { header?: string; value?: string }) => {
const key = entry?.header?.trim();
if (key) staticHeaders[key] = entry?.value ?? "";
});
if (Object.keys(staticHeaders).length > 0) {
agentData.static_headers = staticHeaders;
}
}
// extra_headers: already an array of strings from Select tags
if (Array.isArray(values.extra_headers) && values.extra_headers.length > 0) {
agentData.extra_headers = values.extra_headers;
}
return agentData;
};
@ -302,5 +319,14 @@ export const parseAgentForForm = (agent: any) => {
cost_per_query: agent.litellm_params?.cost_per_query,
input_cost_per_token: agent.litellm_params?.input_cost_per_token,
output_cost_per_token: agent.litellm_params?.output_cost_per_token,
// static_headers: {key: value} → [{header, value}, ...]
static_headers: agent.static_headers
? Object.entries(agent.static_headers as Record<string, string>).map(([header, value]) => ({
header,
value,
}))
: [],
// extra_headers: already an array of strings
extra_headers: agent.extra_headers ?? [],
};
};

View file

@ -1,7 +1,7 @@
import React from "react";
import { Form, Input, Switch, Collapse } from "antd";
import { Form, Input, Switch, Collapse, Select, Space, Tooltip } from "antd";
import { Button as AntButton } from "antd";
import { PlusOutlined, MinusCircleOutlined } from "@ant-design/icons";
import { PlusOutlined, MinusCircleOutlined, InfoCircleOutlined } from "@ant-design/icons";
import { AGENT_FORM_CONFIG, SKILL_FIELD_CONFIG } from "./agent_config";
import CostConfigFields from "./cost_config_fields";
@ -188,6 +188,72 @@ const AgentFormFields: React.FC<AgentFormFieldsProps> = ({ showAgentName = true,
))}
</Panel>
)}
{/* Authentication Headers */}
{shouldShow("auth_headers") && (
<Panel header="Authentication Headers" key="auth_headers">
{/* Static Headers */}
<Form.Item
label={
<span>
Static Headers{" "}
<Tooltip title="Headers always sent to the backend agent, regardless of the client request. Admin-configured, static wins on conflict.">
<InfoCircleOutlined style={{ color: "#8c8c8c" }} />
</Tooltip>
</span>
}
>
<Form.List name="static_headers">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Space key={key} style={{ display: "flex", marginBottom: 8 }} align="baseline">
<Form.Item
{...restField}
name={[name, "header"]}
rules={[{ required: true, message: "Header name required" }]}
>
<Input placeholder="Header name (e.g. Authorization)" style={{ width: 220 }} />
</Form.Item>
<Form.Item
{...restField}
name={[name, "value"]}
rules={[{ required: true, message: "Value required" }]}
>
<Input placeholder="Value (e.g. Bearer token123)" style={{ width: 260 }} />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} style={{ color: "#ff4d4f" }} />
</Space>
))}
<AntButton type="dashed" onClick={() => add()} icon={<PlusOutlined />} style={{ width: "100%" }}>
Add Static Header
</AntButton>
</>
)}
</Form.List>
</Form.Item>
{/* Extra Headers (dynamic forwarding) */}
<Form.Item
label={
<span>
Forward Client Headers{" "}
<Tooltip title="Header names to extract from the client's request and forward to the agent. Type a name and press Enter.">
<InfoCircleOutlined style={{ color: "#8c8c8c" }} />
</Tooltip>
</span>
}
name="extra_headers"
>
<Select
mode="tags"
style={{ width: "100%" }}
placeholder="e.g. x-api-key, Authorization"
tokenSeparators={[","]}
/>
</Form.Item>
</Panel>
)}
</Collapse>
</>
);