feat: enhance external tool routing with domains, intents, slots and examples
parent
a4f5859c81
commit
67585d17ce
|
|
@ -37,6 +37,11 @@ export interface ExternalToolApiRouting {
|
||||||
summary: string;
|
summary: string;
|
||||||
useWhen: string[];
|
useWhen: string[];
|
||||||
doNotUseWhen?: string[];
|
doNotUseWhen?: string[];
|
||||||
|
domains?: string[];
|
||||||
|
intents?: string[];
|
||||||
|
requiredSlots?: string[];
|
||||||
|
optionalSlots?: string[];
|
||||||
|
examples?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExternalToolApi {
|
export interface ExternalToolApi {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,11 @@ const EMPTY_API: ToolApiFormValue = {
|
||||||
summary: '',
|
summary: '',
|
||||||
useWhen: [''],
|
useWhen: [''],
|
||||||
doNotUseWhen: [],
|
doNotUseWhen: [],
|
||||||
|
domains: [],
|
||||||
|
intents: [],
|
||||||
|
requiredSlots: [],
|
||||||
|
optionalSlots: [],
|
||||||
|
examples: [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -132,6 +137,11 @@ function normalizeRouting(value: ToolApiRoutingFormValue | undefined, apiName: s
|
||||||
summary: value.summary?.trim() || '',
|
summary: value.summary?.trim() || '',
|
||||||
useWhen,
|
useWhen,
|
||||||
doNotUseWhen: normalizeStringList(value.doNotUseWhen),
|
doNotUseWhen: normalizeStringList(value.doNotUseWhen),
|
||||||
|
domains: normalizeStringList(value.domains),
|
||||||
|
intents: normalizeStringList(value.intents),
|
||||||
|
requiredSlots: normalizeStringList(value.requiredSlots),
|
||||||
|
optionalSlots: normalizeStringList(value.optionalSlots),
|
||||||
|
examples: normalizeStringList(value.examples),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,6 +259,11 @@ export default function ExternalToolEditor({ open, agentId, plugin, onClose, onS
|
||||||
summary: item.routing?.summary || '',
|
summary: item.routing?.summary || '',
|
||||||
useWhen: item.routing?.useWhen?.length ? item.routing.useWhen : [''],
|
useWhen: item.routing?.useWhen?.length ? item.routing.useWhen : [''],
|
||||||
doNotUseWhen: item.routing?.doNotUseWhen || [],
|
doNotUseWhen: item.routing?.doNotUseWhen || [],
|
||||||
|
domains: item.routing?.domains || [],
|
||||||
|
intents: item.routing?.intents || [],
|
||||||
|
requiredSlots: item.routing?.requiredSlots || [],
|
||||||
|
optionalSlots: item.routing?.optionalSlots || [],
|
||||||
|
examples: item.routing?.examples || [],
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
|
|
@ -469,6 +484,52 @@ export default function ExternalToolEditor({ open, agentId, plugin, onClose, onS
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
|
||||||
|
<div className="agent-editor-tool-grid" style={{ marginTop: 16 }}>
|
||||||
|
<Form.Item label="domains(领域)" name={[field.name, 'routing', 'domains']}>
|
||||||
|
<Select mode="tags" placeholder="例如:e-commerce, logistics" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="intents(意图)" name={[field.name, 'routing', 'intents']}>
|
||||||
|
<Select mode="tags" placeholder="例如:query_order, cancel_order" />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="agent-editor-tool-grid">
|
||||||
|
<Form.Item label="requiredSlots(必填槽位)" name={[field.name, 'routing', 'requiredSlots']}>
|
||||||
|
<Select mode="tags" placeholder="例如:order_id, user_id" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="optionalSlots(可选槽位)" name={[field.name, 'routing', 'optionalSlots']}>
|
||||||
|
<Select mode="tags" placeholder="例如:start_date, end_date" />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Form.List name={[field.name, 'routing', 'examples']}>
|
||||||
|
{(exampleFields, { add: addExample, remove: removeExample }) => (
|
||||||
|
<Space direction="vertical" size={8} className="agent-editor-tool-list" style={{ marginTop: 16 }}>
|
||||||
|
<div className="agent-editor-tool-list-header">
|
||||||
|
<div>
|
||||||
|
<strong>examples(示例)</strong>
|
||||||
|
<div className="agent-editor-tool-help">描述用户可能的提问方式。</div>
|
||||||
|
</div>
|
||||||
|
<Button type="dashed" icon={<PlusOutlined />} onClick={() => addExample('')}>
|
||||||
|
添加示例
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{exampleFields.map((exampleField) => (
|
||||||
|
<Space key={exampleField.key} align="start" className="agent-editor-tool-list">
|
||||||
|
<Form.Item
|
||||||
|
name={exampleField.name}
|
||||||
|
className="flex-1 mb-0"
|
||||||
|
rules={[{ validator: validateTrimmedText('示例不能为空') }]}
|
||||||
|
>
|
||||||
|
<Input placeholder="我想查一下最近的订单" style={{ width: 600 }} />
|
||||||
|
</Form.Item>
|
||||||
|
<Button danger type="text" icon={<MinusCircleOutlined />} onClick={() => removeExample(exampleField.name)} />
|
||||||
|
</Space>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
</Form.List>
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,21 @@ export default function KnowledgeSettingsPanel({
|
||||||
),
|
),
|
||||||
children: (
|
children: (
|
||||||
<div className="agent-editor-api-detail">
|
<div className="agent-editor-api-detail">
|
||||||
<div>{api.description || '暂无描述'}</div>
|
<div className="mb-2">{api.description || '暂无描述'}</div>
|
||||||
|
|
||||||
|
{api.routing?.requiredSlots?.length ? (
|
||||||
|
<div className="mb-3 p-2 bg-orange-50 border border-orange-100 rounded">
|
||||||
|
<div className="text-[10px] text-orange-400 mb-1 font-bold uppercase tracking-wider">调用前关键信息提示</div>
|
||||||
|
<Space wrap size={[4, 4]}>
|
||||||
|
{api.routing.requiredSlots.map((slot) => (
|
||||||
|
<Tag key={slot} color="orange" className="m-0 border-none bg-orange-200 text-orange-700">
|
||||||
|
{slot}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<div className="agent-editor-api-config-grid">
|
<div className="agent-editor-api-config-grid">
|
||||||
<div>
|
<div>
|
||||||
<strong>headers</strong>
|
<strong>headers</strong>
|
||||||
|
|
@ -238,6 +252,96 @@ export default function KnowledgeSettingsPanel({
|
||||||
<pre>{JSON.stringify(api.parametersSchema || {}, null, 2)}</pre>
|
<pre>{JSON.stringify(api.parametersSchema || {}, null, 2)}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-3 pt-3 border-t border-gray-100">
|
||||||
|
<div className="text-[10px] text-gray-400 mb-2 font-bold uppercase tracking-wider">Routing (路由规则)</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Summary</div>
|
||||||
|
<div className="text-xs text-gray-500">{api.routing?.summary || '-'}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
{api.routing?.domains?.length ? (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Domains</div>
|
||||||
|
<Space wrap size={[4, 4]}>
|
||||||
|
{api.routing.domains.map((d) => (
|
||||||
|
<Tag key={d} className="m-0 text-[10px] px-1 leading-4">
|
||||||
|
{d}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{api.routing?.intents?.length ? (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Intents</div>
|
||||||
|
<Space wrap size={[4, 4]}>
|
||||||
|
{api.routing.intents.map((i) => (
|
||||||
|
<Tag key={i} className="m-0 text-[10px] px-1 leading-4">
|
||||||
|
{i}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
{api.routing?.useWhen?.length ? (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Use When</div>
|
||||||
|
<div className="text-[11px] text-gray-500 space-y-1">
|
||||||
|
{api.routing.useWhen.map((item, idx) => (
|
||||||
|
<div key={idx} className="flex gap-1">
|
||||||
|
<span>·</span>
|
||||||
|
<span>{item}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{api.routing?.doNotUseWhen?.length ? (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Do Not Use When</div>
|
||||||
|
<div className="text-[11px] text-gray-500 space-y-1">
|
||||||
|
{api.routing.doNotUseWhen.map((item, idx) => (
|
||||||
|
<div key={idx} className="flex gap-1">
|
||||||
|
<span>·</span>
|
||||||
|
<span>{item}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{api.routing?.optionalSlots?.length ? (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Optional Slots</div>
|
||||||
|
<Space wrap size={[4, 4]}>
|
||||||
|
{api.routing.optionalSlots.map((slot) => (
|
||||||
|
<Tag key={slot} className="m-0 text-[10px] px-1 leading-4">
|
||||||
|
{slot}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
{api.routing?.examples?.length ? (
|
||||||
|
<div>
|
||||||
|
<div className="text-xs font-medium text-gray-600 mb-1">Examples</div>
|
||||||
|
<div className="text-[11px] text-gray-500 italic space-y-1 bg-gray-50 p-2 rounded">
|
||||||
|
{api.routing.examples.map((ex, idx) => (
|
||||||
|
<div key={idx}>"{ex}"</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
})) || []}
|
})) || []}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue