Skip to content

feat: 主动建议系统(Proactive Suggestion)— 周期 1 - #8

Merged
CavinHuang merged 24 commits into
mainfrom
worktree-proactive-suggestion
Aug 4, 2026
Merged

feat: 主动建议系统(Proactive Suggestion)— 周期 1#8
CavinHuang merged 24 commits into
mainfrom
worktree-proactive-suggestion

Conversation

@CavinHuang

@CavinHuang CavinHuang commented Aug 4, 2026

Copy link
Copy Markdown
Owner

主动建议系统(Proactive Suggestion)— 周期 1

为 Lume 增加完整的主动建议子系统,对齐 proma的 ProactiveAgent 能力。让 Agent 从「被动回答」进化到「对的时候提对的建议 + 越用越准」。

设计依据:docs/superpowers/specs/2026-08-03-proactive-suggestion-design.md · 实现计划:docs/superpowers/plans/2026-08-03-proactive-suggestion.md · 对标分析:docs/superpowers/analysis/2026-08-03-proactive-agent-proma-parity.md

核心理念

主动性 = 用户接受率,不是建议次数。所有 LLM Recall 98%+ 但误报率 51-65%,因此误报控制是一等公民(阈值 / 预算 / 频率学习 / 静默)。

实现(1:1 移植 Proma 建议引擎,适配 Lume sidecar 架构)

  • sidecar apps/sidecar/src/services/suggest/:signals(6 类词典正则,零 LLM)/ rules(5 类规则 + skill 后处理)/ engine(误报控制:threshold 0.6 / 预算 1+2 / 拒绝门 / 去重四连)/ feedback(频率学习 ×1.2/×0.8/×0.5 + 连续忽略 3 次静默)/ analyst(LLM 工作模式发现 + 严格 schema)/ service / store(suggestions.json 原子持久化)/ adapter(thread transcript 提取)
  • workflow-hookcore-suggestion-hooks 监听 run.afterComplete(与 memory-hooks 平行,不改 lume-runner),fire-and-forget
  • IPC:7 RPC channels + suggestion:changed 推送(复用 writeNotification
  • web:SuggestionBanner(三态横幅)+ ProactiveHub(「主动中心」侧栏聚合视图)+ typed IPC client + atom 实时刷新
  • action 复用既有底座:correction → memory-v2 pending(不新建存储)/ automation → createAutomationJob

9-link pipeline 端到端贯通

trigger → hook → service → engine → signals/rules → store → broadcaster → sidecar→web 推送 → UI → feedback。final review (opus) 逐跳验证无遗留 dead link。

⭐ 子代理实测发现并修复 1 个 P0 dead link

apps/desktop/src/renderer-sidecar-methods.ts 的 RPC 白名单漏配 7 个 suggestion 通道——sidecar 单测全绿(不跑 desktop preload),但生产桌面模式下所有 suggestion RPC 抛 unsupported 静默失败。这正是 Proma 1409 的 P0 教训(「功能看似正常但真实链路从不执行」)的精确复现。已修复 + electron-security.test 反射 guard 守门。

验证

  • ✅ 全 7 包 typecheck 干净
  • 207 测试全绿(proactive-suggest 164 + 集成 + web)
  • ✅ final whole-branch review (opus): Ready to merge,无 Critical/Important
  • 所有 deferred minors 均非阻塞(feedback 广播已修;recordFeedback 单写 / analyst 哨兵短路等留 follow-up)

架构落点

全在 apps/sidecar(逻辑)+ apps/web(UI),不依赖任何原生 API,无「必须放 desktop」约束。

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: beb47c24ec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +209 to +212
case "open_memory_board":
case "open_skill_creator":
// TODO(Task 11+): UI 导航由 web 端处理;此处仅完成反馈记录(已 recordFeedback)。
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Execute accepted todo and skill actions

When a user accepts a todo or skill suggestion, both the banner and ProactiveHub send only suggestion:act; neither renderer handles navigation separately. These branches therefore mark the record accepted and immediately return, so “把未完成任务记下来” creates no todo and a skill suggestion opens or creates nothing. Implement the promised action or return enough information for the renderer to perform it before removing the suggestion.

Useful? React with 👍 / 👎.

case "open_automation_create": {
createAutomationJob({
name: action.automationTitle,
schedule: { type: "manual" },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Create an actual schedule for automation suggestions

When an automation or follow-up suggestion is accepted, this creates a manual job even though the suggestion promises a timed reminder or unattended recurring task. Manual jobs receive nextRunAt: null and are explicitly skipped by scheduleJob in automation-runner-service.ts, so the accepted automation never runs automatically. Open the scheduling flow or derive a valid once/interval/cron schedule instead of silently creating a manual-only job.

Useful? React with 👍 / 👎.

export function getNeverKeys(): Set<string> {
const keys = new Set<string>();
for (const r of listSuggestions()) {
if (r.status === "never") keys.add(r.duplicateKey);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Persist the kind-level mute promised by never feedback

When the user clicks “不再建议这类”, the never state contributes only this record's duplicateKey; isTypeSilenced separately considers only three consecutive ignored records. A different suggestion with the same kind therefore continues to appear, directly violating the explicit opt-out shown in both suggestion UIs. Persist and consult a muted-kind setting, or relabel the action as suppressing only this exact suggestion.

Useful? React with 👍 / 👎.

feedback: SuggestionFeedback,
): Promise<void> {
try {
recordFeedback(id, feedback);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make feedback processing idempotent

If suggestion:act is retried or submitted twice for the same ID, there is no guard requiring the record to still be suggested: every request reapplies the type-weight multiplier and an accepted retry dispatches the action again, potentially creating duplicate automation jobs or memory candidates. Read and validate the prior status before recording feedback and dispatching the action so only the first transition is effective.

Useful? React with 👍 / 👎.

const seenKeys = new Set<string>();
let sessionSuggested = 0;
if (sessionKey) {
for (const r of listSuggestions("suggested")) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep handled records in the session dedup set

After a suggestion is accepted or ignored, it disappears from listSuggestions("suggested"), so it no longer counts toward the two-per-session budget and its duplicate key is forgotten. Because every evaluation reprocesses the last 30 user messages, the same ignored signal can be proposed again on the very next completed run, while a long-lived thread can receive more than the documented session maximum. Build the session count and seenKeys from all records for that session, not only currently pending ones.

Useful? React with 👍 / 👎.

TaTaLiao and others added 24 commits August 4, 2026 08:34
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Task 14: SuggestionBanner 组件。订阅 suggestionsVersionAtom,过滤 thread+workspace+24h 未过期记录,渲染 接受/忽略/不再建议 三态按钮,点击后调 actOnSuggestion 并显式重拉(覆盖 Task 12 feedback 不广播的 gap)。仿 AgentView.test.tsx fake-DOM 测试模式。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PUBLIC_RENDERER_SIDECAR_METHODS 漏配 7 个 suggestion RPC
(list/act/stats/delete/clear-all/run-analysis/set-enabled),
导致生产桌面模式下 validateRendererSidecarMethod 抛
'unsupported renderer sidecar method',前端 list/act 等全部
失败。这是 Proma P0 教训的典型:链路看似接通但实际 IPC
被白名单拦截。electron-security.test.mjs 已覆盖(修复前失败)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@CavinHuang
CavinHuang force-pushed the worktree-proactive-suggestion branch from beb47c2 to cd47394 Compare August 4, 2026 00:38
@CavinHuang
CavinHuang merged commit 88a06d2 into main Aug 4, 2026
0 of 5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cd4739473e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +231 to +232
try {
const neverKeys = getNeverKeys();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor the global switch during manual analysis

When suggestion:set-enabled has set the global switch to false, this entry point still calls the analyst and persists its results because only evaluateSessionSuggestions checks getEnabled(). A subsequent suggestion:run-analysis therefore creates new suggestions while the suggestion system is disabled; short-circuit this path on the same setting.

Useful? React with 👍 / 👎.

Comment on lines +243 to +245
const filtered = candidates.filter(
(c) => !neverKeys.has(c.duplicateKey) && !suggestedKeys.has(c.duplicateKey),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Recheck duplicate keys after the analyst finishes

The duplicate-key snapshot is taken before the potentially 60-second LLM call. If another analysis request or a session evaluation persists the same key while this request is awaiting runAnalysis, this stale set lets a second identical record through. Re-read the current suggested keys after the await, or enforce duplicate-key uniqueness atomically when persisting.

Useful? React with 👍 / 👎.

// fail-open:automation 段省略
}

return sections.length > 0 ? sections.join("\n") : "(暂无记忆)";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip analysis when there is no supporting context

For a fresh user with no memory entries, correction rules, or automation jobs, this returns the non-empty sentinel (暂无记忆); runAnalysis only short-circuits empty context, so clicking “分析工作模式” still makes a paid model request and may wait up to 60 seconds despite having no evidence to analyze. Return an empty string here, or explicitly recognize the sentinel before invoking the provider.

Useful? React with 👍 / 👎.

CavinHuang pushed a commit that referenced this pull request Aug 4, 2026
合并 remote 6 个 commit 到本地 browser-annotation + abort 线:
- 输入队列 followUpQueueMode 三态(shared/sidecar/web:blocked 重试/富引导/三态路由)
- PR #8 主动建议 / #9 L3 Persona / #10 主动中心自动化

冲突仅 schemas.agent-attachments.test.ts(两边各加独立 describe 块,保留两块)。
合并后 sidecar typecheck 绿 + abort/schema 66 测试绿。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants