"""Profile-driven Glas gateway. The gateway resolves a versioned harness profile before creating a sandbox. There is deliberately no default rein or model in governed execution. """ from __future__ import annotations import time import uuid from datetime import UTC, datetime from sandboxer.core.manager import SandboxManager from sandboxer.models import Consumer, SandboxCreateRequest from glas_harness import hub from glas_harness.contract import ( CONTRACT_VERSION, ExecutionEvidence, ExecutionRequest, ExecutionSummary, GatewayResult, Rein, SandboxHandle, ToolCall, ToolResult, ) from glas_harness.profiles import ProfileCatalog def _now() -> str: return datetime.now(UTC).isoformat() def _request_refs(request: ExecutionRequest) -> dict: refs = { "assignment_ref": request.assignment_ref, "role_ref": request.role_ref, "duty_ref": request.duty_ref, "goal_refs": request.goal_refs, "resource_envelope_refs": request.resource_envelope_refs, "expected_output": request.expected_output, } return {key: value for key, value in refs.items() if value not in (None, [], "")} def run_execution( request: ExecutionRequest, *, catalog: ProfileCatalog | None = None, rein: Rein | None = None, manager: SandboxManager | None = None, ) -> GatewayResult: """Resolve and run one request, returning evidence for every outcome.""" request_id = request.request_id or str(uuid.uuid4()) started_at = _now() started = time.monotonic() catalog = catalog or ProfileCatalog() refs = _request_refs(request) profile = None descriptor = None sandbox_id: str | None = None tool_result: ToolResult | None = None summary: ExecutionSummary | None = None outcome = "failed" failure_stage = None error: str | None = None try: profile, descriptor = catalog.resolve(request.harness_profile_ref) selected_rein = rein or catalog.build_rein(profile, descriptor) except Exception as exc: outcome = "refused" failure_stage = "resolution" error = str(exc) result = _build_result( request=request, request_id=request_id, started_at=started_at, started=started, outcome=outcome, failure_stage=failure_stage, error=error, profile=profile, descriptor=descriptor, sandbox_id=None, tool_result=None, summary=None, refs=refs, ) _report(request, result) return result manager = manager or SandboxManager() status = None try: try: status = manager.create( SandboxCreateRequest( profile=profile.sandbox_profile, inputs={"repo": request.repo}, consumer=Consumer(actor=request.actor, project=request.project), ttl=None, ) ) sandbox_id = status.sandbox_id except Exception as exc: failure_stage = "sandbox_create" error = str(exc) raise reachability = ( status.reachability.model_dump(mode="json", exclude_none=True) if status.reachability else {} ) sandbox = SandboxHandle( sandbox_id=status.sandbox_id, host=status.host or "", reachability=reachability, ) try: session = selected_rein.start_session( profile, { "title": request.title, "description": request.description, "target_repo": request.repo, "request_id": request_id, }, sandbox, ) except Exception as exc: failure_stage = "session_start" error = str(exc) raise try: tool_result = selected_rein.dispatch_tool( session, ToolCall(name="run_task", actor=request.actor) ) except Exception as exc: failure_stage = "execution" error = str(exc) raise try: summary = selected_rein.end_session(session) except Exception as exc: failure_stage = "session_end" error = str(exc) raise if tool_result.ok and summary.outcome == "succeeded": outcome = "succeeded" else: outcome = summary.outcome if summary.outcome in {"failed", "refused"} else "failed" failure_stage = "execution" error = tool_result.error or summary.reason or "rein reported unsuccessful execution" except Exception: # The exact error/stage is captured above. All paths still tear down and # return normalized evidence rather than leaking a provider exception. pass finally: if status is not None: try: manager.destroy(status.sandbox_id) except Exception as exc: if outcome == "succeeded" or not error: outcome = "failed" failure_stage = "teardown" error = str(exc) result = _build_result( request=request, request_id=request_id, started_at=started_at, started=started, outcome=outcome, failure_stage=failure_stage, error=error, profile=profile, descriptor=descriptor, sandbox_id=sandbox_id, tool_result=tool_result, summary=summary, refs=refs, ) _report(request, result) return result def run_task_through_rein( *, harness_profile: str, repo: str, title: str, description: str, rein: Rein | None = None, actor: str = "agt", project: str = "glas-harness", manager: SandboxManager | None = None, catalog: ProfileCatalog | None = None, report_to_hub: bool = True, ) -> dict: """Compatibility-shaped wrapper around the versioned execution request. It intentionally requires a harness profile. Direct rein injection is retained only as a library/test seam and never selects a default backend. """ result = run_execution( ExecutionRequest( harness_profile_ref=harness_profile, repo=repo, title=title, description=description, actor=actor, project=project, report_to_hub=report_to_hub, ), catalog=catalog, rein=rein, manager=manager, ) return result.model_dump(mode="json") def _build_result( *, request: ExecutionRequest, request_id: str, started_at: str, started: float, outcome: str, failure_stage: str | None, error: str | None, profile, descriptor, sandbox_id: str | None, tool_result: ToolResult | None, summary: ExecutionSummary | None, refs: dict, ) -> GatewayResult: duration = max(0.0, time.monotonic() - started) resolved_model = ( (summary.resolved_model if summary else None) or (tool_result.resolved_model if tool_result else None) or (profile.model.model if profile else None) ) tokens_spent = ( summary.tokens_spent if summary and summary.tokens_spent is not None else tool_result.tokens_spent if tool_result else None ) execution_duration = ( summary.duration_s if summary and summary.duration_s is not None else tool_result.duration_s if tool_result else None ) evidence_error = error if failure_stage == "resolution" else ( f"{failure_stage} failed; inspect direct caller error" if error and failure_stage else None ) evidence = ExecutionEvidence( request_id=request_id, correlation_id=request.correlation_id, actor=request.actor, project=request.project, target_repo=request.repo, contract_version=CONTRACT_VERSION, profile_ref=str(profile.ref) if profile else None, rein_id=descriptor.id if descriptor else None, rein_version=descriptor.version if descriptor else None, model_route=profile.model.route if profile else None, resolved_model=resolved_model, sandbox_profile=profile.sandbox_profile if profile else None, sandbox_id=sandbox_id, tool_profile=profile.tool_profile if profile else None, outcome=outcome, failure_stage=failure_stage, error=evidence_error, started_at=started_at, finished_at=_now(), duration_s=execution_duration if execution_duration is not None else duration, tokens_spent=tokens_spent, token_budget=profile.limits.budget_tokens if profile else None, commit_sha=summary.commit_sha if summary else None, artifacts=summary.artifacts if summary else [], tool_events_count=len(tool_result.events) if tool_result else 0, tool_events_completeness=( tool_result.events_completeness if tool_result else "unavailable" ), refs=refs, ) return GatewayResult( ok=outcome == "succeeded", evidence=evidence, tool_output=tool_result.output if tool_result else "", tool_error=error or (tool_result.error if tool_result else None), ) def _report(request: ExecutionRequest, result: GatewayResult) -> None: if not request.report_to_hub: return evidence = result.evidence.model_dump(mode="json", exclude_none=True) hub.post_progress_event( summary=( f"gateway run: {request.title} " f"({'ok' if result.ok else result.evidence.outcome})" ), event_type="gateway_run", detail=evidence, )