@dsh-enhanced/assistant-delivery 0.1.32 → 0.1.35
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 +11 -1
- package/lib/acceptance.d.ts +11 -3
- package/lib/acceptance.d.ts.map +1 -1
- package/lib/agent-runtime.d.ts +15 -0
- package/lib/agent-runtime.d.ts.map +1 -1
- package/lib/agent-runtime.js +150 -17
- package/lib/agent-runtime.js.map +1 -1
- package/lib/foreground-observation.d.ts +32 -0
- package/lib/foreground-observation.d.ts.map +1 -0
- package/lib/foreground-observation.js +13 -0
- package/lib/foreground-observation.js.map +1 -0
- package/lib/index.d.ts +6 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/reply-replay.d.ts +52 -0
- package/lib/reply-replay.d.ts.map +1 -0
- package/lib/reply-replay.js +122 -0
- package/lib/reply-replay.js.map +1 -0
- package/lib/service.d.ts +112 -2
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +429 -64
- 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 +146 -3
- package/lib/sqlite.js.map +1 -1
- package/lib/store.d.ts +151 -10
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +520 -7
- package/lib/store.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +14 -10
package/README.md
CHANGED
|
@@ -131,6 +131,8 @@ ownerRoutes:
|
|
|
131
131
|
|
|
132
132
|
`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,也不能由成长系统自行创建或修改。
|
|
133
133
|
|
|
134
|
+
`inspectOwnerModelSelection()` 在同一 owner route 校验后提供模型快照,供修复与成长继承。传入 `sourceAgent` 时读取匹配 binding 的 Session 最新原生 `request/header`,避免初始 Agent options 已过期;未传入时读取外部会话的持久模型选择或其 Delivery 默认配置。原生 Web 的模型由 DSH 管理,必须提供来源 Agent;该接口不替它猜测模型。返回值仅含 provider/model/可选 reasoning effort,不含会话内容或凭据。
|
|
135
|
+
|
|
134
136
|
`enqueueBackgroundRoute()` 的 Policy resource 固定为精确的 `message/route:<authorityId>`,subject 同时带配置中的 workspace 与 canonical owner principal;部署规则不需要、也不应为这条控制路径授予 message 通配符。Policy 通过后,Delivery 会在同一个 `BEGIN IMMEDIATE` 事务内重新解析 active binding 并写 Outbox,封住授权期间 `/new` 的竞态。claim 时还会在同一写事务内重新验证 authority、source hash、完整 owner scope、generation floor 与当前 exact Policy;route 被删除、修改或撤权时不会调用 adapter,而是写入带 `owner-route-*` failure code 的 terminal Outbox 和 `outbox_attempts` 审计 receipt。
|
|
135
137
|
|
|
136
138
|
显式 Policy deny 表示 T3 撤权并永久 dead;Policy 检查本身抛错(例如 SQLite busy、滚动部署中的短暂不可用)不等同撤权。claim 前发生时,消息保持 `retry_wait`、`attemptCount` 不增加并暴露 `owner-route-policy-check-failed`;claim 后、adapter I/O 前发生时,当前 not-sent attempt 进入带退避的 `retry_wait`。两者都不会调用 provider,Policy 恢复后可自动继续。锁顺序也保持单向:enqueue 的 Policy 写在进入 Delivery 事务前已经完成;claim 只有 Delivery→Policy 的同步检查,没有持有 Policy 写事务再进入 Delivery 的反向路径。运维可用 `pendingOutbox` 加该 failure code 定位持续锁冲突,而不丢失唯一告警。
|
|
@@ -388,6 +390,8 @@ pnpm --dir plugins/assistant-delivery pack --dry-run
|
|
|
388
390
|
|
|
389
391
|
旧 foreground receipt 未保存 principal version:仅当前仍为同一 record 的初始 v1 身份可修订;身份已更新时保守拒绝继承旧判断修订权。新记录完整保存 record+version。
|
|
390
392
|
|
|
393
|
+
Host 可用 `inspectOwnerForegroundLearningTask()` 将 Evaluation 增量结果绑定到精确 owner。它核对当前 route、原始 Inbox/binding、Host 执行回执和 principal record/version,再区分独立 Verifier 与 owner 的纠正/撤回;只有核对成功才返回来源 Session、最多 4096 字符的原任务正文及 canonical receipt。来源带 `modelSelectionState`:`frozen` 才返回实际原生 `request/header` 已物化的 provider/model/可选 reasoning effort;`missing` 表示历史执行未采到调用快照,`inconsistent` 表示同一前台执行出现不同实际路由。后两者不猜测当前会话或部署默认模型。schema v23 为内置 Delivery 运行时的普通 owner 对话增加独立执行回执:无需预设验收 profile,回复具体消息的 `/feedback not-achieved`、更正或撤回也能进入 canonical 前台结果。记录只证明任务归属、实际模型和执行已停止,不能证明目标达成;没有验收契约时只接受已认证的 typed owner 反馈。这类新任务的目标结果反馈要求 Evaluation 可用,先提交 canonical 修订再更新本地 workflow;服务缺失时明确返回不可用,不确认仅有本地记录的成功。偏好反馈和没有执行回执的历史 workflow 路径保持原行为。旧 acceptance 回执继续兼容,旧普通任务不回填,终态执行不能事后补写路由。此入口覆盖内置外部渠道运行时;原生 Web 和自定义运行时不能据此推断已接通。`/new` 前的同 owner 任务可被识别,主体身份变更不能继承旧任务权限。该接口仅供发现前台学习来源,尚不自动调度修复,也不授予执行或采用权限;消费者写入前仍须使用 Evaluation 的 canonical writer fence。
|
|
394
|
+
|
|
391
395
|
|
|
392
396
|
## 原生 Web owner 接入
|
|
393
397
|
|
|
@@ -397,10 +401,16 @@ pnpm --dir plugins/assistant-delivery pack --dry-run
|
|
|
397
401
|
|
|
398
402
|
原生 Goal 仍为 `active` 且 `armed` 时,空闲回收保留同一个 Agent 和 Session lease,允许宿主唯一 GoalRoundDriver 在会话保存完成后调度下一轮。目标终态或 disarm 后恢复普通空闲回收;owner 撤权、租约失效、scope 卸载和原有 `maxExecutionMs` 期限仍优先结束执行,不为每轮重置期限。若宿主缺少 GoalRoundDriver,armed 目标最多保持到该期限;此保留检查本身不派发任务。
|
|
399
403
|
|
|
400
|
-
当前 Web 只支持单已认证控制面的文本交互;图片、完整 queue/steer、跨渠道 owner 别名和子 Agent 历史仍未验收。原生 Web 安装及浏览器验证范围见 [
|
|
404
|
+
当前 Web 只支持单已认证控制面的文本交互;图片、完整 queue/steer、跨渠道 owner 别名和子 Agent 历史仍未验收。原生 Web 安装及浏览器验证范围见 [RSI 当前状态](../../docs/rsi-status.md),配置、Policy 与权限见 [Web owner 包说明](../assistant-web-owner/README.md)。
|
|
405
|
+
|
|
406
|
+
可选 Host 接口 `registerForegroundTaskObserver()` 只接受当前 Control Plane 拥有的注册,在认证 Inbox 的执行绑定后同步通知开始,资源释放并保存真实执行回执后通知结束。它不改变 schema 23 或学习来源摘要,不注册模型工具;注销、owner/服务换代及重启后不补发历史事件,观察错误不影响正常聊天。部署版本与 readiness 核对由 [Control Plane](../plugin-control-plane) 持有;这些事件本身不证明任务质量或具体工具调用。
|
|
401
407
|
|
|
402
408
|
Host 编排可从 `@dsh-enhanced/assistant-delivery/types` 读取无服务初始化的公开类型;该入口不激活 Delivery,也不授予消息发送权限。根构建先生成此类型入口,避免 Evaluation benchmark 与 Delivery 服务声明形成构建环。
|
|
403
409
|
|
|
410
|
+
## Host 回放的回复阻断
|
|
411
|
+
|
|
412
|
+
`blockAgentRepliesForReplay(agent, { operationId, maximumAttempts, expiresAt })` 为专用 Agent 建立永久拒绝回复的标记。真实 `reply()` 与完成偏好回合的回复在绑定、Policy、Outbox 前记录有界输入摘要并拒绝;其他 Agent 不受影响。关闭句柄、到期、限额和 Agent Fiber 卸载均不会恢复权限。它不授予发送权限、不新增模型工具,也不阻断其他 Host 发送 API;快照是进程内观察,不是外部签名或全局无副作用证明。见[回放组件契约](../../docs/effect-blocked-replay.md)。
|
|
413
|
+
|
|
404
414
|
## 持久主人提醒
|
|
405
415
|
|
|
406
416
|
`enqueueOwnerNotification` 为可信 Host 插件提供限定主人路由、原会话、身份版本和有效期的提醒入队接口。普通 `enqueueBackground` 不能写入保留的 `dsh.native-notice*` 元数据。投递前重查当前主人、绑定版本与代次、路由、期限及背景 `send` Policy;过期、撤权或换代的队列不会发送。
|
package/lib/acceptance.d.ts
CHANGED
|
@@ -34,13 +34,21 @@ export interface AcceptanceContract extends AcceptanceTask {
|
|
|
34
34
|
readonly id: string;
|
|
35
35
|
readonly digest: string;
|
|
36
36
|
}
|
|
37
|
-
export interface
|
|
38
|
-
readonly contractId: string;
|
|
39
|
-
readonly contractDigest: string;
|
|
37
|
+
export interface ForegroundExecution {
|
|
40
38
|
readonly dispatchedAt: number;
|
|
41
39
|
readonly status: 'succeeded' | 'failed' | 'timed-out' | 'cancelled' | 'unknown';
|
|
42
40
|
readonly quiescent: boolean;
|
|
43
41
|
readonly completedAt: number;
|
|
44
42
|
readonly executionRef: string;
|
|
43
|
+
readonly modelSelectionState: 'missing' | 'frozen' | 'inconsistent';
|
|
44
|
+
readonly modelSelection?: Readonly<{
|
|
45
|
+
provider: string;
|
|
46
|
+
model: string;
|
|
47
|
+
reasoningEffort?: string;
|
|
48
|
+
}>;
|
|
49
|
+
}
|
|
50
|
+
export interface AcceptedExecution extends ForegroundExecution {
|
|
51
|
+
readonly contractId: string;
|
|
52
|
+
readonly contractDigest: string;
|
|
45
53
|
}
|
|
46
54
|
//# sourceMappingURL=acceptance.d.ts.map
|
package/lib/acceptance.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACxF,MAAM,WAAW,eAAe;IAAG,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE;AAC1G,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AACD,MAAM,WAAW,gBAAgB;IAAG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAAE;AAClG,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,EAAE,qCAAqC,CAAA;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE;QAAE,8BAA8B,CAAC,YAAY,EAAE,0BAA0B,GAAG,OAAO,CAAA;KAAE,CAAA;IACrG,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAA;IACpC,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,gBAAgB,GAAG,IAAI,CAAA;IACvD,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnD;AACD,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IAAG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC3G,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AACxF,MAAM,WAAW,eAAe;IAAG,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE;AAC1G,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAA;IAC/B,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IACzE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AACD,MAAM,WAAW,gBAAgB;IAAG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAAE;AAClG,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,QAAQ,EAAE,qCAAqC,CAAA;IACxD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE;QAAE,8BAA8B,CAAC,YAAY,EAAE,0BAA0B,GAAG,OAAO,CAAA;KAAE,CAAA;IACrG,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAA;IACpC,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,gBAAgB,GAAG,IAAI,CAAA;IACvD,SAAS,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnD;AACD,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IAAG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE;AAC3G,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,CAAA;IAC/E,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,mBAAmB,EAAE,SAAS,GAAG,QAAQ,GAAG,cAAc,CAAA;IACnE,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAClG;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC"}
|
package/lib/agent-runtime.d.ts
CHANGED
|
@@ -42,6 +42,21 @@ interface DshDeliveryRuntimeOptions {
|
|
|
42
42
|
status: 'succeeded' | 'failed' | 'timed-out' | 'cancelled' | 'unknown';
|
|
43
43
|
quiescent: boolean;
|
|
44
44
|
}): Promise<void>;
|
|
45
|
+
recordForegroundTaskModelSelection(handle: AcceptanceHandle, input: {
|
|
46
|
+
provider: string;
|
|
47
|
+
model: string;
|
|
48
|
+
reasoningEffort?: string;
|
|
49
|
+
}): void;
|
|
50
|
+
beginForegroundTaskExecution(binding: Readonly<ConversationBinding>, envelope: Readonly<InboundEnvelope>): string | undefined;
|
|
51
|
+
recordForegroundExecutionModelSelection(inboxId: string, input: {
|
|
52
|
+
provider: string;
|
|
53
|
+
model: string;
|
|
54
|
+
reasoningEffort?: string;
|
|
55
|
+
}): void;
|
|
56
|
+
completeForegroundTaskExecution(inboxId: string, input: {
|
|
57
|
+
status: 'succeeded' | 'unknown';
|
|
58
|
+
quiescent: boolean;
|
|
59
|
+
}): void;
|
|
45
60
|
permissionPickerTtlMs: number;
|
|
46
61
|
getModelSelection(conversation: ConversationRef): ConversationModelSelection | undefined;
|
|
47
62
|
/** Atomically remove a stale explicit effort without overwriting a newer model choice. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-runtime.d.ts","sourceRoot":"","sources":["../src/agent-runtime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,OAAO,EAEL,KAAK,KAAK,EAGX,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,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
|
@@ -3,6 +3,7 @@ import { mkdir, stat } from 'node:fs/promises';
|
|
|
3
3
|
import { isDeepStrictEqual } from 'node:util';
|
|
4
4
|
import { installModelSelection, } from '@deepseek-ai/dsh-agent';
|
|
5
5
|
import { contentHasImage, createUserMessage, ReasoningEffortId, } from '@deepseek-ai/dsh-llm';
|
|
6
|
+
import { TOOL_ABORTED_BEFORE_DISPATCH } from '@deepseek-ai/dsh-tools';
|
|
6
7
|
import { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy';
|
|
7
8
|
import { isAppendSurfaceEvent, SessionId } from '@deepseek-ai/dsh-session';
|
|
8
9
|
import { setApprovalPolicy, } from '@deepseek-ai/dsh-user-approval';
|
|
@@ -329,6 +330,13 @@ export function deliveryProgressFromSessionEvent(event) {
|
|
|
329
330
|
if (event.type === 'assistant/message') {
|
|
330
331
|
return undefined;
|
|
331
332
|
}
|
|
333
|
+
if (event.type === 'approval/asked') {
|
|
334
|
+
// approval/asked is appended before the review waterfall runs, so this label
|
|
335
|
+
// must stay accurate for both the (usually fast) automatic review and a real
|
|
336
|
+
// human escalation (which additionally renders a separate allow/reject card).
|
|
337
|
+
// A tool name here is policy-controlled, but bound it like every other field.
|
|
338
|
+
return { kind: 'step', text: `正在确认工具「${boundedProgressText(event.data.toolName)}」的调用权限…` };
|
|
339
|
+
}
|
|
332
340
|
if (event.type === 'tool/call') {
|
|
333
341
|
if (event.data.name === 'ask_user_question') {
|
|
334
342
|
return { kind: 'step', text: '等待您的回答…' };
|
|
@@ -977,13 +985,14 @@ function automaticCompletionPrompt(kind, maxTextBytes, maxOutputTokens) {
|
|
|
977
985
|
}
|
|
978
986
|
function finalAssistant(events, from, expectedTurn) {
|
|
979
987
|
if (expectedTurn === undefined) {
|
|
980
|
-
return { text: '', completed: false, truncated: false, stopped: false, hasUnpairedToolCall: false };
|
|
988
|
+
return { text: '', completed: false, truncated: false, stopped: false, hasUnpairedToolCall: false, hadToolCall: false };
|
|
981
989
|
}
|
|
982
990
|
let text = '';
|
|
983
991
|
let completed = false;
|
|
984
992
|
let truncated = false;
|
|
985
993
|
let stopped = false;
|
|
986
994
|
const unpairedToolCalls = new Set();
|
|
995
|
+
let hadToolCall = false;
|
|
987
996
|
let failureCode;
|
|
988
997
|
for (const event of events.slice(from)) {
|
|
989
998
|
if (event.type === 'assistant/message' && event.data.turn === expectedTurn) {
|
|
@@ -991,6 +1000,7 @@ function finalAssistant(events, from, expectedTurn) {
|
|
|
991
1000
|
.map(block => block.type === 'text' ? block.text : '').join('');
|
|
992
1001
|
for (const block of event.data.message.content) {
|
|
993
1002
|
if (block.type === 'tool-call') {
|
|
1003
|
+
hadToolCall = true;
|
|
994
1004
|
unpairedToolCalls.add(String(block.id));
|
|
995
1005
|
}
|
|
996
1006
|
}
|
|
@@ -1026,6 +1036,7 @@ function finalAssistant(events, from, expectedTurn) {
|
|
|
1026
1036
|
truncated,
|
|
1027
1037
|
stopped,
|
|
1028
1038
|
hasUnpairedToolCall: unpairedToolCalls.size > 0,
|
|
1039
|
+
hadToolCall,
|
|
1029
1040
|
...(failureCode === undefined ? {} : { failureCode }),
|
|
1030
1041
|
};
|
|
1031
1042
|
}
|
|
@@ -1033,6 +1044,58 @@ function isScheduledGoalRuntimeContext(source) {
|
|
|
1033
1044
|
return (source.kind === 'plugin' && source.plugin === '@deepseek-ai/dsh-system-prompt' && source.form === 'snapshot')
|
|
1034
1045
|
|| (source.kind === 'skill-catalog' && source.form === 'catalog');
|
|
1035
1046
|
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Trusted Host clarification injected after the human deliberately cancels a
|
|
1049
|
+
* tool call before it dispatched.
|
|
1050
|
+
*
|
|
1051
|
+
* Why this exists: when a turn is aborted by the human, the agent loop persists
|
|
1052
|
+
* a `tool/result` pair whose ONLY model-visible text is the bare technical
|
|
1053
|
+
* string "Error: tool call aborted before dispatch" (`isError: true`). The
|
|
1054
|
+
* accurate structured facts — `error.code = ABORTED_BEFORE_DISPATCH` and the
|
|
1055
|
+
* `turn/end` reason `{ aborted, reason: { user } }` — are not surface events,
|
|
1056
|
+
* so the model never sees them. A string of those error-looking results makes a
|
|
1057
|
+
* later no-op message (e.g. "hi") look like "retry the fetch the system kept
|
|
1058
|
+
* interrupting", causing the model to re-fire the cancelled tool unprompted.
|
|
1059
|
+
*
|
|
1060
|
+
* This text is a FIXED Host constant. It never interpolates message content,
|
|
1061
|
+
* tool names, or arguments, so untrusted input cannot flow into the trusted
|
|
1062
|
+
* snapshot. The predicate keys only off structured, Host-owned fields.
|
|
1063
|
+
*/
|
|
1064
|
+
const USER_CANCELLED_TOOL_NOTICE = [
|
|
1065
|
+
'The most recent turn was stopped deliberately by the human (they pressed stop or declined the tool permission).',
|
|
1066
|
+
'Any earlier tool result reading "Error: tool call aborted before dispatch" is that human cancellation, NOT a tool or system failure and NOT an instruction to retry.',
|
|
1067
|
+
'Do not retry, resume, restart, or continue any tool call or task that was interrupted by that stop.',
|
|
1068
|
+
'Respond only to the human\'s latest message on its own terms. Resume the earlier work only if the human explicitly asks for it again.',
|
|
1069
|
+
].join(' ');
|
|
1070
|
+
/** Whether a `turn/end` reason is a human-initiated abort (stop, /new, or a declined approval). */
|
|
1071
|
+
function isUserAbortedTurnEnd(reason) {
|
|
1072
|
+
return typeof reason === 'object' && reason !== null
|
|
1073
|
+
&& reason.kind === 'aborted'
|
|
1074
|
+
&& typeof reason.reason === 'object'
|
|
1075
|
+
&& reason.reason?.kind === 'user';
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Returns the fixed Host clarification when the most recent turn boundary is a
|
|
1079
|
+
* human abort whose turn contains an aborted-before-dispatch tool result;
|
|
1080
|
+
* otherwise `''`. Pure over the supplied events so the projection dedups stable
|
|
1081
|
+
* text across repeated no-op messages and flips to empty once a turn completes.
|
|
1082
|
+
*/
|
|
1083
|
+
function userCancelledToolNotice(events) {
|
|
1084
|
+
let lastEnd;
|
|
1085
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
1086
|
+
const event = events[index];
|
|
1087
|
+
if (event?.type === 'turn/end') {
|
|
1088
|
+
lastEnd = event;
|
|
1089
|
+
break;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
if (lastEnd === undefined || !isUserAbortedTurnEnd(lastEnd.data.reason))
|
|
1093
|
+
return '';
|
|
1094
|
+
const abortedBeforeDispatch = events.some(event => event.type === 'tool/result'
|
|
1095
|
+
&& event.data.turn === lastEnd.data.turn
|
|
1096
|
+
&& event.data.error?.code === TOOL_ABORTED_BEFORE_DISPATCH);
|
|
1097
|
+
return abortedBeforeDispatch ? USER_CANCELLED_TOOL_NOTICE : '';
|
|
1098
|
+
}
|
|
1036
1099
|
export class DshDeliveryRuntime {
|
|
1037
1100
|
ctx;
|
|
1038
1101
|
policy;
|
|
@@ -1392,6 +1455,7 @@ export class DshDeliveryRuntime {
|
|
|
1392
1455
|
aborted();
|
|
1393
1456
|
return {
|
|
1394
1457
|
settle: beginSettling,
|
|
1458
|
+
pinActiveArmedGoal: pinArmedGoal,
|
|
1395
1459
|
teardownTimeoutMs,
|
|
1396
1460
|
isQuiescent,
|
|
1397
1461
|
dispose: () => {
|
|
@@ -1675,6 +1739,36 @@ export class DshDeliveryRuntime {
|
|
|
1675
1739
|
const unbind = this.policy.bindInitiator(agent, initiator, principal);
|
|
1676
1740
|
agentCtx.effect(() => unbind, `assistant-delivery.${initiator}-initiator`);
|
|
1677
1741
|
installModelSelection(agentCtx, { current: selected, assembled: undefined });
|
|
1742
|
+
// The trusted post-cancellation clarification is installed LAZILY and only
|
|
1743
|
+
// for a session whose history actually contains a human-aborted turn with an
|
|
1744
|
+
// aborted-before-dispatch tool result. Merely registering a runtime context
|
|
1745
|
+
// flips the system-prompt assembly out of its empty baseline and perturbs the
|
|
1746
|
+
// cold-resume/lease-recovery accounting for EVERY ordinary session (a
|
|
1747
|
+
// permission /stop compensation run has no such tool result, yet regressed
|
|
1748
|
+
// when the context was registered unconditionally). Keep the exact baseline —
|
|
1749
|
+
// no contribution installed at all — until the Host-owned predicate matches.
|
|
1750
|
+
let cancelNoticeInstalled = false;
|
|
1751
|
+
const installUserCancelledToolNotice = () => {
|
|
1752
|
+
if (cancelNoticeInstalled)
|
|
1753
|
+
return;
|
|
1754
|
+
if (!userCancelledToolNotice(agent.session.snapshotEvents()))
|
|
1755
|
+
return;
|
|
1756
|
+
cancelNoticeInstalled = true;
|
|
1757
|
+
agentCtx.inject(['systemPrompt'], promptCtx => promptCtx.systemPrompt.context({
|
|
1758
|
+
name: 'assistant-delivery:user-cancelled-tool-notice',
|
|
1759
|
+
order: 260,
|
|
1760
|
+
text: () => userCancelledToolNotice(agent.session.snapshotEvents()),
|
|
1761
|
+
}));
|
|
1762
|
+
};
|
|
1763
|
+
// A cold resume may already carry the abort (the real Feishu sequence did).
|
|
1764
|
+
installUserCancelledToolNotice();
|
|
1765
|
+
// A live abort only becomes visible once its turn/end + tool/result land.
|
|
1766
|
+
agentCtx.on('session/event', (eventSession, event) => {
|
|
1767
|
+
if (eventSession !== agent.session)
|
|
1768
|
+
return;
|
|
1769
|
+
if (event.type === 'turn/end' || event.type === 'tool/result')
|
|
1770
|
+
installUserCancelledToolNotice();
|
|
1771
|
+
});
|
|
1678
1772
|
await agentPresets?.mount(agentCtx, presetId);
|
|
1679
1773
|
}
|
|
1680
1774
|
/**
|
|
@@ -3376,6 +3470,8 @@ export class DshDeliveryRuntime {
|
|
|
3376
3470
|
let handle;
|
|
3377
3471
|
let dispatched = false;
|
|
3378
3472
|
let acceptance;
|
|
3473
|
+
let foregroundExecution;
|
|
3474
|
+
let removeAcceptanceRequest;
|
|
3379
3475
|
let acceptanceSucceeded = false;
|
|
3380
3476
|
let goalContinuation;
|
|
3381
3477
|
let goalContinuationQuiescent = true;
|
|
@@ -3473,6 +3569,20 @@ export class DshDeliveryRuntime {
|
|
|
3473
3569
|
// host driver is otherwise free to claim its first round at idle.
|
|
3474
3570
|
goalContinuation = this.waitForNativeGoalContinuation(binding, envelope, agent, signal);
|
|
3475
3571
|
acceptance = this.options.prepareForegroundTaskAcceptance(binding, envelope);
|
|
3572
|
+
foregroundExecution = this.options.beginForegroundTaskExecution(binding, envelope);
|
|
3573
|
+
if (acceptance !== undefined || foregroundExecution !== undefined)
|
|
3574
|
+
removeAcceptanceRequest = this.ctx.on('session/event', (session, event) => {
|
|
3575
|
+
if (session !== agent.session || event.type !== 'request/header')
|
|
3576
|
+
return;
|
|
3577
|
+
// `agent/request` exposes the candidate route. The native loop writes
|
|
3578
|
+
// this header only after `llm.prepareCall()` has applied adapter
|
|
3579
|
+
// defaults such as reasoning effort, which is the route actually sent
|
|
3580
|
+
// to the provider.
|
|
3581
|
+
if (foregroundExecution !== undefined)
|
|
3582
|
+
this.options.recordForegroundExecutionModelSelection(foregroundExecution, event.data.header.config);
|
|
3583
|
+
if (acceptance !== undefined)
|
|
3584
|
+
this.options.recordForegroundTaskModelSelection(acceptance, event.data.header.config);
|
|
3585
|
+
});
|
|
3476
3586
|
markDispatching();
|
|
3477
3587
|
// Once the durable marker exists, even a synchronous followup failure is ambiguous:
|
|
3478
3588
|
// implementations may enqueue before throwing, so no retry is safe.
|
|
@@ -3636,18 +3746,28 @@ export class DshDeliveryRuntime {
|
|
|
3636
3746
|
return { outcome: 'not-processed', failureCode: 'agent-turn-incomplete', retryable: false };
|
|
3637
3747
|
}
|
|
3638
3748
|
if (currentEmpty || assembledText.trim() === '') {
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3749
|
+
// A tool-only foreground turn can arm a native goal (typically
|
|
3750
|
+
// `goal_create`); the host round driver then continues with its own
|
|
3751
|
+
// rounds and this turn has no user-facing reply text. It must not be
|
|
3752
|
+
// classified as an empty response, which would dispose the armed
|
|
3753
|
+
// continuation fence and cancel the in-flight goal round.
|
|
3754
|
+
if (output.hadToolCall && goalContinuation?.pinActiveArmedGoal()) {
|
|
3755
|
+
// Fall through to the continuation fence below instead of replying.
|
|
3756
|
+
}
|
|
3757
|
+
else {
|
|
3758
|
+
const hasPartial = bestEffortText.trim() !== '';
|
|
3759
|
+
this.options.replyCommand(binding, envelope.eventId, {
|
|
3760
|
+
text: hasPartial
|
|
3761
|
+
? truncatedAgentReply(bestEffortText, this.options.maxTextBytes)
|
|
3762
|
+
: emptyAgentReply(this.options.maxTextBytes),
|
|
3763
|
+
format: 'markdown',
|
|
3764
|
+
});
|
|
3765
|
+
publishProgress({
|
|
3766
|
+
kind: 'failed',
|
|
3767
|
+
code: hasPartial ? AGENT_OUTPUT_TRUNCATED_CODE : AGENT_EMPTY_RESPONSE_CODE,
|
|
3768
|
+
});
|
|
3769
|
+
return { outcome: 'processed' };
|
|
3770
|
+
}
|
|
3651
3771
|
}
|
|
3652
3772
|
break;
|
|
3653
3773
|
}
|
|
@@ -3655,10 +3775,12 @@ export class DshDeliveryRuntime {
|
|
|
3655
3775
|
// The foreground reply has already crossed its durable reply path.
|
|
3656
3776
|
// Retain the same Agent afterwards only for the native goal driver; its
|
|
3657
3777
|
// unknown result must never turn the original reply into a claim that
|
|
3658
|
-
// the business goal was achieved.
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3778
|
+
// the business goal was achieved. A tool-only turn has no reply text.
|
|
3779
|
+
if (assembledText.trim() !== '') {
|
|
3780
|
+
const learning = await this.options.replyCompletedPreferenceTurn(agent, binding, envelope, { text: assembledText, format: 'markdown' });
|
|
3781
|
+
if (learning === 'unknown') {
|
|
3782
|
+
this.ctx.logger.warn('assistant-delivery: completed-turn preference projection is ambiguous');
|
|
3783
|
+
}
|
|
3662
3784
|
}
|
|
3663
3785
|
if (goalContinuation !== undefined) {
|
|
3664
3786
|
goalContinuationQuiescent = await goalContinuation.settle();
|
|
@@ -3722,6 +3844,7 @@ export class DshDeliveryRuntime {
|
|
|
3722
3844
|
}
|
|
3723
3845
|
finally {
|
|
3724
3846
|
removeAbort?.();
|
|
3847
|
+
removeAcceptanceRequest?.();
|
|
3725
3848
|
removeProgress?.();
|
|
3726
3849
|
progressOpen = false;
|
|
3727
3850
|
let disposed = false;
|
|
@@ -3731,6 +3854,16 @@ export class DshDeliveryRuntime {
|
|
|
3731
3854
|
finally {
|
|
3732
3855
|
acceptanceSucceeded = acceptanceSucceeded && disposed && !signal.aborted
|
|
3733
3856
|
&& (goalContinuation?.isQuiescent() ?? true);
|
|
3857
|
+
if (foregroundExecution !== undefined) {
|
|
3858
|
+
try {
|
|
3859
|
+
this.options.completeForegroundTaskExecution(foregroundExecution, {
|
|
3860
|
+
status: acceptanceSucceeded ? 'succeeded' : 'unknown', quiescent: acceptanceSucceeded,
|
|
3861
|
+
});
|
|
3862
|
+
}
|
|
3863
|
+
catch (error) {
|
|
3864
|
+
this.ctx.logger.warn(`assistant-delivery: foreground execution completion failed: ${String(error)}`);
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3734
3867
|
if (acceptance !== undefined) {
|
|
3735
3868
|
try {
|
|
3736
3869
|
await this.options.completeForegroundTaskAcceptance(acceptance, {
|