mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-01 05:30:19 +02:00
feat: add TypeSafe Jev as HITL audit backend
Let audit_agent approve or reject with one System One call instead of chat JSON, while keeping the OpenAI-compatible backend as an option. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
3aa9274675
commit
38b96ec67a
30 files changed
+1372
-21
No files matched your search
+31
-1
@@ -143,6 +143,7 @@ let chatAIChannels = {};
|
||||
let chatDefaultAIChannel = '';
|
||||
let chatAIChannelIdByNormalizedId = {};
|
||||
let chatHitlAuditModelName = '';
|
||||
let chatHitlAuditBackend = '';
|
||||
let chatSystemModelRequestSeq = 0;
|
||||
let chatSystemModelSaving = false;
|
||||
let chatSystemModelCloseTimer = null;
|
||||
@@ -1070,10 +1071,26 @@ function currentSystemModelLabel() {
|
||||
return model || (ch && (ch.name || chatDefaultAIChannel)) || currentChatModelLabel();
|
||||
}
|
||||
|
||||
function currentHitlAuditBackend() {
|
||||
const b = String(chatHitlAuditBackend || (typeof window !== 'undefined' && window.csaiHitlAuditBackend) || '').trim().toLowerCase();
|
||||
return (b === 'typesafe' || b === 'jev' || b === 'type-safe') ? 'typesafe' : 'openai';
|
||||
}
|
||||
|
||||
function currentHitlAuditModelLabel() {
|
||||
if (currentHitlAuditBackend() === 'typesafe') {
|
||||
return chatHitlAuditModelName || 'jev-latest';
|
||||
}
|
||||
return chatHitlAuditModelName || currentSystemModelLabel();
|
||||
}
|
||||
|
||||
function currentHitlAuditEngineLabel() {
|
||||
const engine = currentHitlAuditBackend() === 'typesafe'
|
||||
? chatTranslate('settings.hitl.auditBackendTypeSafe', 'TypeSafe Jev')
|
||||
: chatTranslate('settings.hitl.auditBackendOpenAI', 'OpenAI 协议模型');
|
||||
const model = currentHitlAuditModelLabel();
|
||||
return engine + (model ? ' · ' + model : '');
|
||||
}
|
||||
|
||||
function resolveChatPickerChannelId() {
|
||||
return selectedChatAIChannelId() || chatDefaultAIChannel;
|
||||
}
|
||||
@@ -1709,7 +1726,7 @@ function updateChatComposerSessionShortcuts(summary) {
|
||||
? chatTranslate('chat.sessionShortcutAuditAgent', 'Agent 审查')
|
||||
: chatTranslate('chat.sessionShortcutHuman', '人工审批');
|
||||
const modeLabel = data.hitl || getHitlModeLabel(cfg.mode);
|
||||
const approvalModel = auditAgent ? currentHitlAuditModelLabel() : '';
|
||||
const approvalModel = auditAgent ? currentHitlAuditEngineLabel() : '';
|
||||
const label = prefix + ':' + modeLabel + (approvalModel ? ' · ' + approvalModel : '');
|
||||
hitlEl.textContent = label;
|
||||
hitlEl.title = label;
|
||||
@@ -2070,9 +2087,22 @@ async function initChatAgentModeFromConfig() {
|
||||
multiAgentAPIEnabled = !!(cfg.multi_agent && cfg.multi_agent.enabled);
|
||||
populateChatAIChannelSelect(cfg.ai || {});
|
||||
const hitlAuditModel = cfg.hitl && cfg.hitl.audit_model;
|
||||
chatHitlAuditBackend = cfg.hitl && typeof cfg.hitl.audit_backend === 'string'
|
||||
? cfg.hitl.audit_backend.trim().toLowerCase()
|
||||
: '';
|
||||
chatHitlAuditModelName = hitlAuditModel && typeof hitlAuditModel.model === 'string'
|
||||
? hitlAuditModel.model.trim()
|
||||
: '';
|
||||
if (typeof window !== 'undefined') {
|
||||
window.csaiHitlAuditBackend = chatHitlAuditBackend;
|
||||
window.csaiHitlAuditModel = chatHitlAuditModelName;
|
||||
if (typeof window.renderHitlPageAuditEngine === 'function') {
|
||||
window.renderHitlPageAuditEngine();
|
||||
}
|
||||
if (typeof window.renderHitlStrategyJevHint === 'function') {
|
||||
window.renderHitlStrategyJevHint();
|
||||
}
|
||||
}
|
||||
updateChatReasoningSummary();
|
||||
if (typeof window !== 'undefined') {
|
||||
window.__csaiMultiAgentPublic = cfg.multi_agent || null;
|
||||
|
||||
@@ -57,7 +57,7 @@ test('输入框可按会话通道获取模型并双向同步会话推理且审
|
||||
assert.match(chat, /function currentHitlAuditModelLabel\(\)/);
|
||||
assert.match(chat, /const label = currentChatModelLabel\(\)/);
|
||||
assert.doesNotMatch(chat, /const label = data\.model \|\| currentChatModelLabel\(\)/);
|
||||
assert.match(chat, /const approvalModel = auditAgent \? currentHitlAuditModelLabel\(\) : ''/);
|
||||
assert.match(chat, /const approvalModel = auditAgent \? currentHitlAuditEngineLabel\(\) : ''/);
|
||||
assert.match(chat, /hitlAuditModel\.model\.trim\(\)/);
|
||||
assert.match(template, /id="chat-model-shortcut"[^>]+onclick="openChatSystemModelPicker\(event\)"/);
|
||||
assert.match(template, /id="chat-system-model-menu"[^>]+hidden/);
|
||||
@@ -361,6 +361,24 @@ test('旧会话首次升级到五分钟默认审批时限,仍允许用户之
|
||||
assert.match(fs.readFileSync('web/static/js/hitl.js', 'utf8'), /markLegacyHitlTimeoutMigrated/);
|
||||
});
|
||||
|
||||
test('人机协同页和日志展示 Jev / OpenAI 审批引擎', () => {
|
||||
const hitlPage = fs.readFileSync('web/static/js/hitl.js', 'utf8');
|
||||
assert.match(template, /id="hitl-page-audit-engine"/);
|
||||
assert.match(template, /id="hitl-log-detail-engine"/);
|
||||
assert.match(hitlPage, /function hitlAuditEngineFromItem/);
|
||||
assert.match(hitlPage, /function renderHitlPageAuditEngine/);
|
||||
assert.match(hitlPage, /function renderHitlStrategyJevHint/);
|
||||
assert.match(template, /id="hitl-strategy-hint-jev"/);
|
||||
assert.equal(zh.hitl.strategyHintJev.includes('Jev'), true);
|
||||
assert.equal(en.hitl.strategyHintJev.includes('Jev'), true);
|
||||
assert.match(handler, /auditBackend/);
|
||||
assert.match(chat, /function currentHitlAuditEngineLabel\(\)/);
|
||||
assert.equal(zh.hitl.auditEngineJev, 'TypeSafe Jev');
|
||||
assert.equal(en.hitl.auditEngineJev, 'TypeSafe Jev');
|
||||
assert.equal(zh.hitl.auditEngineOpenAI, 'OpenAI 协议');
|
||||
assert.equal(en.hitl.auditEngineOpenAI, 'OpenAI protocol');
|
||||
});
|
||||
|
||||
test('审批体验文案具有完整中英文资源', () => {
|
||||
const hitlKeys = [
|
||||
'waitingApprovalShort',
|
||||
|
||||
+139
-2
@@ -272,9 +272,15 @@ function applyHitlDefaultConfigFromServer(data) {
|
||||
reviewer: reviewer,
|
||||
timeoutSeconds: timeoutSeconds
|
||||
};
|
||||
const backend = hitlNormalizeAuditBackend(src.auditBackend || src.audit_backend);
|
||||
const model = String(src.auditModel || src.audit_model || '').trim();
|
||||
if (backend) out.auditBackend = backend;
|
||||
if (model) out.auditModel = model;
|
||||
if (typeof window !== 'undefined') {
|
||||
window.csaiHitlDefaultConfig = out;
|
||||
window.csaiHitlDefaultReviewer = reviewer;
|
||||
if (backend) window.csaiHitlAuditBackend = backend;
|
||||
if (model || backend) window.csaiHitlAuditModel = model;
|
||||
if (Array.isArray(src.hitlGlobalToolWhitelist)) {
|
||||
window.csaiHitlGlobalToolWhitelist = src.hitlGlobalToolWhitelist;
|
||||
}
|
||||
@@ -1088,6 +1094,8 @@ function refreshHitlPageReviewerBar() {
|
||||
if (typeof window.bindHitlReviewerToggleListeners === 'function') {
|
||||
window.bindHitlReviewerToggleListeners();
|
||||
}
|
||||
renderHitlPageAuditEngine();
|
||||
renderHitlStrategyJevHint();
|
||||
}
|
||||
|
||||
let hitlDefaultAuditPrompt = '';
|
||||
@@ -1114,6 +1122,7 @@ function switchHitlStrategyMode(mode) {
|
||||
if (reviewTa) reviewTa.hidden = hitlStrategyMode !== 'review_edit';
|
||||
if (hintApproval) hintApproval.hidden = hitlStrategyMode !== 'approval';
|
||||
if (hintReview) hintReview.hidden = hitlStrategyMode !== 'review_edit';
|
||||
renderHitlStrategyJevHint();
|
||||
}
|
||||
|
||||
function showHitlStrategyFeedback(text, isError) {
|
||||
@@ -1151,6 +1160,23 @@ async function refreshHitlAuditStrategy() {
|
||||
}
|
||||
}
|
||||
|
||||
function renderHitlStrategyJevHint() {
|
||||
let el = document.getElementById('hitl-strategy-hint-jev');
|
||||
const bar = document.querySelector('.hitl-page-strategy-bar') || document.getElementById('hitl-page-strategy-bar');
|
||||
if (!el && bar) {
|
||||
el = document.createElement('p');
|
||||
el.className = 'hitl-page-strategy-hint';
|
||||
el.id = 'hitl-strategy-hint-jev';
|
||||
const reviewHint = document.getElementById('hitl-strategy-hint-review-edit');
|
||||
if (reviewHint && reviewHint.parentNode) reviewHint.parentNode.insertBefore(el, reviewHint.nextSibling);
|
||||
else bar.appendChild(el);
|
||||
}
|
||||
if (!el) return;
|
||||
const ts = hitlCurrentAuditEngine().backend === 'typesafe';
|
||||
el.hidden = !ts;
|
||||
if (ts) el.textContent = hitlT('strategyHintJev', 'TypeSafe Jev evaluates the custom strategy as structured questions. Built-in destructive rules remain a hard floor.');
|
||||
}
|
||||
|
||||
async function saveHitlAuditStrategy() {
|
||||
const approvalTa = document.getElementById('hitl-audit-agent-prompt');
|
||||
const reviewTa = document.getElementById('hitl-audit-agent-prompt-review-edit');
|
||||
@@ -1205,7 +1231,6 @@ function refreshHitlActivePanel() {
|
||||
}
|
||||
|
||||
function hitlDecidedByLabel(v) {
|
||||
const key = 'reviewer' + String(v || 'human').replace(/_([a-z])/g, function (_, c) { return c.toUpperCase(); }).replace(/^./, function (c) { return c.toUpperCase(); });
|
||||
const map = {
|
||||
human: hitlT('reviewerHuman', 'Human'),
|
||||
audit_agent: hitlT('reviewerAgent', 'Audit Agent'),
|
||||
@@ -1215,6 +1240,83 @@ function hitlDecidedByLabel(v) {
|
||||
return map[v] || v || '-';
|
||||
}
|
||||
|
||||
function hitlNormalizeAuditBackend(v) {
|
||||
const s = String(v || '').trim().toLowerCase();
|
||||
if (s === 'typesafe' || s === 'jev' || s === 'type-safe' || s === 'typesafe-ai') return 'typesafe';
|
||||
if (s === 'openai' || s === 'openai_compatible' || s === 'llm') return 'openai';
|
||||
return '';
|
||||
}
|
||||
|
||||
function hitlCurrentAuditEngine() {
|
||||
const cfg = (typeof window !== 'undefined' && window.csaiHitlDefaultConfig) || {};
|
||||
const backend = hitlNormalizeAuditBackend(cfg.auditBackend || (typeof window !== 'undefined' && window.csaiHitlAuditBackend));
|
||||
let model = String(cfg.auditModel || (typeof window !== 'undefined' && window.csaiHitlAuditModel) || '').trim();
|
||||
if (backend === 'typesafe' && !model) model = 'jev-latest';
|
||||
return { backend: backend || 'openai', model: model };
|
||||
}
|
||||
|
||||
function hitlAuditEngineLabel(backend, model) {
|
||||
const b = hitlNormalizeAuditBackend(backend);
|
||||
if (!b) return '';
|
||||
const name = b === 'typesafe'
|
||||
? hitlT('auditEngineJev', 'TypeSafe Jev')
|
||||
: hitlT('auditEngineOpenAI', 'OpenAI protocol');
|
||||
const m = String(model || '').trim();
|
||||
return m ? (name + ' · ' + m) : name;
|
||||
}
|
||||
|
||||
function hitlAuditEngineFromItem(item) {
|
||||
const data = item && typeof item === 'object' ? item : {};
|
||||
let backend = hitlNormalizeAuditBackend(data.auditBackend || data.audit_backend);
|
||||
let model = String(data.auditModel || data.audit_model || '').trim();
|
||||
if (!backend) {
|
||||
const payload = typeof window.hitlParsePayloadObject === 'function'
|
||||
? hitlParsePayloadObject(data.payload || '')
|
||||
: {};
|
||||
const approval = payload && payload.hitlApproval && typeof payload.hitlApproval === 'object'
|
||||
? payload.hitlApproval
|
||||
: {};
|
||||
backend = hitlNormalizeAuditBackend(approval.auditBackend || approval.audit_backend);
|
||||
if (!model) model = String(approval.auditModel || approval.audit_model || '').trim();
|
||||
}
|
||||
if (!backend) {
|
||||
const comment = String(data.comment || '');
|
||||
if (/TypeSafe|破坏分|choice=|Jev/i.test(comment)) backend = 'typesafe';
|
||||
else if (hitlReviewerNormalize(data.decidedBy || data.decided_by) === 'audit_agent') backend = 'openai';
|
||||
}
|
||||
if (backend === 'typesafe' && !model) model = 'jev-latest';
|
||||
return { backend: backend, model: model };
|
||||
}
|
||||
|
||||
function ensureHitlPageAuditEngineEl() {
|
||||
let el = document.getElementById('hitl-page-audit-engine');
|
||||
if (el) return el;
|
||||
const bar = document.getElementById('hitl-page-reviewer-bar');
|
||||
if (!bar) return null;
|
||||
el = document.createElement('p');
|
||||
el.className = 'hitl-page-audit-engine';
|
||||
el.id = 'hitl-page-audit-engine';
|
||||
el.hidden = true;
|
||||
const hint = bar.querySelector('.hitl-page-reviewer-hint');
|
||||
if (hint) bar.insertBefore(el, hint);
|
||||
else bar.appendChild(el);
|
||||
return el;
|
||||
}
|
||||
|
||||
function renderHitlPageAuditEngine() {
|
||||
const el = ensureHitlPageAuditEngineEl();
|
||||
if (!el) return;
|
||||
const info = hitlCurrentAuditEngine();
|
||||
const engine = hitlAuditEngineLabel(info.backend, info.model);
|
||||
if (!engine) {
|
||||
el.hidden = true;
|
||||
el.textContent = '';
|
||||
return;
|
||||
}
|
||||
el.hidden = false;
|
||||
el.textContent = hitlT('auditEngineLabel', 'Approval engine') + ':' + engine;
|
||||
}
|
||||
|
||||
function hitlFormatTime(v) {
|
||||
if (!v) return '-';
|
||||
try {
|
||||
@@ -1594,7 +1696,11 @@ function renderHitlLogsTable(items) {
|
||||
'<td>' + escapeHtml(String(item.toolName || '-')) + '</td>' +
|
||||
'<td class="hitl-logs-cell-mono">' + escapeHtml(String(item.conversationId || '-')) + '</td>' +
|
||||
'<td><span class="hitl-decision-tag ' + decisionCls + '">' + escapeHtml(hitlDecisionLabel(decision)) + '</span></td>' +
|
||||
'<td>' + escapeHtml(hitlDecidedByLabel(item.decidedBy)) + '</td>' +
|
||||
'<td>' + escapeHtml(hitlDecidedByLabel(item.decidedBy)) + (function () {
|
||||
const engine = hitlAuditEngineFromItem(item);
|
||||
const label = hitlAuditEngineLabel(engine.backend, engine.model);
|
||||
return label ? '<div class="hitl-log-engine">' + escapeHtml(label) + '</div>' : '';
|
||||
}()) + '</td>' +
|
||||
'<td class="hitl-logs-summary">' + escapeHtml(summary) + '</td>' +
|
||||
'<td>' + escapeHtml(hitlFormatTime(item.decidedAt || item.createdAt)) + '</td>' +
|
||||
'<td class="hitl-logs-actions">' +
|
||||
@@ -1676,6 +1782,8 @@ function refreshHitlI18n() {
|
||||
syncAllHitlLogFilterSelects();
|
||||
renderHitlLogsPagination();
|
||||
renderHitlPendingPagination();
|
||||
renderHitlPageAuditEngine();
|
||||
renderHitlStrategyJevHint();
|
||||
}
|
||||
|
||||
function renderHitlLogsPagination() {
|
||||
@@ -1788,6 +1896,33 @@ async function openHitlLogModal(idOpt) {
|
||||
decisionEl.innerHTML = '<span class="hitl-decision-tag ' + cls + '">' + escapeHtml(hitlDecisionLabel(decision)) + '</span>';
|
||||
}
|
||||
if (decidedByEl) decidedByEl.textContent = hitlDecidedByLabel(item.decidedBy);
|
||||
let engineRow = document.getElementById('hitl-log-detail-engine-row');
|
||||
let engineEl = document.getElementById('hitl-log-detail-engine');
|
||||
if (!engineRow || !engineEl) {
|
||||
const decidedRow = decidedByEl && decidedByEl.closest('.hitl-log-detail-row');
|
||||
const dl = decidedRow && decidedRow.parentElement;
|
||||
if (dl && decidedRow) {
|
||||
engineRow = document.createElement('div');
|
||||
engineRow.className = 'hitl-log-detail-row';
|
||||
engineRow.id = 'hitl-log-detail-engine-row';
|
||||
engineRow.hidden = true;
|
||||
engineRow.innerHTML = '<dt>' + escapeHtml(hitlT('colAuditEngine', 'Approval engine')) + '</dt><dd id="hitl-log-detail-engine">—</dd>';
|
||||
if (decidedRow.nextSibling) dl.insertBefore(engineRow, decidedRow.nextSibling);
|
||||
else dl.appendChild(engineRow);
|
||||
engineEl = document.getElementById('hitl-log-detail-engine');
|
||||
}
|
||||
}
|
||||
if (engineRow && engineEl) {
|
||||
const engine = hitlAuditEngineFromItem(item);
|
||||
const label = hitlAuditEngineLabel(engine.backend, engine.model);
|
||||
if (label) {
|
||||
engineEl.textContent = label;
|
||||
engineRow.hidden = false;
|
||||
} else {
|
||||
engineEl.textContent = '';
|
||||
engineRow.hidden = true;
|
||||
}
|
||||
}
|
||||
if (timeEl) timeEl.textContent = hitlFormatTime(item.decidedAt || item.createdAt);
|
||||
const comment = String(item.comment || '').trim();
|
||||
if (commentRow && commentEl) {
|
||||
@@ -1823,6 +1958,8 @@ window.refreshHitlPageWhitelist = refreshHitlPageWhitelist;
|
||||
window.refreshHitlPending = refreshHitlPending;
|
||||
window.refreshHitlLogs = refreshHitlLogs;
|
||||
window.refreshHitlActivePanel = refreshHitlActivePanel;
|
||||
window.renderHitlPageAuditEngine = renderHitlPageAuditEngine;
|
||||
window.renderHitlStrategyJevHint = renderHitlStrategyJevHint;
|
||||
window.switchHitlPageTab = switchHitlPageTab;
|
||||
window.switchHitlStrategyMode = switchHitlStrategyMode;
|
||||
window.resetHitlAuditStrategy = resetHitlAuditStrategy;
|
||||
|
||||
@@ -110,6 +110,12 @@
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof window.syncHitlAuditBackendUI === 'function') {
|
||||
window.syncHitlAuditBackendUI();
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
|
||||
function updateLangLabel() {
|
||||
|
||||
@@ -790,6 +790,11 @@ async function loadConfig(loadTools = true, options = {}) {
|
||||
hitlReviewerEl.value = reviewer === 'audit_agent' ? 'audit_agent' : 'human';
|
||||
}
|
||||
const hitlAuditModel = hitl.audit_model || {};
|
||||
const hitlAuditBackendEl = document.getElementById('hitl-audit-backend');
|
||||
if (hitlAuditBackendEl) {
|
||||
const backend = String(hitl.audit_backend || '').trim().toLowerCase();
|
||||
hitlAuditBackendEl.value = (backend === 'typesafe' || backend === 'jev') ? 'typesafe' : 'openai';
|
||||
}
|
||||
const hitlAuditProviderEl = document.getElementById('hitl-audit-model-provider');
|
||||
if (hitlAuditProviderEl) {
|
||||
const provider = String(hitlAuditModel.provider || '').trim().toLowerCase();
|
||||
@@ -817,6 +822,9 @@ async function loadConfig(loadTools = true, options = {}) {
|
||||
if (hitlReviewEditPromptEl) {
|
||||
hitlReviewEditPromptEl.value = hitl.audit_agent_prompt_review_edit || '';
|
||||
}
|
||||
if (typeof window.syncHitlAuditBackendUI === 'function') {
|
||||
window.syncHitlAuditBackendUI();
|
||||
}
|
||||
|
||||
// 填充Agent配置
|
||||
document.getElementById('agent-max-iterations').value = currentConfig.agent.max_iterations || 30;
|
||||
@@ -2020,6 +2028,7 @@ async function applySettings() {
|
||||
},
|
||||
hitl: {
|
||||
...prevHitl,
|
||||
audit_backend: document.getElementById('hitl-audit-backend')?.value === 'typesafe' ? 'typesafe' : 'openai',
|
||||
audit_model: {
|
||||
...(prevHitl.audit_model || {}),
|
||||
provider: document.getElementById('hitl-audit-model-provider')?.value || '',
|
||||
@@ -3287,6 +3296,15 @@ function initModelListControls() {
|
||||
hitlAuditProv.dataset.modelListBound = '1';
|
||||
hitlAuditProv.addEventListener('change', syncModelListFetchButtons);
|
||||
}
|
||||
const hitlAuditBackend = document.getElementById('hitl-audit-backend');
|
||||
if (hitlAuditBackend && !hitlAuditBackend.dataset.backendBound) {
|
||||
hitlAuditBackend.dataset.backendBound = '1';
|
||||
hitlAuditBackend.addEventListener('change', function () {
|
||||
syncHitlAuditBackendUI();
|
||||
syncModelListFetchButtons();
|
||||
});
|
||||
syncHitlAuditBackendUI();
|
||||
}
|
||||
const knowledgeEmbeddingProv = document.getElementById('knowledge-embedding-provider');
|
||||
if (knowledgeEmbeddingProv && !knowledgeEmbeddingProv.dataset.modelListBound) {
|
||||
knowledgeEmbeddingProv.dataset.modelListBound = '1';
|
||||
@@ -3638,6 +3656,48 @@ async function testVisionConnection() {
|
||||
}
|
||||
}
|
||||
|
||||
function isHitlAuditTypeSafe() {
|
||||
const v = (document.getElementById('hitl-audit-backend')?.value || '').trim().toLowerCase();
|
||||
return v === 'typesafe' || v === 'jev';
|
||||
}
|
||||
|
||||
function syncHitlAuditBackendUI() {
|
||||
const ts = isHitlAuditTypeSafe();
|
||||
const providerGroup = document.getElementById('hitl-audit-openai-provider-group');
|
||||
if (providerGroup) providerGroup.style.display = ts ? 'none' : '';
|
||||
const fetchBtn = document.getElementById('fetch-hitl-audit-models-btn');
|
||||
if (fetchBtn) fetchBtn.style.display = ts ? 'none' : '';
|
||||
const openaiHint = document.getElementById('hitl-audit-model-openai-hint');
|
||||
const tsHint = document.getElementById('hitl-audit-model-typesafe-hint');
|
||||
if (openaiHint) openaiHint.hidden = ts;
|
||||
if (tsHint) tsHint.hidden = !ts;
|
||||
const promptHint = document.getElementById('hitl-audit-prompt-typesafe-hint');
|
||||
if (promptHint) promptHint.hidden = !ts;
|
||||
|
||||
const tFn = function (key, fallback) {
|
||||
return typeof settingsT === 'function' ? settingsT(key, fallback) : (fallback || key);
|
||||
};
|
||||
const baseUrlEl = document.getElementById('hitl-audit-model-base-url');
|
||||
const apiKeyEl = document.getElementById('hitl-audit-model-api-key');
|
||||
const modelEl = document.getElementById('hitl-audit-model-name');
|
||||
if (baseUrlEl) {
|
||||
baseUrlEl.placeholder = ts
|
||||
? tFn('settings.hitl.auditModelTypeSafeBaseUrlPlaceholder', '留空使用 https://api.typesafe.ai')
|
||||
: tFn('settings.hitl.auditModelBaseUrlPlaceholder', '留空则复用主模型 Base URL');
|
||||
}
|
||||
if (apiKeyEl) {
|
||||
apiKeyEl.placeholder = ts
|
||||
? tFn('settings.hitl.auditModelTypeSafeApiKeyPlaceholder', 'TypeSafe API Key(必填,不复用主模型)')
|
||||
: tFn('settings.hitl.auditModelApiKeyPlaceholder', '留空则复用主模型 API Key');
|
||||
}
|
||||
if (modelEl) {
|
||||
modelEl.placeholder = ts
|
||||
? tFn('settings.hitl.auditModelTypeSafeNamePlaceholder', '留空使用 jev-latest')
|
||||
: tFn('settings.hitl.auditModelNamePlaceholder', '留空则复用主模型;建议填写小模型');
|
||||
}
|
||||
}
|
||||
window.syncHitlAuditBackendUI = syncHitlAuditBackendUI;
|
||||
|
||||
function collectHitlAuditModelEffectiveConfig() {
|
||||
const main = {
|
||||
provider: document.getElementById('openai-provider')?.value || 'openai',
|
||||
@@ -3656,9 +3716,29 @@ function collectHitlAuditModelEffectiveConfig() {
|
||||
async function testHitlAuditModelConnection() {
|
||||
const btn = document.getElementById('test-hitl-audit-model-btn');
|
||||
const resultEl = document.getElementById('test-hitl-audit-model-result');
|
||||
const typeSafe = isHitlAuditTypeSafe();
|
||||
const cfg = collectHitlAuditModelEffectiveConfig();
|
||||
const apiKey = typeSafe
|
||||
? (document.getElementById('hitl-audit-model-api-key')?.value.trim() || '')
|
||||
: cfg.api_key;
|
||||
const baseUrl = typeSafe
|
||||
? (document.getElementById('hitl-audit-model-base-url')?.value.trim() || '')
|
||||
: cfg.base_url;
|
||||
const model = typeSafe
|
||||
? (document.getElementById('hitl-audit-model-name')?.value.trim() || 'jev-latest')
|
||||
: cfg.model;
|
||||
|
||||
if (!cfg.base_url || !cfg.api_key || !cfg.model) {
|
||||
if (typeSafe) {
|
||||
if (!apiKey) {
|
||||
if (resultEl) {
|
||||
resultEl.style.color = 'var(--danger-color, #e53e3e)';
|
||||
resultEl.textContent = typeof settingsT === 'function'
|
||||
? settingsT('settings.hitl.testTypeSafeFillRequired', '请先填写 TypeSafe API Key')
|
||||
: '请先填写 TypeSafe API Key';
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (!cfg.base_url || !cfg.api_key || !cfg.model) {
|
||||
if (resultEl) {
|
||||
resultEl.style.color = 'var(--danger-color, #e53e3e)';
|
||||
resultEl.textContent = typeof window.t === 'function' ? window.t('settingsBasic.testFillRequired') : '请先填写 Base URL、API Key 和模型';
|
||||
@@ -3676,10 +3756,14 @@ async function testHitlAuditModelConnection() {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await apiFetch('/api/config/test-openai', {
|
||||
const endpoint = typeSafe ? '/api/config/test-typesafe' : '/api/config/test-openai';
|
||||
const payload = typeSafe
|
||||
? { base_url: baseUrl, api_key: apiKey, model: model }
|
||||
: cfg;
|
||||
const response = await apiFetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(cfg)
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
const result = await response.json();
|
||||
|
||||
|
||||
Reference in new issue
Block a user