Thanks to visit codestin.com
Credit goes to github.com

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
7 changes: 7 additions & 0 deletions src/gaia/agents/base/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def __init__(
max_consecutive_repeats: int = 4,
min_context_size: int = 32768,
skip_lemonade: bool = False,
device: Optional[str] = None,
):
"""
Initialize the Agent with LLM client.
Expand All @@ -272,9 +273,14 @@ def __init__(
min_context_size: Minimum context size required for this agent (default: 32768).
skip_lemonade: If True, skip Lemonade server initialization (default: False).
Use this when connecting to a different OpenAI-compatible backend.
device: Runtime device selector ('cpu', 'gpu', 'npu') chosen by the
user (Agent UI dropdown / CLI --device). Validated against
detected hardware at startup via LemonadeManager.ensure_ready;
an unavailable device fails loudly (default: None = no check).

Note: Uses local LLM server by default unless use_claude or use_chatgpt is True.
"""
self.device = device
self.error_history = [] # Store error history for learning
self.conversation_history = (
[]
Expand Down Expand Up @@ -312,6 +318,7 @@ def __init__(
quiet=silent_mode,
base_url=base_url,
required_min_device=required_min_device,
device=device,
)

# Initialize state management
Expand Down
10 changes: 10 additions & 0 deletions src/gaia/agents/chat/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ class ChatAgentConfig:
max_steps: int = 10
streaming: bool = False # Use --streaming to enable

# NPU's FLM build runs at 4K, so a device config can override the 32K ctx.
device: Optional[str] = None
min_context_size: Optional[int] = None

# Debug/output settings
debug: bool = False
debug_prompts: bool = False # Backward compatibility
Expand Down Expand Up @@ -353,6 +357,12 @@ def __init__(self, config: Optional[ChatAgentConfig] = None):
show_stats=config.show_stats,
silent_mode=config.silent_mode,
debug=config.debug,
device=config.device,
min_context_size=(
config.min_context_size
if config.min_context_size is not None
else 32768
),
)

# Index initial documents (only if RAG is available)
Expand Down
45 changes: 42 additions & 3 deletions src/gaia/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,9 @@ async def async_main(action, **kwargs):
if device_was_explicit:
print(
"❌ NPU not available on this system. "
"Requires Ryzen AI 300/400/Max (XDNA2).",
"Requires Ryzen AI 300/400/Max (XDNA2). "
"Run `gaia init --profile npu` to set it up, "
"or choose --device gpu.",
file=sys.stderr,
)
sys.exit(1)
Expand All @@ -635,9 +637,45 @@ async def async_main(action, **kwargs):
for k, v in _devices.items()
)
if not has_gpu and not device_was_explicit:
# Default GPU target unavailable — announce the
# *reason* for the CPU fallback so it doesn't read
# like a deliberate user choice.
print(
"No GPU detected; falling back to CPU (slower). "
"Run `gaia init` to set up GPU acceleration."
)
effective_device = "cpu"
except Exception:
pass # Lemonade not running yet; proceed with requested device
except LemonadeClientError as _probe_err:
# Only treat "server not reachable yet" (connection refused /
# timeout) as a soft pass. A reachable but broken server
# (HTTP 4xx/5xx, 401 auth) must NOT silently let an explicit
# --device proceed; surface it so the user sees the real
# failure. The agent runtime re-validates the device
# regardless (LemonadeManager.ensure_ready).
#
# Prefer the original requests exception preserved in the
# cause chain over message-string matching — the client
# wraps RequestException without an HTTP status, but the
# exact wrapper text can change independently of this guard.
import requests

_cause = _probe_err.__cause__ or _probe_err.__context__
_unreachable = isinstance(
_cause,
(
requests.exceptions.ConnectionError,
requests.exceptions.Timeout,
),
) or (
# Fallback for wrappers that don't preserve __cause__.
str(_probe_err).startswith("Request failed:")
and "with status" not in str(_probe_err)
)
if not _unreachable:
raise
log.debug(
"Device probe: Lemonade not reachable yet (%s)", _probe_err
)

for dc in DEFAULT_DEVICE_CONFIGS:
if dc.device == effective_device:
Expand Down Expand Up @@ -666,6 +704,7 @@ async def async_main(action, **kwargs):
os.getenv("LEMONADE_BASE_URL", DEFAULT_LEMONADE_URL),
),
model_id=explicit_model,
device=effective_device,
max_steps=kwargs.get("max_steps", 100),
streaming=kwargs.get("stream", False),
show_prompts=kwargs.get("show_prompts", False),
Expand Down
Loading
Loading