Commit Graph

3 Commits

Author SHA1 Message Date
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