Commit Graph

165 Commits

Author SHA1 Message Date
chiguyong 47a437c5e3 fix(experts): resolve residual review findings from PR #13
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
Addresses 4 actionable findings (1 P1 + 3 P2) from ce-code-review of
feat/ui-ue-enhancement (PR #13), now merged to main (8066e0b).

P1 — expert_step payload alignment (_phase_executor.py)
  The thinking/tool_call/tool_result event payloads were missing the
  fields the frontend WsServerMessage contract requires
  (expert_name/expert_color/content/step). Frontend code consuming these
  events silently degraded. Now all expert_step broadcasts carry the
  full contract; tool_call/tool_result keep step_data for the raw payload.

P2 #1 — execute_stream CancellationToken registration (config_driven.py)
  execute_stream() bypassed BaseAgent.execute() and never registered a
  CancellationToken, so cancel_task() could not cooperatively cancel a
  streaming task. Now registers the token and cleans it up in finally.

P2 #2 — team_synthesis orphan milestone cleanup (orchestrator.py)
  If synthesis streaming was interrupted (cancel/exception), no terminal
  team_synthesis event was emitted, leaving the frontend streaming
  milestone spinning forever. Now an inner try/except emits a terminal
  team_synthesis with status=cancelled|error before re-raising, so the
  frontend can finalize the milestone. The success path also carries
  the synthesis_id.

P2 #3 — synthesis_id dedup (orchestrator.py + types.ts + chatStream.ts)
  Without an identifier, the frontend could not precisely match a
  team_synthesis terminal event to its streaming milestone (especially
  across retries/concurrent teams). The backend now injects a stable
  synthesis_id (`{plan.id}:synthesis`) into both team_synthesis_chunk
  and team_synthesis events; the frontend uses it for exact milestone
  matching and treats error/cancelled status as terminal.

Test updates
  - Updated test_thinking_events_forwarded_as_expert_step to assert the
    new payload contract (expert_id/name/color/content/step).
  - Added test_tool_call_events_forwarded_as_expert_step covering
    tool_call/tool_result payload shape (content=tool_name摘要 +
    step_data=原始 payload).

Verification
  - ruff check: clean
  - pytest tests/unit/experts/test_phase_executor_streaming.py: 14/14
  - npm run typecheck: clean
  - vitest: 126/127 (1 unrelated baseline failure in tauri-auth.test.ts)

Residuals doc: docs/residual-review-findings/feat-ui-ue-enhancement.md
2026-07-01 13:26:19 +08:00
chiguyong f872a3fac6 feat: UI/UE enhancement — streaming, sticky header, hover actions, calendar tokens
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
U1 ThinkingBlock: streaming cursor + auto-collapse to summary bar
U2 StickyModeHeader: new component replacing ExpertTeamView + BoardStatusView
U3 Backend _phase_executor: execute_stream() with token/thinking/final_answer forwarding
U4 Frontend chatStream: expert_result_chunk/team_synthesis_chunk token accumulation
U5 AssistantText: routing tag hover fade-in
U6 UserBubble: hover actions (copy/delete/refill)
U7 CalendarGrid: token-based color redesign

Review fixes (ce-code-review):
- P0: _VALID_TEAM_EVENT_TYPES whitelist adds 3 new streaming event types
- P0: final_answer no longer double-accumulates token content
- P2: exception handling expanded to except Exception for LLMProviderError etc.

Simplification (ce-simplify-code):
- _synthesizer.py: O(n²) concat -> list+join, _concat_results extraction
- config_driven.py: 4 duplicate _handle_*_stream -> _wrap_sync_as_stream
- chatStream.ts: 5x [...messages].reverse().find() -> findLastMessage helper

Tests: pytest 13/13, vitest 126/127 (1 baseline), typecheck pass, ruff clean
2026-07-01 12:51:45 +08:00
Fischer c005642851 refactor: tech debt Wave 3+4 (tools/skills/mcp/rag/calendar/auth/cli/quality/channels/telemetry/session/bus/documents Any 治理) (#11)
Deploy to Production / deploy (push) Waiting to run Details
Test / backend-test (push) Waiting to run Details
Test / frontend-unit (push) Waiting to run Details
Test / api-e2e (push) Waiting to run Details
Test / frontend-e2e (push) Waiting to run Details
2026-07-01 08:08:36 +08:00
Fischer a778f816c5 refactor: tech debt Wave 1+2 (except Exception 收尾 + core/experts Any 治理) (#10)
Deploy to Production / deploy (push) Waiting to run Details
Test / backend-test (push) Waiting to run Details
Test / frontend-unit (push) Waiting to run Details
Test / api-e2e (push) Waiting to run Details
Test / frontend-e2e (push) Waiting to run Details
2026-07-01 03:54:53 +08:00
Fischer 838a05772e refactor: follow-up tech debt cleanup (except Exception + Any 治理) (#9)
Deploy to Production / deploy (push) Waiting to run Details
Test / backend-test (push) Waiting to run Details
Test / frontend-unit (push) Waiting to run Details
Test / api-e2e (push) Waiting to run Details
Test / frontend-e2e (push) Waiting to run Details
2026-07-01 03:03:02 +08:00
chiguyong ec9a0a1f70 refactor(frontend): split chat.ts (2025 lines) into chatStore/chatSocket/chatStream (U5)
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
chatStore.ts (498 lines, <=500 target met): Pinia store entry composing useChatSocket + useChatStream; retains all actions + backward-compat export aliases.

chatSocket.ts (165 lines): resolveIncomingConvId pure fn + useChatSocket composable (connect/disconnect/heartbeat/reconnect).

chatStream.ts (1557 lines): dispatchWsEvent pure fn for 30+ WS event types + useChatStream composable. Exceeds plan ~300 estimate due to discriminated union breadth (each case 30-50 lines); core testability goal met.

8 components + chat-phase.test.ts migrated from @/stores/chat to @/stores/chatStore.

vitest: 35 new tests (chatStream 19 + chatSocket 13 + chat-phase 3) all green; typecheck passes.
2026-06-30 22:32:48 +08:00
chiguyong a3cecd4b50 fix(review): apply P0/P2 findings from dual-agent review
- Dockerfile: split ENTRYPOINT/CMD to align with docker-compose serve
- test_termbase: guard jieba import with pytest.importorskip
- orchestrator: mark silent review-degradation with [DEGRADED] prefix
- chat.py: accurate ExecutionMode log message
- agentkit.yaml: document OTel exporter config
- skill_routing: replace 12 Any with object/typed (AGENTS.md compliance)
- AssistantText.vue: add aria-live/role for a11y
2026-06-30 14:27:46 +08:00
chiguyong 8627777f87 fix(review): apply ce-code-review findings
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
Six safe fixes from Stage 5c review:

phase.py: delete dead _DEFAULT_BASH_FILTER constant (no references after U1)
chat.py: drop Any from _build_phase_engine params (AGENTS.md prohibits any)
chat.ts: delete stale comment about phase_changed emission
chat-phase.test.ts: rename misleading 'capped at 5' test name
test_chat_plan_exec_ws.py: tighten test_rest_react_mode_still_works assertion
test_plan_exec_e2e.py: clarify test_auto_advance assertion comment

Known limitations documented in PR description (not fixed): loop detector + advance_phase (P1), parallel path phase_violation ordering (P2), REST cancellation_token (P2), Callable filter exceptions (P3).
2026-06-30 12:42:15 +08:00
chiguyong 2abe7c9e49 feat(U4): frontend phase_violation handling + PhaseIndicator component
Extend the frontend to surface PLAN_EXEC phase lifecycle events to the
user:

- WsServerMessage union (types.ts) gains two branches:
  `phase_changed` and `phase_violation` (matching backend U2 emission).
- chat.ts Pinia store gains a phase state slice:
  `currentPhase`, `phaseViolations` (capped at 5), `isPlanExec`
  computed, and `resetPlanExecState()`.
- handleWsMessage adds `case "phase_changed"` (sets currentPhase +
  appends a milestone step) and `case "phase_violation"` (sets
  currentPhase from violation data, appends to violations, fires an
  ant-design-vue message.warning toast, appends an error step).
- `result` handler calls `resetPlanExecState()` to clear the
  indicator when the conversation completes.
- New `PhaseIndicator.vue` component: compact badge + 4 dots
  (PLANNING/BUILDING/VERIFICATION/DELIVERY) with the current phase
  highlighted + violation counter. Renders nothing when
  `!isPlanExec` (graceful degradation).
- Mounted in `ChatView.vue` alongside ExpertTeamView and
  BoardStatusView.

Tests:
- New `tests/unit/stores/chat-phase.test.ts` verifies the phase state
  slice is exposed with correct initial values and `isPlanExec`
  derives from `currentPhase`.
- `npm run typecheck` clean.
- Pre-existing `tauri-auth.test.ts` failure is unrelated (fails in
  isolation on main).
2026-06-30 11:11:03 +08:00
chiguyong b032e08866 feat(U3): extract _build_phase_engine helper + wire REST PLAN_EXEC
Extract the WS path's inline phase_policy construction into a shared
_build_phase_engine helper so the REST send_message endpoint can reuse
it. Replace the former 501 stub with actual PLAN_EXEC execution:

- REST POST /chat/sessions/{id}/messages with execution_mode=plan_exec
  now builds a phase-policy-backed ReActEngine, calls execute()
  (non-streaming), and returns a MessageResponse.
- KTD5: PLAN_EXEC bypasses execute_with_fallback_chain — phase policy
  and fallback chain are mutually exclusive.
- When plan_exec.enabled=False, REST falls through to the REACT path
  (matching WS behavior).
- WS path refactored to call the same helper; behavior unchanged.

Tests:
- Replace TestRestPlanExec501 with TestRestPlanExec (happy path, bad
  config → 500, disabled → falls through to REACT, REACT mode unchanged).
- Add TestBuildPhaseEngineHelper covering all return branches:
  not-PLAN_EXEC, disabled, empty-config, invalid-config, tool append,
  default-policy fallback.
- All 109 tests pass across the three PLAN_EXEC test files.
2026-06-30 10:59:43 +08:00
chiguyong 4dc58c24bc feat(U2): emit phase_violation WS event alongside LLM reinjection
Wave 3 only injected the violation error dict back to the LLM as a tool
result. Wave 4 U2 adds a parallel WS event so the frontend PhaseIndicator
can surface violations to the user.

- ReActEngine: add _phase_violations accumulator (list[dict]). Cleared in
  reset(). _check_phase_permission appends a structured violation dict
  (with new violation_kind field: tool_not_allowed | bash_command_blocked)
  before returning the error.
- Add _drain_phase_violations(step) helper that pops pending violations
  and returns ReActEvent(event_type="phase_violation", ...) list. Events
  carry a shallow copy of the violation dict so callers can't mutate the
  accumulator.
- execute_stream: drain after each tool_result yield at all 3 tool
  execution sites (parallel, serial-with-confirmation, parsed_calls).
  Non-streaming execute() ignores the accumulator (the LLM reinjection
  via the error dict is the only signal there).
- chat.py WS handler: new elif branch forwards phase_violation ReActEvents
  to the client as {"type": "phase_violation", "data": ...} WS messages.
- Tests: 11 new tests covering accumulator lifecycle, drain semantics,
  shallow-copy isolation, and execute_stream event emission for both
  tool_block and bash_block paths. 2 new WS forwarding tests pin the
  chat.py path (forward + characterization for REACT mode).
2026-06-30 10:48:35 +08:00
Fischer 2b8a7d8909 feat(agent): Wave 3 strategic coupling (G5/G6) (#6)
Deploy to Production / deploy (push) Waiting to run Details
Test / backend-test (push) Waiting to run Details
Test / frontend-unit (push) Waiting to run Details
Test / api-e2e (push) Waiting to run Details
Test / frontend-e2e (push) Waiting to run Details
2026-06-30 09:17:19 +08:00
Fischer a2dcde01b8 feat(agent): Wave 2 medium coupling (G4/G7/G9) (#5)
Deploy to Production / deploy (push) Waiting to run Details
Test / backend-test (push) Waiting to run Details
Test / frontend-unit (push) Waiting to run Details
Test / api-e2e (push) Waiting to run Details
Test / frontend-e2e (push) Waiting to run Details
2026-06-30 09:09:33 +08:00
chiguyong d7ca6e8065 fix(review): W1 ServerConfig from_dict wiring, W3 internal kwargs filter, N3 status docstring
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
Code review fixes for Wave 1:
- W1: ServerConfig.from_dict now wires prompt_cache/streaming/verification sections
  from YAML to constructor (previously these params existed but were never read)
- W3: Tool._validate_input filters _-prefixed kwargs (e.g. _skip_dangerous_check)
  before jsonschema.validate, preventing additionalProperties:false schemas from
  rejecting internal control parameters
- N3: ReActResult.status docstring now lists "empty_fallback" and "verify_failed"

Added test test_internal_kwargs_underscore_prefixed_skipped_by_validation for W3.
2026-06-29 21:58:40 +08:00
chiguyong cd211c6cd9 feat(U4): G1 verify 失败回灌 ReAct
- ReActEngine 新增 max_reinjections 构造参数(默认 1,=0 等价原行为)
- execute()/execute_stream() verify 块从循环后移到循环内 final-answer 检测点:
  - verify 通过 → 正常 break
  - verify 失败 + reinjections < max + step < max_steps → errors 作为 user 消息回灌 conversation, continue 让 LLM 自纠正
  - verify 失败 + 达到 max_reinjections 或 max_steps → 记录 verify log 到 trajectory, trace_outcome="verify_failed", break
- execute_stream 的 final_answer 事件在 verify 通过后才 yield,避免客户端过早收到完成信号
- ReActResult.status 现在传递 trace_outcome(原默认 "success")
- ServerConfig.verification 配置项(max_reinjections)
- test_verify_reinjection.py 10 测试:characterization(max=0)+ 新行为(R1/R2/R3/R14)
2026-06-29 21:35:08 +08:00
chiguyong 0f3f0a7550 feat(U3): G8 delta_flush_interval 调速
- ReActEngine 新增 flush_interval_ms 构造参数(默认 0 = 逐 chunk yield 向后兼容)
- execute_stream chunk 循环用 time.monotonic 节流,累积 _flush_buffer 批量 yield
- flush_interval_ms=0 条件短路为 True 逐 chunk yield 保当前行为
- 流结束 mid-interval 最终 flush 剩余 buffer 不丢字符
- ServerConfig.streaming 配置项(flush_interval_ms)
- test_delta_flush.py 覆盖 R11/R12/R14
2026-06-29 20:49:52 +08:00
chiguyong c4aaef05aa feat(U2): G2 prompt cache 双块结构
- ReActEngine 新增 _build_system_message(stable+volatile) 双块构造
- Anthropic provider 返回 content blocks,stable 块带 cache_control
- 非 Anthropic provider 返回字符串拼接,依赖 stable 前缀命中自动前缀缓存
- execute_stream/execute 记忆注入从 system_prompt 末尾移到 volatile 层
- LLMGateway.get_provider_name_for_model 暴露 provider 检测能力
- anthropic.py _convert_messages 支持 list-type system content 透传
- ServerConfig.prompt_cache 配置项(默认 enable=True)
- ReActEngine.prompt_cache_enable 构造参数(默认 True 保当前行为)
- test_prompt_cache_layers.py 覆盖 R4-R7/R13
2026-06-29 20:47:23 +08:00
chiguyong 2747bb4e64 chore(prior): malformed tool call handling, auth whitelist, dev scripts, wave1 plan 2026-06-29 20:25:03 +08:00
chiguyong a6e1bf5884 feat(bitable): 多维表格文件层 + 默认字段 + 表内字段操作 + ce-code-review 修复 (Stage 1)
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
实现多维表格 UI 完整性 Stage 1(U1-U6),补齐飞书/twenty 对齐缺失的文件层、
默认字段与表内字段操作能力,并修复 ce-code-review 走查发现的 P0/P1 级问题。

后端(U1-U2):
- 新增 BitableFile 实体(models/db/repository/service/routes),三级层级:文件→数据表→字段/记录
- Schema V2 迁移:bitable_files 表 + tables.file_id 列,幂等(IF NOT EXISTS),保留 V1 孤儿表
- 新建数据表自动创建 5 个默认字段(标题/状态/日期/创建人/创建时间)
- agent-owned 字段在 create_record 时自动填充(按 type+owner 匹配,传 actor_user_id)
- 7 个文件 REST 端点 + IDOR ownership 检查(404-before-403,internal token 旁路)

前端(U3-U5):
- 文件列表页(FileCard 网格 + 新建/重命名/删除)+ 文件详情页(侧栏表格列表 + vxe-table 网格)
- Vue Router 嵌套路由 /bitable → /bitable/:fileId → /bitable/:fileId/:tableId
- 列头菜单(编辑/隐藏/删除字段)+ 末尾 + 列新增字段
- select/multiselect 字段自定义单元格编辑器 + Tag 展示
- Pinia store 扩展 file 状态与动作,深链直访回退 getFile,fileId 切换 watch

测试(U6):
- 文件 CRUD(12 例)+ 默认字段(10 例)单元测试
- 3 个 E2E spec(视图加载、文件流、字段操作),后端不可用时优雅跳过

ce-code-review 修复(P0/P1):
- P0 路由冲突:GET /files/{file_id} 遮蔽下载端点 → 下载改 /uploads/{filename}
- P0 IDOR:update/delete field/record/view 五端点补 ownership 检查
- P1 is_initialized property 缺失致二次初始化崩溃
- P1 直接 URL 导航失效(files 数组为空)→ selectFile 回退 getFile
- P1 fileId 切换不重载 → 增加 watch
- P1 轮询丢弃最终公式值(wasCalculating 守卫)+ 复用视图 filters
- P1 测试断言 200→201;test_db 无 URL 用例解除 postgres 标记得以执行
- P2 _check_table_ownership 403→404;输入长度校验;upload field-table 一致性校验
- P2 multiselect 浅比较 → 深比较;E2E bitable-view 补 waitForServer 守卫

验证:ruff check 通过;pytest 91 passed/116 skipped;vue-tsc --noEmit 通过。
2026-06-29 04:07:45 +08:00
chiguyong 5c15238a5a fix(calendar): 修复 agent 创建日历事件后 UI 不刷新 + 文档化三根因三部曲
Test / backend-test (pull_request) Has been cancelled Details
Test / frontend-unit (pull_request) Has been cancelled Details
Test / api-e2e (pull_request) Has been cancelled Details
Test / frontend-e2e (pull_request) Has been cancelled Details
代码修复 (ce-debug):
- CalendarService.create_event 注入 notify_callback,成功后广播 calendar_event_created WS 消息
- app.py 调整 _calendar_ws_sender 闭包定义顺序,注入 CalendarService(与 ReminderScheduler 共享)
- tauri-auth.ts keychain fallback 修复(localStorage 始终作为备份)
- 新增 2 个广播回归测试

文档 (ce-compound + ce-compound-refresh):
- 新增 docs/solutions/ui-bugs/calendar-agent-create-no-refresh.md(第三根因:WS 广播缺失)
- 更新 calendar-capability-and-ui-fixes.md:刷新 test count + 加 Related Issues 前向引用
- 更新 jwt-secret-dev-mode-user-id-mismatch.md:扩展 e2e bullet + 加第三个根因引用
- CONCEPTS.md 新增 Service Broadcast Callback 条目 (Real-Time Fan-Out 节)

测试:
- 新增 E2E 测试套件 (admin/auth-persistence/bitable/calendar/conversation/documents/evolution/settings/skills)
- 新增 tests/e2e/test_api_coverage.py
- CI: .gitea/.github workflows/test.yml
2026-06-29 02:20:33 +08:00
chiguyong d27681a93c fix(portal-auth): 修复 dev mode JWT 验证误激活 + README 文档同步
## Portal 401 根因修复

问题:AGENTKIT_JWT_SECRET 未设置时,jwt_utils 生成 ephemeral 非空 secret,
该 secret 被传给 AuthMiddleware 后 _is_dev_mode() 返回 False(not "" = False),
导致无 JWT/API key 的请求被拒为 401(17 个 portal 测试失败)。

修复:分离 explicit_jwt_secret 与 jwt_secret —
- explicit_jwt_secret = get_jwt_secret()  # None when env unset
- jwt_secret = explicit_jwt_secret or get_or_create_jwt_secret()  # for signing
- AuthMiddleware(jwt_secret=explicit_jwt_secret or "")  # only explicit activates JWT verify

ephemeral secret 仅供 token 签名 routes,不激活 middleware 的 JWT 验证。
生产环境(AGENTKIT_JWT_SECRET 已设置)行为不变。

验证:
- _is_dev_mode(): False → True
- GET /api/v1/portal/conversations: 401 → 200
- 27 个 portal 测试全部通过(之前 17 失败)
- 232 个测试通过 (portal + auth + calendar),0 失败

## README 文档同步

代码中 CostAwareRouter / RegexRules / HeuristicClassifier / SemanticRouter / LLMClassifier
类已完全删除,仅 RequestPreprocessor 存在。README.md 6 处过时引用同步:

- 第 4 节"意图路由"改为引用 RequestPreprocessor(详见第 7 节)
- 第 7 节重写为"请求预处理(RequestPreprocessor)",按 AGENTS.md 架构描述
- 第 8 节"语义路由"删除(合并入第 7 节历史说明)
- 架构图 CostAwareRouter → RequestPreprocessor,22→28 路由模块
- 模块详解 chat/skill_routing + chat/semantic_router 合并为 chat/request_preprocessor
- 模块详解 router/intent 描述更新为"未接入 chat 流程"
- 目录注释 CostAwareRouter → RequestPreprocessor
- 章节重新编号 1-16 连续(原 1-17 跳过 9)
2026-06-28 15:26:42 +08:00
chiguyong c9ce15fa4b fix(code-review): 修复走查发现的 13 High + Medium 安全/可靠性问题
代码修复(8 High + 9 Medium):
- portal.py — C1 IDOR 文档 / C2 类型修复 / C3 WS 连接上限 16 / C4 ws_user_id 早初始化 / M silent swallow 日志化
- auth/middleware.py — C5 WS sid 补齐
- calendar_tool.py — C6 偏移量 ±43200 双向校验 + reminder_channels 类型/白名单校验
- sqlite_conversation_store.py — C7 DELETE 事务回滚
- chat.ts (Pinia) — C8 deleteConversation 清理 pending 缓存
- app.py — M except: pass → logger.debug(exc_info=True)
- Scene6Error.vue — M onUnmounted 清理 setTimeout
- DocumentsTab.vue — M Invalid Date 守卫
- ChatSidebar/RightPanel/TopNav.vue — M aria-label 无障碍标签
- SystemMonitorPanel.vue — M v-else 兜底 + active 边框色 + tablist 键盘导航
- CalendarDrawer.vue — M overflow-y: auto
- CalendarGrid.vue — M ResizeObserver 反馈循环防护
- SkillsTab.vue — M onMounted 始终 fetchSkills

文档修复(5 High + 6 Medium):
- portal-platform-security-reliability-fixes.md — D2 测试路径 / D3 Root Cause+Impact 章节 / D4 severity: mixed / 标题中文化 / 12 处绝对路径转相对 / P2 #12 数字口径
- AGENTS.md — D5 路由表 22→28 / 专家模板 5→15 / LiteLLM U15 迁移 / 配置查找 fallback
- README.md — 8 处端口 8000→8001

新增测试:
- tests/unit/calendar/test_calendar_tool.py — ponytail 自检断言

验证:
- ruff check (5 文件) — All checks passed
- vue-tsc --noEmit — exit 0
- git stash baseline 验证 — portal 17 个 401 失败为预存在问题

已知限制(预存在):
- 17 个 portal 测试 401 失败 — 需另起 ce-debug 调查
- README.md 7 处 CostAwareRouter 引用过时 — 文档同步另起任务
2026-06-28 15:06:41 +08:00
chiguyong 43e9025c6d fix(calendar): 日历能力缺失修复 + UI 布局优化 + 会话404处理
P0: calendar_tool reminder_rules 未传入 create_event,提醒功能完全失效。P1: chat.ts deleteConversation 未清理 pending + 404 递归保护。P2: app.py 系统提示重复段落 + gui_mode F821 + SystemMonitorPanel flex 布局。P3: portal send_json 快照 + WS connected 清除 is_local + 移除死代码。验证: ruff+pytest 98passed+typecheck 通过。
2026-06-28 14:24:58 +08:00
chiguyong 31c65e01b8 fix(security): P0 安全加固 + 多实例部署一致性 (U1-U4 + U5c)
Deploy to Production / deploy (push) Has been cancelled Details
U1: LLM gateway KB 缓存 fail-closed — 异常时默认禁用缓存防止 KB 数据泄漏
U2: MCP 危险工具黑名单过滤 — 6+1 端点覆盖,防止绕过 chat confirmation
U3: SecretsStore Redis 迁移 — 多 worker 共享凭证,内存降级保留开发模式
U4: channels webhook Redis 状态 — ZSET 滑动窗口限流 + nonce dedup + backpressure
U5c: ce-code-review 修复批次:
  - P0: 统一 MCP 黑名单与 publisher.py 一致 (terminal_execute -> terminal, +file_read)
  - P1: ZSET 限流 member 加 uuid 后缀避免同时间戳碰撞
  - P1: SecretsStore redis 参数 Any -> aioredis.Redis | None (AGENTS.md 合规)
  - P1: Redis client 添加 socket_timeout 防止单点故障请求挂死

测试: 171 scoped tests pass, ruff clean
2026-06-26 04:05:33 +08:00
chiguyong 53faa60472 fix(review): ce-code-review P1+P2 修复 — 安全/可靠性/性能
P1 安全与可靠性(4 项):
- wecom: verify_signature 增加时间戳新鲜度校验(5 分钟窗口防重放)
- cache: should_cache 在 per_user_namespace 开启时拒绝 user_id=None
  匿名请求,避免跨用户缓存泄漏(安全要求 a/e)
- channels: webhook receive_message 异常兜底,防止 500 触发平台重试风暴
- app: shutdown 调用 close_all_adapters + await _pending_webhook_tasks,
  防止 httpx 连接泄漏和丢失 IM 回复

P2 效率与可维护性(5 项):
- feishu: _TOKEN_CACHE_TTL 300 → 6900(2h 减 5min 余量,避免 24x 过频刷新)
- channels: _pending_webhook_tasks 有界化(2x 并发上限时 429 拒绝)
- gateway: quota 检查每 period 单次 get_usage,复用 summary 检查 token+cost
- cache_key: generate_cache_key 合并为单次 SHA-256(消除 8-10 次冗余哈希)
- config: ProviderConfig.get_api_key 移除未用的 secrets_store 参数

P3 去重(1 项):
- channels: _process_inbound_message DIRECT_CHAT 路径提取 _direct_chat 辅助函数

测试:
- test_wecom: 时间戳改用 int(time.time()),新增 test_expired_timestamp_rejected
- test_cache: should_cache 测试覆盖匿名拒绝 + namespace_off 兼容
- test_config_migration: get_api_key 测试适配新签名
- channels/config_migration/quota_enforcement 测试全部通过
2026-06-26 01:40:31 +08:00
chiguyong 1ccaf56b9a refactor: ce-simplify-code 审查修复 — 去重 + 效率 + 死代码清理
3 个审查代理(复用/质量/效率)发现 15 个问题,全部修复:

效率与安全(6 项):
- MCPClient 缓存 MultiServerMCPClient 单例 + aclose(),修复连接/子进程泄漏
- _rate_limits 清理空 IP 条目,修复 X-Forwarded-For 欺骗下内存泄漏
- _seen_nonces 改用 OrderedDict,O(1) 摊销过期清理
- webhook 后台任务加 Semaphore(20) + 任务引用追踪,限制无界并发
- _build_adapter 用 asyncio.gather 并行解密 secrets
- 适配器实例缓存(_adapter_cache),token TTL 缓存跨请求命中

去重(4 项):
- header_get 提取到 channels/base.py,4 个适配器统一 import
- _get_client/close() 移入 MessageAdapter 基类,子类继承
- URLVerificationChallenge 统一到 base.py,feishu/slack/wecom 共用
- Transport ABC 添加 endpoint_url 属性,from_transport 不再访问私有字段

死代码与类型安全(5 项):
- detect_cache_hit 死方法替换为 record_cache_result 公开 API
- execution_mode.value == "direct_chat" 改用枚举比较
- 删除 yielded_any 死变量、重复 from fastapi import Request、
  多余 getattr 防御

453 tests passed, ruff clean(预存 F841 非本次引入)
2026-06-25 23:54:14 +08:00
chiguyong 069dbc22b1 feat(llm): U15 — LiteLLM unified provider + api_key encrypted secrets migration 2026-06-25 21:41:15 +08:00
chiguyong 13c516a54f feat(mcp): U14 — Skill/Team MCP publish with admin auth + dangerous-tool opt-in 2026-06-25 21:10:06 +08:00
chiguyong 16c33be295 feat(mcp): U13 — refactor MCPServer to route factory + mount at /api/v1/mcp with auth 2026-06-25 20:58:41 +08:00
chiguyong 8998f94c42 feat(channels): U12 — DingTalk/WeCom/Slack adapters + multi-channel webhook dispatch 2026-06-25 20:45:43 +08:00
chiguyong 4b58e8f661 feat(channels): U11 — Feishu IM adapter end-to-end (webhook + signature + AES-CBC decrypt + chat integration) 2026-06-25 20:24:21 +08:00
chiguyong 5572387c01 feat(channels): U10 — message adapter ABC + AES-256-GCM secrets store + channel CRUD routes 2026-06-25 20:13:37 +08:00
chiguyong 864bb95a30 feat(server): wire rag_platform components to app.state lifespan
Initialize in lifespan() (after bitable, before yield):
- KBStore + ensure_tables() → app.state.kb_store (if database_url available)
- RetrievalEngine + vector_store → app.state.retrieval_engine (if database_url available)
- HitProcessor → app.state.hit_processor (with llm_gateway)
- TaskManager → app.state.task_manager (degraded mode, InMemoryTaskStore)
- KBSettingsStore → app.state.kb_settings_store (singleton)

Each component wrapped in try/except — failures logged but don't block startup.
Follows same pattern as episodic memory initialization.
2026-06-25 20:02:01 +08:00
chiguyong 1f691ca178 feat(frontend): U9 — KB management extension with segment preview, status display, settings
New: SegmentPreview.vue, KBSettings.vue
Extended: DocumentUpload.vue (status badges, retry, preview), SearchTest.vue (3 modes), SourceConfig.vue (ACL), KnowledgeBaseView.vue (settings + task history tabs)
API+Store: kb.ts new types/methods, knowledge.ts new state/actions

typecheck: passed
2026-06-25 13:14:58 +08:00
chiguyong d026a91f43 feat(rag_platform): U6 — hit processing mode + KB settings
Add hit_processing.py: HitProcessor with model_opt (LLM-generated) and direct (concatenated chunks) modes, with in-process cache
Add settings.py: KBSettings/KBSettingsUpdate models, KBSettingsStore with async CRUD
Add KB settings endpoints to kb_management.py: GET/PUT /kb-management/kbs/{kb_id}/settings with owner-only modification

Tests: 43 new tests (25 hit_processing + 18 settings), 293 total passing
2026-06-25 12:44:47 +08:00
chiguyong 3f9588e673 feat(rag_platform): U3+U7 — rewrite upload endpoint with sanitization + pipeline
Rewrite upload_document() to use rag_platform sanitize + DocumentProcessor:
- File type whitelist validation (8 allowed types, reject .exe/.sh)
- File size limit (50MB) + zip bomb detection for ZIP-based formats
- DocumentProcessor.parse() (with content sanitization) + segment()
- Return chunks preview, status="segmenting" (pending vectorization)

Add POST /kb-management/documents/preview endpoint:
- Pre-upload preview with adjustable chunk_size/chunk_overlap
- Same security validation as upload, no document record created

Add POST /kb-management/documents/{id}/vectorize placeholder:
- Returns 503 — full async vectorization deferred to U8 (TaskIQ)

Test: update test_upload_document assertion (status "indexed" → "segmenting")
2026-06-25 12:06:16 +08:00
chiguyong bbbf9cd40a feat(bitable): add bitable companion service with full P0-P2 fixes
Bitable is a multi-dimensional table companion service that runs alongside
the main AgentKit server. It provides structured data storage with formula
fields, views, and ingestion pipelines.

Major components:
- Domain models (Pydantic v2): Table, Field, Record, View, RecalcTask
- SQLAlchemy 2 async ORM with independent bitable PostgreSQL schema
- Formula engine: AST parser, DAG, Kahn topological sort, safe eval
- RecalcWorker: atomic task claiming (FOR UPDATE SKIP LOCKED), topo-order
  processing, stale-threshold reaper for crash recovery
- REST API (/api/v1/bitable): tables, fields, records, views, files
- BitableTool: agent-facing tool with batch chunking (500/batch)
- CLI: agentkit bitable subcommands (create, list, import-excel, etc.)
- Frontend: Vue 3 + vxe-table grid with field management, views, filters
- Ingestion: Excel (openpyxl), database reflection, API collector

Security fixes (ce-code-review P0 + ce-debug P1):
- SQL injection prevention (field_id validation, parameterized queries)
- IDOR protection (_check_table_ownership on all table-level endpoints)
- SSRF prevention (URL scheme + private IP validation in parse_excel_url)
- OOM prevention (streaming file upload, batch delete, batch insert)
- Atomic recalc task claiming (FOR UPDATE SKIP LOCKED)
- Formula engine cache invalidation on field changes
- Composite cursor pagination for non-id sort orders
- Batch upsert (eliminates N+1 queries)
- Sync I/O offloaded to thread pool in async contexts
- Internal token auth (X-Internal-Token, hmac.compare_digest)
- PK unique index enforcement

Test coverage: 88 unit tests (95 skipped without Docker)
2026-06-25 01:09:59 +08:00
chiguyong dfd188b1a4 feat(orchestrator): add pipeline checkpoint and crash recovery (U7)
Add PipelineCheckpoint for stage-level crash recovery with Redis-first
+ memory fallback. TeamOrchestrator saves checkpoints after each phase
finalizes and supports resume(plan_id) to continue from the last
completed phase. New POST /api/v1/tasks/{id}/resume endpoint recreates
the team from saved plan and calls resume.
2026-06-24 21:04:18 +08:00
chiguyong ef84e3fd53 feat(experts): add SharedWorkspace state offloading for long-horizon runs
U4: ExpertTeam accepts redis_client, passes to SharedWorkspace. After phase
completion, full result is written to workspace and in-memory phase.result
is replaced with a 500-char summary + _ref_key. Dependency output reading
resolves offloaded content from workspace on demand, with graceful fallback
to summary on read failure.

Tests: 8 scenarios (offload creation, short content, dependency resolution,
workspace failure fallback, non-offloaded passthrough, redis_client wiring,
memory dict fallback, pipeline integration) — all pass.
2026-06-24 20:32:10 +08:00
chiguyong a312e584ae Merge branch 'feat/expert-team-pm-collaboration' — PM 协同模式 + 代码审查全量修复
Deploy to Production / deploy (push) Waiting to run Details
# Conflicts:
#	src/agentkit/server/frontend/components.d.ts
2026-06-24 18:57:37 +08:00
chiguyong 574db8458f fix(experts): PM 协同代码审查全量修复
P0: 跨阶段契约状态同步 — _notify_collaborators 更新接收方契约状态为 received
P0: 4 个 PM 事件加入 _VALID_TEAM_EVENT_TYPES 白名单

P1: 验收 fail-open 改标注降级原因
P1: 返工失败抛 RuntimeError 而非返回 dict
P1: 验收 prompt injection 防护 — 专家输出用 XML 标签包裹
P1: 契约字段校验 _EXPERT_NAME_RE
P1: bool("false") 修复 — 显式比较避免字符串真值陷阱
P1: _parse_risk_flags(None) 防御

P2: _notify_collaborators 移到验收通过后
P2: SharedWorkspace 写入移到验收通过后
P2: 验收贪婪正则修复
P2: 风险标记数量上限 MAX_RISK_FLAGS=10
P2: 返工 feedback 截断
P2: 前端会话隔离 — 切换会话时清除/恢复 collaborationState
P2: 前端契约状态更新 — collaboration_notice 时标记 delivered
P2: CLI 死代码标注 + 异常改 debug 日志
P2: 模块级 _RISK_FLAG_RE 预编译
2026-06-24 18:56:27 +08:00
chiguyong 34a4164430 feat(frontend): U5 前端协作关系图 + 验收/风险卡片
- types.ts 新增 ICollaborationContract/ICollaborationNotice/IReviewResult/IRiskFlag 等接口
- chat.ts 新增 collaborationState ref,处理 4 种协同事件
  (collaboration_contract_defined/collaboration_notice/review_result/risk_flagged)
  并在 plan_update 中提取 contracts,team_formed/dissolved 清理状态
- CollaborationGraphCard.vue SVG 协作关系图:
  圆形布局节点(专家首字),实线=契约,虚线动画=数据流向
  节点颜色编码验收状态(绿=通过,红=返工/失败),橙色!标记风险
- ReviewResultCard.vue 验收结果卡片(passed/failed + feedback)
- RiskFlagCard.vue 风险标记卡片(专家 + 风险描述)
- useMessageRenderer.ts 新增 3 个视图类型和渲染规格
- index.ts 导出 3 个新组件
- 遵循 U5 辩论可视化 BoardState 模式
- typecheck 通过
2026-06-24 14:42:00 +08:00
chiguyong 59e47c5871 test(calendar): 8 Playwright e2e tests + config fixes (JWT secret, rate limit)
E2E tests (calendar.spec.ts):
- E1: panel loads, shows empty state
- E2: create event via UI, verify in panel
- E3: switch between calendar/card/list views
- E4: edit event title via UI
- E5: delete event via API, verify removal from UI
- E6: create event with tag via UI (keyboard.type for Ant Select)
- E7: recurring event displays multiple occurrences
- E8: invitation manager button accessible

Config fixes (playwright.config.ts):
- Set AGENTKIT_JWT_SECRET so AuthMiddleware can verify login tokens
  (without it, get_jwt_secret() returns None → 401 on all API calls)
- Call create_app(rate_limit=10000) explicitly instead of uvicorn
  factory=True — factory mode lets server_config.rate_limit (60, from
  agentkit.yaml) override the env var, causing 429 rate limiting
- Use .venv/bin/python instead of system python3 (missing deps)

All 8 tests pass (47s).
2026-06-24 13:17:53 +08:00
chiguyong 49b483b933 feat(frontend): U5 前端辩论可视化
前端展示辩论过程,专家交锋有独立气泡样式,裁决结果清晰可见。

类型 (api/types.ts):
- WsServerMessage 新增 5 个辩论事件:debate_started / expert_argument /
  debate_round_summary / debate_resolved / team_intervention_ack
- IChatMessage.message_type 新增 4 个辩论消息类型
- IChatMessage 新增 7 个可选辩论字段(topic/round/decision 等)
- 新增 4 个数据接口

Chat Store (stores/chat.ts):
- 新增 debateState ref(topic/participants/round/status)
- WS switch 新增 5 个 case,复用 appendMessage/appendStep 模式
- 辩论结束 1s 后清空 debateState(与 board_concluded 一致)

渲染器 (useMessageRenderer.ts):
- MessageViewType + resolveMessageType 新增 4 个辩论视图类型
- useMessageRenderer 新增 4 个 render spec

新组件 (messages/):
- DebateBannerCard.vue — 辩论开始横幅(主题 + 参与专家 + 开场白)
- DebateArgumentCard.vue — 专家论点卡片(专家色边框 + 轮次标签)
- DebateSummaryCard.vue — 主持人轮次小结
- DebateConclusionCard.vue — 裁决卡片(按 decision 着色)

输入框 (ChatInput.vue):
- 团队模式下显示「辩论」按钮,点击弹出 prompt 输入主题
- 发送 /debate <topic> 命令(U4 WS 干预通道处理)

npm run typecheck 通过。
2026-06-24 12:37:37 +08:00
chiguyong c831e925b6 feat(experts): U4 用户干预通道 + 手动辩论触发
建立 @team 执行期间的用户干预通道,支持 /stop、/debate <topic>、
普通文本追加上下文。

ExpertTeam (src/agentkit/experts/team.py):
- 新增 _interventions: asyncio.Queue (maxsize=64) 干预队列
- add_user_intervention(msg): 广播 + 入队
- consume_user_interventions(): 排空并返回待处理干预
- broadcast_user_message 现在同时入队干预队列

TeamOrchestrator (src/agentkit/experts/orchestrator.py):
- 新增 _user_context: list[str] 累积普通文本干预
- 新增 _process_interventions(lead, plan) 在每层执行前调用:
  * /stop → 终止执行,广播 plan_update(stopped_by_user)
  * /debate <topic> → 动态插入 DEBATE phase(受 MAX_DEBATES 限制)
  * 普通文本 → 累积到 _user_context
- _synthesize_results 将 _user_context 追加到 synthesis prompt

WS 路由 (src/agentkit/server/routes/chat.py):
- 模块级 _active_teams dict 跟踪每个 session 的活跃团队
- _execute_team_collab 执行前注册、finally 注销
- WS 消息循环:若 session 有活跃团队,message 路由为干预而非新任务
- 新增 team_intervention_ack 确认消息

测试:tests/unit/experts/test_team_intervention.py(20 测试),
覆盖队列基础、/stop、/debate、普通文本、混合消息、synthesis 影响。
同步更新 test_orchestrator_debate.py 的干预通道兼容性测试
(U4 已实现 consume_user_interventions)。

全部 418 experts 测试 + 325 server 测试通过。
2026-06-24 12:17:09 +08:00
chiguyong d4bc79e409 test(calendar): wire calendar router into app.py + test plan
- Register calendar router in create_app() so /api/v1/calendar/* is reachable
- Initialize CalendarService + ReminderScheduler in lifespan
- Register CalendarTool into tool registry for ReAct integration
- Lazy-import ICSProvider in routes to break circular import
- Add test plan document (5 layers: unit/integration/e2e)
2026-06-24 11:51:31 +08:00
chiguyong 3fdee65979 fix(calendar): code review fixes - 23 issues (2 critical, 15 major, 6 minor) 2026-06-24 11:29:23 +08:00
chiguyong 394d734d42 feat(calendar): U12 reminder config and external sync settings UI 2026-06-24 05:02:29 +08:00
chiguyong 3131769aed feat(calendar): U11 event editor, invitation manager and batch operations 2026-06-24 05:02:12 +08:00
chiguyong 8350b02d75 feat(calendar): U10 frontend calendar views with 3 view modes and drawer 2026-06-23 23:50:28 +08:00