refactor: remove legacy assistant compatibility

This commit is contained in:
Xin Wang
2026-08-18 10:07:18 +08:00
parent abfcd4cd19
commit d003ee77a5
40 changed files with 505 additions and 729 deletions
@@ -447,34 +447,6 @@ function startupAssistantMessages(startup: BatchStartupResult): string[] {
return [greeting, ...assistantMessages].filter(Boolean);
}
function legacyStartupRuntimeRecords(
startup: BatchStartupResult,
): Array<Record<string, unknown>> {
return startup.autoConfirmedMessages.flatMap((message, index) => {
const confirmedAction =
message.actions?.find((action) => action.id === "confirmed") ??
message.actions?.[0];
const legacyId = `${index}-${message.title ?? message.message ?? "message"}`;
return [
{
eventId: `legacy-message-started-${legacyId}`,
event: "message_started",
phase: "opening",
requiresConfirmation: true,
messageTitle: message.title?.trim() || "未命名消息",
messageContent: message.message?.trim() || "(没有消息正文)",
messageActions: message.actions ?? [],
},
{
eventId: `legacy-message-completed-${legacyId}`,
event: "message_completed",
phase: "opening",
action: confirmedAction?.id?.trim() || "confirmed",
},
];
});
}
function runtimeRecordKey(
event: Record<string, unknown>,
prefix: string,
@@ -514,10 +486,7 @@ function AutoTestTimeline({
});
const openingMessages = startupAssistantMessages(startup);
const records =
(startup.runtimeRecords?.length ?? 0) > 0
? startup.runtimeRecords ?? []
: legacyStartupRuntimeRecords(startup);
const records = startup.runtimeRecords ?? [];
const firstMessageStartedIndex = records.findIndex(
(event) => event.event === "message_started",
);
@@ -727,8 +727,8 @@ export function AssistantPage(props: AssistantPageProps) {
graph.settings?.turnConfig ?? assistant.turnConfig,
),
};
// 编辑器会把兼容字段和默认值写回 graph。状态与保存基线必须使用
// 同一个规范化结果,否则页面刚打开就会被误判为有未保存改动。
// 状态与保存基线使用同一个完整 graph,避免页面刚打开就被误判
// 为有未保存改动。
const normalizedGraph = workflowGraphWithSettings(graph, wfSettings);
setWorkflowName(assistant.name);
setWorkflowGraph(normalizedGraph);
@@ -1,7 +1,7 @@
"use client";
/**
* Workflow v3 edge: LLM judgement, variable expression, or deterministic default.
* Workflow v4 edge: LLM judgement, variable expression, or deterministic default.
*/
import {
@@ -18,7 +18,6 @@ import {
} from "./context";
import {
accentVar,
messageCompletionPolicy,
type WorkflowNodeData,
} from "./specs";
@@ -31,7 +30,7 @@ export function GenericNode({ id, type, data, selected }: NodeProps) {
if (!spec) return null;
const nodeData = data as WorkflowNodeData;
const messagePolicy = messageCompletionPolicy(nodeData);
const messagePolicy = nodeData.completionPolicy ?? "playback";
const Icon = spec.icon;
const preview = (
nodeData.prompt ||
@@ -6,10 +6,7 @@ import { SectionCard } from "@/components/editor/section-card";
import { ToolBindingEditor } from "@/components/tools/tool-binding-editor";
import { NodeSelect } from "./controls";
import {
actionUserInputPolicy,
type WorkflowNodeData,
} from "../specs";
import { type WorkflowNodeData } from "../specs";
import type { ModelOption } from "../types";
import type { DynamicVariableDefinition } from "@/lib/api";
@@ -28,7 +25,7 @@ export function ActionNodePanel({
dynamicVariableDefinitions,
runtimeMode,
}: ActionNodePanelProps) {
const userInputPolicy = actionUserInputPolicy(draft);
const userInputPolicy = draft.userInputPolicy ?? "queue";
return (
<SectionCard
@@ -87,7 +87,7 @@ export function GlobalSettingsPanel({
? [{ value: "edge_tool", label: "边工具(Realtime 必需)" }]
: [
{ value: "edge_tool", label: "边工具(低延迟)" },
{ value: "llm_router", label: "独立 LLM Router(兼容)" },
{ value: "llm_router", label: "独立 LLM Router" },
]
}
onChange={(llmRoutingMode) =>
@@ -14,7 +14,6 @@ import {
import { Textarea } from "@/components/ui/textarea";
import {
messageCompletionPolicy,
type MessageCompletionPolicy,
type WorkflowNodeData,
} from "../specs";
@@ -51,17 +50,13 @@ export function MessageNodePanel({
set: (key: string, value: unknown) => void;
setPatch: (patch: Partial<WorkflowNodeData>) => void;
}) {
const completionPolicy = messageCompletionPolicy(draft);
const completionPolicy = draft.completionPolicy ?? "playback";
const completionDescription = COMPLETION_OPTIONS.find(
(option) => option.value === completionPolicy,
)?.description;
const selectCompletionPolicy = (value: MessageCompletionPolicy) => {
setPatch({
completionPolicy: value,
requireConfirmation: undefined,
showMessage: undefined,
});
setPatch({ completionPolicy: value });
};
return (
+1 -26
View File
@@ -1,4 +1,4 @@
/** Workflow v3 public graph types and defaults. */
/** Current Workflow graph types and defaults. */
import * as LucideIcons from "lucide-react";
import { Circle, type LucideIcon } from "lucide-react";
@@ -68,13 +68,9 @@ export type WorkflowNodeData = {
updates?: StateUpdateRule[];
userInputPolicy?: ActionUserInputPolicy;
speech?: string;
/** Legacy field read only while an older graph is open in the editor. */
showMessage?: boolean;
title?: string;
confirmLabel?: string;
completionPolicy?: MessageCompletionPolicy;
/** Legacy field read only while an older graph is open in the editor. */
requireConfirmation?: boolean;
targetType?: "ai" | "human" | "queue" | "phone";
target?: string;
message?: string;
@@ -82,27 +78,6 @@ export type WorkflowNodeData = {
[key: string]: unknown;
};
/** Infer the new Message policy for graphs saved before it was explicit. */
export function messageCompletionPolicy(
data: WorkflowNodeData,
): MessageCompletionPolicy {
if (
data.completionPolicy === "interruptible" ||
data.completionPolicy === "playback" ||
data.completionPolicy === "confirmation"
) {
return data.completionPolicy;
}
return data.requireConfirmation === true ? "confirmation" : "playback";
}
/** Older Action nodes allowed input to continue, which matches queue. */
export function actionUserInputPolicy(
data: WorkflowNodeData,
): ActionUserInputPolicy {
return data.userInputPolicy === "block" ? "block" : "queue";
}
export type ExpressionRule = {
variable: string;
operator: ExpressionOperator;
+1 -3
View File
@@ -827,8 +827,7 @@ export function useVoicePreview(
void refreshDevices();
// SmallWebRTCTransport discards APIRequest.requestData when endpoint is a
// Request object. Keep capabilities in a header as the reliable path;
// requestData remains below for compatibility with other transports.
// Request object, so client capabilities use the request header only.
const clientToolNames = Array.from(clientToolHandlersRef.current.keys());
const request = new Request(`${API_BASE}/api/webrtc/offer`, {
method: "POST",
@@ -849,7 +848,6 @@ export function useVoicePreview(
assistant_id: assistantId,
vision_enabled: Boolean(options.visionEnabled),
dynamic_variables: options.dynamicVariables ?? {},
client_tool_names: clientToolNames,
},
},
});