openteam 0.7.0 → 0.7.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/package.json +1 -1
- package/src/capabilities/messaging.js +26 -26
- package/src/interfaces/plugin/tools.js +59 -49
package/package.json
CHANGED
|
@@ -212,31 +212,31 @@ function formatTeamPrompt(teamConfig, currentAgentName) {
|
|
|
212
212
|
*/
|
|
213
213
|
function getCollaborationRules() {
|
|
214
214
|
return `<collaboration-rules>
|
|
215
|
-
##
|
|
216
|
-
|
|
217
|
-
###
|
|
218
|
-
- \`[from xxx]\`
|
|
219
|
-
- \`[from boss]\` =
|
|
220
|
-
- \`[from <agent>]\` =
|
|
221
|
-
|
|
222
|
-
###
|
|
223
|
-
-
|
|
224
|
-
-
|
|
225
|
-
|
|
226
|
-
### Boss
|
|
227
|
-
-
|
|
228
|
-
-
|
|
229
|
-
-
|
|
230
|
-
|
|
231
|
-
###
|
|
232
|
-
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
|
|
236
|
-
###
|
|
237
|
-
-
|
|
238
|
-
-
|
|
239
|
-
-
|
|
240
|
-
-
|
|
215
|
+
## Team Collaboration Rules
|
|
216
|
+
|
|
217
|
+
### Message Sources
|
|
218
|
+
- \`[from xxx]\` prefix identifies the sender
|
|
219
|
+
- \`[from boss]\` = direct instruction from the boss, highest priority
|
|
220
|
+
- \`[from <agent>]\` = message from another agent (e.g., architect, developer)
|
|
221
|
+
|
|
222
|
+
### Communication
|
|
223
|
+
- **Your text output is invisible to other agents** — use the \`msg\` tool to communicate
|
|
224
|
+
- When you receive \`[from <agent>]\`, reply with \`msg\` so they can see your response
|
|
225
|
+
|
|
226
|
+
### Boss Messages (IMPORTANT)
|
|
227
|
+
- When you receive \`[from boss]\`, **reply directly in your output** — boss is in your session, not an agent
|
|
228
|
+
- **NEVER** use \`msg(who="boss", ...)\` — msg is only for team agents
|
|
229
|
+
- Boss can see your output directly, no tool needed
|
|
230
|
+
|
|
231
|
+
### Task Reporting (IMPORTANT)
|
|
232
|
+
- **After completing a task, use \`msg\` to report results to whoever assigned it**
|
|
233
|
+
- Include: what was done, key outputs, any remaining issues
|
|
234
|
+
- No report = the assigner doesn't know you finished, collaboration breaks
|
|
235
|
+
|
|
236
|
+
### Task System
|
|
237
|
+
- A message starting with \`[task #N]\` means you have a new task ready — start working on it
|
|
238
|
+
- When done, call \`taskboard(action="done", id=N)\` to mark complete — the system auto-notifies downstream
|
|
239
|
+
- Use \`taskboard(action="list")\` to view all tasks and their status
|
|
240
|
+
- After marking a task done, no extra msg report is needed (system handles flow automatically)
|
|
241
241
|
</collaboration-rules>`;
|
|
242
242
|
}
|
|
@@ -17,17 +17,26 @@ function createTraceID() {
|
|
|
17
17
|
return `msg-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* 记录工具错误并返回错误字符串
|
|
22
|
+
* 基础设施错误(agent 识别失败、serve 不可用等)用 error 级别,始终写入日志文件
|
|
23
|
+
*/
|
|
24
|
+
function toolError(toolName, message, data = {}) {
|
|
25
|
+
log.error(`${toolName}: ${message}`, data);
|
|
26
|
+
return `Error: ${message}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
20
29
|
export function createToolDefs() {
|
|
21
30
|
return {
|
|
22
31
|
msg: {
|
|
23
32
|
description:
|
|
24
|
-
'
|
|
33
|
+
'Send a message to a team agent (async). Your text output is invisible to other agents — use this tool to communicate. When you receive [from <agent>], reply with msg. IMPORTANT: When you receive [from boss], reply directly in your output — boss is in your session, not an agent. Leader can broadcast by omitting "who".',
|
|
25
34
|
args: {
|
|
26
35
|
who: tool.schema
|
|
27
36
|
.string()
|
|
28
37
|
.optional()
|
|
29
|
-
.describe('
|
|
30
|
-
message: tool.schema.string().describe('
|
|
38
|
+
.describe('Target agent name. Omit or set to "all" to broadcast (leader only).'),
|
|
39
|
+
message: tool.schema.string().describe('Message content'),
|
|
31
40
|
},
|
|
32
41
|
execute: async (args, ctx) => {
|
|
33
42
|
const trace = createTraceID();
|
|
@@ -39,20 +48,20 @@ export function createToolDefs() {
|
|
|
39
48
|
});
|
|
40
49
|
|
|
41
50
|
const currentAgent = await getCurrentAgent(ctx.sessionID, 2000, { trace, reason: 'msg.execute' });
|
|
42
|
-
if (!currentAgent) return '
|
|
51
|
+
if (!currentAgent) return toolError('msg', 'unable to identify current agent', { trace, sessionID: ctx.sessionID });
|
|
43
52
|
|
|
44
53
|
const teamConfig = loadTeamConfig(currentAgent.team);
|
|
45
|
-
if (!teamConfig) return '
|
|
54
|
+
if (!teamConfig) return toolError('msg', 'team config not found', { trace, team: currentAgent.team });
|
|
46
55
|
|
|
47
56
|
const projectDir = currentAgent.projectDir;
|
|
48
|
-
if (!projectDir) return '
|
|
57
|
+
if (!projectDir) return toolError('msg', 'unable to determine project directory', { trace, agent: currentAgent.full });
|
|
49
58
|
const serveUrl = getServeUrl(currentAgent.team, projectDir, { trace, reason: 'msg.execute' });
|
|
50
|
-
if (!serveUrl) return '
|
|
59
|
+
if (!serveUrl) return toolError('msg', 'team serve is not running', { trace, agent: currentAgent.full, team: currentAgent.team, projectDir });
|
|
51
60
|
|
|
52
61
|
const isLeader = currentAgent.name === teamConfig.leader;
|
|
53
62
|
const isBroadcast = !args.who || args.who === 'all';
|
|
54
63
|
|
|
55
|
-
if (isBroadcast && !isLeader) return 'Error:
|
|
64
|
+
if (isBroadcast && !isLeader) return 'Error: only the leader can broadcast';
|
|
56
65
|
|
|
57
66
|
if (isBroadcast) {
|
|
58
67
|
// 广播
|
|
@@ -63,11 +72,11 @@ export function createToolDefs() {
|
|
|
63
72
|
|
|
64
73
|
// 单点发送
|
|
65
74
|
if (args.who === 'boss') {
|
|
66
|
-
return 'Error: boss
|
|
75
|
+
return 'Error: boss is in your session — reply directly in your output, no need to use msg.';
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
if (!isAgentInTeam(currentAgent.team, args.who)) {
|
|
70
|
-
return `Error:
|
|
79
|
+
return `Error: "${args.who}" is not in the team. Available agents: ${teamConfig.agents.join(', ')}`;
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
const msgPreview = args.message.slice(0, 30) + (args.message.length > 30 ? '...' : '');
|
|
@@ -87,28 +96,29 @@ export function createToolDefs() {
|
|
|
87
96
|
|
|
88
97
|
command: {
|
|
89
98
|
description:
|
|
90
|
-
'Leader
|
|
99
|
+
'Leader-only commands for team management. Actions: status (view status), free (release agent), redirect (change working directory).',
|
|
91
100
|
args: {
|
|
92
|
-
action: tool.schema.string().describe('
|
|
93
|
-
who: tool.schema.string().optional().describe('
|
|
94
|
-
cwd: tool.schema.string().optional().describe('
|
|
95
|
-
alias: tool.schema.string().optional().describe('
|
|
101
|
+
action: tool.schema.string().describe('Action: status, free, or redirect'),
|
|
102
|
+
who: tool.schema.string().optional().describe('Target agent (optional for status)'),
|
|
103
|
+
cwd: tool.schema.string().optional().describe('Working directory (for redirect)'),
|
|
104
|
+
alias: tool.schema.string().optional().describe('Instance alias'),
|
|
96
105
|
},
|
|
97
106
|
execute: async (args, ctx) => {
|
|
107
|
+
const trace = createTraceID();
|
|
98
108
|
const currentAgent = await getCurrentAgent(ctx.sessionID);
|
|
99
|
-
if (!currentAgent) return '
|
|
109
|
+
if (!currentAgent) return toolError('command', 'unable to identify current agent', { trace, sessionID: ctx.sessionID });
|
|
100
110
|
|
|
101
111
|
const teamConfig = loadTeamConfig(currentAgent.team);
|
|
102
|
-
if (!teamConfig) return '
|
|
112
|
+
if (!teamConfig) return toolError('command', 'team config not found', { trace, team: currentAgent.team });
|
|
103
113
|
|
|
104
114
|
if (currentAgent.name !== teamConfig.leader) {
|
|
105
|
-
return `Error:
|
|
115
|
+
return `Error: only ${teamConfig.leader} can use command`;
|
|
106
116
|
}
|
|
107
117
|
|
|
108
118
|
const projectDir = currentAgent.projectDir;
|
|
109
|
-
if (!projectDir) return '
|
|
110
|
-
const serveUrl = getServeUrl(currentAgent.team, projectDir);
|
|
111
|
-
if (!serveUrl) return '
|
|
119
|
+
if (!projectDir) return toolError('command', 'unable to determine project directory', { trace, agent: currentAgent.full });
|
|
120
|
+
const serveUrl = getServeUrl(currentAgent.team, projectDir, { trace, reason: 'command.execute' });
|
|
121
|
+
if (!serveUrl) return toolError('command', 'team serve is not running', { trace, agent: currentAgent.full, team: currentAgent.team, projectDir });
|
|
112
122
|
|
|
113
123
|
let who = args.who;
|
|
114
124
|
let alias = args.alias;
|
|
@@ -123,10 +133,10 @@ export function createToolDefs() {
|
|
|
123
133
|
return getStatus(currentAgent.team, projectDir, serveUrl, who);
|
|
124
134
|
}
|
|
125
135
|
|
|
126
|
-
if (!who) return 'Error:
|
|
136
|
+
if (!who) return 'Error: "who" parameter is required';
|
|
127
137
|
|
|
128
138
|
if (!isAgentInTeam(currentAgent.team, who)) {
|
|
129
|
-
return `Error:
|
|
139
|
+
return `Error: "${who}" is not in the team. Available agents: ${teamConfig.agents.join(', ')}`;
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
// FREE
|
|
@@ -136,46 +146,46 @@ export function createToolDefs() {
|
|
|
136
146
|
|
|
137
147
|
// REDIRECT
|
|
138
148
|
if (args.action === 'redirect') {
|
|
139
|
-
if (!args.cwd) return 'Error: redirect
|
|
140
|
-
if (!fs.existsSync(args.cwd)) return `Error:
|
|
149
|
+
if (!args.cwd) return 'Error: redirect requires "cwd" parameter';
|
|
150
|
+
if (!fs.existsSync(args.cwd)) return `Error: directory not found - ${args.cwd}`;
|
|
141
151
|
return redirectAgent(currentAgent.team, projectDir, who, args.cwd, serveUrl, { alias });
|
|
142
152
|
}
|
|
143
153
|
|
|
144
|
-
return `Error:
|
|
154
|
+
return `Error: unknown action "${args.action}". Available: status, free, redirect`;
|
|
145
155
|
},
|
|
146
156
|
},
|
|
147
157
|
|
|
148
158
|
taskboard: {
|
|
149
159
|
description:
|
|
150
|
-
'
|
|
160
|
+
'Task management. Actions: create (leader only), done (mark complete), list (view all tasks).',
|
|
151
161
|
args: {
|
|
152
|
-
action: tool.schema.string().describe('
|
|
153
|
-
title: tool.schema.string().optional().describe('
|
|
154
|
-
description: tool.schema.string().optional().describe('
|
|
155
|
-
assignee: tool.schema.string().optional().describe('
|
|
156
|
-
depends_on: tool.schema.array(tool.schema.number()).optional().describe('
|
|
157
|
-
id: tool.schema.number().optional().describe('
|
|
162
|
+
action: tool.schema.string().describe('Action: create, done, or list'),
|
|
163
|
+
title: tool.schema.string().optional().describe('Task title (required for create)'),
|
|
164
|
+
description: tool.schema.string().optional().describe('Task description (optional for create)'),
|
|
165
|
+
assignee: tool.schema.string().optional().describe('Assignee agent name (required for create)'),
|
|
166
|
+
depends_on: tool.schema.array(tool.schema.number()).optional().describe('Dependency task IDs (optional for create)'),
|
|
167
|
+
id: tool.schema.number().optional().describe('Task ID (required for done)'),
|
|
158
168
|
},
|
|
159
169
|
execute: async (args, ctx) => {
|
|
160
170
|
const trace = createTraceID();
|
|
161
171
|
const currentAgent = await getCurrentAgent(ctx.sessionID, 2000, { trace, reason: 'task.execute' });
|
|
162
|
-
if (!currentAgent) return '
|
|
172
|
+
if (!currentAgent) return toolError('taskboard', 'unable to identify current agent', { trace, sessionID: ctx.sessionID });
|
|
163
173
|
|
|
164
174
|
const teamConfig = loadTeamConfig(currentAgent.team);
|
|
165
|
-
if (!teamConfig) return '
|
|
175
|
+
if (!teamConfig) return toolError('taskboard', 'team config not found', { trace, team: currentAgent.team });
|
|
166
176
|
|
|
167
177
|
const projectDir = currentAgent.projectDir;
|
|
168
|
-
if (!projectDir) return '
|
|
178
|
+
if (!projectDir) return toolError('taskboard', 'unable to determine project directory', { trace, agent: currentAgent.full });
|
|
169
179
|
const serveUrl = getServeUrl(currentAgent.team, projectDir, { trace, reason: 'task.execute' });
|
|
170
|
-
if (!serveUrl) return '
|
|
180
|
+
if (!serveUrl) return toolError('taskboard', 'team serve is not running', { trace, agent: currentAgent.full, team: currentAgent.team, projectDir });
|
|
171
181
|
|
|
172
182
|
// CREATE
|
|
173
183
|
if (args.action === 'create') {
|
|
174
184
|
if (currentAgent.name !== teamConfig.leader) {
|
|
175
|
-
return `Error:
|
|
185
|
+
return `Error: only ${teamConfig.leader} can create tasks`;
|
|
176
186
|
}
|
|
177
|
-
if (!args.title) return 'Error: create
|
|
178
|
-
if (!args.assignee) return 'Error: create
|
|
187
|
+
if (!args.title) return 'Error: create requires "title" parameter';
|
|
188
|
+
if (!args.assignee) return 'Error: create requires "assignee" parameter';
|
|
179
189
|
|
|
180
190
|
const result = await createTask({
|
|
181
191
|
teamName: currentAgent.team, projectDir, serveUrl,
|
|
@@ -188,18 +198,18 @@ export function createToolDefs() {
|
|
|
188
198
|
|
|
189
199
|
if (!result.ok) return `Error: ${result.error}`;
|
|
190
200
|
|
|
191
|
-
let response =
|
|
201
|
+
let response = `Task #${result.task.id} created: "${result.task.title}" → ${result.task.assignee}`;
|
|
192
202
|
if (result.triggered && result.triggered.length > 0) {
|
|
193
|
-
response += `\
|
|
203
|
+
response += `\nNotified: ${result.triggered.join(', ')}`;
|
|
194
204
|
} else if (result.task.dependsOn.length > 0) {
|
|
195
|
-
response += `\
|
|
205
|
+
response += `\nWaiting on: ${result.task.dependsOn.map(id => '#' + id).join(', ')}`;
|
|
196
206
|
}
|
|
197
207
|
return response;
|
|
198
208
|
}
|
|
199
209
|
|
|
200
210
|
// DONE
|
|
201
211
|
if (args.action === 'done') {
|
|
202
|
-
if (args.id == null) return 'Error: done
|
|
212
|
+
if (args.id == null) return 'Error: done requires "id" parameter';
|
|
203
213
|
|
|
204
214
|
const result = await completeTask({
|
|
205
215
|
teamName: currentAgent.team, projectDir, serveUrl,
|
|
@@ -210,9 +220,9 @@ export function createToolDefs() {
|
|
|
210
220
|
|
|
211
221
|
if (!result.ok) return `Error: ${result.error}`;
|
|
212
222
|
|
|
213
|
-
let response =
|
|
223
|
+
let response = `Task #${result.task.id} "${result.task.title}" completed`;
|
|
214
224
|
if (result.triggered.length > 0) {
|
|
215
|
-
response += `\n
|
|
225
|
+
response += `\nTriggered downstream:\n${result.triggered.join('\n')}`;
|
|
216
226
|
}
|
|
217
227
|
return response;
|
|
218
228
|
}
|
|
@@ -220,17 +230,17 @@ export function createToolDefs() {
|
|
|
220
230
|
// LIST
|
|
221
231
|
if (args.action === 'list') {
|
|
222
232
|
const tasks = listTasks(currentAgent.team, projectDir);
|
|
223
|
-
if (tasks.length === 0) return '
|
|
233
|
+
if (tasks.length === 0) return 'No tasks';
|
|
224
234
|
|
|
225
235
|
return tasks.map(t => {
|
|
226
236
|
const status = t.status === 'done' ? '✓' : '⏳';
|
|
227
|
-
const deps = t.dependsOn.length > 0 ? ` (
|
|
237
|
+
const deps = t.dependsOn.length > 0 ? ` (depends on ${t.dependsOn.map(id => '#' + id).join(',')})` : '';
|
|
228
238
|
const desc = t.description ? `\n ${t.description}` : '';
|
|
229
239
|
return `#${t.id} ${status} ${t.title} → ${t.assignee}${deps}${desc}`;
|
|
230
240
|
}).join('\n');
|
|
231
241
|
}
|
|
232
242
|
|
|
233
|
-
return `Error:
|
|
243
|
+
return `Error: unknown action "${args.action}". Available: create, done, list`;
|
|
234
244
|
},
|
|
235
245
|
},
|
|
236
246
|
};
|