sync: UI animations, select styling, TLS verify flag via proxy second line, brand spacing

This commit is contained in:
2025-09-27 18:46:52 +03:00
parent 135c393eda
commit 2abfbb4b1a
52 changed files with 8029 additions and 1408 deletions

View File

@@ -12,7 +12,8 @@
// Top-level pipeline meta kept in memory and included into JSON on save.
// Allows UI to edit loop parameters without manual JSON edits.
let _pipelineMeta = {
// DRY: единый источник дефолтов и нормализации meta
const MetaDefaults = Object.freeze({
id: 'pipeline_editor',
name: 'Edited Pipeline',
parallel_limit: 8,
@@ -20,19 +21,74 @@
loop_max_iters: 1000,
loop_time_budget_ms: 10000,
clear_var_store: true,
// New: default HTTP timeout for upstream requests (seconds)
http_timeout_sec: 60,
// New (v1): стратегия извлечения текста для [[OUTx]] (глобальная по умолчанию)
// auto | deep | openai | gemini | claude | jsonpath
text_extract_strategy: 'auto',
// Используется при стратегии jsonpath (dot-нотация, поддержка индексов: a.b.0.c)
text_extract_json_path: '',
// Разделитель при объединении массива результатов
text_join_sep: '\n',
// v2: коллекция пресетов извлечения текста, управляется в "Запуск"
// [{ id, name, strategy, json_path, join_sep }]
text_extract_presets: [],
};
});
let _pipelineMeta = { ...MetaDefaults };
// Нормализатор meta: приводит типы, поддерживает синонимы ключей, заполняет дефолты
function ensureMeta(p) {
const src = (p && typeof p === 'object') ? p : {};
const out = { ...MetaDefaults };
// helpers
const toInt = (v, def) => {
try {
const n = parseInt(v, 10);
return Number.isFinite(n) && n > 0 ? n : def;
} catch { return def; }
};
const toNum = (v, def) => {
try {
const n = parseFloat(v);
return !Number.isNaN(n) && n > 0 ? n : def;
} catch { return def; }
};
// базовые поля
try { out.id = String((src.id ?? out.id) || out.id); } catch {}
try { out.name = String((src.name ?? out.name) || out.name); } catch {}
out.parallel_limit = toInt(src.parallel_limit, out.parallel_limit);
out.loop_mode = String((src.loop_mode ?? out.loop_mode) || out.loop_mode);
out.loop_max_iters = toInt(src.loop_max_iters, out.loop_max_iters);
out.loop_time_budget_ms = toInt(src.loop_time_budget_ms, out.loop_time_budget_ms);
out.clear_var_store = (typeof src.clear_var_store === 'boolean') ? !!src.clear_var_store : out.clear_var_store;
out.http_timeout_sec = toNum(src.http_timeout_sec, out.http_timeout_sec);
out.text_extract_strategy = String((src.text_extract_strategy ?? out.text_extract_strategy) || out.text_extract_strategy);
out.text_extract_json_path = String((src.text_extract_json_path ?? out.text_extract_json_path) || out.text_extract_json_path);
// поддержка синонимов text_join_sep (регистр и вариации)
let joinSep = out.text_join_sep;
try {
for (const k of Object.keys(src)) {
if (String(k).toLowerCase() === 'text_join_sep') { joinSep = src[k]; break; }
}
} catch {}
out.text_join_sep = String((joinSep ?? src.text_join_sep ?? out.text_join_sep) || out.text_join_sep);
// коллекция пресетов
try {
const arr = Array.isArray(src.text_extract_presets) ? src.text_extract_presets : [];
out.text_extract_presets = arr
.filter(it => it && typeof it === 'object')
.map((it, idx) => ({
id: String((it.id ?? '') || ('p' + Date.now().toString(36) + Math.random().toString(36).slice(2) + idx)),
name: String(it.name ?? (it.json_path || 'Preset')),
strategy: String(it.strategy ?? 'auto'),
json_path: String(it.json_path ?? ''),
join_sep: String(it.join_sep ?? '\n'),
}));
} catch { out.text_extract_presets = []; }
return out;
}
function getPipelineMeta() {
return { ..._pipelineMeta };
@@ -40,48 +96,8 @@
function updatePipelineMeta(p) {
if (!p || typeof p !== 'object') return;
const keys = [
'id','name','parallel_limit','loop_mode','loop_max_iters','loop_time_budget_ms','clear_var_store','http_timeout_sec',
'text_extract_strategy','text_extract_json_path','text_join_sep','text_join_sep','text_join_SEP',
// v2 presets collection
'text_extract_presets'
];
for (const k of keys) {
if (Object.prototype.hasOwnProperty.call(p, k) && p[k] !== undefined && p[k] !== null && (k === 'clear_var_store' ? true : p[k] !== '')) {
if (k === 'parallel_limit' || k === 'loop_max_iters' || k === 'loop_time_budget_ms') {
const v = parseInt(p[k], 10);
if (!Number.isNaN(v) && v > 0) _pipelineMeta[k] = v;
} else if (k === 'http_timeout_sec') {
const fv = parseFloat(p[k]);
if (!Number.isNaN(fv) && fv > 0) _pipelineMeta[k] = fv;
} else if (k === 'clear_var_store') {
_pipelineMeta[k] = !!p[k];
} else {
// спец-обработка коллекции пресетов
if (k === 'text_extract_presets') {
try {
const arr = Array.isArray(p[k]) ? p[k] : [];
_pipelineMeta[k] = arr
.filter(it => it && typeof it === 'object')
.map(it => ({
id: String((it.id ?? '') || ('p' + Date.now().toString(36) + Math.random().toString(36).slice(2))),
name: String(it.name ?? 'Preset'),
strategy: String(it.strategy ?? 'auto'),
json_path: String(it.json_path ?? ''),
join_sep: String(it.join_sep ?? '\n'),
}));
} catch (_) {
_pipelineMeta[k] = [];
}
} else if (k.toLowerCase() === 'text_join_sep') {
// нормализация ключа join separator (допускаем разные написания)
_pipelineMeta['text_join_sep'] = String(p[k]);
} else {
_pipelineMeta[k] = String(p[k]);
}
}
}
}
// DRY: единая точка нормализации
_pipelineMeta = ensureMeta({ ..._pipelineMeta, ...p });
}
// Drawflow -> pipeline JSON
@@ -260,24 +276,10 @@
}
}
// 3) Собираем итоговый pipeline JSON с метаданными
const meta = getPipelineMeta();
return {
id: meta.id || 'pipeline_editor',
name: meta.name || 'Edited Pipeline',
parallel_limit: (typeof meta.parallel_limit === 'number' ? meta.parallel_limit : 8),
loop_mode: (meta.loop_mode || 'dag'),
loop_max_iters: (typeof meta.loop_max_iters === 'number' ? meta.loop_max_iters : 1000),
loop_time_budget_ms: (typeof meta.loop_time_budget_ms === 'number' ? meta.loop_time_budget_ms : 10000),
clear_var_store: (typeof meta.clear_var_store === 'boolean' ? meta.clear_var_store : true),
http_timeout_sec: (typeof meta.http_timeout_sec === 'number' ? meta.http_timeout_sec : 60),
text_extract_strategy: (meta.text_extract_strategy || 'auto'),
text_extract_json_path: (meta.text_extract_json_path || ''),
text_join_sep: (meta.text_join_sep || '\n'),
// v2: persist presets
text_extract_presets: (Array.isArray(meta.text_extract_presets) ? meta.text_extract_presets : []),
nodes
};
// 3) Собираем итоговый pipeline JSON с метаданными (нормализованными)
const meta = ensureMeta(getPipelineMeta());
try { console.debug('[AgentUISer.toPipelineJSON] meta_keys', Object.keys(meta || {})); } catch (e) {}
return { ...meta, nodes };
}
// pipeline JSON -> Drawflow
@@ -285,25 +287,25 @@
ensureDeps();
const editor = w.editor;
const NODE_IO = w.NODE_IO;
// Сохраняем метаданные пайплайна для UI
try {
updatePipelineMeta({
id: p && p.id ? p.id : 'pipeline_editor',
name: p && p.name ? p.name : 'Edited Pipeline',
parallel_limit: (p && typeof p.parallel_limit === 'number') ? p.parallel_limit : 8,
loop_mode: p && p.loop_mode ? p.loop_mode : 'dag',
loop_max_iters: (p && typeof p.loop_max_iters === 'number') ? p.loop_max_iters : 1000,
loop_time_budget_ms: (p && typeof p.loop_time_budget_ms === 'number') ? p.loop_time_budget_ms : 10000,
clear_var_store: (p && typeof p.clear_var_store === 'boolean') ? p.clear_var_store : true,
http_timeout_sec: (p && typeof p.http_timeout_sec === 'number') ? p.http_timeout_sec : 60,
text_extract_strategy: (p && typeof p.text_extract_strategy === 'string') ? p.text_extract_strategy : 'auto',
text_extract_json_path: (p && typeof p.text_extract_json_path === 'string') ? p.text_extract_json_path : '',
text_join_sep: (p && typeof p.text_join_sep === 'string') ? p.text_join_sep : '\n',
// v2: presets from pipeline.json
text_extract_presets: (p && Array.isArray(p.text_extract_presets)) ? p.text_extract_presets : [],
});
} catch (e) {}
// Сохраняем метаданные пайплайна для UI (сквозная нормализация)
try {
updatePipelineMeta(p || {});
// Диагностический лог состава meta для подтверждения DRY-рефакторинга
try {
const metaKeys = ["id","name","parallel_limit","loop_mode","loop_max_iters","loop_time_budget_ms","clear_var_store","http_timeout_sec","text_extract_strategy","text_extract_json_path","text_join_sep","text_extract_presets"];
const incomingKeys = metaKeys.filter(k => (p && Object.prototype.hasOwnProperty.call(p, k)));
const currentMeta = (typeof getPipelineMeta === 'function') ? getPipelineMeta() : {};
console.debug('[AgentUISer.fromPipelineJSON] meta_keys', {
incomingKeys,
resultKeys: Object.keys(currentMeta || {}),
metaPreview: {
id: currentMeta && currentMeta.id,
loop_mode: currentMeta && currentMeta.loop_mode,
http_timeout_sec: currentMeta && currentMeta.http_timeout_sec
}
});
} catch (_) {}
} catch (e) {}
editor.clear();
let x = 100; let y = 120; // Fallback