mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
fix(agents): apply discovery overlay uniformly on create and dedupe ALLOWED_CAPABILITY_KEYS
- buildAgentData now applies overlayDiscoveredCardParams after every non-custom branch (a2a, use_a2a_form_fields, dynamic) so types with credential_fields no longer silently drop discovered skills, capabilities, input/output modes, provider, and icon/doc URLs on submit. Mirrors the edit flow in agent_info.tsx. - Export ALLOWED_CAPABILITY_KEYS from agent_discovery_utils and import it in agent_card_discovery so the rendering and selection-filtering logic share a single source of truth. Co-authored-by: Yassin Kortam <yassin@berri.ai>
This commit is contained in:
parent
da4d9ce4e5
commit
4e3cdda739
3 changed files with 51 additions and 40 deletions
|
|
@ -210,6 +210,44 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({
|
|||
setCurrentStep((s) => Math.max(0, s - 1));
|
||||
};
|
||||
|
||||
// Overlay the user's discovery selections onto the agent_card_params built
|
||||
// from the form. Form-driven fields (name, description, version, url) stay
|
||||
// as-is; only skills, capabilities, input/output modes, provider, and
|
||||
// icon/doc URLs are overlaid because dynamic agent forms (e.g. LangGraph)
|
||||
// don't register Form.Items for them, so AntD's setFieldsValue silently
|
||||
// drops those keys and the values never make it back through buildAgentData.
|
||||
const overlayDiscoveredCardParams = (
|
||||
agentData: Record<string, any>,
|
||||
): Record<string, any> => {
|
||||
if (!appliedDiscoveredSelection) return agentData;
|
||||
const discovered = appliedDiscoveredSelection.selected_card;
|
||||
return {
|
||||
...agentData,
|
||||
agent_card_params: {
|
||||
...agentData.agent_card_params,
|
||||
...(Array.isArray(discovered.skills) && {
|
||||
skills: discovered.skills,
|
||||
}),
|
||||
...(discovered.capabilities && {
|
||||
capabilities: discovered.capabilities,
|
||||
}),
|
||||
...(Array.isArray(discovered.defaultInputModes) &&
|
||||
discovered.defaultInputModes.length > 0 && {
|
||||
defaultInputModes: discovered.defaultInputModes,
|
||||
}),
|
||||
...(Array.isArray(discovered.defaultOutputModes) &&
|
||||
discovered.defaultOutputModes.length > 0 && {
|
||||
defaultOutputModes: discovered.defaultOutputModes,
|
||||
}),
|
||||
...(discovered.provider && { provider: discovered.provider }),
|
||||
...(discovered.iconUrl && { iconUrl: discovered.iconUrl }),
|
||||
...(discovered.documentationUrl && {
|
||||
documentationUrl: discovered.documentationUrl,
|
||||
}),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const buildAgentData = (values: any) => {
|
||||
if (agentType === CUSTOM_AGENT_TYPE) {
|
||||
return {
|
||||
|
|
@ -226,10 +264,13 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({
|
|||
skills: [],
|
||||
},
|
||||
};
|
||||
} else if (agentType === "a2a") {
|
||||
return buildAgentDataFromForm(values);
|
||||
}
|
||||
|
||||
let agentData: Record<string, any>;
|
||||
if (agentType === "a2a") {
|
||||
agentData = buildAgentDataFromForm(values);
|
||||
} else if (selectedAgentTypeInfo?.use_a2a_form_fields) {
|
||||
const agentData = buildAgentDataFromForm(values);
|
||||
agentData = buildAgentDataFromForm(values);
|
||||
if (selectedAgentTypeInfo.litellm_params_template) {
|
||||
agentData.litellm_params = {
|
||||
...agentData.litellm_params,
|
||||
|
|
@ -242,42 +283,13 @@ const AddAgentForm: React.FC<AddAgentFormProps> = ({
|
|||
agentData.litellm_params[field.key] = value;
|
||||
}
|
||||
}
|
||||
return agentData;
|
||||
} else if (selectedAgentTypeInfo) {
|
||||
const agentData = buildDynamicAgentData(values, selectedAgentTypeInfo);
|
||||
// The dynamic form has no UI for skills, capabilities, or input/output
|
||||
// modes — buildDynamicAgentData fills those with a generic stub. If the
|
||||
// admin ran discovery, their selections are the only real source of
|
||||
// truth for these fields, so we overlay them here. Form-driven fields
|
||||
// (name, description, version, url) stay as-is.
|
||||
if (appliedDiscoveredSelection) {
|
||||
const discovered = appliedDiscoveredSelection.selected_card;
|
||||
agentData.agent_card_params = {
|
||||
...agentData.agent_card_params,
|
||||
...(Array.isArray(discovered.skills) && {
|
||||
skills: discovered.skills,
|
||||
}),
|
||||
...(discovered.capabilities && {
|
||||
capabilities: discovered.capabilities,
|
||||
}),
|
||||
...(Array.isArray(discovered.defaultInputModes) &&
|
||||
discovered.defaultInputModes.length > 0 && {
|
||||
defaultInputModes: discovered.defaultInputModes,
|
||||
}),
|
||||
...(Array.isArray(discovered.defaultOutputModes) &&
|
||||
discovered.defaultOutputModes.length > 0 && {
|
||||
defaultOutputModes: discovered.defaultOutputModes,
|
||||
}),
|
||||
...(discovered.provider && { provider: discovered.provider }),
|
||||
...(discovered.iconUrl && { iconUrl: discovered.iconUrl }),
|
||||
...(discovered.documentationUrl && {
|
||||
documentationUrl: discovered.documentationUrl,
|
||||
}),
|
||||
};
|
||||
}
|
||||
return agentData;
|
||||
agentData = buildDynamicAgentData(values, selectedAgentTypeInfo);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
return overlayDiscoveredCardParams(agentData);
|
||||
};
|
||||
|
||||
const handleCreateAgent = async () => {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
discoverAgentCardCall,
|
||||
} from "../networking";
|
||||
import {
|
||||
ALLOWED_CAPABILITY_KEYS,
|
||||
selectionsFromSavedAgentCard,
|
||||
selectionsFromUpstreamCard,
|
||||
skillId,
|
||||
|
|
@ -70,8 +71,6 @@ interface AgentCardDiscoveryProps {
|
|||
savedAgentCard?: DiscoveredAgentCard | null;
|
||||
}
|
||||
|
||||
const ALLOWED_CAPABILITY_KEYS = ["streaming"] as const;
|
||||
|
||||
const AgentCardDiscovery: React.FC<AgentCardDiscoveryProps> = ({
|
||||
accessToken,
|
||||
onApply,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface DiscoveryRequestPlan {
|
|||
export const skillId = (skill: any, idx: number): string =>
|
||||
skill?.id ?? skill?.name ?? `skill-${idx}`;
|
||||
|
||||
const ALLOWED_CAPABILITY_KEYS = ["streaming"] as const;
|
||||
export const ALLOWED_CAPABILITY_KEYS = ["streaming"] as const;
|
||||
|
||||
export const filterCapabilitiesForUI = (
|
||||
capabilities: Record<string, any> | undefined,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue