Download workbench_grounded_theory/supervisor.py from Viske/Spjimr: direct link, hf CLI and curl.
- Browser
- Download file 2.45 kB
-
https://huggingface.co/spaces/Viske/Spjimr/resolve/main/workbench_grounded_theory/supervisor.py
- Command line
-
hf download hf://spaces/Viske/Spjimr/workbench_grounded_theory/supervisor.py
-
curl -L -o supervisor.py https://huggingface.co/spaces/Viske/Spjimr/resolve/main/workbench_grounded_theory/supervisor.py
2.45 kB
| # ============================================================================ | |
| # supervisor.py — routing node for the Grounded Theory workbench | |
| # ============================================================================ | |
| # | |
| # COMPLIANCE | |
| # ---------- | |
| # The supervisor's entire job is to let the LLM decide which node runs | |
| # next. This file used to have Python guards that overrode the LLM's | |
| # decision when it picked an out-of-order step. Those guards are gone. | |
| # The LLM decides. If it misroutes, the prompt gets fixed. | |
| # | |
| # There is no MAX_ITERATIONS check. LangGraph's own recursion_limit | |
| # (set in graph.run) is the single source of truth for loop termination. | |
| # ============================================================================ | |
| import providers | |
| from .prompts import SUPERVISOR_PROMPT | |
| def supervisor_node(state): | |
| iteration = state.get("iteration", 0) + 1 | |
| prompt = SUPERVISOR_PROMPT.format( | |
| user_message=state["user_message"], | |
| detection_done=state.get("detection_result") is not None, | |
| refinement_done=state.get("refinement_result") is not None, | |
| confirmation_done=state.get("confirmation_result") is not None, | |
| ) | |
| client = providers.get_llm_client(state["llm_provider"], state["llm_key"]) | |
| model_name = providers.get_llm_model(state["llm_provider"]) | |
| resp = client.chat.complete( | |
| model=model_name, | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.0, | |
| max_tokens=20, | |
| ) | |
| text = (resp.choices[0].message.content or "").strip().lower() | |
| # Parse the first matching keyword. If none match, action stays as | |
| # "respond" — a sensible default that means "we're done". | |
| keywords = {"detect": "detect", "refine": "refine", | |
| "confirm": "confirm", "respond": "respond"} | |
| action = next((v for k, v in keywords.items() if k in text), "respond") | |
| return { | |
| "next_action": action, | |
| "iteration": iteration, | |
| "steps": [{ | |
| "step": iteration, | |
| "node": "supervisor", | |
| "action": f"route -> {action}", | |
| "detail": text[:60], | |
| }], | |
| } | |
| def route_from_supervisor(state): | |
| """Conditional edge function. Maps action keyword to node name.""" | |
| mapping = { | |
| "detect": "pattern_detection", | |
| "refine": "pattern_refinement", | |
| "confirm": "pattern_confirmation", | |
| } | |
| return mapping.get(state["next_action"], "respond") | |