626 lines
20 KiB
TypeScript
626 lines
20 KiB
TypeScript
import {
|
||
defaultAgentWorkflowUiConfig,
|
||
flattenVisibleAgentWorkflowSteps,
|
||
getAgentWorkflowSelectedOptionPath,
|
||
getEnabledAgentWorkflowStepTree,
|
||
isAgentWorkflowStepSelectionComplete,
|
||
} from "@/lib/agents/workflow-ui-config";
|
||
import type {
|
||
AgentWorkflowComposerContext,
|
||
AgentWorkflowComposerSelection,
|
||
AgentWorkflowMaterialSelections,
|
||
AgentWorkflowReferenceImage,
|
||
AgentWorkflowSelectedBrandModel,
|
||
AgentWorkflowStepKey,
|
||
AgentWorkflowUiConfig,
|
||
} from "@/types/agent";
|
||
|
||
export interface AgentWorkflowInputsValue {
|
||
primarySku: string;
|
||
secondarySku: string;
|
||
brand: string;
|
||
store: string;
|
||
thirdCategory: string;
|
||
fourthCategory: string;
|
||
fifthCategory: string;
|
||
priceBand: string;
|
||
}
|
||
|
||
const WORKFLOW_FRAGMENT_INLINE_LABELS = [
|
||
"角色",
|
||
"技能",
|
||
"目标",
|
||
"约束条件",
|
||
"流程",
|
||
"输出",
|
||
"前景",
|
||
"中景",
|
||
"背景",
|
||
"主产品",
|
||
"台面摆件",
|
||
"模特",
|
||
];
|
||
|
||
function buildGoodsInfoPromptLine(params: {
|
||
label: string;
|
||
result?: AgentWorkflowMaterialSelections["primary"]["result"] | null;
|
||
}) {
|
||
const goodsInfo = params.result?.goodsInfo;
|
||
if (!goodsInfo) {
|
||
return "";
|
||
}
|
||
|
||
const parts = [
|
||
goodsInfo.productName ? `商品名称:${goodsInfo.productName}` : "",
|
||
goodsInfo.sizeInfo ? `尺寸信息:${goodsInfo.sizeInfo}` : "",
|
||
goodsInfo.materialInfo ? `材质信息:${goodsInfo.materialInfo}` : "",
|
||
goodsInfo.boardType ? `板材类型:${goodsInfo.boardType}` : "",
|
||
].filter(Boolean);
|
||
|
||
if (parts.length === 0) {
|
||
return "";
|
||
}
|
||
|
||
return `${params.label}:${parts.join(";")}`;
|
||
}
|
||
|
||
function buildGoodsInfoSizeConstraintLine(params: {
|
||
label: string;
|
||
result?: AgentWorkflowMaterialSelections["primary"]["result"] | null;
|
||
}) {
|
||
const goodsInfo = params.result?.goodsInfo;
|
||
const sizeInfo = String(goodsInfo?.sizeInfo || "").trim();
|
||
if (!sizeInfo) {
|
||
return "";
|
||
}
|
||
|
||
return `${params.label}尺寸比例:${sizeInfo}。场景中必须保持真实体量、长宽高关系与产品结构比例,不得随意拉伸、压缩或失真。`;
|
||
}
|
||
|
||
function buildGoodsInfoAppearanceConstraintLine(params: {
|
||
label: string;
|
||
result?: AgentWorkflowMaterialSelections["primary"]["result"] | null;
|
||
}) {
|
||
const appearanceSummary = String(
|
||
params.result?.images?.slice().sort((left, right) => left.sortOrder - right.sortOrder)[0]
|
||
?.appearanceSummary ||
|
||
params.result?.goodsInfo?.appearanceSummary ||
|
||
""
|
||
).trim();
|
||
|
||
if (!appearanceSummary) {
|
||
return "";
|
||
}
|
||
|
||
return `${params.label}外观锁定:${appearanceSummary}。必须保持同一产品身份,不得改款、增减结构件、改变开合方式或替换主体颜色。`;
|
||
}
|
||
|
||
function buildGoodsInfoSummaryLine(params: {
|
||
label: string;
|
||
result?: AgentWorkflowMaterialSelections["primary"]["result"] | null;
|
||
}) {
|
||
const goodsInfo = params.result?.goodsInfo;
|
||
if (!goodsInfo) {
|
||
return "";
|
||
}
|
||
|
||
const parts = [
|
||
goodsInfo.productName || "",
|
||
goodsInfo.sizeInfo || "",
|
||
goodsInfo.materialInfo || "",
|
||
].filter(Boolean);
|
||
|
||
if (parts.length === 0) {
|
||
return "";
|
||
}
|
||
|
||
return `${params.label}:${parts.join(" / ")}`;
|
||
}
|
||
|
||
function buildBundleUsagePromptLine(params: {
|
||
referenceImages: AgentWorkflowReferenceImage[];
|
||
}) {
|
||
const primaryCount = params.referenceImages.filter((item) => item.source === "primary").length;
|
||
const secondaryCount = params.referenceImages.filter((item) => item.source === "secondary").length;
|
||
|
||
if (primaryCount <= 0 || secondaryCount <= 0) {
|
||
return "";
|
||
}
|
||
|
||
return "搭配SKU使用规则:搭配SKU是独立的第二产品,不是主SKU的另一角度或替代图。需要做搭配展示时,必须同场景同时呈现两者,且不得融合、替换或混淆产品身份。";
|
||
}
|
||
|
||
function normalizeWorkflowText(value: string) {
|
||
return String(value || "")
|
||
.replace(/\s+/g, " ")
|
||
.trim();
|
||
}
|
||
|
||
function sanitizeWorkflowPromptFragment(value: string) {
|
||
return normalizeWorkflowText(value)
|
||
.replace(/请按选项[\d一二三四五六七八九十]+执行[。.]?/g, "")
|
||
.replace(/流程\s*严格遵循下列流程/gi, "")
|
||
.replace(
|
||
/输出\s*([0-9]+\s*[kK])\s*([0-9]+\s*[::]\s*[0-9]+)/g,
|
||
(_, quality: string, ratio: string) =>
|
||
`输出:${String(quality || "").toUpperCase()},${String(ratio || "")
|
||
.replace(/\s+/g, "")
|
||
.replace(":", ":")}`
|
||
)
|
||
.replace(/\s+/g, " ")
|
||
.replace(/^[;;、,,]+|[;;、,,]+$/g, "")
|
||
.trim();
|
||
}
|
||
|
||
function splitWorkflowPromptFragment(value: string) {
|
||
const sanitized = sanitizeWorkflowPromptFragment(value);
|
||
if (!sanitized) {
|
||
return [] as string[];
|
||
}
|
||
|
||
let normalized = sanitized;
|
||
WORKFLOW_FRAGMENT_INLINE_LABELS.forEach((label) => {
|
||
normalized = normalized.replace(
|
||
new RegExp(`(?<!^)(?:${label})[::]`, "g"),
|
||
`\n${label}:`
|
||
);
|
||
});
|
||
|
||
return normalized
|
||
.split(/\n+/)
|
||
.flatMap((line) =>
|
||
line
|
||
.split(/;+/)
|
||
.map((item) => item.trim())
|
||
.filter(Boolean)
|
||
)
|
||
.map((item) => item.replace(/\s+/g, " ").trim())
|
||
.filter(Boolean);
|
||
}
|
||
|
||
function buildGroupedSelectionLines(params: {
|
||
selections: AgentWorkflowComposerSelection[];
|
||
valueKey: "optionName" | "promptFragment";
|
||
separator: string;
|
||
leafOnly?: boolean;
|
||
dedupeAcrossSteps?: boolean;
|
||
}) {
|
||
const grouped = new Map<
|
||
string,
|
||
{
|
||
stepTitle: string;
|
||
values: string[];
|
||
valueSet: Set<string>;
|
||
}
|
||
>();
|
||
const globalValueSet = new Set<string>();
|
||
|
||
const sourceSelections = params.leafOnly
|
||
? params.selections.filter((item, index, items) => {
|
||
const nextItem = items[index + 1];
|
||
return !nextItem || nextItem.stepKey !== item.stepKey;
|
||
})
|
||
: params.selections;
|
||
|
||
sourceSelections.forEach((item) => {
|
||
const rawValue =
|
||
params.valueKey === "promptFragment"
|
||
? item.promptFragment || item.optionName
|
||
: item.optionName;
|
||
const normalizedValue = normalizeWorkflowText(rawValue || "");
|
||
if (!normalizedValue) {
|
||
return;
|
||
}
|
||
|
||
const groupKey = item.stepKey;
|
||
const currentGroup = grouped.get(groupKey) || {
|
||
stepTitle: item.stepTitle,
|
||
values: [],
|
||
valueSet: new Set<string>(),
|
||
};
|
||
|
||
const dedupeKey = normalizedValue.toLowerCase();
|
||
if (params.dedupeAcrossSteps && globalValueSet.has(dedupeKey)) {
|
||
return;
|
||
}
|
||
if (!currentGroup.valueSet.has(dedupeKey)) {
|
||
currentGroup.valueSet.add(dedupeKey);
|
||
if (params.dedupeAcrossSteps) {
|
||
globalValueSet.add(dedupeKey);
|
||
}
|
||
currentGroup.values.push(normalizedValue);
|
||
}
|
||
|
||
grouped.set(groupKey, currentGroup);
|
||
});
|
||
|
||
return Array.from(grouped.values())
|
||
.filter((group) => group.values.length > 0)
|
||
.map((group) => `${group.stepTitle}:${group.values.join(params.separator)}`);
|
||
}
|
||
|
||
function buildStructuredSelectionPromptSections(params: {
|
||
selections: AgentWorkflowComposerSelection[];
|
||
}) {
|
||
const groups = new Map<
|
||
string,
|
||
{
|
||
title: string;
|
||
values: string[];
|
||
valueSet: Set<string>;
|
||
}
|
||
>();
|
||
const globalValueSet = new Set<string>();
|
||
|
||
params.selections.forEach((selection) => {
|
||
const fragments = splitWorkflowPromptFragment(
|
||
selection.promptFragment || selection.optionName || ""
|
||
);
|
||
if (fragments.length === 0) {
|
||
return;
|
||
}
|
||
|
||
const currentGroup = groups.get(selection.stepKey) || {
|
||
title: selection.stepTitle,
|
||
values: [],
|
||
valueSet: new Set<string>(),
|
||
};
|
||
|
||
fragments.forEach((fragment) => {
|
||
const dedupeKey = fragment.toLowerCase();
|
||
if (currentGroup.valueSet.has(dedupeKey) || globalValueSet.has(dedupeKey)) {
|
||
return;
|
||
}
|
||
currentGroup.valueSet.add(dedupeKey);
|
||
globalValueSet.add(dedupeKey);
|
||
currentGroup.values.push(fragment);
|
||
});
|
||
|
||
if (currentGroup.values.length > 0) {
|
||
groups.set(selection.stepKey, currentGroup);
|
||
}
|
||
});
|
||
|
||
return Array.from(groups.values())
|
||
.filter((group) => group.values.length > 0)
|
||
.map((group) => `【${group.title}】\n${group.values.map((value) => `- ${value}`).join("\n")}`);
|
||
}
|
||
|
||
function buildPromptSection(title: string, lines: string[]) {
|
||
const normalizedLines = lines
|
||
.map((line) => String(line || "").trim())
|
||
.filter(Boolean);
|
||
if (normalizedLines.length === 0) {
|
||
return "";
|
||
}
|
||
|
||
return `【${title}】\n${normalizedLines.join("\n")}`;
|
||
}
|
||
|
||
export function buildAgentWorkflowComposerContext(params: {
|
||
config?: AgentWorkflowUiConfig | null;
|
||
inputs: AgentWorkflowInputsValue;
|
||
materials?: AgentWorkflowMaterialSelections | null;
|
||
selectedBrandModel?: AgentWorkflowSelectedBrandModel | null;
|
||
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
||
}): AgentWorkflowComposerContext | null {
|
||
const config = params.config || defaultAgentWorkflowUiConfig;
|
||
const steps = flattenVisibleAgentWorkflowSteps(
|
||
getEnabledAgentWorkflowStepTree(Array.isArray(config.steps) ? config.steps : []),
|
||
params.selections
|
||
)
|
||
.map(({ step }) => step)
|
||
.filter((step) => Array.isArray(step.options) && step.options.length > 0);
|
||
const selections = steps
|
||
.map((step) => {
|
||
const selectedOptions = getAgentWorkflowSelectedOptionPath({
|
||
step,
|
||
selectionValue: params.selections[step.key],
|
||
});
|
||
if (selectedOptions.length === 0) return [];
|
||
return selectedOptions.map((option) => ({
|
||
stepKey: step.key,
|
||
stepTitle: step.title,
|
||
optionKey: option.key,
|
||
optionName: option.buttonName,
|
||
promptFragment: option.promptFragment || option.buttonName,
|
||
}));
|
||
})
|
||
.flat() as AgentWorkflowComposerContext["selections"];
|
||
const referenceImages = getSelectedWorkflowReferenceImages({
|
||
inputs: params.inputs,
|
||
materials: params.materials,
|
||
selectedBrandModel: params.selectedBrandModel,
|
||
});
|
||
|
||
const summaryParts: string[] = [];
|
||
if (params.inputs.primarySku.trim()) {
|
||
summaryParts.push(`主SKU:${params.inputs.primarySku.trim()}`);
|
||
}
|
||
if (params.inputs.secondarySku.trim()) {
|
||
summaryParts.push(`搭配SKU:${params.inputs.secondarySku.trim()}`);
|
||
}
|
||
if (params.inputs.brand.trim()) {
|
||
summaryParts.push(`品牌:${params.inputs.brand.trim()}`);
|
||
}
|
||
if (params.inputs.store.trim()) {
|
||
summaryParts.push(`店铺:${params.inputs.store.trim()}`);
|
||
}
|
||
if (params.inputs.thirdCategory.trim()) {
|
||
summaryParts.push(`三级分类:${params.inputs.thirdCategory.trim()}`);
|
||
}
|
||
if (params.inputs.fourthCategory.trim()) {
|
||
summaryParts.push(`四级分类:${params.inputs.fourthCategory.trim()}`);
|
||
}
|
||
if (params.inputs.fifthCategory.trim()) {
|
||
summaryParts.push(`五级分类:${params.inputs.fifthCategory.trim()}`);
|
||
}
|
||
if (params.inputs.priceBand.trim()) {
|
||
summaryParts.push(`价格带:${params.inputs.priceBand.trim()}`);
|
||
}
|
||
const primaryGoodsInfoSummary = buildGoodsInfoSummaryLine({
|
||
label: "主SKU商品信息",
|
||
result: params.materials?.primary?.result || null,
|
||
});
|
||
if (primaryGoodsInfoSummary) {
|
||
summaryParts.push(primaryGoodsInfoSummary);
|
||
}
|
||
const secondaryGoodsInfoSummary = buildGoodsInfoSummaryLine({
|
||
label: "搭配SKU商品信息",
|
||
result: params.materials?.secondary?.result || null,
|
||
});
|
||
if (secondaryGoodsInfoSummary) {
|
||
summaryParts.push(secondaryGoodsInfoSummary);
|
||
}
|
||
if (referenceImages.some((item) => item.source === "primary")) {
|
||
summaryParts.push(
|
||
`主SPU图:${referenceImages.filter((item) => item.source === "primary").length}张`
|
||
);
|
||
}
|
||
if (referenceImages.some((item) => item.source === "secondary")) {
|
||
summaryParts.push(
|
||
`搭配SKU图:${referenceImages.filter((item) => item.source === "secondary").length}张`
|
||
);
|
||
}
|
||
if (referenceImages.some((item) => item.source === "brandModel")) {
|
||
summaryParts.push(
|
||
`品牌模特图:${referenceImages.filter((item) => item.source === "brandModel").length}张`
|
||
);
|
||
}
|
||
summaryParts.push(
|
||
...buildGroupedSelectionLines({
|
||
selections,
|
||
valueKey: "optionName",
|
||
separator: " / ",
|
||
})
|
||
);
|
||
|
||
if (summaryParts.length === 0) {
|
||
return null;
|
||
}
|
||
|
||
const basicContextLines: string[] = [];
|
||
if (params.inputs.primarySku.trim()) {
|
||
basicContextLines.push(`主SKU:${params.inputs.primarySku.trim()}`);
|
||
}
|
||
if (params.inputs.secondarySku.trim()) {
|
||
basicContextLines.push(`搭配SKU:${params.inputs.secondarySku.trim()}`);
|
||
}
|
||
if (params.inputs.brand.trim()) {
|
||
basicContextLines.push(`品牌:${params.inputs.brand.trim()}`);
|
||
}
|
||
if (params.inputs.store.trim()) {
|
||
basicContextLines.push(`店铺:${params.inputs.store.trim()}`);
|
||
}
|
||
if (params.inputs.thirdCategory.trim()) {
|
||
basicContextLines.push(`三级分类:${params.inputs.thirdCategory.trim()}`);
|
||
}
|
||
if (params.inputs.fourthCategory.trim()) {
|
||
basicContextLines.push(`四级分类:${params.inputs.fourthCategory.trim()}`);
|
||
}
|
||
if (params.inputs.fifthCategory.trim()) {
|
||
basicContextLines.push(`五级分类:${params.inputs.fifthCategory.trim()}`);
|
||
}
|
||
if (params.inputs.priceBand.trim()) {
|
||
basicContextLines.push(`价格带:${params.inputs.priceBand.trim()}`);
|
||
}
|
||
|
||
const primaryLockLines: string[] = [];
|
||
const primaryGoodsInfoPrompt = buildGoodsInfoPromptLine({
|
||
label: "主SKU商品信息",
|
||
result: params.materials?.primary?.result || null,
|
||
});
|
||
if (primaryGoodsInfoPrompt) {
|
||
primaryLockLines.push(primaryGoodsInfoPrompt);
|
||
}
|
||
const primaryGoodsInfoSizeConstraint = buildGoodsInfoSizeConstraintLine({
|
||
label: "主SKU",
|
||
result: params.materials?.primary?.result || null,
|
||
});
|
||
if (primaryGoodsInfoSizeConstraint) {
|
||
primaryLockLines.push(primaryGoodsInfoSizeConstraint);
|
||
}
|
||
const primaryGoodsInfoAppearanceConstraint = buildGoodsInfoAppearanceConstraintLine({
|
||
label: "主SKU",
|
||
result: params.materials?.primary?.result || null,
|
||
});
|
||
if (primaryGoodsInfoAppearanceConstraint) {
|
||
primaryLockLines.push(primaryGoodsInfoAppearanceConstraint);
|
||
}
|
||
|
||
const secondaryLockLines: string[] = [];
|
||
const secondaryGoodsInfoPrompt = buildGoodsInfoPromptLine({
|
||
label: "搭配SKU商品信息",
|
||
result: params.materials?.secondary?.result || null,
|
||
});
|
||
if (secondaryGoodsInfoPrompt) {
|
||
secondaryLockLines.push(secondaryGoodsInfoPrompt);
|
||
}
|
||
const secondaryGoodsInfoSizeConstraint = buildGoodsInfoSizeConstraintLine({
|
||
label: "搭配SKU",
|
||
result: params.materials?.secondary?.result || null,
|
||
});
|
||
if (secondaryGoodsInfoSizeConstraint) {
|
||
secondaryLockLines.push(secondaryGoodsInfoSizeConstraint);
|
||
}
|
||
const secondaryGoodsInfoAppearanceConstraint = buildGoodsInfoAppearanceConstraintLine({
|
||
label: "搭配SKU",
|
||
result: params.materials?.secondary?.result || null,
|
||
});
|
||
if (secondaryGoodsInfoAppearanceConstraint) {
|
||
secondaryLockLines.push(secondaryGoodsInfoAppearanceConstraint);
|
||
}
|
||
|
||
const referenceLines: string[] = [];
|
||
if (referenceImages.some((item) => item.source === "primary")) {
|
||
const labels = referenceImages
|
||
.filter((item) => item.source === "primary")
|
||
.map((item) => item.label)
|
||
.filter(Boolean)
|
||
.slice(0, 8);
|
||
referenceLines.push(
|
||
`主SPU参考图:已选${referenceImages.filter((item) => item.source === "primary").length}张${
|
||
labels.length > 0 ? `(${labels.join("、")})` : ""
|
||
}`
|
||
);
|
||
}
|
||
if (referenceImages.some((item) => item.source === "secondary")) {
|
||
const labels = referenceImages
|
||
.filter((item) => item.source === "secondary")
|
||
.map((item) => item.label)
|
||
.filter(Boolean)
|
||
.slice(0, 8);
|
||
referenceLines.push(
|
||
`搭配SKU参考图:已选${referenceImages.filter((item) => item.source === "secondary").length}张${
|
||
labels.length > 0 ? `(${labels.join("、")})` : ""
|
||
}`
|
||
);
|
||
}
|
||
if (referenceImages.some((item) => item.source === "brandModel")) {
|
||
const labels = referenceImages
|
||
.filter((item) => item.source === "brandModel")
|
||
.map((item) => item.label)
|
||
.filter(Boolean)
|
||
.slice(0, 8);
|
||
referenceLines.push(
|
||
`品牌模特图:已选${referenceImages.filter((item) => item.source === "brandModel").length}张${
|
||
labels.length > 0 ? `(${labels.join("、")})` : ""
|
||
}`
|
||
);
|
||
}
|
||
const bundleUsagePrompt = buildBundleUsagePromptLine({ referenceImages });
|
||
if (bundleUsagePrompt) {
|
||
secondaryLockLines.push(bundleUsagePrompt);
|
||
}
|
||
|
||
const promptSections = [
|
||
buildPromptSection("项目背景", basicContextLines),
|
||
buildPromptSection("主SKU锁定", primaryLockLines),
|
||
buildPromptSection("搭配SKU锁定", secondaryLockLines),
|
||
buildPromptSection("参考图", referenceLines),
|
||
...buildStructuredSelectionPromptSections({ selections }),
|
||
].filter(Boolean);
|
||
|
||
return {
|
||
primarySku: params.inputs.primarySku.trim() || undefined,
|
||
secondarySku: params.inputs.secondarySku.trim() || undefined,
|
||
brand: params.inputs.brand.trim() || undefined,
|
||
store: params.inputs.store.trim() || undefined,
|
||
thirdCategory: params.inputs.thirdCategory.trim() || undefined,
|
||
fourthCategory: params.inputs.fourthCategory.trim() || undefined,
|
||
fifthCategory: params.inputs.fifthCategory.trim() || undefined,
|
||
priceBand: params.inputs.priceBand.trim() || undefined,
|
||
selections,
|
||
referenceImages,
|
||
summaryText: summaryParts.join(" / "),
|
||
promptText: promptSections.join("\n\n"),
|
||
};
|
||
}
|
||
|
||
export function getSelectedWorkflowReferenceImages(params: {
|
||
inputs: AgentWorkflowInputsValue;
|
||
materials?: AgentWorkflowMaterialSelections | null;
|
||
selectedBrandModel?: AgentWorkflowSelectedBrandModel | null;
|
||
}): AgentWorkflowReferenceImage[] {
|
||
const materials = params.materials;
|
||
if (!materials) return [];
|
||
|
||
const collect = (
|
||
source: "primary" | "secondary",
|
||
sourceLabel: string,
|
||
fallbackSku: string
|
||
) => {
|
||
const state = materials[source];
|
||
const result = state?.result;
|
||
if (!result || !Array.isArray(result.images) || result.images.length === 0) {
|
||
return [] as AgentWorkflowReferenceImage[];
|
||
}
|
||
|
||
const selectedIds = new Set(
|
||
(state.selectedImageIds || []).map((item) => String(item || "").trim()).filter(Boolean)
|
||
);
|
||
if (selectedIds.size === 0) {
|
||
return [] as AgentWorkflowReferenceImage[];
|
||
}
|
||
|
||
return result.images
|
||
.filter((item) => selectedIds.has(item.id))
|
||
.map((item) => ({
|
||
id: item.id,
|
||
source,
|
||
sourceLabel,
|
||
sku: result.matchedSku || fallbackSku || undefined,
|
||
productModel: result.productModel || null,
|
||
label: item.label,
|
||
name: item.fileName || item.label,
|
||
url: item.imageUrl,
|
||
assetId: item.assetId || null,
|
||
mimeType: item.mimeType || null,
|
||
}));
|
||
};
|
||
|
||
return [
|
||
...collect("primary", "主SPU", params.inputs.primarySku.trim()),
|
||
...collect("secondary", "搭配SKU", params.inputs.secondarySku.trim()),
|
||
...(params.selectedBrandModel?.imageUrl
|
||
? [
|
||
{
|
||
id: params.selectedBrandModel.id,
|
||
source: "brandModel" as const,
|
||
sourceLabel: "品牌模特",
|
||
label: params.selectedBrandModel.displayName || params.selectedBrandModel.brandName,
|
||
name: params.selectedBrandModel.displayName || params.selectedBrandModel.brandName,
|
||
url: params.selectedBrandModel.imageUrl,
|
||
assetId: params.selectedBrandModel.assetId || null,
|
||
mimeType: params.selectedBrandModel.mimeType || null,
|
||
},
|
||
]
|
||
: []),
|
||
];
|
||
}
|
||
|
||
export function getAgentWorkflowProgress(params: {
|
||
config?: AgentWorkflowUiConfig | null;
|
||
selections: Partial<Record<AgentWorkflowStepKey, string>>;
|
||
}) {
|
||
const config = params.config || defaultAgentWorkflowUiConfig;
|
||
const enabledSteps = flattenVisibleAgentWorkflowSteps(
|
||
getEnabledAgentWorkflowStepTree(config.steps || []),
|
||
params.selections
|
||
)
|
||
.map(({ step }) => step)
|
||
.filter((step) => Array.isArray(step.options) && step.options.length > 0);
|
||
const completedSteps = enabledSteps.filter((step) => {
|
||
return isAgentWorkflowStepSelectionComplete({
|
||
step,
|
||
selectionValue: params.selections[step.key],
|
||
});
|
||
});
|
||
|
||
return {
|
||
total: enabledSteps.length,
|
||
completed: completedSteps.length,
|
||
isComplete: enabledSteps.length > 0 && completedSteps.length === enabledSteps.length,
|
||
};
|
||
}
|