diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 3033d0209..eab59c888 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -58,6 +58,7 @@ import { type SiteBranding, type SessionCapabilities, type StudioAccess, + type UiConfig, type UiFeatures, } from "./adk/client"; import { @@ -100,6 +101,7 @@ import { type AgentEntry, type RemoteConnection, } from "./adk/connections"; +import { defaultCloudRegion, formatCloudRegion } from "./adk/cloudProvider"; import { Blocks, ThinkingPlaceholder } from "./ui/Blocks"; import { Composer } from "./ui/Composer"; import { InvocationChips } from "./ui/InvocationChips"; @@ -165,6 +167,7 @@ import { SandboxAgentWorkspace } from "./ui/SandboxAgentWorkspace"; import { SandboxComposer } from "./ui/SandboxComposer"; import { sandboxSnapshotTurns } from "./ui/sandboxCommands"; import { useSandboxCodexCommands } from "./ui/useSandboxCodexCommands"; +import byteplusLogo from "./assets/byteplus.svg"; import defaultSiteLogo from "./assets/logo.svg"; import { FeedbackDownIcon, @@ -945,6 +948,8 @@ export default function App() { }); const [agentsSource, setAgentsSource] = useState<"local" | "cloud">("cloud"); const [siteBranding, setSiteBranding] = useState(DEFAULT_SITE_BRANDING); + const [cloudProvider, setCloudProvider] = + useState("volcengine"); const [version, setVersion] = useState(""); const [uiConfigLoaded, setUiConfigLoaded] = useState(false); const [localMode, setLocalMode] = useState(false); @@ -1135,7 +1140,7 @@ export default function App() { return next; }); }, []); - // Whether the server has Volcengine AK/SK. The agent-creation workbench needs + // Whether the server has cloud AK/SK. The agent-creation workbench needs // them; assume present until the runtime-config check says otherwise (avoids // flashing the notice in the common, configured case). const [hasCreds, setHasCreds] = useState(true); @@ -1198,7 +1203,9 @@ export default function App() { appName?: string; currentVersion?: number | null; } | null>(null); - const [newRuntimeRegion, setNewRuntimeRegion] = useState("cn-beijing"); + const [newRuntimeRegion, setNewRuntimeRegion] = useState( + defaultCloudRegion(cloudProvider), + ); const [focusedDeploymentTaskId, setFocusedDeploymentTaskId] = useState(""); const [focusedWorkspaceAgentId, setFocusedWorkspaceAgentId] = useState(""); const [agentDetailTarget, setAgentDetailTarget] = @@ -1849,6 +1856,7 @@ export default function App() { trackStudioLoaded({ agentsSource: cfg.agentsSource }); setFeatures(cfg.features); setAgentsSource(cfg.agentsSource); + setCloudProvider(cfg.provider); setSiteBranding(cfg.branding); setVersion(cfg.version); setUiConfigLoaded(true); @@ -1864,6 +1872,20 @@ export default function App() { }); }, [access, authStatus, localMode, userInfo]); + useEffect(() => { + setNewRuntimeRegion((region) => { + const providerDefault = defaultCloudRegion(cloudProvider); + if (!region) return providerDefault; + if (cloudProvider === "byteplus" && region.startsWith("cn-")) { + return providerDefault; + } + if (cloudProvider === "volcengine" && region.startsWith("ap-")) { + return providerDefault; + } + return region; + }); + }, [cloudProvider]); + useEffect(() => { if (!access) return; if (!access.capabilities.createAgents) { @@ -1898,10 +1920,11 @@ export default function App() { document.head.appendChild(favicon); } favicon.removeAttribute("type"); - favicon.href = siteBranding.logoUrl || defaultSiteLogo; - }, [siteBranding]); + favicon.href = siteBranding.logoUrl + || (cloudProvider === "byteplus" ? byteplusLogo : defaultSiteLogo); + }, [cloudProvider, siteBranding]); - // Check whether the server has Volcengine AK/SK (needed by the workbench). + // Check whether the server has cloud AK/SK (needed by the workbench). useEffect(() => { fetch("/web/runtime-config", { signal: AbortSignal.timeout(10_000) }) .then((r) => (r.ok ? r.json() : null)) @@ -3686,7 +3709,13 @@ export default function App() { return
; // resolving identity } if (authStatus === "unauthenticated") { - return ; + return ( + + ); } if (!access) { return
; @@ -3842,7 +3871,7 @@ export default function App() { if (currentConn?.runtimeId && currentRuntimeAppName) { upsertCachedAgentFeedbackCase({ runtimeId: currentConn.runtimeId, - region: currentConn.region ?? "cn-beijing", + region: currentConn.region ?? defaultCloudRegion(cloudProvider), appName: currentRuntimeAppName, userId, sessionId: sid, @@ -3887,7 +3916,7 @@ export default function App() { if (currentConn?.runtimeId && currentRuntimeAppName) { upsertCachedAgentFeedbackCase({ runtimeId: currentConn.runtimeId, - region: currentConn.region ?? "cn-beijing", + region: currentConn.region ?? defaultCloudRegion(cloudProvider), appName: currentRuntimeAppName, userId, sessionId: sid, @@ -3902,7 +3931,7 @@ export default function App() { }); refreshAgentFeedbackCases({ runtimeId: currentConn.runtimeId, - region: currentConn.region ?? "cn-beijing", + region: currentConn.region ?? defaultCloudRegion(cloudProvider), appName: currentRuntimeAppName, pageSize: 100, }); @@ -3918,7 +3947,7 @@ export default function App() { if (currentConn?.runtimeId && currentRuntimeAppName) { upsertCachedAgentFeedbackCase({ runtimeId: currentConn.runtimeId, - region: currentConn.region ?? "cn-beijing", + region: currentConn.region ?? defaultCloudRegion(cloudProvider), appName: currentRuntimeAppName, userId, sessionId: sid, @@ -4110,7 +4139,7 @@ export default function App() { const agentId = await connectRuntime( agent.runtimeId, agent.label, - agent.region ?? "cn-beijing", + agent.region ?? defaultCloudRegion(cloudProvider), agent.currentVersion, ); trackAgentConnectSucceeded({ @@ -4170,6 +4199,7 @@ export default function App() {
) : myAgents ? ( setAddAgent(false)} /> ) : skillCenter ? ( - + ) : visibleCreateView !== null && !hasCreds ? (
- 需要配置火山引擎 AK/SK + 需要配置{cloudProvider === "byteplus" ? "BytePlus" : "火山引擎"} AK/SK
- 智能体工作台需要 Volcengine 凭据才能使用。请在运行环境中设置 - {" "} - VOLCENGINE_ACCESS_KEY 与{" "} - VOLCENGINE_SECRET_KEY 后重试。 + 智能体工作台需要 + {cloudProvider === "byteplus" ? " BytePlus " : " Volcengine "} + 凭据才能使用。请在运行环境中设置{" "} + + {cloudProvider === "byteplus" + ? "BYTEPLUS_ACCESS_KEY" + : "VOLCENGINE_ACCESS_KEY"} + {" "} + 与{" "} + + {cloudProvider === "byteplus" + ? "BYTEPLUS_SECRET_KEY" + : "VOLCENGINE_SECRET_KEY"} + {" "} + 后重试。
) : visibleCreateView === "menu" ? ( @@ -4840,6 +4884,7 @@ export default function App() { ) : visibleCreateView === "intelligent" ? ( setCreateView("menu")} onCreate={onCreate} onAgentAdded={onAgentAdded} @@ -4848,6 +4893,7 @@ export default function App() { ) : visibleCreateView === "custom" ? ( setCreateView("menu")} onCreate={onCreate} @@ -4886,11 +4932,20 @@ export default function App() { onDeploymentComplete={finishDeployment} /> ) : visibleCreateView === "template" ? ( - setCreateView("menu")} onCreate={onCreate} /> + setCreateView("menu")} + onCreate={onCreate} + /> ) : visibleCreateView === "workflow" ? ( - setCreateView("menu")} onCreate={onCreate} /> + setCreateView("menu")} + onCreate={onCreate} + /> ) : visibleCreateView === "package" ? ( { setCreateView(null); setAddMenu(true); diff --git a/frontend/src/adk/client.ts b/frontend/src/adk/client.ts index 5aed9cfc3..3c8d75512 100644 --- a/frontend/src/adk/client.ts +++ b/frontend/src/adk/client.ts @@ -20,6 +20,7 @@ import { import type { AgentProject } from "../create/project"; import type { AgentDraft, NetworkConfig } from "../create/types"; import type { IssueFeedbackReport } from "./issueFeedback"; +import { VOLCENGINE_DEFAULT_REGION } from "./cloudProvider"; /** An ADK event as serialised over `/run_sse` (camelCase, by_alias=True). */ export interface AdkUsage { @@ -516,7 +517,10 @@ function runtimeAppsCacheKey(runtimeId: string, region: string): string { } function runtimeRegionCandidates(region?: string): string[] { - const primary = region || "cn-beijing"; + const primary = region || VOLCENGINE_DEFAULT_REGION; + if (!RUNTIME_REGION_FALLBACKS.includes(primary as (typeof RUNTIME_REGION_FALLBACKS)[number])) { + return [primary]; + } return [ primary, ...RUNTIME_REGION_FALLBACKS.filter((candidate) => candidate !== primary), @@ -2053,7 +2057,7 @@ export interface ManagedRuntime { /** List AgentKit runtimes the server authorizes this user to manage. */ export async function getMyRuntimes( - region = "cn-beijing", + region = VOLCENGINE_DEFAULT_REGION, ): Promise { const res = await apiFetch(`/web/my-runtimes?region=${encodeURIComponent(region)}`); if (!res.ok) throw new Error(`加载失败 (${res.status})`); @@ -2107,6 +2111,7 @@ export interface StudioTelemetryConfig { export interface UiConfig { studio: boolean; version: string; + provider: "volcengine" | "byteplus"; branding: SiteBranding; features: UiFeatures; defaultView: "chat" | "addAgent"; @@ -2128,6 +2133,7 @@ const DISABLED_STUDIO_TELEMETRY: StudioTelemetryConfig = { const DEFAULT_UI_CONFIG: UiConfig = { studio: false, version: "", + provider: "volcengine", branding: DEFAULT_SITE_BRANDING, features: { newChat: true, @@ -2204,6 +2210,7 @@ export async function getUiConfig(): Promise { return { studio: d.studio ?? false, version: typeof d.version === "string" ? d.version : "", + provider: d.provider === "byteplus" ? "byteplus" : "volcengine", branding: { title: typeof d.branding?.title === "string" ? d.branding.title diff --git a/frontend/src/adk/cloudProvider.ts b/frontend/src/adk/cloudProvider.ts new file mode 100644 index 000000000..8aa45d84e --- /dev/null +++ b/frontend/src/adk/cloudProvider.ts @@ -0,0 +1,65 @@ +export type CloudProvider = "volcengine" | "byteplus"; + +export interface CloudRegionOption { + value: string; + label: string; +} + +export const BYTEPLUS_DEFAULT_REGION = "ap-southeast-1"; +export const VOLCENGINE_DEFAULT_REGION = "cn-beijing"; +export const BYTEPLUS_MODELARK_BASE_URL = "https://ark.ap-southeast.bytepluses.com/api/v3"; +export const VOLCENGINE_MODELARK_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3/"; +export const BYTEPLUS_DEFAULT_MODEL_NAME = "seed-2-0-lite-260228"; +export const VOLCENGINE_DEFAULT_MODEL_NAME = "doubao-seed-2-1-pro-260628"; +export const BYTEPLUS_DEFAULT_EMBEDDING_NAME = "skylark-embedding-vision-250615"; +export const VOLCENGINE_DEFAULT_EMBEDDING_NAME = "doubao-embedding-vision-250615"; +export const BYTEPLUS_PLANNER_MODEL_NAME = "seed-2-0-lite-260228"; +export const VOLCENGINE_PLANNER_MODEL_NAME = "doubao-seed-2-0-lite-260428"; + +const VOLCENGINE_REGIONS: CloudRegionOption[] = [ + { value: "cn-beijing", label: "华北 2(北京)" }, + { value: "cn-shanghai", label: "华东 2(上海)" }, +]; + +const BYTEPLUS_REGIONS: CloudRegionOption[] = [ + { value: BYTEPLUS_DEFAULT_REGION, label: "ap-southeast-1 (Singapore)" }, +]; + +export function cloudRegionOptions(provider: CloudProvider): CloudRegionOption[] { + return provider === "byteplus" ? BYTEPLUS_REGIONS : VOLCENGINE_REGIONS; +} + +export function defaultCloudRegion(provider: CloudProvider): string { + return cloudRegionOptions(provider)[0]?.value || VOLCENGINE_DEFAULT_REGION; +} + +export function formatCloudRegion(region: string, provider?: CloudProvider): string { + const options = provider + ? cloudRegionOptions(provider) + : [...VOLCENGINE_REGIONS, ...BYTEPLUS_REGIONS]; + return options.find((option) => option.value === region)?.label || region || "-"; +} + +export function defaultModelName(provider: CloudProvider): string { + return provider === "byteplus" + ? BYTEPLUS_DEFAULT_MODEL_NAME + : VOLCENGINE_DEFAULT_MODEL_NAME; +} + +export function defaultModelApiBase(provider: CloudProvider): string { + return provider === "byteplus" + ? BYTEPLUS_MODELARK_BASE_URL + : VOLCENGINE_MODELARK_BASE_URL; +} + +export function defaultEmbeddingModelName(provider: CloudProvider): string { + return provider === "byteplus" + ? BYTEPLUS_DEFAULT_EMBEDDING_NAME + : VOLCENGINE_DEFAULT_EMBEDDING_NAME; +} + +export function plannerModelName(provider: CloudProvider): string { + return provider === "byteplus" + ? BYTEPLUS_PLANNER_MODEL_NAME + : VOLCENGINE_PLANNER_MODEL_NAME; +} diff --git a/frontend/src/adk/connections.ts b/frontend/src/adk/connections.ts index db0373a34..8b939123d 100644 --- a/frontend/src/adk/connections.ts +++ b/frontend/src/adk/connections.ts @@ -47,6 +47,9 @@ const RUNTIME_REGION_FALLBACKS = ["cn-beijing", "cn-shanghai"] as const; function runtimeRegionCandidates(region: string): string[] { const primary = region || "cn-beijing"; + if (!RUNTIME_REGION_FALLBACKS.includes(primary as (typeof RUNTIME_REGION_FALLBACKS)[number])) { + return [primary]; + } return [ primary, ...RUNTIME_REGION_FALLBACKS.filter((candidate) => candidate !== primary), diff --git a/frontend/src/assets/byteplus.svg b/frontend/src/assets/byteplus.svg new file mode 100644 index 000000000..18fcff669 --- /dev/null +++ b/frontend/src/assets/byteplus.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/create/CodePackageCreate.tsx b/frontend/src/create/CodePackageCreate.tsx index 9b76b1413..d7649eb18 100644 --- a/frontend/src/create/CodePackageCreate.tsx +++ b/frontend/src/create/CodePackageCreate.tsx @@ -6,6 +6,10 @@ import { type DragEvent, } from "react"; import { deployAgentkitProject, type DeployStage } from "../adk/client"; +import { + defaultCloudRegion, + type CloudProvider, +} from "../adk/cloudProvider"; import { ProjectPreview, type DeployResult, @@ -28,6 +32,7 @@ interface CodePackageCreateProps { onDeploymentStarted?: (task: DeploymentTaskUpdate) => void; onDeploymentComplete?: (result: DeployResult) => void | Promise; initialDeployRegion?: string; + cloudProvider?: CloudProvider; } function packageProjectName(fileName: string): string { @@ -88,7 +93,8 @@ export function CodePackageCreate({ onDeploymentTaskChange, onDeploymentStarted, onDeploymentComplete, - initialDeployRegion = "cn-beijing", + cloudProvider = "volcengine", + initialDeployRegion = defaultCloudRegion(cloudProvider), }: CodePackageCreateProps) { const inputRef = useRef(null); const loadRunRef = useRef(0); @@ -178,6 +184,7 @@ export function CodePackageCreate({ return (
{ + if (item.key === "MODEL_EMBEDDING_NAME") { + return { ...item, placeholder: defaultEmbeddingModelName(cloudProvider) }; + } + if (item.key === "MODEL_EMBEDDING_API_BASE") { + return { ...item, placeholder: defaultModelApiBase(cloudProvider) }; + } + return item; + }); +} + /* ---------------------------------------------------------------- * * Multi-select checklist. Each row = label + desc, toggling the id in * `selected`. Used for built-in tools and tracing exporters. @@ -564,7 +593,9 @@ function a2aSpaceDisplayName(space: A2aSpaceRef): string { } function vikingKnowledgebaseDisplayName(item: VikingKnowledgebaseRef): string { - return item.name.trim() || item.id || "未命名知识库"; + const name = item.name.trim() || item.id || "未命名知识库"; + const details = [item.sourceLabel, item.projectName].filter(Boolean); + return details.length ? `${name} · ${details.join(" · ")}` : name; } function A2aSpaceSelect({ @@ -664,7 +695,7 @@ function A2aSpaceSelect({ }; return ( -
+
@@ -933,6 +982,14 @@ function VikingKnowledgebaseSelect({ {filteredItems.map((item) => { const optionLabel = vikingKnowledgebaseDisplayName(item); const selected = item.id === value; + const optionIds = [ + item.id, + item.resourceId, + item.agentkitKnowledgeId, + item.providerKnowledgeId, + ] + .filter(Boolean) + .join(" / "); return ( @@ -1226,9 +1283,11 @@ const SKILL_SOURCES: { function SkillsSourceTabs({ selected, onChange, + cloudProvider, }: { selected: SelectedSkill[]; onChange: (next: SelectedSkill[]) => void; + cloudProvider: CloudProvider; }) { const [active, setActive] = useState("local"); const [open, setOpen] = useState(false); @@ -1355,7 +1414,11 @@ function SkillsSourceTabs({ )} {active === "skillspace" && ( - + )}
@@ -1445,10 +1508,14 @@ function updateNode( return { ...root, subAgents }; } -function addChild(root: AgentDraft, path: NodePath): AgentDraft { +function addChild( + root: AgentDraft, + path: NodePath, + cloudProvider: CloudProvider = "volcengine", +): AgentDraft { return updateNode(root, path, (n) => ({ ...n, - subAgents: [...n.subAgents, emptyDraft()], + subAgents: [...n.subAgents, emptyDraft(cloudProvider)], })); } @@ -1456,10 +1523,11 @@ function insertChild( root: AgentDraft, parentPath: NodePath, index: number, + cloudProvider: CloudProvider = "volcengine", ): AgentDraft { return updateNode(root, parentPath, (n) => { const subAgents = n.subAgents.slice(); - subAgents.splice(index, 0, emptyDraft()); + subAgents.splice(index, 0, emptyDraft(cloudProvider)); return { ...n, subAgents }; }); } @@ -1575,10 +1643,11 @@ function collectDeploymentEnv(root: AgentDraft): RuntimeEnvConfiguration { const prepared = prepareMcpAuth(root); const selections: RuntimeEnvSelection[] = []; const fixedValues: Record = { ...prepared.envValues }; + const cloudProvider = prepared.draft.cloudProvider ?? "volcengine"; const visit = (node: AgentDraft) => { for (const toolId of node.builtinTools ?? []) { const tool = BUILTIN_TOOLS.find((item) => item.id === toolId); - if (tool) selections.push({ env: tool.env }); + if (tool) selections.push({ env: providerRuntimeEnv(tool.env, cloudProvider) }); } for (const mcpTool of node.mcpTools ?? []) { if (mcpTool.authTokenEnv) { @@ -1603,26 +1672,35 @@ function collectDeploymentEnv(root: AgentDraft): RuntimeEnvConfiguration { if (node.memory.shortTerm) { selections.push({ env: - STM_BACKENDS.find( - (item) => item.id === (node.shortTermBackend ?? "local"), - )?.env ?? [], + providerRuntimeEnv( + STM_BACKENDS.find( + (item) => item.id === (node.shortTermBackend ?? "local"), + )?.env ?? [], + cloudProvider, + ), }); } if (node.memory.longTerm) { selections.push({ env: - LTM_BACKENDS.find( - (item) => item.id === (node.longTermBackend ?? "local"), - )?.env ?? [], + providerRuntimeEnv( + LTM_BACKENDS.find( + (item) => item.id === (node.longTermBackend ?? "local"), + )?.env ?? [], + cloudProvider, + ), }); } if (node.knowledgebase) { selections.push({ env: - KB_BACKENDS.find( - (item) => - item.id === (node.knowledgebaseBackend ?? DEFAULT_KB_BACKEND), - )?.env ?? [], + providerRuntimeEnv( + KB_BACKENDS.find( + (item) => + item.id === (node.knowledgebaseBackend ?? DEFAULT_KB_BACKEND), + )?.env ?? [], + cloudProvider, + ), }); } if (node.tracing) { @@ -2490,6 +2568,8 @@ interface CustomCreateProps extends CreateModeProps { }; /** Region selected before entering the create flow. */ initialDeployRegion?: string; + /** Cloud provider selected by the Studio shell. */ + cloudProvider?: CloudProvider; /** Called after an existing Runtime has been updated and released. */ onDeploymentComplete?: (result: DeployResult) => void | Promise; /** Called once the persistent deployment task has been created. */ @@ -2509,7 +2589,8 @@ export function CustomCreate({ onDeploymentTaskChange, createMode = "custom", deploymentTarget, - initialDeployRegion = "cn-beijing", + cloudProvider = "volcengine", + initialDeployRegion = defaultCloudRegion(cloudProvider), onDeploymentComplete, onDeploymentStarted, onDraftChange, @@ -2519,8 +2600,37 @@ export function CustomCreate({ void onBack; // no footer nav in the single-scroll layout; back lives in app chrome void onDiscard; // the discard action is intentionally hidden in this flow const [draft, setDraft] = useState( - () => initialDraft ?? emptyDraft(), + () => initialDraft ?? emptyDraft(cloudProvider), ); + useEffect(() => { + const otherProviderModel = cloudProvider === "byteplus" + ? VOLCENGINE_DEFAULT_MODEL_NAME + : BYTEPLUS_DEFAULT_MODEL_NAME; + const otherProviderBase = cloudProvider === "byteplus" + ? VOLCENGINE_MODELARK_BASE_URL + : BYTEPLUS_MODELARK_BASE_URL; + setDraft((current) => { + const nextModelName = + current.modelName?.trim() === otherProviderModel + ? defaultModelName(cloudProvider) + : current.modelName; + const nextModelApiBase = + current.modelApiBase?.trim() === otherProviderBase + ? defaultModelApiBase(cloudProvider) + : current.modelApiBase; + if ( + nextModelName === current.modelName && + nextModelApiBase === current.modelApiBase + ) { + return current; + } + return { + ...current, + modelName: nextModelName, + modelApiBase: nextModelApiBase, + }; + }); + }, [cloudProvider]); const [aiRequirement, setAiRequirement] = useState(""); const [aiGenerating, setAiGenerating] = useState(false); const [aiGenerated, setAiGenerated] = useState(false); @@ -2561,9 +2671,9 @@ export function CustomCreate({ { id: "baseline", name: "基准组", - modelName: defaultDebugModelName(initialDraft ?? emptyDraft()), - description: (initialDraft ?? emptyDraft()).description, - instruction: (initialDraft ?? emptyDraft()).instruction, + modelName: defaultDebugModelName(initialDraft ?? emptyDraft(cloudProvider)), + description: (initialDraft ?? emptyDraft(cloudProvider)).description, + instruction: (initialDraft ?? emptyDraft(cloudProvider)).instruction, optimizations: [], configOpen: false, phase: "idle", @@ -2779,7 +2889,7 @@ export function CustomCreate({ const addCanvasStep = (path: NodePath) => { const parent = getNode(draft, path); if (!nodeAcceptsChildren(parent) || path.length >= MAX_TREE_DEPTH) return; - const next = addChild(draft, path); + const next = addChild(draft, path, cloudProvider); const childIndex = getNode(next, path).subAgents.length - 1; applyTree(next, [...path, childIndex]); }; @@ -2793,7 +2903,7 @@ export function CustomCreate({ return; } const safeIndex = Math.max(0, Math.min(index, parent.subAgents.length)); - const next = insertChild(draft, parentPath, safeIndex); + const next = insertChild(draft, parentPath, safeIndex, cloudProvider); applyTree(next, [...parentPath, safeIndex]); }; @@ -2803,7 +2913,7 @@ export function CustomCreate({ ) { return; } - setDraft(emptyDraft()); + setDraft(emptyDraft(cloudProvider)); setSelectedPath([]); setShowErrors(false); }; @@ -3399,7 +3509,7 @@ export function CustomCreate({ value={aiRequirement} maxLength={8000} disabled={aiGenerating} - placeholder="描述目标,使用 doubao-seed-2-0-lite-260428 模型一键生成配置" + placeholder={`描述目标,使用 ${plannerModelName(cloudProvider)} 模型一键生成配置`} aria-invalid={Boolean(aiRequirementError)} aria-describedby={ aiRequirementError ? "ai-requirement-error" : undefined @@ -3735,7 +3845,7 @@ export function CustomCreate({ patch({ modelName: e.target.value }) } @@ -3786,7 +3896,7 @@ export function CustomCreate({ patch({ modelApiBase: e.target.value }) } @@ -3862,6 +3972,7 @@ export function CustomCreate({ patch({ selectedSkills: next })} + cloudProvider={cloudProvider} />
@@ -3897,9 +4008,33 @@ export function CustomCreate({ - patch({ knowledgebaseIndex }) - } + onChange={(knowledgebase) => { + patch({ + knowledgebaseIndex: knowledgebase.id, + }); + if (knowledgebase.projectName) { + patchDeploymentEnv( + "DATABASE_VIKING_PROJECT", + knowledgebase.projectName, + ); + } + if (knowledgebase.region) { + patchDeploymentEnv( + "DATABASE_VIKING_REGION", + knowledgebase.region, + ); + } + if (knowledgebase.sourceKind) { + patchDeploymentEnv( + "DATABASE_VIKING_COLLECTION_KIND", + knowledgebase.sourceKind, + ); + } + patchDeploymentEnv( + "DATABASE_VIKING_RESOURCE_ID", + knowledgebase.resourceId ?? "", + ); + }} />
)} @@ -4067,6 +4202,7 @@ export function CustomCreate({ {project ? ( void; onCreate: (draft: AgentDraft) => void; @@ -83,7 +86,10 @@ function stripFence(raw: string): string { * backend to produce the project. Tolerant of surrounding * prose: falls back to the first `{ … }` slice. Returns null when the text * isn't a config (e.g. a clarifying question). */ -async function parseProject(raw: string): Promise { +async function parseProject( + raw: string, + cloudProvider: CloudProvider = "volcengine", +): Promise { const candidates: string[] = []; const stripped = stripFence(raw); candidates.push(stripped); @@ -103,7 +109,7 @@ async function parseProject(raw: string): Promise { typeof (obj as Record).instruction === "string") ) { // Shared path: config -> normalized draft -> backend generated files. - return await generateAgentProject(normalizeDraft(obj)); + return await generateAgentProject(normalizeDraft({ ...obj, cloudProvider })); } } catch { /* try next candidate */ @@ -114,6 +120,7 @@ async function parseProject(raw: string): Promise { export function IntelligentCreate({ userId, + cloudProvider = "volcengine", onBack, onCreate, onAgentAdded, @@ -219,7 +226,7 @@ export function IntelligentCreate({ acc = applyEvent(acc, evt); } const finalText = accText(acc).trim(); - return { project: await parseProject(finalText), finalText }; + return { project: await parseProject(finalText, cloudProvider), finalText }; } const handleDeploy = async ( @@ -308,7 +315,7 @@ export function IntelligentCreate({ } const finalText = accText(acc).trim(); - const parsed = await parseProject(finalText); + const parsed = await parseProject(finalText, cloudProvider); if (parsed) { setProject(parsed); pushAssistant( diff --git a/frontend/src/create/SkillSpacePicker.tsx b/frontend/src/create/SkillSpacePicker.tsx index d2912b7df..978989edf 100644 --- a/frontend/src/create/SkillSpacePicker.tsx +++ b/frontend/src/create/SkillSpacePicker.tsx @@ -1,4 +1,4 @@ -// Volcengine AgentKit SkillSpace picker. Lists account-scoped SkillSpaces via +// AgentKit SkillSpace picker. Lists account-scoped SkillSpaces via // the server-side /web/skill-spaces* routes (which sign with the SERVER's AK/SK // so the browser never sees credentials), lists skills within a chosen space, // and lets the user toggle them into the draft. SKILL.md content is fetched at @@ -17,19 +17,19 @@ import { } from "./skills/skillspace"; import type { SelectedSkill, SkillHit } from "./skills/types"; import { displayDescription } from "./displayText"; - -function regionLabel(region: string): string { - if (region === "cn-beijing") return "北京"; - if (region === "cn-shanghai") return "上海"; - return region; -} +import { + formatCloudRegion, + type CloudProvider, +} from "../adk/cloudProvider"; export function SkillSpacePicker({ selected, onChange, + cloudProvider = "volcengine", }: { selected: SelectedSkill[]; onChange: (next: SelectedSkill[]) => void; + cloudProvider?: CloudProvider; }) { const [spaces, setSpaces] = useState([]); const [skills, setSkills] = useState([]); @@ -85,6 +85,9 @@ export function SkillSpacePicker({ }, [spaceId, spaces]); const selectedSpace = spaces.find((s) => s.id === spaceId); + const consoleUrl = selectedSpace + ? getSkillSpaceConsoleUrl(selectedSpace.id, selectedSpace.region, cloudProvider) + : ""; const isSelected = (skillId: string, ver: string) => selected.some( @@ -161,19 +164,21 @@ export function SkillSpacePicker({ className="cw-skillspace-region-label" title={selectedSpace.region} > - {regionLabel(selectedSpace.region)} + {formatCloudRegion(selectedSpace.region, cloudProvider)} )} - - - + {consoleUrl && ( + + + + )} )}
diff --git a/frontend/src/create/TemplateCreate.tsx b/frontend/src/create/TemplateCreate.tsx index 4e90570ac..1ddf7ec2d 100644 --- a/frontend/src/create/TemplateCreate.tsx +++ b/frontend/src/create/TemplateCreate.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { motion } from "motion/react"; import { ArrowLeft, @@ -18,6 +18,13 @@ import { } from "lucide-react"; import { type CreateModeProps, type AgentDraft, emptyDraft } from "./types"; import { displayDescription } from "./displayText"; +import { + defaultModelApiBase, + defaultModelName, + VOLCENGINE_DEFAULT_MODEL_NAME, + VOLCENGINE_MODELARK_BASE_URL, + type CloudProvider, +} from "../adk/cloudProvider"; import "./TemplateCreate.css"; /** A gallery preset: an AgentDraft plus presentation metadata. */ @@ -154,6 +161,29 @@ const TEMPLATES: Template[] = [ }, ]; +function providerTemplateDraft( + draft: AgentDraft, + cloudProvider: CloudProvider, +): AgentDraft { + if (cloudProvider !== "byteplus") return draft; + const byteplusModelName = defaultModelName(cloudProvider); + return { + ...draft, + model: draft.model === "doubao-1.5-pro-32k" ? byteplusModelName : draft.model, + modelName: + draft.modelName === VOLCENGINE_DEFAULT_MODEL_NAME + ? byteplusModelName + : draft.modelName, + modelApiBase: + !draft.modelApiBase || draft.modelApiBase === VOLCENGINE_MODELARK_BASE_URL + ? defaultModelApiBase(cloudProvider) + : draft.modelApiBase, + subAgents: draft.subAgents.map((child) => + providerTemplateDraft(child, cloudProvider), + ), + }; +} + /** Which built-in components a draft uses → tags on the card. */ function components(d: AgentDraft) { const out: { icon: LucideIcon; label: string }[] = []; @@ -165,8 +195,20 @@ function components(d: AgentDraft) { return out; } -export function TemplateCreate({ onBack, onCreate }: CreateModeProps) { +export function TemplateCreate({ + cloudProvider = "volcengine", + onBack, + onCreate, +}: CreateModeProps) { const [selected, setSelected] = useState