@optima-chat/optima-agent 0.8.91 → 0.8.93
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/skills/browser/SKILL.md +8 -0
- package/.claude/skills/homepage/SKILL.md +4 -3
- package/.claude/skills/kol-outreach/SKILL.md +371 -0
- package/.claude/skills/kol-outreach/template/campaign/CONFIG.md +60 -0
- package/.claude/skills/kol-outreach/template/campaign/CONVERSATIONS/.gitkeep +0 -0
- package/.claude/skills/kol-outreach/template/campaign/KOLS.md +6 -0
- package/.claude/skills/kol-outreach/template/campaign/PROGRESS.md +3 -0
- package/.claude/skills/kol-outreach/template/campaign/TEMPLATES.md +88 -0
- package/.claude/skills/kol-outreach/template/campaign/assets/.gitkeep +0 -0
- package/.claude/skills/kol-outreach/template/merchant/BRAND.md +36 -0
- package/.claude/skills/kol-outreach/template/merchant/CAMPAIGNS.md +6 -0
- package/.claude/skills/kol-outreach/template/merchant/MERCHANT_LIMITS.md +16 -0
- package/.claude/skills/kol-outreach/template/merchant/PROGRESS.md +4 -0
- package/.claude/skills/kol-outreach/template/merchant/README.md +20 -0
- package/.claude/skills/video-clone/SKILL.md +125 -217
- package/.claude/skills/video-clone/assets/phase-state-template.json +11 -0
- package/.claude/skills/video-clone/references/ffmpeg-commands.md +31 -34
- package/.claude/skills/video-clone/references/gate-enforcement.md +144 -0
- package/.claude/skills/video-clone/references/kling-api.md +75 -75
- package/.claude/skills/video-clone/references/url-parsing.md +32 -13
- package/.claude/skills/video-clone/scripts/_confirm.py +96 -0
- package/.claude/skills/video-clone/scripts/_confirm_test.py +125 -0
- package/.claude/skills/video-clone/scripts/_gate.py +162 -0
- package/.claude/skills/video-clone/scripts/_gate_e2e_test.py +226 -0
- package/.claude/skills/video-clone/scripts/_gate_test.py +148 -0
- package/.claude/skills/video-clone/scripts/_project.py +56 -0
- package/.claude/skills/video-clone/scripts/analyze_source.py +113 -0
- package/.claude/skills/video-clone/scripts/analyze_source_test.py +52 -0
- package/.claude/skills/video-clone/scripts/assemble.py +106 -0
- package/.claude/skills/video-clone/scripts/confirm.py +12 -0
- package/.claude/skills/video-clone/scripts/edit_first_frame.py +66 -0
- package/.claude/skills/video-clone/scripts/extract_frames.py +108 -0
- package/.claude/skills/video-clone/scripts/gen_video.py +59 -0
- package/.claude/skills/video-clone/scripts/init_project.py +103 -0
- package/.claude/skills/video-clone/scripts/init_project_test.py +106 -0
- package/.claude/skills/video-clone/scripts/kling_generate.py +262 -0
- package/.claude/skills/video-clone/scripts/kling_generate_test.py +191 -0
- package/.claude/skills/video-clone/scripts/preflight.py +102 -0
- package/.claude/skills/video-clone/scripts/preview.py +208 -0
- package/.claude/skills/video-clone/scripts/preview_test.py +169 -0
- package/.claude/skills/video-clone/scripts/save_workflow.py +129 -0
- package/.claude/skills/video-clone/scripts/save_workflow_test.py +106 -0
- package/.claude/skills/video-clone/scripts/status.py +202 -0
- package/.claude/skills/video-clone/scripts/status_test.py +174 -0
- package/package.json +2 -1
|
@@ -144,6 +144,13 @@ browser-cli runscript xiaohongshu-image-note \
|
|
|
144
144
|
--param body="内容..." \
|
|
145
145
|
--param 'images=["~/images/photo1.jpg", "~/images/photo2.jpg"]'
|
|
146
146
|
# 输出: ✓ Script completed
|
|
147
|
+
|
|
148
|
+
# 另一个例子:小红书评论
|
|
149
|
+
browser-cli runscript xiaohongshu-comment \
|
|
150
|
+
--param search_keyword="辞职做跨境电商" \
|
|
151
|
+
--param comment="写得好!"
|
|
152
|
+
# 输出: ✓ Script completed
|
|
153
|
+
# 脚本会搜索帖子 → 打开 → 激活评论框 → 输入 → 发送
|
|
147
154
|
```
|
|
148
155
|
|
|
149
156
|
### 流程二:无脚本(首次)
|
|
@@ -426,3 +433,4 @@ if target_idx is None:
|
|
|
426
433
|
- **务必关闭**:操作完成后运行 `browser-cli close` 释放资源
|
|
427
434
|
- **login_required 处理**:如果 runscript 返回 `login_required` 错误,说明该平台未登录。先 `browser-cli launch --url <平台URL>` 手动登录(问用户要验证码),登录后 `browser-cli close` 保存登录态,再重新 `runscript`
|
|
428
435
|
- **Fallback 后更新脚本**:如果脚本频繁失败,重新生成并 submit-script 覆盖
|
|
436
|
+
- **Extension 模式**:标记了 `REQUIRES_USER_SESSION=True` 的脚本会自动使用用户的真实 Chrome(通过 Optima Browser Operator 扩展),未标记的脚本走 Chromium。这由后端自动判断,无需手动指定
|
|
@@ -52,8 +52,8 @@ description: 店铺首页配置。管理首页区块(Banner、集合列表、
|
|
|
52
52
|
|
|
53
53
|
| 用户说 | 命令 |
|
|
54
54
|
|-------|------|
|
|
55
|
-
| 设置首页背景图 | `commerce homepage update-page-settings --background-
|
|
56
|
-
| 设置固定背景(照片) | `commerce homepage update-page-settings --background-
|
|
55
|
+
| 设置首页背景图 | 先 `commerce upload --file bg.png` 拿到 media_id,再 `commerce homepage update-page-settings --background-media-id <id> --background-mode repeat-y` |
|
|
56
|
+
| 设置固定背景(照片) | 先上传,再 `commerce homepage update-page-settings --background-media-id <id> --background-mode fixed` |
|
|
57
57
|
| 调整背景叠加透明度 | `commerce homepage update-page-settings --overlay-opacity 0.7` |
|
|
58
58
|
| 调整背景叠加颜色 | `commerce homepage update-page-settings --overlay-color "#f5f5f5"` |
|
|
59
59
|
| 移除背景图 | `commerce homepage update-page-settings --remove-background` |
|
|
@@ -116,7 +116,8 @@ description: 店铺首页配置。管理首页区块(Banner、集合列表、
|
|
|
116
116
|
|
|
117
117
|
| 字段 | 类型 | 说明 |
|
|
118
118
|
|------|------|------|
|
|
119
|
-
|
|
|
119
|
+
| background_media_id | string / null | 背景图片 Media ID(通过 `commerce upload` 获取,推荐) |
|
|
120
|
+
| background_image | string / null | 背景图片 URL(不推荐直接使用,应通过 media_id 设置) |
|
|
120
121
|
| background_mode | string | `repeat-y`(横向填满纵向平铺,默认)/ `fixed`(固定视口) |
|
|
121
122
|
| background_overlay_color | string | 叠加颜色(hex 格式,默认 `#ffffff`) |
|
|
122
123
|
| background_overlay_opacity | number | 叠加透明度 0-1(默认 0.85,越大越不透明) |
|
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kol-outreach
|
|
3
|
+
description: "KOL 建联全自动化:从 TikTok 发现潜在 KOL、提取 bio email、发送个性化 outreach、自动谈判价格与条款。当用户说'帮我找 KOL'、'{产品} KOL 建联'、'KOL 进展如何',或收到系统触发的 [KOL_INBOUND:...] 或 [KOL_INBOUND] 标记时,使用此 skill。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# KOL Outreach Skill
|
|
7
|
+
|
|
8
|
+
本 skill 帮助商家在 TikTok 上端到端完成 KOL 建联:发现 → 触达 → 谈判 →
|
|
9
|
+
意向交付,运行时零打扰,所有决策参数在首次 onboarding 时固化。
|
|
10
|
+
|
|
11
|
+
## 核心工作目录
|
|
12
|
+
|
|
13
|
+
所有状态都在 `~/kol-outreach/`,整个目录是一个 git repo。结构:
|
|
14
|
+
|
|
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
|
+
```
|
|
29
|
+
|
|
30
|
+
## 每次 session 的启动流程
|
|
31
|
+
|
|
32
|
+
按顺序执行这些检查,决定本次 session 的动作:
|
|
33
|
+
|
|
34
|
+
1. **检测系统触发**:用户消息是否包含 `[KOL_INBOUND:{campaignId}]` 或 `[KOL_INBOUND]`(无 campaignId)标记?
|
|
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 进展" / "查看状态" → 走「查询进度」
|
|
44
|
+
|
|
45
|
+
**单会话单任务原则**:每次 session 只执行一种操作,完成后 git commit 并
|
|
46
|
+
更新 PROGRESS.md。出错时可以精准回滚。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 流程 A:Merchant onboarding(只发生一次)
|
|
51
|
+
|
|
52
|
+
1. 创建工作目录:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
mkdir -p ~/kol-outreach/campaigns
|
|
56
|
+
cp -r $CLAUDE_SKILL_DIR/template/merchant/. ~/kol-outreach/
|
|
57
|
+
cd ~/kol-outreach && git init && git add -A && git commit -m "init merchant workspace"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
2. 会话式填 `BRAND.md`:
|
|
61
|
+
- 询问 brand_name
|
|
62
|
+
- 从 brand_name 生成 brand_slug 建议(kebab-case)
|
|
63
|
+
- 调 `scout outreach brand-slug check {slug}` 验证唯一性
|
|
64
|
+
- 可用 → 确认
|
|
65
|
+
- 被占用 → 使用 API 返回的 suggestions 让商家选或自己改
|
|
66
|
+
- 成功后调 `scout outreach brand-slug claim` 锁定
|
|
67
|
+
- 依次询问 brand_website / brand_social / default_contact_name / default_brand_pitch
|
|
68
|
+
- 给出默认的兜底话术模板,让商家确认或改
|
|
69
|
+
- 给出默认的双语 escalation_keywords,让商家确认或扩展
|
|
70
|
+
- Edit `BRAND.md`
|
|
71
|
+
- `git add BRAND.md && git commit -m "setup BRAND.md"`
|
|
72
|
+
|
|
73
|
+
3. 会话式填 `MERCHANT_LIMITS.md`:
|
|
74
|
+
- 默认 `max_daily_sends: 50`,询问商家是否调整
|
|
75
|
+
- 初始化 `sent_today: 0`,`date_utc: $(date -u +%Y-%m-%d)`
|
|
76
|
+
- `git commit -m "setup MERCHANT_LIMITS.md"`
|
|
77
|
+
|
|
78
|
+
4. 告诉商家:商家级配置完成,现在为第一个商品创建 campaign,进入流程 B。
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 流程 B:Campaign onboarding(每次新建 campaign)
|
|
83
|
+
|
|
84
|
+
1. 确定 campaignId:
|
|
85
|
+
- 询问商家要为哪个商品建联(可列出他的 Optima 店铺商品作为选项)
|
|
86
|
+
- 从商品标题生成 kebab-case slug 建议("Titanium Travel Tumbler" → "titanium-tumbler")
|
|
87
|
+
- 校验:与 `CAMPAIGNS.md` 现有 campaign 不重复;匹配 `^[a-z0-9][a-z0-9-]{0,29}$`
|
|
88
|
+
- 告诉商家建议值,让他确认或改
|
|
89
|
+
|
|
90
|
+
2. 创建 campaign 目录:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
mkdir -p ~/kol-outreach/campaigns/{campaignId}
|
|
94
|
+
cp -r $CLAUDE_SKILL_DIR/template/campaign/. ~/kol-outreach/campaigns/{campaignId}/
|
|
95
|
+
cd ~/kol-outreach && git add -A && git commit -m "init campaign {campaignId}"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
3. 分段会话式填 campaign `CONFIG.md`:
|
|
99
|
+
- 3.1 Campaign 元信息(填 campaignId、创建时间、status=active)
|
|
100
|
+
- 3.2 商品段(ID/URL/标题/卖点/受众/样品)
|
|
101
|
+
- 3.3 目标 KOL 画像
|
|
102
|
+
- 3.4 预算与报价
|
|
103
|
+
- **校验**:`max_price >= target_price >= first_offer`、
|
|
104
|
+
`max_step <= max_price - first_offer`、`total_budget >= max_price`
|
|
105
|
+
- 任一不过 → 说明原因 + 建议调整 + 重新问,不要跳过
|
|
106
|
+
- 3.5 合作条款边界(保留时长/使用授权/付款节点/样品政策)
|
|
107
|
+
- 3.6 兜底话术覆写(默认留空继承 BRAND.md)+ 运行参数(max_rounds/max_days/max_concurrent_kols/覆写的 escalation_keywords/forbidden_phrases)
|
|
108
|
+
- 每段填完 → Edit CONFIG.md → `git commit -m "[{campaignId}] setup CONFIG section N"`
|
|
109
|
+
|
|
110
|
+
4. 追加 `CAMPAIGNS.md`(新增一行,status=active)
|
|
111
|
+
|
|
112
|
+
5. `git commit -m "[{campaignId}] campaign ready"`
|
|
113
|
+
|
|
114
|
+
6. 告诉商家 campaign 已就绪,问他是否立即开始发现 KOL。
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 流程 C:发现 KOL + 首发 Outreach
|
|
119
|
+
|
|
120
|
+
触发:用户说"给 {campaign} 开始建联" / "为 {campaign} 发送 outreach"。
|
|
121
|
+
如果商家没指定 campaign,读 `CAMPAIGNS.md`:
|
|
122
|
+
- 只有一个 active → 用它
|
|
123
|
+
- 多个 active → 列出让商家选
|
|
124
|
+
|
|
125
|
+
1. 读配置:
|
|
126
|
+
- `CONFIG.md`(目标画像/运行参数/预算)
|
|
127
|
+
- `KOLS.md`(已存在 KOL 列表)
|
|
128
|
+
- `BRAND.md`(后面生成 outreach 需要)
|
|
129
|
+
- `MERCHANT_LIMITS.md`(今日发信数)
|
|
130
|
+
|
|
131
|
+
2. 并行上限预检:
|
|
132
|
+
- `in_flight = KOLS.md 中 status ∈ {awaiting_reply, in_progress} 的行数`
|
|
133
|
+
- `available_slots = max_concurrent_kols - in_flight`
|
|
134
|
+
- `available_slots <= 0` → 告诉商家"当前 {in_flight} 个 KOL 在谈,已达并行上限。等 KOL 进入终态后再继续。"退出
|
|
135
|
+
- `target_new = min(CONFIG.target_kols_this_round, available_slots)`
|
|
136
|
+
|
|
137
|
+
3. 日发信上限预检(merchant 级):
|
|
138
|
+
- 读 MERCHANT_LIMITS.md 的 sent_today 和 max_daily_sends
|
|
139
|
+
- 如果当前 UTC 日期 ≠ MERCHANT_LIMITS.md 的 date_utc:归档昨天计数到历史表,sent_today=0,写回
|
|
140
|
+
- `daily_budget = max_daily_sends - sent_today`
|
|
141
|
+
- `daily_budget <= 0` → 告诉商家"今日所有 campaign 合计发信配额已用完",退出
|
|
142
|
+
- `本轮发送量 = min(target_new, daily_budget)`
|
|
143
|
+
|
|
144
|
+
4. 调 `scout tiktok creators` 发现 KOL:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
scout tiktok creators \
|
|
148
|
+
--follower-count "<CONFIG.powder_count_range>" \
|
|
149
|
+
--country "<CONFIG.region>" \
|
|
150
|
+
--limit <本轮发送量 * 3> \
|
|
151
|
+
--format json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
(×3 给过滤留空间)
|
|
155
|
+
|
|
156
|
+
5. 过滤:
|
|
157
|
+
- engagement_rate < 2% 丢弃
|
|
158
|
+
- 已在 KOLS.md 的 username 丢弃
|
|
159
|
+
- 粉丝量不在目标区间的丢弃
|
|
160
|
+
|
|
161
|
+
6. 对每个候选 KOL:
|
|
162
|
+
- 调 `scout tiktok creator-products @username --limit 5` 获取最近视频(用于生成开场白)
|
|
163
|
+
- 如果 scout 的 creators 响应 **没有返回 bio**,也从这里拉(见 probe Task 0.2)
|
|
164
|
+
- 用正则从 bio 抠 email:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
python3 -c "import re, sys; print(re.findall(r'[\\w.+-]+@[\\w-]+\\.[\\w.-]+', sys.stdin.read())[0] if re.search(r'[\\w.+-]+@[\\w-]+\\.[\\w.-]+', sys.stdin.read()) else '')" <<< "$BIO"
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- 有 email → 追加到 KOLS.md,status=pending_outreach
|
|
171
|
+
- 没 email → 追加到 KOLS.md,status=no_contact
|
|
172
|
+
- `git commit -m "[{campaignId}] discovered N KOLs"`
|
|
173
|
+
|
|
174
|
+
7. 对每个 status=pending_outreach 的 KOL(限制本轮发送量):
|
|
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
|
+
```
|
|
208
|
+
|
|
209
|
+
- 解析响应,拿 message_id 写回 CONVERSATIONS/{username}.md 的 Message-ID chain
|
|
210
|
+
- Edit KOLS.md:status: pending_outreach → awaiting_reply,offer=first_offer
|
|
211
|
+
- 读 MERCHANT_LIMITS.md,sent_today += 1,写回
|
|
212
|
+
- `git commit -m "[{campaignId}] outreach sent to @{username}"`
|
|
213
|
+
|
|
214
|
+
8. 追加本 campaign 的 PROGRESS.md;重要事件同步追加 merchant PROGRESS.md
|
|
215
|
+
|
|
216
|
+
9. 告诉商家本次发送结果。
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 流程 D:KOL 回信处理(由 `[KOL_INBOUND:{campaignId}]` 或 `[KOL_INBOUND]` 触发)
|
|
221
|
+
|
|
222
|
+
1. 解析 prompt:
|
|
223
|
+
- 如果包含 `[KOL_INBOUND:{campaignId}]` → 直接知道 campaignId,同时抠 email metadata(From / Subject / Message-ID / In-Reply-To / References / Body)
|
|
224
|
+
- 如果包含 `[KOL_INBOUND]` + `merchant_id: {X}` → campaignId 未知,抠 merchant_id 和 email metadata;campaignId 在步骤 3 中搜索确定
|
|
225
|
+
(`merchant_id` 仅用于日志和审计。campaign 查找基于 `~/kol-outreach/campaigns/*/KOLS.md` 遍历,因为工作目录已隐含了 merchant 身份。)
|
|
226
|
+
|
|
227
|
+
2. 校验 campaign 存在(仅 campaignId 已知时):
|
|
228
|
+
- `ls ~/kol-outreach/campaigns/{campaignId}/CONFIG.md`
|
|
229
|
+
- 不存在 → 写 merchant PROGRESS.md 异常记录 + `sentinel report --condition-met false --summary "unknown campaign"` + 退出
|
|
230
|
+
|
|
231
|
+
3. 按 from_email 查找 KOL:
|
|
232
|
+
- **campaignId 已知**(from step 1):只读该 campaign 的 KOLS.md
|
|
233
|
+
- 找到 → 继续步骤 4
|
|
234
|
+
- 找不到 → orphan_inbound:写 campaign PROGRESS.md + sentinel report false + 退出
|
|
235
|
+
- **campaignId 未知**(fallback):遍历 `~/kol-outreach/campaigns/*/KOLS.md`
|
|
236
|
+
- 唯一匹配 → 确定 campaignId,继续步骤 4
|
|
237
|
+
- 多个匹配 → 选 **KOLS.md 中该 email 对应条目的 `last_update` 字段**最新的那个 campaign
|
|
238
|
+
- 无匹配 → orphan_inbound:写 merchant PROGRESS.md + sentinel report false + 退出
|
|
239
|
+
|
|
240
|
+
※ 同一 campaign 内如果同一 email 出现多条记录(例如 KOL 换 username 后被重新添加),取 status 非终态(非 rejected / expired / no_contact)的活跃记录。
|
|
241
|
+
|
|
242
|
+
4. 读本 campaign 的 `CONFIG.md`、`BRAND.md`、`CONVERSATIONS/{username}.md`
|
|
243
|
+
|
|
244
|
+
5. **Layer 2 预检**(收到回信后、调 LLM 前):
|
|
245
|
+
- 当前 KOL `rounds >= CONFIG.max_rounds` → escalate
|
|
246
|
+
- 对话时长 `>= CONFIG.max_days` → expired
|
|
247
|
+
- KOL 最新回信 body 匹配 escalation_keywords(先查 CONFIG 覆写,再 fallback 到 BRAND 默认) → escalate
|
|
248
|
+
- Idempotency:最后一条 inbound round 的 message_id ≠ 本次 in_reply_to → escalate
|
|
249
|
+
|
|
250
|
+
6. **如果 Layer 2 触发**:
|
|
251
|
+
- 用 `escalate_fallback_v1` 模板渲染一封兜底回复
|
|
252
|
+
- 调 `scout outreach send` 发出去(带 in_reply_to / references)
|
|
253
|
+
- 更新 KOLS.md:status → needs_merchant_followup
|
|
254
|
+
- git commit
|
|
255
|
+
- `sentinel report --condition-met true --summary "layer2 escalate" --action-taken "..."`
|
|
256
|
+
- 退出
|
|
257
|
+
|
|
258
|
+
7. **LLM 结构化决策**(每一轮都重新调一次 LLM,全量对话历史放进上下文):
|
|
259
|
+
输入:
|
|
260
|
+
- campaign CONFIG.md 全文
|
|
261
|
+
- BRAND.md 全文
|
|
262
|
+
- CONVERSATIONS/{username}.md 全文
|
|
263
|
+
- 最新 KOL 回信
|
|
264
|
+
- TEMPLATES.md 里 counter_offer_v1 / deal_confirmation_v1 / escalate_fallback_v1 的变量列表
|
|
265
|
+
|
|
266
|
+
输出(结构化 JSON):
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"action": "counter_offer | accept | decline | clarify | escalate",
|
|
270
|
+
"new_price": 200,
|
|
271
|
+
"final_price": 250,
|
|
272
|
+
"concessions": ["video_retention_90d"],
|
|
273
|
+
"template_id": "counter_offer_v1",
|
|
274
|
+
"template_vars": { },
|
|
275
|
+
"reasoning": "..."
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
8. **Layer 3 后验**(基于本 campaign CONFIG 的预算和条款,不跨 campaign):
|
|
280
|
+
- `action ∈ {counter_offer, accept, decline, clarify, escalate}`
|
|
281
|
+
- 如果 `counter_offer`:
|
|
282
|
+
- `CONFIG.first_offer ≤ new_price ≤ CONFIG.max_price`
|
|
283
|
+
- `new_price - previous_offer ≤ CONFIG.max_step`
|
|
284
|
+
- 如果 `accept`:
|
|
285
|
+
- `CONFIG.first_offer ≤ final_price ≤ CONFIG.max_price`
|
|
286
|
+
- `committed_so_far (本 campaign KOLS.md 中 deal_reached 的 offer 总和) + final_price ≤ CONFIG.total_budget`
|
|
287
|
+
- `concessions ⊆ CONFIG.allowed_uses ∪ {'video_retention_N'}`
|
|
288
|
+
- `template_id ∈ 本 campaign TEMPLATES.md 的模板列表`
|
|
289
|
+
- 任一不过 → 降级为 escalate(走 Layer 2 失败分支)
|
|
290
|
+
|
|
291
|
+
9. 模板渲染:套对应模板 + template_vars → 最终 body
|
|
292
|
+
|
|
293
|
+
10. **Layer 4 终检**:
|
|
294
|
+
- body 不含 forbidden_phrases(CONFIG 覆写优先,fallback BRAND)
|
|
295
|
+
- body 长度 ≤ 2000 字符
|
|
296
|
+
- 不过 → 降级为 escalate
|
|
297
|
+
|
|
298
|
+
11. Edit `CONVERSATIONS/{username}.md` 追加 Round N (response sent),包括完整 LLM decision JSON 供审计
|
|
299
|
+
|
|
300
|
+
12. 调 `scout outreach send`:
|
|
301
|
+
- 带 `in_reply_to = KOL 的 message_id`
|
|
302
|
+
- 带 `references = 原 references 追加 KOL 的 message_id`
|
|
303
|
+
- 拿到新 message_id 写回 CONVERSATIONS
|
|
304
|
+
|
|
305
|
+
13. Edit `KOLS.md`:更新 rounds、current_offer、last_update、status
|
|
306
|
+
- 如果 action == accept:status → deal_reached
|
|
307
|
+
- 否则 status → awaiting_reply
|
|
308
|
+
|
|
309
|
+
14. 读 `MERCHANT_LIMITS.md`,sent_today += 1,写回
|
|
310
|
+
|
|
311
|
+
15. 如果 action == accept:
|
|
312
|
+
- 额外调 `scout outreach send` 发 deal_confirmation_v1 的 recap 给**商家注册邮箱**
|
|
313
|
+
- 在 merchant PROGRESS.md 记录 `[campaignId] DEAL REACHED with @username ($final_price)`
|
|
314
|
+
|
|
315
|
+
16. `git commit -m "[{campaignId}] round N {action} with @{username}"`
|
|
316
|
+
|
|
317
|
+
17. 追加 campaign PROGRESS.md
|
|
318
|
+
|
|
319
|
+
18. `sentinel report --condition-met true --summary "..." --action-taken "..."`
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 流程 E:查询进度
|
|
324
|
+
|
|
325
|
+
触发:商家说"KOL 进展如何" / "查看 {X} 状态"。
|
|
326
|
+
|
|
327
|
+
1. 读 `CAMPAIGNS.md`
|
|
328
|
+
2. 解析范围:
|
|
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 表格 + 待办列表)
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
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(防止重复投递)
|
|
355
|
+
|
|
356
|
+
## 错误处理要点
|
|
357
|
+
|
|
358
|
+
| 故障 | 处理 |
|
|
359
|
+
|---|---|
|
|
360
|
+
| `scout outreach send` 返回 `ok: false` | Edit KOLS.md status=send_error,记 PROGRESS.md,不中断其他 KOL 的处理 |
|
|
361
|
+
| LLM 结构化输出格式错误 | 重试 1 次;仍失败降级为 escalate |
|
|
362
|
+
| git commit 失败 | 说明冲突原因,修复后重试;不要擅自 reset |
|
|
363
|
+
| 当前 UTC 日期跨天 | 读 MERCHANT_LIMITS.md 时先归档昨天计数再继续 |
|
|
364
|
+
|
|
365
|
+
## 相关工具
|
|
366
|
+
|
|
367
|
+
- `scout tiktok creators` — 发现 KOL
|
|
368
|
+
- `scout tiktok creator-products` — 获取 KOL 最近内容用于个性化
|
|
369
|
+
- `scout outreach send` — 发送邮件(内部调 Resend)
|
|
370
|
+
- `scout outreach brand-slug check|claim` — 验证/锁定 brand_slug
|
|
371
|
+
- `sentinel report` — 回信处理结束时汇报结果(仅在 `[KOL_INBOUND]` 触发的会话里)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Campaign: {campaignId}
|
|
2
|
+
|
|
3
|
+
<!-- 首次 campaign onboarding 时由 skill 对话式填入,之后可手动编辑 -->
|
|
4
|
+
<!-- 品牌素材继承自 ../../BRAND.md,本文件只有覆写时才会重复 -->
|
|
5
|
+
|
|
6
|
+
## Campaign 元信息
|
|
7
|
+
- campaignId:
|
|
8
|
+
- 创建时间:
|
|
9
|
+
- 状态: active <!-- active | paused | completed | archived -->
|
|
10
|
+
|
|
11
|
+
## 商品
|
|
12
|
+
- 商品 ID 或 URL:
|
|
13
|
+
- 商品标题:
|
|
14
|
+
- 核心卖点(3-5 条):
|
|
15
|
+
- 目标受众(年龄/性别/兴趣/地区):
|
|
16
|
+
- 样品可寄送地区:
|
|
17
|
+
|
|
18
|
+
## 目标 KOL 画像
|
|
19
|
+
- 地区(scout --country):
|
|
20
|
+
- 粉丝量区间(scout --follower-count):
|
|
21
|
+
- 品类关键词:
|
|
22
|
+
- 本 campaign 目标合作 KOL 数量:
|
|
23
|
+
|
|
24
|
+
## 预算与报价(per-campaign 独立)
|
|
25
|
+
- max_price:
|
|
26
|
+
- target_price:
|
|
27
|
+
- first_offer:
|
|
28
|
+
- max_step:
|
|
29
|
+
- total_budget:
|
|
30
|
+
|
|
31
|
+
## 合作条款边界
|
|
32
|
+
- min_retention_days:
|
|
33
|
+
- allowed_uses:
|
|
34
|
+
- [ ] 商家官方账号转发
|
|
35
|
+
- [ ] 二创
|
|
36
|
+
- [ ] 付费广告投放
|
|
37
|
+
- payment_schedule:
|
|
38
|
+
- 样品政策:
|
|
39
|
+
|
|
40
|
+
## 兜底话术覆写(可选,留空则继承 BRAND.md)
|
|
41
|
+
- commission_request:
|
|
42
|
+
- contract_request:
|
|
43
|
+
- invoice_request:
|
|
44
|
+
- negative_tone:
|
|
45
|
+
|
|
46
|
+
## 品牌素材覆写(可选,留空则继承 BRAND.md)
|
|
47
|
+
- contact_name:
|
|
48
|
+
- brand_pitch:
|
|
49
|
+
|
|
50
|
+
## 运行参数(per-campaign 独立)
|
|
51
|
+
- max_rounds: 5
|
|
52
|
+
- max_days: 14
|
|
53
|
+
- max_concurrent_kols: 30
|
|
54
|
+
- escalation_keywords 覆写 (可选):
|
|
55
|
+
- English:
|
|
56
|
+
- 中文:
|
|
57
|
+
- forbidden_phrases 覆写 (可选):
|
|
58
|
+
- follow_up_enabled: false <!-- v1.1 -->
|
|
59
|
+
|
|
60
|
+
<!-- 注意: max_daily_sends 在 ../../MERCHANT_LIMITS.md,是 merchant 级配额 -->
|
|
File without changes
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Email Templates
|
|
2
|
+
|
|
3
|
+
<!-- LLM 只填变量({placeholder}),不写 body 。每个模板有固定的骨架。 -->
|
|
4
|
+
|
|
5
|
+
## first_outreach_v1
|
|
6
|
+
|
|
7
|
+
**Subject**: Collaboration opportunity with {brand_name}
|
|
8
|
+
|
|
9
|
+
**Body**:
|
|
10
|
+
Hi {kol_first_name},
|
|
11
|
+
|
|
12
|
+
{opener_line}
|
|
13
|
+
|
|
14
|
+
I'm {contact_name} from {brand_name} ({brand_website}). We make
|
|
15
|
+
{product_one_liner} and your audience seems to be a great fit because
|
|
16
|
+
{fit_reason}.
|
|
17
|
+
|
|
18
|
+
We'd love to work with you on a TikTok video featuring our {product_name}.
|
|
19
|
+
Here's what we're proposing:
|
|
20
|
+
|
|
21
|
+
- Fee: ${first_offer}
|
|
22
|
+
- Deliverable: 1 TikTok video, kept on your profile for at least
|
|
23
|
+
{min_retention_days} days
|
|
24
|
+
- We'll ship you a free sample to get you started
|
|
25
|
+
|
|
26
|
+
If this sounds interesting, just reply and we can work out the details.
|
|
27
|
+
|
|
28
|
+
Best,
|
|
29
|
+
{contact_name}
|
|
30
|
+
{brand_name}
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## counter_offer_v1
|
|
35
|
+
|
|
36
|
+
**Body**:
|
|
37
|
+
Hi {kol_first_name},
|
|
38
|
+
|
|
39
|
+
Thanks for the quick reply!
|
|
40
|
+
|
|
41
|
+
{acknowledge_line}
|
|
42
|
+
|
|
43
|
+
We're a bit tighter on budget, but we can go up to **${new_price}** for
|
|
44
|
+
the collaboration. {concession_line}
|
|
45
|
+
|
|
46
|
+
Would that work for you?
|
|
47
|
+
|
|
48
|
+
Best,
|
|
49
|
+
{contact_name}
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## escalate_fallback_v1
|
|
54
|
+
|
|
55
|
+
<!-- 用于 Layer 2/3/4 任一护栏触发时的兜底回复 -->
|
|
56
|
+
|
|
57
|
+
**Body**:
|
|
58
|
+
Hi {kol_first_name},
|
|
59
|
+
|
|
60
|
+
Thanks for your note. This is something I'd like to check with our team
|
|
61
|
+
before confirming. I'll get back to you within 1-2 business days.
|
|
62
|
+
|
|
63
|
+
Best,
|
|
64
|
+
{contact_name}
|
|
65
|
+
{brand_name}
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## deal_confirmation_v1
|
|
70
|
+
|
|
71
|
+
**Body**:
|
|
72
|
+
Hi {kol_first_name},
|
|
73
|
+
|
|
74
|
+
Great — we have a deal at **${final_price}**. Here's a summary for your
|
|
75
|
+
records:
|
|
76
|
+
|
|
77
|
+
- Fee: ${final_price}
|
|
78
|
+
- Deliverable: 1 TikTok video
|
|
79
|
+
- Video retention: at least {min_retention_days} days
|
|
80
|
+
- Payment: {payment_schedule}
|
|
81
|
+
- We'll ship the sample to {shipping_address_request}
|
|
82
|
+
|
|
83
|
+
Please reply with your shipping address and any PayPal/bank info you
|
|
84
|
+
prefer for payment. We'll take it from there.
|
|
85
|
+
|
|
86
|
+
Thanks for working with us!
|
|
87
|
+
{contact_name}
|
|
88
|
+
{brand_name}
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# 商家品牌素材
|
|
2
|
+
|
|
3
|
+
<!-- 商家首次使用 skill 时 onboarding 一次,之后所有 campaign 复用 -->
|
|
4
|
+
<!-- 单个 campaign 需要不同品牌身份时可在该 campaign 的 CONFIG.md 里覆写 -->
|
|
5
|
+
|
|
6
|
+
## 品牌基础
|
|
7
|
+
- brand_name:
|
|
8
|
+
- brand_slug: <!-- 用作发件邮箱 local part,全局唯一 -->
|
|
9
|
+
- brand_website:
|
|
10
|
+
- brand_social:
|
|
11
|
+
- default_contact_name:
|
|
12
|
+
- default_brand_pitch:
|
|
13
|
+
|
|
14
|
+
## 默认兜底话术(非白名单话题的预设回复,可被 campaign 覆写)
|
|
15
|
+
- default_commission_request:
|
|
16
|
+
- default_contract_request:
|
|
17
|
+
- default_invoice_request:
|
|
18
|
+
- default_negative_tone:
|
|
19
|
+
|
|
20
|
+
## 默认升级关键词(可被 campaign 覆写,必须中英双语)
|
|
21
|
+
- default_escalation_keywords_en:
|
|
22
|
+
- contract
|
|
23
|
+
- lawyer
|
|
24
|
+
- exclusive
|
|
25
|
+
- refund
|
|
26
|
+
- lawsuit
|
|
27
|
+
- NDA
|
|
28
|
+
- default_escalation_keywords_zh:
|
|
29
|
+
- 合同
|
|
30
|
+
- 律师
|
|
31
|
+
- 独家
|
|
32
|
+
- 退款
|
|
33
|
+
- 投诉
|
|
34
|
+
- 骗子
|
|
35
|
+
|
|
36
|
+
## 默认禁用词 (default_forbidden_phrases):
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Merchant-level Rate Limits
|
|
2
|
+
|
|
3
|
+
<!-- 所有 campaign 共享的 sending 配额 -->
|
|
4
|
+
<!-- skill 在每次发信前读/写这个文件,git commit -->
|
|
5
|
+
|
|
6
|
+
## 配置
|
|
7
|
+
- max_daily_sends: 50
|
|
8
|
+
- tz: UTC
|
|
9
|
+
|
|
10
|
+
## 今日发信计数
|
|
11
|
+
- date_utc:
|
|
12
|
+
- sent_today: 0
|
|
13
|
+
|
|
14
|
+
## 最近 10 天统计(滚动,由 skill 自动追加)
|
|
15
|
+
| date_utc | sent_count |
|
|
16
|
+
|---|---|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# KOL Outreach Workspace
|
|
2
|
+
|
|
3
|
+
This directory is your KOL 建联 workspace. Each file is markdown and git-tracked.
|
|
4
|
+
|
|
5
|
+
## Layout
|
|
6
|
+
|
|
7
|
+
- `BRAND.md` — your brand info, shared across all campaigns
|
|
8
|
+
- `MERCHANT_LIMITS.md` — cross-campaign sending rate limit
|
|
9
|
+
- `CAMPAIGNS.md` — index of all your campaigns
|
|
10
|
+
- `PROGRESS.md` — merchant-level log (one line per milestone)
|
|
11
|
+
- `campaigns/{campaignId}/` — one directory per campaign
|
|
12
|
+
|
|
13
|
+
## What you can edit by hand
|
|
14
|
+
|
|
15
|
+
Any markdown file. The skill will read your edits on the next invocation.
|
|
16
|
+
|
|
17
|
+
## How to add a new campaign
|
|
18
|
+
|
|
19
|
+
Say "帮我给 {product} 找 KOL" to the skill — it walks you through onboarding
|
|
20
|
+
and creates a new `campaigns/{campaignId}/` directory from the template.
|