perf: variabel replace;Feat: prompt optimizer code (#5453)

* feat: add prompt optimizer (#5444)

* feat: add prompt optimizer

* fix

* perf: variabel replace

* perf: prompt optimizer code

* feat: init charts shell

* perf: user error remove

---------

Co-authored-by: heheer <heheer@sealos.io>
This commit is contained in:
Archer
2025-08-14 15:48:22 +08:00
committed by GitHub
parent 6a02d2a2e5
commit 9fbfabac61
35 changed files with 1968 additions and 202 deletions

View File

@@ -20,7 +20,7 @@ import type { WorkflowInteractiveResponseType } from '../workflow/template/syste
import type { FlowNodeInputItemType } from '../workflow/type/io';
import type { FlowNodeTemplateType } from '../workflow/type/node.d';
export type ChatSchema = {
export type ChatSchemaType = {
_id: string;
chatId: string;
userId: string;
@@ -33,6 +33,8 @@ export type ChatSchema = {
customTitle: string;
top: boolean;
source: `${ChatSourceEnum}`;
sourceName?: string;
shareId?: string;
outLinkUid?: string;
@@ -43,7 +45,7 @@ export type ChatSchema = {
metadata?: Record<string, any>;
};
export type ChatWithAppSchema = Omit<ChatSchema, 'appId'> & {
export type ChatWithAppSchema = Omit<ChatSchemaType, 'appId'> & {
appId: AppSchema;
};

View File

@@ -467,27 +467,63 @@ export const formatVariableValByType = (val: any, valueType?: WorkflowIOValueTyp
return val;
};
// replace {{$xx.xx$}} variables for text
export function replaceEditorVariable({
text,
nodes,
variables
variables,
depth = 0
}: {
text: any;
nodes: RuntimeNodeItemType[];
variables: Record<string, any>; // global variables
depth?: number;
}) {
if (typeof text !== 'string') return text;
if (text === '') return text;
const MAX_REPLACEMENT_DEPTH = 10;
const processedVariables = new Set<string>();
// Prevent infinite recursion
if (depth > MAX_REPLACEMENT_DEPTH) {
return text;
}
text = replaceVariable(text, variables);
// Check for circular references in variable values
const hasCircularReference = (value: any, targetKey: string): boolean => {
if (typeof value !== 'string') return false;
// Check if the value contains the target variable pattern (direct self-reference)
const selfRefPattern = new RegExp(
`\\{\\{\\$${targetKey.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\$\\}\\}`,
'g'
);
return selfRefPattern.test(value);
};
const variablePattern = /\{\{\$([^.]+)\.([^$]+)\$\}\}/g;
const matches = [...text.matchAll(variablePattern)];
if (matches.length === 0) return text;
matches.forEach((match) => {
let result = text;
let hasReplacements = false;
// Build replacement map first to avoid modifying string during iteration
const replacements: Array<{ pattern: string; replacement: string }> = [];
for (const match of matches) {
const nodeId = match[1];
const id = match[2];
const variableKey = `${nodeId}.${id}`;
// Skip if already processed to avoid immediate circular reference
if (processedVariables.has(variableKey)) {
continue;
}
const variableVal = (() => {
if (nodeId === VARIABLE_NODE_ID) {
@@ -505,13 +541,35 @@ export function replaceEditorVariable({
if (input) return getReferenceVariableValue({ value: input.value, nodes, variables });
})();
const formatVal = valToStr(variableVal);
// Check for direct circular reference
if (hasCircularReference(String(variableVal), variableKey)) {
continue;
}
const regex = new RegExp(`\\{\\{\\$(${nodeId}\\.${id})\\$\\}\\}`, 'g');
text = text.replace(regex, () => formatVal);
const formatVal = valToStr(variableVal);
const escapedNodeId = nodeId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const escapedId = id.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
replacements.push({
pattern: `\\{\\{\\$(${escapedNodeId}\\.${escapedId})\\$\\}\\}`,
replacement: formatVal
});
processedVariables.add(variableKey);
hasReplacements = true;
}
// Apply all replacements
replacements.forEach(({ pattern, replacement }) => {
result = result.replace(new RegExp(pattern, 'g'), replacement);
});
return text || '';
// If we made replacements and there might be nested variables, recursively process
if (hasReplacements && /\{\{\$[^.]+\.[^$]+\$\}\}/.test(result)) {
result = replaceEditorVariable({ text: result, nodes, variables, depth: depth + 1 });
}
return result || '';
}
export const textAdaptGptResponse = ({