acra-cli 0.1.1__py3-none-any.whl
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.
- acra/__init__.py +7 -0
- acra/__main__.py +4 -0
- acra/agents/__init__.py +0 -0
- acra/agents/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/__pycache__/llm.cpython-312.pyc +0 -0
- acra/agents/__pycache__/llm_utils.cpython-312.pyc +0 -0
- acra/agents/coder/__init__.py +0 -0
- acra/agents/coder/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/coder/__pycache__/coder_agent.cpython-312.pyc +0 -0
- acra/agents/coder/__pycache__/coder_chain.cpython-312.pyc +0 -0
- acra/agents/coder/coder_agent.py +235 -0
- acra/agents/coder/coder_chain.py +204 -0
- acra/agents/critic/__init__.py +0 -0
- acra/agents/critic/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/critic/__pycache__/critic_agent.cpython-312.pyc +0 -0
- acra/agents/critic/__pycache__/critic_chain.cpython-312.pyc +0 -0
- acra/agents/critic/critic_agent.py +199 -0
- acra/agents/critic/critic_chain.py +268 -0
- acra/agents/executor/__init__.py +0 -0
- acra/agents/executor/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/executor/__pycache__/docker_runner.cpython-312.pyc +0 -0
- acra/agents/executor/__pycache__/executor_agent.cpython-312.pyc +0 -0
- acra/agents/executor/__pycache__/sandbox_runner.cpython-312.pyc +0 -0
- acra/agents/executor/docker_runner.py +114 -0
- acra/agents/executor/executor_agent.py +142 -0
- acra/agents/executor/sandbox_runner.py +144 -0
- acra/agents/human/__init__.py +0 -0
- acra/agents/human/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/human/__pycache__/human_node.cpython-312.pyc +0 -0
- acra/agents/human/human_node.py +37 -0
- acra/agents/llm.py +263 -0
- acra/agents/llm_utils.py +161 -0
- acra/agents/memory/__init__.py +0 -0
- acra/agents/memory/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/memory/__pycache__/memory_agent.cpython-312.pyc +0 -0
- acra/agents/memory/__pycache__/memory_manager.cpython-312.pyc +0 -0
- acra/agents/memory/__pycache__/retrieval.cpython-312.pyc +0 -0
- acra/agents/memory/memory_agent.py +239 -0
- acra/agents/memory/memory_manager.py +273 -0
- acra/agents/memory/retrieval.py +355 -0
- acra/agents/planner/__init__.py +0 -0
- acra/agents/planner/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/planner/__pycache__/planner_agent.cpython-312.pyc +0 -0
- acra/agents/planner/__pycache__/planner_chain.cpython-312.pyc +0 -0
- acra/agents/planner/planner_agent.py +97 -0
- acra/agents/planner/planner_chain.py +160 -0
- acra/agents/researcher/__init__.py +1 -0
- acra/agents/researcher/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/agents/researcher/__pycache__/researcher_agent.cpython-312.pyc +0 -0
- acra/agents/researcher/__pycache__/researcher_chain.cpython-312.pyc +0 -0
- acra/agents/researcher/researcher_agent.py +231 -0
- acra/agents/researcher/researcher_chain.py +193 -0
- acra/brain/__init__.py +6 -0
- acra/brain/model_registry.py +19 -0
- acra/brain/provider_manager.py +21 -0
- acra/cli.py +52 -0
- acra/commands/__init__.py +29 -0
- acra/commands/ask.py +49 -0
- acra/commands/brain.py +58 -0
- acra/commands/config.py +25 -0
- acra/commands/context.py +30 -0
- acra/commands/graph.py +18 -0
- acra/commands/keys.py +40 -0
- acra/commands/logs.py +13 -0
- acra/commands/memory.py +27 -0
- acra/commands/plugin.py +18 -0
- acra/commands/research.py +65 -0
- acra/commands/serve.py +13 -0
- acra/commands/session.py +20 -0
- acra/commands/utils.py +12 -0
- acra/config/__init__.py +36 -0
- acra/config/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/config/__pycache__/defaults.cpython-312.pyc +0 -0
- acra/config/__pycache__/profile_manager.cpython-312.pyc +0 -0
- acra/config/defaults.py +88 -0
- acra/config/profile_manager.py +87 -0
- acra/execution/__init__.py +1 -0
- acra/execution/logs/__init__.py +1 -0
- acra/execution/logs/error_logs/__init__.py +1 -0
- acra/execution/logs/execution_logs/__init__.py +1 -0
- acra/execution/sandbox/__init__.py +1 -0
- acra/execution/sandbox/docker_executor.py +209 -0
- acra/execution/sandbox/isolated_runner.py +148 -0
- acra/execution/sandbox/sandbox_manager.py +178 -0
- acra/graph/__init__.py +0 -0
- acra/graph/checkpoint.py +85 -0
- acra/graph/conditional_edges.py +103 -0
- acra/graph/edges.py +85 -0
- acra/graph/graph_visualizer.py +175 -0
- acra/graph/nodes.py +68 -0
- acra/graph/router.py +69 -0
- acra/graph/state.py +93 -0
- acra/graph/workflow.py +117 -0
- acra/memory/__init__.py +1 -0
- acra/memory/checkpoints/__init__.py +1 -0
- acra/memory/checkpoints/data/__init__.py +1 -0
- acra/memory/checkpoints/postgres_checkpoint.py +247 -0
- acra/memory/checkpoints/sqlite_checkpoint.py +309 -0
- acra/memory/chroma_db/__init__.py +1 -0
- acra/memory/conversation_memory/__init__.py +1 -0
- acra/memory/conversation_memory/long_term.py +229 -0
- acra/memory/conversation_memory/short_term.py +158 -0
- acra/memory/storage/__init__.py +1 -0
- acra/memory/vector_store/__init__.py +0 -0
- acra/memory/vector_store/chroma_store.py +260 -0
- acra/memory/vector_store/embeddings.py +43 -0
- acra/observability/__init__.py +1 -0
- acra/observability/langsmith_tracing.py +91 -0
- acra/observability/metrics.py +189 -0
- acra/observability/monitoring.py +162 -0
- acra/observability/token_tracking.py +131 -0
- acra/prompts/__init__.py +1 -0
- acra/schemas/__init__.py +0 -0
- acra/schemas/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/coder_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/critic_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/execution_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/planner_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/researcher_schema.cpython-312.pyc +0 -0
- acra/schemas/__pycache__/shared_schema.cpython-312.pyc +0 -0
- acra/schemas/coder_schema.py +257 -0
- acra/schemas/critic_schema.py +177 -0
- acra/schemas/execution_schema.py +74 -0
- acra/schemas/planner_schema.py +129 -0
- acra/schemas/researcher_schema.py +220 -0
- acra/schemas/shared_schema.py +329 -0
- acra/tools/__init__.py +1 -0
- acra/tools/code_tools/__init__.py +1 -0
- acra/tools/code_tools/file_reader.py +156 -0
- acra/tools/code_tools/file_writer.py +108 -0
- acra/tools/code_tools/python_repl.py +72 -0
- acra/tools/code_tools/terminal_runner.py +98 -0
- acra/tools/github_tools/__init__.py +1 -0
- acra/tools/github_tools/commit_generator.py +91 -0
- acra/tools/github_tools/github_search.py +113 -0
- acra/tools/github_tools/repo_analyzer.py +138 -0
- acra/tools/integration_test_helper.py +370 -0
- acra/tools/validation_tools/__init__.py +1 -0
- acra/tools/validation_tools/dependency_checker.py +101 -0
- acra/tools/validation_tools/environment_config_validator.py +353 -0
- acra/tools/validation_tools/http_validator.py +336 -0
- acra/tools/validation_tools/response_validator.py +407 -0
- acra/tools/validation_tools/security_checker.py +93 -0
- acra/tools/validation_tools/syntax_checker.py +75 -0
- acra/tools/validation_tools/web_framework_validator.py +382 -0
- acra/tools/web_tools/__init__.py +1 -0
- acra/tools/web_tools/arxiv_search.py +110 -0
- acra/tools/web_tools/serpapi_search.py +106 -0
- acra/tools/web_tools/tavily_search.py +96 -0
- acra/ui/__init__.py +8 -0
- acra/ui/__pycache__/__init__.cpython-312.pyc +0 -0
- acra/ui/__pycache__/banner.cpython-312.pyc +0 -0
- acra/ui/__pycache__/components.cpython-312.pyc +0 -0
- acra/ui/__pycache__/shell.cpython-312.pyc +0 -0
- acra/ui/__pycache__/theme.cpython-312.pyc +0 -0
- acra/ui/banner.py +40 -0
- acra/ui/components.py +32 -0
- acra/ui/shell.py +91 -0
- acra/ui/theme.py +28 -0
- acra/utils/__init__.py +21 -0
- acra/utils/context_manager.py +20 -0
- acra/utils/keyring_manager.py +83 -0
- acra/utils/output_formatter.py +18 -0
- acra/utils/session_manager.py +59 -0
- acra_cli-0.1.1.dist-info/METADATA +616 -0
- acra_cli-0.1.1.dist-info/RECORD +169 -0
- acra_cli-0.1.1.dist-info/WHEEL +5 -0
- acra_cli-0.1.1.dist-info/licenses/LICENSE +661 -0
- acra_cli-0.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Brain provider management utilities for acra."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ProviderManager:
|
|
9
|
+
"""Stub provider manager for brain commands."""
|
|
10
|
+
|
|
11
|
+
def __init__(self) -> None:
|
|
12
|
+
self.providers: dict[str, dict[str, Any]] = {}
|
|
13
|
+
|
|
14
|
+
def add_provider(self, name: str, config: dict[str, Any]) -> None:
|
|
15
|
+
self.providers[name] = config
|
|
16
|
+
|
|
17
|
+
def get_provider(self, name: str) -> dict[str, Any] | None:
|
|
18
|
+
return self.providers.get(name)
|
|
19
|
+
|
|
20
|
+
def list_providers(self) -> list[str]:
|
|
21
|
+
return list(self.providers)
|
acra/cli.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""acra CLI entrypoint."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from acra.commands import (
|
|
6
|
+
serve_app,
|
|
7
|
+
config_app,
|
|
8
|
+
keys_app,
|
|
9
|
+
research_app,
|
|
10
|
+
memory_app,
|
|
11
|
+
session_app,
|
|
12
|
+
graph_app,
|
|
13
|
+
utils_app,
|
|
14
|
+
)
|
|
15
|
+
from acra.ui.shell import launch_shell
|
|
16
|
+
|
|
17
|
+
app = typer.Typer(add_completion=True)
|
|
18
|
+
|
|
19
|
+
app.add_typer(serve_app, name="serve")
|
|
20
|
+
app.add_typer(config_app, name="config")
|
|
21
|
+
app.add_typer(keys_app, name="keys")
|
|
22
|
+
app.add_typer(research_app, name="research")
|
|
23
|
+
app.add_typer(memory_app, name="memory")
|
|
24
|
+
app.add_typer(session_app, name="session")
|
|
25
|
+
app.add_typer(graph_app, name="graph")
|
|
26
|
+
app.add_typer(utils_app, name="workspace")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def app_main() -> None:
|
|
30
|
+
"""Run the acra CLI."""
|
|
31
|
+
app(prog_name="acra")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@app.callback(invoke_without_command=True)
|
|
35
|
+
def main(
|
|
36
|
+
ctx: typer.Context,
|
|
37
|
+
profile: str = typer.Option(None, "--profile", help="Profile to use."),
|
|
38
|
+
workspace: str = typer.Option(None, "--workspace", help="Override workspace path."),
|
|
39
|
+
no_memory: bool = typer.Option(False, "--no-memory", help="Run without memory."),
|
|
40
|
+
dry_run: bool = typer.Option(False, "--dry-run", help="Display planned actions without executing."),
|
|
41
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON-formatted results."),
|
|
42
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose logging."),
|
|
43
|
+
quiet: bool = typer.Option(False, "--quiet", "-q", help="Suppress output."),
|
|
44
|
+
timeout: int = typer.Option(0, "--timeout", help="Override execution timeout in seconds."),
|
|
45
|
+
):
|
|
46
|
+
"""acra: Agentic CLI for LLM powered task execution and research workflows."""
|
|
47
|
+
if ctx.invoked_subcommand is None:
|
|
48
|
+
launch_shell(profile=profile, workspace=workspace)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
if __name__ == "__main__":
|
|
52
|
+
app_main()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""acra command modules."""
|
|
2
|
+
|
|
3
|
+
from .serve import app as serve_app
|
|
4
|
+
from .config import app as config_app
|
|
5
|
+
from .brain import app as brain_app
|
|
6
|
+
from .research import app as research_app
|
|
7
|
+
from .context import app as context_app
|
|
8
|
+
from .memory import app as memory_app
|
|
9
|
+
from .session import app as session_app
|
|
10
|
+
from .keys import app as keys_app
|
|
11
|
+
from .logs import app as logs_app
|
|
12
|
+
from .graph import app as graph_app
|
|
13
|
+
from .plugin import app as plugin_app
|
|
14
|
+
from .utils import app as utils_app
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"serve_app",
|
|
18
|
+
"config_app",
|
|
19
|
+
"brain_app",
|
|
20
|
+
"research_app",
|
|
21
|
+
"context_app",
|
|
22
|
+
"memory_app",
|
|
23
|
+
"session_app",
|
|
24
|
+
"keys_app",
|
|
25
|
+
"logs_app",
|
|
26
|
+
"graph_app",
|
|
27
|
+
"plugin_app",
|
|
28
|
+
"utils_app",
|
|
29
|
+
]
|
acra/commands/ask.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Agent task commands for acra."""
|
|
2
|
+
|
|
3
|
+
import uuid
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from acra.graph.workflow import OmniAgentCallbacks, omniagent_graph
|
|
7
|
+
from acra.ui.components import render_panel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _run_task(task: str, task_label: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
11
|
+
state = {
|
|
12
|
+
"user_request": task,
|
|
13
|
+
"task_label": task_label,
|
|
14
|
+
"no_memory": no_memory,
|
|
15
|
+
"profile": profile,
|
|
16
|
+
}
|
|
17
|
+
result = omniagent_graph.invoke(state, config={"callbacks": [OmniAgentCallbacks()]})
|
|
18
|
+
render_panel(result, title=task_label)
|
|
19
|
+
return result
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def ask(task: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
23
|
+
"""Ask the assistant a question."""
|
|
24
|
+
return _run_task(task, "ask", profile, no_memory)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def build(task: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
28
|
+
"""Run a build workflow for a project task."""
|
|
29
|
+
return _run_task(task, "build", profile, no_memory)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def fix(task: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
33
|
+
"""Run a fix workflow for a code issue."""
|
|
34
|
+
return _run_task(task, "fix", profile, no_memory)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def review(task: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
38
|
+
"""Review code or design with the critic pipeline."""
|
|
39
|
+
return _run_task(task, "review", profile, no_memory)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def explain(task: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
43
|
+
"""Explain a technical concept or code path."""
|
|
44
|
+
return _run_task(task, "explain", profile, no_memory)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def run(task: str, profile: Optional[str] = None, no_memory: bool = False):
|
|
48
|
+
"""Execute a task using the executor agent."""
|
|
49
|
+
return _run_task(task, "run", profile, no_memory)
|
acra/commands/brain.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Brain management commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from acra.brain.provider_manager import ProviderManager
|
|
7
|
+
from acra.brain.model_registry import ModelRegistry
|
|
8
|
+
from acra.config.profile_manager import ProfileManager
|
|
9
|
+
from acra.ui.components import render_panel
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(help="Brain management commands for acra.")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command("add")
|
|
15
|
+
def add_brain(name: str = typer.Argument(..., help="Brain name to add."), provider: str = typer.Option(..., help="LLM provider to associate.")):
|
|
16
|
+
"""Add a new brain profile."""
|
|
17
|
+
manager = ProfileManager()
|
|
18
|
+
profile = manager.load_profile()
|
|
19
|
+
profile.setdefault("brains", {})[name] = {"provider": provider}
|
|
20
|
+
manager.save_profile(profile_name=profile.get("name", "default"), profile_data=profile)
|
|
21
|
+
render_panel(f"Added brain '{name}' using provider {provider}.")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@app.command("use")
|
|
25
|
+
def use_brain(name: str = typer.Argument(..., help="Brain name to activate.")):
|
|
26
|
+
"""Switch to a saved brain."""
|
|
27
|
+
profile = ProfileManager().load_profile()
|
|
28
|
+
if name not in profile.get("brains", {}):
|
|
29
|
+
raise typer.BadParameter(f"Brain not found: {name}")
|
|
30
|
+
profile["active_brain"] = name
|
|
31
|
+
ProfileManager().save_profile(profile_name=profile.get("name", "default"), profile_data=profile)
|
|
32
|
+
render_panel(f"Using brain '{name}'.")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@app.command("list")
|
|
36
|
+
def list_brains():
|
|
37
|
+
"""List configured brains."""
|
|
38
|
+
profile = ProfileManager().load_profile()
|
|
39
|
+
brains = profile.get("brains", {})
|
|
40
|
+
if not brains:
|
|
41
|
+
render_panel("No brains configured.")
|
|
42
|
+
return
|
|
43
|
+
rows = [{"name": name, "status": "active" if name == profile.get("active_brain") else "inactive", "value": brain["provider"]} for name, brain in brains.items()]
|
|
44
|
+
render_panel(rows, title="Brains")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@app.command("test")
|
|
48
|
+
def test_brain(name: str = typer.Argument(..., help="Brain name to test.")):
|
|
49
|
+
"""Test a brain configuration."""
|
|
50
|
+
render_panel(f"Tested brain '{name}'. (stubbed)")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@app.command("models")
|
|
54
|
+
def list_models(provider: Optional[str] = typer.Option(None, help="Provider to list models for.")):
|
|
55
|
+
"""List available models for a provider."""
|
|
56
|
+
registry = ModelRegistry()
|
|
57
|
+
choices = registry.list_models(provider)
|
|
58
|
+
render_panel(choices, title=f"Models for {provider or 'all providers'}")
|
acra/commands/config.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Configuration and initialization commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from acra.config.profile_manager import ProfileManager
|
|
7
|
+
from acra.ui.components import render_message
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Configuration commands for acra.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("init")
|
|
13
|
+
def init(profile: Optional[str] = typer.Option(None, help="Profile name to create")):
|
|
14
|
+
"""Run first-time setup and save a config profile."""
|
|
15
|
+
manager = ProfileManager()
|
|
16
|
+
profile_name = manager.run_wizard(profile_name=profile)
|
|
17
|
+
render_message(f"Created profile: {profile_name}")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@app.command("show")
|
|
21
|
+
def show(profile: Optional[str] = typer.Option(None, help="Profile name to display")):
|
|
22
|
+
"""Show the active profile configuration."""
|
|
23
|
+
manager = ProfileManager()
|
|
24
|
+
config = manager.load_profile(profile)
|
|
25
|
+
render_message(str(config))
|
acra/commands/context.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Context management commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
from acra.utils.context_manager import ContextManager
|
|
7
|
+
from acra.ui.components import render_panel
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Context management commands for acra.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("add")
|
|
13
|
+
def add_context(item: str = typer.Argument(..., help="Context item to add.")):
|
|
14
|
+
"""Add a context item."""
|
|
15
|
+
ContextManager().add(item)
|
|
16
|
+
render_panel(f"Added context: {item}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@app.command("list")
|
|
20
|
+
def list_context():
|
|
21
|
+
"""List stored context items."""
|
|
22
|
+
items = ContextManager().list()
|
|
23
|
+
render_panel(items, title="Context")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app.command("clear")
|
|
27
|
+
def clear_context():
|
|
28
|
+
"""Clear all stored context."""
|
|
29
|
+
ContextManager().clear()
|
|
30
|
+
render_panel("Context cleared.")
|
acra/commands/graph.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Graph utility commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from acra.ui.components import render_panel
|
|
5
|
+
|
|
6
|
+
app = typer.Typer(help="Graph commands for acra.")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.command("show")
|
|
10
|
+
def show_graph():
|
|
11
|
+
"""Show the workflow graph structure."""
|
|
12
|
+
render_panel("Graph visualization is not implemented yet.")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.command("run")
|
|
16
|
+
def run_graph():
|
|
17
|
+
"""Run the workflow graph directly."""
|
|
18
|
+
render_panel("Graph run not implemented yet.")
|
acra/commands/keys.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""Key management commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from acra.utils.keyring_manager import (
|
|
7
|
+
set_key,
|
|
8
|
+
get_key_status,
|
|
9
|
+
delete_key,
|
|
10
|
+
list_keys,
|
|
11
|
+
)
|
|
12
|
+
from acra.ui.components import render_panel
|
|
13
|
+
|
|
14
|
+
app = typer.Typer(help="Key management commands for acra.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command("set")
|
|
18
|
+
def set_key_cmd(
|
|
19
|
+
name: str = typer.Argument(..., help="Key name, e.g. provider or research.github"),
|
|
20
|
+
value: Optional[str] = typer.Argument(None, help="API key value. If omitted, you will be prompted."),
|
|
21
|
+
):
|
|
22
|
+
"""Set a provider or research API key."""
|
|
23
|
+
if value is None:
|
|
24
|
+
value = typer.prompt("Enter API key", hide_input=True)
|
|
25
|
+
set_key(name, value)
|
|
26
|
+
render_panel(f"Key set: {name}")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@app.command("list")
|
|
30
|
+
def list_key_cmd():
|
|
31
|
+
"""List configured API keys."""
|
|
32
|
+
rows = list_keys()
|
|
33
|
+
render_panel(rows, title="Configured Keys")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@app.command("delete")
|
|
37
|
+
def delete_key_cmd(name: str = typer.Argument(..., help="Key name to delete.")):
|
|
38
|
+
"""Delete a configured API key."""
|
|
39
|
+
delete_key(name)
|
|
40
|
+
render_panel(f"Deleted key: {name}")
|
acra/commands/logs.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Logging commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
|
|
5
|
+
from acra.ui.components import render_panel
|
|
6
|
+
|
|
7
|
+
app = typer.Typer(help="Logging commands for acra.")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@app.command("show")
|
|
11
|
+
def show_logs(limit: int = typer.Option(10, help="Number of log entries to show.")):
|
|
12
|
+
"""Show recent log entries."""
|
|
13
|
+
render_panel([{"timestamp": "2024-01-01T00:00:00Z", "message": "Placeholder log entry."}], title=f"Last {limit} logs")
|
acra/commands/memory.py
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Memory commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from acra.utils.keyring_manager import get_key_status
|
|
7
|
+
from acra.ui.components import render_panel
|
|
8
|
+
|
|
9
|
+
app = typer.Typer(help="Memory commands for acra.")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@app.command("list")
|
|
13
|
+
def list_memory():
|
|
14
|
+
"""List memory entries."""
|
|
15
|
+
render_panel("Memory listing not implemented yet.")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@app.command("clear")
|
|
19
|
+
def clear_memory():
|
|
20
|
+
"""Clear memory entries."""
|
|
21
|
+
render_panel("Memory cleared.")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@app.command("search")
|
|
25
|
+
def search_memory(query: str = typer.Argument(..., help="Search query.")):
|
|
26
|
+
"""Search memory using semantic search."""
|
|
27
|
+
render_panel(f"Search results for: {query}")
|
acra/commands/plugin.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Plugin commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from acra.ui.components import render_panel
|
|
5
|
+
|
|
6
|
+
app = typer.Typer(help="Plugin commands for acra.")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.command("list")
|
|
10
|
+
def list_plugins():
|
|
11
|
+
"""List installed plugins."""
|
|
12
|
+
render_panel("No plugins installed.")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.command("add")
|
|
16
|
+
def add_plugin(name: str = typer.Argument(..., help="Plugin name to add.")):
|
|
17
|
+
"""Add a plugin."""
|
|
18
|
+
render_panel(f"Plugin {name} added. (stubbed)")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Research command module for acra."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import typer
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
from acra.graph.workflow import OmniAgentCallbacks, create_workflow
|
|
8
|
+
from acra.config.profile_manager import ProfileManager
|
|
9
|
+
from acra.utils.output_formatter import format_research_report
|
|
10
|
+
from acra.utils.keyring_manager import get_research_key_status
|
|
11
|
+
from acra.ui.components import render_panel
|
|
12
|
+
|
|
13
|
+
app = typer.Typer(help="Research commands for acra.")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load_profile(profile: Optional[str]):
|
|
17
|
+
manager = ProfileManager()
|
|
18
|
+
return manager.load_profile(profile)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@app.command()
|
|
22
|
+
def research(
|
|
23
|
+
query: str = typer.Argument(..., help="The research topic or question."),
|
|
24
|
+
depth: str = typer.Option("standard", help="Research depth: shallow, standard, deep."),
|
|
25
|
+
sources: str = typer.Option("all", help="Comma-separated sources to use."),
|
|
26
|
+
format: str = typer.Option("citations", help="Output format: citations, summary, detailed."),
|
|
27
|
+
output: Optional[str] = typer.Option(None, help="Write research output to a file."),
|
|
28
|
+
save: bool = typer.Option(False, help="Persist research output into memory."),
|
|
29
|
+
follow_up: bool = typer.Option(False, help="Keep the session open for follow-up questions."),
|
|
30
|
+
no_memory: bool = typer.Option(False, help="Skip memory persistence for this research."),
|
|
31
|
+
profile: Optional[str] = typer.Option(None, help="Profile to use."),
|
|
32
|
+
json_output: bool = typer.Option(False, "--json", help="Output JSON instead of rich text."),
|
|
33
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed debug output."),
|
|
34
|
+
):
|
|
35
|
+
"""Run a standalone research workflow using the Researcher agent."""
|
|
36
|
+
config = _load_profile(profile)
|
|
37
|
+
source_list = [s.strip() for s in sources.split(",") if s.strip()]
|
|
38
|
+
if not source_list:
|
|
39
|
+
source_list = ["all"]
|
|
40
|
+
|
|
41
|
+
# Minimal research subgraph under the researcher agent.
|
|
42
|
+
workflow = create_workflow()
|
|
43
|
+
state = {
|
|
44
|
+
"user_request": query,
|
|
45
|
+
"research_depth": depth,
|
|
46
|
+
"research_sources": source_list,
|
|
47
|
+
"follow_up": follow_up,
|
|
48
|
+
"save_to_memory": save and not no_memory,
|
|
49
|
+
"profile": profile,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
result = workflow.invoke(state, config={"callbacks": [OmniAgentCallbacks()]})
|
|
53
|
+
|
|
54
|
+
report = format_research_report(result, output_format=format)
|
|
55
|
+
|
|
56
|
+
if output:
|
|
57
|
+
with open(output, "w", encoding="utf-8") as f:
|
|
58
|
+
if output.endswith(".json"):
|
|
59
|
+
json.dump(report, f, indent=2)
|
|
60
|
+
else:
|
|
61
|
+
f.write(str(report))
|
|
62
|
+
|
|
63
|
+
render_panel(report, title="Research Results")
|
|
64
|
+
if json_output:
|
|
65
|
+
typer.echo(json.dumps(report, indent=2))
|
acra/commands/serve.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Interactive shell command for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from acra.ui.shell import launch_shell
|
|
5
|
+
|
|
6
|
+
app = typer.Typer(help="Interactive shell for acra.", invoke_without_command=True)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.callback()
|
|
10
|
+
def serve(ctx: typer.Context):
|
|
11
|
+
"""Launch the interactive acra shell."""
|
|
12
|
+
if ctx.invoked_subcommand is None:
|
|
13
|
+
launch_shell()
|
acra/commands/session.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Session commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from acra.ui.components import render_panel
|
|
7
|
+
|
|
8
|
+
app = typer.Typer(help="Session commands for acra.")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@app.command("list")
|
|
12
|
+
def list_sessions():
|
|
13
|
+
"""List saved sessions."""
|
|
14
|
+
render_panel("No sessions found.")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command("resume")
|
|
18
|
+
def resume_session(session_id: str = typer.Argument(..., help="Session ID to resume.")):
|
|
19
|
+
"""Resume a saved session."""
|
|
20
|
+
render_panel(f"Resuming session {session_id}")
|
acra/commands/utils.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""General utility commands for acra."""
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from acra.ui.components import render_panel
|
|
5
|
+
|
|
6
|
+
app = typer.Typer(help="Utility commands for acra.")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@app.command()
|
|
10
|
+
def workspace():
|
|
11
|
+
"""Show the current workspace path and status."""
|
|
12
|
+
render_panel("Workspace utilities are not implemented yet.")
|
acra/config/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""acra configuration package."""
|
|
2
|
+
|
|
3
|
+
from .defaults import *
|
|
4
|
+
from .profile_manager import ProfileManager
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"ProfileManager",
|
|
8
|
+
"PROJECT_ROOT",
|
|
9
|
+
"USER_DATA_DIR",
|
|
10
|
+
"GENERATED_PROJECT_DIR",
|
|
11
|
+
"MEMORY_STORAGE_DIR",
|
|
12
|
+
"CHROMA_DB_PATH",
|
|
13
|
+
"CHECKPOINT_DIR",
|
|
14
|
+
"SQLITE_DB_PATH",
|
|
15
|
+
"LLM_PROVIDER",
|
|
16
|
+
"LLM_TEMPERATURE",
|
|
17
|
+
"GEMINI_MODEL",
|
|
18
|
+
"GEMINI_API_KEY",
|
|
19
|
+
"OPENAI_MODEL",
|
|
20
|
+
"OPENAI_API_KEY",
|
|
21
|
+
"GROQ_MODEL",
|
|
22
|
+
"GROQ_API_KEY",
|
|
23
|
+
"OLLAMA_MODEL",
|
|
24
|
+
"OLLAMA_BASE_URL",
|
|
25
|
+
"HF_MODEL",
|
|
26
|
+
"HF_API_KEY",
|
|
27
|
+
"HF_DEVICE",
|
|
28
|
+
"HF_LOCAL_REPO",
|
|
29
|
+
"MAX_RETRIES",
|
|
30
|
+
"EXECUTION_TIMEOUT",
|
|
31
|
+
"CHECKPOINT_BACKEND",
|
|
32
|
+
"MEMORY_MAX_ENTRIES",
|
|
33
|
+
"SHORT_TERM_MEM_LIMIT",
|
|
34
|
+
"MEMORY_LOG_TRUNCATE",
|
|
35
|
+
"EMBEDDING_MODEL",
|
|
36
|
+
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
acra/config/defaults.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
OmniAgent central configuration.
|
|
3
|
+
All hardcoded constants live here. Import from this module everywhere.
|
|
4
|
+
"""
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
try:
|
|
8
|
+
from dotenv import load_dotenv
|
|
9
|
+
except ImportError:
|
|
10
|
+
def load_dotenv():
|
|
11
|
+
return False
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from platformdirs import user_data_dir
|
|
15
|
+
except ImportError:
|
|
16
|
+
user_data_dir = None
|
|
17
|
+
|
|
18
|
+
load_dotenv()
|
|
19
|
+
|
|
20
|
+
# Project root
|
|
21
|
+
PROJECT_ROOT = Path(__file__).resolve().parent
|
|
22
|
+
|
|
23
|
+
# User data directory — resolves to the right place per OS:
|
|
24
|
+
# Linux: ~/.local/share/omniagent
|
|
25
|
+
# macOS: ~/Library/Application Support/omniagent
|
|
26
|
+
# Windows: C:\Users\<you>\AppData\Local\omniagent\omniagent
|
|
27
|
+
def _default_user_data_dir() -> str:
|
|
28
|
+
if user_data_dir is not None:
|
|
29
|
+
return user_data_dir("omniagent", "omniagent")
|
|
30
|
+
return str(Path.home() / ".local" / "share" / "omniagent")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
USER_DATA_DIR = Path(
|
|
34
|
+
os.getenv("OMNIAGENT_DATA_DIR") or _default_user_data_dir()
|
|
35
|
+
).expanduser().resolve()
|
|
36
|
+
|
|
37
|
+
# Paths
|
|
38
|
+
GENERATED_PROJECT_DIR = USER_DATA_DIR / "projects"
|
|
39
|
+
MEMORY_STORAGE_DIR = USER_DATA_DIR / "memory" / "storage"
|
|
40
|
+
CHROMA_DB_PATH = USER_DATA_DIR / "memory" / "chroma_db"
|
|
41
|
+
CHECKPOINT_DIR = USER_DATA_DIR / "memory" / "checkpoints" / "data"
|
|
42
|
+
SQLITE_DB_PATH = CHECKPOINT_DIR / "workflow_checkpoints.db"
|
|
43
|
+
|
|
44
|
+
# Ensure directories exist
|
|
45
|
+
for _dir in [GENERATED_PROJECT_DIR, MEMORY_STORAGE_DIR, CHROMA_DB_PATH, CHECKPOINT_DIR]:
|
|
46
|
+
_dir.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
|
|
48
|
+
# LLM Configuration
|
|
49
|
+
# Provider selection: "gemini", "openai", "groq", "ollama", "huggingface_local", "huggingface_cloud"
|
|
50
|
+
LLM_PROVIDER = os.getenv("LLM_PROVIDER", "gemini")
|
|
51
|
+
LLM_TEMPERATURE = float(os.getenv("LLM_TEMPERATURE", "0.6"))
|
|
52
|
+
|
|
53
|
+
# Google Gemini
|
|
54
|
+
GEMINI_MODEL = os.getenv("GEMINI_MODEL", "gemini-2.5-flash")
|
|
55
|
+
GEMINI_API_KEY = os.getenv("GOOGLE_GEMINI_API_KEY", "")
|
|
56
|
+
|
|
57
|
+
# OpenAI
|
|
58
|
+
OPENAI_MODEL = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
|
|
59
|
+
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
|
|
60
|
+
|
|
61
|
+
# Groq
|
|
62
|
+
GROQ_MODEL = os.getenv("GROQ_MODEL", "llama-3.3-70b-versatile")
|
|
63
|
+
GROQ_API_KEY = os.getenv("GROQ_API_KEY", "")
|
|
64
|
+
|
|
65
|
+
# Ollama (local inference)
|
|
66
|
+
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "mistral")
|
|
67
|
+
OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
|
|
68
|
+
|
|
69
|
+
# HuggingFace
|
|
70
|
+
HF_MODEL = os.getenv("HF_MODEL", "mistralai/Mistral-7B-Instruct-v0.1")
|
|
71
|
+
HF_API_KEY = os.getenv("HF_API_KEY", "")
|
|
72
|
+
HF_DEVICE = os.getenv("HF_DEVICE", "cpu") # "cpu" or "cuda"
|
|
73
|
+
HF_LOCAL_REPO = str(Path(os.getenv("HF_LOCAL_REPO", str(USER_DATA_DIR / "hf_models"))).expanduser())
|
|
74
|
+
|
|
75
|
+
# Workflow limits
|
|
76
|
+
MAX_RETRIES = 5
|
|
77
|
+
EXECUTION_TIMEOUT = 60 # seconds
|
|
78
|
+
|
|
79
|
+
# Checkpointing
|
|
80
|
+
CHECKPOINT_BACKEND = os.getenv("CHECKPOINT_BACKEND", "sqlite")
|
|
81
|
+
|
|
82
|
+
# Memory
|
|
83
|
+
MEMORY_MAX_ENTRIES = 500
|
|
84
|
+
SHORT_TERM_MEM_LIMIT = 20
|
|
85
|
+
MEMORY_LOG_TRUNCATE = 2000 # chars
|
|
86
|
+
|
|
87
|
+
# Embedding
|
|
88
|
+
EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
|