feat(cli): enhance agent loading with optional config parameter for improved initialization
This commit is contained in:
+174
-111
@@ -1,11 +1,15 @@
|
||||
"""EvoScientist Agent graph construction.
|
||||
|
||||
This module creates and exports the compiled agent graph.
|
||||
This module defines the agent graph and its factory functions. All heavy
|
||||
initialization (deepagents, backends, LLM, middleware) is deferred to first
|
||||
use so that importing this module is fast and non-agent CLI commands
|
||||
(``EvoSci config list``, ``EvoSci onboard``) never pay the cost.
|
||||
|
||||
Usage:
|
||||
from EvoScientist import agent
|
||||
from EvoScientist import EvoScientist_agent
|
||||
|
||||
# Notebook / programmatic usage
|
||||
for state in agent.stream(
|
||||
for state in EvoScientist_agent.stream(
|
||||
{"messages": [HumanMessage(content="your question")]},
|
||||
config={"configurable": {"thread_id": "1"}},
|
||||
stream_mode="values",
|
||||
@@ -17,107 +21,81 @@ import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import FilesystemBackend, CompositeBackend
|
||||
|
||||
from .backends import CustomSandboxBackend, MergedReadOnlyBackend
|
||||
from .config import get_effective_config, apply_config_to_env
|
||||
from .llm import get_chat_model
|
||||
from .mcp import load_mcp_tools
|
||||
from .middleware import create_memory_middleware, ToolErrorHandlerMiddleware
|
||||
from .prompts import RESEARCHER_INSTRUCTIONS, get_system_prompt
|
||||
from .utils import load_subagents
|
||||
from .tools import tavily_search, think_tool, skill_manager
|
||||
from . import paths as _paths_mod
|
||||
from .paths import set_active_workspace, set_workspace_root
|
||||
|
||||
# =============================================================================
|
||||
# Configuration
|
||||
# Constants
|
||||
# =============================================================================
|
||||
|
||||
# Load configuration from file/env/defaults
|
||||
_config = get_effective_config()
|
||||
apply_config_to_env(_config)
|
||||
|
||||
# NOTE: We intentionally do NOT call set_workspace_root() at module level.
|
||||
# The CLI (commands.py) calls set_workspace_root() *before* importing this
|
||||
# module. A module-level call here would overwrite the CLI's --workdir
|
||||
# value with config.default_workdir, violating the priority chain
|
||||
# (CLI args > config file). Instead, config.default_workdir is applied
|
||||
# as a fallback inside create_cli_agent() when no explicit workspace_dir
|
||||
# is provided.
|
||||
|
||||
# Research limits (from config)
|
||||
MAX_CONCURRENT = _config.max_concurrent
|
||||
MAX_ITERATIONS = _config.max_iterations
|
||||
|
||||
# Workspace settings (defer dir creation to CLI; here we just resolve paths)
|
||||
# Read from the paths module so values reflect any earlier set_workspace_root().
|
||||
WORKSPACE_DIR = str(_paths_mod.WORKSPACE_ROOT)
|
||||
set_active_workspace(WORKSPACE_DIR)
|
||||
MEMORY_DIR = str(_paths_mod.MEMORY_DIR) # Shared across sessions (not per-session)
|
||||
SKILLS_DIR = str(Path(__file__).parent / "skills")
|
||||
USER_SKILLS_DIR = str(_paths_mod.USER_SKILLS_DIR)
|
||||
SUBAGENTS_CONFIG = Path(__file__).parent / "subagent.yaml"
|
||||
SKILLS_DIR = str(Path(__file__).parent / "skills")
|
||||
|
||||
# =============================================================================
|
||||
# Initialization
|
||||
# Lazy state — initialized on first use, not at import time
|
||||
# =============================================================================
|
||||
|
||||
|
||||
# Generate system prompt with limits
|
||||
SYSTEM_PROMPT = get_system_prompt(
|
||||
max_concurrent=MAX_CONCURRENT,
|
||||
max_iterations=MAX_ITERATIONS,
|
||||
)
|
||||
|
||||
# Initialize chat model using the LLM module (respects config settings)
|
||||
chat_model = get_chat_model(
|
||||
model=_config.model,
|
||||
provider=_config.provider,
|
||||
)
|
||||
|
||||
# Initialize workspace backend
|
||||
_workspace_backend = CustomSandboxBackend(
|
||||
root_dir=WORKSPACE_DIR,
|
||||
virtual_mode=True,
|
||||
timeout=300,
|
||||
)
|
||||
|
||||
# Skills backend: merge user-installed (./skills/) and system (package) skills
|
||||
_skills_backend = MergedReadOnlyBackend(
|
||||
primary_dir=USER_SKILLS_DIR, # user-installed, takes priority
|
||||
secondary_dir=SKILLS_DIR, # package built-in, fallback
|
||||
)
|
||||
|
||||
# Memory backend: persistent filesystem for long-term memory (shared across sessions)
|
||||
_memory_backend = FilesystemBackend(
|
||||
root_dir=MEMORY_DIR,
|
||||
virtual_mode=True,
|
||||
)
|
||||
|
||||
# Composite backend: workspace as default, skills and memory mounted
|
||||
backend = CompositeBackend(
|
||||
default=_workspace_backend,
|
||||
routes={
|
||||
"/skills/": _skills_backend,
|
||||
"/memory/": _memory_backend,
|
||||
},
|
||||
)
|
||||
|
||||
tool_registry = {
|
||||
"think_tool": think_tool,
|
||||
"tavily_search": tavily_search,
|
||||
}
|
||||
|
||||
# Base tools that every agent variant gets (before MCP)
|
||||
BASE_TOOLS = [think_tool, skill_manager]
|
||||
_config = None
|
||||
_chat_model = None
|
||||
_system_prompt = None
|
||||
|
||||
# Cache MCP tools by the effective config signature to avoid reconnecting
|
||||
# to MCP servers on every `/new` when config is unchanged.
|
||||
_MCP_TOOLS_CACHE_KEY: str | None = None
|
||||
_MCP_TOOLS_CACHE_VALUE: dict[str, list] | None = None
|
||||
|
||||
# Default agent (no checkpointer) — used by langgraph dev / LangSmith / notebooks.
|
||||
# Lazily constructed on first access so MCP tools are included without
|
||||
# spawning subprocesses at import time.
|
||||
_EvoScientist_agent = None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Lazy initialization helpers
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def _ensure_config(config=None):
|
||||
"""Return cached config. If *config* is passed, cache and use it."""
|
||||
global _config
|
||||
if config is not None:
|
||||
_config = config
|
||||
apply_config_to_env(_config)
|
||||
if _config is None:
|
||||
_config = get_effective_config()
|
||||
apply_config_to_env(_config)
|
||||
return _config
|
||||
|
||||
|
||||
def _ensure_chat_model():
|
||||
"""Return cached chat model, creating it on first call."""
|
||||
global _chat_model
|
||||
if _chat_model is None:
|
||||
from .llm import get_chat_model
|
||||
|
||||
cfg = _ensure_config()
|
||||
_chat_model = get_chat_model(model=cfg.model, provider=cfg.provider)
|
||||
return _chat_model
|
||||
|
||||
|
||||
def _ensure_system_prompt():
|
||||
"""Return cached system prompt, creating it on first call."""
|
||||
global _system_prompt
|
||||
if _system_prompt is None:
|
||||
cfg = _ensure_config()
|
||||
_system_prompt = get_system_prompt(
|
||||
max_concurrent=cfg.max_concurrent,
|
||||
max_iterations=cfg.max_iterations,
|
||||
)
|
||||
return _system_prompt
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# MCP caching
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def _mcp_config_signature() -> str:
|
||||
"""Return a stable signature for the effective MCP config."""
|
||||
@@ -137,6 +115,8 @@ def _load_mcp_tools_cached() -> dict[str, list]:
|
||||
"""Load MCP tools with config-aware caching."""
|
||||
global _MCP_TOOLS_CACHE_KEY, _MCP_TOOLS_CACHE_VALUE
|
||||
|
||||
from .mcp import load_mcp_tools
|
||||
|
||||
cfg_key = _mcp_config_signature()
|
||||
if not cfg_key:
|
||||
_MCP_TOOLS_CACHE_KEY = ""
|
||||
@@ -152,6 +132,11 @@ def _load_mcp_tools_cached() -> dict[str, list]:
|
||||
return {k: list(v) for k, v in loaded.items()}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Agent construction helpers
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def _inject_subagent_middleware(subs: list[dict]) -> None:
|
||||
"""Ensure every subagent gets ToolErrorHandlerMiddleware.
|
||||
|
||||
@@ -159,12 +144,29 @@ def _inject_subagent_middleware(subs: list[dict]) -> None:
|
||||
ToolNode handler which produces terse messages without tracebacks or
|
||||
retry guidance — reducing the subagent's ability to self-recover.
|
||||
"""
|
||||
from .middleware import ToolErrorHandlerMiddleware
|
||||
|
||||
for sa in subs:
|
||||
sa.setdefault("middleware", []).append(ToolErrorHandlerMiddleware())
|
||||
|
||||
|
||||
def _build_prompt_refs() -> dict:
|
||||
"""Build prompt references with the current date (not frozen at import)."""
|
||||
return {
|
||||
"RESEARCHER_INSTRUCTIONS": RESEARCHER_INSTRUCTIONS.format(
|
||||
date=datetime.now().strftime("%Y-%m-%d"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _build_base_kwargs(base_backend, base_middleware):
|
||||
"""Build agent kwargs *without* MCP (fast, no subprocess spawning)."""
|
||||
from .utils import load_subagents
|
||||
from .tools import tavily_search, think_tool, skill_manager
|
||||
|
||||
tool_registry = {"think_tool": think_tool, "tavily_search": tavily_search}
|
||||
base_tools = [think_tool, skill_manager]
|
||||
|
||||
subs = load_subagents(
|
||||
SUBAGENTS_CONFIG,
|
||||
tool_registry=tool_registry,
|
||||
@@ -173,12 +175,12 @@ def _build_base_kwargs(base_backend, base_middleware):
|
||||
_inject_subagent_middleware(subs)
|
||||
return dict(
|
||||
name="EvoScientist",
|
||||
model=chat_model,
|
||||
tools=list(BASE_TOOLS),
|
||||
model=_ensure_chat_model(),
|
||||
tools=list(base_tools),
|
||||
backend=base_backend,
|
||||
subagents=subs,
|
||||
middleware=base_middleware,
|
||||
system_prompt=SYSTEM_PROMPT,
|
||||
system_prompt=_ensure_system_prompt(),
|
||||
skills=["/skills/"],
|
||||
)
|
||||
|
||||
@@ -189,10 +191,16 @@ def load_mcp_and_build_kwargs(base_backend, base_middleware):
|
||||
Re-connects to MCP servers only when the effective MCP config changes.
|
||||
Falls back to base kwargs if no MCP configured.
|
||||
"""
|
||||
from .utils import load_subagents
|
||||
from .tools import tavily_search, think_tool, skill_manager
|
||||
|
||||
mcp_by_agent = _load_mcp_tools_cached()
|
||||
if not mcp_by_agent:
|
||||
return _build_base_kwargs(base_backend, base_middleware)
|
||||
|
||||
tool_registry = {"think_tool": think_tool, "tavily_search": tavily_search}
|
||||
base_tools = [think_tool, skill_manager]
|
||||
|
||||
# Fresh tool registry — start from base tools + MCP tools
|
||||
registry = dict(tool_registry)
|
||||
for tools in mcp_by_agent.values():
|
||||
@@ -216,40 +224,73 @@ def load_mcp_and_build_kwargs(base_backend, base_middleware):
|
||||
|
||||
return dict(
|
||||
name="EvoScientist",
|
||||
model=chat_model,
|
||||
tools=BASE_TOOLS + mcp_main,
|
||||
model=_ensure_chat_model(),
|
||||
tools=base_tools + mcp_main,
|
||||
backend=base_backend,
|
||||
subagents=subs,
|
||||
middleware=base_middleware,
|
||||
system_prompt=SYSTEM_PROMPT,
|
||||
system_prompt=_ensure_system_prompt(),
|
||||
skills=["/skills/"],
|
||||
)
|
||||
|
||||
|
||||
def _build_prompt_refs() -> dict:
|
||||
"""Build prompt references with the current date (not frozen at import)."""
|
||||
return {
|
||||
"RESEARCHER_INSTRUCTIONS": RESEARCHER_INSTRUCTIONS.format(
|
||||
date=datetime.now().strftime("%Y-%m-%d"),
|
||||
),
|
||||
}
|
||||
# =============================================================================
|
||||
# Default agent (langgraph dev / notebooks)
|
||||
# =============================================================================
|
||||
|
||||
base_middleware = [
|
||||
ToolErrorHandlerMiddleware(),
|
||||
create_memory_middleware(MEMORY_DIR, extraction_model=chat_model),
|
||||
]
|
||||
|
||||
# Default agent (no checkpointer) — used by langgraph dev / LangSmith / notebooks.
|
||||
# Lazily constructed on first access so MCP tools are included without
|
||||
# spawning subprocesses at import time.
|
||||
_EvoScientist_agent = None
|
||||
def _get_default_backend():
|
||||
"""Build the default composite backend from current paths."""
|
||||
from deepagents.backends import FilesystemBackend, CompositeBackend
|
||||
from .backends import CustomSandboxBackend, MergedReadOnlyBackend
|
||||
|
||||
workspace_dir = str(_paths_mod.WORKSPACE_ROOT)
|
||||
set_active_workspace(workspace_dir)
|
||||
memory_dir = str(_paths_mod.MEMORY_DIR)
|
||||
user_skills_dir = str(_paths_mod.USER_SKILLS_DIR)
|
||||
|
||||
ws_backend = CustomSandboxBackend(
|
||||
root_dir=workspace_dir,
|
||||
virtual_mode=True,
|
||||
timeout=300,
|
||||
)
|
||||
sk_backend = MergedReadOnlyBackend(
|
||||
primary_dir=user_skills_dir,
|
||||
secondary_dir=SKILLS_DIR,
|
||||
)
|
||||
mem_backend = FilesystemBackend(
|
||||
root_dir=memory_dir,
|
||||
virtual_mode=True,
|
||||
)
|
||||
return CompositeBackend(
|
||||
default=ws_backend,
|
||||
routes={
|
||||
"/skills/": sk_backend,
|
||||
"/memory/": mem_backend,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def _get_default_middleware():
|
||||
"""Build the default middleware list."""
|
||||
from .middleware import create_memory_middleware, ToolErrorHandlerMiddleware
|
||||
|
||||
memory_dir = str(_paths_mod.MEMORY_DIR)
|
||||
return [
|
||||
ToolErrorHandlerMiddleware(),
|
||||
create_memory_middleware(memory_dir, extraction_model=_ensure_chat_model()),
|
||||
]
|
||||
|
||||
|
||||
def _get_default_agent():
|
||||
"""Build the default agent (with MCP, no checkpointer) on first access."""
|
||||
global _EvoScientist_agent
|
||||
if _EvoScientist_agent is None:
|
||||
kwargs = load_mcp_and_build_kwargs(backend, base_middleware)
|
||||
from deepagents import create_deep_agent
|
||||
|
||||
be = _get_default_backend()
|
||||
mw = _get_default_middleware()
|
||||
kwargs = load_mcp_and_build_kwargs(be, mw)
|
||||
_EvoScientist_agent = create_deep_agent(**kwargs).with_config(
|
||||
{"recursion_limit": 500}
|
||||
)
|
||||
@@ -259,10 +300,22 @@ def _get_default_agent():
|
||||
def __getattr__(name: str):
|
||||
if name == "EvoScientist_agent":
|
||||
return _get_default_agent()
|
||||
# Backward compat for module-level names
|
||||
if name == "chat_model":
|
||||
return _ensure_chat_model()
|
||||
if name == "SYSTEM_PROMPT":
|
||||
return _ensure_system_prompt()
|
||||
if name == "backend":
|
||||
return _get_default_backend()
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
|
||||
|
||||
def create_cli_agent(workspace_dir: str | None = None, checkpointer=None):
|
||||
# =============================================================================
|
||||
# CLI agent factory
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def create_cli_agent(workspace_dir: str | None = None, checkpointer=None, config=None):
|
||||
"""Create agent with checkpointer for CLI multi-turn support.
|
||||
|
||||
A fresh backend is constructed on every call using the current
|
||||
@@ -274,10 +327,20 @@ def create_cli_agent(workspace_dir: str | None = None, checkpointer=None):
|
||||
defaults to the current ``paths.WORKSPACE_ROOT``.
|
||||
checkpointer: Optional LangGraph checkpointer. If ``None``,
|
||||
falls back to ``InMemorySaver`` (non-persistent).
|
||||
config: Optional pre-loaded ``EvoScientistConfig``. If ``None``,
|
||||
loads from file/env/defaults. Passing this avoids double
|
||||
loading when the CLI has already loaded config.
|
||||
"""
|
||||
import os as _os
|
||||
|
||||
from deepagents import create_deep_agent
|
||||
from deepagents.backends import FilesystemBackend, CompositeBackend
|
||||
from .backends import CustomSandboxBackend, MergedReadOnlyBackend
|
||||
from .middleware import create_memory_middleware, ToolErrorHandlerMiddleware
|
||||
from . import paths as _paths
|
||||
|
||||
cfg = _ensure_config(config)
|
||||
|
||||
if checkpointer is None:
|
||||
from langgraph.checkpoint.memory import InMemorySaver # type: ignore[import-untyped]
|
||||
checkpointer = InMemorySaver()
|
||||
@@ -287,9 +350,9 @@ def create_cli_agent(workspace_dir: str | None = None, checkpointer=None):
|
||||
# that never call set_workspace_root() themselves. CLI callers always
|
||||
# pass workspace_dir explicitly, so their --workdir is never overwritten.
|
||||
if workspace_dir is None:
|
||||
if _config.default_workdir:
|
||||
if cfg.default_workdir:
|
||||
set_workspace_root(
|
||||
_os.path.abspath(_os.path.expanduser(_config.default_workdir))
|
||||
_os.path.abspath(_os.path.expanduser(cfg.default_workdir))
|
||||
)
|
||||
workspace_dir = str(_paths.WORKSPACE_ROOT)
|
||||
|
||||
@@ -324,7 +387,7 @@ def create_cli_agent(workspace_dir: str | None = None, checkpointer=None):
|
||||
|
||||
mw = [
|
||||
ToolErrorHandlerMiddleware(),
|
||||
create_memory_middleware(_mem_dir, extraction_model=chat_model),
|
||||
create_memory_middleware(_mem_dir, extraction_model=_ensure_chat_model()),
|
||||
]
|
||||
|
||||
# Re-load MCP tools from current config (picks up /mcp add changes)
|
||||
|
||||
@@ -52,13 +52,15 @@ def _create_session_workspace(name: str | None = None) -> str:
|
||||
return workspace_dir
|
||||
|
||||
|
||||
def _load_agent(workspace_dir: str | None = None, checkpointer=None):
|
||||
def _load_agent(workspace_dir: str | None = None, checkpointer=None, config=None):
|
||||
"""Load the CLI agent with optional persistent checkpointer.
|
||||
|
||||
Args:
|
||||
workspace_dir: Optional per-session workspace directory.
|
||||
checkpointer: Optional LangGraph checkpointer (e.g. ``AsyncSqliteSaver``).
|
||||
Falls back to ``InMemorySaver`` when ``None``.
|
||||
config: Optional pre-loaded ``EvoScientistConfig``. Forwarded to
|
||||
``create_cli_agent`` to avoid double config loading.
|
||||
"""
|
||||
from ..EvoScientist import create_cli_agent
|
||||
return create_cli_agent(workspace_dir=workspace_dir, checkpointer=checkpointer)
|
||||
return create_cli_agent(workspace_dir=workspace_dir, checkpointer=checkpointer, config=config)
|
||||
|
||||
@@ -122,7 +122,7 @@ def serve(
|
||||
ensure_dirs()
|
||||
|
||||
console.print("[dim]Loading agent...[/dim]")
|
||||
agent = _load_agent(workspace_dir=ws)
|
||||
agent = _load_agent(workspace_dir=ws, config=config)
|
||||
tid = str(uuid.uuid4())
|
||||
|
||||
_start_channels_bus_mode(
|
||||
@@ -532,7 +532,7 @@ def _main_callback(
|
||||
async def _single_shot():
|
||||
async with get_checkpointer() as checkpointer:
|
||||
console.print("[dim]Loading agent...[/dim]")
|
||||
agent = _load_agent(workspace_dir=workspace_dir, checkpointer=checkpointer)
|
||||
agent = _load_agent(workspace_dir=workspace_dir, checkpointer=checkpointer, config=config)
|
||||
tid = thread_id or generate_thread_id()
|
||||
cmd_run(
|
||||
agent,
|
||||
@@ -560,6 +560,7 @@ def _main_callback(
|
||||
run_name=name,
|
||||
thread_id=thread_id,
|
||||
ui_backend=config.ui_backend,
|
||||
config=config,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -163,6 +163,7 @@ def cmd_interactive(
|
||||
run_name: str | None = None,
|
||||
thread_id: str | None = None,
|
||||
ui_backend: str = "rich",
|
||||
config=None,
|
||||
) -> None:
|
||||
"""Interactive conversation mode with streaming output.
|
||||
|
||||
@@ -186,6 +187,8 @@ def cmd_interactive(
|
||||
|
||||
resolved_ui_backend = resolve_ui_backend(ui_backend, warn_fallback=True)
|
||||
if resolved_ui_backend == "textual":
|
||||
from functools import partial
|
||||
load_agent = partial(_load_agent, config=config)
|
||||
run_textual_interactive(
|
||||
show_thinking=show_thinking,
|
||||
channel_send_thinking=channel_send_thinking,
|
||||
@@ -196,7 +199,7 @@ def cmd_interactive(
|
||||
provider=provider,
|
||||
run_name=run_name,
|
||||
thread_id=thread_id,
|
||||
load_agent=_load_agent,
|
||||
load_agent=load_agent,
|
||||
create_session_workspace=_create_session_workspace,
|
||||
)
|
||||
return
|
||||
@@ -382,7 +385,7 @@ def cmd_interactive(
|
||||
if ws:
|
||||
state["workspace_dir"] = ws
|
||||
console.print("[dim]Loading session...[/dim]")
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer)
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer, config=config)
|
||||
# Sync shared refs if channel is running
|
||||
if _channels_is_running():
|
||||
_ch_mod._cli_agent = state["agent"]
|
||||
@@ -425,7 +428,7 @@ def cmd_interactive(
|
||||
state["workspace_dir"] = ws
|
||||
|
||||
console.print("[dim]Loading agent...[/dim]")
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer)
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer, config=config)
|
||||
|
||||
# Print banner
|
||||
if state["resumed"]:
|
||||
@@ -561,12 +564,12 @@ def cmd_interactive(
|
||||
|
||||
# Auto-start channel if enabled in config
|
||||
from ..config import load_config
|
||||
config = load_config()
|
||||
if config and config.channel_enabled and not _channels_is_running():
|
||||
_channel_cfg = load_config()
|
||||
if _channel_cfg and _channel_cfg.channel_enabled and not _channels_is_running():
|
||||
_auto_start_channel(
|
||||
state["agent"],
|
||||
state["thread_id"],
|
||||
config,
|
||||
_channel_cfg,
|
||||
send_thinking=channel_send_thinking,
|
||||
)
|
||||
|
||||
@@ -616,7 +619,7 @@ def cmd_interactive(
|
||||
if not workspace_fixed:
|
||||
state["workspace_dir"] = _create_session_workspace(run_name)
|
||||
console.print("[dim]Loading new session...[/dim]")
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer)
|
||||
state["agent"] = _load_agent(workspace_dir=state["workspace_dir"], checkpointer=checkpointer, config=config)
|
||||
state["thread_id"] = generate_thread_id()
|
||||
state["resumed"] = False
|
||||
# Sync channel refs so the queue checker uses the new agent
|
||||
|
||||
@@ -920,7 +920,6 @@ def run_textual_interactive(
|
||||
metadata=msg.metadata,
|
||||
),
|
||||
"Media",
|
||||
timeout=30,
|
||||
)
|
||||
|
||||
response = ""
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
Re-exports all public symbols from settings and onboard submodules
|
||||
so that existing ``from EvoScientist.config import X`` imports continue
|
||||
to work without modification.
|
||||
|
||||
The onboard module is loaded lazily because it pulls in heavy dependencies
|
||||
(langchain, llm) that are not needed for normal config operations.
|
||||
"""
|
||||
|
||||
from .settings import (
|
||||
@@ -18,7 +21,6 @@ from .settings import (
|
||||
get_effective_config,
|
||||
apply_config_to_env,
|
||||
)
|
||||
from .onboard import run_onboard
|
||||
|
||||
__all__ = [
|
||||
# settings
|
||||
@@ -33,6 +35,13 @@ __all__ = [
|
||||
"list_config",
|
||||
"get_effective_config",
|
||||
"apply_config_to_env",
|
||||
# onboard
|
||||
# onboard (lazy)
|
||||
"run_onboard",
|
||||
]
|
||||
|
||||
|
||||
def __getattr__(name: str):
|
||||
if name == "run_onboard":
|
||||
from .onboard import run_onboard
|
||||
return run_onboard
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
|
||||
@@ -27,7 +27,7 @@ class TestMcpToolCaching:
|
||||
calls["load"] += 1
|
||||
return {"main": [tool]}
|
||||
|
||||
monkeypatch.setattr(agent_module, "load_mcp_tools", fake_load_mcp_tools)
|
||||
monkeypatch.setattr("EvoScientist.mcp.load_mcp_tools", fake_load_mcp_tools)
|
||||
|
||||
first = agent_module._load_mcp_tools_cached()
|
||||
second = agent_module._load_mcp_tools_cached()
|
||||
@@ -49,7 +49,7 @@ class TestMcpToolCaching:
|
||||
return {"main": [f"tool-v{calls['load']}"]}
|
||||
|
||||
monkeypatch.setattr("EvoScientist.mcp.client.load_mcp_config", fake_load_config)
|
||||
monkeypatch.setattr(agent_module, "load_mcp_tools", fake_load_mcp_tools)
|
||||
monkeypatch.setattr("EvoScientist.mcp.load_mcp_tools", fake_load_mcp_tools)
|
||||
|
||||
first = agent_module._load_mcp_tools_cached()
|
||||
state["cfg"] = {"srv": {"transport": "stdio", "command": "v2"}}
|
||||
|
||||
@@ -40,7 +40,7 @@ def _run_serve_once(
|
||||
def _fake_ensure_dirs():
|
||||
order.append(("ensure_dirs", None))
|
||||
|
||||
def _fake_load_agent(workspace_dir=None, checkpointer=None):
|
||||
def _fake_load_agent(workspace_dir=None, checkpointer=None, config=None):
|
||||
captured["workspace_dir"] = workspace_dir
|
||||
return object()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user