christlurker's picture
FrontierAgent react demo
9d0fd45
Raw
History Blame Contribute Delete
6.37 kB
"""Native profile loader and LLM builders for the stateful ReAct agent."""
from __future__ import annotations
import logging
from pathlib import Path
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from frontier_agent.core.runtime.loop.model_profile import ThinkingFormat
from frontier_agent.core.llm import LLMClient
logger = logging.getLogger(__name__)
_PROFILES_DIR = Path(__file__).resolve().parent / "profiles"
_PROJECT_ROOT = Path(__file__).resolve().parents[2]
# Retired profile names kept resolvable so saved command lines, CI jobs and
# pinned ``workflow_profile:`` values don't hard-fail with FileNotFoundError
# after a rename. Mirrors ``workflows/agent_team/profile.py``.
_PROFILE_ALIASES = {
"default": "simple",
"keep5": "benchmark",
"Apodex1.1-solve": "tui",
}
# An alias must not silently change what a pinned name DOES. The retired
# ``default`` profile retained every tool result (``keep_last_k: -1``) while
# ``simple`` blanks after 5, and eight ``scripts/evaluate-*.sh`` runs plus the
# ``officeqa``/``gdpval``/``apex`` sandbox defaults are still pinned to
# ``--profile default``; remapping the name alone would quietly make those runs
# incomparable with every earlier result. Applied before caller ``overrides``,
# so an explicit override still wins.
_ALIAS_OVERRIDES: dict[str, dict[str, Any]] = {
"default": {"agent": {"keep_last_k": -1}},
}
def _deep_merge(base: dict[str, Any], overrides: dict[str, Any]) -> dict[str, Any]:
"""Recursively merge profile overrides without importing another workflow."""
merged = dict(base)
for key, value in overrides.items():
if isinstance(value, dict) and isinstance(merged.get(key), dict):
merged[key] = _deep_merge(merged[key], value)
else:
merged[key] = value
return merged
def load_react_profile(
name: str,
*,
overrides: dict[str, Any] | None = None,
inline: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""Load a ReAct profile YAML with env-var resolution."""
import yaml
from dotenv import load_dotenv
from frontier_agent.infra.config import _resolve_env_vars
load_dotenv(_PROJECT_ROOT / ".env", override=False)
if inline is not None:
raw: Any = inline
else:
path = _PROFILES_DIR / f"{_PROFILE_ALIASES.get(name, name)}.yaml"
if not path.exists():
raise FileNotFoundError(f"ReAct profile not found: {path}")
raw = yaml.safe_load(path.read_text(encoding="utf-8"))
resolved = _resolve_env_vars(raw)
if inline is None and (alias_overrides := _ALIAS_OVERRIDES.get(name)):
resolved = _deep_merge(resolved, alias_overrides)
if overrides:
resolved = _deep_merge(resolved, overrides)
return resolved
def _resolve_thinking_format(profile: dict[str, Any]) -> ThinkingFormat:
from frontier_agent.core.runtime.loop.model_profile import (
infer_thinking_format,
is_thinking_format,
)
from frontier_agent.infra.protocol_client import (
protocol_of,
thinking_format_for_protocol,
)
explicit = (profile.get("agent") or {}).get("thinking_format")
if explicit:
if is_thinking_format(explicit):
return explicit
logger.warning(
"profile agent.thinking_format=%r is not a known format — ignoring",
explicit,
)
# Native Anthropic / OpenAI Responses return content as a typed block list
# → content_block so the parser keeps the verbatim blocks.
by_protocol = thinking_format_for_protocol(protocol_of(profile.get("llm") or {}))
if by_protocol:
return by_protocol
model_id = (profile.get("llm") or {}).get("model")
return infer_thinking_format(model_id, default="tag")
def create_react_llm(profile: dict[str, Any]) -> LLMClient:
"""Create the ReAct LLM from a profile dict, keyed on ``llm.protocol``.
- ``anthropic`` → native Anthropic Messages API (thinking + signature).
- ``responses`` → OpenAI Responses API (reasoning + encrypted_content).
- ``chat_completions`` (default) → OpenAI-compatible Chat Completions.
"""
from frontier_agent.infra.llm import with_provider_stamp
from frontier_agent.infra.openai_client import OpenAIClient
from frontier_agent.infra.protocol_client import build_protocol_client
cfg = profile["llm"]
provider = cfg.get("_provider_label") or cfg.get("provider") or "openai"
protocol_client = build_protocol_client(cfg, title="FrontierAgent-StatefulReAct")
if protocol_client is not None:
return with_provider_stamp(protocol_client, str(provider))
extra_body: dict[str, Any] = dict(cfg.get("extra_body") or {})
if (top_p := cfg.get("top_p")) is not None:
extra_body.setdefault("top_p", top_p)
repetition_penalty = cfg.get("repetition_penalty")
if (
repetition_penalty is not None
and repetition_penalty != 1.0
and "repetition_penalty" not in extra_body
):
extra_body["repetition_penalty"] = repetition_penalty
client = OpenAIClient(
model=cfg["model"],
api_key=cfg.get("api_key", "dummy"),
base_url=cfg.get("base_url"),
temperature=cfg.get("temperature", 0.0),
# int(): ``max_tokens`` may come from a ``${OPENAI_MAX_TOKENS:-…}``
# placeholder, and env-var substitution always yields a string. It is
# forwarded verbatim into the request body, where a quoted number is a
# 400 from the endpoint.
max_completion_tokens=int(cfg.get("max_tokens") or 65536),
default_headers={
"HTTP-Referer": "frontier_agent",
"X-Title": "FrontierAgent-StatefulReAct",
},
extra_body=extra_body or None,
)
return with_provider_stamp(client, str(provider))
def build_react_model_profile(profile: dict[str, Any]) -> Any:
"""Build a ModelProfile from a ReAct profile dict."""
from frontier_agent.core.runtime.loop.model_profile import ModelProfile
from frontier_agent.infra.protocol_client import protocol_of
return ModelProfile(
model_id=profile["llm"]["model"],
provider=str(profile["llm"].get("provider") or "openai"),
thinking_format=_resolve_thinking_format(profile),
protocol=protocol_of(profile.get("llm") or {}),
)