@optima-chat/optima-agent 0.8.97 → 0.8.99
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/.claude/settings.local.json +166 -0
- package/.claude/skills/.kb-skills-managed.json +9 -0
- package/.claude/skills/ingesting-sources/SKILL.md +76 -0
- package/.claude/skills/initializing-kb/SKILL.md +102 -0
- package/.claude/skills/kol-outreach/SKILL.md +351 -272
- package/.claude/skills/linting-the-wiki/SKILL.md +69 -0
- package/.claude/skills/querying-the-wiki/SKILL.md +66 -0
- package/.claude/skills/updating-related-pages/SKILL.md +76 -0
- package/dist/bin/bi-cli.js +0 -0
- package/dist/bin/browser-cli.js +0 -0
- package/dist/bin/comfy.d.ts +3 -0
- package/dist/bin/comfy.d.ts.map +1 -0
- package/dist/bin/comfy.js +3 -0
- package/dist/bin/comfy.js.map +1 -0
- package/dist/bin/commerce.js +0 -0
- package/dist/bin/gen.js +0 -0
- package/dist/bin/google-ads.js +0 -0
- package/dist/bin/growth.d.ts +3 -0
- package/dist/bin/growth.d.ts.map +1 -0
- package/dist/bin/growth.js +3 -0
- package/dist/bin/growth.js.map +1 -0
- package/dist/bin/logistics.js +0 -0
- package/dist/bin/optima.js +0 -0
- package/dist/bin/scout.js +0 -0
- package/dist/bin/sentinel.js +0 -0
- package/dist/bin/shopify.js +0 -0
- package/dist/bin/sync-kb-skills.d.ts +6 -0
- package/dist/bin/sync-kb-skills.d.ts.map +1 -0
- package/dist/bin/sync-kb-skills.js +65 -0
- package/dist/bin/sync-kb-skills.js.map +1 -0
- package/dist/src/hooks-loader.d.ts +6 -0
- package/dist/src/hooks-loader.d.ts.map +1 -0
- package/dist/src/hooks-loader.js +215 -0
- package/dist/src/hooks-loader.js.map +1 -0
- package/dist/src/ui/App.d.ts +6 -0
- package/dist/src/ui/App.d.ts.map +1 -0
- package/dist/src/ui/App.js +164 -0
- package/dist/src/ui/App.js.map +1 -0
- package/dist/src/ui/components/Composer.d.ts +10 -0
- package/dist/src/ui/components/Composer.d.ts.map +1 -0
- package/dist/src/ui/components/Composer.js +13 -0
- package/dist/src/ui/components/Composer.js.map +1 -0
- package/dist/src/ui/components/Header.d.ts +7 -0
- package/dist/src/ui/components/Header.d.ts.map +1 -0
- package/dist/src/ui/components/Header.js +7 -0
- package/dist/src/ui/components/Header.js.map +1 -0
- package/dist/src/ui/components/Message.d.ts +12 -0
- package/dist/src/ui/components/Message.d.ts.map +1 -0
- package/dist/src/ui/components/Message.js +21 -0
- package/dist/src/ui/components/Message.js.map +1 -0
- package/dist/src/ui/components/MessageList.d.ts +9 -0
- package/dist/src/ui/components/MessageList.d.ts.map +1 -0
- package/dist/src/ui/components/MessageList.js +18 -0
- package/dist/src/ui/components/MessageList.js.map +1 -0
- package/dist/src/ui/components/Spinner.d.ts +6 -0
- package/dist/src/ui/components/Spinner.d.ts.map +1 -0
- package/dist/src/ui/components/Spinner.js +7 -0
- package/dist/src/ui/components/Spinner.js.map +1 -0
- package/dist/src/ui/components/StatusBar.d.ts +11 -0
- package/dist/src/ui/components/StatusBar.d.ts.map +1 -0
- package/dist/src/ui/components/StatusBar.js +7 -0
- package/dist/src/ui/components/StatusBar.js.map +1 -0
- package/dist/src/ui/components/index.d.ts +7 -0
- package/dist/src/ui/components/index.d.ts.map +1 -0
- package/dist/src/ui/components/index.js +7 -0
- package/dist/src/ui/components/index.js.map +1 -0
- package/dist/src/validation/error-formatter.d.ts +21 -0
- package/dist/src/validation/error-formatter.d.ts.map +1 -0
- package/dist/src/validation/error-formatter.js +98 -0
- package/dist/src/validation/error-formatter.js.map +1 -0
- package/dist/src/validation/index.d.ts +10 -0
- package/dist/src/validation/index.d.ts.map +1 -0
- package/dist/src/validation/index.js +10 -0
- package/dist/src/validation/index.js.map +1 -0
- package/dist/src/validation/json-validator.d.ts +25 -0
- package/dist/src/validation/json-validator.d.ts.map +1 -0
- package/dist/src/validation/json-validator.js +173 -0
- package/dist/src/validation/json-validator.js.map +1 -0
- package/dist/src/validation/schema.d.ts +353 -0
- package/dist/src/validation/schema.d.ts.map +1 -0
- package/dist/src/validation/schema.js +57 -0
- package/dist/src/validation/schema.js.map +1 -0
- package/dist/src/validation/suggestions.d.ts +25 -0
- package/dist/src/validation/suggestions.d.ts.map +1 -0
- package/dist/src/validation/suggestions.js +144 -0
- package/dist/src/validation/suggestions.js.map +1 -0
- package/dist/src/validation/types.d.ts +40 -0
- package/dist/src/validation/types.d.ts.map +1 -0
- package/dist/src/validation/types.js +5 -0
- package/dist/src/validation/types.js.map +1 -0
- package/dist/src/validation/yaml-validator.d.ts +25 -0
- package/dist/src/validation/yaml-validator.d.ts.map +1 -0
- package/dist/src/validation/yaml-validator.js +177 -0
- package/dist/src/validation/yaml-validator.js.map +1 -0
- package/package.json +6 -4
|
@@ -1,55 +1,70 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kol-outreach
|
|
3
|
-
description: "KOL 建联全自动化:从 TikTok 发现潜在 KOL、提取 bio email、发送个性化 outreach
|
|
3
|
+
description: "KOL 建联全自动化:从 TikTok 发现潜在 KOL、提取 bio email、发送个性化 outreach、自动处理 KOL 回信并维护本地状态。当用户说'帮我找 KOL'、'{产品} KOL 建联'、'KOL 进展如何',或消息中出现 [KOL_INBOUND:{campaignId}] / [KOL_INBOUND] 时,使用此 skill。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# KOL
|
|
6
|
+
# KOL 建联
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
意向交付,运行时零打扰,所有决策参数在首次 onboarding 时固化。
|
|
8
|
+
## 概述
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
本 skill 用于在 TikTok 上完成 KOL 建联的完整操作流程:发现、触达、回信处理、进度维护。
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
- 所有业务状态都保存在 `~/kol-outreach/`
|
|
13
|
+
- 运行时默认零打扰,优先按已固化配置执行
|
|
14
|
+
- 本 skill 只负责操作,不解释系统实现
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
~/kol-outreach/
|
|
17
|
-
├── BRAND.md # 商家品牌素材(跨 campaign)
|
|
18
|
-
├── MERCHANT_LIMITS.md # 跨 campaign 发信速率
|
|
19
|
-
├── CAMPAIGNS.md # campaign 索引
|
|
20
|
-
├── PROGRESS.md # 商家级里程碑日志
|
|
21
|
-
└── campaigns/{campaignId}/
|
|
22
|
-
├── CONFIG.md # 本 campaign 的商品/预算/条款
|
|
23
|
-
├── KOLS.md # 本 campaign 的 KOL 索引
|
|
24
|
-
├── TEMPLATES.md # 邮件模板(4 类)
|
|
25
|
-
├── PROGRESS.md # 本 campaign 的事件日志
|
|
26
|
-
├── CONVERSATIONS/{username}.md # 每个 KOL 的对话历史
|
|
27
|
-
└── assets/ # 商品图/素材
|
|
28
|
-
```
|
|
16
|
+
## 工作规则
|
|
29
17
|
|
|
30
|
-
|
|
18
|
+
- outbound 只用 `scout outreach send`
|
|
19
|
+
- onboarding 时只用 `scout outreach brand-slug check|claim`
|
|
20
|
+
- 所有业务状态只从 `~/kol-outreach/` 读取和写回
|
|
21
|
+
- 单会话单任务:每次 session 只做一种动作
|
|
22
|
+
- 每次关键状态变更后都要 `git add` + `git commit`
|
|
23
|
+
- 所有对外邮件都必须走模板渲染;LLM 只能产出结构化变量或结构化决策
|
|
31
24
|
|
|
32
|
-
|
|
25
|
+
## 工作目录文件
|
|
33
26
|
|
|
34
|
-
|
|
35
|
-
- 是 → 走「KOL 回信处理」流程(见下)
|
|
36
|
-
- 否 → 继续步骤 2
|
|
37
|
-
2. **检测首次使用**:`ls ~/kol-outreach/BRAND.md` 是否存在?
|
|
38
|
-
- 不存在 → 走「Merchant onboarding」→ 接着走「Campaign onboarding」
|
|
39
|
-
- 存在 → 继续步骤 3
|
|
40
|
-
3. **根据用户意图**分流:
|
|
41
|
-
- 用户说"给 {新产品} 建联" → 走「Campaign onboarding」创建新 campaign
|
|
42
|
-
- 用户说"开始建联 {campaign}" / "发送 outreach" → 走「发现 + 首发 outreach」
|
|
43
|
-
- 用户说"KOL 进展" / "查看状态" → 走「查询进度」
|
|
27
|
+
优先关注这些文件:
|
|
44
28
|
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
- merchant 级
|
|
30
|
+
- `~/kol-outreach/BRAND.md`
|
|
31
|
+
- `~/kol-outreach/MERCHANT_LIMITS.md`
|
|
32
|
+
- `~/kol-outreach/CAMPAIGNS.md`
|
|
33
|
+
- `~/kol-outreach/PROGRESS.md`
|
|
34
|
+
- campaign 级
|
|
35
|
+
- `~/kol-outreach/campaigns/{campaignId}/CONFIG.md`
|
|
36
|
+
- `~/kol-outreach/campaigns/{campaignId}/KOLS.md`
|
|
37
|
+
- `~/kol-outreach/campaigns/{campaignId}/TEMPLATES.md`
|
|
38
|
+
- `~/kol-outreach/campaigns/{campaignId}/PROGRESS.md`
|
|
39
|
+
- `~/kol-outreach/campaigns/{campaignId}/CONVERSATIONS/{username}.md`
|
|
40
|
+
|
|
41
|
+
## Session 分流
|
|
42
|
+
|
|
43
|
+
每次 session 开始时,按这个顺序判断要走哪条流程:
|
|
44
|
+
|
|
45
|
+
1. 如果用户消息包含 `[KOL_INBOUND:{campaignId}]` 或 `[KOL_INBOUND]`,走「流程 D:KOL 回信处理」
|
|
46
|
+
2. 否则,检查 `~/kol-outreach/BRAND.md` 是否存在
|
|
47
|
+
- 不存在:先走「流程 A:Merchant onboarding」,再走「流程 B:Campaign onboarding」
|
|
48
|
+
3. 如果 merchant 已存在,则按用户意图分流
|
|
49
|
+
- 用户要为新产品建联:走「流程 B:Campaign onboarding」
|
|
50
|
+
- 用户要开始建联或发送 outreach:走「流程 C:发现 KOL + 首发 Outreach」
|
|
51
|
+
- 用户要查看状态或进展:走「流程 E:查询进度」
|
|
52
|
+
|
|
53
|
+
## Inbound 前置条件
|
|
54
|
+
|
|
55
|
+
进入流程 D 前,先检查:
|
|
56
|
+
|
|
57
|
+
1. `BRAND.md`
|
|
58
|
+
2. 对应 campaign 目录
|
|
59
|
+
3. 可匹配的 `KOLS.md` / `CONVERSATIONS/*.md`
|
|
60
|
+
|
|
61
|
+
缺任何一项,都不要继续正常谈判;直接转状态恢复或人工跟进。
|
|
47
62
|
|
|
48
63
|
---
|
|
49
64
|
|
|
50
|
-
## 流程 A
|
|
65
|
+
## 流程 A:商家初始化
|
|
51
66
|
|
|
52
|
-
1.
|
|
67
|
+
1. 初始化工作目录:
|
|
53
68
|
|
|
54
69
|
```bash
|
|
55
70
|
mkdir -p ~/kol-outreach/campaigns
|
|
@@ -57,37 +72,38 @@ description: "KOL 建联全自动化:从 TikTok 发现潜在 KOL、提取 bio
|
|
|
57
72
|
cd ~/kol-outreach && git init && git add -A && git commit -m "init merchant workspace"
|
|
58
73
|
```
|
|
59
74
|
|
|
60
|
-
2.
|
|
61
|
-
-
|
|
62
|
-
- 从 brand_name 生成
|
|
63
|
-
- 调 `scout outreach brand-slug check {slug}`
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
- 给出默认的双语 escalation_keywords,让商家确认或扩展
|
|
70
|
-
- Edit `BRAND.md`
|
|
75
|
+
2. 填 `BRAND.md`
|
|
76
|
+
- 询问:`brand_name`
|
|
77
|
+
- 从 `brand_name` 生成 kebab-case 的 `brand_slug` 建议
|
|
78
|
+
- 调 `scout outreach brand-slug check {slug}`
|
|
79
|
+
- 如果可用,让商家确认;如果被占用,让商家从建议里选或自己改
|
|
80
|
+
- 成功后调 `scout outreach brand-slug claim`
|
|
81
|
+
- 继续询问:`brand_website`、`brand_social`、`default_contact_name`、`default_brand_pitch`
|
|
82
|
+
- 提供默认兜底话术和默认双语 `escalation_keywords`,让商家确认或修改
|
|
83
|
+
- 写回 `BRAND.md`
|
|
71
84
|
- `git add BRAND.md && git commit -m "setup BRAND.md"`
|
|
72
85
|
|
|
73
|
-
3.
|
|
74
|
-
- 默认 `max_daily_sends: 50
|
|
75
|
-
- 初始化 `sent_today: 0
|
|
76
|
-
- `
|
|
86
|
+
3. 填 `MERCHANT_LIMITS.md`
|
|
87
|
+
- 默认 `max_daily_sends: 50`
|
|
88
|
+
- 初始化 `sent_today: 0`
|
|
89
|
+
- 初始化 `date_utc: $(date -u +%Y-%m-%d)`
|
|
90
|
+
- 写回并 commit
|
|
77
91
|
|
|
78
|
-
4.
|
|
92
|
+
4. 告诉商家:merchant 级配置已完成,继续创建第一个 campaign。
|
|
79
93
|
|
|
80
94
|
---
|
|
81
95
|
|
|
82
|
-
## 流程 B
|
|
96
|
+
## 流程 B:创建 Campaign
|
|
83
97
|
|
|
84
|
-
1. 确定 campaignId
|
|
85
|
-
-
|
|
86
|
-
- 从商品标题生成 kebab-case slug
|
|
87
|
-
-
|
|
88
|
-
|
|
98
|
+
1. 确定 `campaignId`
|
|
99
|
+
- 询问商家要为哪个商品建联
|
|
100
|
+
- 从商品标题生成 kebab-case slug 建议
|
|
101
|
+
- 校验:
|
|
102
|
+
- 与 `CAMPAIGNS.md` 现有 campaign 不重复
|
|
103
|
+
- 匹配 `^[a-z0-9][a-z0-9-]{0,29}$`
|
|
104
|
+
- 让商家确认或修改
|
|
89
105
|
|
|
90
|
-
2. 创建 campaign
|
|
106
|
+
2. 创建 campaign 目录
|
|
91
107
|
|
|
92
108
|
```bash
|
|
93
109
|
mkdir -p ~/kol-outreach/campaigns/{campaignId}
|
|
@@ -95,277 +111,340 @@ description: "KOL 建联全自动化:从 TikTok 发现潜在 KOL、提取 bio
|
|
|
95
111
|
cd ~/kol-outreach && git add -A && git commit -m "init campaign {campaignId}"
|
|
96
112
|
```
|
|
97
113
|
|
|
98
|
-
3.
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
-
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
3. 分段填写 `CONFIG.md`
|
|
115
|
+
- 依次填写:
|
|
116
|
+
- campaign 元信息
|
|
117
|
+
- 商品
|
|
118
|
+
- 目标 KOL 画像
|
|
119
|
+
- 预算与报价
|
|
120
|
+
- 合作条款边界
|
|
121
|
+
- 兜底话术覆写
|
|
122
|
+
- 运行参数
|
|
123
|
+
- 严格校验:
|
|
124
|
+
- `max_price >= target_price >= first_offer`
|
|
125
|
+
- `max_step <= max_price - first_offer`
|
|
126
|
+
- `total_budget >= max_price`
|
|
127
|
+
- 任一不满足:说明原因,给出调整建议,重新问
|
|
128
|
+
- 每个大段写完后都要写文件并 commit
|
|
129
|
+
|
|
130
|
+
4. 更新 `CAMPAIGNS.md`
|
|
131
|
+
- 追加一行新 campaign,`status=active`
|
|
111
132
|
|
|
112
133
|
5. `git commit -m "[{campaignId}] campaign ready"`
|
|
113
134
|
|
|
114
|
-
6. 告诉商家 campaign
|
|
135
|
+
6. 告诉商家 campaign 已就绪,并询问是否立即开始发现 KOL。
|
|
115
136
|
|
|
116
137
|
---
|
|
117
138
|
|
|
118
|
-
## 流程 C:发现 KOL
|
|
139
|
+
## 流程 C:发现 KOL 与首发 Outreach
|
|
140
|
+
|
|
141
|
+
先按这个顺序执行:
|
|
119
142
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
143
|
+
- 先定 campaign
|
|
144
|
+
- 再检查并行上限和 merchant 日配额
|
|
145
|
+
- 先发现 KOL,再补拉 bio / email
|
|
146
|
+
- LLM 只产出模板变量,不直接写邮件正文
|
|
147
|
+
- 每发出一封邮件,都要立刻写回并 commit
|
|
124
148
|
|
|
125
|
-
1.
|
|
126
|
-
-
|
|
127
|
-
- `
|
|
128
|
-
|
|
129
|
-
|
|
149
|
+
1. 确定 campaign
|
|
150
|
+
- 如果用户指定 campaign,用指定值
|
|
151
|
+
- 如果用户未指定,读 `CAMPAIGNS.md`
|
|
152
|
+
- 只有一个 active:用它
|
|
153
|
+
- 多个 active:列出让商家选
|
|
130
154
|
|
|
131
|
-
2.
|
|
155
|
+
2. 读取所需文件
|
|
156
|
+
- `CONFIG.md`
|
|
157
|
+
- `KOLS.md`
|
|
158
|
+
- `BRAND.md`
|
|
159
|
+
- `MERCHANT_LIMITS.md`
|
|
160
|
+
- `TEMPLATES.md`
|
|
161
|
+
|
|
162
|
+
3. 检查并行上限
|
|
132
163
|
- `in_flight = KOLS.md 中 status ∈ {awaiting_reply, in_progress} 的行数`
|
|
133
164
|
- `available_slots = max_concurrent_kols - in_flight`
|
|
134
|
-
- `available_slots <= 0
|
|
165
|
+
- `available_slots <= 0`:告诉商家当前已达并行上限,退出
|
|
135
166
|
- `target_new = min(CONFIG.target_kols_this_round, available_slots)`
|
|
136
167
|
|
|
137
|
-
|
|
138
|
-
-
|
|
139
|
-
-
|
|
168
|
+
4. 检查 merchant 日发信配额
|
|
169
|
+
- 读取 `MERCHANT_LIMITS.md`
|
|
170
|
+
- 如果 UTC 日期变了,先归档昨天计数,再把 `sent_today` 重置为 0
|
|
140
171
|
- `daily_budget = max_daily_sends - sent_today`
|
|
141
|
-
- `daily_budget <= 0
|
|
172
|
+
- `daily_budget <= 0`:告诉商家今日配额已用完,退出
|
|
142
173
|
- `本轮发送量 = min(target_new, daily_budget)`
|
|
143
174
|
|
|
144
|
-
|
|
175
|
+
5. 调 `scout tiktok creators`
|
|
145
176
|
|
|
146
177
|
```bash
|
|
147
178
|
scout tiktok creators \
|
|
148
|
-
--follower-count "<CONFIG.
|
|
179
|
+
--follower-count "<CONFIG.follower_count_range>" \
|
|
149
180
|
--country "<CONFIG.region>" \
|
|
150
181
|
--limit <本轮发送量 * 3> \
|
|
151
182
|
--format json
|
|
152
183
|
```
|
|
153
184
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
- engagement_rate < 2% 丢弃
|
|
158
|
-
- 已在 KOLS.md 的 username 丢弃
|
|
185
|
+
6. 过滤候选人
|
|
186
|
+
- `engagement_rate < 2%` 丢弃
|
|
187
|
+
- 已在 `KOLS.md` 的 `username` 丢弃
|
|
159
188
|
- 粉丝量不在目标区间的丢弃
|
|
160
189
|
|
|
161
|
-
|
|
162
|
-
- 调 `scout tiktok creator-products @username --limit 5`
|
|
163
|
-
- 如果
|
|
164
|
-
- 用正则从 bio
|
|
190
|
+
7. 补拉 bio / email 并写 `KOLS.md`
|
|
191
|
+
- 对每个候选 KOL 调 `scout tiktok creator-products @username --limit 5`
|
|
192
|
+
- 如果 creators 结果没带 bio,就从这里补拉
|
|
193
|
+
- 用正则从 bio 提取 email
|
|
194
|
+
- 有 email:
|
|
195
|
+
- 追加到 `KOLS.md`
|
|
196
|
+
- `status=pending_outreach`
|
|
197
|
+
- 没 email:
|
|
198
|
+
- 追加到 `KOLS.md`
|
|
199
|
+
- `status=no_contact`
|
|
200
|
+
- `git commit -m "[{campaignId}] discovered N KOLs"`
|
|
165
201
|
|
|
166
|
-
|
|
167
|
-
|
|
202
|
+
8. 发送首发 outreach
|
|
203
|
+
- 只处理 `status=pending_outreach`,并限制在本轮发送量内
|
|
204
|
+
- 读取 `TEMPLATES.md` 中的 `first_outreach_v1`
|
|
205
|
+
- 让 LLM 只输出模板变量 JSON,例如:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"kol_first_name": "...",
|
|
210
|
+
"opener_line": "...",
|
|
211
|
+
"fit_reason": "...",
|
|
212
|
+
"product_one_liner": "..."
|
|
213
|
+
}
|
|
168
214
|
```
|
|
169
215
|
|
|
170
|
-
-
|
|
171
|
-
-
|
|
172
|
-
|
|
216
|
+
- 用模板渲染正文,不要直接自由写 body
|
|
217
|
+
- 终检:
|
|
218
|
+
- body 不含 `forbidden_phrases`
|
|
219
|
+
- body 长度 `<= 2000`
|
|
220
|
+
- 任一不过:
|
|
221
|
+
- 写 `KOLS.md` 为 `send_error`
|
|
222
|
+
- 记 `PROGRESS.md`
|
|
223
|
+
- 跳过该 KOL
|
|
173
224
|
|
|
174
|
-
|
|
175
|
-
- 读 `TEMPLATES.md` 的 first_outreach_v1 骨架
|
|
176
|
-
- **LLM 决策**(结构化 JSON 输出):
|
|
177
|
-
- 输入:CONFIG 商品段 + BRAND.md(覆盖后) + KOL 最近视频 + template 变量列表
|
|
178
|
-
- 输出:
|
|
179
|
-
```json
|
|
180
|
-
{
|
|
181
|
-
"kol_first_name": "...",
|
|
182
|
-
"opener_line": "...",
|
|
183
|
-
"fit_reason": "...",
|
|
184
|
-
"product_one_liner": "..."
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
- 你只决定变量值,**不要直接写 email body**
|
|
188
|
-
- 模板渲染:把变量代入 first_outreach_v1 → 最终 body
|
|
189
|
-
- **Layer 4 内容终检**:
|
|
190
|
-
- body 不含 CONFIG.forbidden_phrases(fallback 到 BRAND.md default)
|
|
191
|
-
- body 长度 ≤ 2000 字符
|
|
192
|
-
- 任一不过 → 跳过这个 KOL,写 KOLS.md status=send_error,记 PROGRESS.md
|
|
193
|
-
- Edit `CONVERSATIONS/{username}.md` 追加 Round 1 (outreach sent) 段
|
|
194
|
-
- 调 `scout outreach send`:
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
echo '{
|
|
198
|
-
"to": "kol_email",
|
|
199
|
-
"subject": "Collaboration opportunity with <brand_name>",
|
|
200
|
-
"body": "<rendered body>",
|
|
201
|
-
"from_merchant_id": "<merchantId>",
|
|
202
|
-
"from_campaign_id": "<campaignId>",
|
|
203
|
-
"from_brand_slug": "<BRAND.brand_slug>",
|
|
204
|
-
"from_brand_name": "<BRAND.brand_name>",
|
|
205
|
-
"from_contact_name": "<effective contact_name>"
|
|
206
|
-
}' | scout outreach send
|
|
207
|
-
```
|
|
225
|
+
9. 调 `scout outreach send`
|
|
208
226
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
227
|
+
```bash
|
|
228
|
+
echo '{
|
|
229
|
+
"to": "kol_email",
|
|
230
|
+
"subject": "Collaboration opportunity with <brand_name>",
|
|
231
|
+
"body": "<rendered body>",
|
|
232
|
+
"from_merchant_id": "<merchantId>",
|
|
233
|
+
"from_campaign_id": "<campaignId>",
|
|
234
|
+
"from_brand_slug": "<BRAND.brand_slug>",
|
|
235
|
+
"from_brand_name": "<BRAND.brand_name>",
|
|
236
|
+
"from_contact_name": "<effective contact_name>"
|
|
237
|
+
}' | scout outreach send
|
|
238
|
+
```
|
|
213
239
|
|
|
214
|
-
|
|
240
|
+
10. 写回状态
|
|
241
|
+
- 在 `CONVERSATIONS/{username}.md` 追加 Round 1
|
|
242
|
+
- 把返回的 `message_id` 写入 conversation
|
|
243
|
+
- 更新 `KOLS.md`
|
|
244
|
+
- `pending_outreach -> awaiting_reply`
|
|
245
|
+
- `offer = first_offer`
|
|
246
|
+
- 更新 `MERCHANT_LIMITS.md`
|
|
247
|
+
- `sent_today += 1`
|
|
248
|
+
- 追加本 campaign 的 `PROGRESS.md`
|
|
249
|
+
- 重要事件同步追加 merchant `PROGRESS.md`
|
|
250
|
+
- `git commit -m "[{campaignId}] outreach sent to @{username}"`
|
|
215
251
|
|
|
216
|
-
|
|
252
|
+
11. 告诉商家本次发送结果。
|
|
217
253
|
|
|
218
254
|
---
|
|
219
255
|
|
|
220
|
-
## 流程 D
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
235
|
-
|
|
236
|
-
-
|
|
237
|
-
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
-
|
|
246
|
-
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
-
|
|
254
|
-
-
|
|
256
|
+
## 流程 D:处理 KOL 回信
|
|
257
|
+
|
|
258
|
+
先按这个顺序执行:
|
|
259
|
+
|
|
260
|
+
- 先确定 campaign 和 KOL
|
|
261
|
+
- 先做预检,再决定是否调用 LLM
|
|
262
|
+
- LLM 只输出结构化决策,不直接写邮件正文
|
|
263
|
+
- 任何校验不过都降级为 `escalate`
|
|
264
|
+
- 每轮处理完都要写回文件、commit,并调用 `sentinel report`
|
|
265
|
+
|
|
266
|
+
1. 读取本次 inbound 的消息内容
|
|
267
|
+
- 从当前消息中读取:
|
|
268
|
+
- `From`
|
|
269
|
+
- `Subject`
|
|
270
|
+
- `Message-ID`
|
|
271
|
+
- `In-Reply-To`
|
|
272
|
+
- `References`
|
|
273
|
+
- `Body`
|
|
274
|
+
|
|
275
|
+
2. 确定 campaign
|
|
276
|
+
- 如果消息包含 `[KOL_INBOUND:{campaignId}]`:只处理该 campaign
|
|
277
|
+
- 如果消息包含 `[KOL_INBOUND]`:稍后在步骤 3 通过 `from_email` 匹配 campaign
|
|
278
|
+
|
|
279
|
+
3. 按 `from_email` 匹配 KOL
|
|
280
|
+
- `campaignId` 已知:只读该 campaign 的 `KOLS.md`
|
|
281
|
+
- `campaignId` 未知:遍历 `~/kol-outreach/campaigns/*/KOLS.md`
|
|
282
|
+
- 匹配结果:
|
|
283
|
+
- 唯一匹配:继续
|
|
284
|
+
- 多个匹配:选 `last_update` 最新的 campaign
|
|
285
|
+
- 无匹配:按 orphan inbound 处理并退出
|
|
286
|
+
- 同一 campaign 内同一 email 有多条记录时,取 `status` 非终态的活跃记录
|
|
287
|
+
|
|
288
|
+
4. 读取所需文件
|
|
289
|
+
- `CONFIG.md`
|
|
290
|
+
- `BRAND.md`
|
|
291
|
+
- `CONVERSATIONS/{username}.md`
|
|
292
|
+
|
|
293
|
+
5. 先做预检
|
|
294
|
+
- `rounds >= CONFIG.max_rounds`:`escalate`
|
|
295
|
+
- 对话时长 `>= CONFIG.max_days`:`expired`
|
|
296
|
+
- 最新回信 body 命中 `escalation_keywords`:`escalate`
|
|
297
|
+
- 最后一条 inbound round 的 `message_id` 与本次 `in_reply_to` 不一致:按幂等性异常处理
|
|
298
|
+
|
|
299
|
+
6. 如果预检触发异常
|
|
300
|
+
- 用 `escalate_fallback_v1` 模板渲染兜底回复
|
|
301
|
+
- 调 `scout outreach send` 发出回复
|
|
302
|
+
- 更新 `KOLS.md` 为 `needs_merchant_followup`
|
|
303
|
+
- 写 `PROGRESS.md`
|
|
304
|
+
- `git commit`
|
|
255
305
|
- `sentinel report --condition-met true --summary "layer2 escalate" --action-taken "..."`
|
|
256
306
|
- 退出
|
|
257
307
|
|
|
258
|
-
7.
|
|
259
|
-
|
|
260
|
-
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
"template_id": "counter_offer_v1",
|
|
274
|
-
"template_vars": { },
|
|
275
|
-
"reasoning": "..."
|
|
276
|
-
}
|
|
277
|
-
```
|
|
308
|
+
7. 调用 LLM 生成结构化决策
|
|
309
|
+
- 输入:`CONFIG.md`、`BRAND.md`、`CONVERSATIONS/{username}.md`、最新回信、模板变量列表
|
|
310
|
+
- 输出 JSON,例如:
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"action": "counter_offer | accept | decline | clarify | escalate",
|
|
315
|
+
"new_price": 200,
|
|
316
|
+
"final_price": 250,
|
|
317
|
+
"concessions": ["video_retention_90d"],
|
|
318
|
+
"template_id": "counter_offer_v1",
|
|
319
|
+
"template_vars": {},
|
|
320
|
+
"reasoning": "..."
|
|
321
|
+
}
|
|
322
|
+
```
|
|
278
323
|
|
|
279
|
-
8.
|
|
324
|
+
8. 校验 LLM 输出
|
|
280
325
|
- `action ∈ {counter_offer, accept, decline, clarify, escalate}`
|
|
281
|
-
- 如果 `counter_offer
|
|
282
|
-
- `CONFIG.first_offer
|
|
283
|
-
- `new_price - previous_offer
|
|
284
|
-
- 如果 `accept
|
|
285
|
-
- `CONFIG.first_offer
|
|
286
|
-
- `committed_so_far
|
|
287
|
-
- `concessions
|
|
288
|
-
- `template_id
|
|
289
|
-
-
|
|
326
|
+
- 如果 `counter_offer`
|
|
327
|
+
- `CONFIG.first_offer <= new_price <= CONFIG.max_price`
|
|
328
|
+
- `new_price - previous_offer <= CONFIG.max_step`
|
|
329
|
+
- 如果 `accept`
|
|
330
|
+
- `CONFIG.first_offer <= final_price <= CONFIG.max_price`
|
|
331
|
+
- `committed_so_far + final_price <= CONFIG.total_budget`
|
|
332
|
+
- `concessions` 只能来自允许集合
|
|
333
|
+
- `template_id` 必须存在于本 campaign 的 `TEMPLATES.md`
|
|
334
|
+
- 任一不通过:降级为 `escalate`
|
|
335
|
+
|
|
336
|
+
9. 渲染模板并终检
|
|
337
|
+
- 用 `template_id + template_vars` 渲染最终 body
|
|
338
|
+
- 终检:
|
|
339
|
+
- body 不含 `forbidden_phrases`
|
|
340
|
+
- body 长度 `<= 2000`
|
|
341
|
+
- 不通过:降级为 `escalate`
|
|
342
|
+
|
|
343
|
+
10. 发送回复
|
|
344
|
+
- 调 `scout outreach send`
|
|
345
|
+
- 带上:
|
|
346
|
+
- `in_reply_to = KOL 的 message_id`
|
|
347
|
+
- `references = 原 references + KOL 的 message_id`
|
|
348
|
+
- 拿到新 `message_id`
|
|
349
|
+
|
|
350
|
+
11. 写回状态
|
|
351
|
+
- 在 `CONVERSATIONS/{username}.md` 追加新一轮,保留完整 LLM decision JSON
|
|
352
|
+
- 更新 `KOLS.md`
|
|
353
|
+
- 更新 `rounds`
|
|
354
|
+
- 更新 `current_offer`
|
|
355
|
+
- 更新 `last_update`
|
|
356
|
+
- `accept -> deal_reached`
|
|
357
|
+
- 其他正常回复 -> `awaiting_reply`
|
|
358
|
+
- 更新 `MERCHANT_LIMITS.md`
|
|
359
|
+
- `sent_today += 1`
|
|
360
|
+
- 如果 `action == accept`
|
|
361
|
+
- 给商家注册邮箱发送 `deal_confirmation_v1`
|
|
362
|
+
- 在 merchant `PROGRESS.md` 记录达成合作
|
|
363
|
+
- 追加 campaign `PROGRESS.md`
|
|
364
|
+
- `git commit -m "[{campaignId}] round N {action} with @{username}"`
|
|
365
|
+
|
|
366
|
+
12. 调 `sentinel report`
|
|
290
367
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
- body 不含 forbidden_phrases(CONFIG 覆写优先,fallback BRAND)
|
|
295
|
-
- body 长度 ≤ 2000 字符
|
|
296
|
-
- 不过 → 降级为 escalate
|
|
368
|
+
```bash
|
|
369
|
+
sentinel report --condition-met true --summary "..." --action-taken "..."
|
|
370
|
+
```
|
|
297
371
|
|
|
298
|
-
|
|
372
|
+
---
|
|
299
373
|
|
|
300
|
-
|
|
301
|
-
- 带 `in_reply_to = KOL 的 message_id`
|
|
302
|
-
- 带 `references = 原 references 追加 KOL 的 message_id`
|
|
303
|
-
- 拿到新 message_id 写回 CONVERSATIONS
|
|
374
|
+
## 流程 E:查询进展
|
|
304
375
|
|
|
305
|
-
|
|
306
|
-
- 如果 action == accept:status → deal_reached
|
|
307
|
-
- 否则 status → awaiting_reply
|
|
376
|
+
1. 读 `CAMPAIGNS.md`
|
|
308
377
|
|
|
309
|
-
|
|
378
|
+
2. 确定范围
|
|
379
|
+
- 用户指定 campaign:只汇报该 campaign
|
|
380
|
+
- 未指定且只有一个 active:只汇报该 campaign
|
|
381
|
+
- 未指定且有多个 active:先给跨 campaign 摘要,再提示用户可继续查看单个 campaign
|
|
382
|
+
|
|
383
|
+
3. 跨 campaign 摘要
|
|
384
|
+
- 对每个 campaign 读 `KOLS.md`
|
|
385
|
+
- 统计:
|
|
386
|
+
- `in_flight`
|
|
387
|
+
- `deal_reached`
|
|
388
|
+
- `needs_merchant_followup`
|
|
389
|
+
- 读 `CONFIG.md` 的 `total_budget`,计算已承诺预算
|
|
390
|
+
- 读 `MERCHANT_LIMITS.md` 的今日 `sent_today`
|
|
391
|
+
- 以 markdown 表格汇报
|
|
392
|
+
|
|
393
|
+
4. 单 campaign 详情
|
|
394
|
+
- 读 `KOLS.md` 按 `status` 分桶
|
|
395
|
+
- 对每个 `needs_merchant_followup`,读对应 `CONVERSATIONS/{username}.md`,总结 KOL 诉求
|
|
396
|
+
- 读 campaign `PROGRESS.md` 最近 5 条
|
|
397
|
+
- 输出:
|
|
398
|
+
- 关键统计
|
|
399
|
+
- 需要人工处理的事项
|
|
400
|
+
- 最近进展
|
|
310
401
|
|
|
311
|
-
|
|
312
|
-
- 额外调 `scout outreach send` 发 deal_confirmation_v1 的 recap 给**商家注册邮箱**
|
|
313
|
-
- 在 merchant PROGRESS.md 记录 `[campaignId] DEAL REACHED with @username ($final_price)`
|
|
402
|
+
---
|
|
314
403
|
|
|
315
|
-
|
|
404
|
+
## 异常处理
|
|
316
405
|
|
|
317
|
-
|
|
406
|
+
- `scout outreach send` 返回 `ok: false`
|
|
407
|
+
- 更新 `KOLS.md` 为 `send_error`
|
|
408
|
+
- 记 `PROGRESS.md`
|
|
409
|
+
- 不要中断其他 KOL 的处理
|
|
318
410
|
|
|
319
|
-
|
|
411
|
+
- LLM 结构化输出格式错误
|
|
412
|
+
- 重试 1 次
|
|
413
|
+
- 仍失败:降级为 `escalate`
|
|
320
414
|
|
|
321
|
-
|
|
415
|
+
- unknown campaign
|
|
416
|
+
- 写 merchant `PROGRESS.md`
|
|
417
|
+
- `sentinel report --condition-met false --summary "unknown campaign"`
|
|
418
|
+
- 退出
|
|
322
419
|
|
|
323
|
-
|
|
420
|
+
- orphan inbound / unknown KOL
|
|
421
|
+
- 写对应 `PROGRESS.md`
|
|
422
|
+
- `sentinel report --condition-met false`
|
|
423
|
+
- 退出
|
|
324
424
|
|
|
325
|
-
|
|
425
|
+
- git commit 失败
|
|
426
|
+
- 说明冲突原因
|
|
427
|
+
- 修复后重试
|
|
428
|
+
- 不要擅自 reset
|
|
326
429
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
- 商家指定 campaign → 只汇报该 campaign
|
|
330
|
-
- 未指定 + 只有一个 active → 只汇报该 campaign
|
|
331
|
-
- 未指定 + 多个 active → 先汇报跨 campaign 摘要,再提示可说"查看 {X}"
|
|
332
|
-
|
|
333
|
-
3. **跨 campaign 摘要**:
|
|
334
|
-
- 对每个 campaign 读 KOLS.md 统计 in_flight / deal_reached / needs_merchant_followup
|
|
335
|
-
- 读 CONFIG 的 total_budget,算已承诺预算
|
|
336
|
-
- 读 MERCHANT_LIMITS.md 今日 sent
|
|
337
|
-
- 汇报表格(markdown)
|
|
338
|
-
|
|
339
|
-
4. **单 campaign 详情**:
|
|
340
|
-
- 读 KOLS.md 按 status 分桶统计
|
|
341
|
-
- 对每个 needs_merchant_followup:读 CONVERSATIONS/{username}.md 最后一轮,总结 KOL 的诉求
|
|
342
|
-
- 读 campaign PROGRESS.md 最近 5 条
|
|
343
|
-
- 汇报(markdown 表格 + 待办列表)
|
|
430
|
+
- UTC 日期跨天
|
|
431
|
+
- 读 `MERCHANT_LIMITS.md` 时先归档昨天计数,再继续
|
|
344
432
|
|
|
345
433
|
---
|
|
346
434
|
|
|
347
|
-
##
|
|
348
|
-
|
|
349
|
-
- **git commit 节奏**:每个原子操作后立即 commit(一个 KOL 的一次发送 / 一个 CONFIG 段 / 一次状态更新),不要批量 commit
|
|
350
|
-
- **LLM 只填变量,不写 body**:所有对外邮件必须走模板渲染;直接生成 body 的 bypass 护栏
|
|
351
|
-
- **运行时零打扰**:任何护栏不过都**不要**问商家,降级为发 escalate_fallback + 标记 needs_merchant_followup
|
|
352
|
-
- **单会话单任务**:一次 session 只做一种动作(onboarding / 发 outreach / 处理回信 / 查询),完成后 git commit 并退出
|
|
353
|
-
- **文件路径**:所有路径都在 `~/kol-outreach/` 之下;运行前先 `cd ~/kol-outreach`
|
|
354
|
-
- **幂等性**:处理回信前检查 `in_reply_to` 是否等于最后一条 outbound 的 message_id;不等则 escalate(防止重复投递)
|
|
435
|
+
## 允许使用的命令
|
|
355
436
|
|
|
356
|
-
|
|
437
|
+
只使用这些命令:
|
|
357
438
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
| 当前 UTC 日期跨天 | 读 MERCHANT_LIMITS.md 时先归档昨天计数再继续 |
|
|
439
|
+
- `scout tiktok creators`
|
|
440
|
+
- `scout tiktok creator-products`
|
|
441
|
+
- `scout outreach send`
|
|
442
|
+
- `scout outreach brand-slug check|claim`
|
|
443
|
+
- `sentinel report`
|
|
364
444
|
|
|
365
|
-
|
|
445
|
+
不要这样做:
|
|
366
446
|
|
|
367
|
-
-
|
|
368
|
-
-
|
|
369
|
-
-
|
|
370
|
-
-
|
|
371
|
-
- `sentinel report` — 回信处理结束时汇报结果(仅在 `[KOL_INBOUND]` 触发的会话里)
|
|
447
|
+
- 不要绕过模板直接自由写外发邮件
|
|
448
|
+
- 不要跳过本地 workspace 状态检查
|
|
449
|
+
- 不要一次 session 混做多个流程
|
|
450
|
+
- 不要修改不属于本次任务的 campaign 状态
|