File size: 12,440 Bytes
363cda9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# ***MVP version #2***
---
## HR-Triggered Autonomous Workflow Concept
The system is designed to operate **autonomously** while still allowing HR to initiate workflows and request status insights.
This ensures maximum automation without losing control or clarity in the process.
---
### **HR Interaction Trigger**
When HR opens the UI, they can interact with the supervisor agent by asking questions such as:
> **“Hey recruitment agent, what is the current status quo? Any new applicants? How many have passed CV screening?”**
The supervisor agent then:
1. Queries the database using predefined tools
2. Generates a clear, human-friendly status report
3. Waits for HR instructions on how to proceed
HR can then issue high-level commands like:
- **“Process all new applicants.”**
- **“Do not process new applicants further — notify them instead.”**
- **“Continue processing only applicants who already passed screening.”**
---
### **Supervisor Executes Fully Autonomous Actions**
Once HR gives the high-level command, the supervisor performs all actions autonomously:
- **Process new applicants**
- Parse CVs
- Run CV screening
- Update DB
- Notify or proceed depending on results
- **Process screened applicants further**
- Notify candidate
- Request available time slots
- Match HR availability
- Schedule interview
- Send confirmation emails
---
### **Concurrency and Isolation**
To avoid mixing contexts across candidates:
- **Only one supervisor agent instance runs at a time**
- Supervisor processes candidates **sequentially**
- Each candidate is handled **individually and deterministically**
This avoids:
- Context bleed
- Duplicate actions
- Race conditions
- Mixed reasoning across candidates
---
### **Per-Candidate Deterministic State Machine**
Each candidate has a small state object:
```json
{
"candidate_id": 123,
"state": "cv_uploaded",
"checklist_path": "users/123/checklist.md"
}
```
This keeps the workflow predictable, restartable, and isolated.
---
### ***Per-Candidate Checklist File***
Each candidate has a personal Markdown checklist:
```text
# Candidate Checklist — ID 123
- [x] CV uploaded
- [x] CV parsed and stored
- [x] CV screening started
- [x] CV screening completed
- [ ] Screening results notified to candidate
- [ ] Asked candidate for available time slots
- [ ] Received candidate availability
- [ ] Checked HR availability
- [ ] Scheduled interview
- [ ] Final confirmation email sent
```
The supervisor uses this checklist to determine the next atomic action.
It loads only this candidate’s context, performs exactly one update, writes back, and moves on.
---
## **Hybrid Progress Tracking — DB Status + Checklist**
The HR agent maintains two synchronized layers of workflow state:
- **Database `status` field:**
Captures the **coarse-grained milestone** in the candidate’s lifecycle
(e.g., `applied`, `cv_screened`, `interview_scheduled`, `decision_made`).
→ This is the **authoritative system state** used for HR dashboards, analytics, and reporting.
- **Per-candidate Markdown checklist:**
Tracks **fine-grained atomic actions** that occur within each milestone
(e.g., CV parsed, CV screened, email sent, candidate replied).
→ This serves as the **agent’s operational log**, enabling deterministic reasoning, auditing, and safe restarts.
---
### **Checklist and Milestone Boundaries**
The **checklist** is composed of multiple **substeps**, each representing one small, deterministic action.
When all substeps belonging to a stage are completed, the system reaches a **milestone boundary**.
That boundary marks a safe point to update the candidate’s `status` field in the database.
| Milestone (`status` in DB) | Meaning | Checklist Substeps Leading to Boundary |
|-----------------------------|----------|---------------------------------------|
| `applied` | Candidate record created | `[x] CV uploaded`, `[x] CV parsed` |
| `cv_screened` | Screening phase finished | `[x] Screening started`, `[x] Screening completed`, `[x] Result stored` |
| `interview_scheduled` | Interview arranged | `[x] Candidate notified`, `[x] Availability received`, `[x] Interview scheduled` |
| `decision_made` | Final decision delivered | `[x] Interview completed`, `[x] Decision logged`, `[x] Notification email sent` |
---
### **Sync Rule**
1. After **each atomic substep**, the supervisor updates the checklist file.
2. When a **milestone boundary** is reached (all substeps for a phase checked off),
the supervisor updates the corresponding `status` field in the database.
3. The checklist remains the **fine-grained operational truth**,
while the database holds the **coarse-grained canonical truth**.
---
### **Summary**
- **Checklist = micro-level progress tracker** (agent reasoning + recovery)
- **Milestone boundaries = transition triggers** (define when to sync with DB)
- **Database `status` = macro-level lifecycle state** (system-wide reference)
This hybrid approach combines **LLM-friendly transparency** with **system-level consistency**, ensuring the agent can reason, recover, and scale safely.
---
### ***Result***
This approach provides:
- High autonomy
- Strong safety boundaries
- No context mixing
- Clear state tracking
- Reliable execution
- HR keeps high-level control
- LLM handles reasoning, routing, and next steps autonomously
This structure is scalable, maintainable, and production-friendly while still pushing agent autonomy very far.
## ⚡ ***Handling Everything Concurrently — The Async Supervisor Layer***
---
`The system must support concurrent processing of multiple candidate groups, each representing a different stage in the application pipeline (e.g., CV screening, voice screening, decision). Within each group, it should be able to process batches of candidates simultaneously while preserving per-candidate isolation and state consistency.`
### **Thread-Based Per-Candidate Isolation For the Rescue**
To ensure deterministic, fault-tolerant, and concurrent execution, the system leverages **LangGraph thread IDs** for per-candidate isolation:
1. **Supervisor Delegation**
The Supervisor Agent queries all candidates, groups them by their current `status` (e.g., CV screening, voice screening, decision), and passes the **list of candidate IDs** to the appropriate subagent tool.
Each subagent handles its own data loading, ensuring the Supervisor remains lightweight and purely orchestration-focused.
2. **Subagent Execution (Thread-per-Candidate)**
Inside each subagent (e.g., `screen_cv`), the system iterates over all received candidate IDs.
For each candidate:
- The **candidate ID serves as the `thread_id`**, providing a unique persistent context in LangGraph.
- The subagent loads candidate data from the database (CV path, JD path, etc.).
- The CV or voice screening logic runs **within that thread’s context**.
- On completion, the results are written back to the database, and the per-candidate checklist and state are updated.
3. **Parallel and Safe Processing**
Subagents can process multiple candidates concurrently by spawning asynchronous executions per `thread_id`.
Each candidate’s context remains isolated, preventing race conditions or context mixing.
**Result:**
- Supervisor coordinates and dispatches candidate groups
- Subagents handle per-candidate logic using thread-based persistence
- Each candidate’s run is self-contained, recoverable, and writes its final results back to the database
> **Note:**
> During a “Process All” operation, the Supervisor Agent executes **multiple reasoning loops**, invoking each subagent tool in sequence (e.g., `screen_cv`, `voice_screening`, `schedule_hr_interview`).
> After each tool call, it observes the result, reasons about the next step, and continues until all candidate groups are processed.
Latest chat: https://chatgpt.com/share/6920d318-3f64-8012-8fca-b17316093131
---
> below mst be adapted based on section above:
...
```mermaid
flowchart TD
HR_UI[UI: HR opens dashboard<br/>and requests candidate status]
--> REPORT[System returns report<br/>showing new and screened candidates]
REPORT --> PARALLEL[Async Supervisor<br/>launches concurrent group tasks]
%% --- New candidate path ---
PARALLEL --> NEW_FLOW[Process new candidates<br/>CV screening pipeline]
NEW_FLOW --> A[Delegate screening to subagent]
A --> B[Subagent screens CV]
B --> C[Write screening results to DB]
C --> D[Supervisor receives results]
D --> E{Did candidate pass screening?}
E -- No --> REJECT[Notify candidate and HR<br/>application rejected]
E -- Yes --> PASSED[Notify candidate and HR<br/>passed screening]
%% --- Screened candidate path ---
PARALLEL --> SCREENED_FLOW[Process screened candidates<br/>interview scheduling pipeline]
SCREENED_FLOW --> I[Request candidate time slots]
I --> J[Check HR calendar availability]
J --> K[Schedule interview]
K --> L[Notify HR and candidate<br/>interview confirmed]
```
To support concurrent processing across groups and candidates, the supervisor now operates as an asynchronous orchestrator.
It remains a single agent context — responsible for reasoning, reporting, and orchestration — but leverages asyncio to execute multiple workflows concurrently.
This allows the system to:
- Process multiple groups (e.g., new vs. screened candidates) in parallel
- Process multiple candidates per group concurrently
- Maintain isolation and determinism per candidate through separate state/checklist files
---
Conceptual Overview
1. HR issues a high-level command (e.g., “Process all candidates”).
2. The supervisor queries the database and identifies candidate groups.
3. It launches async tasks for each group simultaneously.
4. Within each group, candidates are processed concurrently — each running the deterministic checklist logic described above.
5. The supervisor awaits completion of all group tasks and reports progress and results.
This preserves:
- ✅ Single supervisor reasoning context
- ✅ Concurrent group + per-candidate execution
- ✅ Isolated per-candidate state and file I/O
- ✅ High throughput without context bleed
---
***Conceptual Async Code Example***
```python
import asyncio
from typing import List
# --- Candidate-level deterministic flow ---
async def process_candidate(candidate):
"""Execute the per-candidate checklist and state transitions."""
state = await load_candidate_state(candidate.id)
if state == "cv_uploaded":
await parse_and_screen_cv(candidate)
elif state == "screened":
await schedule_interview(candidate)
# ... additional states here
await save_candidate_state(candidate.id, state)
print(f"✅ Candidate {candidate.id} processed ({state})")
# --- Group-level concurrent handler ---
async def process_group(candidates: List, group_name: str):
"""Handle all candidates in one group concurrently."""
print(f"⚙️ Processing group: {group_name} ({len(candidates)} candidates)")
tasks = [process_candidate(c) for c in candidates]
await asyncio.gather(*tasks)
print(f"✅ Group {group_name} completed")
# --- Main supervisor orchestration ---
async def supervisor_run():
"""Supervisor orchestrates all concurrent candidate workflows."""
print("🧠 Supervisor initialized")
# Query database and classify candidates
report = await get_candidate_report()
new_candidates = report["new"]
screened_candidates = report["screened"]
# Launch group workflows concurrently
await asyncio.gather(
process_group(new_candidates, "new_candidates"),
process_group(screened_candidates, "screened_candidates")
)
print("🎯 All candidate groups processed successfully")
# --- Entry point ---
if __name__ == "__main__":
asyncio.run(supervisor_run())
```
---
***Key Properties***
- **Async orchestration, single agent:** The supervisor coordinates all tasks without duplicating reasoning contexts.
- **Per-candidate determinism:** Each checklist/state file is loaded, updated, and written atomically.
- **Parallel group execution:** New and screened candidates can be processed simultaneously.
- **Scalability path:** The same async structure can later integrate with LangGraph’s parallel nodes or distributed queues. |