# Orchestration Pseudocode This document provides pseudocode for the core runtime components of Dynavera. Source references point to the submitted repository. --- ## 1. Multi-Turn Orchestration Loop **Source:** `apps/onboarding/consumers/base.py:77–132` The `orchestrate` method is the central inference loop. It accumulates a message history, calls the GPU inference endpoint with MCP tool definitions attached, handles any tool calls the model requests, and only returns once the model produces a final text response (and the minimum-turn threshold has been met). ``` function ORCHESTRATE(message, config, min_turns, max_turns): messages ← [ {role: system, content: config.system_prompt}, {role: user, content: message} ] for turn = 1 to max_turns do emit THOUGHT status to WebSocket client response ← POST /v1/chat/completions { messages: messages, tools: MCP_ROUTER.get_tool_definitions(), tool_choice: "auto", max_tokens: resolved_max_tokens } ai_msg ← response.choices[0].message append ai_msg to messages if ai_msg contains tool_calls then for each call in ai_msg.tool_calls do emit TOOL_START {name, args} to client result ← MCP_ROUTER.handle(call.name, call.args) emit TOOL_RESULT {result} to client append {role: tool, name: call.name, content: result} to messages end for continue // re-enter loop with updated context else // model returned a text response content ← censor(ai_msg.content) if turn < min_turns then append force_reasoning_prompt to messages continue // force at least one reasoning pass end if return content end if end for return last_content // fallback if max_turns reached ``` **Key design points:** - Tool results are injected back into the message history before the next inference call, allowing the model to reason over retrieved evidence. - `min_turns` enforces at least one structured reasoning pass before returning, improving output quality on complex generation tasks. - All status events (`THOUGHT`, `TOOL_START`, `TOOL_RESULT`, `COMPLETED`) are streamed to the client over the WebSocket, making the reasoning process inspectable in the UI. --- ## 2. MCP Tool Dispatch **Source:** `apps/onboarding/mcp.py:42–127` The `MCPRouter` exposes a fixed set of approved tools to the model. Tool definitions are generated at class load time from method-level `@mcp_tool` decorator metadata. ``` function MCP_ROUTER.handle(tool_name, args): method ← tool_name_to_method_map[tool_name] if method is None then return {error: "Tool not found"} end if try return await method(args) catch Exception as e return {error: e.message} end try // search_knowledge (lines 78–127) function search_knowledge(args): query_vector ← POST /v1/embeddings {input: args.query} chunks ← SELECT content, metadata FROM KnowledgeChunk WHERE organization = role.organization AND (role = args.role_uuid OR role IS NULL) AND is_active = true ORDER BY CosineDistance(embedding, query_vector) ASC LIMIT 5 return [{content, source, relevance: 1 - distance} for chunk in chunks] // update_progress (lines 129–159) function update_progress(args): session ← OnboardingSession.get(uuid=args.session_uuid) if args.score → session.state.last_score ← args.score if args.completed → session.state.completed_modules ← append(args.completed_module) session.save() return {status: "success", new_state: session.state} ``` --- ## 3. Knowledge Ingestion Pipeline **Source:** `apps/knowledge/tasks.py:45–117` ``` task ingest_training_file(file_uuid): file ← TrainingFile.get(uuid=file_uuid) file.status ← "ingesting"; file.save() raw_text ← extract_text(file) // PDF / DOCX / TXT all_chunks ← [] for segment in split(raw_text, size=CHUNK_SIZE) do response ← POST /v1/semantic-chunk { text: segment, threshold: SEMANTIC_CHUNK_THRESHOLD } for (chunk_text, embedding) in zip(response.chunks, response.embeddings) do all_chunks.append(KnowledgeChunk { content: chunk_text, embedding: embedding, // 768-dim vector role: file.role, metadata: {source: file.file_name} }) end for end for new_chunks ← [c for c in all_chunks if c.hash not in existing_hashes] KnowledgeChunk.bulk_create(new_chunks) file.status ← "embedded"; file.save() trigger update_agent_prompts_from_file(file.role.uuid) ``` --- ## 4. Onboarding Generation Pipeline (CA → KA → AA) **Source:** `apps/onboarding/consumers/generate.py:34–124` ``` function run_pipeline(role): // Phase 1 — Curriculum Agent context ← search_knowledge(role, query=role.name + " responsibilities") topics ← ORCHESTRATE(curriculum_generation_prompt(role, context), CA_config) → parsed as JSON list of topic strings (max 15) // Phase 2 — Knowledge Agent (one pass per topic) full_structure ← [] for each topic in topics do hits ← search_knowledge(role, query=topic) content ← ORCHESTRATE(knowledge_generation_prompt(topic, hits), KA_config, min_turns=2, max_tokens=3500) full_structure.append({title: topic, body: content}) end for // Phase 3 — Assessment Agent quiz_fields ← ORCHESTRATE(quiz_generation_prompt(topics, module_briefs), AA_config) → sanitised and validated; fallback quiz generated if JSON invalid full_structure.append({title: "Final Assessment Quiz", fields: quiz_fields, meta: {pass_mark: 80}}) OnboardingFlow.save(role, full_structure) emit COMPLETED to client ``` **Grading strategy:** - Multiple-choice questions: deterministic string comparison against `correct_option` - Free-text / textarea responses: agent-graded by the AA at session completion - Per-question outcomes persisted in session state for audit and feedback rendering