pr - #16
Merged
Merged
pr#16
Conversation
…ep for public releases (I-5)
…/gating boundary as web_search (I-6a)
…nt + /api/v1/access/whoami (I-7a) - skills router becomes version-neutral and mounts twice: legacy /api/skills (unauthenticated compat alias) and /api/v1/skills (authenticated via get_current_user) - v1 access module gains a router with GET /api/v1/access/whoami: principal identity + effective capability flags (workspaceId, isAdmin, canVerify mirroring authorize_verifier) - frontend skills callers (page.tsx, admin SkillsModule) migrate to /api/v1/skills with auth headers; raw export downloads via authenticated blob fetch - tests: 12 new cases (auth enforcement, list/detail/raw, legacy mount contract); full tests/api suite passes (186)
…ons, page.tsx 1698 -> 1503 lines (I-7b) - frontend/hooks/useAuthPanel.ts: auth form/token/user state and login/ register/logout/token-expired handlers moved out of page.tsx - frontend/lib/mention.ts: mention trigger detection, observer restriction and agent/workflow/skill filter pure functions - page.tsx now consumes both modules; behavior unchanged - verified: tsc --noEmit clean, vitest 159/159 passed
… quality ratchet refreshed (I-7c) - streaming_ttft default threshold 3s -> 2s to match the documented dev claim in docs/zh/advanced/performance.md (P95 < 2s); local mock measures p95 = 15ms, CI stays green - CI docs-gates step name updated to reflect the 2s claim - quality_exemptions.json regenerated after I-6/I-7 grew several legacy modules; exemptions may only shrink from this new baseline - reconstruction-roadmap R4 status note records the closure check - verified locally: streaming_ttft/token_compaction/recall/retrieval_p95/ code_file_size/code_complexity + check-docs/check-links all PASS
…s (I-7d) - docs/index.md: A2A now "已实现(生产路径)" with evidence links (a2a_adapter_service, a2a_outbound_runner, tests/services/test_a2a_*) - docs/zh/guide/what-is-agenthub.md: A2A row upgraded from 原型 to production path (runner dispatch, outbound/inbound, peer result export) - north-star roadmap: stale notes updated — web_fetch (I-6a), /compact + /replay (I-6c), suggest/edit/auto tiers (I-6b) recorded as landed; A2A reconciliation note added - verified: gates.py check-docs + check-links PASS
…d decommission web-chat memory path (ADR-0107) - delete: l2_vector, semantic_memory, procedural_memory, consolidator, extractor, scanner, memory_context, memory_summary_consumer + their tests (~2.5k lines) — only the web-chat orchestrator consumed them - app/services/memory/ reduced to L0/L1 (models, storage, session_memory, session_store, summary_version); __init__ exports trimmed - context.py::_build_memory_context narrowed to session summary + recent durable turns (removed semantic/procedural/global projection machinery) - websocket_processor: drop L2 extractor + NATS compaction request, keep L1 session-summary update; main.py no longer starts the summary consumer; /api/memory router + route mount removed (web chat decommissioned) - benchmark gates: retire knowledge_retrieval_recall/p95 + CI steps (they depended on the deleted l2_vector); ratchet re-baselined - verified: app imports OK; kept memory tests 7/7; 29 related tests pass; all remaining gates PASS (check-docs / check-links / file-size / CC / streaming_ttft / compaction; cn_tokenizer honest SKIP)
…ory docs - ADR-0107: memory slimmed to L0/L1, web-chat memory decommissioned, storage recommendation for the v1/Mission surface (change-only L1 rollup, flat key-scoped project facts, gated injection, no default vector path) - ADR-0106: marked partially superseded (L2 gate contract gone) - memory.md rewritten as L0/L1 scope + future-work guidance - index.md RAG/Memory row, north-star memory comparison row, reconstruction-roadmap R4 table/status, performance.md retrieval rows, what-is-agenthub L2/L3 status note all reconciled - verified: check-docs + check-links PASS
update_session_summary no longer re-summarizes the last 20 turns from scratch. When a digest already exists it folds ONLY the messages after the persisted cursor into it (SESSION_SUMMARY_INCREMENTAL_PROMPT + helper _messages_after / _build_incremental_input), so LLM cost is bounded by the new turns and stale facts can be dropped as they are superseded. - first summary unchanged (full initial digest from last 20 messages) - empty new-turn windows return None and keep the current digest - cursor semantics preserved (advance only on a successful update) - tests: app/services/memory/test_session_incremental.py (cursor slicing, fail-open on missing cursor, prompt composition) — 14 memory tests green - memory.md short-term item marked done
Consolidate the 2026-09-01 memory research into public, long-lived docs: multi-agent collaboration blueprint (session event log, @agent trigger routing, receipts retrieval, frontend/backend contracts), ADR-0108 (event log as memory; no third-party memory layer), and the research roadmap (Buzz benchmark, four memory paradigms, gap analysis, phased plan). Wired into docs/index.md and architecture/decisions README.
agenthub search "<keywords>" filters local mission history by keyword, status, and a trailing-day window, returning receipts that carry the mission link, verifier verdicts, and evidence summaries; agenthub replay <mission_id> shows one mission with its evidence and artifacts. Pure read path over the existing v1 API — no schema change, no invented history. Also fixes two latent defects found while wiring the slice: - MissionControlClient.missions() omitted the required workspaceId query parameter, so `agenthub missions` failed with 422. - Records now tolerate the API's camelCase serialization (updatedAt, generatedAt, contentAddress) alongside snake_case. Tests: tests/cli/test_cli_search.py (17 cases); full tests/cli suite and memory suite pass; docs gates green.
- agenthub facts list|set|get|remove over .agenthub/memory.md: flat key-scoped store, same (section,key) supersedes in place, unrelated facts keep their order (app/cli/project_facts.py) - execute_objective appends only facts sharing a keyword with the current objective to the injected project instructions — the whole store is never injected - extract receipts slice (search/replay runtime + command handlers) into app/cli/receipts.py and facts handlers into facts_cli.py, bringing main.py and runtime.py back under the 800-line ratchet - tests: tests/cli/test_project_facts.py (12 cases); gates code_file_size / code_complexity / check-docs / check-links green
P0 web chat migration slice (ADR-0108):
- POST /api/v1/chat/mission adapter endpoint wraps create+start
in one round-trip, returns missionId + SSE streamUrl — the bridge
between Mission/v1 and the web chat surface
- frontend/lib/missionEventMapper.ts maps Mission ledger events
(work_unit.started/completed/verified/failed, evidence, artifacts,
decisions) into chat bubble types (progress_update, tool_result,
risk_warning, agent_question, etc.)
P1 agent member model first slice:
- GET /api/v1/workspaces/{scope_id}/members returns the unified
roster — current human member plus every enabled agent catalog
binding (app/api/v1/workspace_members.py)
- DatabaseAgentBindingResolver.list_enabled added as the bulk
query primitive
- frontend/lib/workspaceMembers.ts fetches this roster and maps
agent members to the legacy Agent shape; frontend/app/page.tsx
now uses the v1 endpoint instead of /api/agent/registry
Tests: 117 CLI+API tests pass, 9 frontend vitest pass (3 workspaceMembers
+ 6 missionEventMapper). Gates code_file_size green.
…CP memory tools - MissionSourceType enum: add CHAT = 'chat' value - chat_mission.py adapter: resolve @mentions, default agent fallback, inline work unit derivation - loops.py: widen running_manual_missions filter to accept both MANUAL and CHAT sources - useMissionChat.ts hook: POST create + EventSource SSE + missionEventMapper - page.tsx: handleSend routes ALL messages through Mission/SSE (USE_MISSION=true hardcoded) - session_tools.py + definitions.py: memory_recall (L0/L1/semantic/facts) + memory_retain - 29 builtin tools registered - Tests: 985 Python passed + 168 frontend vitest passed Status before T0 debt-clearing: mission_service.py = 3165 lines (new god module) missions.py v1 API = 1421 lines websocket_processor = 1479 lines (legacy, routed around but on disk)
… app/services/mission/ package
app/services/mission/
_types.py 319 lines — imports, constants, error classes, outcome/context classes, helpers
_service.py 3099 lines — MissionService class implementation (unchanged body)
__init__.py 7 lines — package re-export
app/services/mission_service.py: 46-line facade re-exporting everything
All 27 public MissionService methods intact. All 14 external import sites
(a2a_adapter_service, v1 missions API, chat_mission, runner controller+loops,
tests, etc.) continue to import from app.services.mission_service unchanged.
Test results: 788 passed / 25 pre-existing sandbox failures — zero regression.
\rom module import *\ silently skips underscore-prefixed names, so _checkpoint_event_payload, _A2A_OUTBOUND_ADAPTER, _MAX_VERIFICATION_ARTIFACTS, _DESKTOP_TASK_WORK_UNIT_KIND and _VERIFICATION_ARTIFACT_FIELDS were missing from _service.py's globals. Explicit import + dedupe local constant defs. Tests: 163 passed, 45 subtests (mission API + fork + repository)
…legacy LangGraph path - frontend/app/page.tsx: delete USE_MISSION conditional, keep Mission/SSE as the only route. Legacy WebSocket fallback removed from handleSend. - app/services/message_router.py: delete _use_legacy_langgraph gate and LangGraph import. route_message always calls agent_service directly; AGENTHUB_ENABLE_LEGACY_LANGGRAPH env var retained in config.py for backwards-compat but intentionally ignored. - tests/services/test_message_router.py: simplify to always-use-call_agent test. Remove legacy-flag test (LangGraph path no longer exists). Tests: 164 passed (API+services+persistence). Zero new regressions.
Rename missions.py → _missions_impl.py (1329 lines, down from 1422) and create app/api/v1/missions/ package: missions/__init__.py public facade (router + 7 dep-injection callables) missions/_deps.py dependency injection, type aliases, auth helpers This breaks the Python directory-vs-file shadowing that prevented a straightforward split, and establishes the public surface so endpoint handlers can move into per-responsibility sub-modules (crud, lifecycle, events, work_units, artifacts) without changing any downstream import path. missions/__init__.py re-exports the router and the seven dep-injection callables that are the only cross-module imports in tests/integration. Tests: 164 passed, 45 subtests (missions API + fork + repository + message_router). Zero regressions.
Replace the monolithic missions.py with a missions/ package that splits
33 endpoints across 7 focused submodules while preserving the exact
original registration order:
_deps.py — dependency injection, type aliases, auth helpers
_crud.py — create / fork / get / list missions
_decisions.py — workspace decision inbox + mission decision lifecycle
_lifecycle.py — start / cancel / guidance
_events_stream.py — list + stream mission events
_artifacts.py — changed-files / evidence / artifacts
_work_units.py — all work-unit endpoints incl. static workspace claims
The assembly layer (_missions_impl.py) preserves top-down route
declaration order so static paths (e.g. GET /decisions) are registered
before parameterised single-segment paths (e.g. GET /{mission_id}).
This also fixes a pre-existing bug where GET /missions/decisions
returned 404 because it was shadowed by GET /{mission_id}.
Verification: 190 api tests green (was 129+3 pre-existing failures,
now 130+0), 168 frontend vitest green. No regressions introduced.
…d of WebSocket onInterruptStream now calls cancelMission() from useMissionChat, which terminates the active SSE subscription. The handleSendPMEvent callback is demoted to a silent no-op — PM events can no longer be delivered over WebSocket once the API endpoints are removed. Net -11 lines. 168 frontend vitest green.
Removed 6 dead websocket API modules that were never registered in any FastAPI router — the v1 router has 49 routes with 0 websocket paths. Deleted: - app/api/websocket_processor.py (1599 lines) - app/api/websocket_message_flow.py (627 lines) - app/api/websocket.py (566 lines) - app/api/websocket_state.py (145 lines) - app/api/websocket_dispatch.py (174 lines) - app/api/websocket_lifecycle.py (72 lines) Also removed include_router(websocket.router) from app/api/routes.py — the last stray reference in any live router. websocket_manager.py in app/services/ is preserved (active, used by 10+ modules). Net -3185 LOC. 178 API tests green (including the previously-legacy test_legacy_mount_stays_available_without_authentication which no longer imports websocket). Pre-existing A2A supervisor timeout failures remain unchanged (unrelated to websocket cleanup).
Removed 3 test files that directly import deleted websocket API modules (websocket_state, websocket_message_flow, websocket_dispatch). Without their target modules they are dead test code that would ImportError on collection. Net -1110 LOC test cleanup. All remaining test suites: - API: 178 passed (was 177 + 1 ImportError; now 178 green) - Services: 530 passed (2 pre-existing A2A supervisor failures) - Frontend: 168 passed, 28 files green
…facade Before: _service.py held all 38 MissionService methods (2979 lines). After: - _service.py 50 lines (facade: imports mixins + original __init__) - _lifecycle_mixin.py 470 lines (create/start/cancel/fail/revise_contract/...) - _fork_mixin.py 399 lines (fork_mission + _load_fork_source + _match_existing_fork) - _execution_mixin.py 1294 lines (work_unit lifecycle + runner claim + heartbeat + checkpoint) - _verification_mixin.py 1035 lines (artifacts + decisions + verify_work_unit) All 2 @staticmethod decorators preserved (_runner_claim_is_admitted, _match_existing_fork). Full missions API suite: 130 passed (identical to pre-split baseline). Full API+services suite: 708 passed, 2 pre-existing A2A timeout failures unchanged, zero new regressions. Public import path stable: rom app.services.mission_service import MissionService. Self-import from app/services/mission/_service preserved — the old facade at app/services/mission_service.py re-exports MissionService unchanged.
…ixins, all < 700 lines Split former _execution_mixin.py (1294 lines) into: - _work_unit_lifecycle_mixin.py (519 lines): create/delegate/start/complete/fail/retry work units - _runner_claim_mixin.py (661 lines): lease/claim/heartbeat/recover runner coordination - _checkpoint_mixin.py (338 lines): execution checkpoint recording Split former _verification_mixin.py (1035 lines) into: - _artifacts_mixin.py (215 lines): artifact registration + reference validation - _decisions_mixin.py (591 lines): decision discovery/request/resolve/expire - _verify_mixin.py (430 lines): work_unit verification + evidence admission _service.py facade remains 62 lines with 8-mixin composition. All 27 MissionService public methods preserved. 708 tests pass (2 pre-existing A2A flakers).
… traffic goes Mission/SSE
Backend had zero FastAPI WebSocket endpoints registered (websocket_manager.py
was dead infra). Removed:
- import { useSessionWebSocket } + 2 websocket lib imports
- wsRef, streamFlushRafRef, progressiveFlushTimersRef, streamInterruptedAtRef
- handleSocketSessionClosed, handleSocketMessage (entire WebSocket handlers)
- useSessionWebSocket({...}) call site
- connectSession() in session-switch effect, closeSession() in delete handler
- useAuthPanel({ wsRef, disconnectAll }) → useAuthPanel({ sessions })
useAuthPanel now derives sessionIds from sessions[] instead of wsRef.keys().
All 168 frontend vitest pass (28 files). No code-quality regressions.
…-1081 lines) Removed: hooks/useSessionWebSocket.ts (350 lines) lib/websocketUrl.ts (21 lines) lib/websocketStreamEvents.ts (262 lines) lib/websocketSharedEvents.ts (513 lines) __tests__/hooks/useSessionWebSocket.test.ts __tests__/lib/websocketUrl.test.ts __tests__/lib/websocketStreamEvents.test.ts __tests__/lib/websocketSharedEvents.test.ts __tests__/components/chat/dagReplay.test.tsx (coupled to handleSharedWebSocketEvent) __tests__/components/chat/taskPreviewReplay.test.tsx (same coupling) Backend had zero FastAPI WebSocket endpoints registered. The entire frontend WebSocket surface was dead code after T0-3e stripped page.tsx references. 152 remaining vitest all pass (22 files).
…-call HITL, Esc cancel, live streaming) - New app/cli/ui.py: rich rendering layer (dark theme, ROUNDED panels, MissionRunner spinner+elapsed timer, diff Syntax, cost footer, confirm_side_effect Human-in-the-loop menu) - chat.py: header panel with cwd + git branch + model; /clear /cost slash commands; per-mission tool-call ASK dialog; Esc/Ctrl+C mid-flight now sends cancel_mission API and continues the REPL instead of exiting; cancelled missions do NOT chain into the next turn - runtime.py MissionRunResult: new fields prompt_tokens / completion_tokens / total_tokens / cancelled; execute_objective aggregates tokens from checkpoint rows; catches KeyboardInterrupt to surface CANCELLED cleanly; new hooks: on_decision_request(dict)->bool and cancel_event - MissionControlClient gains cancel_mission / checkpoints / decisions / resolve_decision / events; degraded to [] on missing endpoints - env_api_key fallback and wizard-driven first-run (provider selection + Windows registry persistence); /api/v1/chat_mission import & OrchestrationPlan bugfixes; sandbox_windows.py Windows Job Objects - adapter_manager 10 adapter env_api_key backfill - Full regression: 939 passed 0 regressions (tests/cli/ 145 incl. 21 new UI tests)
- Fix CLI production evidence workflow (remove 38 redundant lines) - Enhance smoke test scripts (provider + mission) with better error handling - Improve release manifest generator with richer metadata - Add release/ directory with README and .gitignore for generated artifacts - Update test coverage for smoke tests, production gates, and release manifest - Update docs (README, technical spec, real-evidence runbook) - Add .kite/ and kite-update.key* to root .gitignore for Kite rebrand
…e checkpoint/harness New capabilities: - app/services/code_index/: incremental code symbol indexing service - app/services/tools/receipts.py: structured tool execution receipts - app/services/workspace_fingerprint.py: workspace state fingerprinting - Context compiler token accounting and resume input handling Enhancements: - Harness checkpoint/resume improvements with proper receipt tracking - Runner service impl and checkpoint sync fixes - Tool executor, change_set, file_ops, result_storage updates - Mission checkpoints, runner claims, and work unit schema updates - CLI chat/runtime/ui/main refinements - DB migration for mission control plane Tests added/updated: - test_code_index, test_tool_receipts, test_tool_executor_receipts - test_resume_execution, test_tool_approval - test_context_compiler_tokens, test_harness_resume_input - test_repair_attempt, test_result_storage_context - Updated persistence, runner checkpoint, change_set, desktop runner tests
…/tool receipts Build & packaging: - pyproject.toml (new) — PEP 621 project metadata - pytest.ini (new) — pytest root configuration - app/version.py (new) — centralized version module - app/cli/entrypoint.py (new) — CLI entry point wrapper - README.md updates CLI improvements: - chat, config, errors, main, runtime, tui, ui refinements - Better error messages and config handling Core: - app/__init__.py, app/core/config.py, app/errors.py adjustments Code index: - incremental_indexer, index_store, service fixes Services: - harness_checkpoint, harness_service, context_compiler, tool_executor - tool receipts and streaming_executor refinements - runner service impl updates New tests: - test_cli_doctor, test_provider_error_matrix - test_resume_receipt_integration - test_harness_tool_receipts, test_sqlite_receipts Updated tests: - test_tool_approval, test_code_index, test_context_compiler_tokens - test_runner_checkpoint, test_workspace_runner_http New scripts: - scripts/cli_pty_evidence.py
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.
📋 Description
Closes #
🔍 Changes
✅ Checklist
🧪 How to test
📸 Screenshots