Version: 0.9.27.dev.260418

后端:
1. SSE 心跳保活——解决 Vite dev proxy 在 LLM thinking 静默期判 idle 断连
- api/agent.go:ChatAgent 新增 5 秒 heartbeat ticker,select 增加 heartbeat.C 分支,每 5 秒写入 SSE 注释行 : ping\n\n 并 Flush
- service/agentsvc/agent_newagent.go:graph 执行失败时增加 context.Canceled / requestCtx.Err() 判断,客户端断连只记 warn 不推 errChan 也不跑 fallback,消除 "错误通道已满" 日志噪音
2. 随口记工具(quick_note_create)接入新 Agent 链路
- agent/node/quicknote.go:parseOptionalDeadlineWithNow / quickNoteLocation 首字母大写导出,供新链路复用旧链路成熟的时间解析和时区能力
- agent/node/quicknote_tool.go:parseOptionalDeadline / quickNoteLocation 同步导出,补充调用目的注释
- newAgent/tools/quicknote.go:新增 QuickNoteToolHandler,实现新链路 quick_note_create 工具的参数校验、时间解析、写库调用
- newAgent/tools/registry.go:DefaultRegistryDeps 新增 QuickNote 字段;新增 RequiresScheduleState 方法和 scheduleFreeTools 集合;注册 quick_note_create 工具(不加入 writeTools,不走 confirm 确认)
- cmd/start.go:NewDefaultRegistryWithDeps 注入 QuickNote.CreateTask 闭包,捕获 taskRepo 实例写库
3. Execute 节点随口记 speak 清空 + 非 ScheduleState 工具支持
- newAgent/node/execute.go:新增非写工具 confirm→continue 自动降级逻辑;新增 quick_note_create speak 强制清空,收口统一交给 deliver,避免 execute + deliver 重复废话
- newAgent/node/execute.go:executeToolCall / executePendingTool 中 scheduleState nil 检查改为仅拦截 RequiresScheduleState 的工具;为不依赖 ScheduleState 的工具自动注入 _user_id 参数
- newAgent/prompt/execute.go:有 plan / ReAct 两套系统 prompt 中,"写操作"规则细化为"日程写操作";新增 quick_note_create 专属执行规则:speak 必须留空,收口由 deliver 完成,调用成功后可 continue 处理多任务
- newAgent/prompt/chat.go:execute 路由描述补充"记录任务/提醒"场景

前端:
1. Vite dev proxy SSE 透传配置
- vite.config.ts:/api 代理新增 configure 回调,设置 x-accel-buffering: no 和 cache-control: no-cache,禁用代理缓冲
2.SSE 流式处理修复
- AssistantPanel.vue:reasoning_content 守卫放宽,移除 !assistantMessage.content.trim() 外层条件,正文回流后仍允许追加 reasoning(工具调用摘要、阶段状态等),不再吞掉 execute/deliver 的 reasoning_content
- AssistantPanel.vue:流式完成后跳过 loadConversationMessages,避免 persistVisibleMessage 尚未落库时 merge 产生重复或丢失

仓库:无
This commit is contained in:
Losita
2026-04-18 11:20:49 +08:00
parent d8280cc647
commit 4fbf9397d2
13 changed files with 549 additions and 1416 deletions

View File

@@ -1223,12 +1223,15 @@ function processSseBlock(block: string, assistantMessage: AssistantMessage) {
if (
typeof delta?.reasoning_content === 'string' &&
delta.reasoning_content &&
!assistantMessage.content.trim()
delta.reasoning_content
) {
markReasoningStart(assistantMessage)
// 正文回流后仍允许追加 reasoning工具调用摘要、阶段状态等
// 但不再切换面板状态,避免 UI 闪烁。
if (!assistantMessage.content.trim()) {
markReasoningStart(assistantMessage)
thinkingMessageMap[assistantMessage.id] = true
}
assistantMessage.reasoning = `${assistantMessage.reasoning || ''}${delta.reasoning_content}`
thinkingMessageMap[assistantMessage.id] = true
}
if (typeof delta?.content === 'string' && delta.content) {
@@ -1377,8 +1380,10 @@ async function sendMessage(preset?: string) {
if (planningTaskClassIdsForRequest.length > 0) {
pendingPlanningTaskClassIds.value = []
}
// 流式成功后不重新加载历史:流式数据就是当前会话的权威来源,
// 过早 reload 会因 persistVisibleMessage 尚未落库导致 merge 产生重复/丢失。
// 历史数据在下次切换会话或刷新页面时自然加载。
await Promise.allSettled([
loadConversationMessages(actualConversationId, true),
loadConversationContextStats(actualConversationId, true),
])
} catch (error) {

View File

@@ -19,6 +19,14 @@ export default defineConfig({
'/api': {
target: 'http://127.0.0.1:8080',
changeOrigin: true,
// SSE 流必须禁用缓冲,否则 Vite proxy 会攒满 buffer 再转发,
// 导致前端长时间收不到数据被判定为连接中断。
configure: (proxy) => {
proxy.on('proxyRes', (proxyRes) => {
proxyRes.headers['x-accel-buffering'] = 'no'
proxyRes.headers['cache-control'] = 'no-cache'
})
},
},
},
},