dsh-aimail 0.1.11 → 0.1.12-rc.2
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 +4 -4
- package/lib/inbound.js +30 -1
- package/lib/tools.d.ts +1 -1
- package/package.json +3 -3
- package/resources/board/role_prompt_en/common.md +0 -1
- package/resources/board/role_prompt_en/orchestrator.md +0 -2
- package/resources/board/role_prompt_en/worker.md +1 -2
- package/resources/board/role_prompt_zh/common.md +0 -1
- package/resources/board/role_prompt_zh/orchestrator.md +0 -2
- package/resources/board/role_prompt_zh/worker.md +1 -2
- package/resources/skills/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
AIMail plugin for dsh (deepseek-harness). It gives a dsh agent a mailbox on
|
|
4
4
|
AIMail: inbound email is delivered into the agent's session, and the agent
|
|
5
5
|
can send mail, manage contacts, keep thread notes, and work on A2A boards
|
|
6
|
-
through
|
|
6
|
+
through 15 plain tools.
|
|
7
7
|
|
|
8
8
|
## Install
|
|
9
9
|
|
|
@@ -24,11 +24,11 @@ dsh plugin --profile web remove dsh-aimail
|
|
|
24
24
|
|
|
25
25
|
## What it does
|
|
26
26
|
|
|
27
|
-
**Tools** — the same
|
|
27
|
+
**Tools** — the same 15 bare-name tools as every other adapter:
|
|
28
28
|
`send_mail`, `manage_contacts`, `contact_profile`, `set_contact_profile`,
|
|
29
29
|
`email_summary`, `set_email_summary`, `search_mail`,
|
|
30
30
|
`board_status`, `board_task_list`, `board_task_show`, `board_heartbeat`,
|
|
31
|
-
`board_members`, `set_public_whoami`.
|
|
31
|
+
`board_members`, `board_roles`, `set_public_whoami`, `activate_address_code`.
|
|
32
32
|
Identity comes from the session id resolved through `@aimail/mail`
|
|
33
33
|
(`agentmail.json` is the sole identity source); unbound sessions fail loud.
|
|
34
34
|
|
|
@@ -47,7 +47,7 @@ workflow (reply-all semantics, tool selection, thread continuity).
|
|
|
47
47
|
|
|
48
48
|
The same tool surface and inbound contract, bound to other agent platforms:
|
|
49
49
|
|
|
50
|
-
- [openclaw-aimail](https://www.npmjs.com/package/openclaw-aimail) — AIMail plugin for OpenClaw — definePluginEntry:
|
|
50
|
+
- [openclaw-aimail](https://www.npmjs.com/package/openclaw-aimail) — AIMail plugin for OpenClaw — definePluginEntry: 15 tools, in-gateway HTTP route, register/status commands.
|
|
51
51
|
- [pi-aimail](https://www.npmjs.com/package/pi-aimail) — AIMail extension for pi (earendil-works/pi) — registerTool tools + local inbound listener bridged via sendUserMessage.
|
|
52
52
|
|
|
53
53
|
## Related repositories
|
package/lib/inbound.js
CHANGED
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
* continuity is aimail's (local meta threading), not the session's.
|
|
13
13
|
* 200 ack on delivery; 503 on session-create failure (bridge retries).
|
|
14
14
|
*/
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as os from 'node:os';
|
|
17
|
+
import * as path from 'node:path';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
15
19
|
import { createServer } from 'node:http';
|
|
16
20
|
import { randomUUID } from 'node:crypto';
|
|
17
21
|
import { createUserMessage } from '@deepseek-ai/dsh-llm';
|
|
@@ -36,6 +40,31 @@ export function apply(ctx, config = {}) {
|
|
|
36
40
|
if (mail === undefined) {
|
|
37
41
|
throw new Error('mail-inbound requires the mail service: mount dsh-aimail/mail-service first');
|
|
38
42
|
}
|
|
43
|
+
// SDK-shipped skill → <dshHome>/skills/agentmail/ (idempotent;
|
|
44
|
+
// identical-content skip; dshHome resolution mirrors mail-service).
|
|
45
|
+
// SKILL.md owns the inbound-message protocol (6-step flow) — a
|
|
46
|
+
// different category from tool registration (tool usage). Symmetric
|
|
47
|
+
// across openclaw/dsh/pi.
|
|
48
|
+
try {
|
|
49
|
+
const dshHome = process.env.AIMAIL_SYSTEM_HOME?.trim() ||
|
|
50
|
+
process.env.DSH_HOME?.trim() ||
|
|
51
|
+
path.join(os.homedir(), '.dsh');
|
|
52
|
+
const skillSrc = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'resources', 'skills');
|
|
53
|
+
const skillDst = path.join(dshHome, 'skills', 'agentmail');
|
|
54
|
+
fs.mkdirSync(skillDst, { recursive: true });
|
|
55
|
+
for (const f of ['SKILL.md', 'DESCRIPTION.md']) {
|
|
56
|
+
const from = path.join(skillSrc, f);
|
|
57
|
+
const to = path.join(skillDst, f);
|
|
58
|
+
if (!fs.existsSync(from))
|
|
59
|
+
continue;
|
|
60
|
+
if (fs.existsSync(to) && fs.readFileSync(from).equals(fs.readFileSync(to)))
|
|
61
|
+
continue;
|
|
62
|
+
fs.copyFileSync(from, to);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// non-fatal; retried on next plugin start
|
|
67
|
+
}
|
|
39
68
|
const host = config.host ?? '127.0.0.1';
|
|
40
69
|
const port = config.port ?? Number(process.env.AIMAIL_INBOUND_PORT ?? 9099);
|
|
41
70
|
const deliverPath = config.path ?? '/aimail/inbound';
|
|
@@ -56,7 +85,7 @@ export function apply(ctx, config = {}) {
|
|
|
56
85
|
}
|
|
57
86
|
// Inbound routing (Q3 — mirror Python bridge routing): the per-delivery
|
|
58
87
|
// target is authoritative. The bridge injects X-AIMail-Email (legacy
|
|
59
|
-
//
|
|
88
|
+
// on each single-delivery POST; payload.to is
|
|
60
89
|
// the FILTERED full list (external recipients first), so to[0] is often
|
|
61
90
|
// an external address. Use the header when present; only iterate toRaw
|
|
62
91
|
// when the header is absent (batch deliveries carry no such header).
|
package/lib/tools.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Semantic text (names, descriptions, parameter descriptions) comes from
|
|
5
5
|
* the shared MAIL_TOOLS registry in @aimail/mail-core (single source of
|
|
6
|
-
* truth, parity-tested against
|
|
6
|
+
* truth, parity-tested against aimail_mcp_server.py). This adapter only:
|
|
7
7
|
* - iterates MAIL_TOOLS, translating each entry to a dsh defineTool
|
|
8
8
|
* - binds execution: exec.agent.id (dsh session uuid) → ctx.mail.resolveCtx
|
|
9
9
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-aimail",
|
|
3
3
|
"description": "AIMail plugin for dsh — install via: dsh plugin --profile web add dsh-aimail",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.12-rc.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": true
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"@deepseek-ai/dsh-tools": "^0.0.1-rc.1"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@aimail/mail-core": "^0.1.
|
|
55
|
-
"@aimail/mail": "^0.1.
|
|
54
|
+
"@aimail/mail-core": "^0.1.12-rc.2",
|
|
55
|
+
"@aimail/mail": "^0.1.12-rc.2"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
@@ -18,7 +18,6 @@ Your AIMail address is **{{AGENTMAIL_ADDRESS}}**.
|
|
|
18
18
|
- `board_roles(board_id, role?)` — view role permissions
|
|
19
19
|
- `board_status(board_id)` — pipeline overview with dependencies
|
|
20
20
|
- `board_heartbeat(task_id, note?)` — long-task heartbeat (first call Ready→Running, assignee only)
|
|
21
|
-
- `board_continue_request(task_id, progress, note?)` — cross-session task continuation
|
|
22
21
|
|
|
23
22
|
## Key Instructions
|
|
24
23
|
|
|
@@ -11,11 +11,9 @@ Your email: {{AGENTMAIL_ADDRESS}}
|
|
|
11
11
|
- `[A2A] block <task-id>` / `[A2A] unblock <task-id>` — block/unblock task
|
|
12
12
|
- `[A2A] cancel <task-id>` — cancel Blocked-only task (block first, then cancel)
|
|
13
13
|
- `[A2A] reassign <task-id>` / `[A2A] edit <task-id>` / `[A2A] deadline <task-id>` — manage tasks
|
|
14
|
-
- `[A2A] notify_all` — broadcast notification (phase report, urgent)
|
|
15
14
|
- `[A2A] comment <task-id>` — add note
|
|
16
15
|
- `[A2A] arbitrate` — request admin arbitration
|
|
17
16
|
- `[A2A] list` / `[A2A] show` / `[A2A] members` / `[A2A] roles` / `[A2A] status` — queries
|
|
18
|
-
- `[A2A] continue` — resume cross-session task (worker-initiated)
|
|
19
17
|
|
|
20
18
|
### Session Flow (to members, CC Board)
|
|
21
19
|
|
|
@@ -6,11 +6,10 @@ Your email: {{AGENTMAIL_ADDRESS}}
|
|
|
6
6
|
### Instruction Flow Commands (to Board)
|
|
7
7
|
|
|
8
8
|
- `[A2A] complete <task-id>` — complete task with summary, Ready→Running on first call
|
|
9
|
-
- `[A2A] continue <task-id>` — request continuation for cross-session long task
|
|
10
9
|
- `[A2A] block <task-id>` — proactively block when stuck (your task, your right to report)
|
|
11
10
|
- `[A2A] comment <task-id>` — add note
|
|
12
11
|
- `[A2A] list` / `[A2A] show` / `[A2A] members` / `[A2A] roles` / `[A2A] status` — queries
|
|
13
|
-
- Use `board_heartbeat(task_id)` for long-running tasks (first call transitions Ready→Running).
|
|
12
|
+
- Use `board_heartbeat(task_id)` for long-running tasks (first call transitions Ready→Running).
|
|
14
13
|
|
|
15
14
|
### Cannot Initiate
|
|
16
15
|
|
|
@@ -11,11 +11,9 @@
|
|
|
11
11
|
- `[A2A] block <task-id>` / `[A2A] unblock <task-id>` — 阻塞/解除
|
|
12
12
|
- `[A2A] cancel <task-id>` — 取消 task(仅 Blocked 状态可 cancel,先 block 再 cancel)
|
|
13
13
|
- `[A2A] reassign <task-id>` / `[A2A] edit <task-id>` / `[A2A] deadline <task-id>` — 管理 task
|
|
14
|
-
- `[A2A] notify_all` — 全员通知(阶段汇报、紧急通知)
|
|
15
14
|
- `[A2A] comment <task-id>` — 添加备注
|
|
16
15
|
- `[A2A] arbitrate` — 提请管理员仲裁
|
|
17
16
|
- `[A2A] list` / `[A2A] show` / `[A2A] members` / `[A2A] roles` / `[A2A] status` — 查询
|
|
18
|
-
- `[A2A] continue` — 长任务延续(Worker 发起)
|
|
19
17
|
|
|
20
18
|
### 可发起会话流(→ 成员,CC Board)
|
|
21
19
|
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
### 可发起指令流指令(→ Board)
|
|
7
7
|
|
|
8
8
|
- `[A2A] complete <task-id>` — 完成任务,带 summary,首次 heartbeat Ready→Running
|
|
9
|
-
- `[A2A] continue <task-id>` — 长任务跨 session 延续
|
|
10
9
|
- `[A2A] block <task-id>` — 遇到困难主动 block(你的任务,你有权报告阻塞)
|
|
11
10
|
- `[A2A] comment <task-id>` — 添加备注
|
|
12
11
|
- `[A2A] list` / `[A2A] show` / `[A2A] members` / `[A2A] roles` / `[A2A] status` — 查询
|
|
13
|
-
- 长任务定期用 `board_heartbeat(task_id)` 发心跳(首次调用 Ready→Running
|
|
12
|
+
- 长任务定期用 `board_heartbeat(task_id)` 发心跳(首次调用 Ready→Running)。
|
|
14
13
|
|
|
15
14
|
### 不可发起
|
|
16
15
|
|
|
@@ -29,7 +29,7 @@ Each inbound email arrives as a JSON message. Key fields:
|
|
|
29
29
|
| `recipients` | `{to: [...], cc: [...]}` — everyone on the thread. Each is `Name <email>`. |
|
|
30
30
|
| `recipients_profile` | Profiles for all recipients except you. |
|
|
31
31
|
| `my_profile` | Your approved persona — who you are (single source of truth, set by your manager via `approve persona`). |
|
|
32
|
-
| `
|
|
32
|
+
| `my_aimail_addr` | Your identity with persona in this conversation. |
|
|
33
33
|
| `direct_message` | `true` = you're the only recipient. `false` = group conversation. |
|
|
34
34
|
| `mentioned` | Someone wrote `@your-name` in the body (only meaningful when `direct_message: false`). |
|
|
35
35
|
| `thread_summary` | Snapshot of active topics, decisions, and pending actions from previous exchanges. Pre-loaded from the last `set_email_summary` call. |
|