Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ Agent 领域几乎每周都有新范式出现。BitFun 的节奏是——**看

| 能力 | 说明 |
| --- | --- |
| **Code Agent** | 四种模式:Agentic(自主读改跑验证)/ Plan(先规划后执行)/ Debug(插桩取证 → 根因定位)/ Review(基于仓库规范审查) |
| **深度审查** | 面向高风险代码变更的并行代码审核团队,内置专项审核员、质量把关和用户确认后的修复流程 |
| **Code Agent** | 四种模式:Agentic(自主读改跑验证)/ Plan(先规划后执行)/ Debug(插桩取证 → 根因定位)/ Review(基于仓库规范审核) |
| **深度审核** | 面向高风险代码变更的并行代码审核团队,内置专项审核员、质量把关和用户确认后的修复流程 |
| **Cowork Agent** | PDF / DOCX / XLSX / PPTX 原生处理能力,可从 Skill 市场按需扩展 |
| **文档协作** | 在文档里边写边问,AI 直接在段落上改写、续写、总结、排版 |
| **Computer Use** | 看屏幕、动鼠标键盘,操作浏览器与任意桌面应用,把"手动点点点"交给 Agent |
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"desktop:build:release-fast": "node scripts/desktop-tauri-build.mjs --no-bundle -- --profile release-fast",
"desktop:build:exe": "node scripts/desktop-tauri-build.mjs --no-bundle",
"desktop:build:nsis": "node scripts/desktop-tauri-build.mjs --bundles nsis",
"desktop:build:nsis:fast": "node scripts/desktop-tauri-build.mjs --bundles nsis -- --profile release-fast",
"desktop:build:arm64": "node scripts/desktop-tauri-build.mjs --target aarch64-apple-darwin --bundles dmg",
"desktop:build:x86_64": "node scripts/desktop-tauri-build.mjs --target x86_64-apple-darwin --bundles dmg",
"desktop:build:linux": "node scripts/desktop-tauri-build.mjs",
Expand Down
38 changes: 29 additions & 9 deletions src/crates/core/src/agentic/agents/prompts/cowork_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,27 +219,47 @@ Tool results and user messages may include <system_reminder> tags. These <system
# Ask User Question Tool

Cowork mode includes an AskUserQuestion tool for gathering user input through multiple-choice
questions. BitFun should always use this tool before starting any real work—research, multi-step
tasks, file creation, or any workflow involving multiple steps or tool calls. The only exception
is simple back-and-forth conversation or quick factual questions.
questions. Use this tool to clarify the user's direction when the request is ambiguous or
underspecified. Once the direction is clear, proceed autonomously without asking for
confirmation on every step.

**Why this matters:**
Even requests that sound simple are often underspecified. Asking upfront prevents wasted effort
on the wrong thing.
**Examples of underspecified requests—always use the tool:**
on the wrong thing. However, Cowork mode emphasizes autonomous execution after direction is set.

**Examples of underspecified requests—use the tool:**
- "Create a presentation about X" → Ask about audience, length, tone, key points
- "Put together some research on Y" → Ask about depth, format, specific angles, intended use
- "Find interesting messages in Slack" → Ask about time period, channels, topics, what
"interesting" means
- "Summarize what's happening with Z" → Ask about scope, depth, audience, format
- "Help me prepare for my meeting" → Ask about meeting type, what preparation means, deliverables

**When to use:**
- The request is ambiguous or could be interpreted in multiple ways
- Multiple valid approaches exist with different trade-offs
- You are unsure about the user's intent or preferences
- The decision has security, performance, or architectural implications

**When NOT to use:**
- The user has already provided clear direction
- You are following an already-approved plan exactly
- The change is trivial and clearly correct
- Simple conversation or quick factual questions
- BitFun has already clarified this earlier in the conversation

**Question design guidelines:**
- State your recommendation clearly and explain WHY
- Make your recommended option the first option and add "(Recommended)"
- Provide 2-4 concrete options with trade-off descriptions
- Put all related questions into a single AskUserQuestion call

**Important:**
- Cowork mode emphasizes autonomous execution after direction is set
- Do not ask for confirmation on every step — trust your judgment once the direction is clear
- BitFun should use THIS TOOL to ask clarifying questions—not just type questions in the response
- When using a skill, BitFun should review its requirements first to inform what clarifying
questions to ask
**When NOT to use:**
- Simple conversation or quick factual questions
- The user already provided clear, detailed requirements
- BitFun has already clarified this earlier in the conversation

# Todo List Tool
Cowork mode includes a TodoWrite tool for tracking progress. **DEFAULT BEHAVIOR:**
Expand Down
13 changes: 13 additions & 0 deletions src/crates/core/src/agentic/agents/prompts/plan_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ At any point in time through this workflow you should feel free to ask the user

4. If there are multiple valid implementations, each changing the plan significantly, you MUST ask the user to clarify which implementation they want you to use.

## What NOT to ask in Plan Mode

- Do NOT ask "Is my plan ready?" or "Should I proceed?" — the user cannot see the plan until you finalize it
- Do NOT ask for feedback on the plan itself — use the CreatePlan tool and wait for user approval instead
- Do NOT reference "the plan" in your questions because the user cannot see it in the UI

## Question design in Plan Mode

- State your recommendation clearly and explain WHY
- Make your recommended option the first option and add "(Recommended)"
- Provide 2-4 concrete options with trade-off descriptions
- Focus on clarifying requirements, not validating the plan

# Plan Creation and Update

1. When you're done researching, present your plan by calling the CreatePlan tool, which creates a plan file for user approval. Do NOT make any file changes or run any tools that modify the system state in any way.
Expand Down
2 changes: 2 additions & 0 deletions src/crates/core/src/agentic/coordination/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,8 @@ Update the persona files and delete BOOTSTRAP.md as soon as bootstrap is complet
todos: None,
workspace_path: Some(workspace_path.to_string()),
workspace_hostname: None,
unread_completion: None,
needs_user_attention: None,
};
if let Err(e) = persistence_manager
.save_session_metadata(&workspace_path_buf, &metadata)
Expand Down
2 changes: 2 additions & 0 deletions src/crates/core/src/agentic/persistence/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@ impl PersistenceManager {
todos: existing.and_then(|value| value.todos.clone()),
workspace_path: Some(workspace_root),
workspace_hostname,
unread_completion: existing.and_then(|value| value.unread_completion.clone()),
needs_user_attention: existing.and_then(|value| value.needs_user_attention.clone()),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/crates/core/src/service/i18n/model_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub struct CodeReviewCopy {
}

const CODE_REVIEW_ZH_CN: CodeReviewCopy = CodeReviewCopy {
description: "提交代码审查结果。完成审查分析后必须调用本工具提交结构化审查报告。所有用户可见的文本字段必须使用简体中文。",
description: "提交代码审核结果。完成审核分析后必须调用本工具提交结构化审核报告。所有用户可见的文本字段必须使用简体中文。",
overall_assessment: "总体评价(2-3 句,使用简体中文)",
confidence_note: "上下文局限说明(可选,使用简体中文)",
issue_title: "问题标题(简体中文)",
Expand All @@ -26,7 +26,7 @@ const CODE_REVIEW_ZH_CN: CodeReviewCopy = CodeReviewCopy {
};

const CODE_REVIEW_ZH_TW: CodeReviewCopy = CodeReviewCopy {
description: "提交程式碼審查結果。完成審查分析後必須呼叫本工具提交結構化審查報告。所有使用者可見的文字欄位必須使用繁體中文。",
description: "提交程式碼審核結果。完成審核分析後必須呼叫本工具提交結構化審核報告。所有使用者可見的文字欄位必須使用繁體中文。",
overall_assessment: "整體評價(2-3 句,使用繁體中文)",
confidence_note: "上下文限制說明(可選,使用繁體中文)",
issue_title: "問題標題(繁體中文)",
Expand Down
26 changes: 26 additions & 0 deletions src/crates/core/src/service/session/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,30 @@ pub struct SessionMetadata {
alias = "workspace_hostname"
)]
pub workspace_hostname: Option<String>,

/// Unread completion status for the session.
/// 'completed' → green dot, 'error' → red dot.
/// Cleared after the user switches to the session and the content renders.
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "unread_completion",
alias = "unreadCompletion"
)]
pub unread_completion: Option<String>,

/// High-priority attention status for the session.
/// Set when the session requires user action while not the active session.
/// 'ask_user' → pending AskUserQuestion waiting for answer.
/// 'tool_confirm' → pending tool confirmations.
/// Takes precedence over unread_completion in the UI.
#[serde(
default,
skip_serializing_if = "Option::is_none",
alias = "needs_user_attention",
alias = "needsUserAttention"
)]
pub needs_user_attention: Option<String>,
}

/// Session status
Expand Down Expand Up @@ -504,6 +528,8 @@ impl SessionMetadata {
todos: None,
workspace_path: None,
workspace_hostname: None,
unread_completion: None,
needs_user_attention: None,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,23 @@
}
}

// Attention badge for high-priority states (ask_user / tool_confirm)
&__inline-item-attention-badge {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
gap: 3px;
height: 14px;
padding: 0 5px;
border: 1px solid color-mix(in srgb, var(--color-warning, #f59e0b) 35%, var(--border-subtle));
border-radius: 999px;
background: color-mix(in srgb, var(--color-warning, #f59e0b) 14%, transparent);
color: color-mix(in srgb, var(--color-warning, #f59e0b) 80%, var(--color-text-primary));
font-size: var(--font-size-xxs);
font-weight: 600;
letter-spacing: 0.02em;
}

&__inline-item-tooltip {
display: flex;
flex-direction: column;
Expand Down Expand Up @@ -271,6 +288,45 @@
0 0 0 1px color-mix(in srgb, var(--color-error, #ef4444) 35%, transparent),
0 0 6px color-mix(in srgb, var(--color-error, #ef4444) 42%, transparent);
}

// High-priority attention states: larger, brighter, with subtle pulse
&.is-ask-user,
&.is-tool-confirm {
width: 8px;
height: 8px;
right: -2px;
bottom: -2px;
}

&.is-ask-user {
background: var(--color-warning, #f59e0b);
box-shadow:
0 0 0 1.5px color-mix(in srgb, var(--color-warning, #f59e0b) 45%, transparent),
0 0 8px color-mix(in srgb, var(--color-warning, #f59e0b) 55%, transparent);
}

&.is-tool-confirm {
background: var(--color-accent-500, #8b5cf6);
box-shadow:
0 0 0 1.5px color-mix(in srgb, var(--color-accent-500, #8b5cf6) 45%, transparent),
0 0 8px color-mix(in srgb, var(--color-accent-500, #8b5cf6) 55%, transparent);
}

// Pulse animation for high-priority states
&.is-high-priority {
animation: bitfun-unread-dot-pulse 2s ease-in-out infinite;
}
}

@keyframes bitfun-unread-dot-pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.35);
opacity: 0.85;
}
}

&__inline-item-actions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ const SessionsSection: React.FC<SessionsSectionProps> = ({
requestAnimationFrame(() => {
requestAnimationFrame(() => {
flowChatStore.clearSessionUnreadCompletion(sessionId);
flowChatStore.clearSessionNeedsAttention(sessionId);
});
});
};
Expand Down Expand Up @@ -477,14 +478,19 @@ const SessionsSection: React.FC<SessionsSectionProps> = ({
: Bot
: Code2;
const isRunning = runningSessionIds.has(session.sessionId);
const isUnreadCompleted = !isRunning && session.hasUnreadCompletion;
const isRowActive = isSessionNavRowActive({
rowSessionId: session.sessionId,
activeTabId,
activeSessionId,
activeChildSessionId: activeBtwSessionData?.childSessionId,
activeChildParentSessionId: activeBtwSessionData?.parentSessionId,
});
// Determine the notification state for this session row.
// Priority: needsUserAttention > hasUnreadCompletion.
const attentionKind = !isRunning && !isRowActive
? (session.needsUserAttention || session.hasUnreadCompletion || undefined)
: undefined;
const isHighPriority = !!session.needsUserAttention;
const row = (
<div
className={[
Expand Down Expand Up @@ -521,16 +527,23 @@ const SessionsSection: React.FC<SessionsSectionProps> = ({
].join(' ')}
/>
)}
{isUnreadCompleted ? (
{attentionKind ? (
<span
className={[
'bitfun-nav-panel__inline-item-unread-dot',
session.hasUnreadCompletion === 'error' && 'is-error',
attentionKind === 'error' && 'is-error',
attentionKind === 'ask_user' && 'is-ask-user',
attentionKind === 'tool_confirm' && 'is-tool-confirm',
isHighPriority && 'is-high-priority',
].filter(Boolean).join(' ')}
aria-label={
session.hasUnreadCompletion === 'error'
attentionKind === 'error'
? t('nav.sessions.unreadError')
: t('nav.sessions.unreadCompleted')
: attentionKind === 'ask_user'
? t('nav.sessions.needsUserInput')
: attentionKind === 'tool_confirm'
? t('nav.sessions.needsToolConfirm')
: t('nav.sessions.unreadCompleted')
}
/>
) : null}
Expand Down Expand Up @@ -577,6 +590,13 @@ const SessionsSection: React.FC<SessionsSectionProps> = ({
{isChildSession ? (
<span className="bitfun-nav-panel__inline-item-btw-badge">{childSessionBadge}</span>
) : null}
{attentionKind === 'ask_user' || attentionKind === 'tool_confirm' ? (
<span className="bitfun-nav-panel__inline-item-attention-badge">
{attentionKind === 'ask_user'
? t('nav.sessions.badgeNeedsInput')
: t('nav.sessions.badgeNeedsConfirm')}
</span>
) : null}
{reviewActivityKind ? (
<span className="bitfun-nav-panel__inline-item-review-badge">
<Loader2 size={9} aria-hidden />
Expand Down
Loading
Loading