Commit Graph

348 Commits

Author SHA1 Message Date
chiguyong b86100a0a1 feat(cli): U6 CLI 多 Agent 入口 + 辩论 Rich 渲染
- 新增 _execute_team_cli() 处理 @team 前缀,运行 ExpertTeam 流水线
- Rich 事件渲染:team_formed/plan_update/phase_*/debate_*/team_synthesis
- 干预循环使用 select.select() 非阻塞轮询 stdin(Unix-only,ponytail 标注)
- 支持 /debate 手动触发辩论、/stop 终止团队、纯文本作为上下文注入
- 扩展 _print_help() 增加 Multi-Agent 与 Interventions 说明
- 新增 12 个单元测试覆盖路由、帮助文档、函数返回值、干预基础设施
2026-06-24 13:03:57 +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 5b5bd44ac4 test(calendar): 7 integration flow tests (lifecycle, recurrence, tags, types, invitations, authz, ICS) 2026-06-24 12:04:42 +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 91352d910e Merge feat/calendar-schedule: calendar & schedule feature (U1-U12 + code review fixes)
Deploy to Production / deploy (push) Waiting to run Details
12 implementation units, 104 tests, 23 code review fixes (2 critical, 15 major, 6 minor).
See docs/plans/2026-06-23-003-feat-calendar-schedule-plan.md for details.
2026-06-24 11:36:30 +08:00
chiguyong 460cf6e926 docs(calendar): add implementation history with code review summary 2026-06-24 11:36:10 +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 ac26d417b3 feat(experts): U3 分歧检测 + 方案评审辩论自动触发
在 TeamOrchestrator 中新增 4 个方法实现自动辩论触发:

- _maybe_add_plan_review_debate: 任务分解后可选插入方案评审 DEBATE
  phase(phases > 2 且 LLM 判断需要时),所有执行阶段依赖它
- _detect_divergence: 每层执行后用 LLM 判断已完成阶段产出是否与其他
  阶段存在分歧,偏好 false negative
- _insert_debate_phase: 动态插入 DEBATE phase 并重 wiring 依赖
  (原依赖 trigger 的 phase 现在依赖 DEBATE)
- _check_divergence_and_insert_debates: 每层完成后的协调入口,
  受 MAX_DEBATES=3 上限保护

主循环从 `for layer in layers` 改为 `while True` + 重新计算
topological_sort(),以支持动态插入 DEBATE phase 后的依赖分层。

测试:tests/unit/experts/test_divergence_detection.py(21 测试),
覆盖 happy path / 边界 / 错误路径 / 集成分层。同步修复
test_team_orchestrator.py 的 mock gateway 以适配 U3 的额外 LLM 调用。

全部 398 测试通过。
2026-06-24 11:09:53 +08:00
chiguyong fbe08cb1e2 feat(experts): add debate phase executor to TeamOrchestrator (U2)
Implement _execute_debate_phase() with Lead-facilitated structured debate:
- Lead opens with divergence point + dependency context
- Experts argue in parallel per round (asyncio.gather)
- Lead summarizes each round, then adjudicates final verdict
- Verdict produces decision (adopt/compromise/shelve/inconclusive) + conclusion
- Conclusion written to SharedWorkspace for downstream phases

Escape hatches:
- debate_config.skip=true short-circuits with template text
- MAX_DEBATE_ROUNDS=4 hard cap on rounds
- User /stop intervention ends debate early (U4-compatible via getattr fallback)
- LLM unavailable falls back to template verdict, no crash

New events: debate_started, expert_argument, debate_round_summary,
debate_resolved (plus existing phase_completed for consistency).

Phase dispatcher (_execute_phase) routes by phase_type:
EXECUTION to _execute_execution_phase, DEBATE to _execute_debate_phase.

36 new tests in test_orchestrator_debate.py covering happy path (2 rounds,
2 experts), max_rounds=1 boundary, empty participants, user stop, skip
escape hatch, LLM unavailable, SharedWorkspace integration, event
broadcasting, intervention channel compatibility, and helper methods.
All 377 expert tests pass.

Also includes planning artifacts (brainstorm requirements + implementation
plan with 6 units U1-U6).
2026-06-24 10:54:51 +08:00
chiguyong e539122314 feat(experts): add PhaseType enum and debate_config to PlanPhase
U1: Data model foundation for structured debate collaboration.
- Add PhaseType enum (EXECUTION | DEBATE)
- Add phase_type and debate_config fields to PlanPhase
- Update to_dict/from_dict for serialization with backward compatibility
- Add tests for PhaseType, debate phase creation, serialization, and
  mixed EXECUTION+DEBATE topological sort
2026-06-24 10:42:11 +08:00
chiguyong 4ea7801bcf fix(router): keyword match tiebreaker should preserve list order, not alphabetical 2026-06-24 10:11:42 +08:00
chiguyong d1250cf32b docs(calendar): mark plan as completed — all 12 units implemented 2026-06-24 05:04:39 +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
chiguyong 8d4145ddf9 feat(calendar): U7 Outlook sync via Microsoft Graph API
OutlookSyncProvider implementing AbstractSyncProvider for
bidirectional Outlook Calendar sync. Uses Graph API delta query
for incremental pull, auto-refreshes OAuth tokens on 401, and
converts Outlook recurrence patterns to RRULE. Same conflict
resolution as CalDAV (last-write-wins + WS notification).

- src/agentkit/calendar/sync/outlook_provider.py — OutlookSyncProvider
- tests/unit/calendar/test_sync_outlook.py — 8 tests
2026-06-23 23:49:24 +08:00
chiguyong 40bc27822f feat(calendar): U9 frontend store, API client and types
CalendarApiClient with 20 methods covering all backend endpoints
(listEvents, createEvent, importIcs, searchUsers, syncNow, etc.).
useCalendarStore Pinia store with events/eventTypes/tags state,
view mode switching, and handleWsEvent dispatch for 4 calendar WS
message types. WsServerMessage union extended with calendar variants.

- src/agentkit/server/frontend/src/api/calendar.ts — API client + types
- src/agentkit/server/frontend/src/stores/calendar.ts — Pinia store
- src/agentkit/server/frontend/src/api/types.ts — WS message types
2026-06-23 22:52:40 +08:00
chiguyong 40d326cd3f feat(calendar): U6 CalDAV sync provider and SyncManager
AbstractSyncProvider interface with CalDAVSyncProvider implementation
for bidirectional Apple Calendar sync. SyncManager orchestrates all
providers (G8) — sync_all/sync_provider/resolve_conflict with
last-write-wins + WS notification on conflicts (G4). caldav library
calls wrapped in asyncio.to_thread for non-blocking operation.

- src/agentkit/calendar/sync/base.py — AbstractSyncProvider ABC
- src/agentkit/calendar/sync/caldav_provider.py — CalDAVSyncProvider
- src/agentkit/calendar/sync/manager.py — SyncManager (G8)
- pyproject.toml — added caldav>=1.3 dependency
- tests — 12 tests (9 CalDAV + 3 SyncManager)
2026-06-23 22:52:29 +08:00
chiguyong ffb184acc7 feat(calendar): U8 iCal/ICS import and export
ICSProvider parses .ics files (icalendar library) and creates local
CalendarEvents, skipping duplicate UIDs. Export builds an iCalendar
from events in a date range, deduplicating recurring event
occurrences back to a single VEVENT with RRULE. REST endpoints:
POST /import-ics (multipart upload), GET /export-ics (download).

- src/agentkit/calendar/sync/__init__.py — sync subpackage init
- src/agentkit/calendar/sync/ics_provider.py — ICSProvider (import/export)
- src/agentkit/calendar/db.py — added get_event_by_external_id() for dedup
- src/agentkit/server/routes/calendar.py — import-ics and export-ics endpoints
- pyproject.toml — added icalendar>=5.0 dependency
- tests/unit/calendar/test_ics_provider.py — 8 tests
2026-06-23 22:20:07 +08:00
chiguyong 26efbb51db feat(calendar): U5 reminder subsystem with scheduler and multi-channel dispatch
ReminderScheduler scans upcoming events every 60s, matches reminder
rules, and dispatches via client (WS), email (SMTP), or webhook
channels. Idempotent delivery (no duplicates on re-scan), retry with
exponential backoff (up to 3 attempts). Follows task_store.py
start/stop asyncio loop pattern (KTD-2 — conscious deviation from
APScheduler).

- src/agentkit/calendar/scheduler.py — ReminderScheduler (start/stop/scan_once)
- src/agentkit/calendar/reminders.py — ReminderDispatcher (strategy per channel)
- src/agentkit/calendar/db.py — added list_all_events_in_time_range() for scheduler
- tests/unit/calendar/test_scheduler.py — 8 tests
- tests/unit/calendar/test_reminders.py — 9 tests
2026-06-23 22:19:57 +08:00
chiguyong ddcedb57b2 feat(calendar): U4 post-processing extractor with keyword gating
Adds PostProcessingExtractor — a zero-LLM keyword gate (Chinese +
English time words) followed by LLM extraction for ambiguous cases.
Events created from extraction carry source="post_extract" so the UI
can style them distinctly (R33). LLM gateway is optional to keep the
constructor testable without a live provider.

- src/agentkit/calendar/extraction.py — PostProcessingExtractor
- tests/unit/calendar/test_extraction.py — 13 tests with MockLLMGateway
2026-06-23 21:56:20 +08:00
chiguyong 42fe7bcbc9 feat(calendar): U3 agent calendar tool for ReAct integration
Adds CalendarTool implementing the Tool ABC so the ReAct engine can
create, query, update, and delete events autonomously. Resolves
event_type_name and tag_names (look up or create), sets
source="agent" to distinguish agent-created events from manual ones.

- src/agentkit/tools/calendar_tool.py — CalendarTool(Tool)
- tests/unit/tools/test_calendar_tool.py — 13 tests covering all actions
2026-06-23 21:56:08 +08:00
chiguyong d36e45bbe7 feat(calendar): U2 backend service & REST API
Add CalendarService business logic layer and 14 REST endpoints:
- service.py: event CRUD with RRULE expansion, event types, tags,
  invitations, non-admin user search (G5/A3), type-level default
  reminder rule cloning
- routes/calendar.py: JWT-authenticated endpoints for events, types,
  tags, invitations, user search — with ownership checks
- 17 new tests (12 service + 5 routes), 33 total calendar tests passing
2026-06-23 21:43:39 +08:00
chiguyong 2ea799f6c4 feat(calendar): U1 backend data model, storage & RRULE expansion
Add calendar subsystem foundation mirroring documents/ pattern:
- models.py: 8 dataclasses (CalendarEvent with is_invited, EventType,
  Tag, EventTag, ReminderRule, ReminderDelivery, ExternalCalendarConfig,
  Invitation)
- db.py: aiosqlite bare-connection CRUD for all 8 tables with WAL mode
- recurrence.py: RRULE expansion via dateutil.rrule (RFC 5545)
- 16 unit tests covering DB CRUD and RRULE edge cases (DST, UNTIL, range)
- Add python-dateutil>=2.9 to pyproject.toml
2026-06-23 21:30:39 +08:00
chiguyong 3337589395 fix(review): document-processing code review fixes — validation, tests, formatting
Deploy to Production / deploy (push) Waiting to run Details
- SkillConfig._validate_v2: validate fallback_strategies against
  ReWOOEngine.VALID_STRATEGIES (lazy import, #20)
- test_skill_config: +4 tests for fallback_strategies validation
- test_document_loader: +8 xlsx edge case tests (empty workbook,
  malformed bytes, column mismatch, row/cell truncation, multi-sheet,
  file size limit, None cells, #16)
- test_execution_modes: fix ReWOOEngine patch path (lazy import ->
  patch at source) + FakeReWOOEngine.execute return .output attribute
- config_driven: ruff formatting (quotes, blank lines after imports)
- project_rules: remove stale "known failing test" note (now passes)
2026-06-23 20:21:19 +08:00
chiguyong b9bb1b7cf1 docs: document skill/agent category split in AGENTS.md and CLAUDE.md
Deploy to Production / deploy (push) Waiting to run Details
Add skill category convention: agent_template (execution engines) vs
business_skill (domain skills), classified via _ENGINE_TEMPLATE_NAMES.
Update preset count 15 -> 16.
2026-06-23 19:51:05 +08:00
chiguyong 3d108dd08e fix(skills): P3 frontend polish for skill/agent category split
Deploy to Production / deploy (push) Waiting to run Details
- skills.ts: make category/agent_type/execution_mode/task_mode optional
  in ISkillInfo and ISkillDetail for backward compat during rollout
- SkillCard.vue: remove dead size="small" on a-tag, add title attr for
  a11y, add isEngine computed, CSS fallback cleanup, category fallback
  in class binding
- SkillsView.vue: fix a-empty condition to use grouped counts so orphan
  skills (category mismatch) don't render a blank page
- SkillsTab.vue: add type tag (引擎/技能) and category-based icon
  (thunderbolt for engine, appstore for business), remove size="small",
  add engine icon color variant
2026-06-23 19:41:54 +08:00
chiguyong a672dddc9a feat(skills): distinguish agent templates from business skills in UI
Deploy to Production / deploy (push) Waiting to run Details
The skills tab mixed generic execution-engine templates (react/direct/
rewoo/...) with business-domain skills (monitor/geo_optimizer/...) with
no visual or data distinction. Adds a derived `category` field to the
SkillInfo/SkillDetail API models and groups the frontend display.

Backend:
- SkillInfo/SkillDetail: add category (Literal), agent_type, execution_mode,
  task_mode fields
- _skill_to_info: derive category from explicit _ENGINE_TEMPLATE_NAMES set
  (not name suffix — trend_agent/deai_agent are business skills despite
  the _agent suffix)
- Simplify repetitive hasattr pattern with getattr

Frontend:
- ISkillInfo/ISkillDetail: add category + mode fields
- skills store: agentTemplates/businessSkills computed getters
  (businessSkills is defensive: anything not explicitly engine template)
- SkillsView: group into 执行引擎 / 业务技能 sections with counts
- SkillCard: type badge (引擎/技能), category-based icon, mode display,
  dark-mode-aware accent color

Tests:
- test_category_derived_from_name_suffix: verifies field exposure
- test_category_no_orphans: invariant — every skill has a valid category
- test_trend_agent_classified_as_business_skill: regression guard for
  the _agent suffix misclassification bug

Code review (ce-code-review): 2 P1 + 5 P2 findings applied.
2026-06-23 15:55:59 +08:00
chiguyong e600722378 merge: feat/document-processing — document generation, template filling, document reading (U1-U9)
Deploy to Production / deploy (push) Waiting to run Details
2026-06-23 15:05:11 +08:00
chiguyong 47f3bfecfc feat(documents): add document processing capability (U1-U9)
Implements end-to-end document generation, template filling, and reading:

- DocumentService: unified business layer for create/query/download
- Renderers: Word (Markdown->docx), Excel (Markdown/JSON->xlsx),
  PDF (Markdown->pdf with CJK font), Template (Jinja2 sandbox .docx fill)
- DocumentLoader: read PDF/Word/Excel/Markdown/HTML/text -> Document
- DocumentTool: Agent tool with action=create|read
- REST API: /api/v1/documents (create, upload-template, list, download)
- Frontend: DocumentPanel, DocumentCard, documents Pinia store,
  chat store tool_result detection
- Security: path traversal guard (Path.resolve + relative_to),
  SSTI guard (SandboxedEnvironment), API key auth, 50MB upload limit
- Bug fixes: template path traversal (400 not 500), TemplateRenderer
  lazy-load (no external registration dependency)
- Tests: 168 tests (unit + security + E2E F1/F2/F3 + bug hunt)
- Docs: README section 17, requirements + plan + test-plan docs

Requirements R1-R28 verified, F1-F3 user flows pass.
2026-06-23 15:05:01 +08:00
chiguyong bc424574c7 fix: Tauri reload, multi-conv blocking, skill install, UI polish
Deploy to Production / deploy (push) Waiting to run Details
1) Tauri reload login: main.ts beginStartup before mount + router guard await waitForStartup

2) Multi-conversation blocking: per-conversation Map/Set tracking

3) Skill install: npx --yes + SKILL.md support + path traversal validation

4) Markdown table rendering + 80ms streaming debounce

5) Agent execution UI: structured IStreamingStep

6) auth.py _ensure_db idempotent

Code review fixes: renderTimer cleanup, counter accumulation, memory leak, WS reconnect stale steps
2026-06-23 11:03:46 +08:00
chiguyong 7e0ef6d1ac merge: feat/admin-console — P0/P1 fixes from ce-code-review (U1-U7)
Deploy to Production / deploy (push) Waiting to run Details
2026-06-22 17:35:07 +08:00
chiguyong 4f261523c2 fix(review): U3 atomic file writes for YAML + .env + skill config
All config file writes now use the write-temp + fsync + os.replace
pattern (KTD-4) so a crash mid-write leaves the original file intact.

- Add src/agentkit/server/utils/atomic_write.py with write_text_atomic
- settings.py: _write_yaml_config and _write_env_var use atomic write
- skill_service.py: import_skill uses atomic write
- skill_service.py: update_skill_config uses atomic write + fcntl.flock
  around the read-modify-write cycle to serialize concurrent updates
- Add 11 unit tests covering happy path, crash safety, concurrency, errors
2026-06-22 17:03:27 +08:00
chiguyong 698a8fafba fix(review): U7 refresh token hash verification on whoami
The whoami route accepted rotated/old refresh tokens for cold-start
because it only checked session revocation status, not the token hash.
Now when token_type == "refresh", the route computes hash_token(token)
and compares it with the session's stored refresh_token_hash using
hmac.compare_digest (constant-time). Mismatch returns 401.

- Add SessionService.get_stored_refresh_hash(session_id) helper
- Add hash verification in whoami route (R9)
- Add TestWhoamiTokenHash with 5 integration tests
2026-06-22 16:55:20 +08:00
chiguyong 206b82740c fix(review): U5 DB migration — always run init_auth_db + busy_timeout 2026-06-22 16:40:30 +08:00
chiguyong 45b6752e0d fix(review): U4 WebSocket quota enforcement + gateway-layer hardening 2026-06-22 16:37:23 +08:00
chiguyong cd371e4155 fix(review): U2 quota semantics — monthly quota + multi-dept attribution + TOCTOU docs 2026-06-22 16:30:22 +08:00
chiguyong 278d76b381 fix(review): U6 frontend field alignment + CLI top-users field fix 2026-06-22 16:28:44 +08:00
chiguyong 00c8386939 fix(review): U1 Redis quota enforcement — key construction + fail-closed + degradation recovery + async 2026-06-22 16:22:33 +08:00
chiguyong abe2a66436 fix(review): CLI field names, Pydantic validation, exception chaining 2026-06-22 15:24:31 +08:00
chiguyong 3efdaafb5f docs: mark admin console plan as completed 2026-06-21 20:02:27 +08:00
chiguyong 5e977539c7 test(admin): U10 — E2E + security isolation + quota enforcement tests
23 integration tests across 3 files:
- test_e2e_admin_flow: 5 end-to-end lifecycle tests (department, user,
  LLM config, skill management, usage dashboard)
- test_security_isolation: 7 department isolation tests + non-admin 403
  tests (cross-dept skill/KB access, multi-dept union, admin sees all,
  removed user loses access, disabled dept, API key client)
- test_quota_enforcement: 10 quota tests (token/cost/whitelist limits,
  multi-dept strictest-wins, real gateway integration, usage recording)

418 admin tests pass, no regressions.
2026-06-21 19:57:49 +08:00
chiguyong e5a92427a4 feat(admin): U9 — frontend AdminLayout + 7 management pages
AdminLayout with sidebar nav + 7 admin views (dashboard, departments,
users, llm, skills, kb, usage). AdminApiClient extended with 40+
methods. Router restructured with nested admin routes. typecheck +
build pass.
2026-06-21 19:34:41 +08:00
chiguyong 2dd0091bda feat(admin): U8 — CLI admin command group
AdminHttpClient: sync HTTP client with JWT/API key auth, config file
support (~/.agentkit/admin_config.yaml), env var fallback.

35+ CLI commands across 7 groups: login, department (CRUD + bind/unbind
skill/KB + quotas), user (CRUD + reset-password + assign/remove dept),
llm (providers + api-key + fallbacks), skill (list/enable/disable/
import/reload), kb (documents CRUD + sync/rebuild), usage (summary/
timeseries/by-model/top-users/export).

All commands support --server-url, --token, --api-key, --json flags.
Rich table output by default, raw JSON with --json. Friendly error
handling for connection/auth/not-found/conflict errors.

64 new tests, 102 CLI tests pass, no regressions.
2026-06-21 18:56:14 +08:00
chiguyong 09feca3307 feat(admin): U7 — usage dashboard + quota enforcement
UsageRecord extended with user_id + department_id (backward compatible).
UsageStore Protocol extended: record() accepts user_id/department_id,
get_usage() accepts filters, new get_usage_by_user/department methods.
RedisUsageStore uses versioned keys (v2) for new records.

LLMGateway.chat()/chat_stream() accept user_id, department_ids, db_path.
Quota check before provider call: model whitelist + token limit + cost
limit (daily). Multi-department uses strictest-wins (any exceed → reject).
QuotaExceededError → 429 at route layer.

UsageService: summary, timeseries, by-model, top-users, export (CSV/JSON).
5 new admin endpoints under /admin/usage/*.

llm_gateway.py routes pass DepartmentContext + db_path to gateway,
catch QuotaExceededError → 429 (JSON for /chat, SSE error for /stream).

84 new tests. 441 admin+usage tests pass, no regressions.
2026-06-21 17:23:20 +08:00
chiguyong fd7f6816b8 feat(admin): U6 — Skill & KB management endpoints + department binding
SkillService: enable/disable (persisted in skill_states table, schema
v4), import from YAML (with path traversal + name validation), reload
from file, update config. GET /skills now filters disabled skills.

KbService: list/upload/delete documents with department_id binding.
Added department_id field to KnowledgeSource + UploadedDocument.
Department visibility: (bound to user depts) ∪ (global = None).

10 new admin endpoints: skill enable/disable/import/reload/update,
KB documents CRUD, source sync/rebuild. All guarded by _require_admin.

Implemented reload stub in skill_management.py (was no-op).

54 new tests (26 unit + 28 integration). Fixed 4 pre-existing lint
errors. 357 admin tests pass, no regressions.
2026-06-21 16:19:51 +08:00
chiguyong 980919fc95 feat(admin): U5 — LLM config admin endpoints + department quotas
QuotaService: set/get/list/delete quotas, check_quota (hard reject),
is_model_allowed. JSON-serialized limit_value, upsert with ON CONFLICT.

LlmConfigService: provider CRUD + set_api_key + fallback management.
fcntl.flock file lock prevents concurrent YAML writes. Reuses
settings.py helpers (_read_yaml_config, _write_yaml_config,
_write_env_var, _mask_api_key).

11 new admin endpoints: provider CRUD, api-key, fallback CRUD,
department quotas CRUD. All guarded by _require_admin.

93 new tests (30 quota unit + 32 llm-config unit + 31 integration).
2026-06-21 15:03:38 +08:00
chiguyong ad65f7a8d7 feat(admin): U1+U2+U4 — schema v3, department service, context filtering
U1: Bump _SCHEMA_VERSION to 3, add 5 department tables (departments,
user_departments, department_skill_bindings, department_kb_bindings,
department_quotas) + 5 ORM models + helpers.

U2: DepartmentService (12 async methods: CRUD + bind/unbind skill/KB +
count_users). Mount admin_router in app.py. 36 unit + 28 integration tests.

U4: DepartmentContext FastAPI dependency (per-route, admin bypasses
filtering). filter_skills_by_department / filter_kb_sources_by_department
helpers. Applied to GET /skills and GET /kb-management/* routes.
15 integration tests for department isolation.

Also includes brainstorm + plan docs. 108 new tests, all pass.
2026-06-21 15:03:27 +08:00
chiguyong 6dca9ba4f2 feat(admin): U3 — user CRUD + password reset + multi-department
Add create_user method to LocalAuthProvider (bcrypt hash + INSERT,
raises ValueError on duplicate username/email).

Add UserService with 9 async methods: create/list/get/update/delete
(soft)/reset_password/assign_department/remove_department/list_user_departments. reset_password revokes all sessions via SessionService.
delete_user is soft (is_active=0, row preserved).

Add 9 user endpoints to routes/admin.py: POST/GET/PATCH/DELETE users,
reset-password, assign/remove department, list departments. All
guarded by _require_admin.

Tests: 40 unit + 37 integration = 77 new tests. Full admin suite
170 tests pass, no regressions.
2026-06-21 13:45:42 +08:00