@lemoncat7/dsh-partner 1.8.2 → 1.8.3
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 +10 -2
- package/docs/architecture.md +17 -11
- package/lib/agent-runtime.d.ts +7 -2
- package/lib/agent-runtime.d.ts.map +1 -1
- package/lib/agent-runtime.js +93 -102
- package/lib/agent-runtime.js.map +1 -1
- package/lib/api/features/workspace-api.d.ts.map +1 -1
- package/lib/api/features/workspace-api.js +1 -10
- package/lib/api/features/workspace-api.js.map +1 -1
- package/lib/api.js +8 -13
- package/lib/api.js.map +1 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +778 -729
- package/lib/client.js.map +4 -4
- package/lib/collaboration/composition.d.ts.map +1 -1
- package/lib/collaboration/composition.js +13 -5
- package/lib/collaboration/composition.js.map +1 -1
- package/lib/companions/management-tool.d.ts +1 -1
- package/lib/companions/management-tool.d.ts.map +1 -1
- package/lib/companions/management-tool.js +1 -1
- package/lib/companions/management-tool.js.map +1 -1
- package/lib/companions/management.d.ts +4 -2
- package/lib/companions/management.d.ts.map +1 -1
- package/lib/companions/management.js +2 -2
- package/lib/companions/management.js.map +1 -1
- package/lib/companions/session-configuration.d.ts +19 -0
- package/lib/companions/session-configuration.d.ts.map +1 -0
- package/lib/companions/session-configuration.js +38 -0
- package/lib/companions/session-configuration.js.map +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -3
- package/lib/index.js.map +1 -1
- package/lib/pendant/notice-motion.d.ts.map +1 -1
- package/lib/pendant/notice-motion.js +12 -6
- package/lib/pendant/notice-motion.js.map +1 -1
- package/lib/pendant/sheen.d.ts +1 -1
- package/lib/pendant/sheen.d.ts.map +1 -1
- package/lib/pendant/sheen.js +9 -8
- package/lib/pendant/sheen.js.map +1 -1
- package/lib/pendant/widget.js +1 -1
- package/lib/pendant/widget.js.map +1 -1
- package/lib/pendant-renderer.js +17 -17
- package/lib/store.d.ts +3 -0
- package/lib/store.d.ts.map +1 -1
- package/lib/store.js +4 -0
- package/lib/store.js.map +1 -1
- package/lib/ui/capability-editor.d.ts +7 -0
- package/lib/ui/capability-editor.d.ts.map +1 -0
- package/lib/ui/capability-editor.js +85 -0
- package/lib/ui/capability-editor.js.map +1 -0
- package/lib/ui/companion-draft.d.ts +12 -0
- package/lib/ui/companion-draft.d.ts.map +1 -0
- package/lib/ui/companion-draft.js +2 -0
- package/lib/ui/companion-draft.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,15 @@
|
|
|
6
6
|
|
|
7
7
|
## 兼容性
|
|
8
8
|
|
|
9
|
-
正式版 `1.8.
|
|
9
|
+
正式版 `1.8.3` 适配 DeepSeek Harness `0.1.2-rc.1`,需要 Node.js `22.19+` 或 `24+`。DSH 官方 Agent、Session、Settings、Tools 与客户端 UI 依赖均锁定到 `0.1.2-rc.1` 接口族。
|
|
10
|
+
|
|
11
|
+
### 1.8.3 更新
|
|
12
|
+
|
|
13
|
+
- 伙伴身份、能力、Skill 和协作配置保存后,在下一轮执行前统一注册到会话;覆盖已有浏览器会话和历史会话恢复,不在正在执行的轮次中重组工具,也不唤醒闲置会话。高权限管理工具继续在调用时检查当前授权。
|
|
14
|
+
- 「应用能力组合」增加保存中、成功和失败反馈,成功显示「已保存,下一轮生效」;防止重复提交,失败保留草稿,区分保存失败与保存后刷新失败。
|
|
15
|
+
- 新消息轻摆转向文字面,仅在文字面扫光两次;结束及阅读后不自动恢复图案面,不锁定用户手动翻面。
|
|
16
|
+
- 挂点旁增加小数字未读标记,超过 99 显示 99+,全部已读后隐藏;支持深浅色与减少动态效果,不增加常驻动画或渲染循环。
|
|
17
|
+
- 保留自定义图案、现有卡片材质、24/30/60 FPS 与休眠策略,不改 DSH 源码或伙伴数据。162 项自动化测试及隔离浏览器交互回归通过。
|
|
10
18
|
|
|
11
19
|
### 1.8.2 更新
|
|
12
20
|
|
|
@@ -97,7 +105,7 @@
|
|
|
97
105
|
|
|
98
106
|
知识库挂载要求同时安装包含 `dshKnowledgeMountManagement` 接口的知识库插件;旧版或未安装时会明确提示,身份、能力等管理仍可用。挂载通过知识库当前选中的本地或远程后端执行,远程只读令牌不能修改挂载,不会绕过认证或退回本地写入。
|
|
99
107
|
|
|
100
|
-
|
|
108
|
+
目标伙伴执行中拒绝管理工具修改,配置过期须重新读取。配置保存成功后,身份、能力、Skill 与协作关系在下一轮执行前注册,无需为了注入工具重开会话;Preset 和模型作为会话默认配置,不覆盖已有会话的选择。此权限不自动开启任何伙伴的记忆、心跳或渠道。
|
|
101
109
|
|
|
102
110
|
## 安装
|
|
103
111
|
|
package/docs/architecture.md
CHANGED
|
@@ -12,13 +12,19 @@ client -> HTTP feature routers -> application services -> repositories/store
|
|
|
12
12
|
|
|
13
13
|
## Module boundaries
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
Configuration saves only commit state. The awaited `agent/pre-step` hook compares
|
|
16
|
+
the saved configuration with the installed revision before each new turn, covering
|
|
17
|
+
native history resume as well as local, channel and task-board conversations.
|
|
18
|
+
Unchanged configurations do not re-register tools or read Skill bodies again;
|
|
19
|
+
mid-turn saves never dismantle a running composition. No polling or eager wakeup
|
|
20
|
+
of inactive sessions is needed. Plugin-owned tools recheck capability revocations
|
|
21
|
+
at execution even when an old schema remains in the current turn.
|
|
22
|
+
The UI reports saved/next-turn, separately from request failures and refresh
|
|
23
|
+
failures. Preset and model defaults remain subject to DSH session-selection rules;
|
|
24
|
+
the plugin does not bypass restrictions on changing an existing session's preset.
|
|
25
|
+
`companions/session-configuration.ts` indexes persisted routes and configuration
|
|
26
|
+
revisions without transcript copies. `ui/capability-editor.tsx` owns the capability
|
|
27
|
+
form and save feedback, using the shared companion draft and existing UI tokens.
|
|
22
28
|
|
|
23
29
|
- `core/`: shared validation, identifiers and bounded collections. It contains
|
|
24
30
|
no partner feature policy.
|
|
@@ -109,9 +115,9 @@ this is separate from refreshing scoped companion tools.
|
|
|
109
115
|
Identity, enabled Skill IDs and outgoing grants commit together. Unknown
|
|
110
116
|
fields, stale revisions, cancellation, missing resources and busy targets
|
|
111
117
|
fail closed. Authority is checked again inside the serialized store write.
|
|
112
|
-
A
|
|
113
|
-
write
|
|
114
|
-
|
|
118
|
+
A runtime confirmation error after commit is reported as saved/next-turn with
|
|
119
|
+
a warning, not a failed write. Browser-owned Agent handles are not destroyed.
|
|
120
|
+
Unspecified settings, including automation, remain unchanged.
|
|
115
121
|
- Knowledge mount management is a separate provider-backed operation. The
|
|
116
122
|
adapter derives the target's default project and existing session scopes on
|
|
117
123
|
the server, never from model-supplied paths. It calls the optional
|
|
@@ -148,7 +154,7 @@ this is separate from refreshing scoped companion tools.
|
|
|
148
154
|
- 点击层不绘制材质或装饰边框,鼠标拖动不触发键盘聚焦,键盘操作保留可见焦点。卸载时一并清理小画布、绳带节点和物理资源。
|
|
149
155
|
- `pendant/use-placement.ts` 只负责挂点位置:拖动顶部挂点或用方向键移动整件挂饰,与卡牌拉伸手势分离。位置按可用视口比例保存在本地浏览器,刷新恢复,窄屏及旋转时约束到可见范围;逐帧移动不触发 React 状态更新,完成时才写存储,不查询宿主私有 DOM。
|
|
150
156
|
- 卡牌正面只负责图案,消息更新不会重绘或覆盖正面纹理;内侧单独绘制未读数量、伙伴名和简短状态。图案与消息使用独立纹理,不自动弹出消息或额外角标。
|
|
151
|
-
- `pendant/notice-motion.ts`
|
|
157
|
+
- `pendant/notice-motion.ts` 统一处理新消息提醒:等待被握持或快速甩动的卡牌空闲,轻摆并以短暂的物理角速度辅助转向文字面(背面,Y 轴半周),再由 `pendant/sheen.ts` 仅在文字面轻扫光两次。结束或阅读后不自动恢复图案面,也不持续锁定朝向;抓取可中断,用户仍能自由翻面。多条到达合并一次动作;后台、全部已读及减少动态效果时取消。效果共用卡面圆角几何,不使用全屏后处理、独立计时器或逐帧纹理重绘。挂点旁保留静态小数字未读标记(超过 99 显示 99+,全部已读后隐藏),翻面及减少动态效果时仍可见,不拦截拖动、不唤醒渲染循环;读屏复用消息按钮和现有单一播报区。
|
|
152
158
|
- `pendant/reader.tsx` 点击打开最新未读正文(无未读时展示列表),保留可见、可玩的挂饰;桌面优先放在卡牌旁边,窄屏选择卡牌上方或下方的可用空间。正文独立滚动,来源操作留在底部;使用独立冷灰纸面材质,支持 Escape 关闭、键盘焦点返回、卡牌再次点击关闭和来源导航。静止挂卡即使在阅读时也会自然休眠。
|
|
153
159
|
- `notifications/service.ts` 从已提交的任务/定时执行变化和完整伙伴回复生成终态通知;不改变任务执行,不暴露内部验收交接。普通回复按会话和轮次去重,任务按 ID/修订/终态去重。
|
|
154
160
|
- `notifications/store.ts` 在主状态文件同目录保存 `partner-inbox.sqlite`,权限 0600,最多 200 条摘要(每条最多 2000 字符)及已读状态。它不是新的会话历史;完整内容仍在原任务/会话中。
|
package/lib/agent-runtime.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
2
3
|
import type { AgentDefaultModelConfig } from '@deepseek-ai/dsh-agent-default-model';
|
|
3
4
|
import type { AgentPresets } from '@deepseek-ai/dsh-agent-presets';
|
|
4
5
|
import type { SessionId } from '@deepseek-ai/dsh-session';
|
|
@@ -66,6 +67,10 @@ export declare class PartnerAgentRuntime {
|
|
|
66
67
|
private readonly restoredCompositions;
|
|
67
68
|
private readonly restoredCompositionJobs;
|
|
68
69
|
private readonly disposeAgentListener;
|
|
70
|
+
private readonly disposeConfigurationListener;
|
|
71
|
+
private readonly configurations;
|
|
72
|
+
private readonly preparedTurns;
|
|
73
|
+
private closed;
|
|
69
74
|
private questionAnswerer;
|
|
70
75
|
constructor(ctx: RuntimeContext, store: PartnerStore, defaultCwd: string, memory?: PartnerMemoryStore | undefined, reflection?: MemoryReflectionService | undefined, concerns?: PartnerConcernStore | undefined, composer?: PartnerAgentComposer | undefined);
|
|
71
76
|
setQuestionAnswerer(answerer: PartnerQuestionAnswerer): void;
|
|
@@ -100,7 +105,8 @@ export declare class PartnerAgentRuntime {
|
|
|
100
105
|
recordHeartbeatActivity(companion: Companion, route: ChannelSession, execution: HeartbeatExecution, outcome: HeartbeatOutcome, deliveryError?: string): Promise<void>;
|
|
101
106
|
resetCompanion(companionId: string): Promise<void>;
|
|
102
107
|
reloadCompanion(companionId: string): Promise<void>;
|
|
103
|
-
|
|
108
|
+
/** Awaited by the host before prompt/tool assembly, never from a running tool. */
|
|
109
|
+
prepareAgentTurn(agent: Agent, turn: number, signal: AbortSignal): Promise<void>;
|
|
104
110
|
isCompanionBusy(companionId: string): boolean;
|
|
105
111
|
private releaseCompanion;
|
|
106
112
|
resetChannel(channelId: string): Promise<void>;
|
|
@@ -110,7 +116,6 @@ export declare class PartnerAgentRuntime {
|
|
|
110
116
|
private persistInbound;
|
|
111
117
|
private ensureSession;
|
|
112
118
|
private ensureAgent;
|
|
113
|
-
private ensureRestoredComposition;
|
|
114
119
|
private composeRestoredAgent;
|
|
115
120
|
private injectProfileUpdate;
|
|
116
121
|
private attachSession;
|
|
@@ -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;
|
|
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;AAClD,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAIlE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,KAAK,EAAa,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,uBAAuB,EAA2C,MAAM,oBAAoB,CAAA;AAC1G,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAErE,OAAO,EAA8B,KAAK,kBAAkB,EAAE,KAAK,2BAA2B,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAChJ,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAClD,OAAO,KAAK,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAE1G,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAIjF,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAEpH,KAAK,cAAc,GAAG,OAAO,GAAG;IAC9B,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IACzB,iBAAiB,EAAE,uBAAuB,CAAA;IAC1C,YAAY,EAAE,YAAY,CAAA;IAC1B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,KAAK,EAAE,WAAW,CAAA;CACnB,CAAA;AASD,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG;QAAE,KAAK,EAAE,WAAW,CAAA;KAAE,EAAE,SAAS,EAAE,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAA;CACzG;AAED,MAAM,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,KAAK,MAAM,IAAI,CAAA;AA4BzF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAA;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,cAAc,EAAE,CAAA;IAC1B,UAAU,EAAE,2BAA2B,EAAE,CAAA;IACzC,YAAY,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACnC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC5B;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAE9D,qBAAa,mBAAmB;IAkB5B,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAvB5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAC1D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiD;IACjF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmC;IAC9D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmC;IAClE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwC;IACnE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAC5D,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAA6E;IAClH,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAmC;IAC3E,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAY;IACjD,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAY;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA2B;IAC1D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+B;IAC7D,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,gBAAgB,CAAqC;gBAG1C,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,kBAAkB,YAAA,EAC3B,UAAU,CAAC,EAAE,uBAAuB,YAAA,EACpC,QAAQ,CAAC,EAAE,mBAAmB,YAAA,EAC9B,QAAQ,CAAC,EAAE,oBAAoB,YAAA;IAmBlD,mBAAmB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAItD,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IASrH,KAAK,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC;YASxG,eAAe;IAyBvB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IASxD,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyBtE,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAQhE,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCvF,WAAW,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAiChK,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;IAIpC,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IActD,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAS/G,4BAA4B,CAChC,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,cAAc,EAAE,EAC1B,YAAY,EAAE,kBAAkB,EAAE,GACjC,OAAO,CAAC,IAAI,CAAC;IAgCV,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;YAqBlE,oBAAoB;IAa5B,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCzE,0BAA0B,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;YAevG,oBAAoB;YAMpB,uBAAuB;IAsB/B,uBAAuB,CAC3B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,cAAc,EACrB,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,gBAAgB,EACzB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC;IAcV,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzD,kFAAkF;IAC5E,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBtF,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;YAK/B,gBAAgB;IAWxB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBd,0BAA0B;YAQ1B,KAAK;YAiCL,cAAc;YAwBd,aAAa;YAqBb,WAAW;YAgDX,oBAAoB;IAuClC,OAAO,CAAC,mBAAmB;YAWb,aAAa;CAS5B;AAUD,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,SAAS,cAAc,EAAE,EACjC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,GAC3C,cAAc,GAAG,SAAS,CAM5B;AAMD,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAiChH;AAYD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC,GAAG,SAAS,YAAY,EAAE,CAY9I;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAoC;AAW1G,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,GAAE,uBAAuB,EAAO,GAAG,MAAM,CAczJ;AAyBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,SAAS,SAAS,EAAE,GAAG,OAAO,CAE7H;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,SAAa,GAAG,cAAc,CAOzF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAEpE;AAuCD,UAAU,mBAAmB;IAC3B,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACrB;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,mBAAmB,CAMhH;AA2ED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,2BAA2B,EAAE,CA8B5G;AAWD,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACtB;AAoBD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAe3H;AA+ED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,kBAAkB,EAC7B,OAAO,EAAE,gBAAgB,EACzB,aAAa,CAAC,EAAE,MAAM,GACrB,MAAM,CAwBR"}
|
package/lib/agent-runtime.js
CHANGED
|
@@ -3,6 +3,7 @@ import { mkdir, realpath, stat, writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import { basename, extname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
4
|
import { BlockAssembler, createToolResultMessage, createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
5
5
|
import { createScope, scopeOf, scopeParentOf } from '@deepseek-ai/dsh-scope';
|
|
6
|
+
import { SessionConfigurationIndex } from './companions/session-configuration.js';
|
|
6
7
|
import { concernObservationPrompt } from './autonomy.js';
|
|
7
8
|
import { boundedConcernCheckMinutes } from './concern-domain.js';
|
|
8
9
|
import { PARTNER_MEDIA_MAX_BYTES, safeMediaName } from './channel-message.js';
|
|
@@ -54,6 +55,10 @@ export class PartnerAgentRuntime {
|
|
|
54
55
|
restoredCompositions = new Map();
|
|
55
56
|
restoredCompositionJobs = new Map();
|
|
56
57
|
disposeAgentListener;
|
|
58
|
+
disposeConfigurationListener;
|
|
59
|
+
configurations;
|
|
60
|
+
preparedTurns = new WeakMap();
|
|
61
|
+
closed = false;
|
|
57
62
|
questionAnswerer;
|
|
58
63
|
constructor(ctx, store, defaultCwd, memory, reflection, concerns, composer) {
|
|
59
64
|
this.ctx = ctx;
|
|
@@ -63,8 +68,15 @@ export class PartnerAgentRuntime {
|
|
|
63
68
|
this.reflection = reflection;
|
|
64
69
|
this.concerns = concerns;
|
|
65
70
|
this.composer = composer;
|
|
71
|
+
this.configurations = new SessionConfigurationIndex(store);
|
|
72
|
+
this.disposeConfigurationListener = typeof this.ctx.on === 'function'
|
|
73
|
+
? this.ctx.on('agent/pre-step', async ({ agent, turn, signal }, next) => {
|
|
74
|
+
await this.prepareAgentTurn(agent, turn, signal);
|
|
75
|
+
return next();
|
|
76
|
+
}) : () => { };
|
|
66
77
|
this.disposeAgentListener = typeof this.ctx.on === 'function'
|
|
67
78
|
? this.ctx.on('agent/disposed', ({ agent }) => {
|
|
79
|
+
this.preparedTurns.delete(agent);
|
|
68
80
|
const restored = this.restoredCompositions.get(agent.session.id);
|
|
69
81
|
if (restored?.agent !== agent)
|
|
70
82
|
return;
|
|
@@ -477,31 +489,38 @@ export class PartnerAgentRuntime {
|
|
|
477
489
|
await this.store.update(state => { state.sessions = state.sessions.filter(item => item.companionId !== companionId); });
|
|
478
490
|
}
|
|
479
491
|
async reloadCompanion(companionId) {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
await this.releaseCompanion(companionId);
|
|
485
|
-
// Releasing a restored composition does not close the browser-owned Agent.
|
|
486
|
-
// Recompose it now: staying in the same conversation must not leave it with
|
|
487
|
-
// no partner tools until the user happens to click "open session" again.
|
|
488
|
-
for (const route of activeRoutes) {
|
|
489
|
-
const state = this.store.snapshot();
|
|
490
|
-
const companion = state.companions.find(item => item.id === companionId);
|
|
491
|
-
const currentRoute = state.sessions.find(item => item.id === route.id && item.companionId === companionId);
|
|
492
|
-
if (companion && currentRoute)
|
|
493
|
-
await this.ensureAgent(companion, currentRoute);
|
|
494
|
-
}
|
|
492
|
+
// Compatibility for callers that saved a configuration. The index already
|
|
493
|
+
// observes committed writes; do not tear down or wake any Agent here.
|
|
494
|
+
if (!this.configurations.companion(companionId))
|
|
495
|
+
throw new Error('伙伴不存在');
|
|
495
496
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
497
|
+
/** Awaited by the host before prompt/tool assembly, never from a running tool. */
|
|
498
|
+
async prepareAgentTurn(agent, turn, signal) {
|
|
499
|
+
if (this.closed)
|
|
500
|
+
throw new Error('伙伴运行时已关闭');
|
|
501
|
+
if (this.preparedTurns.get(agent) === turn)
|
|
502
|
+
return;
|
|
503
|
+
const configuration = this.configurations.forSession(agent.session.id);
|
|
504
|
+
if (!configuration)
|
|
505
|
+
return;
|
|
506
|
+
signal.throwIfAborted();
|
|
507
|
+
const installed = this.restoredCompositions.get(agent.session.id);
|
|
508
|
+
if (installed?.agent !== agent || installed.revision !== configuration.revision) {
|
|
509
|
+
const profile = await this.memory?.profileSnapshot(configuration.companion.id, memoryScope(configuration.route.channelId, configuration.route.userId)).catch(() => undefined);
|
|
510
|
+
signal.throwIfAborted();
|
|
511
|
+
if (this.closed)
|
|
512
|
+
throw new Error('伙伴运行时已关闭');
|
|
513
|
+
const job = this.composeRestoredAgent(agent, configuration.companion, configuration.route, configuration.revision, profile, signal);
|
|
514
|
+
this.restoredCompositionJobs.set(agent.session.id, job);
|
|
515
|
+
try {
|
|
516
|
+
await job;
|
|
517
|
+
}
|
|
518
|
+
finally {
|
|
519
|
+
if (this.restoredCompositionJobs.get(agent.session.id) === job)
|
|
520
|
+
this.restoredCompositionJobs.delete(agent.session.id);
|
|
521
|
+
}
|
|
504
522
|
}
|
|
523
|
+
this.preparedTurns.set(agent, turn);
|
|
505
524
|
}
|
|
506
525
|
isCompanionBusy(companionId) {
|
|
507
526
|
return this.store.snapshot().sessions.some(route => route.companionId === companionId
|
|
@@ -529,7 +548,10 @@ export class PartnerAgentRuntime {
|
|
|
529
548
|
await this.store.update(state => { state.sessions = state.sessions.filter(item => item.channelId !== channelId); });
|
|
530
549
|
}
|
|
531
550
|
async close() {
|
|
551
|
+
this.closed = true;
|
|
552
|
+
this.disposeConfigurationListener();
|
|
532
553
|
this.disposeAgentListener();
|
|
554
|
+
this.configurations.close();
|
|
533
555
|
await Promise.allSettled(this.restoredCompositionJobs.values());
|
|
534
556
|
for (const restored of this.restoredCompositions.values())
|
|
535
557
|
restored.dispose();
|
|
@@ -545,6 +567,8 @@ export class PartnerAgentRuntime {
|
|
|
545
567
|
async releaseRestoredComposition(sessionId) {
|
|
546
568
|
await this.restoredCompositionJobs.get(sessionId)?.catch(() => { });
|
|
547
569
|
const restored = this.restoredCompositions.get(sessionId);
|
|
570
|
+
if (restored)
|
|
571
|
+
this.preparedTurns.delete(restored.agent);
|
|
548
572
|
restored?.dispose();
|
|
549
573
|
this.restoredCompositions.delete(sessionId);
|
|
550
574
|
}
|
|
@@ -647,7 +671,6 @@ export class PartnerAgentRuntime {
|
|
|
647
671
|
}
|
|
648
672
|
const live = this.ctx.agents.get(route.sessionId);
|
|
649
673
|
if (live !== undefined) {
|
|
650
|
-
await this.ensureRestoredComposition(live, companion, route, profile);
|
|
651
674
|
await this.attachSession(companion, route);
|
|
652
675
|
if (profile)
|
|
653
676
|
this.injectProfileUpdate(live, route.sessionId, profile);
|
|
@@ -659,24 +682,8 @@ export class PartnerAgentRuntime {
|
|
|
659
682
|
if (presets === undefined)
|
|
660
683
|
throw new Error('伙伴会话缺少 Agent Presets 服务');
|
|
661
684
|
await presets.mount(agentCtx, companion.presetId);
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
order: -10,
|
|
665
|
-
text: renderPartnerPersona(companion, route.kind === 'local' ? 'local' : 'conversation'),
|
|
666
|
-
});
|
|
667
|
-
agentCtx.systemPrompt.section({
|
|
668
|
-
name: 'partner-tool-routing',
|
|
669
|
-
order: -9,
|
|
670
|
-
text: renderToolProtocol(),
|
|
671
|
-
});
|
|
672
|
-
if (profile && profile.entries.length > 0)
|
|
673
|
-
agentCtx.systemPrompt.section({
|
|
674
|
-
name: 'partner-user-profile',
|
|
675
|
-
order: -8,
|
|
676
|
-
text: renderProfile(profile),
|
|
677
|
-
});
|
|
678
|
-
this.questionAnswerer?.(agentCtx, route);
|
|
679
|
-
await this.composer?.compose(agentCtx, companion);
|
|
685
|
+
// Partner composition is installed at the same awaited pre-step boundary
|
|
686
|
+
// for factory-created and native browser-resumed Agents alike.
|
|
680
687
|
};
|
|
681
688
|
let handle;
|
|
682
689
|
try {
|
|
@@ -703,69 +710,53 @@ export class PartnerAgentRuntime {
|
|
|
703
710
|
await this.attachSession(companion, route);
|
|
704
711
|
return handle.agent;
|
|
705
712
|
}
|
|
706
|
-
async
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
if (this.restoredCompositionJobs.get(route.sessionId) === job)
|
|
720
|
-
this.restoredCompositionJobs.delete(route.sessionId);
|
|
713
|
+
async composeRestoredAgent(agent, companion, route, revision, profile, signal) {
|
|
714
|
+
// Already inside the driver's awaited pre-step hook. Waiting for idle or
|
|
715
|
+
// runMaintenance here would deadlock the very turn we are preparing.
|
|
716
|
+
signal.throwIfAborted();
|
|
717
|
+
const agentCtx = agent.ctx;
|
|
718
|
+
const key = scopeOf(agentCtx);
|
|
719
|
+
if (key === undefined)
|
|
720
|
+
throw new Error('伙伴会话缺少 Agent 作用域');
|
|
721
|
+
if (scopeParentOf(key) === undefined) {
|
|
722
|
+
const presets = agentCtx.get('agentPresets');
|
|
723
|
+
if (presets === undefined)
|
|
724
|
+
throw new Error('伙伴会话缺少 Agent Presets 服务');
|
|
725
|
+
await presets.mount(agentCtx, companion.presetId);
|
|
721
726
|
}
|
|
722
|
-
}
|
|
723
|
-
async composeRestoredAgent(agent, companion, route, profile) {
|
|
724
|
-
await agent.whenIdle();
|
|
725
|
-
let dispose;
|
|
726
|
-
await agent.runMaintenance(async (signal) => {
|
|
727
|
-
if (signal.aborted)
|
|
728
|
-
throw signal.reason;
|
|
729
|
-
const agentCtx = agent.ctx;
|
|
730
|
-
const key = scopeOf(agentCtx);
|
|
731
|
-
if (key === undefined)
|
|
732
|
-
throw new Error('伙伴会话缺少 Agent 作用域');
|
|
733
|
-
if (scopeParentOf(key) === undefined) {
|
|
734
|
-
const presets = agentCtx.get('agentPresets');
|
|
735
|
-
if (presets === undefined)
|
|
736
|
-
throw new Error('伙伴会话缺少 Agent Presets 服务');
|
|
737
|
-
await presets.mount(agentCtx, companion.presetId);
|
|
738
|
-
}
|
|
739
|
-
const disposers = [];
|
|
740
|
-
try {
|
|
741
|
-
disposers.push(agentCtx.systemPrompt.section({ name: 'partner-identity', order: -10, text: renderPartnerPersona(companion, route.kind === 'local' ? 'local' : 'conversation') }));
|
|
742
|
-
disposers.push(agentCtx.systemPrompt.section({ name: 'partner-tool-routing', order: -9, text: renderToolProtocol() }));
|
|
743
|
-
if (profile && profile.entries.length > 0)
|
|
744
|
-
disposers.push(agentCtx.systemPrompt.section({ name: 'partner-user-profile', order: -8, text: renderProfile(profile) }));
|
|
745
|
-
if (this.questionAnswerer)
|
|
746
|
-
disposers.push(this.questionAnswerer(agentCtx, route));
|
|
747
|
-
if (this.composer)
|
|
748
|
-
disposers.push(await this.composer.compose(agentCtx, companion));
|
|
749
|
-
}
|
|
750
|
-
catch (error) {
|
|
751
|
-
for (let index = disposers.length - 1; index >= 0; index -= 1)
|
|
752
|
-
disposers[index]?.();
|
|
753
|
-
throw error;
|
|
754
|
-
}
|
|
755
|
-
let disposed = false;
|
|
756
|
-
dispose = () => {
|
|
757
|
-
if (disposed)
|
|
758
|
-
return;
|
|
759
|
-
disposed = true;
|
|
760
|
-
for (let index = disposers.length - 1; index >= 0; index -= 1)
|
|
761
|
-
disposers[index]?.();
|
|
762
|
-
};
|
|
763
|
-
});
|
|
764
|
-
if (dispose === undefined)
|
|
765
|
-
throw new Error('伙伴会话恢复组合未完成');
|
|
766
727
|
const previous = this.restoredCompositions.get(route.sessionId);
|
|
767
728
|
previous?.dispose();
|
|
768
|
-
this.restoredCompositions.
|
|
729
|
+
this.restoredCompositions.delete(route.sessionId);
|
|
730
|
+
const disposers = [];
|
|
731
|
+
try {
|
|
732
|
+
disposers.push(agentCtx.systemPrompt.section({ name: 'partner-identity', order: -10, text: renderPartnerPersona(companion, route.kind === 'local' ? 'local' : 'conversation') }));
|
|
733
|
+
disposers.push(agentCtx.systemPrompt.section({ name: 'partner-tool-routing', order: -9, text: renderToolProtocol() }));
|
|
734
|
+
if (profile && profile.entries.length > 0)
|
|
735
|
+
disposers.push(agentCtx.systemPrompt.section({ name: 'partner-user-profile', order: -8, text: renderProfile(profile) }));
|
|
736
|
+
if (this.questionAnswerer)
|
|
737
|
+
disposers.push(this.questionAnswerer(agentCtx, route));
|
|
738
|
+
if (this.composer)
|
|
739
|
+
disposers.push(await this.composer.compose(agentCtx, companion));
|
|
740
|
+
signal.throwIfAborted();
|
|
741
|
+
if (this.closed)
|
|
742
|
+
throw new Error('伙伴运行时已关闭');
|
|
743
|
+
}
|
|
744
|
+
catch (error) {
|
|
745
|
+
for (let index = disposers.length - 1; index >= 0; index -= 1)
|
|
746
|
+
disposers[index]?.();
|
|
747
|
+
throw error;
|
|
748
|
+
}
|
|
749
|
+
let disposed = false;
|
|
750
|
+
const dispose = () => {
|
|
751
|
+
if (disposed)
|
|
752
|
+
return;
|
|
753
|
+
disposed = true;
|
|
754
|
+
for (let index = disposers.length - 1; index >= 0; index -= 1)
|
|
755
|
+
disposers[index]?.();
|
|
756
|
+
};
|
|
757
|
+
// Keep the captured revision: a concurrent save must be applied next turn,
|
|
758
|
+
// never incorrectly recorded as already installed by this composition.
|
|
759
|
+
this.restoredCompositions.set(route.sessionId, { agent, dispose, revision });
|
|
769
760
|
}
|
|
770
761
|
injectProfileUpdate(agent, sessionId, profile) {
|
|
771
762
|
const previous = this.profileVersions.get(sessionId);
|