暂未添加密钥
@@ -168,7 +185,14 @@ import { ref, reactive, computed, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import { getAgentApiDetail, createAgentApi, updateAgentApi } from '@/api/agentapimanagement'
-import { normalizeModels, normalizeApiKeys } from '../constants'
+import {
+ normalizeModels,
+ normalizeApiKeys,
+ PROTOCOLS,
+ PROTOCOL_MAP,
+ DEFAULT_PROTOCOL,
+ previewEndpoint,
+} from '../constants'
const emit = defineEmits(['saved'])
@@ -193,6 +217,7 @@ const inputRef = ref(null)
const form = reactive({
id: 0,
provider: '',
+ protocol: DEFAULT_PROTOCOL,
base_url: '',
use_custom_url: false,
custom_url: '',
@@ -202,8 +227,34 @@ const form = reactive({
remark: '',
})
+// 当前协议的说明文案
+const currentProtocolDesc = computed(
+ () => PROTOCOL_MAP[form.protocol]?.desc || ''
+)
+
+// 地址输入框的占位提示随协议变化
+const urlPlaceholder = computed(() => {
+ if (form.protocol === 'custom') {
+ return '填写完整端点,例如:https://your-gateway.com/invoke'
+ }
+ if (form.protocol === 'anthropic') {
+ return '填根地址,例如:https://api.anthropic.com/v1'
+ }
+ if (form.protocol === 'gemini') {
+ return '填根地址,例如:https://generativelanguage.googleapis.com/v1beta'
+ }
+ return '填根地址,例如:https://api.openai.com/v1'
+})
+
+// 最终请求地址预览,规则与后端一致
+const endpointPreview = computed(() => {
+ const url = form.use_custom_url ? form.custom_url : form.base_url
+ return previewEndpoint(form.protocol, url)
+})
+
const rules = {
provider: [{ required: true, message: '请输入上游接口名称', trigger: 'blur' }],
+ protocol: [{ required: true, message: '请选择请求协议', trigger: 'change' }],
base_url: [
{
validator: (rule, value, callback) => {
@@ -329,6 +380,7 @@ function validateKeys() {
function resetForm() {
form.id = 0
form.provider = ''
+ form.protocol = DEFAULT_PROTOCOL
form.base_url = ''
form.use_custom_url = false
form.custom_url = ''
@@ -394,6 +446,7 @@ async function loadInto(id) {
const d = res.data
form.id = d.id
form.provider = d.provider || ''
+ form.protocol = d.protocol || DEFAULT_PROTOCOL
form.base_url = d.base_url || ''
form.use_custom_url = Number(d.use_custom_url) === 1
form.custom_url = d.custom_url || ''
@@ -430,6 +483,7 @@ async function submit() {
const payload = {
provider: form.provider.trim(),
+ protocol: form.protocol,
base_url: form.base_url || '',
use_custom_url: form.use_custom_url ? 1 : 0,
custom_url: form.use_custom_url ? form.custom_url : '',
@@ -479,6 +533,19 @@ defineExpose({ open, openCopy })
margin-top: 6px;
}
+.endpoint-preview {
+ width: 100%;
+ padding: 6px 10px;
+ background: var(--el-fill-color-lighter);
+ border: 1px dashed var(--el-border-color);
+ border-radius: 4px;
+ font-family: Consolas, Monaco, monospace;
+ font-size: 12px;
+ color: #409eff;
+ word-break: break-all;
+ line-height: 1.5;
+}
+
.keys-box {
width: 100%;
}
diff --git a/platform/src/views/tools/agentapimanagement/components/test.vue b/platform/src/views/tools/agentapimanagement/components/test.vue
index 367278b..4ecac54 100644
--- a/platform/src/views/tools/agentapimanagement/components/test.vue
+++ b/platform/src/views/tools/agentapimanagement/components/test.vue
@@ -5,6 +5,9 @@
+
+
+
@@ -88,6 +91,9 @@
{{ r.message || (r.success ? '连接正常' : '连接异常') }}
+
+ 实际请求:{{ r.endpoint }}
+
{{ r.response }}
{{ r.detail }}
@@ -111,6 +117,7 @@ import {
normalizeModels,
normalizeApiKeys,
maskKey,
+ protocolLabel,
} from '../constants'
const visible = ref(false)
@@ -128,6 +135,7 @@ const results = ref([])
const info = reactive({
provider_label: '',
+ protocol_label: '',
url: '',
})
@@ -152,6 +160,7 @@ async function open(id) {
if (res?.code === 200 && res.data) {
const d = res.data
info.provider_label = providerLabel(d.provider)
+ info.protocol_label = protocolLabel(d.protocol)
info.url = effectiveUrl(d)
models.value = normalizeModels(d.models)
selectedModel.value = models.value[0] || ''
@@ -308,6 +317,15 @@ defineExpose({ open })
}
}
+ .result-endpoint {
+ margin-top: 6px;
+ font-size: 12px;
+ font-family: Consolas, Monaco, monospace;
+ color: #909399;
+ word-break: break-all;
+ line-height: 1.5;
+ }
+
.result-response {
margin: 8px 0 0;
padding: 8px 10px;
diff --git a/platform/src/views/tools/agentapimanagement/constants.js b/platform/src/views/tools/agentapimanagement/constants.js
index b98e380..1e5fc99 100644
--- a/platform/src/views/tools/agentapimanagement/constants.js
+++ b/platform/src/views/tools/agentapimanagement/constants.js
@@ -2,9 +2,75 @@
* 智能体 API 管理 - 共享工具
*
* 上游接口(provider)为用户自由填写的文本,不做枚举限制。
- * 这里只提供展示辅助(配色、首字母徽标)与数据规整能力。
+ * 请求协议(protocol)显式选择,决定实际请求哪个端点路径。
*/
+/**
+ * 请求协议枚举,与后端 models.AgentProtocol* 常量保持一致
+ * path 为在接口地址之后追加的路径,custom 与 gemini 特殊处理
+ */
+export const PROTOCOLS = [
+ {
+ value: 'chat_completions',
+ label: 'Chat Completions API',
+ path: '/chat/completions',
+ desc: 'OpenAI 标准对话接口,绝大多数上游与中转都兼容',
+ },
+ {
+ value: 'responses',
+ label: 'Responses API',
+ path: '/responses',
+ desc: 'OpenAI 新版接口,请求体用 input 替代 messages',
+ },
+ {
+ value: 'anthropic',
+ label: 'Anthropic Messages API',
+ path: '/messages',
+ desc: 'Claude 官方协议,鉴权头为 x-api-key',
+ },
+ {
+ value: 'gemini',
+ label: 'Google Gemini',
+ path: '/models/{model}:generateContent',
+ desc: '模型名嵌在路径中,密钥通过 query 传递',
+ },
+ {
+ value: 'custom',
+ label: '自定义(直接请求填写的地址)',
+ path: '',
+ desc: '不追加任何路径,把填写的地址当完整端点请求',
+ },
+];
+
+export const PROTOCOL_MAP = Object.fromEntries(PROTOCOLS.map((p) => [p.value, p]));
+
+export const DEFAULT_PROTOCOL = 'chat_completions';
+
+/** 协议展示名 */
+export function protocolLabel(value) {
+ return PROTOCOL_MAP[value]?.label || value || '未设置协议';
+}
+
+/**
+ * 预览实际请求地址,与后端 buildAgentEndpoint 的规则一致
+ * 供表单实时提示用,避免地址拼错才在测试时发现
+ */
+export function previewEndpoint(protocol, url, model = '{model}') {
+ const base = String(url || '').trim().replace(/\/+$/, '');
+ if (!base) return '';
+
+ if (protocol === 'custom') return base;
+
+ if (protocol === 'gemini') {
+ return `${base}/models/${model}:generateContent?key=***`;
+ }
+
+ const path = PROTOCOL_MAP[protocol]?.path || '/chat/completions';
+ // 地址已以该路径结尾时不重复追加
+ if (base.toLowerCase().endsWith(path.toLowerCase())) return base;
+ return base + path;
+}
+
/** 徽标配色池,按上游名称哈希稳定取色,保证同一上游每次渲染颜色一致 */
const BADGE_COLORS = [
'#10a37f',
diff --git a/platform/src/views/tools/agentapimanagement/index.vue b/platform/src/views/tools/agentapimanagement/index.vue
index 6194658..2fdbd03 100644
--- a/platform/src/views/tools/agentapimanagement/index.vue
+++ b/platform/src/views/tools/agentapimanagement/index.vue
@@ -108,6 +108,9 @@
接口地址
+
+ {{ protocolLabel(row.protocol) }}
+
自定义
@@ -264,6 +267,7 @@ import {
normalizeModels,
normalizeApiKeys,
maskKey,
+ protocolLabel,
} from './constants'
import AgentApiEdit from './components/edit.vue'
import AgentApiDetail from './components/detail.vue'