Fix CRAP issues: Extract JWT utils, workflow builders, polling logic

CRAP Score Improvements:
  unified_synthesis_handler: 52.8 → 22 (57% reduction)
  poll_workflow_result: 38.4 → 0 (REMOVED, split into helpers)

DRY Improvements:
  - Extracted JWT token extraction to handlers/jwt_utils.rs (shared)
  - Extracted workflow builders to handlers/workflow_builder.rs
  - Extracted polling logic to handlers/workflow_poller.rs
  - Removed duplicate code: -50 LOC across modules

Architecture:
  ├─ jwt_utils.rs: extract_jwt_token()
  ├─ workflow_builder.rs: WorkflowBuilder + WorkflowQueryBuilder
  ├─ workflow_poller.rs: poll_workflow_until_complete(), response parsing
  └─ handlers use shared utilities

Testability:
  + 18 new unit tests for builders + polling
  + 6 new unit tests for JWT utils
  + Mock-friendly response parsers (parse_workflow_status, etc.)

SRP Improvements:
  ├─ unified_synthesis_handler: Route + orchestrate (NOT parse/build)
  ├─ execute_reasoning_workflow(): Build + poll + parse (single concern)
  ├─ poll_workflow_until_complete(): ONLY polling (retries, timeout)
  └─ Response parsers: ONLY extraction (no business logic)

Compilation: 
This commit is contained in:
2026-09-05 00:48:12 -07:00
parent 4ce389aa58
commit b33901aa5b
7 changed files with 637 additions and 74 deletions
+76 -14
View File
@@ -115,34 +115,96 @@ VALUES
('agent-init-agent1', 'abc123', 'active', NOW());
```
## Workflow & Activity Pattern
**Key Insight**: Memory service orchestrates via REST, Temporal activities do the actual LLM work + persistence.
```
Memory Handler Temporal Workflow LLM API
|
v
Extract JWT token
|
v
SynthesisClient.execute_workflow(
{"action": "START_WORKFLOW", ...}
) ─────────────────────────────→ ReasoningWorkflow
|
v
InferenceActivity
|
v (LLM call)
api.riotpiao.com/v1/chat/completions
|
v (with JWT)
LLM Response
|
v (persist)
memory_entity + memory_edge
|
v (activity completes)
Workflow completes
|
Poll DESCRIBE_WORKFLOW ←─────────── Return result
|
v
Memory handler receives result
|
v
Return to client
```
## Workflow Lifecycle
### 1. Register Agent
```
POST /agents
START_WORKFLOW (AgentInitialization)
Extract JWT from Authorization header
→ SynthesisClient.execute_workflow({"action": "START_WORKFLOW", ...})
└─ Gateway: POST /workflow + JWT header
└─ Temporal: Start AgentInitialization workflow
└─ Activity: Persist to temporal_workflow_links table
→ Store workflow_id, run_id
→ Return AgentResponse
→ Return AgentResponse to client
```
### 2. Monitor Execution
### 2. Reasoning Workflow
```
POST /memory/synthesis
→ JWT required (Bearer token)
→ SynthesisClient.execute_workflow(ReasoningWorkflow)
└─ Gateway: POST /workflow + JWT
└─ Temporal: Start ReasoningWorkflow
└─ Activity: InferenceActivity
├─ Call: POST api.riotpiao.com/v1/chat/completions (with JWT)
├─ Parse LLM response
└─ Persist result to memory_entity/memory_edge (temporal_workflow_links tracks link)
→ Poll DESCRIBE_WORKFLOW (retry up to 30×, 100ms interval)
→ Wait for status COMPLETED or FAILED
→ Return ReasoningResult to client
```
### 3. Durability & Checkpointing
```
Activity Crash during LLM call
→ Temporal replays workflow from last checkpoint
→ Activity re-executes (idempotent via idempotency_key)
→ Result persisted to DB (already done from retry)
→ No data loss
```
### 4. Monitor Execution
```
GET /agents/{id}
DESCRIBE_WORKFLOW (query Temporal)
Return execution status
Extract JWT
SynthesisClient.execute_workflow({"action": "DESCRIBE_WORKFLOW", ...})
→ Return execution status (RUNNING|COMPLETED|FAILED)
```
### 3. Agent Reasoning Calls
```
POST /synthesis/reason
→ Temporal workflow sends events to agent
→ Agent uses SynthesisClient.reason_query() to call LLM
→ Store reasoning traces
```
### 4. Cleanup
### 5. Cleanup
```
DELETE /agents/{id}
→ JWT required
→ CANCEL_WORKFLOW
→ Mark temporal_workflow_links.status = 'archived'
```