168、【Agent】【OpenCode】TuiThreadCmd(SSE)
【声明】本博客所有内容均为个人业余时间创作所述技术案例均来自公开开源项目如GithubApache基金会不涉及任何企业机密或未公开技术如有侵权请联系删除标题168、【Agent】【OpenCode】TuiThreadCmdSSE背景上篇 blog【Agent】【OpenCode】TuiThreadCmdEvenSource分析了 Headers 是一个特殊的浏览器/Node.js 内置对象它不能直接被 JSON 序列化所以必须先把它“拆”成普通的{ key: value }对象才能通过 RPC 发送因为 Headers 把数据存在了内部私有槽位里而不是挂在可枚举的属性上。JSON 序列化器只能看到对象的自有可枚举属性所以什么都读不到而.entries()是 Headers 提供的标准读取接口能正确访问到内部存储的数据再由Object.fromEntries()把迭代器里的每一对[key, value]重新组装成一个纯普通对象接着分析了基于 RPC 通道的“伪 EventSource”对象它和上一个createWorkerFetch是同一套设计思路对外暴露熟悉的 API对内走 RPC 通道。但这次适配的不是 HTTP 请求而是服务端推送事件下面继续分析OpenCode上篇 blog 提到了 SSE 的概念下面澄清下SSE Server-Sent Events服务器发送事件它是浏览器原生提供的一种 “服务端向客户端单向推送数据” 的标准协议。用最简单的类比理解通信方式类比方向普通 HTTP打电话问老师问题老师回答后挂断一问一答WebSocket和老师接通电话双方可以随时说话双向实时SSE老师打开广播频道只能听不能说话服务端 → 客户端 单向推送SSE 就是那个“广播频道”服务端持续往客户端推数据客户端只需要监听不需要反复发请求。浏览器里怎么用// 浏览器原生 API就这么简单constsourcenewEventSource(/api/events)// 此 EventSource 非 opencode EvenSource方法不一样source.onmessage(event){console.log(收到推送:,event.data)}source.onerror(err){console.log(连接出错浏览器会自动重连)}浏览器会自动建立一个 HTTP 长连接服务端返回的响应头是 Content-Type: text/event-stream然后数据就像水流一样持续推过来。SSE 的数据格式服务端推送的内容是纯文本格式非常简单data:{user:alice,action:login}data:{user:bob,action:upload}event:notificationdata:{title:新消息,body:你好}每条消息以data:开头空行表示一条消息结束可选的event:字段区分消息类型SSE vs WebSocketSSEWebSocket方向单向服务端→客户端双向协议普通 HTTP独立协议 (ws://)自动重连✅ 浏览器内置❌ 需自己实现数据格式纯文本文本或二进制复杂度极低较高适用场景通知推送、实时日志、AI 流式输出聊天室、游戏、协作编辑为什么 AI 对话都用 SSEChatGPT 等产品的“打字机效果”就是 SSE模型生成一个 token服务端就通过 SSE 推一个 token前端逐字渲染。不需要双向通信SSE 比 WebSocket 简单得多。回到代码functioncreateEventSource(client:RpcClient):EventSource{return{on:(handler)client.onEvent(event,handler),// ...}}这里做的事情就是把原本应该走 HTTP SSE 长连接的推送替换成了走 RPC 通道的事件订阅。原来浏览器new EventSource(url)→ HTTP 长连接 → 服务端推 SSE 文本流现在client.on(event, handler)→ RPC 通道WebSocket/IPC→ 服务端推结构化事件对象调用handler通知好处是不需要额外维护一个 SSE 端点所有通信都走同一个 RPC 通道代价是失去了浏览器原生的自动重连等能力需要自己在 RpcClient 里实现。另外这里的 “event” 就是一个硬编码的字符串字面量。这意味着所有 handler 都绑定在同一个通道上无论注册多少次on(handler)底层都是在执行client.on(event, handler)。所有的回调函数都被注册到了 RPC Client 内部名为 “event” 的这唯一一个事件监听器列表中。服务端推送时没有区分度当服务端通过 RPC 发送消息时它只能发类似这样的结构client.emit(event,payload)它无法直接指定“这条消息只给某个特定的 handler”。RPC Client 收到 “event” 消息后会广播式地触发所有注册在该通道上的 handler。那如何区分不同类型的事件既然通道只有一个事件的分类逻辑就下沉到了 payload 内部。通常 Event 类型会长这样interfaceEvent{type:workspaceChanged|fileUpdated|notificationdata:unknown}客户端消费方需要在自己的 handler 里做二次分发eventSource.on((event){if(event.typefileUpdated){handleFileUpdate(event.data)}elseif(event.typenotification){showNotification(event.data)}})为什么这么设计这是一种 “单通道 消息自描述” 的模式好处是RPC 接口极简服务端只需要暴露一个emit(event, ...)方法不用为每种事件定义单独的 RPC 消息名统一中间件可以在 “event” 这一个点上统一做日志、鉴权、序列化等处理与 SSE 语义对齐原生 SSE 本质上也是一个 HTTP 连接上的单一文本流所有事件都走同一个管道靠event: type字段区分类型。这个设计是对 SSE 模型的忠实映射⚠️潜在风险如果业务事件种类很多、频率很高所有 handler 都会被频繁触发然后各自过滤存在一定的性能开销。当事件量大到成为瓶颈时就需要拆分为多个命名通道如client.on(fileUpdated, ...)但在那之前单通道模式是更简单、更合理的选择OK本篇先到这里如有疑问欢迎评论区留言讨论祝各位功力大涨技术更上一层楼更多内容见下篇 blog【Agent】【OpenCode】TuiThreadCmdworkspaceworker路径

相关新闻

C语言-循环嵌套、goto与数组入门

C语言-循环嵌套、goto与数组入门

前言 今天学的是 C 语言 Day05:循环嵌套、goto 语句和数组入门。前面已经掌握了三种循环,今天主要看循环怎么嵌套、跳转语句怎么用,以及数组这个“容器”怎么创建。 本篇文章要解决三个问题: 循环嵌套的执行顺序和次数怎么算&am…

2026/10/7 5:44:57 阅读更多 →
Unity小游戏架构选型:MVC与MVVM的实战抉择与避坑指南

Unity小游戏架构选型:MVC与MVVM的实战抉择与避坑指南

1. 项目概述:架构选择,小游戏开发中的“生存智慧”在Unity里做小游戏,尤其是独立开发者或者小团队,最怕什么?不是技术实现不了,而是项目做着做着,代码就变成了一团乱麻,加个新功能像…

2026/10/3 2:08:43 阅读更多 →
MSVC命令行编译C++程序:从环境配置到构建自动化

MSVC命令行编译C++程序:从环境配置到构建自动化

1. 项目概述:为什么需要从命令行使用MSVC?很多刚开始接触C的朋友,第一个接触的开发环境往往是Visual Studio那个庞大的IDE。点一下绿色的三角按钮,程序就跑起来了,一切看起来都很美好。但时间久了,你可能会…

2026/10/1 15:43:25 阅读更多 →

最新新闻

LeetCode 437 路径总和 III:从暴力解到前缀和优化的完整思路

LeetCode 437 路径总和 III:从暴力解到前缀和优化的完整思路

Day 16 的刷题计划轮到 LeetCode 437 路径总和 III。说实话,刚开始我有点轻敌:前面刚把路径总和 I、II 都过了一遍,觉得二叉树路径问题无非就是递归套递归,用 JavaScript 写起来也不会难到哪里去。等我真正动手才发现,…

2026/10/9 4:04:31 阅读更多 →
Java Servlet图书管理系统:零框架部署与课设实战指南

Java Servlet图书管理系统:零框架部署与课设实战指南

简介:这是一份面向计算机专业本科生的Java课程设计与期末大作业实战资源,基于B/S架构实现功能完整的图书管理系统,帮助学习者掌握JDBC连接MySQL、ServletJSP前后端交互、MVC分层开发等核心技能。资源包共93个文件,包含40个Java业务…

2026/10/9 4:04:31 阅读更多 →
红黑树学习笔记:从规则、旋转变色到插入删除实操

红黑树学习笔记:从规则、旋转变色到插入删除实操

红黑树大概是数据结构里退学率最高的一章,没有之一。链表、栈、队列这些结构,说白了就是换种方式组织数据,看两遍代码基本能上手。但红黑树不一样,它天生带着一堆规则、旋转、变色、再平衡,哪怕你对着博客把插入的六种…

2026/10/9 4:04:31 阅读更多 →
栈上变量覆写:一道CTF入门题的PWN解题全流程

栈上变量覆写:一道CTF入门题的PWN解题全流程

不用多说,直接进正题。今天要拆的这道题是HappyNewYearCTF系列里的第三题,题目全名叫“栈上变量覆写2”。一看到这个名字,基本就能猜个大概:又是栈上变量被覆写的路子,而且这题带个“2”,说明同系列里还有一…

2026/10/9 4:04:31 阅读更多 →
Spring Boot 3 接入 AI 生图:异步管道与防刷限流架构实践

Spring Boot 3 接入 AI 生图:异步管道与防刷限流架构实践

做 AI 应用的朋友应该都有体会:同一张图,老手能生成得又快又稳,新手可能连接口都调不明白,或者好不容易调通了,一上线就被刷爆了配额。这段时间我正好把一个 AI 生图功能从零接入到一个 Spring Boot 3 的现有后端里&am…

2026/10/9 4:04:31 阅读更多 →
4G显存也能流畅跑大模型:llama.cpp与GGUF量化实战指南

4G显存也能流畅跑大模型:llama.cpp与GGUF量化实战指南

如果你的电脑还在用 4GB 显存的显卡,比如 GTX 1650、RTX 3050 Laptop 或者 AMD 那边的 RX 6500 XT,想跑本地大模型,第一反应可能是到处找精简版、量化版,或者干脆放弃转用云 API。但今天我直接说结论:4G 显存完全能跑&…

2026/10/9 4:03:31 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →