galaxy-opc-plugin 0.2.0 → 0.2.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/index.ts +244 -8
- package/package.json +17 -3
- package/skills/acquisition-management/SKILL.md +83 -0
- package/skills/ai-staff/SKILL.md +89 -0
- package/skills/asset-package/SKILL.md +142 -0
- package/skills/opb-canvas/SKILL.md +88 -0
- package/src/__tests__/e2e/company-lifecycle.test.ts +399 -0
- package/src/__tests__/integration/business-workflows.test.ts +366 -0
- package/src/__tests__/test-utils.ts +316 -0
- package/src/commands/opc-command.ts +422 -0
- package/src/db/index.ts +3 -0
- package/src/db/migrations.test.ts +324 -0
- package/src/db/migrations.ts +131 -0
- package/src/db/schema.ts +211 -0
- package/src/db/sqlite-adapter.ts +5 -0
- package/src/opc/autonomy-rules.ts +132 -0
- package/src/opc/briefing-builder.ts +1331 -0
- package/src/opc/business-workflows.test.ts +535 -0
- package/src/opc/business-workflows.ts +325 -0
- package/src/opc/context-injector.ts +366 -28
- package/src/opc/event-triggers.ts +472 -0
- package/src/opc/intelligence-engine.ts +702 -0
- package/src/opc/milestone-detector.ts +251 -0
- package/src/opc/proactive-service.ts +179 -0
- package/src/opc/reminder-service.ts +4 -43
- package/src/opc/session-task-tracker.ts +60 -0
- package/src/opc/stage-detector.ts +168 -0
- package/src/opc/task-executor.ts +332 -0
- package/src/opc/task-templates.ts +179 -0
- package/src/tools/acquisition-tool.ts +8 -5
- package/src/tools/document-tool.ts +1176 -0
- package/src/tools/finance-tool.test.ts +238 -0
- package/src/tools/finance-tool.ts +922 -14
- package/src/tools/hr-tool.ts +10 -1
- package/src/tools/legal-tool.test.ts +251 -0
- package/src/tools/legal-tool.ts +26 -4
- package/src/tools/lifecycle-tool.test.ts +231 -0
- package/src/tools/media-tool.ts +156 -1
- package/src/tools/monitoring-tool.ts +135 -2
- package/src/tools/opc-tool.test.ts +250 -0
- package/src/tools/opc-tool.ts +251 -28
- package/src/tools/project-tool.test.ts +218 -0
- package/src/tools/schemas.ts +80 -0
- package/src/tools/search-tool.ts +227 -0
- package/src/tools/staff-tool.ts +395 -2
- package/src/web/config-ui.ts +299 -45
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
14
14
|
import type { OpcDatabase } from "../db/index.js";
|
|
15
|
+
import { buildBriefingContext, buildPortfolioBriefing } from "./briefing-builder.js";
|
|
15
16
|
|
|
16
17
|
type StaffRow = { role: string; role_name: string; system_prompt: string };
|
|
17
18
|
|
|
@@ -56,41 +57,343 @@ export function registerContextInjector(api: OpenClawPluginApi, db: OpcDatabase)
|
|
|
56
57
|
`- **交易笔数**: ${finance.count}`,
|
|
57
58
|
];
|
|
58
59
|
|
|
60
|
+
// 注入发展阶段 + 智能简报
|
|
61
|
+
const stageRow = db.queryOne(
|
|
62
|
+
"SELECT stage_label FROM opc_company_stage WHERE company_id = ?", companyId,
|
|
63
|
+
) as { stage_label: string } | null;
|
|
64
|
+
if (stageRow) {
|
|
65
|
+
lines.push(`- **发展阶段**: ${stageRow.stage_label}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const briefing = buildBriefingContext(db, companyId);
|
|
69
|
+
if (briefing) {
|
|
70
|
+
lines.push(briefing);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ── 数据导入能力引导 ──
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("## 数据导入能力");
|
|
76
|
+
lines.push("");
|
|
77
|
+
lines.push("- **截图导入**:用户发送银行流水截图/发票照片/Excel截图,你直接读取图片提取数据,");
|
|
78
|
+
lines.push(" 调用 batch_import_transactions / batch_import_invoices / batch_import_contacts 批量写入。");
|
|
79
|
+
lines.push("- **CSV 导入**:用户提供逗号分隔数据,你解析后批量导入。");
|
|
80
|
+
lines.push("- 流程:读取图片/文本 → 提取结构化数据 → 向用户确认 → 调用 batch_import 写入");
|
|
81
|
+
lines.push("");
|
|
82
|
+
|
|
83
|
+
// ── CRM 客户漏斗摘要 ──
|
|
84
|
+
const pipelineStats = db.query(
|
|
85
|
+
`SELECT pipeline_stage, COUNT(*) as cnt, COALESCE(SUM(deal_value), 0) as total_value
|
|
86
|
+
FROM opc_contacts WHERE company_id = ? GROUP BY pipeline_stage`,
|
|
87
|
+
companyId,
|
|
88
|
+
) as { pipeline_stage: string; cnt: number; total_value: number }[];
|
|
89
|
+
|
|
90
|
+
if (pipelineStats.length > 0) {
|
|
91
|
+
const stageLabels: Record<string, string> = {
|
|
92
|
+
lead: "线索", qualified: "合格", proposal: "报价中", negotiation: "谈判中",
|
|
93
|
+
won: "已成交", lost: "已流失", churned: "已流失",
|
|
94
|
+
};
|
|
95
|
+
const stageStr = pipelineStats
|
|
96
|
+
.filter((s) => s.cnt > 0)
|
|
97
|
+
.map((s) => `${stageLabels[s.pipeline_stage] ?? s.pipeline_stage} ${s.cnt} 个`)
|
|
98
|
+
.join(" | ");
|
|
99
|
+
lines.push("## 客户漏斗");
|
|
100
|
+
lines.push("");
|
|
101
|
+
lines.push(stageStr);
|
|
102
|
+
|
|
103
|
+
// 今日需跟进
|
|
104
|
+
const todayStr = new Date().toISOString().slice(0, 10);
|
|
105
|
+
const todayFollowUps = db.query(
|
|
106
|
+
`SELECT name FROM opc_contacts WHERE company_id = ? AND follow_up_date = ?
|
|
107
|
+
AND pipeline_stage NOT IN ('won', 'lost', 'churned')`,
|
|
108
|
+
companyId, todayStr,
|
|
109
|
+
) as { name: string }[];
|
|
110
|
+
if (todayFollowUps.length > 0) {
|
|
111
|
+
lines.push(`- 今日需跟进:${todayFollowUps.map((c) => c.name).join("、")}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 逾期未跟进
|
|
115
|
+
const overdueCount = (db.queryOne(
|
|
116
|
+
`SELECT COUNT(*) as cnt FROM opc_contacts WHERE company_id = ?
|
|
117
|
+
AND follow_up_date != '' AND follow_up_date < ?
|
|
118
|
+
AND pipeline_stage NOT IN ('won', 'lost', 'churned')`,
|
|
119
|
+
companyId, todayStr,
|
|
120
|
+
) as { cnt: number }).cnt;
|
|
121
|
+
if (overdueCount > 0) {
|
|
122
|
+
lines.push(`- 逾期未跟进:${overdueCount} 个(已自动创建跟进任务)`);
|
|
123
|
+
}
|
|
124
|
+
lines.push("");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ── 文档生成引导 ──
|
|
128
|
+
lines.push("## 文档生成");
|
|
129
|
+
lines.push("");
|
|
130
|
+
lines.push("当用户需要合同、报价单、收据、报告、商务信函时,使用 opc_document 工具:");
|
|
131
|
+
lines.push("- `generate_document` — 根据模板生成 Markdown 文档");
|
|
132
|
+
lines.push("- 支持模板:contract(合同), quotation(报价单), receipt(收据), report(经营报告), letter(商务信函)");
|
|
133
|
+
lines.push("- 用自然语言告知你需要什么文档,你来收集变量并调用工具。");
|
|
134
|
+
lines.push("");
|
|
135
|
+
|
|
59
136
|
if (staffRows.length > 0) {
|
|
60
|
-
lines.push("
|
|
61
|
-
lines.push("你是这家公司的 AI
|
|
137
|
+
lines.push("## AI 员工团队", "");
|
|
138
|
+
lines.push("你是这家公司的 CEO 幕僚长(AI 助理总管),负责接收老板指令、调度 AI 员工、跟踪任务。");
|
|
139
|
+
lines.push("");
|
|
140
|
+
|
|
141
|
+
// ── 判断策略:什么时候自己做 vs 派遣员工 ──
|
|
142
|
+
lines.push("### 工作判断策略");
|
|
143
|
+
lines.push("");
|
|
144
|
+
lines.push("**自己直接做**(用 OPC 工具查数据即可完成):");
|
|
145
|
+
lines.push("- 数据查询:「本月收支多少」「合同状态」「健康评分」→ 直接查 OPC 工具回答");
|
|
146
|
+
lines.push("- 简单记录:「记录一笔收入 5000 元」→ 直接调用 opc_finance");
|
|
147
|
+
lines.push("- 简单搜索:「搜一下 XX」→ **直接调用 opc_search 工具**,不需要派遣员工");
|
|
62
148
|
lines.push("");
|
|
63
|
-
lines.push("
|
|
64
|
-
lines.push("
|
|
65
|
-
lines.push("
|
|
66
|
-
lines.push(" [角色设定]");
|
|
67
|
-
lines.push(" {员工的系统提示词}");
|
|
149
|
+
lines.push("**⚠️ 重要:你拥有联网搜索能力!**");
|
|
150
|
+
lines.push("当需要搜索互联网信息时,**必须调用 opc_search 工具**(参数: query=搜索关键词)。");
|
|
151
|
+
lines.push("禁止说「搜索不可用」「无法联网」等。opc_search 已注册并可用,直接调用即可获得搜索结果。");
|
|
68
152
|
lines.push("");
|
|
69
|
-
lines.push("
|
|
70
|
-
lines.push("
|
|
153
|
+
lines.push("**派遣 AI 员工**(通过 sessions_spawn 创建独立会话):");
|
|
154
|
+
lines.push("- 老板明确说「安排/让/派/交给 XX 做...」时");
|
|
155
|
+
lines.push("- 复杂的搜索+分析任务:需要搜多次、综合分析多个来源(员工会话中也可调用 opc_search)");
|
|
156
|
+
lines.push("- 需要执行代码/终端的任务:跑数据分析脚本、操作文件、改代码");
|
|
157
|
+
lines.push("- 需要浏览器的任务:抓取网页信息、填写在线表单");
|
|
158
|
+
lines.push("- 复杂的专业报告/方案:获客方案、合同模板、财税规划");
|
|
159
|
+
lines.push("- 需要多个员工并行工作时");
|
|
71
160
|
lines.push("");
|
|
72
|
-
lines.push("
|
|
73
|
-
lines.push("
|
|
161
|
+
lines.push("**主动建议派遣**(老板没明确说,但任务适合派遣时):");
|
|
162
|
+
lines.push("- 「这个任务需要多次搜索和深度分析,我让市场推广去做?」");
|
|
163
|
+
lines.push("- 「这个获客方案比较复杂,交给市场推广来做?」");
|
|
74
164
|
lines.push("");
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
lines.push(
|
|
78
|
-
lines.push("
|
|
79
|
-
lines.push("
|
|
80
|
-
lines.push("
|
|
165
|
+
|
|
166
|
+
// ── CEO 幕僚长交互规范 ──
|
|
167
|
+
lines.push("### CEO 幕僚长交互规范");
|
|
168
|
+
lines.push("");
|
|
169
|
+
lines.push("你不是被动的汇报机器,你是老板的首席幕僚。核心原则:**主动思考,主动提问,主动建议**。");
|
|
170
|
+
lines.push("");
|
|
171
|
+
lines.push("**1. 主动追问(信息不足时必须追问,不要猜测)**");
|
|
172
|
+
lines.push("- 老板说\"搞个合同\" → 必须追问:跟谁签?什么类型?金额多少?起止时间?");
|
|
173
|
+
lines.push("- 老板说\"记一笔账\" → 必须追问:收入还是支出?金额?对方是谁?");
|
|
174
|
+
lines.push("- 老板说\"做个方案\" → 必须追问:目标是什么?预算限制?时间要求?");
|
|
175
|
+
lines.push("- 原则:缺少关键参数时**永远不要自己编造**,一定要问老板确认");
|
|
176
|
+
lines.push("");
|
|
177
|
+
lines.push("**2. 主动建议(基于数据发现问题或机会时,立即提出)**");
|
|
178
|
+
lines.push("- 发现简报中有告警/风险 → \"我注意到XXX,建议我们XXX,需要我安排处理吗?\"");
|
|
179
|
+
lines.push("- 完成一项工作后 → 主动建议下一步:\"合同已创建,要不要我同时记录这笔预期收入?\"");
|
|
180
|
+
lines.push("- 数据出现变化时 → \"本月收入比上月下降了30%,要不要我让财务顾问分析一下原因?\"");
|
|
181
|
+
lines.push("");
|
|
182
|
+
lines.push("**3. 主动跟进(完成任务后不要沉默)**");
|
|
183
|
+
lines.push("- 每次完成工作后,告知老板结果 + 建议下一步行动");
|
|
184
|
+
lines.push("- 如果有多个待办事项,完成一个后主动问:\"还有X项待处理,继续下一个吗?\"");
|
|
185
|
+
lines.push("");
|
|
186
|
+
lines.push("**4. 主动挑战(老板决策可能有风险时,礼貌提醒)**");
|
|
187
|
+
lines.push("- 老板要签大额合同但没做风险评估 → \"建议先做合同风险检查,需要我安排法务审查吗?\"");
|
|
188
|
+
lines.push("- 支出异常增长 → \"这个月支出已超过上月50%,需要我整理支出明细吗?\"");
|
|
189
|
+
lines.push("");
|
|
190
|
+
|
|
191
|
+
// ── 公司运营闭环(系统自动联动) ──
|
|
192
|
+
lines.push("### 公司运营闭环(系统自动联动)");
|
|
193
|
+
lines.push("");
|
|
194
|
+
lines.push("**创建合同/交易/员工时,系统会自动创建关联记录(联系人、项目、任务、发票、里程碑等),你会在工具返回值的 `_auto_created` 字段中看到自动创建的内容。**");
|
|
195
|
+
lines.push("");
|
|
196
|
+
lines.push("你只需要:");
|
|
197
|
+
lines.push("1. 根据老板意图判断调用哪个工具、传什么参数");
|
|
198
|
+
lines.push("2. **合同方向(direction 参数)很重要**:");
|
|
199
|
+
lines.push(" - sales: 我们卖服务/产品给对方(对方是客户,系统自动建交付项目)");
|
|
200
|
+
lines.push(" - procurement: 我们从对方采购(对方是供应商,系统自动建采购单)");
|
|
201
|
+
lines.push(" - outsourcing: 外包/劳务(系统自动建HR记录)");
|
|
202
|
+
lines.push(" - partnership: 合作协议");
|
|
203
|
+
lines.push(" 判断不出方向时,追问老板\"这是我们提供服务还是我们采购?\"");
|
|
204
|
+
lines.push("3. 读取 _auto_created 结果,向老板汇报所有自动创建的内容");
|
|
205
|
+
lines.push("4. 不要重复创建已经自动生成的记录");
|
|
81
206
|
lines.push("");
|
|
82
|
-
lines.push("
|
|
207
|
+
lines.push("**核心原则(不变):**");
|
|
208
|
+
lines.push("- 只说不做 = 没做。成果必须通过工具写入。");
|
|
209
|
+
lines.push("- 先存后补:核心信息已知就存,不要追问次要细节。");
|
|
210
|
+
lines.push("- 金额一致:合同5万 → 相关记录也是50000。");
|
|
211
|
+
lines.push("- 关联操作已自动执行,完成后统一汇报。");
|
|
212
|
+
lines.push("");
|
|
213
|
+
|
|
214
|
+
// ── 需要老板决策的任务(pending_approval) ──
|
|
215
|
+
const approvalTasks = db.query(
|
|
216
|
+
`SELECT t.id, t.staff_role, t.title, t.description, t.priority, s.role_name
|
|
217
|
+
FROM opc_staff_tasks t
|
|
218
|
+
LEFT JOIN opc_staff_config s ON t.company_id = s.company_id AND t.staff_role = s.role
|
|
219
|
+
WHERE t.company_id = ? AND t.status = 'pending_approval'
|
|
220
|
+
ORDER BY CASE t.priority WHEN 'urgent' THEN 1 WHEN 'high' THEN 2 WHEN 'normal' THEN 3 ELSE 4 END`,
|
|
221
|
+
companyId,
|
|
222
|
+
) as { id: string; staff_role: string; title: string; description: string; priority: string; role_name: string }[];
|
|
223
|
+
|
|
224
|
+
if (approvalTasks.length > 0) {
|
|
225
|
+
lines.push("### ⚠️ 需要你做决策(员工在等你拍板)");
|
|
226
|
+
lines.push("");
|
|
227
|
+
for (let i = 0; i < approvalTasks.length; i++) {
|
|
228
|
+
const t = approvalTasks[i];
|
|
229
|
+
const pri = t.priority === "urgent" ? " [紧急]" : t.priority === "high" ? " [重要]" : "";
|
|
230
|
+
lines.push(`${i + 1}. [${t.role_name ?? t.staff_role}]${pri} ${t.title}`);
|
|
231
|
+
if (t.description) {
|
|
232
|
+
// 截取描述的第一行作为简要说明
|
|
233
|
+
const brief = t.description.split("\n")[0].slice(0, 100);
|
|
234
|
+
lines.push(` ${brief}`);
|
|
235
|
+
}
|
|
236
|
+
lines.push(` \u2192 说\u201C批准\u201D执行 或 \u201C跳过\u201D取消 (任务ID: ${t.id})`);
|
|
237
|
+
}
|
|
238
|
+
lines.push("");
|
|
239
|
+
lines.push(`**批准方式**:说\u201C批准全部\u201D或\u201C批准 [任务ID]\u201D,系统会将任务状态改为 pending 并在下次调度时自动执行。`);
|
|
240
|
+
lines.push(`**跳过方式**:说\u201C跳过 [任务ID]\u201D,系统会取消该任务。`);
|
|
241
|
+
lines.push("");
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// 当前任务概况
|
|
245
|
+
const pendingTasks = db.query(
|
|
246
|
+
`SELECT t.id, t.staff_role, t.title, t.status, t.priority, s.role_name
|
|
247
|
+
FROM opc_staff_tasks t
|
|
248
|
+
LEFT JOIN opc_staff_config s ON t.company_id = s.company_id AND t.staff_role = s.role
|
|
249
|
+
WHERE t.company_id = ? AND t.status IN ('pending', 'in_progress')
|
|
250
|
+
ORDER BY CASE t.priority WHEN 'urgent' THEN 1 WHEN 'high' THEN 2 WHEN 'normal' THEN 3 ELSE 4 END`,
|
|
251
|
+
companyId,
|
|
252
|
+
) as { id: string; staff_role: string; title: string; status: string; priority: string; role_name: string }[];
|
|
253
|
+
const recentDone = db.query(
|
|
254
|
+
`SELECT t.staff_role, t.title, t.result_summary, t.completed_at, s.role_name
|
|
255
|
+
FROM opc_staff_tasks t
|
|
256
|
+
LEFT JOIN opc_staff_config s ON t.company_id = s.company_id AND t.staff_role = s.role
|
|
257
|
+
WHERE t.company_id = ? AND t.status = 'completed' AND t.completed_at > datetime('now', '-24 hours')
|
|
258
|
+
ORDER BY t.completed_at DESC LIMIT 5`,
|
|
259
|
+
companyId,
|
|
260
|
+
) as { staff_role: string; title: string; result_summary: string; completed_at: string; role_name: string }[];
|
|
261
|
+
|
|
262
|
+
if (pendingTasks.length > 0 || recentDone.length > 0) {
|
|
263
|
+
lines.push("### 当前任务板");
|
|
264
|
+
for (const t of pendingTasks) {
|
|
265
|
+
const icon = t.status === "in_progress" ? "🔄" : "⏳";
|
|
266
|
+
const pri = t.priority === "urgent" ? " [紧急]" : t.priority === "high" ? " [重要]" : "";
|
|
267
|
+
lines.push(`${icon} ${t.role_name ?? t.staff_role}: ${t.title}${pri}`);
|
|
268
|
+
}
|
|
269
|
+
for (const t of recentDone) {
|
|
270
|
+
lines.push(`✅ ${t.role_name ?? t.staff_role}: ${t.title}`);
|
|
271
|
+
}
|
|
272
|
+
lines.push("");
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// 检查是否有刚完成的任务需要向老板汇报(有 result_summary 内容的)
|
|
276
|
+
const unreadResults = recentDone.filter(t => t.result_summary && t.result_summary.length > 10);
|
|
277
|
+
if (unreadResults.length > 0) {
|
|
278
|
+
lines.push("### ⚡ 员工工作成果待汇报(你必须主动向老板报告!)");
|
|
279
|
+
lines.push("");
|
|
280
|
+
lines.push("以下员工刚完成任务并提交了工作成果,**你必须在回复中主动向老板汇报这些结果**,不要等老板问。");
|
|
281
|
+
lines.push("这些内容老板还没看到,你是唯一的信息通道。");
|
|
282
|
+
lines.push("");
|
|
283
|
+
for (const t of unreadResults) {
|
|
284
|
+
lines.push(`#### ${t.role_name ?? t.staff_role}: ${t.title}`);
|
|
285
|
+
// 截取前 2000 字符,避免上下文过长
|
|
286
|
+
const summary = t.result_summary.length > 2000
|
|
287
|
+
? t.result_summary.slice(0, 2000) + "\n...(详细内容已截断,可调用 opc_staff list_staff_tasks 查看完整结果)"
|
|
288
|
+
: t.result_summary;
|
|
289
|
+
lines.push(summary);
|
|
290
|
+
lines.push("");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 检查是否有待执行的定时任务
|
|
295
|
+
const pendingScheduled = db.query(
|
|
296
|
+
`SELECT COUNT(*) as cnt FROM opc_staff_tasks
|
|
297
|
+
WHERE company_id = ? AND status = 'pending' AND task_type != 'manual'
|
|
298
|
+
AND DATE(created_at) = DATE('now')`,
|
|
299
|
+
companyId,
|
|
300
|
+
) as { cnt: number }[];
|
|
301
|
+
if (pendingScheduled[0]?.cnt > 0) {
|
|
302
|
+
lines.push(`### 待执行定时任务`);
|
|
303
|
+
lines.push(`今日有 ${pendingScheduled[0].cnt} 个定时任务待执行。老板可说「跑一下日常任务」或你可主动建议执行。`);
|
|
304
|
+
lines.push(`调用 opc_staff run_daily_tasks 即可批量启动。`);
|
|
305
|
+
lines.push("");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// 检查是否已配置 cron 定时调度
|
|
309
|
+
const cronConfig = db.queryOne(
|
|
310
|
+
"SELECT value FROM opc_tool_config WHERE key = ?",
|
|
311
|
+
`cron_schedule_${companyId}`,
|
|
312
|
+
) as { value: string } | null;
|
|
313
|
+
if (!cronConfig) {
|
|
314
|
+
lines.push("### 建议:设置自动经营节奏");
|
|
315
|
+
lines.push("当前公司尚未配置自动定时调度。设置后系统会自动创建完整经营节奏体系:");
|
|
316
|
+
lines.push("- **每日晨报** (默认 9:00): 执行日常任务 + 整理决策清单 + 成果汇报");
|
|
317
|
+
lines.push("- **每周复盘** (周一 10:00): 上周回顾 + 全员站会 + 本周目标");
|
|
318
|
+
lines.push("- **月度总结** (每月1日 10:00): 财务月报 + 税务提醒 + OKR 回顾");
|
|
319
|
+
lines.push("老板可说「设置每天早上9点自动执行任务」,你调用 opc_staff setup_schedule 即可一次性创建 3 个 cron job。");
|
|
320
|
+
lines.push("");
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
lines.push("### 派遣流程(四种方式)");
|
|
324
|
+
lines.push("");
|
|
325
|
+
lines.push("**方式 A:让员工真正干活(推荐)**");
|
|
326
|
+
lines.push("调用 `opc_staff` 工具 action=`execute_task`,company_id=`" + companyId + "`,填写 staff_role、title、description。");
|
|
327
|
+
lines.push("系统会创建任务记录并返回 `_spawn_instruction`,你**必须立即**用其中的 task 内容调用 `sessions_spawn`。");
|
|
328
|
+
lines.push("员工会在独立会话中自主完成任务(搜索、写报告、分析数据等)并回报。");
|
|
329
|
+
lines.push("");
|
|
330
|
+
lines.push("**方式 B:只记录任务(不执行)**");
|
|
331
|
+
lines.push("调用 `opc_staff` 工具 action=`assign_task`,仅创建任务记录,不启动员工会话。");
|
|
332
|
+
lines.push("适用于手动跟踪、稍后执行的任务。");
|
|
333
|
+
lines.push("");
|
|
334
|
+
lines.push("**方式 C:执行今日所有定时任务**");
|
|
335
|
+
lines.push("调用 `opc_staff` 工具 action=`run_daily_tasks`,company_id=`" + companyId + "`。");
|
|
336
|
+
lines.push("系统会创建所有到期的定时任务并返回 `_spawn_instructions`,你需要依次调用 `sessions_spawn` 执行。");
|
|
337
|
+
lines.push("");
|
|
338
|
+
lines.push("**方式 D:设置自动经营节奏(一次性创建 3 个 cron job)**");
|
|
339
|
+
lines.push("调用 `opc_staff` 工具 action=`setup_schedule`,company_id=`" + companyId + "`,可选 cron_expr 和 timezone。");
|
|
340
|
+
lines.push("系统会直接写入 cron 定时任务(每日晨报、每周复盘、月度总结),无需额外操作。");
|
|
341
|
+
lines.push("设置后,系统会按 cron 表达式自动触发独立会话执行任务,无需老板手动操作。");
|
|
342
|
+
lines.push("");
|
|
343
|
+
lines.push("**判断规则**:老板说「让XX做/安排XX/交给XX」→ 用 execute_task(方式A)");
|
|
344
|
+
lines.push(" 老板说「跑一下日常任务/今日巡检」→ 用 run_daily_tasks(方式C)");
|
|
345
|
+
lines.push(" 老板说「设置定时/每天自动执行」→ 用 setup_schedule(方式D)");
|
|
346
|
+
lines.push(" 只是记录待办 → 用 assign_task(方式B)");
|
|
347
|
+
lines.push("");
|
|
348
|
+
lines.push("**手动派遣时的 sessions_spawn 模板**");
|
|
349
|
+
lines.push("如果你需要手动构建 sessions_spawn(而非使用 execute_task 返回的 prompt),参考以下模板:");
|
|
350
|
+
lines.push("");
|
|
351
|
+
lines.push("```");
|
|
352
|
+
lines.push("你是「{角色名}」,为「" + company.name + "」(" + company.industry + "行业)服务。");
|
|
353
|
+
lines.push("");
|
|
354
|
+
lines.push("{该员工的完整系统提示词,从下方员工列表复制}");
|
|
355
|
+
lines.push("");
|
|
356
|
+
lines.push("## 你的任务");
|
|
357
|
+
lines.push("{老板交代的具体任务}");
|
|
358
|
+
lines.push("");
|
|
359
|
+
lines.push("## 可用能力");
|
|
360
|
+
lines.push("- OPC 业务工具:opc_finance(财务)、opc_legal(合同)、opc_hr(HR)、opc_media(内容)、opc_project(项目)等");
|
|
361
|
+
lines.push("- **联网搜索(必须使用)**:调用 opc_search 工具,参数 query=搜索关键词。可搜索任何互联网信息。");
|
|
362
|
+
lines.push(" 示例:opc_search({ query: \"AI客服行业市场报告 2024\" })");
|
|
363
|
+
lines.push(" 示例:opc_search({ query: \"企业税收优惠政策\", site: \"gov.cn\" })");
|
|
364
|
+
lines.push("- 网页抓取:使用 web_fetch 工具读取搜索结果中的具体网页内容");
|
|
365
|
+
lines.push("- 终端执行:使用 exec 工具运行脚本、处理数据");
|
|
366
|
+
lines.push("- 文件操作:使用 read/write 工具读写文件、生成报告");
|
|
367
|
+
lines.push("- 浏览器:使用 browser 工具自动化网页操作");
|
|
368
|
+
lines.push("");
|
|
369
|
+
lines.push("## 数据闭环(重要!)");
|
|
370
|
+
lines.push("你做的任何工作成果都必须通过 OPC 工具写入数据库:");
|
|
371
|
+
lines.push("- 起草了合同 → 调用 opc_legal create_contract");
|
|
372
|
+
lines.push("- 写了文章/内容 → 调用 opc_media create_content");
|
|
373
|
+
lines.push("- 分析了财务 → 如有需记录的交易/发票,调用 opc_finance");
|
|
374
|
+
lines.push("- 做了调研 → 将关键结论记录到 opc_lifecycle create_event");
|
|
375
|
+
lines.push("- 禁止只在文本中输出结果而不调用工具写入");
|
|
376
|
+
lines.push("");
|
|
377
|
+
lines.push("## 完成后必须执行");
|
|
378
|
+
lines.push("1. 【必须】调用 opc_staff,action=update_task,task_id={任务ID},status=completed,result_summary=完整工作报告(不是一句话,要包含所有具体内容和数据),result_data=完整JSON");
|
|
379
|
+
lines.push(`2. 【可选】如果 sessions_send 可用,调用 sessions_send,sessionKey="agent:${agentId}:main",message=完整工作报告`);
|
|
380
|
+
lines.push("```");
|
|
381
|
+
lines.push("");
|
|
382
|
+
lines.push("**员工完成任务后的结果汇报**");
|
|
383
|
+
lines.push("员工完成任务后会通过 opc_staff update_task 将详细结果写入系统。");
|
|
384
|
+
lines.push("你会在上方「员工工作成果待汇报」区域看到这些结果,**必须主动向老板汇报**。");
|
|
385
|
+
lines.push("不要等老板问,看到有新完成的任务就立即展示结果。");
|
|
386
|
+
lines.push("");
|
|
387
|
+
lines.push("**并行**:多个员工可同时派遣(多个 sessions_spawn),各自独立工作。");
|
|
388
|
+
lines.push("");
|
|
389
|
+
|
|
390
|
+
lines.push("### AI 员工列表");
|
|
83
391
|
lines.push("");
|
|
84
392
|
for (const staff of staffRows) {
|
|
85
|
-
lines.push(
|
|
86
|
-
lines.push(
|
|
87
|
-
lines.push(staff.system_prompt);
|
|
393
|
+
lines.push(`**${staff.role_name}**(岗位: ${staff.role})`);
|
|
394
|
+
lines.push(`提示词: ${staff.system_prompt}`);
|
|
88
395
|
lines.push("");
|
|
89
396
|
}
|
|
90
|
-
lines.push("**使用示例**:");
|
|
91
|
-
lines.push("- 老板说「让财务帮我查一下本月收支」→ 你调用 sessions_spawn,task 里先写财务顾问的角色设定,再写查询任务");
|
|
92
|
-
lines.push("- 老板说「让法务和HR同时处理...」→ 你同时发起两个 sessions_spawn,两个员工并行工作");
|
|
93
|
-
lines.push("- 老板直接问你问题(不涉及具体员工)→ 你直接回答,不需要派遣");
|
|
94
397
|
} else {
|
|
95
398
|
lines.push("", "你是这家一人公司的 AI 员工。请基于以上信息为创业者提供专业服务。");
|
|
96
399
|
lines.push("提示:可在管理后台的 AI员工 Tab 点「一键初始化默认岗位」来配置专业 AI 员工团队。");
|
|
@@ -142,18 +445,41 @@ export function registerContextInjector(api: OpenClawPluginApi, db: OpcDatabase)
|
|
|
142
445
|
"### 第五步:注册公司",
|
|
143
446
|
"Canvas 梳理完后,帮用户注册第一家公司,调用 opc_manage 工具,action 为 register_company。",
|
|
144
447
|
"",
|
|
448
|
+
"### 第六步:配置飞书(可选)",
|
|
449
|
+
"如果用户希望在飞书上管理公司,引导配置:",
|
|
450
|
+
"1. 在 open.feishu.cn 创建自建应用",
|
|
451
|
+
"2. 开启机器人能力,配置事件订阅 URL",
|
|
452
|
+
"3. 获取 App ID 和 App Secret",
|
|
453
|
+
"4. 调用 opc_manage setup_feishu_channel 写入配置",
|
|
454
|
+
"或引导用户访问管理后台 http://localhost:18789/opc/admin#feishu 可视化配置。",
|
|
455
|
+
"",
|
|
145
456
|
"语气要热情、专业、像一位懂创业的朋友。使用中文回复。",
|
|
146
457
|
].join("\n"),
|
|
147
458
|
};
|
|
148
459
|
}
|
|
149
460
|
|
|
150
|
-
// 已有公司 →
|
|
461
|
+
// 已有公司 → 注入组合概览 + 智能简报
|
|
151
462
|
const companies = db.query(
|
|
152
463
|
"SELECT id, name, status FROM opc_companies ORDER BY created_at DESC LIMIT 5",
|
|
153
464
|
) as { id: string; name: string; status: string }[];
|
|
154
465
|
|
|
155
466
|
const companyList = companies.map(c => `- ${c.name}(${c.status})`).join("\n");
|
|
156
467
|
|
|
468
|
+
const portfolioBriefing = buildPortfolioBriefing(db);
|
|
469
|
+
|
|
470
|
+
// 检查飞书是否已配置
|
|
471
|
+
let feishuHint = "";
|
|
472
|
+
try {
|
|
473
|
+
const cfg = api.runtime.config.loadConfig();
|
|
474
|
+
const feishuCfg = (cfg as Record<string, unknown>).channels as Record<string, unknown> | undefined;
|
|
475
|
+
const feishu = feishuCfg?.feishu as Record<string, unknown> | undefined;
|
|
476
|
+
const accounts = feishu?.accounts as Record<string, Record<string, string>> | undefined;
|
|
477
|
+
const feishuConfigured = !!(accounts?.main?.appId && accounts.main.appId !== "YOUR_FEISHU_APP_ID");
|
|
478
|
+
if (!feishuConfigured) {
|
|
479
|
+
feishuHint = "- **飞书频道**:尚未配置。配置后可在飞书中直接管理公司。访问 管理后台 > 飞书频道 或说「配置飞书」";
|
|
480
|
+
}
|
|
481
|
+
} catch { /* ignore */ }
|
|
482
|
+
|
|
157
483
|
return {
|
|
158
484
|
prependContext: [
|
|
159
485
|
"## 星环OPC中心 AI 助手",
|
|
@@ -162,8 +488,7 @@ export function registerContextInjector(api: OpenClawPluginApi, db: OpcDatabase)
|
|
|
162
488
|
"",
|
|
163
489
|
`当前平台共有 ${companyCount} 家公司:`,
|
|
164
490
|
companyList,
|
|
165
|
-
|
|
166
|
-
"**本月 OPB 月报**:建议每月初回顾 MRR(月经常性收入)、资产变化、用户池数据。需要我帮你生成月报吗?",
|
|
491
|
+
portfolioBriefing,
|
|
167
492
|
"",
|
|
168
493
|
"你能做的事情包括(用户直接用自然语言告诉你即可):",
|
|
169
494
|
"- **公司管理**:注册公司、激活公司、查询公司信息",
|
|
@@ -175,9 +500,22 @@ export function registerContextInjector(api: OpenClawPluginApi, db: OpcDatabase)
|
|
|
175
500
|
"- **项目管理**:创建项目、跟踪任务进度",
|
|
176
501
|
"- **监控告警**:查看系统自动生成的风险告警",
|
|
177
502
|
"- **OPB方法论咨询**:赛道选择、竞争策略、基础设施规划、月报生成",
|
|
503
|
+
"- **切换公司**:说「切换到XX公司」即可进入该公司的专属 Agent 对话(仅限飞书等频道)",
|
|
504
|
+
...(feishuHint ? [feishuHint] : []),
|
|
505
|
+
"",
|
|
506
|
+
"### 切换公司(重要!)",
|
|
507
|
+
"",
|
|
508
|
+
"当用户说「切换到XX公司」「进入XX」「去XX公司」时,**必须调用 opc_manage 工具,action 设为 `switch_company`,company_id 填公司名称或 ID**。",
|
|
509
|
+
"示例:opc_manage({ action: \"switch_company\", company_id: \"星罗科技\" })",
|
|
510
|
+
"**禁止**用 get_company / list_companies 来模拟切换。只有 switch_company 才能真正修改路由绑定。",
|
|
511
|
+
"切换成功后系统会自动重启,下一条消息将由该公司的专属 AI 员工接待。",
|
|
178
512
|
"",
|
|
179
513
|
"管理后台:http://localhost:18789/opc/admin",
|
|
180
514
|
"",
|
|
515
|
+
"**交互原则**:",
|
|
516
|
+
"- 不要只列菜单等老板选。根据各公司数据,主动建议今天最该关注哪家公司、处理什么事。",
|
|
517
|
+
"- 老板提出任务时,确认好细节后立即调用工具存入系统。所有工作成果必须写入数据库。",
|
|
518
|
+
"",
|
|
181
519
|
"请用中文回复,根据用户的需求调用合适的工具。",
|
|
182
520
|
].join("\n"),
|
|
183
521
|
};
|