Enhance conversation history and runtime variable management
- Update ConversationRecorder to include source and nodeId metadata in transcripts for better context tracking. - Introduce optional variable handling in DynamicVariableStore, allowing for unset variables to be rendered as empty without raising errors. - Refactor WorkflowBrain to apply turn configurations and manage interaction policies dynamically, improving agent responsiveness. - Implement tests to ensure proper handling of updated session variables and workflow metadata in various scenarios.
This commit is contained in:
@@ -56,14 +56,27 @@ export function GenericNode({ id, type, data, selected }: NodeProps) {
|
||||
<div
|
||||
data-node-id={id}
|
||||
className={cn(
|
||||
"group relative w-[250px] rounded-2xl border bg-card p-4 text-card-foreground shadow-sm transition-[border-color,box-shadow,transform]",
|
||||
"group relative isolate w-[250px] rounded-2xl border bg-card p-4 text-card-foreground shadow-sm transition-[border-color,box-shadow,transform]",
|
||||
isActive
|
||||
? "border-success shadow-[0_12px_34px_color-mix(in_srgb,var(--success)_20%,transparent)] ring-2 ring-success/50"
|
||||
? "border-success/90 shadow-[0_0_0_1px_color-mix(in_srgb,var(--success)_38%,transparent),0_0_18px_color-mix(in_srgb,var(--success)_38%,transparent),0_0_46px_color-mix(in_srgb,var(--success)_22%,transparent),0_16px_38px_color-mix(in_srgb,var(--success)_18%,transparent)] ring-1 ring-success/60"
|
||||
: selected
|
||||
? "border-primary shadow-[0_12px_34px_color-mix(in_srgb,var(--primary)_16%,transparent)]"
|
||||
: "border-hairline hover:border-hairline-strong hover:shadow-md",
|
||||
)}
|
||||
>
|
||||
{isActive && (
|
||||
<>
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute -inset-1 rounded-[1.2rem] border border-success/35 opacity-80 motion-safe:animate-pulse"
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute inset-x-5 -bottom-px h-px bg-gradient-to-r from-transparent via-success to-transparent shadow-[0_0_12px_var(--success)]"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{spec.hasTarget && (
|
||||
<Handle
|
||||
type="target"
|
||||
@@ -81,9 +94,12 @@ export function GenericNode({ id, type, data, selected }: NodeProps) {
|
||||
/>
|
||||
|
||||
{isActive && (
|
||||
<div className="absolute -top-3 left-3 flex items-center gap-1.5 rounded-full bg-success px-2 py-0.5 text-[10px] font-medium text-on-primary shadow-sm">
|
||||
<span className="h-1.5 w-1.5 animate-pulse rounded-full bg-on-primary" />
|
||||
对话中
|
||||
<div className="absolute -top-3 left-3 flex items-center gap-2 rounded-full border border-success/60 bg-card/95 px-2.5 py-1 text-[10px] font-semibold tracking-[0.14em] text-success shadow-[0_0_16px_color-mix(in_srgb,var(--success)_42%,transparent)] backdrop-blur-sm">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="absolute inline-flex h-full w-full rounded-full bg-success opacity-55 motion-safe:animate-ping" />
|
||||
<span className="relative inline-flex h-2 w-2 rounded-full bg-success shadow-[0_0_8px_var(--success)]" />
|
||||
</span>
|
||||
LIVE · 对话中
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ import {
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import type { KnowledgeRetrievalConfig, TurnConfig } from "@/lib/api";
|
||||
import { TurnConfigEditor } from "@/components/turn-config-editor";
|
||||
import { normalizeTurnConfig } from "@/lib/turn-config";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import {
|
||||
Tooltip,
|
||||
@@ -195,6 +196,8 @@ function fromFlow(nodes: Node[], edges: Edge[]): WorkflowGraph {
|
||||
knowledgeMode: "automatic",
|
||||
knowledgeTopN: 5,
|
||||
knowledgeScoreThreshold: 0,
|
||||
enableInterrupt: true,
|
||||
turnConfig: defaultGraph().settings.turnConfig,
|
||||
},
|
||||
nodes: nodes.map((n) => ({
|
||||
id: n.id,
|
||||
@@ -261,6 +264,8 @@ function Canvas({
|
||||
knowledgeTopN: settings.knowledgeRetrievalConfig.topN,
|
||||
knowledgeScoreThreshold:
|
||||
settings.knowledgeRetrievalConfig.scoreThreshold,
|
||||
enableInterrupt: settings.allowInterrupt,
|
||||
turnConfig: settings.turnConfig,
|
||||
};
|
||||
onChangeRef.current?.(graph);
|
||||
}, [
|
||||
@@ -273,6 +278,8 @@ function Canvas({
|
||||
settings.toolIds,
|
||||
settings.knowledgeBaseId,
|
||||
settings.knowledgeRetrievalConfig,
|
||||
settings.allowInterrupt,
|
||||
settings.turnConfig,
|
||||
]);
|
||||
|
||||
const onConnect = useCallback(
|
||||
@@ -1519,6 +1526,9 @@ function AgentPanelForm({
|
||||
topN: Number(draft.knowledgeTopN ?? 5),
|
||||
scoreThreshold: Number(draft.knowledgeScoreThreshold ?? 0),
|
||||
};
|
||||
const agentTurnConfig = normalizeTurnConfig(
|
||||
draft.turnConfig ?? workflowSettings.turnConfig,
|
||||
);
|
||||
|
||||
const setInheritance = (inheritGlobalConfig: boolean) => {
|
||||
if (inheritGlobalConfig) {
|
||||
@@ -1550,6 +1560,9 @@ function AgentPanelForm({
|
||||
knowledgeScoreThreshold:
|
||||
draft.knowledgeScoreThreshold ??
|
||||
workflowSettings.knowledgeRetrievalConfig.scoreThreshold,
|
||||
enableInterrupt:
|
||||
draft.enableInterrupt ?? workflowSettings.allowInterrupt,
|
||||
turnConfig: agentTurnConfig,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1592,10 +1605,10 @@ function AgentPanelForm({
|
||||
|
||||
<SectionCard
|
||||
icon={<MessageSquareText size={15} />}
|
||||
title="提示词"
|
||||
title={inheritsGlobal ? "任务" : "提示词"}
|
||||
description={
|
||||
inheritsGlobal
|
||||
? "描述当前阶段任务,并与工作流全局提示词合并"
|
||||
? "描述当前阶段要完成的目标;角色、能力和通用规则继承工作流全局配置"
|
||||
: "描述当前独立助手的角色、能力和回答要求"
|
||||
}
|
||||
>
|
||||
@@ -1603,7 +1616,11 @@ function AgentPanelForm({
|
||||
rows={8}
|
||||
value={draft.prompt ?? ""}
|
||||
onChange={(event) => set("prompt", event.target.value)}
|
||||
placeholder="请输入提示词,描述助手的角色、能力和回答要求"
|
||||
placeholder={
|
||||
inheritsGlobal
|
||||
? "例如:确认用户身份,并收集需要查询的订单编号"
|
||||
: "请输入提示词,描述助手的角色、能力和回答要求"
|
||||
}
|
||||
className="field-sizing-fixed min-h-28 resize-y border-hairline-strong bg-background text-sm text-foreground placeholder:text-muted-soft"
|
||||
/>
|
||||
</SectionCard>
|
||||
@@ -1714,6 +1731,23 @@ function AgentPanelForm({
|
||||
onChange={(toolIds) => set("toolIds", toolIds)}
|
||||
/>
|
||||
</SectionCard>
|
||||
|
||||
<SectionCard
|
||||
icon={<Sparkles size={15} />}
|
||||
title="交互策略"
|
||||
description="配置当前 Agent 独立使用的打断和轮次检测策略"
|
||||
>
|
||||
<TurnConfigEditor
|
||||
enabled={
|
||||
draft.enableInterrupt ?? workflowSettings.allowInterrupt
|
||||
}
|
||||
config={agentTurnConfig}
|
||||
onEnabledChange={(enableInterrupt) =>
|
||||
set("enableInterrupt", enableInterrupt)
|
||||
}
|
||||
onConfigChange={(turnConfig) => set("turnConfig", turnConfig)}
|
||||
/>
|
||||
</SectionCard>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import * as LucideIcons from "lucide-react";
|
||||
import { Circle, type LucideIcon } from "lucide-react";
|
||||
|
||||
import type { NodeSpecDto } from "@/lib/api";
|
||||
import type { NodeSpecDto, TurnConfig } from "@/lib/api";
|
||||
import { defaultTurnConfig } from "@/lib/turn-config";
|
||||
|
||||
export type WorkflowNodeType = "start" | "agent" | "action" | "handoff" | "end";
|
||||
export type ContextPolicy = "inherit" | "fresh";
|
||||
@@ -37,6 +38,8 @@ export type WorkflowNodeData = {
|
||||
llmResourceId?: string;
|
||||
asrResourceId?: string;
|
||||
ttsResourceId?: string;
|
||||
enableInterrupt?: boolean;
|
||||
turnConfig?: TurnConfig;
|
||||
toolId?: string;
|
||||
arguments?: Record<string, unknown>;
|
||||
resultAssignments?: Record<string, string>;
|
||||
@@ -142,6 +145,8 @@ export type WorkflowGraph = {
|
||||
knowledgeMode: "automatic" | "on_demand";
|
||||
knowledgeTopN: number;
|
||||
knowledgeScoreThreshold: number;
|
||||
enableInterrupt: boolean;
|
||||
turnConfig: TurnConfig;
|
||||
};
|
||||
nodes: Array<{
|
||||
id: string;
|
||||
@@ -172,6 +177,8 @@ export function defaultGraph(): WorkflowGraph {
|
||||
knowledgeMode: "automatic",
|
||||
knowledgeTopN: 5,
|
||||
knowledgeScoreThreshold: 0,
|
||||
enableInterrupt: true,
|
||||
turnConfig: defaultTurnConfig(),
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user