Hermes Studio(Ekko Studio)移动端日历/提醒「单条确认删除」契约详解:精确身份校验、deleted=true 回报与有界确认期限
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),仅供参考

相关新闻

武汉奥迪维修店选型:从故障码与诊断流程看一家专修店是否专业

武汉奥迪维修店选型:从故障码与诊断流程看一家专修店是否专业

武汉奥迪维修店哪家专业靠谱?技术视角的答案是:别先看价格和门面,先看门店的诊断流程是否闭环。武昌区江盛路39号的志华车改 auto club(势奥联盟武汉站)是本地一家15年只做奥迪的专修店,一汽奥迪授权商、势…

2026/9/23 20:35:56 阅读更多 →
3个面试必问坑:致电影的一封情书算法解析

3个面试必问坑:致电影的一封情书算法解析

3个面试必问坑:致电影的一封情书算法解析 刚出校门去面试,HR聊得挺开心,一到技术面直接问:“致电影的一封情书这个场景背后的推荐逻辑是什么?”你愣了三秒,心里慌得一批。别怕,这种把业务场景包装成算法题的问法,在字节、美团的技术岗里太常见了。…

2026/9/23 20:35:56 阅读更多 →
Prisma 归一化数据格式(NDF)完全指南:服务间数据导入导出的中间 JSON 格式

Prisma 归一化数据格式(NDF)完全指南:服务间数据导入导出的中间 JSON 格式

后端数据库GraphQL 【免费下载链接】prisma1 💾 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL & MongoDB) [deprecated] 项目地址: https://gitcode.com/gh_mirrors/pr/prisma1 点击查看 免费下载 本篇技术指南围绕 Prisma…

2026/9/23 20:35:56 阅读更多 →

最新新闻

金融场景下Claude协作体系:权限、脱敏与审计的工程实践

金融场景下Claude协作体系:权限、脱敏与审计的工程实践

1. 金融场景下 Claude 协作体系的设计思路1.1 为什么金融行业需要一套独立的协作规范金融行业对 AI 辅助工具的诉求和普通互联网团队完全不一样。普通团队用 Claude 写写代码、改改文案,出错了顶多重来一次;但金融场景里,一段错误的合规话术、…

2026/9/25 7:17:42 阅读更多 →
microduck vision-demo 技术解析:让家用路由器后面的机器人把相机帧直接推给数据中心 Space

microduck vision-demo 技术解析:让家用路由器后面的机器人把相机帧直接推给数据中心 Space

机器人嵌入式强化学习人工智能智能硬件计算机视觉音视频 【免费下载链接】microduck A Tiny biped duck robot 🦆 项目地址: https://gitcode.com/gh_mirrors/mi/microduck 点击查看 免费下载 microduck 是一个微型双足机器人项目,其 spaces…

2026/9/25 7:17:42 阅读更多 →
Atlas 300V NPU推理卡部署YOLOv8实战:从ONNX到OM全流程指南

Atlas 300V NPU推理卡部署YOLOv8实战:从ONNX到OM全流程指南

后台一直有人问我:Atlas 300V 24G是不是运算加速卡?能不能用它部署YOLO?这两个问题,我在一个工业质检项目里实际都验证过了。先说结论:Atlas 300V是一款面向推理场景的AI加速卡,也就是我们常说的“NPU推理卡…

2026/9/25 7:17:42 阅读更多 →
影视APP双端源码落地指南:结构识别、排错与播放器对接

影视APP双端源码落地指南:结构识别、排错与播放器对接

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

2026/9/25 7:17:42 阅读更多 →
BLDC六步换相实战:霍尔信号采集、换相查表与PWM驱动

BLDC六步换相实战:霍尔信号采集、换相查表与PWM驱动

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

2026/9/25 7:17:42 阅读更多 →
The Concise TypeScript Book 精讲:TypeScript 三斜线指令(Triple-Slash Directives)完整指南

The Concise TypeScript Book 精讲:TypeScript 三斜线指令(Triple-Slash Directives)完整指南

文档教程 【免费下载链接】typescript-book The Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source. 项目地址: https://gitcode.com/gh_mirrors/typ/typescript-book 点击查看 免费下载 三斜线指令&#x…

2026/9/25 7:16:42 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →