dsh-agent-message 1.5.1 → 1.6.0
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.en.md +21 -9
- package/README.md +21 -9
- package/lib/client.js +86 -227
- package/lib/index.js +27 -4
- package/package.json +18 -10
package/README.en.md
CHANGED
|
@@ -25,9 +25,10 @@ Typical scenarios: an orchestrator Agent dispatching work to a developer Agent,
|
|
|
25
25
|
| `list_peer_agents` | List all **sendable independent sessions**: non-archived, excluding actual subagents while retaining ordinary forks; returns id, title, working directory, and runtime status |
|
|
26
26
|
| `send_agent_message` | Send a message to a session id; `followup` creates an independent turn by default and offline targets are resumed automatically; explicit modes are `followup`, `inject`, and `steer` |
|
|
27
27
|
| `check_delivery` | Query receipts on demand (pending/claimed/discarded/unknown); a successful send first returns accepted, while pre-admission failure is a tool error; explicit message ids remain queryable after restart |
|
|
28
|
-
|
|
|
29
|
-
| Visible Agent message card | Relay keeps its true plugin provenance while the Client presents it as a left-aligned Agent message card; `From Session · <name>:` opens the sender by click or keyboard |
|
|
28
|
+
| Native Harness `@` session reference | Reuse Harness's structured Session Reference directly. The current Agent receives the stable Session ID plus a bounded, read-only snapshot marked as untrusted. Referencing alone does not send a message or wake the target |
|
|
29
|
+
| Visible Agent message card | Relay keeps its true plugin provenance while the Client presents it as a left-aligned Agent message card; `From Session · <name>:` opens the sender by click or keyboard, with labels following the Harness language setting |
|
|
30
30
|
| Copy session id | A "Copy ID" button is added to the session header for one-click copying of the current session id |
|
|
31
|
+
| Delivery card settings | In Settings → Plugin configuration, toggle delivery mode and target runtime details; `messageId` is always shown |
|
|
31
32
|
|
|
32
33
|
### Sender navigation example
|
|
33
34
|
|
|
@@ -55,7 +56,7 @@ dsh plugin --profile web add dsh-agent-message
|
|
|
55
56
|
|
|
56
57
|
It self-registers on install; no extra configuration is needed.
|
|
57
58
|
|
|
58
|
-
Compatibility: Node.js 24 and DeepSeek Harness `>=0.1.
|
|
59
|
+
Compatibility: Node.js 24 and DeepSeek Harness `>=0.1.1-rc.2 <0.2.0`; currently verified with Node.js `24.x` and Harness `0.1.1-rc.2`.
|
|
59
60
|
|
|
60
61
|
### Option 2: Install from GitHub
|
|
61
62
|
|
|
@@ -77,8 +78,8 @@ The plugin ships a `cordis.patch.yml` (pointed to by `dsh.bundle.patch` in `pack
|
|
|
77
78
|
|
|
78
79
|
## Usage
|
|
79
80
|
|
|
80
|
-
1. Type `@`
|
|
81
|
-
2.
|
|
81
|
+
1. Type `@` in session A's composer and choose the target session from Harness's native candidate menu;
|
|
82
|
+
2. Harness gives A a bounded, read-only, untrusted snapshot of that Session, but does not message or wake B. A calls `send_agent_message` only when the current request or an orchestration responsibility already granted by the user explicitly requires cross-session communication. For example, `@B tell it to stop after opening the draft PR` sends, while `@B analyze its latest conversation result` only uses the referenced snapshot;
|
|
82
83
|
3. For an explicit forwarding request, A only delivers and reports whether the message was accepted or failed. It must not execute the forwarded task itself or ask B for an extra acknowledgement. B sends a message to `senderSessionId` only when the body explicitly asks it to return business content;
|
|
83
84
|
4. You can still ask the Agent to call `list_peer_agents` and send directly with a full session id;
|
|
84
85
|
5. Session B receives a native `UserMessage` with a typed relay source plus a minimal Host-generated source header on the first body line, so B does not have to guess the sender. The Client presents it as a visible Agent message card whose header opens the sender session;
|
|
@@ -99,13 +100,13 @@ Delivery paths of `send_agent_message`:
|
|
|
99
100
|
|
|
100
101
|
Session enumeration, batched titles, and offline log reads use Harness's `sessionQuery.listSessions()`, `readTitleSnapshots()`, and `readSession()` respectively. `SessionId` is the only address; `parentSession` records fork lineage only, and only `origin: subagent` identifies an actual subagent. The plugin does not scan `sessionPersistence` directly to rebuild a parallel session directory.
|
|
101
102
|
|
|
102
|
-
After `send_agent_message` submits the native message to the target Inbox, it immediately returns `accepted` with the native `messageId`; the
|
|
103
|
+
After `send_agent_message` submits the native message to the target Inbox, it immediately returns `accepted` with the native `messageId`; both the terse tool result and the full tool card show a selectable `messageId` for copying, while the complete result also stays in tool presentation metadata. `check_delivery` then derives `pending` (still queued), `claimed` (claimed by a turn), `discarded` (cancelled), or `unknown` from Inbox events on demand. `claimed` is transport evidence only: it does not prove that the message was read, answered, or completed. Pre-admission failure remains a Harness tool error and writes nothing to the target Inbox. Runtime state is reported separately as `targetRuntimeStatus`, so unrelated Agent activity never changes the message state. A known `messageId` remains queryable from the target Inbox log after a process restart.
|
|
103
104
|
|
|
104
105
|
Every cross-session message is created by Harness `createUserMessage()`, and `UserMessage.id` is its only message identity. Its source always uses `kind: dsh-agent-message` and `form: relay`, plus the protocol version, sender/target Session ids, and display title. Because current Harness model requests do not expand custom source fields, the Host also writes a minimal `<dsh-agent-message>` header containing only `senderSessionId` on the first body line. The typed source is the durable/UI truth; the header is only the model-visible projection needed for reply addressing. The plugin registers no global system prompt; send admission lives only in the `send_agent_message` tool contract. The Client only projects relay as a visible Agent message card and never rewrites an Agent message as human `user` provenance.
|
|
105
106
|
|
|
106
107
|
Relay only means “a message addressed by another session”; it neither requires nor forbids a reply. When the body explicitly requests business content in return, the receiving Agent may send a message to `senderSessionId` with the same tool. Otherwise it must not send a transport acknowledgement or a bare “received.” The plugin does not automatically correlate requests and replies or forward ordinary Agent answers.
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
Composer-side `@` is provided entirely by Harness's native `ui-reference` / `session-reference` services. Harness retains the stable Session ID in the structured reference and owns bounded snapshot loading and injection. The plugin no longer registers an `@` source, parses titles for addressing, or maintains a second session-reference UI.
|
|
109
110
|
|
|
110
111
|
See [`docs/architecture-v2.md`](./docs/architecture-v2.md) for the current architecture contract.
|
|
111
112
|
|
|
@@ -115,14 +116,25 @@ See [`docs/architecture-v2.md`](./docs/architecture-v2.md) for the current archi
|
|
|
115
116
|
dsh-agent-message/
|
|
116
117
|
├── lib/
|
|
117
118
|
│ ├── index.js # host half: list_peer_agents / send_agent_message / check_delivery
|
|
118
|
-
│ └── client.js # client half:
|
|
119
|
+
│ └── client.js # client half: relay display, sender navigation, settings, and copy-session-id button
|
|
119
120
|
├── cordis.patch.yml # self-registration patch (pointed to by dsh.bundle.patch)
|
|
120
121
|
├── package.json # DSH plugin manifest (dsh.bundle / dsh.client / dshx.contributes)
|
|
121
|
-
├── docs/ #
|
|
122
|
+
├── docs/ # active/proposed architecture and README example screenshot
|
|
123
|
+
├── scripts/web-smoke.mjs # real Web Profile startup and configuration smoke test
|
|
122
124
|
├── README.md # Chinese documentation
|
|
123
125
|
└── README.en.md # English documentation
|
|
124
126
|
```
|
|
125
127
|
|
|
128
|
+
## Development validation
|
|
129
|
+
|
|
130
|
+
```sh
|
|
131
|
+
pnpm test
|
|
132
|
+
pnpm run test:web-smoke
|
|
133
|
+
pnpm peers check
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`test:web-smoke` requires a local `dsh` installation and a configured Web Profile. It checks startup, plugin composition, and HTTP reachability only; see the [architecture validation record](./docs/architecture-v2.md#14-验证记录) for real interaction coverage.
|
|
137
|
+
|
|
126
138
|
## Limitations
|
|
127
139
|
|
|
128
140
|
- The target session must be **non-archived** and present in local persistence; archived sessions are always rejected.
|
package/README.md
CHANGED
|
@@ -25,9 +25,10 @@
|
|
|
25
25
|
| `list_peer_agents` | 列出所有**可发送**的独立会话:未归档、排除真实子代理;普通 fork 保留。返回 id、标题、工作目录和运行状态 |
|
|
26
26
|
| `send_agent_message` | 给指定会话 ID 发消息;默认使用 `followup` 创建独立的新 turn,离线时自动恢复后投递;显式支持 `followup`、`inject`、`steer` |
|
|
27
27
|
| `check_delivery` | 按需查询消息回执(pending/claimed/discarded/unknown);发送成功时先返回 accepted,接纳前失败由工具错误表示;指定消息 ID 时支持重启后恢复查询 |
|
|
28
|
-
| `@`
|
|
29
|
-
| 可见的 Agent 消息卡片 | relay 仍保留真实的插件来源,但 Client 将它显示为左侧 Agent 消息卡片;`From Session · <名称>:`
|
|
28
|
+
| Harness 原生 `@` 会话引用 | 直接复用 Harness 的结构化 Session Reference;选择后当前 Agent 获得稳定 Session ID 和一份有界、只读、标记为不可信的会话快照。引用本身不会发送消息或唤醒目标 |
|
|
29
|
+
| 可见的 Agent 消息卡片 | relay 仍保留真实的插件来源,但 Client 将它显示为左侧 Agent 消息卡片;`From Session · <名称>:` 可点击或通过键盘打开发送方会话,文案跟随 Harness 语言设置 |
|
|
30
30
|
| 复制会话 ID | 会话头部新增「复制ID」按钮,一键复制当前会话 ID |
|
|
31
|
+
| 投递卡片设置 | 在设置 → 插件配置中,可切换是否显示投递模式和目标运行状态;`messageId` 始终显示 |
|
|
31
32
|
|
|
32
33
|
### 发送方导航示例
|
|
33
34
|
|
|
@@ -56,7 +57,7 @@ dsh plugin --profile web add dsh-agent-message
|
|
|
56
57
|
|
|
57
58
|
装完即自动注册,无需任何额外配置。
|
|
58
59
|
|
|
59
|
-
兼容范围:Node.js 24、DeepSeek Harness `>=0.1.
|
|
60
|
+
兼容范围:Node.js 24、DeepSeek Harness `>=0.1.1-rc.2 <0.2.0`;当前验证版本为 Node.js `24.x`、Harness `0.1.1-rc.2`。
|
|
60
61
|
|
|
61
62
|
### 方式二:从 GitHub 安装
|
|
62
63
|
|
|
@@ -78,8 +79,8 @@ Agent 会用 bash 执行这条命令,装完自动挂载、所有会话立即
|
|
|
78
79
|
|
|
79
80
|
## 使用
|
|
80
81
|
|
|
81
|
-
1. 在会话 A
|
|
82
|
-
2.
|
|
82
|
+
1. 在会话 A 的输入框中键入 `@`,从 Harness 原生候选菜单中选择目标会话;
|
|
83
|
+
2. Harness 会把该 Session 的有界、只读、不可信快照提供给 A,但不会向 B 发消息或唤醒 B。只有当前请求或用户已授予的编排职责明确要求跨会话传递信息时,A 才调用 `send_agent_message`。例如 `@B 告诉他最后提交 PR draft 就停止` 会发送;`@B 帮我分析他最新的对话结果` 只使用引用快照;
|
|
83
84
|
3. 显式要求转告时,A 只负责投递并报告“已接受”或失败,不代为执行被转发的任务,也不要求 B 额外回复“收到”;如果正文明确要求 B 把业务内容返回 A,B 才向 `senderSessionId` 发送消息;
|
|
84
85
|
4. 也可以让 Agent 调 `list_peer_agents`,再用完整会话 ID 直接发送;
|
|
85
86
|
5. 会话 B 收到的是带 typed relay source 的原生 `UserMessage`;正文首行还有 Host 生成的最小来源协议,B 不需要猜测发送方;Client 将其显示为可见 Agent 消息卡片,并可从消息头打开发送方会话;
|
|
@@ -100,13 +101,13 @@ Agent 会用 bash 执行这条命令,装完自动挂载、所有会话立即
|
|
|
100
101
|
|
|
101
102
|
会话枚举、批量标题和离线日志读取分别使用 Harness 的 `sessionQuery.listSessions()`、`readTitleSnapshots()` 与 `readSession()`。`SessionId` 是唯一地址;`parentSession` 只记录分叉血缘,只有 `origin: subagent` 才会被识别为真实子代理。插件不直接扫描 `sessionPersistence` 重建另一份会话目录。
|
|
102
103
|
|
|
103
|
-
`send_agent_message` 成功把原生消息提交给目标 Inbox 后立即返回 `accepted` 和该消息的原生 `messageId
|
|
104
|
+
`send_agent_message` 成功把原生消息提交给目标 Inbox 后立即返回 `accepted` 和该消息的原生 `messageId`;精简工具结果和完整工具卡片都会显示可选择复制的 `messageId`,完整结果同时保留在工具呈现元数据中。`check_delivery` 根据 Inbox 事件按需返回 `pending`(仍在排队)、`claimed`(已被某轮认领)、`discarded`(被取消)或 `unknown`。`claimed` 只是传输证据,不表示已读、回复或任务完成。接纳前失败由 Harness 工具错误表示,不写入目标 Inbox。目标是否正在运行通过独立的 `targetRuntimeStatus` 返回,不把 Agent 的整体运行状态误当成某条消息正在处理。指定 `messageId` 时可从目标现有 Inbox 日志恢复状态,因此进程重启后仍可查询。
|
|
104
105
|
|
|
105
106
|
所有跨会话消息都由 Harness `createUserMessage()` 创建,`UserMessage.id` 是唯一消息身份。`source.kind` 固定为 `dsh-agent-message`,`form` 固定为 `relay`,并携带协议版本、发送/目标 Session 和显示标题。由于当前 Harness 不会把自定义 source 字段展开给模型,Host 还会在正文首行写入只含 `senderSessionId` 的最小 `<dsh-agent-message>` 协议头;source 是持久化/UI 真相,协议头只是回复寻址所需的模型可见投影。插件不注册全局系统提示词,发送准入只存在于 `send_agent_message` 的工具合同中。Client 只把 relay 投影为可见的 Agent 消息卡片,不会反向把 Agent 消息伪装成人类 `user` 来源。
|
|
106
107
|
|
|
107
108
|
relay 只表达“另一会话发来的消息”,本身不等于必须回复或禁止回复。正文明确要求返回业务内容时,接收 Agent 可用同一工具向 `senderSessionId` 发送消息;没有明确要求时不回传 transport ack 或单纯的“收到”。插件不自动关联请求与回复,也不自动转发 Agent 的普通回答。
|
|
108
109
|
|
|
109
|
-
输入框的 `@`
|
|
110
|
+
输入框的 `@` 完全由 Harness 原生 `ui-reference` / `session-reference` 提供,结构化引用保留稳定 Session ID,并由 Harness 负责读取和注入有界快照。插件不再注册自己的 `@` source、不解析标题寻址,也不维护第二套会话引用 UI。
|
|
110
111
|
|
|
111
112
|
完整的现役架构合同见 [`docs/architecture-v2.md`](./docs/architecture-v2.md)。
|
|
112
113
|
|
|
@@ -116,14 +117,25 @@ relay 只表达“另一会话发来的消息”,本身不等于必须回复
|
|
|
116
117
|
dsh-agent-message/
|
|
117
118
|
├── lib/
|
|
118
119
|
│ ├── index.js # host 半区:list_peer_agents / send_agent_message / check_delivery
|
|
119
|
-
│ └── client.js # client
|
|
120
|
+
│ └── client.js # client 半区:relay 显示、发送方导航、设置与复制会话ID按钮
|
|
120
121
|
├── cordis.patch.yml # 自注册补丁(dsh.bundle.patch 指向它)
|
|
121
122
|
├── package.json # DSH 插件清单(dsh.bundle / dsh.client / dshx.contributes)
|
|
122
|
-
├── docs/ #
|
|
123
|
+
├── docs/ # 现役/候选架构与 README 示例截图
|
|
124
|
+
├── scripts/web-smoke.mjs # 真实 Web Profile 启动与配置冒烟
|
|
123
125
|
├── README.md # 中文文档
|
|
124
126
|
└── README.en.md # English documentation
|
|
125
127
|
```
|
|
126
128
|
|
|
129
|
+
## 开发验证
|
|
130
|
+
|
|
131
|
+
```sh
|
|
132
|
+
pnpm test
|
|
133
|
+
pnpm run test:web-smoke
|
|
134
|
+
pnpm peers check
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`test:web-smoke` 需要本机已安装 `dsh` 并配置 Web Profile,它只验证启动、插件组合和 HTTP 可达性;真实交互验收记录见 [`docs/architecture-v2.md`](./docs/architecture-v2.md#14-验证记录)。
|
|
138
|
+
|
|
127
139
|
## 限制
|
|
128
140
|
|
|
129
141
|
- 目标会话必须**未归档**且存在于本机持久化里;归档会话一律拒绝发送。
|
package/lib/client.js
CHANGED
|
@@ -5,159 +5,106 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
const React = require("react");
|
|
8
|
-
const { createRoot } = require("react-dom/client");
|
|
9
|
-
const { IconQueueOutline14, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
8
|
|
|
11
9
|
const name = "dsh-agent-message-client";
|
|
12
|
-
const inject = ["slots", "timer", "sessions", "
|
|
10
|
+
const inject = ["slots", "timer", "sessions", "settingsScope", "locale"];
|
|
13
11
|
|
|
14
12
|
function apply(ctx) {
|
|
15
|
-
const senderSelector =
|
|
16
|
-
const referenceSource = "agent-message-session";
|
|
17
|
-
const reactRootSelector = "[data-agent-msg-react-root]";
|
|
18
|
-
const candidateRows = new WeakMap();
|
|
19
|
-
const mountedRoots = new Map();
|
|
13
|
+
const senderSelector = "[data-context-relay-sender]";
|
|
20
14
|
const sessionLinks = new Set();
|
|
21
|
-
const
|
|
15
|
+
const subscribeLocale = function (listener) { return ctx.locale.subscribe(listener); };
|
|
16
|
+
const getLocaleSnapshot = function () { return ctx.locale.getSnapshot(); };
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
const AGENT_MESSAGE_SETTINGS_NAMESPACE = "agent-message";
|
|
19
|
+
|
|
20
|
+
function useLocale() {
|
|
21
|
+
React.useSyncExternalStore(subscribeLocale, getLocaleSnapshot);
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
function
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
function AgentMessageSettingsCard(props) {
|
|
25
|
+
useLocale();
|
|
26
|
+
const snapshot = props.useAgentMessageSettings(function (value) { return value; });
|
|
27
|
+
const current = snapshot.value?.showTechnicalDetails !== false;
|
|
28
|
+
const [draft, setDraft] = React.useState(current);
|
|
29
|
+
const [saving, setSaving] = React.useState(false);
|
|
30
|
+
const [error, setError] = React.useState(false);
|
|
31
|
+
React.useEffect(function () { setDraft(current); }, [snapshot.revision, current]);
|
|
32
|
+
const dirty = draft !== current;
|
|
33
|
+
const writable = snapshot.writable && snapshot.status === "ready";
|
|
34
|
+
function save() {
|
|
35
|
+
if (!dirty || saving || !writable) return;
|
|
36
|
+
setSaving(true);
|
|
37
|
+
setError(false);
|
|
38
|
+
props.setShowTechnicalDetails(draft)
|
|
39
|
+
.catch(function () { setError(true); })
|
|
40
|
+
.finally(function () { setSaving(false); });
|
|
41
|
+
}
|
|
42
|
+
function reset() {
|
|
43
|
+
if (!writable) return;
|
|
44
|
+
setDraft(snapshot.base?.showTechnicalDetails !== false);
|
|
45
|
+
}
|
|
46
|
+
return React.createElement("section", { style: { padding: "12px 0", maxWidth: "760px" } },
|
|
47
|
+
React.createElement("h3", { style: { margin: "0 0 4px" } }, uiText("跨会话消息", "Agent messages")),
|
|
48
|
+
React.createElement("p", { style: { color: "var(--dsw-alias-label-tertiary)", margin: "0 0 12px", fontSize: "13px" } }, uiText("控制投递卡片是否显示传输细节。messageId 始终保留。", "Control transport details in delivery cards. The messageId is always kept.")),
|
|
49
|
+
React.createElement("label", { style: { display: "flex", gap: "8px", alignItems: "center" } },
|
|
50
|
+
React.createElement("input", { type: "checkbox", checked: draft, disabled: !writable, onChange: function (event) { setDraft(event.target.checked); } }),
|
|
51
|
+
uiText("显示投递模式和目标运行状态", "Show delivery mode and target runtime status")),
|
|
52
|
+
error ? React.createElement("p", { role: "alert", style: { color: "var(--dsw-alias-state-error)", margin: "10px 0 0", fontSize: "13px" } }, uiText("保存失败,设置可能已被其他页面修改。", "Save failed; the setting may have changed elsewhere.")) : null,
|
|
53
|
+
React.createElement("div", { style: { display: "flex", gap: "8px", marginTop: "14px" } },
|
|
54
|
+
React.createElement("button", { type: "button", disabled: !dirty || saving || !writable, onClick: reset }, uiText("恢复默认", "Reset")),
|
|
55
|
+
React.createElement("button", { type: "button", disabled: !dirty || saving || !writable, onClick: save }, saving ? uiText("保存中…", "Saving…") : uiText("保存", "Save")))
|
|
56
|
+
);
|
|
37
57
|
}
|
|
38
58
|
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
if (ctx.settingsScope !== undefined && ctx.slots !== undefined) {
|
|
60
|
+
const scope = ctx.settingsScope.bind({ namespace: AGENT_MESSAGE_SETTINGS_NAMESPACE });
|
|
61
|
+
const agentMessageSettingsStore = {
|
|
62
|
+
getSnapshot: function () { return scope.getSnapshot(); },
|
|
63
|
+
subscribe: function (listener) { return scope.subscribe(listener); },
|
|
64
|
+
};
|
|
65
|
+
ctx.slots.inject("settings.plugin.item", function () {
|
|
66
|
+
return ctx.slots.register({
|
|
67
|
+
name: "settings.plugin.item",
|
|
68
|
+
key: AGENT_MESSAGE_SETTINGS_NAMESPACE,
|
|
69
|
+
inject: function () {
|
|
70
|
+
return {
|
|
71
|
+
hooks: { agentMessageSettings: agentMessageSettingsStore },
|
|
72
|
+
setShowTechnicalDetails: function (value) { return scope.set("showTechnicalDetails", value); },
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
}, AgentMessageSettingsCard);
|
|
76
|
+
});
|
|
41
77
|
}
|
|
42
78
|
|
|
43
|
-
function
|
|
44
|
-
return
|
|
79
|
+
function uiText(zh, en) {
|
|
80
|
+
return getLocaleSnapshot().active === "zh" ? zh : en;
|
|
45
81
|
}
|
|
46
82
|
|
|
47
|
-
function
|
|
48
|
-
|
|
49
|
-
return chars.length > 40 ? chars.slice(0, 39).join("") + "…" : chars.join("");
|
|
83
|
+
function sessionRow(id) {
|
|
84
|
+
return ctx.sessions.list.getSnapshot().byId[id];
|
|
50
85
|
}
|
|
51
86
|
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
if (!root) {
|
|
55
|
-
root = createRoot(host);
|
|
56
|
-
mountedRoots.set(host, root);
|
|
57
|
-
host.setAttribute("data-agent-msg-react-root", "true");
|
|
58
|
-
}
|
|
59
|
-
root.render(content);
|
|
87
|
+
function sessionTitle(row) {
|
|
88
|
+
return String(row?.displayTitle || row?.title || row?.id || "");
|
|
60
89
|
}
|
|
61
90
|
|
|
62
91
|
function cleanupRoots(node) {
|
|
63
92
|
if (!(node instanceof Element)) return;
|
|
64
|
-
const hosts = node.matches(reactRootSelector)
|
|
65
|
-
? [node].concat(Array.from(node.querySelectorAll(reactRootSelector)))
|
|
66
|
-
: Array.from(node.querySelectorAll(reactRootSelector));
|
|
67
|
-
hosts.forEach(function (host) {
|
|
68
|
-
const root = mountedRoots.get(host);
|
|
69
|
-
if (!root) return;
|
|
70
|
-
root.unmount();
|
|
71
|
-
mountedRoots.delete(host);
|
|
72
|
-
});
|
|
73
93
|
const links = node.matches(".agent-msg-session-link")
|
|
74
94
|
? [node].concat(Array.from(node.querySelectorAll(".agent-msg-session-link")))
|
|
75
95
|
: Array.from(node.querySelectorAll(".agent-msg-session-link"));
|
|
76
96
|
links.forEach(function (element) { sessionLinks.delete(element); });
|
|
77
97
|
}
|
|
78
98
|
|
|
79
|
-
function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
: React.createElement("span", { className: "agent-msg-status-dot agent-msg-status-dot-idle", "aria-hidden": "true" });
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function SessionReference(props) {
|
|
86
|
-
return React.createElement("span", { className: "agent-msg-reference-content" },
|
|
87
|
-
React.createElement(IconQueueOutline14, { size: 14, className: "agent-msg-session-icon" }),
|
|
88
|
-
React.createElement("span", { className: "agent-msg-reference-title" }, "@" + sessionTitle(props.row)));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function RelaySender(props) {
|
|
92
|
-
return React.createElement("span", { className: "agent-msg-relay-sender-content" },
|
|
93
|
-
React.createElement(IconQueueOutline14, { size: 14, className: "agent-msg-session-icon" }),
|
|
94
|
-
React.createElement("span", null, uiText("来自会话 · ", "From Session · ") + props.title + ":"));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function enhanceReferenceHost(element, row) {
|
|
98
|
-
let host = element.querySelector(":scope > .agent-msg-reference-host");
|
|
99
|
-
if (!host) {
|
|
100
|
-
element.textContent = "";
|
|
101
|
-
host = document.createElement("span");
|
|
102
|
-
host.className = "agent-msg-reference-host";
|
|
103
|
-
element.appendChild(host);
|
|
99
|
+
function restoreSender(element) {
|
|
100
|
+
if (element.dataset.agentMsgOriginalText !== undefined) {
|
|
101
|
+
element.textContent = element.dataset.agentMsgOriginalText;
|
|
104
102
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
ctx.effect(() => inputTriggers.registerSource({
|
|
111
|
-
trigger: "@",
|
|
112
|
-
name: referenceSource,
|
|
113
|
-
order: 2,
|
|
114
|
-
async candidates(session, request) {
|
|
115
|
-
if (request.position !== "leading") return [];
|
|
116
|
-
const query = String(request.query || "").toLowerCase();
|
|
117
|
-
return sessionRows(false)
|
|
118
|
-
.filter(function (row) {
|
|
119
|
-
return String(row.id) !== String(session.sessionId)
|
|
120
|
-
&& (query === "" || sessionTitle(row).toLowerCase().includes(query));
|
|
121
|
-
})
|
|
122
|
-
.sort(function (a, b) {
|
|
123
|
-
if (a.running !== b.running) return a.running ? -1 : 1;
|
|
124
|
-
return sessionTitle(a).localeCompare(sessionTitle(b));
|
|
125
|
-
})
|
|
126
|
-
.map(function (row) {
|
|
127
|
-
const candidate = {
|
|
128
|
-
name: sessionTitle(row),
|
|
129
|
-
description: row.running ? uiText("运行中", "Running") : uiText("空闲", "Idle"),
|
|
130
|
-
icon: "",
|
|
131
|
-
};
|
|
132
|
-
candidateRows.set(candidate, row);
|
|
133
|
-
return candidate;
|
|
134
|
-
});
|
|
135
|
-
},
|
|
136
|
-
onPick({ candidate, session }) {
|
|
137
|
-
const row = candidateRows.get(candidate);
|
|
138
|
-
if (!row) return undefined;
|
|
139
|
-
const label = "@" + compactSessionTitle(row);
|
|
140
|
-
return {
|
|
141
|
-
claim: {
|
|
142
|
-
token: label + " ",
|
|
143
|
-
hint: uiText("输入要处理的内容", "Describe what to do"),
|
|
144
|
-
async submit(args) {
|
|
145
|
-
const content = String(args || "").trim();
|
|
146
|
-
if (content === "") return { kind: "error", text: uiText("请输入要处理的内容", "Describe what to do") };
|
|
147
|
-
const binding = ctx.sessions.binding(session.sessionId);
|
|
148
|
-
if (!binding) return { kind: "error", text: uiText("当前会话不可用", "Current session is unavailable") };
|
|
149
|
-
const result = await binding.session.prompt([{
|
|
150
|
-
type: "text",
|
|
151
|
-
text: "@" + String(row.id) + " " + content,
|
|
152
|
-
}], "queue");
|
|
153
|
-
return result.ok
|
|
154
|
-
? { kind: "success" }
|
|
155
|
-
: { kind: "error", text: result.error.message };
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
|
-
}), "dsh-agent-message: @ session source");
|
|
103
|
+
delete element.dataset.agentMsgOriginalText;
|
|
104
|
+
delete element.dataset.agentMsgSessionId;
|
|
105
|
+
delete element.dataset.agentMsgSenderTitle;
|
|
106
|
+
element.classList.remove("agent-msg-session-link", "agent-msg-sender-link");
|
|
107
|
+
["role", "tabindex", "title", "aria-label"].forEach(function (name) { element.removeAttribute(name); });
|
|
161
108
|
}
|
|
162
109
|
|
|
163
110
|
function senderLink(target) {
|
|
@@ -171,24 +118,6 @@ window.__ModuleLoader__.load({
|
|
|
171
118
|
return match ? { element: element, sessionId: match[0] } : null;
|
|
172
119
|
}
|
|
173
120
|
|
|
174
|
-
function titleFrom(text) {
|
|
175
|
-
const line = String(text || "").split("\n", 1)[0].trim();
|
|
176
|
-
const current = line.match(/^(?:From (?:Session|Agent)|来自会话)(?: ·)? (.+?):(?: @session-[\w-]+)?$/);
|
|
177
|
-
const previous = line.match(/^来自 Agent · (.+)$/);
|
|
178
|
-
const legacy = line.match(/^来自 Agent「(.+)」\s*[·::]?$/);
|
|
179
|
-
return (current || previous || legacy)?.[1]?.trim() || "";
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function senderTitle(element) {
|
|
183
|
-
if (element.dataset.agentMsgSenderTitle) return element.dataset.agentMsgSenderTitle;
|
|
184
|
-
const label = element.previousElementSibling;
|
|
185
|
-
const title = titleFrom(label?.textContent);
|
|
186
|
-
if (title && label) {
|
|
187
|
-
label.classList.add("agent-msg-sender-prefix");
|
|
188
|
-
}
|
|
189
|
-
return title;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
121
|
function prepareSenderLinks(root) {
|
|
193
122
|
if (!(root instanceof Element)) return;
|
|
194
123
|
const elements = root.matches(senderSelector)
|
|
@@ -197,13 +126,13 @@ window.__ModuleLoader__.load({
|
|
|
197
126
|
elements.forEach(function (element) {
|
|
198
127
|
const link = senderLink(element);
|
|
199
128
|
if (!link) return;
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
129
|
+
const title = sessionTitle(sessionRow(link.sessionId)) || "@" + link.sessionId;
|
|
130
|
+
if (element.dataset.agentMsgOriginalText === undefined) {
|
|
131
|
+
element.dataset.agentMsgOriginalText = element.textContent || "";
|
|
132
|
+
}
|
|
203
133
|
element.dataset.agentMsgSessionId = link.sessionId;
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
else element.textContent = uiText("来自会话 · ", "From Session · ") + title + ":";
|
|
134
|
+
element.dataset.agentMsgSenderTitle = title;
|
|
135
|
+
element.textContent = uiText("来自会话 · ", "From Session · ") + title + ":";
|
|
207
136
|
element.classList.add("agent-msg-session-link", "agent-msg-sender-link");
|
|
208
137
|
sessionLinks.add(element);
|
|
209
138
|
element.setAttribute("role", "link");
|
|
@@ -240,74 +169,18 @@ window.__ModuleLoader__.load({
|
|
|
240
169
|
});
|
|
241
170
|
}
|
|
242
171
|
|
|
243
|
-
function prepareSessionReferences(root) {
|
|
244
|
-
if (!(root instanceof Element)) return;
|
|
245
|
-
const elements = root.matches('[data-ref-chip="subagent"]')
|
|
246
|
-
? [root].concat(Array.from(root.querySelectorAll('[data-ref-chip="subagent"]')))
|
|
247
|
-
: Array.from(root.querySelectorAll('[data-ref-chip="subagent"]'));
|
|
248
|
-
elements.forEach(function (element) {
|
|
249
|
-
if (element.classList.contains("agent-msg-sender-link")) return;
|
|
250
|
-
const id = element.dataset.agentMsgSessionId
|
|
251
|
-
|| String(element.textContent || "").trim().match(/^@(session-[\w-]+)$/)?.[1];
|
|
252
|
-
const row = id ? sessionRow(id) : undefined;
|
|
253
|
-
if (!id || !row) return;
|
|
254
|
-
element.dataset.agentMsgSessionId = id;
|
|
255
|
-
element.classList.add("agent-msg-session-link", "agent-msg-reference-link");
|
|
256
|
-
sessionLinks.add(element);
|
|
257
|
-
element.setAttribute("role", "link");
|
|
258
|
-
element.setAttribute("tabindex", "0");
|
|
259
|
-
element.setAttribute("title", uiText("打开引用会话", "Open referenced session"));
|
|
260
|
-
element.setAttribute("aria-label", uiText("打开引用会话:", "Open referenced session: ") + sessionTitle(row));
|
|
261
|
-
enhanceReferenceHost(element, row);
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function prepareSessionMenu(root) {
|
|
266
|
-
if (!(root instanceof Element)) return;
|
|
267
|
-
const menu = root.matches('[role="listbox"]') ? root : root.closest('[role="listbox"]') || root.querySelector('[role="listbox"]');
|
|
268
|
-
if (!menu) return;
|
|
269
|
-
const group = menu.querySelector('[data-source="' + referenceSource + '"]');
|
|
270
|
-
if (!group) return;
|
|
271
|
-
group.textContent = uiText("会话", "Sessions");
|
|
272
|
-
let element = group.nextElementSibling;
|
|
273
|
-
while (element && !element.hasAttribute("data-source")) {
|
|
274
|
-
if (element.matches('button[role="option"]')) {
|
|
275
|
-
element.classList.add("agent-msg-session-candidate");
|
|
276
|
-
const spans = element.querySelectorAll(":scope > span");
|
|
277
|
-
const icon = spans[0];
|
|
278
|
-
const description = spans[2];
|
|
279
|
-
if (icon) {
|
|
280
|
-
icon.classList.add("agent-msg-candidate-icon");
|
|
281
|
-
renderInto(icon, React.createElement(IconQueueOutline14, { size: 14 }));
|
|
282
|
-
}
|
|
283
|
-
if (description) {
|
|
284
|
-
const running = /^(运行中|Running)$/.test(String(description.textContent || "").trim())
|
|
285
|
-
|| element.dataset.agentMsgRunning === "true";
|
|
286
|
-
element.dataset.agentMsgRunning = String(running);
|
|
287
|
-
renderInto(description, React.createElement("span", { className: "agent-msg-status-label" },
|
|
288
|
-
React.createElement(SessionActivity, { running: running }),
|
|
289
|
-
React.createElement("span", null, running ? uiText("运行中", "Running") : uiText("空闲", "Idle"))));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
element = element.nextElementSibling;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
172
|
function prepare(root) {
|
|
297
173
|
prepareRelayCards(root);
|
|
298
174
|
prepareSenderLinks(root);
|
|
299
|
-
prepareSessionReferences(root);
|
|
300
|
-
prepareSessionMenu(root);
|
|
301
175
|
}
|
|
302
176
|
|
|
303
|
-
function
|
|
177
|
+
function refreshSenderLinks() {
|
|
304
178
|
sessionLinks.forEach(function (element) {
|
|
305
179
|
if (!element.isConnected) {
|
|
306
180
|
sessionLinks.delete(element);
|
|
307
181
|
return;
|
|
308
182
|
}
|
|
309
|
-
|
|
310
|
-
else prepareSessionReferences(element);
|
|
183
|
+
prepareSenderLinks(element);
|
|
311
184
|
});
|
|
312
185
|
}
|
|
313
186
|
|
|
@@ -357,6 +230,7 @@ window.__ModuleLoader__.load({
|
|
|
357
230
|
}
|
|
358
231
|
|
|
359
232
|
function CopyButton(props) {
|
|
233
|
+
useLocale();
|
|
360
234
|
const [copyState, setCopyState] = React.useState("idle");
|
|
361
235
|
async function onClick() {
|
|
362
236
|
const text = String(props.sessionId || "");
|
|
@@ -387,25 +261,11 @@ window.__ModuleLoader__.load({
|
|
|
387
261
|
const css =
|
|
388
262
|
".agent-msg-copy-id { cursor: pointer; font-size: 12px; line-height: 1; padding: 5px 10px; border: 1px solid rgba(127,127,127,.35); border-radius: 6px; background: transparent; color: inherit; opacity: .85; } " +
|
|
389
263
|
".agent-msg-copy-id:hover { opacity: 1; border-color: rgba(127,127,127,.7); } " +
|
|
390
|
-
".agent-msg-sender-prefix { display: none !important; } " +
|
|
391
264
|
".agent-msg-session-link { cursor: pointer; text-decoration: none; } " +
|
|
392
|
-
".agent-msg-sender-link[data-ref-chip=\"subagent\"] { display: block; width: fit-content; padding: 0; background: transparent; color: inherit; font-size: 13px; font-weight: 600; line-height: 1.5; } " +
|
|
393
|
-
".agent-msg-reference-link { display: inline-flex !important; align-items: center; color: var(--dsw-alias-state-business-primary) !important; } " +
|
|
394
|
-
".agent-msg-reference-host, .agent-msg-reference-content { display: inline-flex; min-width: 0; align-items: center; } " +
|
|
395
|
-
".agent-msg-reference-content { gap: 5px; max-width: 100%; } " +
|
|
396
|
-
".agent-msg-reference-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } " +
|
|
397
|
-
".agent-msg-session-icon, .agent-msg-candidate-icon { display: inline-flex; flex: none; color: var(--dsw-alias-state-business-primary); } " +
|
|
398
|
-
".agent-msg-relay-sender-content { display: inline-flex; align-items: center; gap: 5px; } " +
|
|
399
265
|
"[data-agent-msg-relay-card] [data-disclosure-row] { display: none !important; } " +
|
|
400
266
|
"[data-agent-msg-relay-card] [data-context-form=\"relay\"] { width: fit-content; max-width: min(78%, 760px); max-height: none; margin: 0; padding: 14px 16px; overflow: visible; border: 1px solid rgba(127,127,127,.24); border-radius: 16px 16px 16px 4px; background: var(--dsw-alias-markdown-code-block); color: var(--dsw-alias-label-primary); font: inherit; } " +
|
|
401
267
|
"[data-agent-msg-relay-card] [data-context-relay-sender] { display: block; width: fit-content; margin: 0 0 8px; color: var(--dsw-alias-state-business-primary); font-size: 13px; font-weight: 600; line-height: 1.5; } " +
|
|
402
268
|
"[data-agent-msg-relay-card] [data-context-text] { margin: 0; overflow: visible; white-space: pre-wrap; overflow-wrap: anywhere; color: inherit; font: inherit; } " +
|
|
403
|
-
".agent-msg-status-dot { flex: none; } " +
|
|
404
|
-
".agent-msg-status-dot-idle { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--dsw-alias-label-tertiary); opacity: .7; } " +
|
|
405
|
-
".agent-msg-status-label { display: inline-flex; align-items: center; gap: 6px; } " +
|
|
406
|
-
".agent-msg-session-candidate { border-radius: 0 !important; } " +
|
|
407
|
-
".agent-msg-session-candidate > span:nth-child(2) { flex: 1; min-width: 0; max-width: none; } " +
|
|
408
|
-
".agent-msg-session-candidate > span:nth-child(3) { display: flex; flex: none; justify-content: flex-end; margin-left: auto; } " +
|
|
409
269
|
".agent-msg-session-link:hover { text-decoration: underline; text-underline-offset: 3px; } " +
|
|
410
270
|
".agent-msg-session-link:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; border-radius: 2px; }";
|
|
411
271
|
const tag = document.createElement("style");
|
|
@@ -420,18 +280,17 @@ window.__ModuleLoader__.load({
|
|
|
420
280
|
});
|
|
421
281
|
});
|
|
422
282
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
423
|
-
const unsubscribeSessions = ctx.sessions.list.subscribe(
|
|
424
|
-
const
|
|
283
|
+
const unsubscribeSessions = ctx.sessions.list.subscribe(refreshSenderLinks);
|
|
284
|
+
const unsubscribeLocale = ctx.locale.subscribe(refreshSenderLinks);
|
|
425
285
|
document.addEventListener("click", openSender);
|
|
426
286
|
document.addEventListener("keydown", onKeyDown);
|
|
427
287
|
ctx.effect(() => () => {
|
|
428
288
|
observer.disconnect();
|
|
429
289
|
unsubscribeSessions();
|
|
430
|
-
|
|
290
|
+
unsubscribeLocale();
|
|
431
291
|
document.removeEventListener("click", openSender);
|
|
432
292
|
document.removeEventListener("keydown", onKeyDown);
|
|
433
|
-
|
|
434
|
-
mountedRoots.clear();
|
|
293
|
+
sessionLinks.forEach(restoreSender);
|
|
435
294
|
sessionLinks.clear();
|
|
436
295
|
tag.remove();
|
|
437
296
|
});
|
package/lib/index.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
2
2
|
import { createUserMessage, freezeMessage } from '@deepseek-ai/dsh-llm/message'
|
|
3
|
+
import z from '@deepseek-ai/schemastery'
|
|
4
|
+
import { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings'
|
|
3
5
|
|
|
4
6
|
export const name = 'dsh-agent-message'
|
|
5
7
|
export const inject = ['agents', 'tools', 'sessionQuery']
|
|
6
8
|
|
|
9
|
+
const AGENT_MESSAGE_SETTINGS_NAMESPACE = settingsNamespace('agent-message')
|
|
10
|
+
const AGENT_MESSAGE_SETTINGS_SCHEMA = z.object({ showTechnicalDetails: z.boolean().default(true) })
|
|
11
|
+
|
|
7
12
|
export function apply(ctx) {
|
|
8
13
|
const agents = ctx.agents
|
|
14
|
+
let settingsSource = () => ({ showTechnicalDetails: true })
|
|
9
15
|
/** messageId -> { to, at, mode };发送成功即记账,供批量查询及补充本进程发送信息。 */
|
|
10
16
|
const sent = new Map()
|
|
11
17
|
/** 记账表 FIFO 上限:超过则淘汰最老记录,内存恒定。 */
|
|
@@ -19,6 +25,16 @@ export function apply(ctx) {
|
|
|
19
25
|
const pairSends = new Map()
|
|
20
26
|
let lastPairPruneAt = 0
|
|
21
27
|
|
|
28
|
+
// 设置由 Cordis 注入;旧版测试宿主没有 inject 时继续使用默认行为。
|
|
29
|
+
if (typeof ctx.inject === 'function') {
|
|
30
|
+
installSettingsSection(ctx, AGENT_MESSAGE_SETTINGS_NAMESPACE, AGENT_MESSAGE_SETTINGS_SCHEMA, { showTechnicalDetails: true }, {
|
|
31
|
+
setSource(source) {
|
|
32
|
+
settingsSource = source
|
|
33
|
+
},
|
|
34
|
+
onChange() {},
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
ctx.effect(() => async () => {
|
|
23
39
|
const handles = [...resumedHandles.values()]
|
|
24
40
|
resumedHandles.clear()
|
|
@@ -56,7 +72,8 @@ export function apply(ctx) {
|
|
|
56
72
|
const recent = (pairSends.get(key) ?? []).filter((entry) => now - entry.at < PAIR_WINDOW_MS)
|
|
57
73
|
if (recent.length >= PAIR_MESSAGE_LIMIT) {
|
|
58
74
|
pairSends.set(key, recent)
|
|
59
|
-
|
|
75
|
+
const retryAfterSeconds = Math.max(1, Math.ceil((PAIR_WINDOW_MS - (now - recent[0].at)) / 1000))
|
|
76
|
+
throw new Error('同一对会话 60 秒内最多投递 10 条消息;请勿立即重试,约 ' + retryAfterSeconds + ' 秒后窗口重置')
|
|
60
77
|
}
|
|
61
78
|
const reservation = { at: now }
|
|
62
79
|
recent.push(reservation)
|
|
@@ -280,8 +297,8 @@ export function apply(ctx) {
|
|
|
280
297
|
},
|
|
281
298
|
output: {
|
|
282
299
|
schema: { type: 'json' },
|
|
283
|
-
render() {
|
|
284
|
-
return [{ type: 'text', text: '
|
|
300
|
+
render(_args, value) {
|
|
301
|
+
return [{ type: 'text', text: '已投递。\nmessageId: ' + value.messageId }]
|
|
285
302
|
},
|
|
286
303
|
presentationMeta(_args, value) {
|
|
287
304
|
return value
|
|
@@ -290,10 +307,16 @@ export function apply(ctx) {
|
|
|
290
307
|
presentResult(_args, result) {
|
|
291
308
|
const meta = result.meta
|
|
292
309
|
if (result.isError || meta === null || typeof meta !== 'object' || Array.isArray(meta)) return
|
|
310
|
+
const messageId = typeof meta.messageId === 'string' ? meta.messageId : ''
|
|
311
|
+
const text = (typeof meta.text === 'string' ? meta.text : '已投递。')
|
|
312
|
+
+ (messageId ? '\nmessageId: ' + messageId : '')
|
|
313
|
+
const details = settingsSource().showTechnicalDetails
|
|
314
|
+
? '\n' + JSON.stringify({ to: meta.to, mode: meta.mode, state: meta.state, targetRuntimeStatus: meta.targetRuntimeStatus })
|
|
315
|
+
: ''
|
|
293
316
|
return {
|
|
294
317
|
card: 'generic',
|
|
295
318
|
title: '消息已投递',
|
|
296
|
-
content: [{ type: 'text', text:
|
|
319
|
+
content: [{ type: 'text', text: text + details }],
|
|
297
320
|
}
|
|
298
321
|
},
|
|
299
322
|
async execute(args, exec) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-agent-message",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"packageManager": "pnpm@11.1.1",
|
|
5
5
|
"description": "跨会话 Agent 通信:让 DeepSeek Harness 里不同的 Agent 会话互相收发消息。",
|
|
6
6
|
"keywords": ["deepseek", "deepseek-harness", "agent", "multi-agent", "messaging"],
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"main": "./lib/index.js",
|
|
15
|
-
"scripts": {
|
|
15
|
+
"scripts": {
|
|
16
|
+
"test": "node --test",
|
|
17
|
+
"test:web-smoke": "node scripts/web-smoke.mjs"
|
|
18
|
+
},
|
|
16
19
|
"exports": {
|
|
17
20
|
".": { "default": "./lib/index.js" },
|
|
18
21
|
"./client": { "default": "./lib/client.js" },
|
|
@@ -26,10 +29,11 @@
|
|
|
26
29
|
"platform": "web",
|
|
27
30
|
"inject": [
|
|
28
31
|
"@deepseek-ai/dsh-client-runtime",
|
|
32
|
+
"@deepseek-ai/dsh-client-locale",
|
|
29
33
|
"@deepseek-ai/dsh-client-ui-slots",
|
|
30
|
-
"@deepseek-ai/dsh-client-ui-
|
|
31
|
-
"@deepseek-ai/dsh-client-ui-
|
|
32
|
-
"@deepseek-ai/dsh-client-ui-
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
35
|
+
"@deepseek-ai/dsh-client-ui-settings-plugins",
|
|
36
|
+
"@deepseek-ai/dsh-client-ui-conversation"
|
|
33
37
|
]
|
|
34
38
|
}
|
|
35
39
|
},
|
|
@@ -41,16 +45,20 @@
|
|
|
41
45
|
},
|
|
42
46
|
"peerDependencies": {
|
|
43
47
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
44
|
-
"@deepseek-ai/dsh-
|
|
45
|
-
"@deepseek-ai/dsh-
|
|
48
|
+
"@deepseek-ai/dsh-settings": ">=0.1.1-rc.2 <0.2.0",
|
|
49
|
+
"@deepseek-ai/dsh-llm": ">=0.1.1-rc.2 <0.2.0",
|
|
50
|
+
"@deepseek-ai/dsh-tools": ">=0.1.1-rc.2 <0.2.0",
|
|
51
|
+
"@deepseek-ai/schemastery": ">=3.18.1 <4.0.0"
|
|
46
52
|
},
|
|
47
53
|
"devDependencies": {
|
|
48
|
-
"@deepseek-ai/dsh-llm": "0.1.
|
|
49
|
-
"@deepseek-ai/dsh-
|
|
54
|
+
"@deepseek-ai/dsh-llm": "0.1.1-rc.2",
|
|
55
|
+
"@deepseek-ai/dsh-settings": "0.1.1-rc.2",
|
|
56
|
+
"@deepseek-ai/dsh-tools": "0.1.1-rc.2",
|
|
57
|
+
"@deepseek-ai/schemastery": "3.18.1"
|
|
50
58
|
},
|
|
51
59
|
"engines": {
|
|
52
60
|
"node": ">=24 <25",
|
|
53
|
-
"dsh": ">=0.1.
|
|
61
|
+
"dsh": ">=0.1.1-rc.2 <0.2.0"
|
|
54
62
|
},
|
|
55
63
|
"license": "MIT"
|
|
56
64
|
}
|