@dsh-enhanced/assistant-delivery 0.1.65 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -4
- package/lib/agent-runtime.d.ts +6 -2
- package/lib/agent-runtime.d.ts.map +1 -1
- package/lib/agent-runtime.js +60 -14
- package/lib/agent-runtime.js.map +1 -1
- package/lib/attention-audit-store.d.ts +54 -0
- package/lib/attention-audit-store.d.ts.map +1 -0
- package/lib/attention-audit-store.js +213 -0
- package/lib/attention-audit-store.js.map +1 -0
- package/lib/attention-enforcement.d.ts +75 -0
- package/lib/attention-enforcement.d.ts.map +1 -0
- package/lib/attention-enforcement.js +84 -0
- package/lib/attention-enforcement.js.map +1 -0
- package/lib/attention.d.ts +203 -0
- package/lib/attention.d.ts.map +1 -0
- package/lib/attention.js +288 -0
- package/lib/attention.js.map +1 -0
- package/lib/coordinator.d.ts.map +1 -1
- package/lib/coordinator.js +6 -0
- package/lib/coordinator.js.map +1 -1
- package/lib/feedback-command.d.ts +23 -0
- package/lib/feedback-command.d.ts.map +1 -1
- package/lib/feedback-command.js +176 -0
- package/lib/feedback-command.js.map +1 -1
- package/lib/foreground-observation.d.ts +21 -0
- package/lib/foreground-observation.d.ts.map +1 -1
- package/lib/foreground-observation.js.map +1 -1
- package/lib/foreground-termination.d.ts +31 -0
- package/lib/foreground-termination.d.ts.map +1 -0
- package/lib/foreground-termination.js +42 -0
- package/lib/foreground-termination.js.map +1 -0
- package/lib/in-process-reload-runtime.d.ts +87 -0
- package/lib/in-process-reload-runtime.d.ts.map +1 -0
- package/lib/in-process-reload-runtime.js +319 -0
- package/lib/in-process-reload-runtime.js.map +1 -0
- package/lib/index.d.ts +20 -6
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +9 -3
- package/lib/index.js.map +1 -1
- package/lib/native-termination.d.ts +12 -0
- package/lib/native-termination.d.ts.map +1 -0
- package/lib/native-termination.js +57 -0
- package/lib/native-termination.js.map +1 -0
- package/lib/native-web-owner.d.ts +7 -0
- package/lib/native-web-owner.d.ts.map +1 -1
- package/lib/native-web-owner.js +40 -10
- package/lib/native-web-owner.js.map +1 -1
- package/lib/operator-snapshot.d.ts +31 -3
- package/lib/operator-snapshot.d.ts.map +1 -1
- package/lib/operator-snapshot.js +120 -47
- package/lib/operator-snapshot.js.map +1 -1
- package/lib/progress-attention.d.ts +55 -0
- package/lib/progress-attention.d.ts.map +1 -0
- package/lib/progress-attention.js +128 -0
- package/lib/progress-attention.js.map +1 -0
- package/lib/service.d.ts +515 -4
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +2183 -130
- package/lib/service.js.map +1 -1
- package/lib/sqlite.d.ts +1 -1
- package/lib/sqlite.d.ts.map +1 -1
- package/lib/sqlite.js +102 -2
- package/lib/sqlite.js.map +1 -1
- package/lib/store.d.ts +113 -2
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +450 -39
- package/lib/store.js.map +1 -1
- package/lib/types.d.ts +175 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/lib/work-item-engineering-context.d.ts +127 -0
- package/lib/work-item-engineering-context.d.ts.map +1 -0
- package/lib/work-item-engineering-context.js +151 -0
- package/lib/work-item-engineering-context.js.map +1 -0
- package/lib/work-item-feedback-schema.d.ts +2 -0
- package/lib/work-item-feedback-schema.d.ts.map +1 -0
- package/lib/work-item-feedback-schema.js +29 -0
- package/lib/work-item-feedback-schema.js.map +1 -0
- package/lib/work-item-feedback-store.d.ts +29 -0
- package/lib/work-item-feedback-store.d.ts.map +1 -0
- package/lib/work-item-feedback-store.js +111 -0
- package/lib/work-item-feedback-store.js.map +1 -0
- package/lib/work-item-feedback.d.ts +157 -0
- package/lib/work-item-feedback.d.ts.map +1 -0
- package/lib/work-item-feedback.js +2 -0
- package/lib/work-item-feedback.js.map +1 -0
- package/lib/work-item-replies-schema.d.ts +3 -0
- package/lib/work-item-replies-schema.d.ts.map +1 -0
- package/lib/work-item-replies-schema.js +45 -0
- package/lib/work-item-replies-schema.js.map +1 -0
- package/lib/work-item-replies-store.d.ts +43 -0
- package/lib/work-item-replies-store.d.ts.map +1 -0
- package/lib/work-item-replies-store.js +203 -0
- package/lib/work-item-replies-store.js.map +1 -0
- package/lib/work-item-replies.d.ts +93 -0
- package/lib/work-item-replies.d.ts.map +1 -0
- package/lib/work-item-replies.js +15 -0
- package/lib/work-item-replies.js.map +1 -0
- package/package.json +24 -24
package/README.md
CHANGED
|
@@ -35,8 +35,25 @@ Host-only `validateOwnerAgentForRoute(agent, authorityId)` 为有限动态工具
|
|
|
35
35
|
|
|
36
36
|
Host-only `inspectOwnerForegroundToolCall({ agent, authorityId, callId, toolName, argumentsJson })` 另核对当前认领的具体 Inbox、尚未结束的原生 turn、pending 前台执行记录及唯一未结算的 `tool/call` 事件。工具名和实际参数须与事件一致;返回内容无关的 task/owner/binding、turn、调用事件与参数摘要,不返回任务正文或参数。同 Session、开放 turn 或 owner 身份本身不足以产生证明;Host 直接调用、PTC 子调用、旧或重复事件保持未归因。此只读接口不迁移数据库,不授予执行权限,也不证明任务成功;消费者须保留后续 canonical 反馈与独立验收边界。
|
|
37
37
|
|
|
38
|
+
Host-only `inspectOwnerAliasRoute(agent, authorityId)` 与 `inspectOwnerAliasForegroundToolCall({ agent, authorityId, callId, toolName, argumentsJson })` 为跨渠道只读查询提供 linked 别名证明;回执本身不构成授权,Work Items 还要求 owner 在 `ownerRecall.linkedAliases` 中列出该别名的 principal id。只有 role 为 `linked`、`linked_to_id` 精确指向当前 active owner、自身 active 且通过当前 active binding(同一 workspace/preset、非 owner route binding、Session 一致)调用的 principal 才有回执;`linked_to_id` 为空、指向他人、owner 交接/撤销、别名撤销(当前“解除关联”即 `revokePrincipal`,会同时撤销其 binding)或 binding 轮换均无回执。回执协议为 `assistant-delivery/owner-alias-receipt/v1`,不含 `receiptVersion`,同时携带别名身份与根 owner 的 principal record/version、binding version/generation,因此 owner 重新配对(版本递增)会改变回执;调用证明协议为 `assistant-delivery/owner-alias-foreground-tool-call/v1`,要求别名在 link 之后认领的 Inbox、未结束 turn 与唯一未结算的原生 `tool/call`;turn 在认领时固定别名 principal record/version 与 `linked_to_id`,证明时须与回执中的别名版本及当前根 owner 一致,因此认领时尚指向其他根、随后在 turn 中途重新 link(版本递增,binding 版本不变)的 turn 不产生证明。两者每次调用都重读两遍并要求一致。别名回执不是 v2 owner receipt:`validateOwnerRoute`、`validateOwnerAgentForRoute`、`inspectOwnerForegroundToolCall`、偏好 turn、审批准备及原生 Web owner(`role !== 'owner'` 检查未改)对别名一律拒绝。此 API 无 schema 迁移;link 仅按 owner record id 生根、不冻结 link 时的 owner 版本;link 绑定 owner 的当前激活期:`revokePrincipal` 撤销 owner 时,同一事务把所有仍 active 且指向它的 `linked` principal 的 `linked_to_id` 置空并递增其版本(principal 与 binding 保持 active,等同未 link 的普通 principal),因此以同一 record 重新激活 owner 后不会恢复别名,须重新 `linkPrincipal`(新回执携带新的根版本);已撤销的 linked 行不变,其后显式重新配对仍按原有规则在根 owner active 时恢复。`linkPrincipal` 在单个写事务内校验并在 UPDATE 中复核 owner 仍 active,与并发撤销串行化。本行为变更无 schema 迁移;打开库时幂等解除 active linked 行中根不是当前 active owner 的 link(升级前撤销 owner 遗留的 link),而变更前已经历撤销又重新激活、现指向 active owner 的 link 与新 link 无法区分,不会被追溯清理。原生 Web 认领不登记别名 turn,Web owner 以别名身份加入属后续工作。
|
|
39
|
+
|
|
40
|
+
Host-only `routeWorkItemReport({ sourceId, workspace, originBindingId, idempotencyKey, text, format, itemId, reportRevision, linkedFallback, prefer? })` 由 Host 决定后台工作项报告的去向。`sourceId` 先按 `canonicalBackgroundSourceId` 规范化(NFC、去首尾空白),入队授权、元数据与发送前重验使用同一规范值。origin 可用时返回 `{ route: 'origin' }`、不入队,调用方走原有 origin 路径。「origin 不可用」的定义:origin binding 非 active(或其 principal 非 active),并且同一会话(`getActiveBinding(origin.conversation)`)下没有同一 principal、同一 workspace/preset、principal active 的后继 active binding。`/new` 经 `rotateBinding` 撤销旧 binding 并插入后继 binding 时 origin 仍算可用:返回 `origin`、不改道,调用方仍以原 `originBindingId` 走原有路径,因此失败/投递语义与未配置 fallback 时完全一致(例如普通 `enqueueBackground` 以已轮换 binding 入队时照旧报 `missing-binding`)。只有 origin 不可用时才按主人给出的 `linkedFallback`(≤8 个 Delivery principal id,按序)选择第一个仍为 active `linked`、`linked_to_id` 指向当前 active owner、在 origin 同 workspace/preset 下恰有一个 active binding(多个即视为歧义跳过;只在其他 workspace/preset 有 binding 也跳过)、且现有 Policy `evaluate` 已允许该来源 `send` 的别名;首个通过这些检查(含 Policy `evaluate`)的别名即终点:随后 `authorize` 若拒绝或入队失败直接抛错,不再尝试名单中后续别名。报告以 `linked-report:<sha256(idempotencyKey)>` 在普通 background lane 入队一次(不走 typed work-item-report lane,因此 fallback 信道上的回复没有报告行,不能续办或反馈;若要只读查看,Work Items 侧还要求该别名列在 `ownerRecall.linkedAliases` 中),并照常写 WP19 注意力审计行(lane `background`,purpose `result`,保留 `workItemId`)。入队记录携带保留元数据 `dsh.linked-report` v1,绑定 origin binding、owner 与别名的 record/version 以及别名 binding version/generation;发送前重验,任何解除关联、owner 撤销/重新 link、binding 轮换或 Policy 变化都不发送,错误码为 `binding-revoked`(别名 binding 已被撤销或轮换时,通用 binding 检查先触发,例如 `revokePrincipal` 解除关联会同时撤销别名 binding)或 `linked-report-route-revoked`(其余情况:owner 撤销/重新 link、版本变化、Policy 不再允许等)。已有 origin 或 linked 记录时重放返回首个去向,不再改道;同 key 用于不同报告拒绝。`enqueueBackground`/`enqueueWorkItemReport` 拒绝伪造 `dsh.linked-report` 元数据前缀和 `linked-report:` 幂等键前缀(`runtime-conflict`)。WP22 `inspectNotificationOutcomeFacts`/`outcomeFactsFor` 会把别名信道上回复该 fallback 消息的入站计为该通知的 reaction(与普通 background 通知相同);事实另带可选 `route: { kind: 'linked', originBindingId }`:仅当 Outbox 元数据 `dsh.linked-report` 为 v1、幂等键带 `linked-report:` 前缀且 `originBindingId` 非空时出现(两者只有本 API 能写入),其余通知省略该字段(不写 `origin`),因此原有事实形状不变;审计行本身仍不标注(审计 lane 有 CHECK 约束,标注需 schema 变更)。Evaluation 把 linked 通知计入账本、feed 与 summary,但排除出注意力调优(见 Evaluation README)。可选 `prefer: 'recent'`(默认 `'origin'`,不传时行为不变;其他取值 `runtime-conflict`):对名单中所有合格别名(每个别名只做一次 Policy `evaluate`),按主人最近入站(`inbox_messages.received_at`,同一会话任一 generation、同一 principal;一次有界参数化查询(≤9 个 binding))降序排序,同时间保持名单顺序;别名 principal 在 link 之前的入站同样计入。origin 可用时仅当最新合格别名的入站严格晚于 origin 会话的最新入站才改道,否则返回 `origin`(无入站、别名被撤销/轮换/Policy `evaluate` 拒绝时均回落 origin);若该别名在 linked 记录提交前被拒绝(Policy `authorize` 拒绝如预算/速率、注意力 enforce 拒绝、`missing-binding` 等),也返回 `origin`、不留别名 outbox 行;已提交则照常抛错,不会再走 origin 重复发送。origin 不可用时按该排序选第一个合格别名,失败语义与默认相同(`authorize` 拒绝或入队失败直接抛错)。改道仍走同一 linked 记录与发送前重验,同样只走普通 background lane(回复不能续办/反馈)。该查询按未索引的 `inbox_messages.binding_id` 扫描;数据量变大后可加 `inbox_messages(binding_id, received_at)` 索引(需 schema 迁移)。可选 Delivery 配置 `ownerReportRouting.orderAcrossLanes`(默认 `false`):开启后,若同一工作项已有更早且仍未结算的报告(`outbox_messages` 状态为 `pending` / `retry_wait` / `attempting` / `unknown_after_send`,且没有与当前 `attempt_count` 匹配的 operator `cancel` 回执;只读、单条有界的 `findUnsettledWorkItemReport`)。
|
|
41
|
+
|
|
42
|
+
- 早期报告是 origin 报告(typed `delivery_work_item_reports` 的低 `reportRevision`,或仅带 `delivery_attention_audit` `purpose: 'result'` 的普通后台通知):新报告留在 origin,即使传了 `prefer: 'recent'`;origin 不可用时按普通规则回退。origin 本身已被 `/new` 轮换、只有后继 binding 可用时不粘滞 origin(调用方拿的是冻结的旧 `originBindingId`,强制 origin 会让入队 `missing-binding` 失败),改为按普通 `prefer` 规则回退。
|
|
43
|
+
- 早期报告是 linked 报告(`dsh.linked-report` v1 的低 `reportRevision`):仅当该别名仍合格且仍在本次 `linkedFallback` 名单中时,新报告留在同一别名;否则按普通规则回退(origin 可用且未传 `prefer: 'recent'` 时回 origin)。sticky 别名的 linked 行在提交前被拒绝时回退 origin,已提交则照常抛错,绝不与 origin 发送重复。
|
|
44
|
+
- sticky linked 去向仍走普通 background lane(回复不能续办/反馈);既有 per-lane claim 顺序(同 `lane_hash` 上更早的非终态行挡住后续行)保证先发旧报告、后发新报告。保序**只在同一 lane 内成立**:typed `work-item-report` 与普通 background 是两条 lane,若调用方在后续修订切换了表示形态(例如 typed 能力瞬时不可用后回退普通 background),本开关不承诺跨 lane 顺序。该开关只在 `linkedFallback` 路由已启用时有实际意义(未配置时调用方走原有路径,粘滞不生效),sticky 去向不可用时不阻塞投递;不放宽 Policy,无新 Loop/timer,无 schema 迁移。
|
|
45
|
+
|
|
46
|
+
`readOwnerForegroundToolInput` 使用同一真实当前调用证明,按 UTF-8 字节分页读取已经持久保存的人类输入,并返回实际记录的供应商冻结状态。每页最多 8192 字节;sourceDigest 绑定 task、原 envelope、全文和 model state,不随调用 ID、模型工具参数或页窗口变化。缺失/不一致 supplier 由执行消费者拒绝。它不接受任意 Inbox、来源或路径选择器,不读取模型生成的替代正文,不新建任务、发送消息或授予执行权限;调用前后 owner/native-call 变化会使读取失效。Delivery 当前 schema 为 31。
|
|
47
|
+
|
|
48
|
+
|
|
38
49
|
Host-only `inspectOwnerRequestedChange(execution, { sourceId })` 限定当前认证 owner 主 Agent 的未结 `memory_manage` 或 `wiki_upsert` 原生调用。它复核已认领的原 Inbox、当前 turn、实际工具名与参数(最多 64 KiB)、owner lineage 和 binding 代次,返回 `prepareAgentApproval` 的精确 route、Inbox 原始正文及只含身份与摘要的 SHA256 receipt。空正文、附件单独输入、PTC、历史或已结算调用均无证明。正文可能包含引用文字;哪些内容构成 owner 指令仍须由 Policy 隔离审查。原生 Web 输入在派发时登记同一前台执行记录并在 drain 时结算,失败或取消不留待结记录。该只读接口不要求 RSI `ownerRoutes` 配置、不注册 Agent 工具,也不授权写入。
|
|
39
50
|
|
|
51
|
+
Host-only `withOwnerWorkItemLearningTaskFence` 对准确的 `itemId`、owner lineage、来源/展示摘要和当前 canonical 版本作严格单项复核;暂不可读或变化时抛错。`withOwnerLearningSourcesFence` 支持至多 1000 个有序、无重复的前台与后台来源,在同一次 Delivery → Evaluation → WorkItems 来源事务中完成所有外部来源回调,再核对整组当前来源,供下游同步写入 Memory 或审查账本。返回快照按输入对齐;暂缺来源只隐藏,只有当前 owner revision 明确 `withdraw` 才证明主人撤回,普通冲突或 retraction 不代表撤回。回调仅允许终端账本的本地同步操作,不能再进入 Delivery/Evaluation 来源事务、调用模型或 producer resolver;Promise/thenable 拒绝。旧前台 source API 与摘要字节保持不变,后台来源不伪造 Inbox,brief/report 是任务上下文,实际反馈才是主人 testimony。这些 fence 不授予采纳权限,也不消耗或续期执行额度。
|
|
52
|
+
|
|
53
|
+
Host-only 工程来源使用独立 `assistant-delivery/work-item-engineering-context/v1`:`inspectOwnerWorkItemEngineeringContext` 返回完整来源 manifest,`readOwnerWorkItemEngineeringContext` 按精确 manifest/objective digest 分页,`withOwnerWorkItemEngineeringContextFence` 在 Delivery → Evaluation → WorkItems 工程来源锁内交给同步终端账本。工程目标按 canonical JSON 封装根任务与全部可核对的主人续办原文,含 framing 最多 16384 UTF-8 字节;不 trim、NFC 归一化、截断或以简报、报告、结果短句替代主人任务。每层输入必须非空白、无附件;当前只接受封存 diagnosis 根和有真实 reply/Inbox/child 关联的 v2 reply 子链,最多 32 个 parent links。缺少原始定位和附件证明的历史 v1 child 在此新接口 abstain,旧 v1 执行及 Memory 来源不变。
|
|
54
|
+
|
|
55
|
+
父报告仅按每个 child 计划封存的准确 cutoff 读取,单份最多 65536 字节、总计 262144 字节;不取 latest,也不进入工程目标。每页包含末页都重验完整 frame、当前 owner/canonical/Policy/producer 与原始 UTF-8 边界。同 owner `/new` 可以读取已经绑定准确完成子项、后来被标 cancelled 的 reply 历史;新增历史 getter 不恢复执行、route、ACK、授权或额度。缺段、附件、空白、超界、反馈更正/撤回或协议缺失均不退回旧 reader 伪造来源。旧 feedback proof、sourceDigest、Memory 请求及 reader 字节保持原样;本接口不启动模型、loop、timer 或新 schema。
|
|
56
|
+
|
|
40
57
|
## 配置
|
|
41
58
|
|
|
42
59
|
| 字段 | 默认值 | 含义 |
|
|
@@ -63,6 +80,10 @@ Host-only `inspectOwnerRequestedChange(execution, { sourceId })` 限定当前认
|
|
|
63
80
|
| `permissionPickerTtlMs` | `900000` | `/permissions` 三档权限卡片的签名提交有效期;范围 1 分钟至 24 小时 |
|
|
64
81
|
| `toolApprovalTtlMs` | `300000` | 当前 open turn 的即时工具审批有效期;范围 1 秒至 5 分钟 |
|
|
65
82
|
| `toolApprovalPreparationTimeoutMs` | `10000` | 卡片前持久化准备上限;范围 100–30000 毫秒,且不超过即时审批总有效期;超时不出卡、不执行 |
|
|
83
|
+
| `ownerReportRouting.orderAcrossLanes` | `false` | 仅在 `linkedFallback` 报告路由已启用时有实际意义:同一工作项仍有未结算的早期报告时,新报告沿用该报告的 origin 或同一合格别名,由既有 per-lane claim 顺序按 revision 先后发送;保序限于同一 lane(typed 与普通 background 分开),origin 已被 `/new` 轮换时不粘滞 origin;sticky 去向不可用时回退普通路由,不阻塞投递 |
|
|
84
|
+
| `naturalFeedback.coverage` | `false` | 可选:启用加宽的自然结果解析(同义/多语言、结果后允许附带原因或证据)。关闭时行为与旧版完全一致:前台仍只按旧版短语解析(含“还是不行,<原因>”形式),后台报告反馈仍只接受旧版整句白名单。开启后问句、假设/条件、引号内文本、否定引用(“并没有解决”)、矛盾陈述、含糊情绪与撤回命令仍不产生结果证据 |
|
|
85
|
+
| `naturalFeedback.mixedIntent` | `false` | 可选,依赖 `naturalFeedback.coverage`:同一条认证主人的 WorkItems 报告回复同时含结果判断与明确续办指令时,拆成两件各自鉴权/幂等/目标绑定的决定——先记 canonical 结果,再按既有续办队列入队;任一侧未获授权时只做允许的一件并在 Host 日志记录原因。关闭时不拆分,行为与旧版一致 |
|
|
86
|
+
| `peerAgents` | `[]` | 可选、默认空的精确 peer bot 白名单(channel/account/tenant/user)。仅当入站 envelope 带 `senderIsBot=true` 且完整元组匹配时,才把该 bot 激活为当前 owner 的 linked principal 并进入它自己的会话;它保留独立 Policy subject,不继承 owner 的工具、记忆、WorkItem 反馈或续办通道。未列入的 bot 仍是 `unauthorized-principal` |
|
|
66
87
|
| `ownerRoutes` | `[]` | Host-owned 稳定 owner 路由;每项精确固定 id、conversation、principal、绝对 workspace、preset、policyRef 和 minimumGeneration |
|
|
67
88
|
|
|
68
89
|
所有可变部署值都经过 Schemastery 校验。每个 binding 会持久固定 workspace 与已解析的 preset id;有 roster 时,fresh create 和 cold resume 都在 Agent 发布前挂载该 preset,不能把 session header 中的 `agentPreset` 当成已经完成组合。fresh create 的新 workspace 使用 `0700` 请求模式,已有目录的权限不会被改写;cold resume 只验证持久 workspace 仍是目录,不会在仓库被删除或网络盘掉线时悄悄创建一个空目录。SQLite 使用 `WAL`、`synchronous=FULL`、foreign keys、busy timeout 和 forward-only schema;私有目录/数据库权限分别收窄为 `0700` / `0600`,未来 schema 会拒绝打开。
|
|
@@ -139,8 +160,22 @@ ownerRoutes:
|
|
|
139
160
|
|
|
140
161
|
`resolveOwnerRoute(id)` 每次从 binding ledger 读取该 conversation 的当前 active binding,只接受 active owner,且要求 principal、workspace、agent preset、policyRef 全部逐项相等、generation 不低于显式 floor;`/new` 产生的同 lineage 下一代可单调前进,任一身份或作用域漂移都会 fail closed。authority 只存在于 Host 配置和 service API,不注册为 Agent 工具、不进入 prompt,也不能由成长系统自行创建或修改。
|
|
141
162
|
|
|
163
|
+
Host-only `inspectOwnerRouteBinding({ authorityId, principalId, workspace, agentPreset })` 与 `validateOwnerRoute()` 共用同一次 route 解析,返回 `{ protocol: 'assistant-delivery/owner-route-binding/v1', receipt, bindingId }`:`receipt` 即不变的 v2 回执,`bindingId` 是它所解析的那条 active binding 行。v2 回执本身仍不含 binding id;该接口只供需要把工作钉到某一条 binding 的 Host 消费者(如 WorkItems 晚绑定 worker run 合同)使用,不注册为 Agent 工具,错误与 `validateOwnerRoute()` 相同(`missing-binding`)。
|
|
164
|
+
|
|
165
|
+
Host-only `inspectOwnerRouteState({ authorityId, principalId, workspace, agentPreset })` 提供无正文的只读状态:`active` 带原 `validateOwnerRoute()` receipt;`revoked` 只在请求 scope 与配置一致、精确 durable owner 行明确撤销时返回 authority id/hash 和 principal id/record/version,不要求仍有 active binding。缺失 authority/owner/binding、scope 漂移或数据库异常均为 `unavailable`,`reason` 只有稳定代码,不包含异常或配置内容;消费者不能据此退休 owner。普通 `/new` 只撤销旧 binding,不等于 owner 撤销。接口不配对、不创建或修改 principal/binding/history;显式 A→B→A 交接仍沿用 durable row 的新版本,旧撤销观察不代表新版本授权。
|
|
166
|
+
|
|
142
167
|
`inspectOwnerModelSelection()` 在同一 owner route 校验后提供模型快照,供修复与成长继承。传入 `sourceAgent` 时读取匹配 binding 的 Session 最新原生 `request/header`,避免初始 Agent options 已过期;未传入时读取外部会话的持久模型选择或其 Delivery 默认配置。原生 Web 的模型由 DSH 管理,必须提供来源 Agent;该接口不替它猜测模型。返回值仅含 provider/model/可选 reasoning effort,不含会话内容或凭据。
|
|
143
168
|
|
|
169
|
+
离线安装器可调用导出的 `inspectRevokedOwnerRouteLocally({ databasePath, authority, principalRecordId, frozenPrincipalVersion })`,用受信任且冻结的完整 `OwnerRouteAuthority` 配置核对精确 durable principal 行。它只接受 canonical principal 与 authority 一致、role 为 owner、status 为 revoked、`linked_to_id` 为空且观察版本不低于冻结版本的记录,不要求仍有 active binding。缺失、active、linked、错误行或版本、非 canonical 身份和数据库不可用均抛出带稳定 code 的 `ActiveLarkOwnerBindingsSnapshotError`,不把缺失当成撤权,也不泄漏正文或异常内容。authority 来自受控安装配置,不接受模型输入;此 API 仅观察撤权,不授予写入或执行权限。
|
|
170
|
+
|
|
171
|
+
返回深度冻结的 `assistant-delivery/revoked-owner-route-snapshot/v1` 快照,包含完整 canonical authority、冻结版本、现有 `OwnerRouteStateInspection` 的 revoked 成员、schema 版本、database/WAL/SHM 文件身份及 storage/snapshot SHA-256 摘要。仅支持已审查的 schema 23–30,未来版本拒绝;摘要用于一致性核对,不是签名。读取与 `inspectActiveLarkOwnerBindingsLocally()` 共用私有目录/文件、fd/inode、SQLite quick_check/foreign-key 及漂移保护;WAL 只在私有临时副本中读取,不迁移、checkpoint、chmod 或修改原数据库,不新建 binding 或修改配置。
|
|
172
|
+
|
|
173
|
+
schema v28 为新的普通前台完成记录增加独立、不可变的 `termination`:只保存 Host 确认的终止分类、固定原因码和句柄收尾结果,不保存异常正文。它与业务结果分开:非成功执行仍为 `unknown,false`,`effects: unknown`、`replay: forbidden`,不会因为错误、超时或句柄已释放而授权重放。明确的用户停止单独记录为 owner-cancelled;缺失或未识别的事实保持 unknown。历史行不补猜测,新终态观察与 completion 在同一次写入中保存,之后不能增改。
|
|
174
|
+
|
|
175
|
+
Host-only `readOwnerForegroundTaskInput({ ...scope, inboxId, expectedSourceDigest, offset?, maxBytes? })` 只读取带合法终止观察的新 terminal 来源的 canonical Inbox 正文。每次读取重验当前 owner/route、原 binding lineage 和精确 source digest;原回复可缺失,不要求成功 Outbox。offset 是 UTF-8 字节偏移,默认 0;maxBytes 默认 4096、范围 4–8192,非法边界或越界拒绝。返回 input 的完整摘要/字节数、当前窗口及可选 nextOffset,contentDigest 跨页稳定。它不是模型工具,不接受任意文件路径;后续 worker 还须另行验证来源、供应商、预算与工具权限。原成功专用 `readOwnerForegroundTaskSource` 的所有准入约束保持不变。
|
|
176
|
+
|
|
177
|
+
内置外部渠道和 Native Web 的观察都来自真实原生 turn/end 或 Host 的明确超时/停止事实。Native Web 同时从实际 request/header 冻结 provider/model/reasoning effort;多次请求路由变化永久标为 inconsistent,不从 UI 或默认配置补齐 missing。该元数据不证明原任务目标达成,也不自动调度修复。
|
|
178
|
+
|
|
144
179
|
Host-only `listOwnerForegroundTaskSources({ authorityId, principalId, workspace, agentPreset, expectedOwner, after?, limit? })` 提供普通 owner 前台任务的持久完成来源。`inspectOwnerForegroundTaskSource({ ...scope, inboxId })` 在同一 owner writer 事务中精确读取该 Inbox 的 terminal 元数据,不扫描完成 feed;pending 或不合格来源返回 `undefined`,即使普通回复 Outbox 尚未入库也可返回元数据,但不提供原文或推断业务结果。`expectedOwner` 必须包含当前 `authorityHash`、`principalRecordId`、`principalVersion`;接口逐次重验 active owner、精确 route 和最低 generation。schema v25 在原 execution 行保存 `completion_sequence`,由同一 SQLite 事务的 trigger 推进 singleton clock,兼容迁移前已打开的 writer;迁移只对已有 terminal 行确定性编号,不从旧 acceptance 推断普通任务,也不制造 quiescent。完成顺序与 Inbox admission、毫秒时间及当前投递状态无关,因此晚完成的旧任务、重启和双连接不会因输入顺序漏项。页含内容空的 `unknown` 元数据;默认 50 行,最多 100 行,按 `hasMore`/`nextCursor` 继续扫描,不合格来源也会推进扫描边界。
|
|
145
180
|
|
|
146
181
|
cursor 的 protocol、数据库 epoch、稳定 owner scopeKey 和 sequence 必须匹配,越过当前 watermark 会拒绝。`/new` 沿用历史 binding 的 revoke + 1 规则,保留原 Session/source digest 和 owner cursor;owner 撤销、ABA、authority 或 generation floor 改变会拒绝旧凭据。source digest 绑定原 execution、owner、binding、Session、admission 和 envelope hash,不绑定当前 Inbox/Outbox 状态。合法 terminal execution 与 model 不可改写;直接 SQL 修改原 identity、完成结果或序号也会拒绝。
|
|
@@ -176,6 +211,7 @@ cursor 的 protocol、数据库 epoch、稳定 owner scopeKey 和 sequence 必
|
|
|
176
211
|
- receipt 必须带同一个 channel、account、provider message id;状态只允许单调 `accepted→delivered→read`。
|
|
177
212
|
- `progress()` 收到的工具参数/结果仅是最多 1500 字符的展示预览,并会脱敏常见 credential 字段与 token 形态;畸形或原始输入过大的参数只产生状态标记,不回显 raw text。它不包含任何 reasoning/thinking 内容或 provider 原始错误。adapter 仍必须按当前受众决定是否展示明细,群聊等共享受众应保持 status-only。
|
|
178
213
|
- adapter 的 socket、timer、SDK client 和 listener 必须由 `start()` disposer 释放。
|
|
214
|
+
- 可选 `observe(observation)`(WP20 intake 观察):只传事件 ID、`occurredAt`、principal、会话 `{kind, chat}`、`addressed`、`senderIsBot`、可选 `replyToProviderMessageId` 与正文 SHA-256,不传正文;不写 Inbox,不影响 `accept()`。无 observer 时为 no-op,畸形观察被丢弃。Delivery 由当前 principal 计算 `senderAllowlisted`,仅白名单发送者在同一会话回复已投递 WorkItems 报告时 `threadFollowUp` 为真,然后交给唯一的 `registerInboundIntakeObserver({ protocol: 1, observe })` 注册对象;注册需通过当前 `assistantWorkItems.ownsInboundIntakeObserver` 所有权栅栏,失去所有权即静默,observer 异常不外抛。
|
|
179
215
|
|
|
180
216
|
内部身份始终是结构化的 `ExternalPrincipalKey`、`ConversationRef` 与 `ConversationBinding`,不会从 `platform:chat:thread` 字符串反解析路由。DM 不允许 thread;group 入口要求渠道提供显式且稳定的 thread,可以是真实 provider root,也可以是渠道命名空间内按 principal 派生的顶层合成 lane。binding 仍固定精确 principal,任何同 conversation 的另一 principal 都会在进入 session 前 dead-letter,不能共享既有 owner 上下文。Lark 顶层群消息使用按发送者派生的合成 lane,真实回复串继续按 `root_id` 隔离。
|
|
181
217
|
|
|
@@ -246,6 +282,8 @@ Goals 的单次计划恢复使用单独的 Host capability。`goalWakeSettlement
|
|
|
246
282
|
|
|
247
283
|
普通前台任务也支持自然反馈:同一 owner 直接回复原任务结果,说“问题解决了”“还是不行,保存报错”或“撤回刚才的任务反馈”,Host 会记录明确判断,原文仍交给 Agent 正常续答。已有判断会自动按当前版本更正,无需先查询版本。只有明确、可确定解析的表述才记录;感谢、疑问、假设、引用、附件和没有精确回复目标的文字仍按普通聊天处理。该入口不覆盖 Automation、whole-goal 或原生 Web 结果;这些结果继续使用原有入口。
|
|
248
284
|
|
|
285
|
+
可选配置 `naturalFeedback.coverage`(默认关闭)把同一个解析器扩展到明确的结果同义族:中文“已解决/问题已修复/修好了/恢复正常了/现在可以正常用了/现在没问题了/可以了”与“不行/仍然不行/还是失败/没有修复/返回值仍然是空的/仍有报错”等,英文 `fixed` / `resolved` / `works now` / `not fixed` / `still broken` / `still empty` 等,并允许结果后附带原因或证据(如“现在可以正常用了,谢谢”“返回值仍然是空的,请检查分页”)。结果判断仍必须是整条消息开头的直接断言;附带部分只是不可信上下文,不进入证据等级、版本、预算或 Growth 采用判定。问句、假设/条件、引号内文本、否定引用(“并没有解决”)、与结果相反的矛盾断言、单独的情绪(“谢谢”“太好了”“还行”)以及撤回命令仍然不产生结果证据。关闭该开关时前台行为与旧版完全一致;该开关不改变 `/feedback` 显式命令、Automation/whole-goal 反馈或 Evaluation 的任何既有入口。
|
|
286
|
+
|
|
249
287
|
自然反馈使用 Delivery schema 24 的持久日志,绑定原始 Inbox、目标 Outbox、owner、入站顺序和一次冻结的修订参数。Evaluation 暂不可用时,普通聊天继续,日志等待后续补记;恢复只重试反馈记录,不重新运行用户的 Agent 请求。若旁路反馈日志本身未能持久化,Host 记诊断并继续普通聊天,不声称该条反馈已保存;普通派发仍须通过自身授权与持久化检查。版本冲突不自动改用新版本重试;明显早于当前反馈或无法确定顺序的相反判断不会覆盖当前结果。自然纠正原因可随精确 canonical 修订交给 Growth,最多 4096 字,作为不可信任务材料,不授予任何新权限。
|
|
250
288
|
|
|
251
289
|
`/feedback` 的完整固定语法如下;不接受附件或额外自由文本,命令本身不进入模型:
|
|
@@ -312,15 +350,15 @@ Profile 还必须为当前 owner principal 添加精确授权,例如:`subjec
|
|
|
312
350
|
|
|
313
351
|
卡片提交后,Delivery 会再次核对 active binding、精确 principal/chat、原始 provider message id 和 Policy,并用实时 `resolveModelInfo()` 验证 provider/model 及该模型支持的 effort;通过后把三项选择按 canonical conversation 持久化到 Delivery SQLite。渠道可以等待该 durable settlement:同实例由完成通知即时唤醒,共享数据库的另一实例完成时由有界轮询感知,从而把原卡更新成不可交互的最终结果。选择从下一条普通消息生效,保留当前 session 上下文,跨 `/new` 和 Host 重启仍有效。卡片可选择“默认(由模型决定)”;`/model use` 保留为无卡片渠道和排错时的文字后备,`/model reset` 删除会话覆盖并恢复 `agentProvider` / `agentModel`。模型目录按宿主约定是建议性的,最终调用是否成功仍由对应 adapter 和账号认证决定。若某个已持久化的显式 effort 在下一条普通消息前被 DSH 核心判为不支持,Delivery 会在任何 prompt 或 durable dispatch 标记之前,以 version CAS 仅清除该 effort、重新预检同一 provider/model 的默认档位;CAS 冲突会重试而不会覆盖更晚的 `/model` 选择。模型不会被静默替换,也不会重放或重复计费。
|
|
314
352
|
|
|
315
|
-
`/permissions`(别名 `/permission`)只允许当前 active binding 的精确 owner
|
|
353
|
+
`/permissions`(别名 `/permission`)只允许当前 active binding 的精确 owner 使用,命令本身不进入 Agent 或触发 LLM。私聊权限卡片提供“请求批准(ask)/帮我批准(auto)/完全访问权限(full)”。助手的 `auto` 使用 `workspace-write + ask` 并持久写入项目专属 reviewer 事件,既不选择也不注册 Harness 保留的原生 `auto`;两套功能可共存。切换仍核验身份、预算和状态指纹,失败时持久回退 ask。`full` 使用 `danger-full-access + never + none`;卡片需要风险确认,文字入口需再次发送 `/permission full confirm`。
|
|
316
354
|
|
|
317
355
|
权限卡片作为受限 Outbox intent 持久化,并用独立 HMAC 域绑定原始 route、精确 owner、binding version、session、权限状态指纹、Policy 紧急停止版本、目标档位和有效期。点击时还必须匹配原卡的 provider message id,并重新核对 active owner/binding、DM、Policy 与 session;转发、错人、跨 chat、篡改、过期、`/new` 后的旧卡,以及权限状态或紧急停止版本变化后的旧卡都会明确提示失效。最终提交在权限 mutation 前、reviewer 等待后和 session flush 后重复核对紧急停止版本,因此紧急停止开→关的 ABA 也只会触发 ask 补偿,不会完成旧卡提权。同一张卡的第一次选择进入原 binding 的 durable Inbox 串行队列;点击 Toast 只表示“已受理”,真正切换成功会另发持久回复。平台重投同一选择幂等,相反选择冲突而不会晚到覆盖;需要再次切档时应重新发送 `/permissions`。
|
|
318
356
|
|
|
319
|
-
原生 DSH 设置与 Web
|
|
357
|
+
原生 DSH 设置与 Web 权限面板写入的最新 preset 会覆盖较早的助手 reviewer 意图。官方 Auto 的工具审查与人工接管由 Harness 负责,不会调用助手模型;再次使用助手 `/permission auto` 会先恢复 workspace 沙箱和 ask,再写显式项目事件。旧项目事件继续可读;未知会话格式失败关闭,非 canonical legacy full 仍经过严格迁移与 flush barrier。
|
|
320
358
|
|
|
321
359
|
旧版本中,这个缺口会产生一个很迷惑的症状:session 看似已经是 native full,但 reviewer 缺失会保守折叠成 `user`,AssistantPolicy 因而把未知/敏感工具送去 `ask-review`;同一 session 的 `approval=never` 又会在渠道审批展示前直接拒绝,上游最终误写成 `"the user rejected tool"`,所以用户既没看到弹窗也没有机会批准。迁移后精确 full 会持久补齐 `reviewer=none`;同时进度适配器会把嵌套 `tool-result.isError=true` 显示为工具失败,而不是继续显示“已完成”。
|
|
322
360
|
|
|
323
|
-
|
|
361
|
+
助手档位从 `ctx.permissionPresets.resolve()` 的静态 workspace/full 候选匹配,明确排除原生保留名称 `auto`。一个或两个 `workspace-write + ask` 候选支持旧版共享或分离的助手目标;实际自动审批必须有显式项目 reviewer 事件。原生 Auto 是否启用不改变助手目标,但仍纳入权限表指纹,以拒绝过时的权限卡片。
|
|
324
362
|
|
|
325
363
|
权限命令在第一次 reviewer/policy/sandbox mutation 前还必须先取得 Inbox 的 durable dispatch/recovery marker;每个异步边界后都复核 abort 与租约。若进程退出、续租失败、flush 未确认、依赖尚未就绪或回复入队失败,该 marker 会绕过普通 `maxAttempts`,在原 binding 串行 lane 中继续恢复,直到确认已持久化目标并补发成功终态,或安全收敛到 ask 后补发失败/取消终态。`/stop` 和 `/new` 会在 abort 前把正在执行的权限命令原子改标为 cancelled recovery;旧命令不会以 `processor-ambiguous` 终止,也不会从原始文本重新制造一次可能已取消的 full 提权。
|
|
326
364
|
|
|
@@ -403,6 +441,19 @@ schema v27 持久保存渠道进度句柄及待发送终态。终态先入账,
|
|
|
403
441
|
|
|
404
442
|
这是同码、事先保存的维护恢复;不提供代码升级,不恢复未知派发,不保证硬崩溃后任意指令继续,也不保证目标离线期间飞书消息不丢。独立接入进程仍是后续交付。外部 helper 与目标同 UID,不构成恶意代码的 OS 隔离;有宿主 shell 权限的模型仍须遵守既有 sandbox/Policy。每个任务最多申请一次,执行器还有时间窗重启次数上限;新建或经受管程序升级的 unit 同时限制 600 秒内最多 3 次启动,重复启动失败会停止并保留诊断,不无限抖动。同 Host 版本升级也会事务式迁移旧 unit 的启动限制,保留原启动命令和环境变量,失败回滚恢复原 unit 字节。通知或监督器在 120 秒内未接管则解除维护栅栏并报告失败;监督器重开不会重置已派发重启的观察期限。维护期间普通 `/status` 会随其它消息排队,`/stop`、`/new` 可直接撤销。额度是调用次数、单次输出和时间上限,不是精确总费用上限。
|
|
405
443
|
|
|
444
|
+
### 同进程重载 adapter(未接线)
|
|
445
|
+
|
|
446
|
+
`createInProcessReloadRuntime(ctx, options)` 是 control plane `in-process-reload` 合同的 Host 侧适配器。它**默认完全不生效**:`apply()` 不注册它,没有新配置字段、没有新工具、没有后台轮询,`--dump-config` 输出不变。它只导出工厂与类型,供未来 Host 接线使用。
|
|
447
|
+
|
|
448
|
+
能力边界:
|
|
449
|
+
|
|
450
|
+
- 只做 config/patch 重载:重读 profile 的 `cordis.yml` 并调用 Include 树的 `refresh()`/`await()`,让 pinned Loader 原地重启变化条目。已安装模块代码不会被重新导入(Loader 的 ESM import 有缓存),代码升级仍须走进程重启的既有 `reload` 路径;artifact 摘要变化由 control plane 直接拒绝。
|
|
451
|
+
- 探针而非声明:成功只在真实观察到 profile 摘要变化、同一 Fiber 原地重启(uid 不变、store 重建、active)、模块实例未替换、pid/InvocationID 未变、Host 进程代次未变、0 失败时成立;否则 `reloaded:false` + `failures>0`,调用方据此保持 `rollback-pending`。`fibersDisposed` 对原地重启恒为 0(没有 Fiber 进入 DISPOSED,旧 effect 在重新 `apply` 前已 dispose)。
|
|
452
|
+
- 代数:`hostGeneration` 必须由调用方注入(不自行发明);`inProcessGeneration` 由 adapter 单调维护,每次完成的挂载尝试 +1。无法解析 Loader/include root/目标 entry、目标包不匹配、目标要求进程重启、warrant 摘要非法、Host 代次变化都在触碰树之前拒绝。
|
|
453
|
+
- rollback 复用同一 warrant;没有调用方 `restore` 钩子证明 profile 已恢复时报告 `profileRestored:false`/`restored:false`,绝不声称恢复成功。
|
|
454
|
+
- 权限:只读取 profile 的 `cordis.yml` 并在既有 Cordis 树内重启 entry;不启动 subprocess、不访问网络、不写 ledger;不持有额外凭据或文件权限。
|
|
455
|
+
- 永不同进程热重载:control plane、assistant-delivery(本包)、assistant-isolation、lark-channel、改变依赖子树的插件、持有没有被证明的进程/cgroup 权限的插件。
|
|
456
|
+
|
|
406
457
|
## Goals 单次唤醒边界
|
|
407
458
|
|
|
408
459
|
Delivery 只向 Goals 的已注册 Host capability 提供一次受限恢复:它重读当前 owner route、binding、原 Session、GoalId、revision 和 deadline,在重新加载原 Session 后重查状态,仅在 Goals 的 dispatch CAS 成功后恢复原生目标。它不把历史 Session snapshot、runtime context 或任意 `user/message` 当作新的 owner 输入;DSH 会把 runtime context snapshot 持久化为 user-role message,它不能替代人类回合证明。
|
|
@@ -452,7 +503,7 @@ Host 可用 `inspectOwnerForegroundLearningTask()` 将 Evaluation 增量结果
|
|
|
452
503
|
|
|
453
504
|
原生 Goal 仍为 `active` 且 `armed` 时,空闲回收保留同一个 Agent 和 Session lease,允许宿主唯一 GoalRoundDriver 在会话保存完成后调度下一轮。目标终态或 disarm 后恢复普通空闲回收;owner 撤权、租约失效、scope 卸载和原有 `maxExecutionMs` 期限仍优先结束执行,不为每轮重置期限。若宿主缺少 GoalRoundDriver,armed 目标最多保持到该期限;此保留检查本身不派发任务。
|
|
454
505
|
|
|
455
|
-
当前 Web 只支持单已认证控制面的文本交互;图片、完整 queue/steer
|
|
506
|
+
当前 Web 只支持单已认证控制面的文本交互;图片、完整 queue/steer、以 linked 别名加入 Web owner 和子 Agent 历史仍未验收(外部渠道别名只读查询见上文 `inspectOwnerAliasRoute`)。原生 Web 安装、配置、Policy 与权限见 [Web owner 包说明](../assistant-web-owner/README.md),浏览器探针及证据边界见 [E2E 指南](../../scripts/e2e/README.md)。
|
|
456
507
|
|
|
457
508
|
可选 Host 接口 `registerForegroundTaskObserver()` 只接受当前 Control Plane 拥有的注册,在认证 Inbox 的执行绑定后同步通知开始,资源释放并保存真实执行回执后通知结束。它不改变 schema 23 或学习来源摘要,不注册模型工具;注销、owner/服务换代及重启后不补发历史事件,观察错误不影响正常聊天。部署版本与 readiness 核对由 [Control Plane](../plugin-control-plane) 持有;这些事件本身不证明任务质量或具体工具调用。
|
|
458
509
|
|
|
@@ -467,3 +518,76 @@ Host 编排可从 `@dsh-enhanced/assistant-delivery/types` 读取无服务初始
|
|
|
467
518
|
`enqueueOwnerNotification` 为可信 Host 插件提供限定主人路由、原会话、身份版本和有效期的提醒入队接口。普通 `enqueueBackground` 不能写入保留的 `dsh.native-notice*` 元数据。投递前重查当前主人、绑定版本与代次、路由、期限及背景 `send` Policy;过期、撤权或换代的队列不会发送。
|
|
468
519
|
|
|
469
520
|
原生 Web 使用本地适配器将通知标为可读取,并由 `assistant-web-owner` 的会话输入区展示。通知不写入 Session 历史,不触发模型,也不表示目标已完成;`accepted` 不表示用户已阅读。读取沿用固定 Web 主人能力,并再次核验上述边界;不另设消息 `read` Policy。其他渠道复用已有适配器。对于已发生但结果未知的外部发送,重启恢复仅通过适配器查询结果;查到过去已发送不表示再次发送,也不会为重发授予权限。
|
|
521
|
+
|
|
522
|
+
### 主人通知回复消费者(opt-in,默认无注册)
|
|
523
|
+
|
|
524
|
+
`registerOwnerNotificationReply` 允许 owner 通知来源的当前 Cordis 槽位注册一个回复消费者。Delivery 只在同时满足以下条件时把一条认证入站**纯文本**回复交给它:`replyToProviderMessageId` 唯一解析到一条 `accepted`/`delivered`/`read` 的 owner 通知(schema 的唯一索引保证;查询仍按最多两行拒绝歧义);通知元数据带 `dsh.native-notice`、规范来源和 `withdrawalAuthority`,与该消费者注册的 `sourceId` 及幂等键前缀匹配;回复来自当前 active binding、同一会话/主人,且通知入队时冻结的 owner 记录 id/version 仍是当前 owner 行;无附件且 UTF-8 文本不超过 256 字节;外部 `answer-attention-question` Policy 决策为 `allow`。不匹配、Policy 拒绝或消费者返回 `ignored` 时走普通入站路径;`applied` 时 Inbox 标为 `processed`,不再交给 Agent;`transient`(含消费者抛错)保持 `received`/`authorized`,等待 provider 重投或同会话下一条消息触发的 pending 恢复重试。恢复中遇到 `transient` 会停止本轮恢复,较旧的待处理回复仍留在队首。
|
|
525
|
+
|
|
526
|
+
消费者按 `(authority, sourceId)` 至多一个,注册对象必须由 `authority` 槽位当前服务通过 `ownsOwnerNotificationReply` 亲自担保;槽位换服务后新的担保注册接管,`unregister` 后旧注册立即不再匹配。该接口只读取认证回复并更新 Inbox 状态,不新增发送权限、不调用网络或模型,也不保存回复正文到新表;正文仅在本次回调中交给消费者。已撤回(`dead`)、未发送或 unknown 状态的通知不能被回复匹配,这类回复按普通消息处理;附件、命令、超过 256 字节或无法唯一解析的引用同样不匹配。Evaluation 的 WP22 切片 5 是本接口的当前唯一使用方(精确 `authorize-once`/`decline` 语义见其 README)。
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
## WorkItems 报告回复交接
|
|
530
|
+
|
|
531
|
+
schema 29 保存 typed WorkItems 报告 sidecar、不可变回复原文、独占 Inbox 交接与 stream head。仅当前 WorkItems 自有注册校验通过的真实报告可经 `enqueueWorkItemReport` 建立关联;普通 metadata 不授予报告身份。功能默认关闭,开启条件和权限见[回复报告后自动继续(显式启用)](../assistant-work-items/README.md#回复报告后自动继续显式启用)。
|
|
532
|
+
|
|
533
|
+
同一会话的 owner 纯文本回复须匹配唯一、已 accepted/delivered/read 的 provider 消息,并通过当前 owner、binding、scope 和外部 `continue-work-items-from-reply` Policy 检查。交接在一笔事务中保存原文来源并将 Inbox 标为 processed;此状态仅表示独占交接,不代表任务成功。已交接输入在 peer 卸载、重启或失败后不会转回前台;原文含敏感输入时也会持续保存在本机私有 Delivery 数据库中。
|
|
534
|
+
|
|
535
|
+
父项选择冻结当前 stream head;只有校验 WorkItems 的持久 child 记录并 ACK 后才推进 head,ACK 后仍可读取原文与摘要。后续回复保留原报告目标与实际执行父项的区别。`/stop`、`/new`、`/clear` 先持久取消较早来源,再通知已关联 child;取消不撤销已经开始的工具。相同 owner 会话的新代次可回复旧报告,旧来源不会因此恢复授权。未知发送、通用或未验证报告、命令和附件保留普通处理路径。
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
## 主人对 WorkItems 报告的结果反馈
|
|
539
|
+
|
|
540
|
+
schema 30 为显式启用 `ownerReportFeedback` 的 WorkItems 保存独占反馈意图、原文摘要、冻结 CAS 与稳定 operation ID,保持 schema 29 的回复队列和 stream head 原样。真实 typed 报告的主人回复“问题解决了”“还是不行”,以及 `/feedback achieved|partial|not-achieved`、`status`、`correct`、`withdraw`,先进入结果反馈路径;它们评价原报告 itemId,不评价后续续办子项。权限是独立的 external `feedback-work-items`,不消费执行额度;反馈功能本身不启用 continuation。
|
|
541
|
+
|
|
542
|
+
生产终态、静止及预算结算证明尚未就绪时,反馈持久等待,不伪造成功、不派新 worker。结果是主人证言,不是独立 verifier 验收;更正和撤回使用冻结版本 CAS,重投、冷恢复或丢失 ACK 不增加票数。`/stop`、`/new`、`/clear` 持久取消较早未完成意图。实际状态通过既有 background send 权限发送稳定 ACK;没有票的 `status` 明确返回暂无反馈,不造 revision。发送拒绝或 unknown 不回滚已记录结果、不盲目重发。
|
|
543
|
+
|
|
544
|
+
可选 `naturalFeedback.coverage`(默认关闭)对该入口同样生效:报告回复可以是同义/多语言结果并附带原因(“现在可以正常用了,谢谢”“返回值仍然是空的,请检查分页”),后台仍只做确定性分类,不把任意文本当结果、不调用模型。可选 `naturalFeedback.mixedIntent`(默认关闭,依赖 `coverage`)把一条混合回复拆成两件事:先按独立的 `feedback-work-items` 权限形成 canonical 结果证据(既有 feedback intent → Evaluation 通道),再按独立的 `continue-work-items-from-reply` 权限把同一原文放进既有续办队列。两件事沿用同一 Inbox 的确定性幂等键,并各自重验当前 owner/binding/report/Policy 与目标绑定;两件都允许时在同一个 Delivery 事务内原子写入(结果行拥有唯一 Inbox handoff,续办行复用已处理 Inbox),任一侧未授权或写入不可用时只做允许的一件,并通过 Host 日志记录 `continuation-not-admitted` / `feedback-not-admitted` / `neither-lane-admitted`。该拆分不新增 schema、无新 Loop/timer、无模型调用;关闭时“还是不行,继续修复”仍沿用旧行为(只进续办队列、不写 canonical 结果),而纯结果回复(“问题解决了”“还是不行”)不会因为该开关变成一次执行。
|
|
545
|
+
|
|
546
|
+
Host-only `inspectOwnerWorkItemLearningTask` 使用独立 `assistant-delivery/owner-work-item-learning/v1` 协议,重验当前主人、报告生产者、全量 WorkItems proof 与 canonical owner 修订。返回去正文的 `proofIdentity`,其 proofDigest 绑定内部原文;`presentation` 的 brief/report/feedback 独立限长与常见凭据过滤,presentationDigest 不冒充原文摘要。sourceDigest 绑定持久来源及修订,不绑定读取时的新 Session 代次;同主人 `/new` 后仍可召回已记录反馈,撤回、更正、换主人或失效证明会拒绝旧来源。它不冒充前台来源,不授予学习、采用或修复执行权限;Growth 后续消费仍是另一项能力。
|
|
547
|
+
|
|
548
|
+
## 注意力合同(WP19 第 1 阶段:审计)
|
|
549
|
+
|
|
550
|
+
schema 31 新增只追加的 `delivery_attention_audit`,按 outbox id 去重,重投保留首次判定。审计尽力而为:入队提交后另起事务写审计行,审计失败不影响入队与发送,因此可能存在没有审计行的 Outbox(缺口检测见下)。覆盖 `enqueueBackground`、`enqueueBackgroundRoute`、`enqueueOwnerNotification`(含内部 ACK 等走同一后台通道的发送)与 typed 结果通道 `enqueueAutomationResult`、`enqueueWorkItemReport`、定时 Goal 结果。前三者可传可选 `attention` 信封:`result`;`attention` 须绑定 `workItemId` 与恰好一个结构化 `question`(id、prompt、可选 2–8 个 choices);`answer` 须引用本 binding 已问过的 `questionId`,且只能用一次。同一工作项已有未答问题时,再问另一问题记为不是当前问题。问题首次被接受时记录其 `workItemId`:同一 question id 换到其他工作项再问记 `attention-question-reused`;answer 声明的 `workItemId` 与问题所属工作项不同记 `answer-work-item-mismatch`(均为 would-reject),未声明时审计行沿用问题的工作项。typed 通道记为 `lane` 来源的 `result`;未声明的旧调用方按 `result` 记录并标 `missing-purpose`。
|
|
551
|
+
|
|
552
|
+
问答账本按 `binding_id` 划分:重新配对或 binding 轮换产生新 binding 后,旧 binding 上问过的问题对新 binding 视为未知,其 answer 记 `answer-unknown-question`,旧的未答问题也不再阻止新 binding 上的提问。本阶段只审计,接受这一限制。
|
|
553
|
+
|
|
554
|
+
字数 = `Intl.Segmenter('und', { granularity: 'word' })` 的 isWordLike 片段数,加上非单词片段中除空白、标点与 ASCII 之外的字素数(如 emoji、图形符号,每个计 1),CJK 按 ICU 切分,链接文字与 URL 一并计入。硬上限:result 400、attention 120、answer 200(`attentionWordCaps`);另按非空白字素数设第二道上限:result 2400、attention 720、answer 1200(`attentionGraphemeCaps`,约 6 倍字数上限),以覆盖一段数千字符不断开的 token(只算 1 个词)等情况。任一超限判为 `would-attach`(`over-word-cap` / `over-grapheme-cap`)。切分依赖运行中 Node.js 自带的 ICU 数据,Node/ICU 升级可能改变同一文本的计数;已记录的判定不重算。原因码见 `attentionAuditReasons`;其中 `text-exposes-estimate`、`text-exposes-identifier` 只记录现有提醒外露估值或 id,本阶段不改文本。
|
|
555
|
+
|
|
556
|
+
本阶段不改变任何发送(强制见第 3 阶段):判定为 `would-reject` 或 `would-attach` 的消息照常入队、原文发送。`inspectAttentionAudit({ afterSequence?, limit? })` 按序分页只读返回判定(默认 100、最多 500),不含正文,并附两项缺口指标:`processLocalWriteFailures` 是本进程启动以来的审计写入失败数,重启清零;`unauditedOutbox` 每次由持久数据查询得出,统计首条审计行之后创建、带审计通道持久标记(owner 通知、owner route、Automation 结果、Goal 结果、WorkItem 报告)却没有审计行的 Outbox。普通 `enqueueBackground` 行没有持久通道标记,不计入 `unauditedOutbox`,只能由进程内计数发现;首条审计行之前的缺口也无法发现。审计表无保留期与清理,任何未来的保留策略都需新 schema。回复与审批通道不在本阶段范围。
|
|
557
|
+
|
|
558
|
+
### 第 2b 阶段:超长转附件与拒绝拆条(opt-in,默认关闭)
|
|
559
|
+
|
|
560
|
+
配置 `attentionAttachOverCap: true` 后,`enqueueBackground`、`enqueueBackgroundRoute`、`enqueueOwnerNotification`(及走同一后台通道的 WorkItem 报告)在入队前处理;默认关闭时行为与第 1 阶段完全一致。typed Automation/Goal 结果通道不转换,只审计。
|
|
561
|
+
|
|
562
|
+
- 超出所属目的字数或字素上限的通知改为一条消息:短正文(最多 60 词、360 非空白字素的整单元前缀,URL 与 Markdown 链接整体保留或整体移出,绝不截断)加固定说明 `(全文较长,共 N 词,已转为附件 notice-<sha256 前 12 位>.txt|md)`,format 为 `plain`;原文完整放入 `intent.attachment`(`kind: 'text'`、`mediaType` 随原 format、`sha256` 绑定原文)。转换为纯函数 `convertOverCapAttention`,同一原文逐字节相同;同一幂等键重放返回原记录。链接文字与 URL 计入上限。
|
|
563
|
+
- 通道适配器须声明 `capabilities.textAttachments: true`;未声明时超长通知在入队时以 `policy-denied` 拒绝,不入队、不拆条;无适配器时为 `runtime-unavailable`。Coordinator 另有兜底:带附件的 Outbox 遇到不支持附件的适配器直接 `dead`(`attachment-unsupported`),绝不只发摘要。仓库内现有适配器(飞书、web)均未声明该能力。
|
|
564
|
+
- 拒绝拆条:同一 binding、同一通道、同一来源在 `attentionSplitWindowMs`(5 分钟)内已审计的内联正文,与本条合计超过本条目的上限时,以 `policy-denied`(`attention split evasion`)拒绝;单条不受影响,补救方式是发一条(超长则自动转附件)。窗口按审计行持久化的 `recorded_at` 与 Delivery Store 时钟比较,重启不会重置。判断依赖尽力而为的审计行,审计写入失败的通知不计入(可由 `processLocalWriteFailures` 发现)。关闭开关后,新通知按第 1 阶段原样入队,已转换的幂等键重放仍返回原记录。
|
|
565
|
+
- Store 校验附件:仅 `plain` intent,键集固定,名称 `[A-Za-z0-9][A-Za-z0-9._-]{0,127}`,正文非空且不超过 `maxTextBytes`,`sha256` 与正文一致。附件存于 `intent_json`,不改 schema(仍为 31)。审计按附件原文计词,因此转换后的行仍记 `would-attach`。
|
|
566
|
+
|
|
567
|
+
### 第 3 阶段:目的强制(opt-in,默认关闭)
|
|
568
|
+
|
|
569
|
+
配置 `attentionEnforce: true` 后,`enqueueBackground`、`enqueueBackgroundRoute`、`enqueueOwnerNotification` 在入队前按第 1 阶段判定强制;WorkItem 只有 typed 报告通道(`enqueueWorkItemReport`)由通道声明 `result`,因此只受上限约束(仅上限),走 `enqueueBackground` 的非 typed 报告按普通后台通知强制。判定与拒绝发生在 Policy 授权之前,被拒绝的通知不写 Policy 审计行、不扣预算。默认关闭时行为与错误文案与第 2b 阶段完全一致。typed Automation/Goal 结果通道、前台进度、回复与审批通道不受影响。
|
|
570
|
+
|
|
571
|
+
- 目的缺失(`missing-purpose`)或任一 would-reject 原因(`invalid-envelope`、`attention-missing-work-item`、`attention-question-*`、`answer-*`)直接拒绝:抛 `AttentionRejectedError`(`code: 'policy-denied'`,`reasons` 为结构化原因码),不入队、不写 Outbox。`text-exposes-*` 仍只审计。
|
|
572
|
+
- 超出字数或字素上限:`attentionAttachOverCap` 开时走第 2b 附件路径;关时以 `over-word-cap` / `over-grapheme-cap` 拒绝。开启附件但适配器不支持时原因为 `attachment-unsupported`,拆条为 `split-evasion`(错误信息与第 2b 相同)。仅开强制不增加拆条检查。
|
|
573
|
+
- 已存在 Outbox 的幂等键重放在任何检查之前返回原记录,切换开关或重启都不改变已入队的键;被拒绝的键不进入问答账本,重试按同一持久账本重新判定。Host 自己发出的结果 ACK 与 Goal 完成提醒在强制开启时声明 `result`。
|
|
574
|
+
- 「一次有效问题」与「当前唯一问题」的强制依据是尽力而为的 v31 审计行:审计写入失败的通知不进入账本,会留下缺口(之后的重复或第二个问题可能不被拒绝),可通过 `inspectAttentionAudit` 的 `processLocalWriteFailures` 发现。
|
|
575
|
+
- 被拒绝的通知没有 Outbox 行,而 v31 审计表以 `outbox_id` 为主键并外键到 Outbox、`verdict` 为封闭集合,容纳不了 `rejected`;为不改 schema(仍为 31),拒绝记录在进程内有界日志(最近 1000 条,同键同原因的重试只记一次),`inspectAttentionRejections({ afterSequence?, limit? })` 只读分页(默认 100、最多 500),不含正文,返回 `durable: false` 与 `evicted`,Host 重启清零。
|
|
576
|
+
- 开启前须确认调用方都已声明目的。仓库内仍有以下未声明目的的调用方,开启后它们的通知以 `missing-purpose` 被拒绝:
|
|
577
|
+
- `assistant-work-items/src/dispatch.ts`(约 256 行)非 typed 报告路径 `enqueueBackground`:被拒后 WorkItems 将该报告修订记为 `failed`(`policy-denied`);
|
|
578
|
+
- `assistant-actions/src/service.ts`(约 833 行)已验证投递后的 `enqueueOwnerNotification`;
|
|
579
|
+
- `assistant-automations/src/coordinator.ts`(约 882 行)incident 告警 `enqueueBackground`,以及 `assistant-automations/src/service.ts`(约 688/694 行)转发 `enqueueBackground` / `enqueueBackgroundRoute` 的 dispatcher(调用方未带 `attention` 时同样被拒);
|
|
580
|
+
- `assistant-skills/src/repair-feedback.ts`(约 135 行)修复反馈 `enqueueOwnerNotification`(被拒后返回 `delivery-rejected`)。
|
|
581
|
+
|
|
582
|
+
### 通知结果事实(WP22 切片 1,只读)
|
|
583
|
+
|
|
584
|
+
`inspectNotificationOutcomeFacts({ afterSequence?, limit? })` 按审计序号分页(默认 100、最多 500),`inspectNotificationOutcomeFacts({ outboxIds })` 按 id 精确查(最多 500,不可与分页参数混用,未知或未审计 id 省略)。每条事实只含审计判定、binding 的 workspace/preset、传输状态(首次 accepted 时间取 attempt,其次 receipt,最后 `updated_at`;delivered/read 取 receipt,否则状态回退)、以 `replyToProviderMessageId` 精确引用该消息的入站回复首次时间与条数(同一会话、同一 principal,含新会话命令轮换后的新 binding),以及最新已记录的工作项反馈,或无错误的 owner 目标命令(无命令时取旧版已验证任务回执作为版本 1,与 Delivery 自身目标状态一致)。回复与工作项反馈的 JSON 查找每次调用整批一次。不返回消息或回复正文,不写库,不改 schema。
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
### 进度来源与进度审计(WP19 第 2c 阶段)
|
|
588
|
+
|
|
589
|
+
`DeliveryProgressIntent` 新增可选 `origin: 'foreground' | 'background'`,缺省视为 foreground。认领本条入站消息的轮次、其自动补全轮次,以及 Delivery 自己发出的 `started` 与终态为 foreground;入站处理期间同一 Session 上其他轮次(主要是原生 Goal 续跑轮次,以及认领前已在运行的轮次)为 background。不带 `turn` 的事件(审批、todo)归属最近打开的轮次。adapter 应默认隐藏非终态 background 进度,且不得为 background 的 `started` 新开进度面板;终态始终送达,以便关闭已有前台面板。
|
|
590
|
+
|
|
591
|
+
每条进度在交给 adapter 前审计一次,按 `lane` 来源的 `result` 计:字数与字素按一次运行(binding + eventId + origin)累计,超过 `attentionWordCaps.result` / `attentionGraphemeCaps.result` 记 `would-attach`,拆成多条气泡不能规避;估值与 id 外露原因码在本次运行内保持。计量文本取 adapter 可能展示的上界(步骤、待办、工具名与参数、结果预览、错误码),与通道详情模式无关。`inspectProgressAttentionAudit({ afterSequence?, limit? })` 只读分页(默认 100、最多 500),不含正文,返回 `durable: false`、环形淘汰数 `evicted` 与 `processLocalWriteFailures`。审计只记录,不改变进度发送。
|
|
592
|
+
|
|
593
|
+
v31 `delivery_attention_audit` 以 `outbox_id` 为主键并外键到 Outbox,`lane` 为封闭集合,进度不是 Outbox 行,因此未复用该表、未改 schema:进度审计只保存在本进程内(最近 1000 条、最多 256 个未结束运行),Host 重启清零。
|
package/lib/agent-runtime.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { type SessionEvent } from '@deepseek-ai/dsh-session';
|
|
|
14
14
|
import { type AssistantPolicyService } from '@dsh-enhanced/assistant-policy';
|
|
15
15
|
import type { InboundPrepareContext, InboundPrepareResult, InboundProcessResult, MarkInboundDispatching, PreparedInboundMessage } from './coordinator.js';
|
|
16
16
|
import type { AcceptanceHandle } from './acceptance.js';
|
|
17
|
+
import type { ForegroundTerminationObservation } from './foreground-termination.js';
|
|
17
18
|
import type { FeedbackSignalSelection, ObjectiveCommand, ObjectiveCommandResult } from './feedback-command.js';
|
|
18
19
|
import type { InboundImageMaterializer } from './inbound-images.js';
|
|
19
20
|
import type { DeliveryInboundRuntime } from './service.js';
|
|
@@ -23,7 +24,7 @@ import { type OwnerApprovalStatusRead } from './approval-status-context.js';
|
|
|
23
24
|
import type { DeliverySessionLeases } from './session-lease-runtime.js';
|
|
24
25
|
import { type DeliveryGoalWakeInput, type DeliveryGoalWakeResult } from './goal-wake-types.js';
|
|
25
26
|
import { type WorkflowCommand } from './workflow-command.js';
|
|
26
|
-
import type { ConversationBinding, ConversationModelSelection, ConversationRef, DeliveryProgressUpdate, DeliveryLearningControlAction, DeliveryLearningControlReceipt, DeliveryPreferenceEvent, InboundEnvelope, ModelPickerIntent, ModelRouteRef, PermissionPickerIntent } from './types.js';
|
|
27
|
+
import type { ConversationBinding, ConversationModelSelection, ConversationRef, DeliveryProgressOrigin, DeliveryProgressUpdate, DeliveryLearningControlAction, DeliveryLearningControlReceipt, DeliveryPreferenceEvent, InboundEnvelope, ModelPickerIntent, ModelRouteRef, PermissionPickerIntent } from './types.js';
|
|
27
28
|
declare module '@deepseek-ai/dsh-llm' {
|
|
28
29
|
interface MessageSourceMap {
|
|
29
30
|
delivery: {
|
|
@@ -80,6 +81,7 @@ interface DshDeliveryRuntimeOptions {
|
|
|
80
81
|
completeForegroundTaskExecution(inboxId: string, input: {
|
|
81
82
|
status: 'succeeded' | 'unknown';
|
|
82
83
|
quiescent: boolean;
|
|
84
|
+
termination?: Readonly<ForegroundTerminationObservation>;
|
|
83
85
|
}): void;
|
|
84
86
|
permissionPickerTtlMs: number;
|
|
85
87
|
getModelSelection(conversation: ConversationRef): ConversationModelSelection | undefined;
|
|
@@ -125,7 +127,9 @@ interface DshDeliveryRuntimeOptions {
|
|
|
125
127
|
selection?: ConversationModelSelection;
|
|
126
128
|
};
|
|
127
129
|
modelPickerTtlMs: number;
|
|
128
|
-
progress(binding: Readonly<ConversationBinding>, eventId: string, update: DeliveryProgressUpdate
|
|
130
|
+
progress(binding: Readonly<ConversationBinding>, eventId: string, update: DeliveryProgressUpdate,
|
|
131
|
+
/** WP19 stage 2c: `background` for session turns other than the claimed foreground turns. */
|
|
132
|
+
origin: DeliveryProgressOrigin): Promise<void>;
|
|
129
133
|
replyCommand(binding: Readonly<ConversationBinding>, eventId: string, input: ModelCommandReply, idempotencyKey?: string): void;
|
|
130
134
|
}
|
|
131
135
|
interface ModelCommandReply {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-runtime.d.ts","sourceRoot":"","sources":["../src/agent-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,gBAAgB;QACxB,oBAAoB,EAAE;YAAE,IAAI,EAAE,oBAAoB,CAAC;YAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACxF;CACF;AAKD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAEL,KAAK,KAAK,EAGX,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,mBAAmB,IAAI,YAAY,EAAE,MAAM,wCAAwC,CAAA;AAcjG,OAAO,EAAiD,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAK3G,OAAO,EAKL,KAAK,sBAAsB,EAC5B,MAAM,gCAAgC,CAAA;AAEvC,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EAEpB,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"agent-runtime.d.ts","sourceRoot":"","sources":["../src/agent-runtime.ts"],"names":[],"mappings":"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"}
|
package/lib/agent-runtime.js
CHANGED
|
@@ -10,6 +10,7 @@ import { setApprovalPolicy, } from '@deepseek-ai/dsh-user-approval';
|
|
|
10
10
|
import { approvalReviewerOf, setApprovalReviewer, waitForApprovalReviewerSessionEventReady, } from '@dsh-enhanced/assistant-policy';
|
|
11
11
|
import { resolveLlmRouteCapability } from '@dsh-enhanced/llm-route-capabilities';
|
|
12
12
|
import { externalPrincipalId } from './canonical.js';
|
|
13
|
+
import { observeNativeTermination } from './native-termination.js';
|
|
13
14
|
import { feedbackSignalInput, feedbackUsage, parseFeedbackCommand, } from './feedback-command.js';
|
|
14
15
|
import { objectiveStateMessage } from './feedback-command.js';
|
|
15
16
|
import { learningCommandUsage, parseLearningCommand, serializeLearningExport, } from './learning-command.js';
|
|
@@ -463,23 +464,23 @@ function permissionPickerGuard(envelope) {
|
|
|
463
464
|
function permissionPresetTargets(service) {
|
|
464
465
|
const workspace = [];
|
|
465
466
|
const full = [];
|
|
466
|
-
const nativeAuto = [];
|
|
467
467
|
const table = [];
|
|
468
468
|
for (const name of service.names) {
|
|
469
469
|
const spec = service.resolve(name);
|
|
470
470
|
table.push([name, spec.sandbox, spec.approval]);
|
|
471
|
+
// Keep the reserved Harness preset in the picker fence, but never select it.
|
|
472
|
+
if (name === 'auto')
|
|
473
|
+
continue;
|
|
471
474
|
if (spec.sandbox === 'workspace-write' && spec.approval === 'ask')
|
|
472
475
|
workspace.push(name);
|
|
473
476
|
if (spec.sandbox === 'danger-full-access' && spec.approval === 'never')
|
|
474
477
|
full.push(name);
|
|
475
|
-
if (name === 'auto' && spec.sandbox === 'danger-full-access' && spec.approval === 'ask')
|
|
476
|
-
nativeAuto.push(name);
|
|
477
478
|
}
|
|
478
|
-
if (workspace.length > 2 || full.length > 1
|
|
479
|
+
if (workspace.length > 2 || full.length > 1) {
|
|
479
480
|
throw new Error('ambiguous permission preset table');
|
|
480
481
|
}
|
|
481
482
|
const ask = workspace[0];
|
|
482
|
-
const auto =
|
|
483
|
+
const auto = workspace[1] ?? ask;
|
|
483
484
|
return {
|
|
484
485
|
...(ask === undefined ? {} : { ask, auto: auto }),
|
|
485
486
|
...(full[0] === undefined ? {} : { full: full[0] }),
|
|
@@ -514,6 +515,8 @@ async function appendApprovalReviewer(session, reviewer) {
|
|
|
514
515
|
}
|
|
515
516
|
function currentPermissionLevel(service, targets, session) {
|
|
516
517
|
const events = session.snapshotEvents();
|
|
518
|
+
if (events.findLast(event => event.type === 'permission/preset')?.data.preset === 'auto')
|
|
519
|
+
return 'custom';
|
|
517
520
|
const current = service.current(session);
|
|
518
521
|
const reviewer = approvalReviewerOf(events, session.header.version);
|
|
519
522
|
if (current === targets.full) {
|
|
@@ -540,14 +543,19 @@ function currentPermissionLevel(service, targets, session) {
|
|
|
540
543
|
function canonicalPresetReviewer(name) {
|
|
541
544
|
if (name === 'workspace-write')
|
|
542
545
|
return 'user';
|
|
543
|
-
if (name === 'auto')
|
|
544
|
-
return 'auto-review';
|
|
545
546
|
if (name === 'danger-full-access')
|
|
546
547
|
return 'none';
|
|
547
548
|
return undefined;
|
|
548
549
|
}
|
|
549
550
|
async function ensurePermissionReviewer(session, preset, reviewer) {
|
|
550
|
-
|
|
551
|
+
let events = session.snapshotEvents();
|
|
552
|
+
if (events.findLast(event => event.type === 'permission/preset')?.data.preset === 'auto') {
|
|
553
|
+
// Native set can be a no-op when the knobs already match the target.
|
|
554
|
+
// Supersede the stale reserved selector before opting into project review.
|
|
555
|
+
session.append('permission/preset', { preset });
|
|
556
|
+
events = session.snapshotEvents();
|
|
557
|
+
}
|
|
558
|
+
if (approvalReviewerOf(events, session.header.version) === reviewer)
|
|
551
559
|
return;
|
|
552
560
|
if (canonicalPresetReviewer(preset) === reviewer) {
|
|
553
561
|
// PermissionPresetService deliberately makes a net-zero selection a no-op.
|
|
@@ -2271,7 +2279,7 @@ export class DshDeliveryRuntime {
|
|
|
2271
2279
|
permissionPresets.set(session, target);
|
|
2272
2280
|
// Legacy/seeded sessions may have no explicit knob events even when
|
|
2273
2281
|
// their effective defaults match this preset. Materialize both facts
|
|
2274
|
-
// before
|
|
2282
|
+
// before changing the project reviewer inside the workspace sandbox.
|
|
2275
2283
|
ensureSandboxMode(session, permissionPresets.resolve(target).sandbox);
|
|
2276
2284
|
ensureApprovalPolicy(session, 'ask');
|
|
2277
2285
|
const reviewer = action.level === 'auto' ? 'auto-review' : 'user';
|
|
@@ -3593,6 +3601,8 @@ export class DshDeliveryRuntime {
|
|
|
3593
3601
|
let dispatched = false;
|
|
3594
3602
|
let acceptance;
|
|
3595
3603
|
let foregroundExecution;
|
|
3604
|
+
let foregroundTurn;
|
|
3605
|
+
let terminationCause;
|
|
3596
3606
|
let removeAcceptanceRequest;
|
|
3597
3607
|
let acceptanceSucceeded = false;
|
|
3598
3608
|
let completionPending = false;
|
|
@@ -3618,7 +3628,18 @@ export class DshDeliveryRuntime {
|
|
|
3618
3628
|
clearTimeout(timeout);
|
|
3619
3629
|
}
|
|
3620
3630
|
};
|
|
3621
|
-
|
|
3631
|
+
// WP19 stage 2c: only turns that claimed this inbound message (or one of its
|
|
3632
|
+
// automatic completion notices) are foreground. Native Goal continuation
|
|
3633
|
+
// rounds keep this listener attached until the fence settles, and a turn
|
|
3634
|
+
// that was already running before the claim also reaches it; both are
|
|
3635
|
+
// background. Events without `data.turn` inherit the latest opened turn.
|
|
3636
|
+
const foregroundTurns = new Set();
|
|
3637
|
+
let currentSessionTurn;
|
|
3638
|
+
const claimForegroundTurn = (turn) => {
|
|
3639
|
+
foregroundTurn = turn;
|
|
3640
|
+
foregroundTurns.add(turn);
|
|
3641
|
+
};
|
|
3642
|
+
const publishProgress = (update, origin = 'foreground') => {
|
|
3622
3643
|
const terminal = update.kind === 'completed' || update.kind === 'failed' || update.kind === 'paused';
|
|
3623
3644
|
if ((!progressOpen && !terminal) || progressTerminal)
|
|
3624
3645
|
return;
|
|
@@ -3627,7 +3648,7 @@ export class DshDeliveryRuntime {
|
|
|
3627
3648
|
const publish = async () => {
|
|
3628
3649
|
if ((!terminal && progressTerminal) || checkAuthorization() !== 'authorized')
|
|
3629
3650
|
return;
|
|
3630
|
-
await this.options.progress(binding, envelope.eventId, update);
|
|
3651
|
+
await this.options.progress(binding, envelope.eventId, update, origin);
|
|
3631
3652
|
};
|
|
3632
3653
|
// Terminal journaling must not wait behind a slow provider's step updates.
|
|
3633
3654
|
// The adapter preserves provider ordering after staging the durable result.
|
|
@@ -3674,6 +3695,12 @@ export class DshDeliveryRuntime {
|
|
|
3674
3695
|
removeProgress = this.ctx.on('session/event', (session, event) => {
|
|
3675
3696
|
if (session !== agent.session)
|
|
3676
3697
|
return;
|
|
3698
|
+
const eventTurn = 'turn' in event.data && typeof event.data.turn === 'number' ? event.data.turn : undefined;
|
|
3699
|
+
if (event.type === 'turn/start' || event.type === 'step/start')
|
|
3700
|
+
currentSessionTurn = eventTurn;
|
|
3701
|
+
const progressTurn = eventTurn ?? currentSessionTurn;
|
|
3702
|
+
const progressOrigin = progressTurn !== undefined && foregroundTurns.has(progressTurn)
|
|
3703
|
+
? 'foreground' : 'background';
|
|
3677
3704
|
if (event.type === 'step/start') {
|
|
3678
3705
|
const automaticKind = automaticCompletionTurns.get(event.data.turn);
|
|
3679
3706
|
if (automaticKind !== undefined) {
|
|
@@ -3695,7 +3722,7 @@ export class DshDeliveryRuntime {
|
|
|
3695
3722
|
return;
|
|
3696
3723
|
const update = deliveryProgressFromSessionEvent(event);
|
|
3697
3724
|
if (update !== undefined)
|
|
3698
|
-
publishProgress(update);
|
|
3725
|
+
publishProgress(update, progressOrigin);
|
|
3699
3726
|
});
|
|
3700
3727
|
publishProgress({ kind: 'started' });
|
|
3701
3728
|
const abort = () => {
|
|
@@ -3756,7 +3783,7 @@ export class DshDeliveryRuntime {
|
|
|
3756
3783
|
kind: 'delivery', channel: envelope.channel, account: envelope.account, eventId: envelope.eventId,
|
|
3757
3784
|
trust: 'untrusted',
|
|
3758
3785
|
} }) : createRestartContinuation({ continuationId: restartContinuation.id, text: restartContinuationText });
|
|
3759
|
-
let deliveryTurn = await this.followupTurn(agent, message,
|
|
3786
|
+
let deliveryTurn = await this.followupTurn(agent, message, claimForegroundTurn, undefined, restartContinuation === undefined ? undefined
|
|
3760
3787
|
: () => admitRestartContinuation(agent, message, { signal,
|
|
3761
3788
|
authorize: () => {
|
|
3762
3789
|
this.sessionLeases.assert(String(agent.session.id));
|
|
@@ -3769,6 +3796,10 @@ export class DshDeliveryRuntime {
|
|
|
3769
3796
|
restart.onContinuationAdmitted(restartContinuation, String(agent.session.id));
|
|
3770
3797
|
},
|
|
3771
3798
|
}), signal);
|
|
3799
|
+
if (deliveryTurn !== undefined)
|
|
3800
|
+
claimForegroundTurn(deliveryTurn);
|
|
3801
|
+
else
|
|
3802
|
+
foregroundTurn = deliveryTurn;
|
|
3772
3803
|
if (restartRun?.requested() !== undefined) {
|
|
3773
3804
|
await this.waitForAgentIdle(agent, signal);
|
|
3774
3805
|
restartCheckpoint = await restartRun.checkpoint();
|
|
@@ -3809,6 +3840,7 @@ export class DshDeliveryRuntime {
|
|
|
3809
3840
|
const automaticToolViolation = deliveryTurn !== undefined
|
|
3810
3841
|
&& automaticCompletionToolViolations.has(deliveryTurn);
|
|
3811
3842
|
if (cancelled !== undefined || (output.stopped && !automaticToolViolation)) {
|
|
3843
|
+
terminationCause = cancelled === 'new' ? 'owner-new-session' : 'owner-stop';
|
|
3812
3844
|
publishProgress({ kind: 'failed', code: cancelled === 'new' ? 'new-session' : 'user-stopped' });
|
|
3813
3845
|
return { outcome: 'processed' };
|
|
3814
3846
|
}
|
|
@@ -3848,7 +3880,7 @@ export class DshDeliveryRuntime {
|
|
|
3848
3880
|
});
|
|
3849
3881
|
completionKind = nextKind;
|
|
3850
3882
|
try {
|
|
3851
|
-
deliveryTurn = await this.automaticCompletionTurn(agent, completionMessage, signal, deliveryTurn, checkAuthorization, turn => automaticCompletionTurns.set(turn, nextKind));
|
|
3883
|
+
deliveryTurn = await this.automaticCompletionTurn(agent, completionMessage, signal, deliveryTurn, checkAuthorization, turn => { claimForegroundTurn(turn); automaticCompletionTurns.set(turn, nextKind); });
|
|
3852
3884
|
}
|
|
3853
3885
|
catch (error) {
|
|
3854
3886
|
if (error instanceof AutomaticCompletionAuthorizationError) {
|
|
@@ -3861,6 +3893,7 @@ export class DshDeliveryRuntime {
|
|
|
3861
3893
|
signal.throwIfAborted();
|
|
3862
3894
|
const cancellation = this.activeSessionControls.get(binding.sessionId)?.command;
|
|
3863
3895
|
if (cancellation !== undefined) {
|
|
3896
|
+
terminationCause = cancellation === 'new' ? 'owner-new-session' : 'owner-stop';
|
|
3864
3897
|
publishProgress({ kind: 'failed', code: cancellation === 'new' ? 'new-session' : 'user-stopped' });
|
|
3865
3898
|
return { outcome: 'processed' };
|
|
3866
3899
|
}
|
|
@@ -3977,6 +4010,7 @@ export class DshDeliveryRuntime {
|
|
|
3977
4010
|
}
|
|
3978
4011
|
catch (error) {
|
|
3979
4012
|
if (causedByUserCancellation(error)) {
|
|
4013
|
+
terminationCause = this.activeSessionControls.get(binding.sessionId)?.command === 'new' ? 'owner-new-session' : 'owner-stop';
|
|
3980
4014
|
if (handle !== undefined && !await sessions.flush(handle.agent.session)) {
|
|
3981
4015
|
return { outcome: 'not-processed', failureCode: 'session-flush-failed', retryable: false };
|
|
3982
4016
|
}
|
|
@@ -3986,6 +4020,7 @@ export class DshDeliveryRuntime {
|
|
|
3986
4020
|
}
|
|
3987
4021
|
if (dispatched) {
|
|
3988
4022
|
const timedOut = signal.reason instanceof AgentTaskTimeoutError;
|
|
4023
|
+
terminationCause = timedOut ? 'execution-timeout' : 'runtime-error';
|
|
3989
4024
|
publishProgress({ kind: 'failed', ...(timedOut
|
|
3990
4025
|
? { code: 'agent-task-timeout' } : {}) });
|
|
3991
4026
|
// Preserve an exact durable diagnosis so the existing interruption
|
|
@@ -4049,8 +4084,19 @@ export class DshDeliveryRuntime {
|
|
|
4049
4084
|
&& (goalContinuation?.isQuiescent() ?? true);
|
|
4050
4085
|
if (foregroundExecution !== undefined && restartCheckpoint === undefined) {
|
|
4051
4086
|
try {
|
|
4087
|
+
const command = this.activeSessionControls.get(binding.sessionId)?.command;
|
|
4088
|
+
if (command !== undefined)
|
|
4089
|
+
terminationCause = command === 'new' ? 'owner-new-session' : 'owner-stop';
|
|
4090
|
+
else if (signal.reason instanceof AgentTaskTimeoutError)
|
|
4091
|
+
terminationCause = 'execution-timeout';
|
|
4092
|
+
else if (signal.aborted)
|
|
4093
|
+
terminationCause = 'execution-aborted';
|
|
4094
|
+
const terminal = foregroundTurn === undefined ? undefined : handle?.agent.session.snapshotEvents().findLast(event => event.type === 'turn/end' && event.data.turn === foregroundTurn);
|
|
4052
4095
|
this.options.completeForegroundTaskExecution(foregroundExecution, {
|
|
4053
4096
|
status: acceptanceSucceeded ? 'succeeded' : 'unknown', quiescent: acceptanceSucceeded,
|
|
4097
|
+
termination: observeNativeTermination({ producer: 'delivery-agent',
|
|
4098
|
+
reason: terminal?.type === 'turn/end' ? terminal.data.reason : undefined,
|
|
4099
|
+
cause: terminationCause, handleDisposed: disposed, completed: acceptanceSucceeded }),
|
|
4054
4100
|
});
|
|
4055
4101
|
}
|
|
4056
4102
|
catch (error) {
|