EvoScientist 0.0.1.dev3__tar.gz → 0.0.1.dev4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/EvoScientist.py +13 -9
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/__init__.py +19 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/cli.py +264 -23
- evoscientist-0.0.1.dev4/EvoScientist/config.py +274 -0
- evoscientist-0.0.1.dev4/EvoScientist/llm/__init__.py +21 -0
- evoscientist-0.0.1.dev4/EvoScientist/llm/models.py +99 -0
- evoscientist-0.0.1.dev4/EvoScientist/onboard.py +725 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/paths.py +2 -3
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills_manager.py +1 -2
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/display.py +1 -1
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/tools.py +11 -2
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist.egg-info/PKG-INFO +68 -22
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist.egg-info/SOURCES.txt +7 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist.egg-info/requires.txt +5 -1
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/PKG-INFO +68 -22
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/README.md +62 -20
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/pyproject.toml +13 -3
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_backends.py +0 -3
- evoscientist-0.0.1.dev4/tests/test_config.py +345 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_imports.py +4 -12
- evoscientist-0.0.1.dev4/tests/test_llm.py +226 -0
- evoscientist-0.0.1.dev4/tests/test_onboard.py +408 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_skills_manager.py +0 -4
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_stream_tracker.py +1 -1
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/__main__.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/backends.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/memory.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/middleware.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/prompts.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/accelerate/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/accelerate/references/custom-plugins.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/accelerate/references/megatron-integration.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/accelerate/references/performance.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/bitsandbytes/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/bitsandbytes/references/memory-optimization.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/bitsandbytes/references/qlora-training.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/bitsandbytes/references/quantization-formats.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/find-skills/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/find-skills/scripts/install_skill.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/flash-attention/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/flash-attention/references/benchmarks.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/flash-attention/references/transformers-integration.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/llama-cpp/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/llama-cpp/references/optimization.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/llama-cpp/references/quantization.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/llama-cpp/references/server.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/lm-evaluation-harness/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/lm-evaluation-harness/references/api-evaluation.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/lm-evaluation-harness/references/benchmark-guide.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/lm-evaluation-harness/references/custom-tasks.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/lm-evaluation-harness/references/distributed-eval.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/references/checklists.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/references/citation-workflow.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/references/reviewer-guidelines.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/references/sources.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/references/writing-guide.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/README.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/aaai2026/README.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/aaai2026/aaai2026-unified-supp.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/aaai2026/aaai2026-unified-template.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/aaai2026/aaai2026.bib +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/aaai2026/aaai2026.bst +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/aaai2026/aaai2026.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/README.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/acl.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/acl_latex.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/acl_lualatex.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/acl_natbib.bst +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/anthology.bib.txt +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/custom.bib +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/acl/formatting.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/README.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/colm2025_conference.bib +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/colm2025_conference.bst +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/colm2025_conference.pdf +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/colm2025_conference.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/colm2025_conference.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/fancyhdr.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/math_commands.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/colm2025/natbib.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/fancyhdr.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.bib +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.bst +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.pdf +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/math_commands.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/iclr2026/natbib.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/algorithm.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/algorithmic.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/example_paper.bib +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/example_paper.pdf +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/example_paper.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/fancyhdr.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/icml2026.bst +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/icml2026.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/icml2026/icml_numpapers.pdf +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/neurips2025/Makefile +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/neurips2025/extra_pkgs.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/neurips2025/main.tex +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ml-paper-writing/templates/neurips2025/neurips.sty +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/peft/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/peft/references/advanced-usage.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/peft/references/troubleshooting.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ray-data/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ray-data/references/integration.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/ray-data/references/transformations.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/LICENSE.txt +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/SKILL.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/references/output-patterns.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/references/workflows.md +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/scripts/init_skill.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/scripts/package_skill.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/skills/skill-creator/scripts/quick_validate.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/__init__.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/emitter.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/events.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/formatter.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/state.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/tracker.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/stream/utils.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/subagent.yaml +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist/utils.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist.egg-info/dependency_links.txt +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist.egg-info/entry_points.txt +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/EvoScientist.egg-info/top_level.txt +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/LICENSE +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/setup.cfg +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_prompts.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_stream_emitter.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_stream_state.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_stream_utils.py +0 -0
- {evoscientist-0.0.1.dev3 → evoscientist-0.0.1.dev4}/tests/test_tools.py +0 -0
|
@@ -13,15 +13,15 @@ Usage:
|
|
|
13
13
|
...
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
import os
|
|
17
16
|
from datetime import datetime
|
|
18
17
|
from pathlib import Path
|
|
19
18
|
|
|
20
19
|
from deepagents import create_deep_agent
|
|
21
20
|
from deepagents.backends import FilesystemBackend, CompositeBackend
|
|
22
|
-
from langchain.chat_models import init_chat_model
|
|
23
21
|
|
|
24
22
|
from .backends import CustomSandboxBackend, MergedReadOnlyBackend
|
|
23
|
+
from .config import get_effective_config, apply_config_to_env
|
|
24
|
+
from .llm import get_chat_model
|
|
25
25
|
from .middleware import create_skills_middleware, create_memory_middleware
|
|
26
26
|
from .prompts import RESEARCHER_INSTRUCTIONS, get_system_prompt
|
|
27
27
|
from .utils import load_subagents
|
|
@@ -37,12 +37,16 @@ from .paths import (
|
|
|
37
37
|
# Configuration
|
|
38
38
|
# =============================================================================
|
|
39
39
|
|
|
40
|
+
# Load configuration from file/env/defaults
|
|
41
|
+
_config = get_effective_config()
|
|
42
|
+
apply_config_to_env(_config)
|
|
43
|
+
|
|
40
44
|
# Backend mode: "sandbox" (with execute) or "filesystem" (read/write only)
|
|
41
45
|
BACKEND_MODE = "sandbox"
|
|
42
46
|
|
|
43
|
-
# Research limits
|
|
44
|
-
MAX_CONCURRENT =
|
|
45
|
-
MAX_ITERATIONS =
|
|
47
|
+
# Research limits (from config)
|
|
48
|
+
MAX_CONCURRENT = _config.max_concurrent
|
|
49
|
+
MAX_ITERATIONS = _config.max_iterations
|
|
46
50
|
|
|
47
51
|
# Workspace settings
|
|
48
52
|
ensure_dirs()
|
|
@@ -65,10 +69,10 @@ SYSTEM_PROMPT = get_system_prompt(
|
|
|
65
69
|
max_iterations=MAX_ITERATIONS,
|
|
66
70
|
)
|
|
67
71
|
|
|
68
|
-
# Initialize chat model
|
|
69
|
-
chat_model =
|
|
70
|
-
model=
|
|
71
|
-
|
|
72
|
+
# Initialize chat model using the LLM module (respects config settings)
|
|
73
|
+
chat_model = get_chat_model(
|
|
74
|
+
model=_config.model,
|
|
75
|
+
provider=_config.provider,
|
|
72
76
|
# thinking={"type": "enabled", "budget_tokens": 2000},
|
|
73
77
|
)
|
|
74
78
|
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"""EvoScientist Agent — AI-powered research & code execution."""
|
|
2
2
|
|
|
3
3
|
from .backends import CustomSandboxBackend, ReadOnlyFilesystemBackend
|
|
4
|
+
from .config import (
|
|
5
|
+
EvoScientistConfig,
|
|
6
|
+
load_config,
|
|
7
|
+
save_config,
|
|
8
|
+
get_effective_config,
|
|
9
|
+
get_config_path,
|
|
10
|
+
)
|
|
11
|
+
from .llm import get_chat_model, MODELS, list_models, DEFAULT_MODEL
|
|
4
12
|
from .middleware import create_skills_middleware
|
|
5
13
|
from .prompts import get_system_prompt, RESEARCHER_INSTRUCTIONS
|
|
6
14
|
from .tools import tavily_search, think_tool
|
|
@@ -13,6 +21,17 @@ __all__ = [
|
|
|
13
21
|
# Backends
|
|
14
22
|
"CustomSandboxBackend",
|
|
15
23
|
"ReadOnlyFilesystemBackend",
|
|
24
|
+
# Configuration
|
|
25
|
+
"EvoScientistConfig",
|
|
26
|
+
"load_config",
|
|
27
|
+
"save_config",
|
|
28
|
+
"get_effective_config",
|
|
29
|
+
"get_config_path",
|
|
30
|
+
# LLM
|
|
31
|
+
"get_chat_model",
|
|
32
|
+
"MODELS",
|
|
33
|
+
"list_models",
|
|
34
|
+
"DEFAULT_MODEL",
|
|
16
35
|
# Middleware
|
|
17
36
|
"create_skills_middleware",
|
|
18
37
|
# Prompts
|
|
@@ -10,6 +10,7 @@ Features:
|
|
|
10
10
|
- Response panel (green) - shows final response
|
|
11
11
|
- Thread ID support for multi-turn conversations
|
|
12
12
|
- Interactive mode with prompt_toolkit
|
|
13
|
+
- Configuration management (onboard, config commands)
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
16
|
import logging
|
|
@@ -25,11 +26,12 @@ from prompt_toolkit.history import FileHistory # type: ignore[import-untyped]
|
|
|
25
26
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory # type: ignore[import-untyped]
|
|
26
27
|
from prompt_toolkit.formatted_text import HTML # type: ignore[import-untyped]
|
|
27
28
|
from rich.text import Text # type: ignore[import-untyped]
|
|
29
|
+
from rich.table import Table # type: ignore[import-untyped]
|
|
28
30
|
|
|
29
31
|
# Backward-compat re-exports (tests import these from EvoScientist.cli)
|
|
30
32
|
from .stream.state import SubAgentState, StreamState, _parse_todo_items, _build_todo_stats # noqa: F401
|
|
31
33
|
from .stream.display import console, _run_streaming
|
|
32
|
-
from .paths import ensure_dirs, new_run_dir
|
|
34
|
+
from .paths import ensure_dirs, new_run_dir, default_workspace_dir
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
def _shorten_path(path: str) -> str:
|
|
@@ -69,8 +71,11 @@ def print_banner(
|
|
|
69
71
|
thread_id: str,
|
|
70
72
|
workspace_dir: str | None = None,
|
|
71
73
|
memory_dir: str | None = None,
|
|
74
|
+
mode: str | None = None,
|
|
75
|
+
model: str | None = None,
|
|
76
|
+
provider: str | None = None,
|
|
72
77
|
):
|
|
73
|
-
"""Print welcome banner with ASCII art logo, thread ID,
|
|
78
|
+
"""Print welcome banner with ASCII art logo, thread ID, workspace path, and mode."""
|
|
74
79
|
for line, color in zip(EVOSCIENTIST_ASCII_LINES, _GRADIENT_COLORS):
|
|
75
80
|
console.print(Text(line, style=f"{color} bold"))
|
|
76
81
|
info = Text()
|
|
@@ -83,6 +88,20 @@ def print_banner(
|
|
|
83
88
|
trimmed = memory_dir.rstrip("/").rstrip("\\")
|
|
84
89
|
info.append("\n Memory dir: ", style="dim")
|
|
85
90
|
info.append(_shorten_path(trimmed), style="cyan")
|
|
91
|
+
if model or provider or mode:
|
|
92
|
+
info.append("\n ", style="dim")
|
|
93
|
+
parts = []
|
|
94
|
+
if model:
|
|
95
|
+
parts.append(("Model: ", model))
|
|
96
|
+
if provider:
|
|
97
|
+
parts.append(("Provider: ", provider))
|
|
98
|
+
if mode:
|
|
99
|
+
parts.append(("Mode: ", mode))
|
|
100
|
+
for i, (label, value) in enumerate(parts):
|
|
101
|
+
if i > 0:
|
|
102
|
+
info.append(" ", style="dim")
|
|
103
|
+
info.append(label, style="dim")
|
|
104
|
+
info.append(value, style="magenta")
|
|
86
105
|
info.append("\n Commands: ", style="dim")
|
|
87
106
|
info.append("/exit", style="bold")
|
|
88
107
|
info.append(", ", style="dim")
|
|
@@ -113,7 +132,7 @@ def _cmd_list_skills() -> None:
|
|
|
113
132
|
|
|
114
133
|
if not skills:
|
|
115
134
|
console.print("[dim]No user skills installed.[/dim]")
|
|
116
|
-
console.print(
|
|
135
|
+
console.print("[dim]Install with:[/dim] /install-skill <path-or-url>")
|
|
117
136
|
console.print(f"[dim]Skills directory:[/dim] [cyan]{_shorten_path(str(USER_SKILLS_DIR))}[/cyan]")
|
|
118
137
|
console.print()
|
|
119
138
|
return
|
|
@@ -182,6 +201,9 @@ def cmd_interactive(
|
|
|
182
201
|
show_thinking: bool = True,
|
|
183
202
|
workspace_dir: str | None = None,
|
|
184
203
|
workspace_fixed: bool = False,
|
|
204
|
+
mode: str | None = None,
|
|
205
|
+
model: str | None = None,
|
|
206
|
+
provider: str | None = None,
|
|
185
207
|
) -> None:
|
|
186
208
|
"""Interactive conversation mode with streaming output.
|
|
187
209
|
|
|
@@ -190,11 +212,14 @@ def cmd_interactive(
|
|
|
190
212
|
show_thinking: Whether to display thinking panels
|
|
191
213
|
workspace_dir: Per-session workspace directory path
|
|
192
214
|
workspace_fixed: If True, /new keeps the same workspace directory
|
|
215
|
+
mode: Workspace mode ('daemon' or 'run'), displayed in banner
|
|
216
|
+
model: Model name to display in banner
|
|
217
|
+
provider: LLM provider name to display in banner
|
|
193
218
|
"""
|
|
194
219
|
thread_id = str(uuid.uuid4())
|
|
195
220
|
from .EvoScientist import MEMORY_DIR
|
|
196
221
|
memory_dir = MEMORY_DIR
|
|
197
|
-
print_banner(thread_id, workspace_dir, memory_dir)
|
|
222
|
+
print_banner(thread_id, workspace_dir, memory_dir, mode, model, provider)
|
|
198
223
|
|
|
199
224
|
history_file = str(os.path.expanduser("~/.EvoScientist_history"))
|
|
200
225
|
session = PromptSession(
|
|
@@ -272,7 +297,13 @@ def cmd_interactive(
|
|
|
272
297
|
console.print("\n[dim]Goodbye![/dim]")
|
|
273
298
|
break
|
|
274
299
|
except Exception as e:
|
|
275
|
-
|
|
300
|
+
error_msg = str(e)
|
|
301
|
+
if "authentication" in error_msg.lower() or "api_key" in error_msg.lower():
|
|
302
|
+
console.print("[red]Error: API key not configured.[/red]")
|
|
303
|
+
console.print("[dim]Run [bold]EvoSci onboard[/bold] to set up your API key.[/dim]")
|
|
304
|
+
break
|
|
305
|
+
else:
|
|
306
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
276
307
|
|
|
277
308
|
|
|
278
309
|
def cmd_run(agent: Any, prompt: str, thread_id: str | None = None, show_thinking: bool = True, workspace_dir: str | None = None) -> None:
|
|
@@ -300,8 +331,14 @@ def cmd_run(agent: Any, prompt: str, thread_id: str | None = None, show_thinking
|
|
|
300
331
|
try:
|
|
301
332
|
_run_streaming(agent, prompt, thread_id, show_thinking, interactive=False)
|
|
302
333
|
except Exception as e:
|
|
303
|
-
|
|
304
|
-
|
|
334
|
+
error_msg = str(e)
|
|
335
|
+
if "authentication" in error_msg.lower() or "api_key" in error_msg.lower():
|
|
336
|
+
console.print("[red]Error: API key not configured.[/red]")
|
|
337
|
+
console.print("[dim]Run [bold]EvoSci onboard[/bold] to set up your API key.[/dim]")
|
|
338
|
+
raise typer.Exit(1)
|
|
339
|
+
else:
|
|
340
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
341
|
+
raise
|
|
305
342
|
|
|
306
343
|
|
|
307
344
|
# =============================================================================
|
|
@@ -332,29 +369,200 @@ def _load_agent(workspace_dir: str | None = None):
|
|
|
332
369
|
|
|
333
370
|
app = typer.Typer(no_args_is_help=False, add_completion=False)
|
|
334
371
|
|
|
372
|
+
# Config subcommand group
|
|
373
|
+
config_app = typer.Typer(help="Configuration management commands", invoke_without_command=True)
|
|
374
|
+
app.add_typer(config_app, name="config")
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
# =============================================================================
|
|
378
|
+
# Onboard command
|
|
379
|
+
# =============================================================================
|
|
380
|
+
|
|
381
|
+
@app.command()
|
|
382
|
+
def onboard(
|
|
383
|
+
skip_validation: bool = typer.Option(
|
|
384
|
+
False,
|
|
385
|
+
"--skip-validation",
|
|
386
|
+
help="Skip API key validation during setup"
|
|
387
|
+
),
|
|
388
|
+
):
|
|
389
|
+
"""Interactive setup wizard for EvoScientist.
|
|
390
|
+
|
|
391
|
+
Guides you through configuring API keys, model selection,
|
|
392
|
+
workspace settings, and agent parameters.
|
|
393
|
+
"""
|
|
394
|
+
from .onboard import run_onboard
|
|
395
|
+
run_onboard(skip_validation=skip_validation)
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
# =============================================================================
|
|
399
|
+
# Config commands
|
|
400
|
+
# =============================================================================
|
|
401
|
+
|
|
402
|
+
@config_app.callback(invoke_without_command=True)
|
|
403
|
+
def config_callback(ctx: typer.Context):
|
|
404
|
+
"""Configuration management commands."""
|
|
405
|
+
if ctx.invoked_subcommand is None:
|
|
406
|
+
config_list()
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
@config_app.command("list")
|
|
410
|
+
def config_list():
|
|
411
|
+
"""List all configuration values."""
|
|
412
|
+
from .config import list_config, get_config_path
|
|
413
|
+
|
|
414
|
+
config_data = list_config()
|
|
415
|
+
|
|
416
|
+
table = Table(title="EvoScientist Configuration", show_header=True)
|
|
417
|
+
table.add_column("Setting", style="cyan")
|
|
418
|
+
table.add_column("Value")
|
|
419
|
+
|
|
420
|
+
# Mask API keys
|
|
421
|
+
def format_value(key: str, value: Any) -> str:
|
|
422
|
+
if "api_key" in key and value:
|
|
423
|
+
return "***" + str(value)[-4:] if len(str(value)) > 4 else "***"
|
|
424
|
+
if value == "":
|
|
425
|
+
return "[dim](not set)[/dim]"
|
|
426
|
+
return str(value)
|
|
427
|
+
|
|
428
|
+
for key, value in config_data.items():
|
|
429
|
+
table.add_row(key, format_value(key, value))
|
|
430
|
+
|
|
431
|
+
console.print(table)
|
|
432
|
+
console.print(f"\n[dim]Config file: {get_config_path()}[/dim]")
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@config_app.command("get")
|
|
436
|
+
def config_get(key: str = typer.Argument(..., help="Configuration key to get")):
|
|
437
|
+
"""Get a single configuration value."""
|
|
438
|
+
from .config import get_config_value
|
|
439
|
+
|
|
440
|
+
value = get_config_value(key)
|
|
441
|
+
if value is None:
|
|
442
|
+
console.print(f"[red]Unknown key: {key}[/red]")
|
|
443
|
+
raise typer.Exit(1)
|
|
444
|
+
|
|
445
|
+
# Mask API keys
|
|
446
|
+
if "api_key" in key and value:
|
|
447
|
+
display_value = "***" + str(value)[-4:] if len(str(value)) > 4 else "***"
|
|
448
|
+
elif value == "":
|
|
449
|
+
display_value = "(not set)"
|
|
450
|
+
else:
|
|
451
|
+
display_value = str(value)
|
|
452
|
+
|
|
453
|
+
console.print(f"[cyan]{key}[/cyan]: {display_value}")
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@config_app.command("set")
|
|
457
|
+
def config_set(
|
|
458
|
+
key: str = typer.Argument(..., help="Configuration key to set"),
|
|
459
|
+
value: str = typer.Argument(..., help="New value"),
|
|
460
|
+
):
|
|
461
|
+
"""Set a single configuration value."""
|
|
462
|
+
from .config import set_config_value
|
|
463
|
+
|
|
464
|
+
if set_config_value(key, value):
|
|
465
|
+
console.print(f"[green]Set {key}[/green]")
|
|
466
|
+
else:
|
|
467
|
+
console.print(f"[red]Invalid key: {key}[/red]")
|
|
468
|
+
raise typer.Exit(1)
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
@config_app.command("reset")
|
|
472
|
+
def config_reset(
|
|
473
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
474
|
+
):
|
|
475
|
+
"""Reset configuration to defaults."""
|
|
476
|
+
from .config import reset_config, get_config_path
|
|
477
|
+
|
|
478
|
+
config_path = get_config_path()
|
|
479
|
+
|
|
480
|
+
if not config_path.exists():
|
|
481
|
+
console.print("[yellow]No config file to reset.[/yellow]")
|
|
482
|
+
return
|
|
483
|
+
|
|
484
|
+
if not yes:
|
|
485
|
+
confirm = typer.confirm("Reset configuration to defaults?")
|
|
486
|
+
if not confirm:
|
|
487
|
+
console.print("[dim]Cancelled.[/dim]")
|
|
488
|
+
return
|
|
489
|
+
|
|
490
|
+
reset_config()
|
|
491
|
+
console.print("[green]Configuration reset to defaults.[/green]")
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@config_app.command("path")
|
|
495
|
+
def config_path():
|
|
496
|
+
"""Show the configuration file path."""
|
|
497
|
+
from .config import get_config_path
|
|
498
|
+
|
|
499
|
+
path = get_config_path()
|
|
500
|
+
exists = path.exists()
|
|
501
|
+
status = "[green]exists[/green]" if exists else "[dim]not created yet[/dim]"
|
|
502
|
+
console.print(f"{path} ({status})")
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
# =============================================================================
|
|
506
|
+
# Main callback (default behavior)
|
|
507
|
+
# =============================================================================
|
|
335
508
|
|
|
336
509
|
@app.callback(invoke_without_command=True)
|
|
337
510
|
def _main_callback(
|
|
338
511
|
ctx: typer.Context,
|
|
339
|
-
prompt: Optional[str] = typer.
|
|
340
|
-
interactive: bool = typer.Option(False, "-i", "--interactive", help="Interactive conversation mode"),
|
|
512
|
+
prompt: Optional[str] = typer.Option(None, "-p", "--prompt", help="Query to execute (single-shot mode)"),
|
|
341
513
|
thread_id: Optional[str] = typer.Option(None, "--thread-id", help="Thread ID for conversation persistence"),
|
|
342
514
|
no_thinking: bool = typer.Option(False, "--no-thinking", help="Disable thinking display"),
|
|
343
515
|
workdir: Optional[str] = typer.Option(None, "--workdir", help="Override workspace directory for this session"),
|
|
344
516
|
use_cwd: bool = typer.Option(False, "--use-cwd", help="Use current working directory as workspace"),
|
|
517
|
+
mode: Optional[str] = typer.Option(
|
|
518
|
+
None,
|
|
519
|
+
"--mode",
|
|
520
|
+
help="Workspace mode: 'daemon' (persistent, default) or 'run' (isolated per-session)"
|
|
521
|
+
),
|
|
345
522
|
):
|
|
346
523
|
"""EvoScientist Agent - AI-powered research & code execution CLI."""
|
|
347
|
-
|
|
348
|
-
|
|
524
|
+
# If a subcommand was invoked, don't run the default behavior
|
|
525
|
+
if ctx.invoked_subcommand is not None:
|
|
526
|
+
return
|
|
527
|
+
|
|
528
|
+
from dotenv import load_dotenv, find_dotenv # type: ignore[import-untyped]
|
|
529
|
+
# find_dotenv() traverses up the directory tree to locate .env
|
|
530
|
+
load_dotenv(find_dotenv(), override=True)
|
|
349
531
|
|
|
350
|
-
|
|
532
|
+
# Load and apply configuration
|
|
533
|
+
from .config import get_effective_config, apply_config_to_env
|
|
351
534
|
|
|
535
|
+
# Build CLI overrides dict
|
|
536
|
+
cli_overrides = {}
|
|
537
|
+
if mode:
|
|
538
|
+
cli_overrides["default_mode"] = mode
|
|
539
|
+
if workdir:
|
|
540
|
+
cli_overrides["default_workdir"] = workdir
|
|
541
|
+
if no_thinking:
|
|
542
|
+
cli_overrides["show_thinking"] = False
|
|
543
|
+
|
|
544
|
+
config = get_effective_config(cli_overrides)
|
|
545
|
+
apply_config_to_env(config)
|
|
546
|
+
|
|
547
|
+
show_thinking = config.show_thinking if not no_thinking else False
|
|
548
|
+
|
|
549
|
+
# Validate mutually exclusive options
|
|
352
550
|
if workdir and use_cwd:
|
|
353
551
|
raise typer.BadParameter("Use either --workdir or --use-cwd, not both.")
|
|
354
552
|
|
|
553
|
+
if mode and (workdir or use_cwd):
|
|
554
|
+
raise typer.BadParameter("--mode cannot be combined with --workdir or --use-cwd")
|
|
555
|
+
|
|
556
|
+
if mode and mode not in ("run", "daemon"):
|
|
557
|
+
raise typer.BadParameter("--mode must be 'run' or 'daemon'")
|
|
558
|
+
|
|
355
559
|
ensure_dirs()
|
|
356
560
|
|
|
561
|
+
# Resolve effective mode from config (CLI mode already applied via overrides)
|
|
562
|
+
effective_mode: str | None = None # None means explicit --workdir/--use-cwd was used
|
|
563
|
+
|
|
357
564
|
# Resolve workspace directory for this session
|
|
565
|
+
# Priority: --use-cwd > --workdir > --mode (explicit) > default_workdir > default_mode
|
|
358
566
|
if use_cwd:
|
|
359
567
|
workspace_dir = os.getcwd()
|
|
360
568
|
workspace_fixed = True
|
|
@@ -362,30 +570,60 @@ def _main_callback(
|
|
|
362
570
|
workspace_dir = os.path.abspath(os.path.expanduser(workdir))
|
|
363
571
|
os.makedirs(workspace_dir, exist_ok=True)
|
|
364
572
|
workspace_fixed = True
|
|
573
|
+
elif mode:
|
|
574
|
+
# Explicit --mode overrides default_workdir
|
|
575
|
+
effective_mode = mode
|
|
576
|
+
workspace_root = config.default_workdir or str(default_workspace_dir())
|
|
577
|
+
workspace_root = os.path.abspath(os.path.expanduser(workspace_root))
|
|
578
|
+
if effective_mode == "run":
|
|
579
|
+
session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
580
|
+
workspace_dir = os.path.join(workspace_root, "runs", session_id)
|
|
581
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
582
|
+
workspace_fixed = False
|
|
583
|
+
else: # daemon
|
|
584
|
+
workspace_dir = workspace_root
|
|
585
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
586
|
+
workspace_fixed = True
|
|
587
|
+
elif config.default_workdir:
|
|
588
|
+
# Use configured default workdir with configured mode
|
|
589
|
+
workspace_root = os.path.abspath(os.path.expanduser(config.default_workdir))
|
|
590
|
+
effective_mode = config.default_mode
|
|
591
|
+
if effective_mode == "run":
|
|
592
|
+
session_id = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
593
|
+
workspace_dir = os.path.join(workspace_root, "runs", session_id)
|
|
594
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
595
|
+
workspace_fixed = False
|
|
596
|
+
else: # daemon
|
|
597
|
+
workspace_dir = workspace_root
|
|
598
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
599
|
+
workspace_fixed = True
|
|
365
600
|
else:
|
|
366
|
-
|
|
367
|
-
|
|
601
|
+
effective_mode = config.default_mode
|
|
602
|
+
if effective_mode == "run":
|
|
603
|
+
workspace_dir = _create_session_workspace()
|
|
604
|
+
workspace_fixed = False
|
|
605
|
+
else: # daemon mode (default)
|
|
606
|
+
workspace_dir = str(default_workspace_dir())
|
|
607
|
+
os.makedirs(workspace_dir, exist_ok=True)
|
|
608
|
+
workspace_fixed = True
|
|
368
609
|
|
|
369
610
|
# Load agent with session workspace
|
|
370
611
|
console.print("[dim]Loading agent...[/dim]")
|
|
371
612
|
agent = _load_agent(workspace_dir=workspace_dir)
|
|
372
613
|
|
|
373
|
-
if
|
|
374
|
-
|
|
375
|
-
agent,
|
|
376
|
-
show_thinking=show_thinking,
|
|
377
|
-
workspace_dir=workspace_dir,
|
|
378
|
-
workspace_fixed=workspace_fixed,
|
|
379
|
-
)
|
|
380
|
-
elif prompt:
|
|
614
|
+
if prompt:
|
|
615
|
+
# Single-shot mode: execute query and exit
|
|
381
616
|
cmd_run(agent, prompt, thread_id=thread_id, show_thinking=show_thinking, workspace_dir=workspace_dir)
|
|
382
617
|
else:
|
|
383
|
-
#
|
|
618
|
+
# Interactive mode (default)
|
|
384
619
|
cmd_interactive(
|
|
385
620
|
agent,
|
|
386
621
|
show_thinking=show_thinking,
|
|
387
622
|
workspace_dir=workspace_dir,
|
|
388
623
|
workspace_fixed=workspace_fixed,
|
|
624
|
+
mode=effective_mode,
|
|
625
|
+
model=config.model,
|
|
626
|
+
provider=config.provider,
|
|
389
627
|
)
|
|
390
628
|
|
|
391
629
|
|
|
@@ -419,6 +657,9 @@ def _configure_logging():
|
|
|
419
657
|
|
|
420
658
|
def main():
|
|
421
659
|
"""CLI entry point — delegates to the Typer app."""
|
|
660
|
+
import warnings
|
|
661
|
+
warnings.filterwarnings("ignore", message=".*not known to support tools.*")
|
|
662
|
+
warnings.filterwarnings("ignore", message=".*type is unknown and inference may fail.*")
|
|
422
663
|
_configure_logging()
|
|
423
664
|
app()
|
|
424
665
|
|