Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions SourceCode/configs/hardware_profiles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"default_profile": "8gb_vram_16gb_ram",
"profiles": {
"8gb_vram_16gb_ram": {
"name": "8gb_vram_16gb_ram",
"display_name": "Default: 8GB VRAM / 16GB RAM",
"description": "Conservative default local profile.",
"hardware": {
"system_ram_gb": 16,
"gpu_backend": "generic",
"gpu_vram_gb": 8,
"unified_memory": false
},
"scheduler": {
"max_context_tokens": 4096,
"warning_context_tokens": 4096,
"max_stage_context_tokens": 1800,
"max_parallel_models": 1,
"max_active_model_calls": 1,
"on_deck_depth": 1,
"warm_depth": 1,
"allow_neural_prefetch": true
},
"inference": {
"preferred_backends": ["ollama", "llama.cpp"],
"default_keep_alive": "10m",
"heavy_keep_alive": "0",
"release_heavy_after_call": true,
"max_loaded_models": 1
},
"model_policy": {
"normal_max_b": 9,
"heavy_max_b": 14,
"premium_min_b": 24,
"allow_premium": false,
"premium_requires_manual": true,
"allow_14b_with_warning": true,
"reject_heavier_fallbacks": false
},
"lane_caps": {},
"validation": {
"startup_mode": "warn",
"strict_mode_available": true,
"warn_on_missing_models": true,
"warn_on_unreachable_backends": true,
"warn_on_context_over_cap": true,
"warn_on_parallelism_over_cap": true,
"warn_on_premium_auto_escalation": true
}
}
}
}
17 changes: 15 additions & 2 deletions SourceCode/core/kernel_commands/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
from cag.memory_store import CAGMemoryStore
from orchestrator.main import OathweaverOrchestrator
from orchestrator.pipelines import replay_turn
from shared_tools.hardware_profiles import (
hardware_profile_summary,
hardware_profile_to_scheduler,
resolve_active_hardware_profile,
)


class KernelCommandService:
Expand Down Expand Up @@ -226,11 +231,19 @@ def benchmark_workflow_eval(
return evaluator.evaluate_run(run_id=target_run, hardware_profile_name=hardware_profile)

def apply_hardware_profile(self, *, profile_name: str = "8gb_vram_16gb_ram") -> dict[str, Any]:
active = resolve_active_hardware_profile(self.repo_root, profile_name)
summary = hardware_profile_summary(active)
if hasattr(self.orchestrator, "resource_budget_manager"):
self.orchestrator.resource_budget_manager.profile = hardware_profile_to_scheduler(active)
if hasattr(self.orchestrator, "hardware_profile"):
self.orchestrator.hardware_profile = active
if not summary.get("resolution_warnings"):
return {"ok": True, "profile": summary}

profile = profile_by_name(profile_name)
# Phase-12 guarantee: scheduler and context budget honor benchmark profile.
if hasattr(self.orchestrator, "resource_budget_manager"):
self.orchestrator.resource_budget_manager.profile = profile.to_scheduler_profile()
return {"ok": True, "profile": profile.as_dict()}
return {"ok": True, "profile": profile.as_dict(), "warnings": summary.get("resolution_warnings", [])}

def stage_resume(
self,
Expand Down
16 changes: 12 additions & 4 deletions SourceCode/orchestrator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
from shared_tools.domain_reputation import DomainReputation
from shared_tools.feedback_learning import ORIGIN_REFLECTION
from shared_tools.handoff_queue import HandoffQueue
from shared_tools.hardware_profiles import (
hardware_profile_summary,
hardware_profile_to_scheduler,
resolve_active_hardware_profile,
)
from shared_tools.model_routing import load_model_routing, lane_model_config
from shared_tools.inference_router import InferenceRouter
from shared_tools.web_research import build_web_progress_payload
Expand Down Expand Up @@ -266,7 +271,10 @@ def __init__(self, repo_root: Path) -> None:
self.model_runtime = build_model_runtime(repo_root)
self.context_pack_store = ContextPackStore(repo_root)
self.context_compiler = ContextCompiler(context_pack_store=self.context_pack_store)
self.resource_budget_manager = ResourceBudgetManager()
self.hardware_profile = resolve_active_hardware_profile(repo_root)
self.resource_budget_manager = ResourceBudgetManager(
profile=hardware_profile_to_scheduler(self.hardware_profile)
)
self.specialist_registry = SpecialistRegistry()
self.bench_manager = BenchManager(repo_root)
self.on_deck_runtime = OnDeckRuntime(
Expand Down Expand Up @@ -685,7 +693,7 @@ def _execute_pipeline_turn(
"mode": mode,
"history": list(history or []),
"hardware_token_budget": adaptive_stage_budget,
"hardware_profile": self.resource_budget_manager.profile.as_dict(),
"hardware_profile": hardware_profile_summary(self.hardware_profile),
}
scratch: dict[str, Any] = {
"web_note": "",
Expand Down Expand Up @@ -1167,7 +1175,7 @@ def _on_deck_planner(
"stage_outputs": dict(stage_outputs),
"stage_audits": dict(stage_audits),
"stage_timings_ms": dict(stage_timings_ms),
"hardware_profile": self.resource_budget_manager.profile.as_dict(),
"hardware_profile": hardware_profile_summary(self.hardware_profile),
"promoted_memory_ids": list(promoted_memory_ids),
"started_at": started_at,
"finished_at": finished_at,
Expand Down Expand Up @@ -1267,7 +1275,7 @@ def _on_deck_planner(
stage_outputs=stage_outputs,
stage_audits=stage_audits,
stage_timings_ms=stage_timings_ms,
hardware_profile=self.resource_budget_manager.profile.as_dict(),
hardware_profile=hardware_profile_summary(self.hardware_profile),
promoted_memory_ids=promoted_memory_ids,
started_at=started_at,
finished_at=finished_at,
Expand Down
212 changes: 212 additions & 0 deletions SourceCode/shared_tools/hardware_profiles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
from __future__ import annotations

import json
import os
from copy import deepcopy
from pathlib import Path
from typing import Any

from scheduler.resource_budget import DEFAULT_PROFILE, HardwareBudgetProfile

ENV_HARDWARE_PROFILE = "OATHWEAVER_HARDWARE_PROFILE"
CONFIG_RELATIVE_PATH = Path("SourceCode") / "configs" / "hardware_profiles.json"


def _coerce_int(value: Any, default: int) -> int:
try:
return int(value)
except Exception:
return int(default)


def _coerce_float(value: Any, default: float) -> float:
try:
return float(value)
except Exception:
return float(default)


def _builtin_config() -> dict[str, Any]:
default = DEFAULT_PROFILE.as_dict()
return {
"default_profile": DEFAULT_PROFILE.name,
"profiles": {
DEFAULT_PROFILE.name: {
"name": DEFAULT_PROFILE.name,
"display_name": "Default: 8GB VRAM / 16GB RAM",
"description": "Built-in conservative default local profile.",
"hardware": {
"system_ram_gb": default["ram_gb"],
"gpu_backend": "generic",
"gpu_vram_gb": default["vram_gb"],
"unified_memory": False,
},
"scheduler": {
"max_context_tokens": default["max_context_tokens"],
"warning_context_tokens": default["max_context_tokens"],
"max_stage_context_tokens": default["max_stage_context_tokens"],
"max_parallel_models": default["max_parallel_models"],
"max_active_model_calls": default["max_parallel_models"],
"on_deck_depth": default["on_deck_depth"],
"warm_depth": default["warm_depth"],
"allow_neural_prefetch": default["allow_neural_prefetch"],
},
"inference": {
"preferred_backends": ["ollama", "llama.cpp"],
"default_keep_alive": "10m",
"heavy_keep_alive": "0",
"release_heavy_after_call": True,
"max_loaded_models": default["max_parallel_models"],
},
"model_policy": {
"normal_max_b": 9,
"heavy_max_b": 14,
"premium_min_b": 24,
"allow_premium": False,
"premium_requires_manual": True,
"allow_14b_with_warning": True,
"reject_heavier_fallbacks": False,
},
"lane_caps": {},
"validation": {
"startup_mode": "warn",
"strict_mode_available": True,
"warn_on_missing_models": True,
"warn_on_unreachable_backends": True,
"warn_on_context_over_cap": True,
"warn_on_parallelism_over_cap": True,
"warn_on_premium_auto_escalation": True,
},
}
},
}


def load_hardware_profiles(repo_root: Path) -> dict[str, Any]:
"""Load structured hardware profiles, falling back to the legacy default."""
config_path = Path(repo_root) / CONFIG_RELATIVE_PATH
if not config_path.exists():
return _builtin_config()
try:
payload = json.loads(config_path.read_text(encoding="utf-8"))
except Exception:
return _builtin_config()
if not isinstance(payload, dict):
return _builtin_config()
profiles = payload.get("profiles")
if not isinstance(profiles, dict) or not profiles:
return _builtin_config()
return payload


def resolve_active_hardware_profile(repo_root: Path, name: str | None = None) -> dict[str, Any]:
"""Resolve the active hardware profile by explicit name, env var, then config default."""
payload = load_hardware_profiles(repo_root)
profiles = payload.get("profiles") if isinstance(payload.get("profiles"), dict) else {}
default_name = str(payload.get("default_profile") or DEFAULT_PROFILE.name).strip() or DEFAULT_PROFILE.name
requested = str(name or os.getenv(ENV_HARDWARE_PROFILE, "") or default_name).strip()
if not requested:
requested = default_name
key = requested.lower()

selected: dict[str, Any] | None = None
for profile_name, profile in profiles.items():
if str(profile_name).strip().lower() == key and isinstance(profile, dict):
selected = dict(profile)
break

warnings: list[str] = []
if selected is None:
fallback = profiles.get(default_name)
selected = dict(fallback) if isinstance(fallback, dict) else _builtin_config()["profiles"][DEFAULT_PROFILE.name]
warnings.append(f"Unknown hardware profile {requested!r}; using {selected.get('name', DEFAULT_PROFILE.name)!r}.")

selected.setdefault("name", requested if not warnings else selected.get("name", DEFAULT_PROFILE.name))
if warnings:
selected["_resolution_warnings"] = warnings
return deepcopy(selected)


def hardware_profile_to_scheduler(profile: dict[str, Any]) -> HardwareBudgetProfile:
scheduler = profile.get("scheduler") if isinstance(profile.get("scheduler"), dict) else {}
hardware = profile.get("hardware") if isinstance(profile.get("hardware"), dict) else {}
return HardwareBudgetProfile(
name=str(profile.get("name") or DEFAULT_PROFILE.name),
vram_gb=_coerce_float(hardware.get("gpu_vram_gb"), DEFAULT_PROFILE.vram_gb),
ram_gb=_coerce_float(hardware.get("system_ram_gb"), DEFAULT_PROFILE.ram_gb),
max_context_tokens=_coerce_int(scheduler.get("max_context_tokens"), DEFAULT_PROFILE.max_context_tokens),
max_parallel_models=_coerce_int(scheduler.get("max_parallel_models"), DEFAULT_PROFILE.max_parallel_models),
on_deck_depth=_coerce_int(scheduler.get("on_deck_depth"), DEFAULT_PROFILE.on_deck_depth),
warm_depth=_coerce_int(scheduler.get("warm_depth"), DEFAULT_PROFILE.warm_depth),
max_stage_context_tokens=_coerce_int(
scheduler.get("max_stage_context_tokens"),
DEFAULT_PROFILE.max_stage_context_tokens,
),
allow_neural_prefetch=bool(scheduler.get("allow_neural_prefetch", DEFAULT_PROFILE.allow_neural_prefetch)),
)


def hardware_profile_to_router_policy(profile: dict[str, Any]) -> dict[str, Any]:
scheduler = profile.get("scheduler") if isinstance(profile.get("scheduler"), dict) else {}
hardware = profile.get("hardware") if isinstance(profile.get("hardware"), dict) else {}
model_policy = profile.get("model_policy") if isinstance(profile.get("model_policy"), dict) else {}
lane_caps = profile.get("lane_caps") if isinstance(profile.get("lane_caps"), dict) else {}
return {
"name": str(profile.get("name") or DEFAULT_PROFILE.name),
"max_context": _coerce_int(scheduler.get("max_context_tokens"), DEFAULT_PROFILE.max_context_tokens),
"warning_context": _coerce_int(
scheduler.get("warning_context_tokens"),
_coerce_int(scheduler.get("max_context_tokens"), DEFAULT_PROFILE.max_context_tokens),
),
"max_concurrency": _coerce_int(
scheduler.get("max_active_model_calls"),
_coerce_int(scheduler.get("max_parallel_models"), DEFAULT_PROFILE.max_parallel_models),
),
"allow_premium": bool(model_policy.get("allow_premium", False)),
"normal_max_b": _coerce_float(model_policy.get("normal_max_b"), 9.0),
"heavy_max_b": _coerce_float(model_policy.get("heavy_max_b"), 14.0),
"premium_min_b": _coerce_float(model_policy.get("premium_min_b"), 24.0),
"premium_requires_manual": bool(model_policy.get("premium_requires_manual", True)),
"allow_14b_with_warning": bool(model_policy.get("allow_14b_with_warning", True)),
"reject_heavier_fallbacks": bool(model_policy.get("reject_heavier_fallbacks", False)),
"gpu_backend": str(hardware.get("gpu_backend") or "generic"),
"gpu_vram_gb": _coerce_float(hardware.get("gpu_vram_gb"), DEFAULT_PROFILE.vram_gb),
"lane_caps": deepcopy(lane_caps),
}


def hardware_profile_summary(profile: dict[str, Any]) -> dict[str, Any]:
scheduler_profile = hardware_profile_to_scheduler(profile)
scheduler = profile.get("scheduler") if isinstance(profile.get("scheduler"), dict) else {}
summary = scheduler_profile.as_dict()
summary.update(
{
"display_name": str(profile.get("display_name") or profile.get("name") or scheduler_profile.name),
"description": str(profile.get("description") or ""),
"warning_context_tokens": _coerce_int(
scheduler.get("warning_context_tokens"),
scheduler_profile.max_context_tokens,
),
"max_active_model_calls": _coerce_int(
scheduler.get("max_active_model_calls"),
scheduler_profile.max_parallel_models,
),
"hardware": deepcopy(profile.get("hardware") if isinstance(profile.get("hardware"), dict) else {}),
"scheduler": deepcopy(profile.get("scheduler") if isinstance(profile.get("scheduler"), dict) else {}),
"inference": deepcopy(profile.get("inference") if isinstance(profile.get("inference"), dict) else {}),
"model_policy": deepcopy(profile.get("model_policy") if isinstance(profile.get("model_policy"), dict) else {}),
"lane_caps": deepcopy(profile.get("lane_caps") if isinstance(profile.get("lane_caps"), dict) else {}),
"validation": deepcopy(profile.get("validation") if isinstance(profile.get("validation"), dict) else {}),
}
)
if isinstance(profile.get("_resolution_warnings"), list):
summary["resolution_warnings"] = list(profile.get("_resolution_warnings") or [])
return summary


def active_router_policy_from_env(repo_root: Path) -> dict[str, Any] | None:
"""Return a router policy only when the operator explicitly selected a profile."""
selected = str(os.getenv(ENV_HARDWARE_PROFILE, "")).strip()
if not selected:
return None
return hardware_profile_to_router_policy(resolve_active_hardware_profile(repo_root, selected))
Loading
Loading