Skip to content

Commit e0e5012

Browse files
committed
✨ feat(agent-runtime): 新增金融工具动态发现与注入能力
- 新增resolveDiscoveredFinanceTools逻辑,识别finance_tool_discover调用结果 - 扩展聊天链路支持AdditionalTools参数,动态注入工具到下一轮对话 - 限制单次注入最多3个金融工具,避免schema过大影响模型效果 - 新增单元测试覆盖注入全链路流程 ✨ feat(finance-tools): 新增只读高层金融数据工具集 - 新增finance_market_data_get、finance_news_get、economy_indicator_get三个只读工具 - 底层封装多源fallback逻辑,单源失败自动重试备用数据源 - 工具默认不加入首轮工具集,仅通过discover动态注入,无副作用无需审批 - 配套完整单测覆盖工具定义、provider、handler全链路 ✨ feat(chat-tools): 新增群成员查询工具集 - 新增get_chat_members工具,查询当前群成员open_id与姓名列表 - 新增get_recent_active_members工具,查询最近发言的活跃成员,含发言统计 - 严格限定仅可查询当前chat_id范围数据,禁止跨群越权访问 - 配套完整单测覆盖边界场景 🐛 fix(aktool): 修复股票简称查询接口兼容性 - 切换股票信息查询接口从东方财富到雪球,提升数据稳定性 - 兼容新旧接口返回字段,优先取org_short_name_cn作为股票简称 - 调整symbol前缀拼接逻辑,适配雪球接口要求 📝 docs(plans): 新增功能实现计划文档 - 新增chat被动限流v2实现方案与上线记录文档 - 新增金融工具基于akshare统一实现计划文档 🔧 chore(config): 优化基础配置 - 新增.worktrees目录到.gitignore,适配多工作流开发 - 调高akshareapi默认重试次数从3到5,提升接口调用成功率 💄 style(ui): 调整agent流式卡片标题 - 将流式对话卡片标题修改为"Agentic Chat For You",优化用户感知
1 parent 9ba9df2 commit e0e5012

28 files changed

+2805
-67
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ __debug_bin*
66
!.codex/skills/
77
!.codex/skills/lark-card-debug/
88
!.codex/skills/lark-card-debug/**
9+
.worktrees/
910
.cache
1011
.env
1112
*.test
1213
script/neteaseapi/api_repo/*
1314
**__pycache__**
1415
.gocache
15-
.gomodcache
16+
.gomodcache

cmd/larkrobot/bootstrap.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,10 @@ func newAppComponents(cfg *infraConfig.BaseConfig) *appComponents {
147147
agentruntime.SetRuntimeAgenticCutoverBuilder(runtimecutover.BuildDefaultHandler)
148148
// agentruntime.SetRuntimeStandardCutoverBuilder(runtimecutover.BuildDefaultStandardHandler)
149149
agentruntime.SetDefaultChatToolProvider(handlers.BuildLarkTools)
150+
agentruntime.SetDefaultChatCapabilityToolProvider(handlers.BuildRuntimeCapabilityTools)
150151
agentruntime.SetChatGenerationPlanExecutor(agentruntime.NewDefaultChatGenerationPlanExecutor())
151152
runtimewire.SetDefaultCapabilityProvider(func() []agentruntime.Capability {
152-
return capdef.BuildToolCapabilities(handlers.BuildLarkTools(), nil, (*larkim.P2MessageReceiveV1)(nil))
153+
return capdef.BuildToolCapabilities(handlers.BuildRuntimeCapabilityTools(), nil, (*larkim.P2MessageReceiveV1)(nil))
153154
})
154155
messageProcessor := messages.NewMessageProcessor(appconfig.GetManager())
155156
reactionProcessor := reaction.NewReactionProcessor()
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# Chat Passive Ratelimit V2 Implementation Plan
2+
3+
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
4+
5+
**Goal:** Rework passive chat reply policy so direct mentions/private chat always bypass blocking, passive replies and active interjections use willingness-aware rate limiting, and `search_history` supports richer metadata filters while remaining strictly scoped to the current `chat_id`.
6+
7+
**Architecture:** Split reply policy into three layers: intent policy classifies direct/passive/interject decisions and willingness metadata, ratelimit enforces passive/interject budgets with separate hard/soft accounting, and chat generation narrows default context while relying on explicit history tools for broader retrieval. `search_history` becomes the primary metadata-aware history tool, but the handler owns the `chat_id` boundary so tool calls cannot escape the current conversation.
8+
9+
**Tech Stack:** Go, OpenSearch, Redis, GORM/gen query layer, Lark handlers/operators, Ark Responses tool calling, Go test.
10+
11+
---
12+
13+
## Chunk 1: Metadata-Aware History Search
14+
15+
### Task 1: Extend `search_history` request model and tests
16+
17+
**Files:**
18+
- Create: `internal/application/lark/history/search_test.go`
19+
- Modify: `internal/application/lark/history/search.go`
20+
- Modify: `internal/application/lark/handlers/history_search_handler.go`
21+
- Modify: `internal/application/lark/handlers/tools_test.go`
22+
23+
- [x] **Step 1: Write failing history-search query builder tests**
24+
25+
Add table-driven tests that verify:
26+
- `HybridSearchRequest.ChatID` is mandatory for tool usage.
27+
- `user_id`, `user_name`, and `message_type` filters become exact filter clauses.
28+
- keyword search still builds both keyword and vector clauses.
29+
- invalid or missing `ChatID` never produces an unscoped query.
30+
31+
- [x] **Step 2: Run test to verify it fails**
32+
33+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/history -run 'TestHybridSearch' -count=1`
34+
Expected: FAIL because metadata filtering and mandatory chat scoping are not implemented.
35+
36+
- [x] **Step 3: Write failing handler/tool tests**
37+
38+
Add tests for:
39+
- `search_history` tool schema exposes metadata fields such as `user_name` and `message_type`.
40+
- handler always injects `metaData.ChatID` into the search request.
41+
- handler rejects empty `metaData.ChatID`.
42+
43+
- [x] **Step 4: Run test to verify it fails**
44+
45+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/handlers -run 'Test(SearchHistory|LarkTools)' -count=1`
46+
Expected: FAIL because the tool does not yet expose the new metadata fields or enforce empty-chat rejection.
47+
48+
- [x] **Step 5: Implement minimal history search changes**
49+
50+
Implement:
51+
- richer `HybridSearchRequest` metadata fields,
52+
- a helper that builds the OpenSearch bool query with mandatory `chat_id`,
53+
- handler-side enforcement that tool searches are scoped to the current chat only.
54+
55+
- [x] **Step 6: Run focused tests**
56+
57+
Run:
58+
- `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/history -run 'TestHybridSearch' -count=1`
59+
- `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/handlers -run 'Test(SearchHistory|LarkTools)' -count=1`
60+
Expected: PASS.
61+
62+
## Chunk 2: Willingness-Aware Passive Reply Policy
63+
64+
### Task 2: Expand intent analysis payload and tests
65+
66+
**Files:**
67+
- Modify: `internal/application/lark/intentmeta/types.go`
68+
- Modify: `internal/application/lark/intent/recognizer.go`
69+
- Modify: `internal/application/lark/intent/recognizer_test.go`
70+
- Modify: `internal/application/lark/messages/ops/intent_recognize_op_test.go`
71+
72+
- [x] **Step 1: Write failing intent payload tests**
73+
74+
Add tests that cover:
75+
- parsing/sanitizing `reply_mode`, `user_willingness`, `interrupt_risk`, `needs_history`, `needs_web`,
76+
- conservative defaults for missing/invalid values,
77+
- prompt text explicitly describing direct/passive/interject distinctions.
78+
79+
- [x] **Step 2: Run test to verify it fails**
80+
81+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/intent ./internal/application/lark/messages/ops -run 'Test(Intent|AnalyzeMessage|IntentRecognize)' -count=1`
82+
Expected: FAIL because the new fields and prompt guidance do not exist yet.
83+
84+
- [x] **Step 3: Implement minimal intent model changes**
85+
86+
Implement:
87+
- new enum/type definitions in `intentmeta`,
88+
- updated recognizer system prompt and JSON parsing,
89+
- sanitization rules that keep direct/private traffic conservative and passive/interject scores bounded to `0-100`.
90+
91+
- [x] **Step 4: Run focused tests**
92+
93+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/intent ./internal/application/lark/messages/ops -run 'Test(Intent|AnalyzeMessage|IntentRecognize)' -count=1`
94+
Expected: PASS.
95+
96+
### Task 3: Rework passive reply decider and ratelimit accounting
97+
98+
**Files:**
99+
- Modify: `internal/application/lark/ratelimit/rate_limiter.go`
100+
- Modify: `internal/application/lark/ratelimit/integration.go`
101+
- Modify: `internal/application/lark/ratelimit/rate_limiter_test.go`
102+
- Modify: `internal/application/lark/messages/ops/chat_op.go`
103+
- Modify: `internal/application/config/accessor.go`
104+
105+
- [x] **Step 1: Write failing decider/ratelimit tests**
106+
107+
Add tests that verify:
108+
- direct mention traffic is never blocked by `Allow` because it bypasses the decider path,
109+
- `TriggerTypeMention` contributes to soft load but not hard passive budget,
110+
- `intent_reply_threshold` and `intent_fallback_rate` come from config accessor rather than hardcoded constants,
111+
- active interjections cost less than passive replies.
112+
113+
- [x] **Step 2: Run test to verify it fails**
114+
115+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/ratelimit ./internal/application/lark/messages/ops -run 'Test(SmartRateLimiter|Decider|ChatMsgOperator)' -count=1`
116+
Expected: FAIL because hard/soft budget separation and config-driven thresholds are not implemented.
117+
118+
- [x] **Step 3: Implement minimal passive-reply ratelimit changes**
119+
120+
Implement:
121+
- separate hard/soft weights,
122+
- willingness-aware score calculation in the decider,
123+
- config-driven thresholds/fallback rates,
124+
- chat operator mapping from intent reply mode to passive/interject trigger type.
125+
126+
- [x] **Step 4: Run focused tests**
127+
128+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/ratelimit ./internal/application/lark/messages/ops -run 'Test(SmartRateLimiter|Decider|ChatMsgOperator)' -count=1`
129+
Expected: PASS.
130+
131+
## Chunk 3: Prompt Split And Context Narrowing
132+
133+
### Task 4: Split direct-response vs ambient-response prompt selection
134+
135+
**Files:**
136+
- Modify: `internal/application/lark/agentruntime/chatflow/standard_plan.go`
137+
- Modify: `internal/application/lark/agentruntime/chatflow/standard_plan_test.go`
138+
- Modify: `internal/application/lark/handlers/chat_handler_test.go`
139+
- Modify: `internal/application/lark/messages/ops/reply_chat_op.go`
140+
- Modify: `internal/application/lark/messages/ops/chat_op.go`
141+
142+
- [x] **Step 1: Write failing plan-selection tests**
143+
144+
Add tests that verify:
145+
- direct replies choose the direct-response prompt path,
146+
- passive/interject replies choose the ambient prompt path,
147+
- passive prompt path no longer requires broad preloaded history to function.
148+
149+
- [x] **Step 2: Run test to verify it fails**
150+
151+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/agentruntime/chatflow ./internal/application/lark/handlers -run 'Test(StandardPlan|GenerateChatSeq|ResolveChatExecutionMode)' -count=1`
152+
Expected: FAIL because prompt selection is still single-path.
153+
154+
- [x] **Step 3: Implement minimal prompt/context split**
155+
156+
Implement:
157+
- prompt variant selection in standard chat planning,
158+
- minimal default context for passive/direct replies,
159+
- continued use of `search_history` for broader recall instead of mandatory pre-spliced history blocks.
160+
161+
- [x] **Step 4: Run focused tests**
162+
163+
Run: `GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/agentruntime/chatflow ./internal/application/lark/handlers -run 'Test(StandardPlan|GenerateChatSeq|ResolveChatExecutionMode)' -count=1`
164+
Expected: PASS.
165+
166+
## Chunk 4: Integrated Verification
167+
168+
### Task 5: Run regression suite for touched domains
169+
170+
**Files:**
171+
- Modify: `docs/superpowers/plans/2026-03-26-chat-passive-ratelimit-v2.md`
172+
173+
- [x] **Step 1: Run the aggregated targeted suite**
174+
175+
Run:
176+
`GOCACHE=/tmp/betago-gocache go test ./internal/application/lark/history ./internal/application/lark/handlers ./internal/application/lark/intent ./internal/application/lark/messages/ops ./internal/application/lark/ratelimit ./internal/application/lark/agentruntime/chatflow -count=1`
177+
178+
Expected: PASS.
179+
180+
- [x] **Step 2: Update plan checklist and capture follow-up debt**
181+
182+
### Follow-up debt
183+
184+
- `prompt_template_args.prompt_id=5` 仍然存在遗留模板耦合;本次通过“强约束系统提示 + 缩窄上下文”压住了问题,但下一轮最好迁到命名化 prompt config,而不是继续依赖数字 prompt ID。
185+
- `search_history` 已支持当前 chat 内的 metadata filter,但还没有进一步拆出 thread slice / recent slice 这类更低成本的专用读取工具。
186+
- 主索引现在作为 bot 自我身份判断的事实来源:bot 自己发出的消息保留真实 `user_id`,展示名仍可渲染成“你”;历史搜索和历史行渲染对旧数据里的 `"你"` sender alias 做兼容映射,暂不要求 retriever 同步这套身份元数据。
187+
- chat / agentic / continuation 三条 runtime user prompt 现在都会显式注入 `self_open_id``self_name``self_name` 通过带缓存的 `application/v6/applications/:app_id` 读取应用名,失败时回落到 `BaseInfo.RobotName`,便于模型在主索引历史和 mention 元数据里稳定识别“谁是自己”。
188+
- 主索引 mention 解析不再把 mention 直接吞掉;历史搜索结果会把 mention 还原成 `@姓名`,命中 bot 自己时渲染成 `@你`,便于模型直接理解“谁在@谁”。
189+
- 频控已经拆成 hard budget 和 soft load,但运营侧观测面板还看不到 direct/passive/interject 的拆分指标,后续应补 stats card 或 dashboard。
190+
- standard chat 现在默认不预取大段历史/主题摘要,后续可以继续根据 `needs_history / needs_web` 做更细粒度的 runtime 提示或自动 tool bias。
191+
192+
Record any deferred work, especially:
193+
- optional new history tools for exact recent chat slices/thread slices,
194+
- migration from numeric prompt IDs to named prompt configs,
195+
- stats panel exposure for passive-vs-direct budgets.
196+
197+
- [ ] **Step 3: Commit**
198+
199+
```bash
200+
git add docs/superpowers/plans/2026-03-26-chat-passive-ratelimit-v2.md \
201+
internal/application/lark/history/search.go \
202+
internal/application/lark/history/search_test.go \
203+
internal/application/lark/handlers/history_search_handler.go \
204+
internal/application/lark/handlers/tools_test.go \
205+
internal/application/lark/intentmeta/types.go \
206+
internal/application/lark/intent/recognizer.go \
207+
internal/application/lark/intent/recognizer_test.go \
208+
internal/application/lark/messages/ops/chat_op.go \
209+
internal/application/lark/messages/ops/intent_recognize_op_test.go \
210+
internal/application/lark/ratelimit/integration.go \
211+
internal/application/lark/ratelimit/rate_limiter.go \
212+
internal/application/lark/ratelimit/rate_limiter_test.go \
213+
internal/application/lark/agentruntime/chatflow/standard_plan.go \
214+
internal/application/lark/agentruntime/chatflow/standard_plan_test.go \
215+
internal/application/lark/handlers/chat_handler_test.go
216+
git commit -m "feat: add willingness-aware passive chat ratelimit"
217+
```

0 commit comments

Comments
 (0)