@pic-ai/pic-agent-call 1.0.2 → 1.0.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 +217 -0
- package/bin/server.mjs +25 -1
- package/package.json +1 -1
- package/src/status.mjs +13 -4
package/README.md
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# @pic-ai/pic-agent-call
|
|
2
|
+
|
|
3
|
+
> Cross-AI MCP server — Memory · Channel · Task-Broker · Agent Identity
|
|
4
|
+
|
|
5
|
+
讓 Claude Code、Gemini CLI、Copilot、Codex 共享記憶、溝通、協作的 MCP server。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **20 MCP tools** 涵蓋四大功能層
|
|
12
|
+
- **Memory** — 知識圖譜(SQLite),相容官方 MCP memory server schema
|
|
13
|
+
- **Channel** — 跨 AI 訊息傳遞,狀態機:UNREAD → IN_PROGRESS → READ / ORPHANED
|
|
14
|
+
- **Task-Broker** — 任務派發,feature+payload 冪等建立,BEGIN IMMEDIATE 原子搶鎖
|
|
15
|
+
- **Agent Identity** — `register_agent` / `agent_status`,per-session 身份管理與 statusline 顯示
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- **Node.js >= 22.0.0**(需要 `node:sqlite` built-in module)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
### Option A: npm / npx
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @pic-ai/pic-agent-call
|
|
31
|
+
# or run directly without installing
|
|
32
|
+
npx @pic-ai/pic-agent-call
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Option B: Local path(推薦用於 `.mcp.json` 設定)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/Vance-PIC/pic-agent-call.git
|
|
39
|
+
cd pic-agent-call
|
|
40
|
+
npm install
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
### Claude Code (`.mcp.json`)
|
|
48
|
+
|
|
49
|
+
在專案根目錄建立 `.mcp.json`:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"mcpServers": {
|
|
54
|
+
"agent-call": {
|
|
55
|
+
"command": "node",
|
|
56
|
+
"args": ["YOUR_PATH/pic-agent-call/bin/server.mjs"]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
將 `YOUR_PATH` 替換為你的本地絕對路徑,例如 `/Users/yourname/projects/pic-agent-call`。
|
|
63
|
+
|
|
64
|
+
### Gemini CLI (`~/.gemini/config/mcp_config.json`)
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"mcpServers": {
|
|
69
|
+
"agent-call": {
|
|
70
|
+
"command": "node",
|
|
71
|
+
"args": ["YOUR_PATH/pic-agent-call/bin/server.mjs"]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 環境變數
|
|
78
|
+
|
|
79
|
+
| Variable | Description | Default |
|
|
80
|
+
|----------|-------------|---------|
|
|
81
|
+
| `MEMORY_DB_PATH` | SQLite DB 路徑 | `.memory/memory-graph.db`(自動解析至 cwd 或 `~/.memory`)|
|
|
82
|
+
| `AGENT_ID` | Agent 識別名稱(可選,配合 `register_agent` 使用)| — |
|
|
83
|
+
|
|
84
|
+
DB 路徑解析優先序:`MEMORY_DB_PATH` env → `settings.local.json` → `cwd/.memory` → `~/.memory`
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Tools (20)
|
|
89
|
+
|
|
90
|
+
### Memory — Custom
|
|
91
|
+
|
|
92
|
+
| Tool | Description |
|
|
93
|
+
|------|-------------|
|
|
94
|
+
| `add-observation` | 向指定記憶實體寫入觀測紀錄。實體不存在時自動建立,並同步更新 JSON 快照。 |
|
|
95
|
+
| `query-entity` | 查詢指定記憶實體的完整資訊,含屬性、關係及所有歷程觀測紀錄。 |
|
|
96
|
+
| `stats` | 取得 SQLite 資料庫統計資訊(entities / relations / observations 筆數與路徑)。 |
|
|
97
|
+
|
|
98
|
+
### Memory — Official Compatible
|
|
99
|
+
|
|
100
|
+
相容 [官方 MCP memory server](https://github.com/modelcontextprotocol/servers/tree/main/src/memory) schema,可直接替換使用。
|
|
101
|
+
|
|
102
|
+
| Tool | Description |
|
|
103
|
+
|------|-------------|
|
|
104
|
+
| `create_entities` | 批次建立知識實體。同名實體已存在則忽略。 |
|
|
105
|
+
| `add_observations` | 向多個已存在實體添加觀測記錄。實體不存在則失敗。 |
|
|
106
|
+
| `create_relations` | 建立兩實體之間的單向關聯。實體不存在時自動建立臨時節點。 |
|
|
107
|
+
| `read_graph` | 讀取並匯出完整知識圖譜(所有實體、觀測紀錄及關係)。 |
|
|
108
|
+
| `search_nodes` | 模糊搜尋知識圖譜(範圍:實體名稱、類型、觀測紀錄內容)。 |
|
|
109
|
+
|
|
110
|
+
### Task-Broker
|
|
111
|
+
|
|
112
|
+
| Tool | Description |
|
|
113
|
+
|------|-------------|
|
|
114
|
+
| `create_task` | 建立任務。相同 feature+payload 具備冪等保護,不會重複建立。 |
|
|
115
|
+
| `list_pending_tasks` | 列出待處理任務。自動釋放逾時(>30 分鐘)的 claimed 任務。 |
|
|
116
|
+
| `claim_task` | 原子操作領取任務,BEGIN IMMEDIATE 確保排他性,防搶單。 |
|
|
117
|
+
| `complete_task` | 標記任務完成並寫回執行結果。任務須為 claimed 狀態。 |
|
|
118
|
+
| `fail_task` | 標記任務失敗並記錄原因。任務須為 claimed 狀態。 |
|
|
119
|
+
| `get_task` | 查詢單一任務的完整詳情。 |
|
|
120
|
+
|
|
121
|
+
### Channel
|
|
122
|
+
|
|
123
|
+
| Tool | Description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| `channel_send` | 傳送訊息給指定 AI 視窗或 pool(receiver 支援具體 ID / 萬用字元 / `all`)。 |
|
|
126
|
+
| `channel_list_unread` | 列出指定接收者的未讀訊息。自動釋放逾時 IN_PROGRESS(>15 分鐘)。 |
|
|
127
|
+
| `channel_claim` | 原子搶鎖:將 UNREAD 訊息標記為 IN_PROGRESS。BEGIN IMMEDIATE 保證同一訊息只有一個視窗成功。 |
|
|
128
|
+
| `channel_ack` | 確認完成:將 IN_PROGRESS 訊息標記為 READ。只有搶鎖者才能 ACK。 |
|
|
129
|
+
|
|
130
|
+
### Agent Identity
|
|
131
|
+
|
|
132
|
+
| Tool | Description |
|
|
133
|
+
|------|-------------|
|
|
134
|
+
| `register_agent` | 登記或更新當前 AI 視窗的身份(`agent_id` + `role`)。`session_id` 自動從環境變數讀取。換角色時自動處理孤兒訊息並通知原始發送者。 |
|
|
135
|
+
| `agent_status` | 查詢當前 AI 視窗的身份與未讀訊息數量。`session_id` 自動讀取。 |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Agent Identity & Statusline
|
|
140
|
+
|
|
141
|
+
`register_agent` 讓每個 AI session 具備獨立身份,供 Channel 路由與 statusline 顯示使用。
|
|
142
|
+
|
|
143
|
+
**Session ID 解析優先序:**
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
CLAUDE_CODE_SESSION_ID → ANTIGRAVITY_CONVERSATION_ID → AGENT_SESSION_ID → hostname-pid
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**呼叫範例:**
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
// Tool: register_agent
|
|
153
|
+
{
|
|
154
|
+
"agent_id": "CC-SA1",
|
|
155
|
+
"role": "SA"
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Statusline 顯示格式:**
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
[CC-SA1|SA] 📨3
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
表示 agent `CC-SA1`,角色 `SA`,有 3 則未讀訊息。
|
|
166
|
+
|
|
167
|
+
Claude Code 使用者可搭配 `bin/statusline.mjs` 將此資訊顯示在 statusbar(詳見 `bin/statusline.mjs`)。
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Multi-Agent Workflow Example
|
|
172
|
+
|
|
173
|
+
三步驟跨 AI 任務協作:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
Step 1 — SA creates a task for PG:
|
|
177
|
+
|
|
178
|
+
create_task(
|
|
179
|
+
feature="auth-feature",
|
|
180
|
+
assign_to="CC-PG1",
|
|
181
|
+
payload='{"action":"implement login endpoint"}'
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
Step 2 — PG polls and claims:
|
|
185
|
+
|
|
186
|
+
list_pending_tasks(assign_to="CC-PG1")
|
|
187
|
+
claim_task(task_id="...", agent_id="CC-PG1")
|
|
188
|
+
|
|
189
|
+
Step 3 — PG completes:
|
|
190
|
+
|
|
191
|
+
complete_task(task_id="...", result='{"status":"done","pr":"#42"}')
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
完整跨平台中繼鏈(CC → Gemini)範例見 `skills/agent-call.md`。
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Development
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
npm test # runs unit tests + P5 function tests
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
專案包含 unit tests(Jest)與 P5 功能驗收測試,測試報告產出至 `evidence/` 資料夾。
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
MIT
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Project
|
|
215
|
+
|
|
216
|
+
- **GitHub**: https://github.com/Vance-PIC/pic-agent-call
|
|
217
|
+
- **npm**: https://www.npmjs.com/package/@pic-ai/pic-agent-call
|
package/bin/server.mjs
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
5
7
|
import { resolveMemoryPaths, initDatabase } from '../src/db.mjs';
|
|
6
8
|
import * as memory from '../src/memory.mjs';
|
|
7
9
|
import * as channel from '../src/channel.mjs';
|
|
@@ -201,6 +203,23 @@ server.tool('channel_ack',
|
|
|
201
203
|
|
|
202
204
|
// ── Agent 身份管理 ────────────────────────────────────────────────────────────
|
|
203
205
|
|
|
206
|
+
function resolveTermKey() {
|
|
207
|
+
const ccId = process.env.CLAUDE_CODE_SESSION_ID;
|
|
208
|
+
if (ccId) return `cc-${ccId.slice(0, 8)}`;
|
|
209
|
+
const agyId = process.env.ANTIGRAVITY_CONVERSATION_ID;
|
|
210
|
+
if (agyId) return `agy-${agyId.slice(0, 8)}`;
|
|
211
|
+
return `ppid-${process.ppid}`;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function writeAgentSessionCache(agentId, termKey) {
|
|
215
|
+
try {
|
|
216
|
+
const sessionDir = path.join(path.dirname(dbPath), 'agent-sessions');
|
|
217
|
+
fs.mkdirSync(sessionDir, { recursive: true });
|
|
218
|
+
const filePath = path.join(sessionDir, `${termKey}.json`);
|
|
219
|
+
fs.writeFileSync(filePath, JSON.stringify({ agent_id: agentId, term_key: termKey, ts: new Date().toISOString() }), 'utf8');
|
|
220
|
+
} catch (_) {}
|
|
221
|
+
}
|
|
222
|
+
|
|
204
223
|
server.tool('register_agent',
|
|
205
224
|
'【agent】登記或更新當前 AI 視窗的身份(agent_id + role)。session_id 自動從環境變數讀取。若 agent_id 已被其他 session 占用,回傳 conflict 資訊供 AI 詢問 user。換角色時自動處理孤兒訊息並通知原始發送者。',
|
|
206
225
|
{
|
|
@@ -222,7 +241,12 @@ server.tool('register_agent',
|
|
|
222
241
|
}
|
|
223
242
|
|
|
224
243
|
const result = registerAgent(db, sessionId, agent_id, role);
|
|
225
|
-
|
|
244
|
+
|
|
245
|
+
// 同步寫入本地快取(供 statusline hook 識別身分)
|
|
246
|
+
const termKey = resolveTermKey();
|
|
247
|
+
writeAgentSessionCache(agent_id, termKey);
|
|
248
|
+
|
|
249
|
+
return textJson({ ...result, term_key: termKey });
|
|
226
250
|
}
|
|
227
251
|
);
|
|
228
252
|
|
package/package.json
CHANGED
package/src/status.mjs
CHANGED
|
@@ -146,10 +146,19 @@ export function getAgentStatus(db, sessionId) {
|
|
|
146
146
|
|
|
147
147
|
const { agent_id, role } = reg;
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
let row;
|
|
150
|
+
if (role) {
|
|
151
|
+
const pool = `${role}?`;
|
|
152
|
+
row = db.prepare(
|
|
153
|
+
`SELECT COUNT(*) as count FROM agent_collaboration_channel
|
|
154
|
+
WHERE status = 'UNREAD' AND (receiver = ? OR receiver = 'all' OR receiver = ?)`
|
|
155
|
+
).get(agent_id, pool);
|
|
156
|
+
} else {
|
|
157
|
+
row = db.prepare(
|
|
158
|
+
`SELECT COUNT(*) as count FROM agent_collaboration_channel
|
|
159
|
+
WHERE status = 'UNREAD' AND (receiver = ? OR receiver = 'all')`
|
|
160
|
+
).get(agent_id);
|
|
161
|
+
}
|
|
153
162
|
|
|
154
163
|
const unread = row?.count || 0;
|
|
155
164
|
const roleLabel = role ? `|${role}` : '';
|