feat: remove OpenCode assistant mode
This commit is contained in:
@@ -4,7 +4,6 @@ import {
|
||||
Boxes,
|
||||
Brain,
|
||||
Copy,
|
||||
MessageSquareText,
|
||||
MoreHorizontal,
|
||||
Pencil,
|
||||
Plus,
|
||||
@@ -14,7 +13,6 @@ import {
|
||||
ChevronDown,
|
||||
LayoutTemplate,
|
||||
Save,
|
||||
Terminal,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
|
||||
@@ -76,8 +74,6 @@ import {
|
||||
EditableTitle,
|
||||
EditorBackButton,
|
||||
ResourceSelectField,
|
||||
TextAreaField,
|
||||
ToggleRow,
|
||||
} from "@/components/assistant-editor/editor-controls";
|
||||
import type { AssistantForm } from "@/components/assistant-editor/types";
|
||||
import { PromptEditor } from "@/components/assistant-editor/prompt-editor";
|
||||
@@ -95,27 +91,13 @@ type AgentPlatformForm = {
|
||||
turnConfig: TurnConfig;
|
||||
};
|
||||
|
||||
type OpenCodeForm = {
|
||||
name: string;
|
||||
prompt: string;
|
||||
agent: string;
|
||||
model: string;
|
||||
asr: string;
|
||||
voice: string;
|
||||
enableInterrupt: boolean;
|
||||
turnConfig: TurnConfig;
|
||||
visionEnabled: boolean;
|
||||
visionModelResourceId: string;
|
||||
};
|
||||
|
||||
type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT" | "OpenCode";
|
||||
type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT";
|
||||
|
||||
const assistantTypes: AssistantType[] = [
|
||||
"提示词",
|
||||
"工作流",
|
||||
"Dify",
|
||||
"FastGPT",
|
||||
"OpenCode",
|
||||
];
|
||||
|
||||
function defaultKnowledgeRetrievalConfig(): KnowledgeRetrievalConfig {
|
||||
@@ -132,7 +114,6 @@ const typeToLabel: Record<ApiAssistantType, AssistantType> = {
|
||||
workflow: "工作流",
|
||||
dify: "Dify",
|
||||
fastgpt: "FastGPT",
|
||||
opencode: "OpenCode",
|
||||
};
|
||||
|
||||
// 后端 type → 编辑器视图(工作流暂为占位页)
|
||||
@@ -140,7 +121,6 @@ const typeToView = {
|
||||
prompt: "create",
|
||||
dify: "create-agent-platform",
|
||||
fastgpt: "create-agent-platform",
|
||||
opencode: "create-opencode",
|
||||
workflow: "workflow",
|
||||
} as const;
|
||||
|
||||
@@ -201,20 +181,6 @@ function blankAgentPlatformForm(name: string): AgentPlatformForm {
|
||||
};
|
||||
}
|
||||
|
||||
function blankOpenCodeForm(name: string): OpenCodeForm {
|
||||
return {
|
||||
name,
|
||||
prompt: "",
|
||||
agent: "",
|
||||
model: "",
|
||||
asr: "",
|
||||
voice: "",
|
||||
enableInterrupt: true,
|
||||
turnConfig: defaultTurnConfig(),
|
||||
visionEnabled: false,
|
||||
visionModelResourceId: "",
|
||||
};
|
||||
}
|
||||
function formatTimestamp(iso?: string | null): string {
|
||||
if (!iso) return "";
|
||||
const d = new Date(iso);
|
||||
@@ -251,9 +217,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
useState<AgentPlatformForm>(() =>
|
||||
blankAgentPlatformForm(""),
|
||||
);
|
||||
const [openCodeForm, setOpenCodeForm] = useState<OpenCodeForm>(() =>
|
||||
blankOpenCodeForm(""),
|
||||
);
|
||||
const [assistants, setAssistants] = useState<Assistant[]>([]);
|
||||
const [listLoading, setListLoading] = useState(true);
|
||||
const [listError, setListError] = useState<string | null>(null);
|
||||
@@ -366,7 +329,7 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
label: c.name,
|
||||
supportImageInput: c.supportImageInput,
|
||||
}));
|
||||
const agentOptions = (interfaceType: "dify" | "fastgpt" | "opencode") =>
|
||||
const agentOptions = (interfaceType: AgentPlatform) =>
|
||||
modelResources
|
||||
.filter(
|
||||
(resource) =>
|
||||
@@ -405,18 +368,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpenCodeVisionEnabledChange(enabled: boolean) {
|
||||
updateOpenCodeForm("visionEnabled", enabled);
|
||||
if (!enabled) updateOpenCodeForm("visionModelResourceId", "");
|
||||
}
|
||||
|
||||
function handleOpenCodeModelChange(value: string) {
|
||||
updateOpenCodeForm("model", value);
|
||||
if (openCodeForm.visionModelResourceId === value) {
|
||||
updateOpenCodeForm("visionModelResourceId", "");
|
||||
}
|
||||
}
|
||||
|
||||
function startCreate() {
|
||||
router.push("/assistants/new");
|
||||
}
|
||||
@@ -541,10 +492,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
const next = { ...agentPlatformForm };
|
||||
setAgentPlatformForm(next);
|
||||
setSavedSnapshot(JSON.stringify(next));
|
||||
} else if (view === "create-opencode") {
|
||||
const next = { ...openCodeForm };
|
||||
setOpenCodeForm(next);
|
||||
setSavedSnapshot(JSON.stringify(next));
|
||||
} else if (view === "workflow") {
|
||||
setSavedSnapshot(
|
||||
JSON.stringify({
|
||||
@@ -640,24 +587,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
);
|
||||
}
|
||||
|
||||
// ---- OpenCode ----
|
||||
function fillOpenCodeForm(a: Assistant): OpenCodeForm {
|
||||
const next: OpenCodeForm = {
|
||||
name: a.name,
|
||||
prompt: a.prompt,
|
||||
agent: a.modelResourceIds.Agent ?? "",
|
||||
model: a.modelResourceIds.LLM ?? "",
|
||||
asr: a.modelResourceIds.ASR ?? "",
|
||||
voice: a.modelResourceIds.TTS ?? "",
|
||||
enableInterrupt: a.enableInterrupt,
|
||||
turnConfig: normalizeTurnConfig(a.turnConfig),
|
||||
visionEnabled: a.visionEnabled,
|
||||
visionModelResourceId: a.visionModelResourceId ?? "",
|
||||
};
|
||||
setOpenCodeForm(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
// 编辑模式:按路由中的 id 拉取助手,回填对应类型的表单后再切换视图
|
||||
useEffect(() => {
|
||||
if (props.mode !== "edit" || !editingId) return;
|
||||
@@ -674,8 +603,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
assistant.type === "dify"
|
||||
) {
|
||||
setSavedSnapshot(JSON.stringify(fillAgentPlatformForm(assistant)));
|
||||
} else if (assistant.type === "opencode") {
|
||||
setSavedSnapshot(JSON.stringify(fillOpenCodeForm(assistant)));
|
||||
} else {
|
||||
// 工作流:回填名称与图(空图回落到默认 开始→智能体→结束)
|
||||
const graph =
|
||||
@@ -770,26 +697,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
setWorkflowSettings,
|
||||
]);
|
||||
|
||||
function handleSaveOpenCode() {
|
||||
void save(
|
||||
baseUpsert({
|
||||
name: openCodeForm.name.trim(),
|
||||
type: "opencode",
|
||||
enableInterrupt: openCodeForm.enableInterrupt,
|
||||
turnConfig: openCodeForm.turnConfig,
|
||||
visionEnabled: openCodeForm.visionEnabled,
|
||||
visionModelResourceId: openCodeForm.visionModelResourceId || null,
|
||||
modelResourceIds: {
|
||||
...(openCodeForm.agent ? { Agent: openCodeForm.agent } : {}),
|
||||
...(openCodeForm.model ? { LLM: openCodeForm.model } : {}),
|
||||
...(openCodeForm.asr ? { ASR: openCodeForm.asr } : {}),
|
||||
...(openCodeForm.voice ? { TTS: openCodeForm.voice } : {}),
|
||||
},
|
||||
prompt: openCodeForm.prompt,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function handleSaveWorkflow() {
|
||||
void save(
|
||||
baseUpsert({
|
||||
@@ -822,16 +729,14 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
? JSON.stringify(form)
|
||||
: view === "create-agent-platform"
|
||||
? JSON.stringify(agentPlatformForm)
|
||||
: view === "create-opencode"
|
||||
? JSON.stringify(openCodeForm)
|
||||
: view === "workflow"
|
||||
? JSON.stringify({
|
||||
name: workflowName,
|
||||
graph: workflowGraph,
|
||||
dynamicVariableDefinitions:
|
||||
effectiveWorkflowDynamicVariableDefinitions,
|
||||
})
|
||||
: null;
|
||||
: view === "workflow"
|
||||
? JSON.stringify({
|
||||
name: workflowName,
|
||||
graph: workflowGraph,
|
||||
dynamicVariableDefinitions:
|
||||
effectiveWorkflowDynamicVariableDefinitions,
|
||||
})
|
||||
: null;
|
||||
const dirty =
|
||||
activeFormJson !== null &&
|
||||
savedSnapshot !== null &&
|
||||
@@ -926,15 +831,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
}));
|
||||
}
|
||||
|
||||
function updateOpenCodeForm<K extends keyof OpenCodeForm>(
|
||||
key: K,
|
||||
value: OpenCodeForm[K],
|
||||
) {
|
||||
setOpenCodeForm((prev) => ({
|
||||
...prev,
|
||||
[key]: value,
|
||||
}));
|
||||
}
|
||||
if (view === "loading") {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
@@ -1325,139 +1221,6 @@ export function AssistantPage(props: AssistantPageProps) {
|
||||
);
|
||||
}
|
||||
|
||||
if (view === "create-opencode") {
|
||||
return (
|
||||
<div className="-mt-6 flex h-full flex-col gap-4">
|
||||
<div className="flex shrink-0 items-center justify-between gap-6 border-b border-hairline pb-3 pt-1">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<EditorBackButton onClick={() => router.push("/assistants")} />
|
||||
<EditableTitle
|
||||
value={openCodeForm.name}
|
||||
onChange={(value) => updateOpenCodeForm("name", value)}
|
||||
/>
|
||||
<AssistantIdentity assistantId={editingId} />
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 gap-2">
|
||||
{saveError && (
|
||||
<span className="self-center text-xs text-destructive">
|
||||
{saveError}
|
||||
</span>
|
||||
)}
|
||||
<Button
|
||||
className="gap-2"
|
||||
disabled={
|
||||
saving ||
|
||||
!dirty ||
|
||||
!openCodeForm.name.trim() ||
|
||||
!openCodeForm.agent
|
||||
}
|
||||
onClick={() => void handleSaveOpenCode()}
|
||||
>
|
||||
{saving ? (
|
||||
<Loader2 size={16} className="animate-spin" />
|
||||
) : (
|
||||
<Save size={16} />
|
||||
)}
|
||||
保存
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-0 flex-1 gap-4">
|
||||
<div className="scrollbar-subtle min-w-0 flex-1 space-y-3 overflow-y-auto pr-1">
|
||||
<SectionCard
|
||||
icon={<Terminal size={15} />}
|
||||
title="OpenCode 服务配置"
|
||||
description="从「模型资源」中选择 OpenCode 服务资源。"
|
||||
>
|
||||
<ResourceSelectField
|
||||
label="OpenCode 服务"
|
||||
value={openCodeForm.agent}
|
||||
onChange={(value) => updateOpenCodeForm("agent", value)}
|
||||
options={agentOptions("opencode")}
|
||||
noneLabel="请选择"
|
||||
/>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<MessageSquareText size={15} />}
|
||||
title="提示词"
|
||||
description="描述助手的角色、能力和回答要求"
|
||||
>
|
||||
<TextAreaField
|
||||
value={openCodeForm.prompt}
|
||||
onChange={(value) => updateOpenCodeForm("prompt", value)}
|
||||
placeholder="请输入提示词,描述助手的角色、能力和回答要求"
|
||||
rows={8}
|
||||
/>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Brain size={15} />}
|
||||
title="模型与语音配置"
|
||||
description="配置 OpenCode 使用的大语言模型、语音识别与语音合成资源。"
|
||||
>
|
||||
<ToggleRow
|
||||
title="视觉理解"
|
||||
hint="开启后,开始对话时会允许助手按需理解当前视频画面。视觉模型选「模型自己」时,大语言模型本身必须支持图片输入。"
|
||||
checked={openCodeForm.visionEnabled}
|
||||
onChange={handleOpenCodeVisionEnabledChange}
|
||||
/>
|
||||
{openCodeForm.visionEnabled && (
|
||||
<ResourceSelectField
|
||||
label="视觉模型"
|
||||
value={openCodeForm.visionModelResourceId}
|
||||
onChange={(value) =>
|
||||
updateOpenCodeForm("visionModelResourceId", value)
|
||||
}
|
||||
options={visionModelOptionsFor(openCodeForm.model)}
|
||||
noneLabel="模型自己"
|
||||
/>
|
||||
)}
|
||||
<ResourceSelectField
|
||||
label="大语言模型"
|
||||
value={openCodeForm.model}
|
||||
onChange={handleOpenCodeModelChange}
|
||||
options={credOptions("LLM")}
|
||||
noneLabel="无"
|
||||
/>
|
||||
<ResourceSelectField
|
||||
label="语音识别"
|
||||
value={openCodeForm.asr}
|
||||
onChange={(value) => updateOpenCodeForm("asr", value)}
|
||||
options={credOptions("ASR")}
|
||||
noneLabel="无"
|
||||
/>
|
||||
<ResourceSelectField
|
||||
label="语音合成"
|
||||
value={openCodeForm.voice}
|
||||
onChange={(value) => updateOpenCodeForm("voice", value)}
|
||||
options={credOptions("TTS")}
|
||||
noneLabel="无"
|
||||
/>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Sparkles size={15} />}
|
||||
title="交互策略"
|
||||
description="设置实时视频对话时的交互体验"
|
||||
>
|
||||
<TurnConfigEditor
|
||||
enabled={openCodeForm.enableInterrupt}
|
||||
config={openCodeForm.turnConfig}
|
||||
onEnabledChange={(checked) => updateOpenCodeForm("enableInterrupt", checked)}
|
||||
onConfigChange={(config) => updateOpenCodeForm("turnConfig", config)}
|
||||
/>
|
||||
</SectionCard>
|
||||
</div>
|
||||
|
||||
<DebugDrawer assistantId={editingId} hasUnsavedChanges={dirty} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<PromptEditor
|
||||
assistantId={editingId}
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
Loader2,
|
||||
MessageSquareText,
|
||||
Rocket,
|
||||
Terminal,
|
||||
Workflow,
|
||||
} from "lucide-react";
|
||||
|
||||
@@ -16,7 +15,6 @@ import {
|
||||
ListPageLayout,
|
||||
ListPageSection,
|
||||
} from "@/components/layout/list-page-layout";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
@@ -31,7 +29,7 @@ import {
|
||||
} from "@/lib/api";
|
||||
import { defaultTurnConfig } from "@/lib/turn-config";
|
||||
|
||||
type BuildMethod = "提示词" | "工作流" | "智能体平台" | "OpenCode";
|
||||
type BuildMethod = "提示词" | "工作流" | "智能体平台";
|
||||
|
||||
const typeFromBuildMethod: Record<
|
||||
Exclude<BuildMethod, "智能体平台">,
|
||||
@@ -39,7 +37,6 @@ const typeFromBuildMethod: Record<
|
||||
> = {
|
||||
提示词: "prompt",
|
||||
工作流: "workflow",
|
||||
OpenCode: "opencode",
|
||||
};
|
||||
|
||||
type AssistantTypeOption = {
|
||||
@@ -47,8 +44,6 @@ type AssistantTypeOption = {
|
||||
label: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
/** 提示词、工作流、智能体平台已落地;OpenCode 暂时显示即将上线 */
|
||||
available: boolean;
|
||||
};
|
||||
|
||||
const assistantTypeOptions: AssistantTypeOption[] = [
|
||||
@@ -57,14 +52,12 @@ const assistantTypeOptions: AssistantTypeOption[] = [
|
||||
label: "使用提示词构建",
|
||||
description: "通过提示词、模型与语音快速搭建对话助手,适合大多数场景。",
|
||||
icon: <MessageSquareText size={20} />,
|
||||
available: true,
|
||||
},
|
||||
{
|
||||
type: "工作流",
|
||||
label: "使用工作流构建",
|
||||
description: "用可视化编排串联多个节点,适合多步骤、带分支的复杂流程。",
|
||||
icon: <Workflow size={20} />,
|
||||
available: true,
|
||||
},
|
||||
{
|
||||
type: "智能体平台",
|
||||
@@ -72,14 +65,6 @@ const assistantTypeOptions: AssistantTypeOption[] = [
|
||||
description:
|
||||
"接入 Dify、FastGPT 等智能体平台,复用平台中的提示词、知识库和工作流配置。",
|
||||
icon: <Boxes size={20} />,
|
||||
available: true,
|
||||
},
|
||||
{
|
||||
type: "OpenCode",
|
||||
label: "使用 OpenCode 构建",
|
||||
description: "对接 OpenCode 服务,通过提示词驱动代码助手并支持实时语音对话。",
|
||||
icon: <Terminal size={20} />,
|
||||
available: false,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -203,16 +188,6 @@ export function CreateAssistantPage() {
|
||||
title={option.label}
|
||||
description={option.description}
|
||||
onClick={() => setDraftType(option.type)}
|
||||
unselectedTrailing={
|
||||
!option.available ? (
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-6 bg-surface-strong px-3 text-xs text-muted-foreground"
|
||||
>
|
||||
即将上线
|
||||
</Badge>
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -263,8 +263,7 @@ export type AssistantType =
|
||||
| "prompt"
|
||||
| "workflow"
|
||||
| "dify"
|
||||
| "fastgpt"
|
||||
| "opencode";
|
||||
| "fastgpt";
|
||||
export type RuntimeMode = "pipeline" | "realtime";
|
||||
export type TurnConfig = {
|
||||
bargeIn: {
|
||||
|
||||
Reference in New Issue
Block a user