obl-engine / app /engine.py
Godswill-IoT's picture
Upload 12 files
8277290 verified
Raw
History Blame Contribute Delete
5.94 kB
import json
from datetime import datetime
from app.contracts import EngineRequest, EngineResponse, EngineError
from app.hf_client import HFClient
class OBLEngine:
def __init__(self):
self.client = HFClient()
async def process(self, request: EngineRequest) -> EngineResponse:
try:
action = request.action.lower()
if action == "create_outcome_contract":
return await self._create_outcome_contract(request)
elif action == "decompose_outcome":
return await self._decompose_outcome(request)
elif action == "generate_path":
return await self._generate_path(request)
elif action == "update_readiness":
return await self._update_readiness(request)
else:
raise ValueError(f"Unknown action: {action}")
except Exception as e:
return EngineResponse(
request_id=request.request_id,
ok=False,
status="error",
engine="obl-engine",
action=request.action,
error=EngineError(code="ENGINE_EXECUTION_ERROR", detail=str(e))
)
async def _create_outcome_contract(self, request: EngineRequest) -> EngineResponse:
outcome_text = request.input.text or "Not specified"
prompt = (
f"User Goal: {outcome_text}\n"
"Create a structured 'Outcome Contract' for this goal. It represents a verified result (job skill, exam pass, etc.). "
"Output JSON only with fields: "
"'outcome_statement', 'time_horizon', 'proof_criteria' (list of specific evidences), 'engagement_rules', 'pricing_model_type'."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
# Simple cleanup for JSON extraction
contract_data = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
contract_data = {"raw_output": response_text, "note": "Failed to parse JSON contract."}
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="obl-engine",
action="create_outcome_contract",
result={"contract_draft": contract_data}
)
async def _decompose_outcome(self, request: EngineRequest) -> EngineResponse:
contract = request.input.refs.get("contract", {})
prompt = (
f"Analyze this Outcome Contract: {json.dumps(contract)}\n"
"Decompose it into:\n"
"1. Skills (What they must do)\n"
"2. Proofs (How we verify it - exams, projects, simulations)\n"
"Output JSON with keys: 'skills' (list of objects with id, name), 'proofs' (list of objects with id, type, rubric)."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
decomposition = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
decomposition = {"raw_output": response_text}
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="obl-engine",
action="decompose_outcome",
result=decomposition
)
async def _generate_path(self, request: EngineRequest) -> EngineResponse:
skills = request.input.refs.get("skills", [])
proofs = request.input.refs.get("proofs", [])
prompt = (
f"Skills: {json.dumps(skills)}\nProofs: {json.dumps(proofs)}\n"
"Generate a 'shortest path' learning plan. Prioritize actions that lead directly to proofs. "
"Output JSON key 'plan' as a list of steps. Each step has: 'step_id', 'action' (Lesson/Practice/Sim/Teachback), 'linked_proof_id'."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
plan = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
plan = {"raw_output": response_text}
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="obl-engine",
action="generate_path",
result=plan
)
async def _update_readiness(self, request: EngineRequest) -> EngineResponse:
evidence = request.input.text # e.g., "Passed quiz with 90%"
current_readiness = request.input.refs.get("readiness_score", 0.0)
prompt = (
f"Current Readiness: {current_readiness}\n"
f"New Evidence: {evidence}\n"
"Estimate the new readiness score (0.0 to 1.0) and identify any risk flags. "
"Output JSON: 'new_readiness_score', 'risk_flags' (list)."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
update_data = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
update_data = {"new_readiness_score": current_readiness, "note": "Failed to parse update."}
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="obl-engine",
action="update_readiness",
result=update_data
)
engine = OBLEngine()