重构: AI流式断线保文StreamResult三分支+重试对齐决策a1,推进链落df-nodes
This commit is contained in:
@@ -619,11 +619,11 @@ onMounted(() => {
|
||||
.detail-section { padding-bottom: 18px; margin-bottom: 18px; border-bottom: 0.5px solid var(--df-border); }
|
||||
.detail-section:last-child { border-bottom: none; margin-bottom: 0; }
|
||||
|
||||
.detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
|
||||
.detail-title-row { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
|
||||
.detail-kind-icon { font-size: 20px; }
|
||||
.detail-title { font-size: 18px; font-weight: 500; color: var(--df-text); word-break: break-word; }
|
||||
.detail-actions { display: flex; gap: 6px; flex-shrink: 0; }
|
||||
.detail-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 12px; min-width: 0; }
|
||||
.detail-title-row { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; overflow: hidden; }
|
||||
.detail-kind-icon { font-size: 20px; flex-shrink: 0; }
|
||||
.detail-title { font-size: 18px; font-weight: 500; color: var(--df-text); word-break: break-word; overflow-wrap: break-word; min-width: 0; }
|
||||
.detail-actions { display: flex; gap: 6px; flex-shrink: 0; flex-wrap: wrap; }
|
||||
|
||||
.detail-badges { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; font-size: 11px; }
|
||||
.badge-plain { color: var(--df-text-dim); }
|
||||
@@ -725,9 +725,11 @@ onMounted(() => {
|
||||
.form-textarea { min-height: 80px; resize: vertical; font-family: inherit; }
|
||||
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
|
||||
|
||||
/* ===== 响应式:窄屏详情标题防竖线化(B-260616-19) ===== */
|
||||
/* ===== 响应式:窄屏详情标题防竖线化(B-260619) ===== */
|
||||
@media (max-width: 760px) {
|
||||
.kn-layout { grid-template-columns: 1fr; }
|
||||
.detail-head { flex-direction: column; align-items: flex-start; }
|
||||
.detail-actions { width: 100%; }
|
||||
.detail-title { font-size: 15px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -277,6 +277,17 @@
|
||||
@change="syncAgentMaxIterations" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-row">
|
||||
<div class="setting-info">
|
||||
<span class="setting-label">{{ $t('settings.labelAgentMaxRetries') }}</span>
|
||||
<span class="setting-desc">{{ $t('settings.descAgentMaxRetries') }}</span>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<input type="number" class="setting-select" min="0" max="10" style="width:80px"
|
||||
v-model.number="settings.agentMaxRetries"
|
||||
@change="syncAgentMaxRetries" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -626,6 +637,8 @@ const settings = reactive({
|
||||
llmPerConvConcurrency: appSettings.get<number>('df-llm-per-conv-concurrency', 2),
|
||||
// F-260616-01: Agentic 循环最大轮次,默认 10(与后端 DEFAULT_MAX_AGENT_ITERATIONS 对齐)
|
||||
agentMaxIterations: appSettings.get<number>('df-ai-agent-max-iterations', 10),
|
||||
// F-260616-07: 流式失败重试次数,默认 3(与后端 DEFAULT_MAX_AGENT_RETRIES 对齐)
|
||||
agentMaxRetries: appSettings.get<number>('df-ai-agent-max-retries', 3),
|
||||
})
|
||||
|
||||
function applyTheme(theme: string) {
|
||||
@@ -664,6 +677,10 @@ watch(() => settings.agentMaxIterations, (v) => {
|
||||
void appSettings.set('df-ai-agent-max-iterations', v)
|
||||
})
|
||||
|
||||
watch(() => settings.agentMaxRetries, (v) => {
|
||||
void appSettings.set('df-ai-agent-max-retries', v)
|
||||
})
|
||||
|
||||
// 同步 LLM 并发上限到后端(debounce 300ms,防快速连续调整时频繁 IPC)
|
||||
// 持久化已由上方 watch 写 appSettings(SQLite) 完成;此处只负责同步内存限流器
|
||||
let _concurrencyTimer: ReturnType<typeof setTimeout> | null = null
|
||||
@@ -704,6 +721,23 @@ function syncAgentMaxIterations() {
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// 同步流式失败重试次数到后端(debounce 300ms)
|
||||
// F-260616-07: 后端 loop 入口 load 快照锁定边界——热改后当前 loop 不受影响,
|
||||
// 下次发消息才生效。双 clamp:此处 0-10 + 后端 command 再 clamp 0-10
|
||||
let _agentRetryTimer: ReturnType<typeof setTimeout> | null = null
|
||||
function syncAgentMaxRetries() {
|
||||
// clamp 0-10,防越界
|
||||
settings.agentMaxRetries = Math.min(10, Math.max(0, settings.agentMaxRetries ?? 3))
|
||||
if (_agentRetryTimer) clearTimeout(_agentRetryTimer)
|
||||
_agentRetryTimer = setTimeout(async () => {
|
||||
try {
|
||||
await aiApi.setAgentMaxRetries(settings.agentMaxRetries)
|
||||
} catch (e) {
|
||||
console.error('同步流式重试次数失败:', e)
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
watch(() => settings.language, (val) => {
|
||||
void appSettings.set('df-language', val)
|
||||
// 同步 i18n 实例,让界面立即跟随语言切换
|
||||
@@ -772,12 +806,15 @@ onMounted(() => {
|
||||
syncConcurrencyConfig()
|
||||
// F-260616-01: 启动同步一次 Agentic 最大轮次(防刷新页面后后端未恢复用户设定值)
|
||||
syncAgentMaxIterations()
|
||||
// F-260616-07: 启动同步一次流式失败重试次数(防刷新页面后后端未恢复用户设定值)
|
||||
syncAgentMaxRetries()
|
||||
})
|
||||
|
||||
// 组件卸载清全部 debounce timer,防 unmount 后旧 timer 仍 fire 写已销毁 reactive(timer 泄漏 FR-C3)
|
||||
onUnmounted(() => {
|
||||
if (_concurrencyTimer) clearTimeout(_concurrencyTimer)
|
||||
if (_agentIterTimer) clearTimeout(_agentIterTimer)
|
||||
if (_agentRetryTimer) clearTimeout(_agentRetryTimer)
|
||||
if (_knowledgeSaveTimer) clearTimeout(_knowledgeSaveTimer)
|
||||
if (_toastTimer) clearTimeout(_toastTimer)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user