Hermes StudioEkko Studio移动端日历/提醒「单条确认删除」契约详解精确身份校验、deletedtrue 回报与有界确认期限【免费下载链接】ekko-studioEkko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web.项目地址: https://gitcode.com/gh_mirrors/he/ekko-studio本文围绕 Hermes StudioEkko Studio在 2026-09-05 引入的Confirmed single-item mobile deletion单条目移动端确认删除变更记录展开讲解其直接聊天会话中删除日历事件与提醒Reminder时强制的三条核心契约删除请求必须携带精确的 id、title 与发生时间App 回报必须显式声明deletedtrue且 id 完全匹配并且全程受一次性 App 确认与有界截止时间的约束。读完本文你将掌握该删除能力在服务端请求规范化、响应净化、Socket 事件流转与超时边界上的完整实现以及如何在测试与 OpenAPI 文档中印证这套契约。背景移动日历能力从「只读写」到「确认删除」的演进该变更记录建立在 docs/chat-chain-changes/2026-09-04-mobile-calendar-reminders.md 所描述的移动日历/提醒能力之上。基线版本2026-09-04 及 PR #2892 集成规定MCP 工具hermes_studio_use_mobile_calendar与hermes_studio_use_mobile_reminders服务端端点POST /api/studio/mobile-calendar/request日历事件支持 list、create、update提醒支持 list、create、update、complete删除、后台访问、工作流/群聊/委派使用、跨会话持久化均不支持每个请求都绑定到已认证 profile 与精确的直接聊天会话App 返回结果在交给 MCP 调用方之前会经过允许清单allowlist净化。2026-09-05 的变更记录 docs/chat-chain-changes/2026-09-05-confirmed-mobile-delete.md 在此基线上只新增了「单条目确认删除」并用一句话概括其影响Delete results must match the requested id and explicitly reportdeletedtrue. No list/batch/series deletion, profile scope or background access expansion. Requires the matching App update; older Apps do not support delete.即只删除单条、只允许精确匹配、必须显式回报删除结果且不扩展任何删除范围列表、批量、系列、profile 范围、后台。这既是安全边界的定义也是本文后续所有源码细节的契约来源。核心契约一删除请求必须携带精确身份exact id title 发生时间删除动作的服务端入口是请求规范化函数normalizeMobileCalendarRequest其核心分支位于 mobile-calendar.ts。cleanItem在action delete时执行严格的字段校验if (action delete) { if (typeof value.id ! string || !value.id.trim() || value.id.length 512) return null if (typeof value.title ! string || !value.title.trim() || value.title.length 500) return null // Require the exact listed occurrence; never invent a time for deletion. const start capability calendar ? value.start_ms : value.due_ms if (capability calendar (typeof start ! number || !Number.isFinite(start) || start MIN_TIME_MS)) return null if (capability reminder start ! null (typeof start ! number || !Number.isFinite(start))) return null return { id: value.id.trim(), title: value.title.trim(), ...(start ! null ? { [capability calendar ? start_ms : due_ms]: start } : {}) } }具体规则可归纳为下表字段校验规则说明id必须是字符串、去空格后非空、长度 ≤ 512缺失、数字、数组均直接判无效title必须是字符串、去空格后非空、长度 ≤ 500与 id 共同构成「精确身份」start_ms日历必须是有限数字且 ≥MIN_TIME_MSDate.UTC(2001, 0, 1)必须携带服务端绝不替删除操作凭空推断发生时间due_ms提醒可选若提供则必须是有限数字提醒允许不携带时间提醒本身可能无截止时间deleteAll/ 批量标记会被剥离不进入透传字段杜绝删除整个系列MIN_TIME_MS定义在 mobile-calendar.ts服务端通过它挡住非法的时间戳输入。这些规则在 mobile-calendar-delete.test.ts 中有逐条测试佐证it.each([calendar, reminder])(requires exact identity for %s, capability { const base { capability, action: delete, purpose: Delete the selected test item } for (const item of [{}, { title: test }, { id: [1], title: test }, { id: 1 }]) { expect(() request({ ...base, item })).toThrow() } const value request({ ...base, item: { id: 1, title: test, start_ms: 1788624000000, due_ms: 1788624000000, deleteAll: true } }) expect(value.item).not.toHaveProperty(deleteAll) ... })测试表明空 item、缺 id、id 为数组、缺 title 的请求一律抛错而携带deleteAll: true的合法请求在规范化后会被剥离该字段——这正是「不支持批量/系列删除」在数据层的落点。核心契约二删除回报必须显式声明deletedtrue且 id 完全匹配请求侧校验只是第一步响应侧同样严格。normalizeMobileCalendarResponse的删除分支位于 mobile-calendar.tsif (expected.action delete) { if (!isRecord(value.result.item) || value.result.item.id ! expected.item?.id || value.result.item.deleted ! true) return null return { status: success, result: { capability: expected.capability, action: delete, item: { id: expected.item?.id, deleted: true } } } }三条硬性条件缺一不可result.item必须是一个对象result.item.id必须严格等于请求中的 id!比较不允许模糊匹配result.item.deleted必须严格等于true仅「存在」不够必须显式声明。任何一条不满足整个响应都会被判为无效返回null调用方随后以calendar_invalid_request错误码收尾。这一点在 mobile-calendar-delete.test.ts 中有完整的行为矩阵响应场景期望结果{ item: { id: 1, deleted: true } }id 匹配、deletedtrue多余字段被净化成功且仅保留{ id: 1, deleted: true }{ item: { id: other, deleted: true } }id 不匹配判无效返回null{}缺少 item判无效返回nullstatus: denied原样透传{ status: denied }此外即使响应通过校验结果字段也会经过cleanResultItem的允许清单净化mobile-calendar.ts只保留id、title、notes、location与startMs、endMs、dueMs、priority、reminderMinutes、allDay、completed等已知字段任何private、secret之类的附加字段都会被丢弃。这与基线文档「App responses are allowlisted and sanitized」一脉相承删除场景也不例外。错误码集合ERROR_CODES定义在 mobile-calendar.tscalendar_permission_denied、calendar_unavailable、calendar_item_not_found、calendar_invalid_request、calendar_failed。未知错误码会被统一映射为calendar_failed避免把 App 内部细节泄露给模型侧。核心契约三一次性 App 确认与有界截止时间删除不是「请求即执行」而是经由 Socket 事件把请求投递给目标移动设备等待用户当场确认并在有界期限内完成。完整链路位于 chat-run.ts前置守卫L574-L588会话必须存在、profile 必须匹配、session.source必须是直接聊天group_chat/workflow直接抛错Mobile calendar and reminders are available only in direct chats同一会话不允许存在未决的重复请求目标设备必须已注册mobileRunTargets且在线设备房间非空。发出请求事件L599-L621生成requestIdUUID向设备房间发出calendar.requested/reminder.requested负载包含calendar_request_id/reminder_request_id、完整请求体、target_device_id、target_user_id、target_profile、timeout_ms与expires_at_ms。等待 App 回报L1366-L1419App 通过calendar.respond/reminder.respond回传服务端校验会话访问权、请求仍处于 pending、sameMobileDevice目标设备一致再经normalizeMobileCalendarResponse规范化。收尾L2921-L2941finishMobileCalendarRequest移除 pending、清理定时器与事件状态向会话广播calendar.resolved/reminder.resolved并把结果附device_idresolve 给 REST 调用方。有界截止时间由boundedMobileCalendarTimeout实现chat-run.tsconst MOBILE_CALENDAR_MIN_TIMEOUT_MS 3_000 const MOBILE_CALENDAR_MAX_TIMEOUT_MS 300_000 const MOBILE_CALENDAR_DEFAULT_TIMEOUT_MS 300_000 function boundedMobileCalendarTimeout(value: unknown): number { const numeric Number(value) if (value null || !Number.isFinite(numeric) || numeric 0) return MOBILE_CALENDAR_DEFAULT_TIMEOUT_MS return Math.max(MOBILE_CALENDAR_MIN_TIMEOUT_MS, Math.min(MOBILE_CALENDAR_MAX_TIMEOUT_MS, numeric)) }即调用方可传timeout_ms但服务端会把其钳制在 3 秒到 300 秒5 分钟之间缺省即为 300 秒到期后未收到有效回报请求以calendar_failed结束。Socket 层同步把expires_at_ms: Date.now() timeoutMs下发给 App确保「确认卡片」与服务端 deadline 对齐。相关行为由 run-chat-mobile-calendar.test.ts 覆盖收到denied时立即以{ status: denied }结束vi.advanceTimersByTimeAsync(3001)推进 3001ms 后未决请求以status: error结束且 pending 表清空对undefined、null、0、600000、300000五种输入最终timeout_ms均为300000钳制与默认值生效过期后才到达的reminder.respond会被忽略pending 已清空finishMobileCalendarRequest返回false——这正是「fresh App confirmation」的服务端保证。调用入口REST 端点与请求参数删除能力通过既有的POST /api/studio/mobile-calendar/request端点暴露路由注册于 chat-run.ts控制器实现位于 chat-run.ts。请求必须携带 Bearer 认证控制器提取session_id、capability、action、purpose、start_ms、end_ms、include_completed、limit、item、timeout_ms后转交ChatRunSocket.requestMobileCalendarSession not found返回 404其余参数问题返回 400服务不可用时返回 503。openapi.json 给出了该端点的完整契约其中与删除直接相关的字段字段类型约束说明session_idstring必填精确的直接聊天会话 idcapabilitystringcalendar/reminder目标能力actionstringlist/create/update/complete/delete删除即deletepurposestring必填maxLength 240请求目的说明itemobject删除时须含精确id、title日历另须start_ms被删条目的精确身份timeout_msinteger3000 ~ 300000默认 300000确认期限有界一个典型的删除日历事件请求示例curl -X POST http://server/api/studio/mobile-calendar/request \ -H Authorization: Bearer token \ -H Content-Type: application/json \ -d { session_id: session-abc123, capability: calendar, action: delete, purpose: 删除用户选定的那条测试日历事件, item: { id: evt-42, title: Project sync, start_ms: 1788624000000 }, timeout_ms: 60000 }成功响应形如{ ok: true, session_id: session-abc123, device_id: iphone, status: success, result: { capability: calendar, action: delete, item: { id: evt-42, deleted: true } } }若用户在 App 上拒绝则返回{ status: denied }若回报的 id 不匹配或未声明deleted: true则会以{ status: error, error: { code: calendar_invalid_request } }结束。边界与不变量删除能力刻意不做的事该变更记录明确「No list/batch/series deletion, profile scope or background access expansion」这些限制在源码中有多处强制不做批量/系列删除请求侧剥离deleteAll响应侧要求单条id完全匹配注入到模型上下文的运行指令进一步约束chat-run.tsDelete only the exact listed item after fresh App confirmation; never delete a whole recurring series.不做后台访问指令明确禁止在委派子任务、工作流节点或后台跟踪中使用移动工具requestMobileCalendar的前置守卫也拒绝group_chat/workflow来源的会话。不做 profile 范围扩展请求绑定到ctx.state.profilegetSession校验会话 profile 必须与请求 profile 一致chat-run.ts。不做跨设备/跨会话漂移回报必须来自sameMobileDevice的目标设备chat-run.ts非目标设备的响应一律拒绝calendar.requested事件也只投递到目标设备房间。App 兼容性记录明确「Requires the matching App update; older Apps do not support delete」——即旧版本 App 即便收到delete请求也无法正确回报服务端不会为其提供降级路径。测试验证矩阵如何证明删除契约成立删除契约的自动化验证分布在两个测试文件中mobile-calendar-delete.test.ts纯函数级契约测试直接驱动normalizeMobileCalendarRequest/normalizeMobileCalendarResponse覆盖精确身份校验、deleteAll剥离、日历删除必须携带start_msundefined、null、NaN、tomorrow全部抛错、响应 id 匹配与deletedtrue回报。run-chat-mobile-calendar.test.tsSocket 级集成测试验证完整事件流——reminder.requested负载含expires_at_ms、Appdenied回报即时结束、超时3001ms后以error结束并清空 pending、五种timeout_ms输入统一钳制为 300000、非目标设备与过期回报均被拒绝、列表响应中的secret字段被净化丢弃。结语与延伸阅读「Confirmed single-item mobile deletion」是 Hermes Studio 移动能力中一个极具代表性的安全设计样本把破坏性操作压缩到最小范围单条、要求最大确定性精确 id title 发生时间 deletedtrue显式回报、并施加时间与设备双重约束一次性确认 有界期限 目标设备绑定。它既没有引入新的权限面也没有破坏既有 list/create/update/complete 流程而是以增量方式在请求规范化和响应净化两层同时收紧。想深入理解这条契约在更大图景中的位置可以继续阅读基线能力说明docs/chat-chain-changes/2026-09-04-mobile-calendar-reminders.md服务端核心实现mobile-calendar.tsSocket 事件流转与超时边界chat-run.tsREST 端点契约docs/openapi.json/api/studio/mobile-calendar/request契约测试mobile-calendar-delete.test.ts、run-chat-mobile-calendar.test.ts【免费下载链接】ekko-studioEkko Studio is a local-first AI workspace for multi-agent chat, coding, and visual workflows, available on desktop and the web.项目地址: https://gitcode.com/gh_mirrors/he/ekko-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
ipman源码解析:5个核心技巧解决IP管理混乱的最佳实践 ipman源码解析:5个核心技巧解决IP管理混乱的最佳实践 刚入行时,我盯着屏幕上的 192.168.1.100 发呆。语法书翻烂了, if-else 写得飞起,可一到实际项目,面对几百台服务器的 IP… · 2026/9/23 20:35:13
VC++ DirectX仿暗黑破坏神RPG源码解析:从编译到状态机实现 简介:这份资源是面向C游戏开发初学者与进阶者的仿Diablo暗黑破坏神RPG游戏完整源代码,基于Visual C与DirectX技术栈实现,适合想通过真实项目理解RPG架构、图形渲染与游戏逻辑的开发者参考学习。压缩包共126个文件,约721KB… · 2026/9/23 20:35:13
电商大屏原生三件套实战:HTML语义锚点+CSS容器查询+JS节流 简介:本资源是一套面向前端开发者与数据可视化初学者的电商营业场景大屏模板,基于纯HTMLCSSJS实现,无需后端依赖,开箱即用。它聚焦电商核心指标(如实时销售额、订单量、地域分布、商品热力等)的动态呈现&am… · 2026/9/23 20:35:13
MMBT2907ALT1G PNP晶体管特性与应用指南 1. MMBT2907ALT1G芯片基础解析MMBT2907ALT1G是安森美半导体(onsemi)推出的一款表面贴装(SMD)PNP型通用双极结型晶体管(BJT),采用SOT-23封装。这个型号后缀中的"ALT1G"代表环保无铅版本,符合RoHS标准。作为2N2907的表面贴装版本,它延… · 2026/9/23 21:44:56
2×300MW火电厂电气一次设计:主接线比选、短路计算与设备选型全流程 简介:这份资源是面向电气工程专业学生与火电厂设计人员的课程设计/毕业设计参考资料,聚焦2300MW机组火力发电厂电气一次部分设计。内容从电气主接线方案选取入手,围绕可靠性、经济性与安全性三大原则,对单元接线、单母线、单母线分… · 2026/9/23 21:44:49
STM32 HAL库驱动TCS34725全功能实战:从I2C通信到RGB与Lux数据输出 简介:这是一份面向嵌入式开发者与STM32学习者的TCS34725全功能驱动源码包,针对RGB颜色识别与环境光感应(ALS)场景,解决从底层I2C通信到上层颜色数据读取的完整驱动实现问题。包内共463个文件,以139个.h头文… · 2026/9/23 21:44:49
写论文软件哪个好?我用书匠策AI跑了一遍毕业论文的“黑匣子” 官网:www.shujiangce.com | 微信 公众号 :书匠策AI
各位同学好,我是那个教你们写论文的博主。
每次直播,弹幕里飘得最多的就是:“博主,写论文软件哪个好?”
这个问题我一开始还认真答&… · 2026/9/23 21:44:49
Synapse 用户目录(User Directory)实现与搜索算法深度解析 后端即时通讯 【免费下载链接】synapse Synapse: Matrix homeserver written in Python/Twisted. 项目地址: https://gitcode.com/gh_mirrors/sy/synapse 点击查看 免费下载 用户目录(User Directory)是 Matrix 联邦网络中"找人"的… · 2026/9/23 21:44:49
eSIM全面落地:从开通实操到双卡双eSIM的取舍指南 eSIM这个词,过去几年在数码圈里一直属于“狼来了”的状态——每年都说要普及,每年都只闻楼梯响。直到最近,移动、联通、电信三家运营商陆续在更多省市开放了eSIM的办理通道,尤其是手机端的独立eSIM业务开始真正落地,我… · 2026/9/23 21:44:49
3招搞定手机怎么下载微信面试难题实战项目解析 3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29