diff --git a/server/internal/api/admin_channels.go b/server/internal/api/admin_channels.go index ea6f747..f4912c5 100644 --- a/server/internal/api/admin_channels.go +++ b/server/internal/api/admin_channels.go @@ -33,7 +33,8 @@ func (h *Handler) AdminChannels(c *gin.Context) { masked = "****" } out = append(out, gin.H{ - "id": ch.ID, "name": ch.Name, "provider": ch.Provider, "formats": ch.FormatsEffective(), "base_url": ch.BaseURL, + "id": ch.ID, "name": ch.Name, "provider": ch.Provider, "formats": ch.FormatsEffective(), + "base_url": ch.BaseURL, "api_key_masked": masked, "weight": ch.Weight, "priority": ch.Priority, "timeout_ms": ch.TimeoutMS, "max_concurrency": ch.MaxConcurrency, "health_status": ch.HealthStatus, "enabled": ch.Enabled, @@ -47,7 +48,7 @@ type channelBody struct { Name string `json:"name" binding:"required,min=1,max=64"` Provider string `json:"provider"` // 可选:为空时按 formats 推断(兼容旧数据) Formats []string `json:"formats"` // 原生支持的协议 chat|responses|messages(主配置) - BaseURL string `json:"base_url"` // 可选:为空时按供应商默认(openai/anthropic) + BaseURL string `json:"base_url"` // 可选:留空按供应商默认;支持前缀或完整端点 APIKey string `json:"api_key"` Weight *int `json:"weight"` Priority *int `json:"priority"` @@ -56,7 +57,7 @@ type channelBody struct { Enabled *bool `json:"enabled"` } -// resolveBaseURL 渠道 base_url:留空按供应商默认;兼容用户填完整地址(含 /v1)。 +// resolveBaseURL 渠道 base_url:留空按供应商默认;网关按内容智能识别前缀/完整端点。 func resolveBaseURL(provider, raw string) (string, error) { base := strings.TrimRight(raw, "/") if base == "" { @@ -70,7 +71,7 @@ func resolveBaseURL(provider, raw string) (string, error) { if base == "" { return "", errors.New("base_url required for compatible channels") } - return strings.TrimSuffix(base, "/v1"), nil + return base, nil } func validateProvider(p string) bool { diff --git a/server/internal/proxy/passthrough.go b/server/internal/proxy/passthrough.go index 2669469..c8b4426 100644 --- a/server/internal/proxy/passthrough.go +++ b/server/internal/proxy/passthrough.go @@ -15,6 +15,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/openteam/server/internal/channel" "github.com/openteam/server/internal/store" ) diff --git a/web/src/lib/protocol.ts b/web/src/lib/protocol.ts index 47c3953..40cb03c 100644 --- a/web/src/lib/protocol.ts +++ b/web/src/lib/protocol.ts @@ -5,6 +5,17 @@ export const PROTOCOL_NAMES: Record = { messages: 'Anthropic Messages', } +// 渠道表格用的短标识 +export const PROTOCOL_SHORT: Record = { + chat: 'chat/completions', + responses: 'responses', + messages: 'messages', +} + +export function protocolShort(p: string): string { + return PROTOCOL_SHORT[p] ?? p +} + export const PROTOCOL_OPTIONS: { value: string; label: string }[] = [ { value: 'chat', label: 'OpenAI Chat Completions' }, { value: 'responses', label: 'OpenAI Responses API' }, diff --git a/web/src/views/admin/ChannelsView.vue b/web/src/views/admin/ChannelsView.vue index 7067461..d0965f4 100644 --- a/web/src/views/admin/ChannelsView.vue +++ b/web/src/views/admin/ChannelsView.vue @@ -2,12 +2,12 @@ import { onMounted, reactive, ref } from 'vue' import { http, errMsg } from '@/api/client' import { useToastStore } from '@/stores/toast' -import { PROTOCOL_OPTIONS, protocolName } from '@/lib/protocol' +import { PROTOCOL_OPTIONS, protocolShort } from '@/lib/protocol' import Button from '@/components/ui/Button.vue' import Input from '@/components/ui/Input.vue' import Modal from '@/components/ui/Modal.vue' import Badge from '@/components/ui/Badge.vue' -import type { Channel } from '@/types' +import type { Channel, ChannelModelMapping } from '@/types' const toast = useToastStore() const channels = ref([]) @@ -154,12 +154,12 @@ onMounted(load) {{ ch.name }} -
- + {{ protocolName(f) }} + class="font-mono text-[11px] leading-4 text-muted" + >{{ protocolShort(f) }}
{{ ch.base_url }} @@ -215,8 +215,8 @@ onMounted(load)