feat: enhance external tool routing with domains, intents, slots and examples
parent
a4f5859c81
commit
67585d17ce
|
|
@ -37,6 +37,11 @@ export interface ExternalToolApiRouting {
|
|||
summary: string;
|
||||
useWhen: string[];
|
||||
doNotUseWhen?: string[];
|
||||
domains?: string[];
|
||||
intents?: string[];
|
||||
requiredSlots?: string[];
|
||||
optionalSlots?: string[];
|
||||
examples?: string[];
|
||||
}
|
||||
|
||||
export interface ExternalToolApi {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@ const EMPTY_API: ToolApiFormValue = {
|
|||
summary: '',
|
||||
useWhen: [''],
|
||||
doNotUseWhen: [],
|
||||
domains: [],
|
||||
intents: [],
|
||||
requiredSlots: [],
|
||||
optionalSlots: [],
|
||||
examples: [],
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -132,6 +137,11 @@ function normalizeRouting(value: ToolApiRoutingFormValue | undefined, apiName: s
|
|||
summary: value.summary?.trim() || '',
|
||||
useWhen,
|
||||
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 || '',
|
||||
useWhen: item.routing?.useWhen?.length ? item.routing.useWhen : [''],
|
||||
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>
|
||||
)}
|
||||
</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>
|
||||
</>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -227,7 +227,21 @@ export default function KnowledgeSettingsPanel({
|
|||
),
|
||||
children: (
|
||||
<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>
|
||||
<strong>headers</strong>
|
||||
|
|
@ -238,6 +252,96 @@ export default function KnowledgeSettingsPanel({
|
|||
<pre>{JSON.stringify(api.parametersSchema || {}, null, 2)}</pre>
|
||||
</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>
|
||||
),
|
||||
})) || []}
|
||||
|
|
|
|||
Loading…
Reference in New Issue