feat(taiji): unofficial custom package - warden/poke/RBAC, legion, ACP bridge, knowledge-base search - #2177
Open
1688mengdie wants to merge 89 commits into
Open
Conversation
AppRoot had grown into a single runtime object that owned routing, remote transport, conversation state and presentation at once, so every feature change reached across all of them. Split it along explicit boundaries: - pages/runtime for the composition root and lifecycle - pages/viewmodel for controllers and view models - pages/policy for pure decision helpers - pages/actions for the typed intent/action surface handed to components - pages/navigation and pages/layout for route and geometry contracts Components now receive typed action objects instead of reaching into view models, which lets Local and Remote share one conversation shell (ConversationRouteSurface on compact, WideConversationHost on wide). Behaviour changes that came out of the split: - Creating a chat from the "chat" option binds the desktop's assistant workspace first. The desktop ignores workspace_path for Claw sessions and always uses its assistant workspace, so the app used to keep showing the code workspace it was on while the session was actually created elsewhere - the new chat never appeared in the list. - Picking a workspace in the create sheet now pairs it with the code agent, so the picker is honoured instead of being silently dropped. - Compact remote conversations open the sidebar over the chat from a menu button, matching local chats, instead of popping back out of the conversation. The system back gesture still leaves the chat and reveals the drawer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The MVVM split only holds if the import direction is enforced. Add `pnpm run harmony:architecture`, which fails when services import pages, when components import view models, when the page graph gains a cycle, or when action and hook interfaces are passed as anything but typed object literals. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
chore(i18n): unify copy wording in zh-CN and zh-TW locale
Remove the parallel application connection and batch review surface, keeping the existing source policy and owner-specific permission controls as the single path. Reduce Web and TUI output, preserve remote and owner guards, and consume retired automatic defaults once without overwriting later user choices.
fix(agent): include goal lifecycle tools in Cowork
…-mode fix(remote-ssh): restore target selection and container stdin
…l-tools fix(agent): make goal lifecycle available to every primary agent
refactor(harmonyos): split the app shell into MVVM layers
…ine under sustained load
Subscription OAuth login, token refresh, and credential resolution now honor the global AI proxy (ai.proxy), including bare host:port URLs normalized to http://. Applies to Codex, Antigravity, and OpenCode subscription providers, and aligns TLS verification with the model configuration. Also reuse the credential committed by a concurrent refresh when the local conditional commit loses the race, instead of always failing on a revision conflict.
…ttings feat(web-ui): add pet switch settings action
fix(acp-agents): hide remote servers without deleting
- move the auto-title toggle into the section header - replace model radio options with a searchable model selector - align session-title labels and remove obsolete layout styles - update the Qwen help link to the Bailian console
chore(release): bump version to 0.2.17
fix(ai): route subscription auth through the configured proxy
… target The setup dialog asked for an approval policy and reported target model readiness, but protocol v4 carries both per turn and the composer already edits both. Choosing them once while picking a target contradicted that, and the model row pushed a manual, credential-bearing sync onto the user. The model picker was also broken for a restored projection. Its options came from the probe snapshot captured when the session was created, which lives only in renderer cache — never in the durable outbound record. A projection rebuilt from the controller index (invariant 28) therefore had an empty list, and the selector rendered nothing at all, so that session could never change model again. Models enabled locally after creation were likewise invisible. Setup now decides only what the target cannot change later: which target, which base revision, and whether uncommitted changes travel. - The new session's approval policy comes from this device's own permission default; the composer strip stays the only editor. Both mapping directions move into one module so they cannot drift. - Because the policy is switchable per turn, a target must advertise all three approval capabilities to be usable, not just the current one. - The dispatch model picker offers this device's catalog, unioning in the target's probed list rather than being replaced by it, and falls back to the local reasoning catalog and default model. - Submission pushes this controller's model configuration to a target that cannot serve the model, before any baseline is created, then re-probes. It stays visible as `model-sync` setup-audit rows in the preparation journal and the projected transcript, exactly like `cli-install`. A failed push is not fatal: the submission reports the target's own model diagnostic instead. - Older targets reject unknown audit actions, so those rows are forwarded only to a CLI advertising `setup_audit_model_sync`. The controller journal keeps them either way. Device targets have no such repair path and still fail closed. AI-assisted. Testing level: fully tested (automated) — dispatch suites in bitfun-core, bitfun-services-core and the CLI, plus the web-ui dispatch, ModelSelector and flow_chat suites. Not exercised against a live SSH host.
…OT at startup (UX-P1-3) CLI startup previously only initialized the global config service; the KnowledgeBaseSearch tool reads BITFUN_KNOWLEDGE_BASE_ROOT at call time, so a configured ai.knowledge_base_root was silently ignored in CLI deployments (L6-P0-1 was desktop-only). Mirror the desktop host injection (desktop/lib.rs:518-548): resolve ai.knowledge_base_root once at startup and inject it into the environment, keeping the explicit-env escape hatch. Adds inject_knowledge_base_root_if_needed + 4 unit tests (configured inject / explicit env wins / unset leaves env absent / blank treated as unset).
export_session_transcript used a bare fs::write over the transcript file; a concurrent reader (SessionHistory export / compression transcript readers) could observe a torn/partial file. create_compression_transcript used create_new + write_all, which is equally non-atomic while holding the lock open during the write. Replace both with the JsonFileStore temp+rename / hard-link publish path: - export_session_transcript -> write_text_atomic (BestEffortReplace) - create_compression_transcript -> write_text_atomic_create_new for the transcript and metadata pair, preserving the unique-name retry semantics of the former create_new reservation (AlreadyExists -> retry with a fresh stem) and removing partial files when the pair reservation fails. Adds two regression tests: transcript_atomic_write_leaves_no_torn_or_temp_artifacts (complete read after re-export, no .tmp droppings) and compression_transcript_pair_is_published_atomically (pair fully readable, no .tmp droppings).
… aggregate cap (UX-P1-4 + UX-P1-5) UX-P1-5: the deployment-frequency limit was a best-effort read-modify-write — two concurrent loads could both read an empty legionDeployTimes history, both pass the cap check, and both deploy. Guard the check-and-reserve with a KeyedAsyncLock keyed by (workspace, creator) so the in-flight deployment is already counted by the next load; the reservation is written before the creation loop and rolled back on every failure path (depth cap, create error, attach rollback, aggregate-cap rejection). A reservation persistence failure now fails the load closed instead of silently deploying without a counter. The cross-deployment aggregate cap is now workspace-dimensional: it counts all persisted legion node sessions in the deployment workspace (via the new SessionManager::count_workspace_legion_node_sessions) instead of the creator subtree, so recursive fission (children deployed as independent creators) can no longer exceed ai.legion_max_total_nodes layer by layer. UX-P1-4: document that max_nodes is resolved once per dispatch and passed into resolve_legion_topology — validate_input stays an early-reject hint and the dispatch-time value is authoritative, so a config hot-update between validate and call cannot make validation and execution disagree. Adds 3 tests: frequency_limit_helper_rejects_only_at_the_cap, rollback_helper_removes_only_the_reserved_timestamp, concurrent_loads_of_the_same_creator_are_serialized_by_the_deploy_lock, sequential_check_reserve_under_lock_counts_inflight_deployments.
…notation (UX-P1-3 + UX-P1-6) UX-P1-3: add a Knowledge Base section to BasicsConfig with an input + save button for ai.knowledge_base_root (injected into BITFUN_KNOWLEDGE_BASE_ROOT by the desktop/CLI hosts at startup). Adds en/zh-CN/zh-TW i18n keys and a vitest spec covering load/render, persist, and clear. UX-P1-6: annotate the legion node role label in CreateLegionPage with a 'display only' badge + tooltip explaining that legionRole is orchestration metadata only — the deployed session's permissions are always resolved by the standard subagent role (Executor), never by this label. Adds en/zh-CN/zh-TW roleAnnotation keys.
UserSteering messages persisted into history could still be re-processed across round/turn boundaries; content-based dedup keys risk prompt-cache prefix drift when matching against the injected payload. - MessageMetadata gains optional steering_id (serde default None, skip_serializing_if none) so the dedup marker persists with the message into snapshots and round-trips through serialization (backwards compatible with legacy snapshots) - execution_engine attaches the injection id to injected UserSteering messages instead of relying on content scanning - SessionRoundInjectionBuffer dedup upgraded to prefer the steering-id metadata key (id:<steering_id>), falling back to the content key for legacy entries without an id; drain/acknowledge/undelivered paths all record the id key; distinct steering events with identical content are no longer collapsed - tests: consumed steering id suppresses reinjection without content scanning; distinct steering ids survive after one is consumed; legacy content-key fallback keeps suppressing; steering_id metadata round-trips and legacy snapshots still load
…act (前端-P2-1/P2-2/P2-3/P2-4/P2-5/P2-6)
P2-S1: document PunishmentExecutor SessionControl scope (list/inspect only,
cancel/delete stay behind resolve_session_mutation_authorization)
P2-S2: Warden template path_policy restricted to .bitfun/warden audit root
(WARDEN_AUDIT_WRITE_ROOT) so prompt injection cannot write arbitrary files
P2-S4: tombstone parent=None now Err-propagates (d4-P1-1 family) in both
list_deleted_session_ids and record_deleted_session_id
P2-S5: warden judgement tool_args embedded as digest summary (param name +
length + sha256 fingerprint), never raw text (prompt-injection surface)
P2-S6: task ACP persist scan distinguishes idle slot (Ok(None) -> append) from
read error (Err -> keep scanning, never overwrite corrupt index)
P2-S7: remote collect_workspace_reader returns (data, timed_out) so callers
can distinguish no-output from truncated output
P2-S8: session tree serialization marks truncated nodes with "truncated": true
(mirrors orphaned marker); + truncation regression test
UX-P2-2: SessionControl list rejects cross-workspace listing unless owner or
warden/daemon audit session
UX-P2-3: transient sessions deny LegionControl (no persistent legion nodes
from throwaway scopes); + deny assertion test
UX-P2-4: session JSON artifacts forced 0o600-equivalent on Unix (best-effort)
before atomic publish
Verification: cargo check 0e0w (core/services-core/services-integrations/
desktop); core 2427 + agent-runtime 325 + desktop 274 + services-core 12 lib
tests green.
… content digest (TOKEN-03)
PERF-02: EventQueue stats switched from async Mutex<QueueStats> to
AtomicU64 counters, removing two async Mutex acquisitions from the
per-delta enqueue path (~thousands of locks per 2k-token reply).
TOKEN-03: User Context cache identity now appends |instr:<sha256> digest of
workspace instruction files (workspace AGENTS.md/CLAUDE.md + external
user sources when enabled), appended AFTER the stable prefix so
unchanged content keeps hitting the cache while an edited instruction
file invalidates it (TTL=None never expires otherwise). Digest failure
falls back to "unreadable" (cache miss, never blocks prompt assembly).
Verification: cargo check 0e0w; core 2427 (incl. user_context_cache_identity
switch-state/remote-layer tests) + agent-runtime 325 (incl. event_queue)
lib tests green.
# Conflicts: # scripts/core-boundaries/rules/feature-rules.mjs # src/crates/assembly/core/Cargo.toml # src/crates/assembly/core/src/agentic/agents/registry/external.rs # src/crates/assembly/core/src/agentic/tools/implementations/mod.rs # src/crates/assembly/core/src/agentic/tools/product_runtime/materialization.rs # src/crates/assembly/core/src/product_runtime/runtime_services.rs
… after upstream sync Upstream added tool_feature_group owner validation for product tool plans; local customization tools (WorkspaceScan/KnowledgeBaseSearch/PlanList/PlanRead/ PlanUpdate/LegionControl/acp_*) were missing from the mapping, breaking the default tool runtime feature closure. Keep them owned by Basic/AgentControl groups (customization preserved).
…basics-config knowledgeBase part, legion font-weight token
…ot scan (平台-P1-2) 根因:resolve_session_workspace_binding 第三查依赖本进程 workspace 注册表, 跨工作区会话(另一 host/runtime scope 创建)不在注册表中,即使元数据已 持久化也扫不到 -> 'Workspace for session could not be resolved'。 修复: 1. 第三查注册表候选从 ? 短路改为安全退化; 2. 新增第四查:扫描 user-level projects_root 下所有含 sessions 目录的 工作区,从会话自身元数据重建绑定(不依赖注册表); 3. session_config_from_persisted_metadata 优先读 stored state 文件恢复 完整 SessionConfig(workspace_id/execution_target),metadata 兜底。 测试:新增 cross_workspace_session_resolves_binding_from_projects_root_scan, bitfun-core lib 2439 全绿,session_manager 模块 131 全绿。
…nused-import warning
feat(input): show paths in file mentions
…rrors fix(ai): retry every provider error
Reattaching on every start turned out to be too eager. The browser only keeps its approval grant while it stays running, so whenever the browser had restarted since the last connection, BitFun's startup reattach put an approval dialog in front of the user before they had asked for the browser at all. Gate it behind ai.browser_control_auto_connect_on_startup, off by default, alongside the default CDP row it applies to. The setting's description says what turning it on does, including the dialog after a browser restart, and what stays true when it is off: BitFun attaches the first time an agent needs the browser.
…ect-opt-in fix(browser): make startup reattach opt-in
The root agent guide only warned about remote SSH workspaces, so changes routinely shipped complete for the local desktop and incomplete for the other remote paths: relay-driven remote control (mobile web and IM bots), Peer Device Mode, and detached Dispatch jobs. Replace the "Remote compatibility" section with "Remote scenarios": - A table naming all four scenarios with their design entry points. - Cross-cutting rules: design the remote path with the feature, degrade loudly instead of falling back to the local host, keep blocking prompts answerable from a distance, survive disconnect, and treat remote workspace paths as POSIX on every client OS. - Per-scenario obligations pointing at the real enforcement points: the remote-workspace policy registry, the RemoteCommand wire protocol and bot command router, the three peer deny lists that must stay in sync, and the dispatch observer/capability contract. AGENTS-CN.md is updated to match.
docs(agents): expand remote scenario guardrails
- refresh reasoning projections while editing explicit models.dev bindings - warn when the active API format cannot reliably apply catalog presets - add combined provider and model search with ranked multi-keyword matching - streamline custom preset naming and hide internal preset IDs
fix(settings): streamline copy and align controls
- 三项注入改造:会话级注入开关 + 配置体系(global/service/types)+ 前端 SessionConfig - 泄露链 A+C 修复:prompt_builder/prompt_cache/prompt_markup/scheduler 链路 - 子代理 steering 修复 + steering 打断修复:coordinator/execution_engine/session_manager - P2 修复:chat_state/instruction_sources/instruction_context - platform-P1-2 修复:tool_pipeline/agent-runtime
…UI consistency + models.dev reasoning preset)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
taiji 定制包合入请求
将 taiji 非官方定制成果合入上游
custom/taiji-unofficial定制分支。1688mengdie:custom/taiji-unofficial(merge commit90f1ad2e5)ca6eb3dad(父 = 最新上游a86e1916a,含全部定制成果,压缩自完整开发历史)custom/taiji-unofficial(792459b7b)→ 合入后变更面 = 上游 3 提交 + 定制包共 482 文件(+53482 / -15744),零混入功能域总览
1. Warden 守卫 + RBAC 权限模型(warden/poke/RBAC)
定位:agentic 运行时守卫全链路 + 三权分立权限底座。
{contentLength: N}+ 内容指纹,判定模型只见长度/指纹、不见全文(防内容泄露 + 判定 token 大降)src/crates/assembly/core/src/agentic/warden/runtime.rs(summarize 链)src/crates/assembly/core/src/agentic/tools/pipeline/tool_pipeline.rs(convert_tool_result / summarize_judgement_tool_args).../tools/implementations/todo_write_tool.rs、.../plan_update_tool.rssanitize_rate(rate=0/NaN/负/超上限 → 永不 poke;f64::INFINITY保留为显式禁用)src/crates/assembly/core/src/agentic/warden/poisson.rs~/.bitfun/warden/(跨 workspace 共享、重启不丢)src/crates/assembly/core/src/agentic/warden/runtime.rs+ scheduler 接线src/crates/assembly/core/src/agentic/tools/restrictions.rsresolve_session_mutation_authorization统一 SessionControl / acp_control / SessionMessage 投递的授权语义(daemon/warden 拦截 + owner 豁免 + created_by + 祖先授权)已知边界:SKILL.md 已降承诺——deadline/defer 当前运行时未执法(协议设计意图);惩罚阶梯为 R-25 纯提醒(无 RBAC 降级/冻结)。
2. Legion 军团系统(legion_mode / legion_control / team_presets)
定位:军团拓扑部署——fractal deployment topology,把复杂工作分解到专门 agent 会话。
MAX_LEGION_NODES=20防资源爆炸src/crates/assembly/core/src/agentic/tools/implementations/legion_control_tool.rslegion_mode.md;注册链完整(modes/mod.rs + agent-runtime agents.rs + registry/catalog.rs + prompt_catalog_contracts)src/crates/assembly/core/src/agentic/agents/definitions/modes/legion.rs、src/crates/assembly/agent-content/prompts/agents/legion_mode.mdsrc/crates/assembly/core/src/agentic/agents/team_presets.rssrc/web-ui/src/app/scenes/agents/components/、src/web-ui/src/infrastructure/api/service-api/LegionPresetAPI.ts已知边界:军团节点硬上限 20;LegionControl 通过 SessionControl 同一条持久化路径部署会话。
3. ACP 通道(真通道直通,去转述层)
定位:把 BitFun 会话/工具调用桥接到真实外部 Agent(Codex / Claude Code / OpenCode 等),
acp__<client>会话 = 真实外部进程。acp__create / Taskacp__<client>spawn 直接经 AcpClientPort 创建真外部 ACP 流会话(持久记录 + 进程启动 + 失败回滚)src/crates/assembly/core/src/agentic/tools/implementations/session_control_tool.rs、.../task/execution.rssrc/crates/assembly/core/src/agentic/tools/implementations/acp_tools.rsAcpClientPort契约(create/send/cancel/release/delete/read_history/stream)+ DesktopAcpClientPort 服务桥src/crates/contracts/runtime-ports/src/acp_client_port.rs、src/apps/desktop/src/runtime/acp_client_port.rssrc/apps/desktop/src/runtime/acp_session_lifecycle.rs已知边界:ACP 外部进程未启动时由首次委托 turn 懒启动;ACL 授权门(R4)已接入。
4. Session 会话管理(session tree / 幽灵防护 / 工具族)
定位:会话全生命周期管理 + 会话树 + 幽灵复活防护。
src/crates/services/services-core/src/session/tree.rs、src/crates/contracts/core-types/src/session_tree.rsdeleted-session-ids.json,上限 2000)+ finalize 前检查 + list 后端 tombstone 过滤 + 写锁/原子写(KeyedAsyncLock + temp+rename)src/crates/assembly/core/src/agentic/session/session_manager.rssrc/crates/assembly/core/src/agentic/tools/implementations/session_control_tool.rs、.../session_message_tool.rsSESSION_CONTEXT_WINDOW_MIN_TOKENS = 1M已知边界:tombstone 损坏显式报错传播(Err 暴露);reconcile 删除失败错误传播 + Windows 删除重试(5×50ms)。
5. 执行引擎 + 工具链(engine / 工具防呆)
定位:执行引擎主循环(消息组装/压缩/输出预留)+ 工具层防呆。
src/crates/assembly/core/src/agentic/execution/execution_engine.rsMAX_SAME_ROUND_COMPRESSION_PASSES=2防同轮无限压缩;ENGINE-03 输出预留钳制 ≤40% 窗口src/crates/assembly/core/src/agentic/tools/implementations/grep_tool.rs、src/crates/services/services-integrations/src/workspace_search/rg_fallback.rs.../file_read_tool.rs、src/crates/execution/agent-runtime/src/file_read_state.rs已知边界:skip_message_for_model_send 仅跳 ComputerUse 截图(刻意窄化);BackgroundResult 通知注入不注全文。
6. 知识库搜索 + 计划/任务工具
knowledge_base_search_tool——知识库根目录经环境变量解析(workspace 外可达,无硬编码路径)src/crates/assembly/core/src/agentic/tools/implementations/knowledge_base_search_tool.rssrc/crates/assembly/core/src/agentic/tools/implementations/plan_*.rs、src/crates/assembly/core/src/agentic/coordination/plan_todo_binding.rs、.../review_propagation.rs7. WebUI 增强
src/web-ui/src/app/layout/BeeColonyMonitor.tsxsrc/web-ui/src/app/components/panels/content-canvas/8. 脚本 / CI / 上游同步基础设施
scripts/embed-server.pypackage-windows-assets.mjs+ 单测SHERPA_ONNX_LIB_DIR;desktop-package workflow 修复变更面
测试程度声明
cargo check -p bitfun-core/-p bitfun-runtime-ports/-p bitfun-services-core→ 0 error 0 warningscripts/check-core-boundaries.test.mjs67/67(上游规则零破坏)bitfun-desktop受限于本地 mobile-web 前端产物缺失(环境预存问题,无 Rust 代码错误;CONTRIBUTING 前置检查项)备注