bareagent-cli 0.1.0__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.
- bareagent/__init__.py +10 -0
- bareagent/concurrency/__init__.py +6 -0
- bareagent/concurrency/background.py +97 -0
- bareagent/concurrency/notification.py +61 -0
- bareagent/concurrency/scheduler.py +136 -0
- bareagent/config.toml +299 -0
- bareagent/core/__init__.py +1 -0
- bareagent/core/config_paths.py +49 -0
- bareagent/core/context.py +127 -0
- bareagent/core/fileutil.py +103 -0
- bareagent/core/goal.py +214 -0
- bareagent/core/handlers/__init__.py +1 -0
- bareagent/core/handlers/bash.py +79 -0
- bareagent/core/handlers/file_edit.py +47 -0
- bareagent/core/handlers/file_read.py +270 -0
- bareagent/core/handlers/file_write.py +34 -0
- bareagent/core/handlers/glob_search.py +30 -0
- bareagent/core/handlers/goal.py +60 -0
- bareagent/core/handlers/grep_search.py +52 -0
- bareagent/core/handlers/memory.py +71 -0
- bareagent/core/handlers/plan.py +106 -0
- bareagent/core/handlers/search_utils.py +77 -0
- bareagent/core/handlers/skill.py +87 -0
- bareagent/core/handlers/subagent_send.py +70 -0
- bareagent/core/handlers/web_fetch.py +126 -0
- bareagent/core/handlers/web_search.py +165 -0
- bareagent/core/handlers/workflow.py +190 -0
- bareagent/core/loop.py +535 -0
- bareagent/core/retry.py +131 -0
- bareagent/core/sandbox.py +27 -0
- bareagent/core/schema.py +21 -0
- bareagent/core/tools.py +779 -0
- bareagent/core/workflow.py +517 -0
- bareagent/core/workflow_registry.py +219 -0
- bareagent/debug/__init__.py +0 -0
- bareagent/debug/interaction_log.py +263 -0
- bareagent/debug/viewer.html +1750 -0
- bareagent/debug/web_viewer.py +157 -0
- bareagent/hooks/__init__.py +32 -0
- bareagent/hooks/config.py +118 -0
- bareagent/hooks/engine.py +197 -0
- bareagent/hooks/errors.py +14 -0
- bareagent/hooks/events.py +22 -0
- bareagent/lsp/__init__.py +63 -0
- bareagent/lsp/config.py +134 -0
- bareagent/lsp/coord.py +118 -0
- bareagent/lsp/diagnostics.py +240 -0
- bareagent/lsp/errors.py +24 -0
- bareagent/lsp/manager.py +866 -0
- bareagent/lsp/tools.py +629 -0
- bareagent/lsp/workspace_edit.py +305 -0
- bareagent/main.py +4205 -0
- bareagent/mcp/__init__.py +69 -0
- bareagent/mcp/_sse.py +69 -0
- bareagent/mcp/client.py +341 -0
- bareagent/mcp/config.py +169 -0
- bareagent/mcp/errors.py +32 -0
- bareagent/mcp/manager.py +318 -0
- bareagent/mcp/protocol.py +187 -0
- bareagent/mcp/registry.py +557 -0
- bareagent/mcp/transport/__init__.py +15 -0
- bareagent/mcp/transport/base.py +149 -0
- bareagent/mcp/transport/http_legacy.py +192 -0
- bareagent/mcp/transport/http_streamable.py +217 -0
- bareagent/mcp/transport/stdio.py +202 -0
- bareagent/memory/__init__.py +1 -0
- bareagent/memory/compact.py +203 -0
- bareagent/memory/conversation_io.py +226 -0
- bareagent/memory/embedding.py +194 -0
- bareagent/memory/persistent.py +515 -0
- bareagent/memory/token_counter.py +67 -0
- bareagent/memory/token_tracker.py +262 -0
- bareagent/memory/transcript.py +100 -0
- bareagent/permission/__init__.py +1 -0
- bareagent/permission/guard.py +329 -0
- bareagent/permission/rules.py +19 -0
- bareagent/planning/__init__.py +19 -0
- bareagent/planning/agent_types.py +169 -0
- bareagent/planning/skill_gen.py +141 -0
- bareagent/planning/skill_store.py +173 -0
- bareagent/planning/skills.py +146 -0
- bareagent/planning/subagent.py +355 -0
- bareagent/planning/subagent_registry.py +77 -0
- bareagent/planning/tasks.py +348 -0
- bareagent/planning/todo.py +153 -0
- bareagent/planning/worktree.py +122 -0
- bareagent/provider/__init__.py +1 -0
- bareagent/provider/anthropic.py +348 -0
- bareagent/provider/base.py +136 -0
- bareagent/provider/factory.py +130 -0
- bareagent/provider/openai.py +881 -0
- bareagent/provider/presets.py +72 -0
- bareagent/provider/setup.py +356 -0
- bareagent/skills/.gitkeep +1 -0
- bareagent/skills/code-review/SKILL.md +68 -0
- bareagent/skills/git/SKILL.md +68 -0
- bareagent/skills/test/SKILL.md +70 -0
- bareagent/team/__init__.py +17 -0
- bareagent/team/autonomous.py +193 -0
- bareagent/team/mailbox.py +239 -0
- bareagent/team/manager.py +155 -0
- bareagent/team/protocols.py +129 -0
- bareagent/tracing/__init__.py +12 -0
- bareagent/tracing/_api.py +92 -0
- bareagent/tracing/_proxy.py +60 -0
- bareagent/tracing/composite.py +115 -0
- bareagent/tracing/json_file.py +115 -0
- bareagent/tracing/langfuse.py +139 -0
- bareagent/tracing/otel.py +107 -0
- bareagent/tracing/setup.py +85 -0
- bareagent/ui/__init__.py +24 -0
- bareagent/ui/console.py +167 -0
- bareagent/ui/prompt.py +78 -0
- bareagent/ui/protocol.py +24 -0
- bareagent/ui/stream.py +66 -0
- bareagent/ui/theme.py +240 -0
- bareagent_cli-0.1.0.dist-info/METADATA +331 -0
- bareagent_cli-0.1.0.dist-info/RECORD +121 -0
- bareagent_cli-0.1.0.dist-info/WHEEL +4 -0
- bareagent_cli-0.1.0.dist-info/entry_points.txt +2 -0
- bareagent_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Handler + schema for the ``workflow`` tool (deterministic DAG orchestration).
|
|
2
|
+
|
|
3
|
+
Like ``exit_plan_mode`` / ``goal_verdict`` / ``skill_create``, ``workflow`` is a
|
|
4
|
+
main-loop-only tool: its schema is NOT in the global ``get_tools()`` set, it is
|
|
5
|
+
appended only to the top-level ``loop_tools`` and its handler is installed on the
|
|
6
|
+
main loop's handler dict (see ``main.py``). ``"workflow"`` is also in
|
|
7
|
+
``agent_types.MAIN_LOOP_ONLY_TOOLS`` so ``filter_tools`` strips it from every
|
|
8
|
+
sub-agent type, and ``filter_handlers`` then drops the orphaned handler -- a
|
|
9
|
+
sub-agent can never fan out its own workflow (no nesting in the MVP).
|
|
10
|
+
|
|
11
|
+
The LLM authors the DAG on the fly: a ``nodes`` array of declarative subagent
|
|
12
|
+
tasks with ``depends_on`` edges (not executable code). The handler is a thin
|
|
13
|
+
shim: parse -> validate -> drive the pure :func:`bareagent.core.workflow.run_workflow`
|
|
14
|
+
engine with the caller-injected ``execute_node`` / ``map_concurrent`` /
|
|
15
|
+
``on_progress`` callbacks -> format the aggregated summary. Returning an
|
|
16
|
+
``Error:`` string for bad input (rather than raising) keeps the main loop's tool
|
|
17
|
+
result clean (see ``error-handling.md``).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from collections.abc import Callable
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
from bareagent.core.schema import tool_schema
|
|
26
|
+
from bareagent.core.workflow import (
|
|
27
|
+
DEFAULT_MAX_NODES,
|
|
28
|
+
NodeResult,
|
|
29
|
+
WorkflowError,
|
|
30
|
+
WorkflowNode,
|
|
31
|
+
WorkflowSpec,
|
|
32
|
+
compute_resume_plan,
|
|
33
|
+
format_summary,
|
|
34
|
+
parse_workflow,
|
|
35
|
+
run_workflow,
|
|
36
|
+
validate_workflow,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
WORKFLOW_TOOL_SCHEMA = tool_schema(
|
|
40
|
+
"workflow",
|
|
41
|
+
(
|
|
42
|
+
"Run a deterministic DAG of subagent tasks in parallel. Provide 'nodes': "
|
|
43
|
+
"each node is an isolated subagent given a 'prompt'; independent nodes run "
|
|
44
|
+
"concurrently and nodes wait for their 'depends_on' nodes. Reference an "
|
|
45
|
+
"upstream node's output in a prompt with {{node_id}}. Use this when you can "
|
|
46
|
+
"decompose the work into independent or dependency-ordered pieces up front; "
|
|
47
|
+
"it returns a structured summary of every node's result. The structure is "
|
|
48
|
+
"fixed once submitted (no loops/conditionals); issue another workflow call "
|
|
49
|
+
"to branch on the results. Set 'run_in_background' to get a run id back "
|
|
50
|
+
"immediately and have the result delivered when it finishes (watch it with "
|
|
51
|
+
"/workflows). Set 'resume_from' to a prior run id to reuse that run's "
|
|
52
|
+
"unchanged completed nodes and only re-run changed/failed/new ones. Set "
|
|
53
|
+
"'token_budget' to cap the run: once spent, remaining nodes are skipped."
|
|
54
|
+
),
|
|
55
|
+
{
|
|
56
|
+
"run_in_background": {
|
|
57
|
+
"type": "boolean",
|
|
58
|
+
"description": (
|
|
59
|
+
"Run asynchronously: return a run id now and deliver the full "
|
|
60
|
+
"summary when it finishes (default false = block and return it)."
|
|
61
|
+
),
|
|
62
|
+
},
|
|
63
|
+
"resume_from": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"description": (
|
|
66
|
+
"A prior workflow run id. Nodes with the same id and an unchanged "
|
|
67
|
+
"prompt that completed last run are reused (not re-executed); "
|
|
68
|
+
"changed/failed/new nodes and everything downstream of them re-run. "
|
|
69
|
+
"An unknown id is ignored (the whole DAG runs fresh)."
|
|
70
|
+
),
|
|
71
|
+
},
|
|
72
|
+
"token_budget": {
|
|
73
|
+
"type": "integer",
|
|
74
|
+
"description": (
|
|
75
|
+
"Soft token ceiling for this run. Checked before each layer; once "
|
|
76
|
+
"spent tokens reach it, remaining nodes are skipped. Omit/0 = no cap."
|
|
77
|
+
),
|
|
78
|
+
},
|
|
79
|
+
"nodes": {
|
|
80
|
+
"type": "array",
|
|
81
|
+
"description": "The DAG nodes. Ids must be unique and the graph acyclic.",
|
|
82
|
+
"items": {
|
|
83
|
+
"type": "object",
|
|
84
|
+
"properties": {
|
|
85
|
+
"id": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"description": "Unique node id (referenced by depends_on and {{id}}).",
|
|
88
|
+
},
|
|
89
|
+
"prompt": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"description": "The task for this node's subagent.",
|
|
92
|
+
},
|
|
93
|
+
"agent_type": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": (
|
|
96
|
+
"Optional subagent profile (e.g. general-purpose, explore, "
|
|
97
|
+
"plan, code-review). Defaults to the configured default."
|
|
98
|
+
),
|
|
99
|
+
},
|
|
100
|
+
"depends_on": {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"items": {"type": "string"},
|
|
103
|
+
"description": "Ids of nodes whose outputs must complete first.",
|
|
104
|
+
},
|
|
105
|
+
"phase": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"description": "Optional label grouping nodes in the summary.",
|
|
108
|
+
},
|
|
109
|
+
"label": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"description": "Optional short human-readable node label.",
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
"required": ["id", "prompt"],
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
["nodes"],
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def validate_workflow_input(
|
|
123
|
+
nodes: Any, *, max_nodes: int = DEFAULT_MAX_NODES
|
|
124
|
+
) -> WorkflowSpec | str:
|
|
125
|
+
"""Parse + validate raw ``nodes`` into a spec, or return an ``Error:`` string.
|
|
126
|
+
|
|
127
|
+
Split out so ``main.py`` can validate once up front (immediate feedback for a
|
|
128
|
+
malformed DAG, even when ``run_in_background`` is set) and then reuse the
|
|
129
|
+
parsed spec without re-parsing.
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
spec = parse_workflow({"nodes": nodes})
|
|
133
|
+
except WorkflowError as exc:
|
|
134
|
+
return f"Error: {exc}"
|
|
135
|
+
errors = validate_workflow(spec, max_nodes=max_nodes)
|
|
136
|
+
if errors:
|
|
137
|
+
return "Error: invalid workflow:\n" + "\n".join(f"- {error}" for error in errors)
|
|
138
|
+
return spec
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def run_workflow_tool(
|
|
142
|
+
*,
|
|
143
|
+
nodes: Any = None,
|
|
144
|
+
spec: WorkflowSpec | None = None,
|
|
145
|
+
resume_from: str | None = None,
|
|
146
|
+
token_budget: int = 0,
|
|
147
|
+
execute_node: Callable[[WorkflowNode, dict[str, NodeResult]], Any],
|
|
148
|
+
map_concurrent: Callable[[list[Callable[[], NodeResult]]], list[NodeResult]],
|
|
149
|
+
on_progress: Callable[[str], None] | None = None,
|
|
150
|
+
on_node_status: Callable[[str, NodeResult], None] | None = None,
|
|
151
|
+
resolve_prior: Callable[[str], tuple[WorkflowSpec, dict[str, NodeResult]] | None] | None = None,
|
|
152
|
+
tokens_spent: Callable[[], int] | None = None,
|
|
153
|
+
max_nodes: int = DEFAULT_MAX_NODES,
|
|
154
|
+
) -> str:
|
|
155
|
+
"""Resolve resume, run, and summarize an LLM-authored workflow DAG.
|
|
156
|
+
|
|
157
|
+
Pass a pre-validated ``spec`` to skip parsing (``main.py`` does this so it can
|
|
158
|
+
register the run before driving); otherwise raw ``nodes`` are parsed +
|
|
159
|
+
validated here, returning an ``Error:`` string for an unusable DAG.
|
|
160
|
+
|
|
161
|
+
Resume: when ``resume_from`` and ``resolve_prior`` are given and the prior run
|
|
162
|
+
is found, :func:`compute_resume_plan` decides which nodes to reuse. An unknown
|
|
163
|
+
id falls open to a fresh run. Budget: ``token_budget`` (>0) plus ``tokens_spent``
|
|
164
|
+
stop the run at a layer boundary once spent. ``on_node_status`` mirrors each
|
|
165
|
+
node's terminal state out to the registry for the ``/workflows`` panel.
|
|
166
|
+
"""
|
|
167
|
+
if spec is None:
|
|
168
|
+
validated = validate_workflow_input(nodes, max_nodes=max_nodes)
|
|
169
|
+
if isinstance(validated, str):
|
|
170
|
+
return validated
|
|
171
|
+
spec = validated
|
|
172
|
+
|
|
173
|
+
reused: dict[str, NodeResult] = {}
|
|
174
|
+
if resume_from and resolve_prior is not None:
|
|
175
|
+
prior = resolve_prior(resume_from)
|
|
176
|
+
if prior is not None:
|
|
177
|
+
prior_spec, prior_results = prior
|
|
178
|
+
reused = compute_resume_plan(spec, prior_spec, prior_results)
|
|
179
|
+
|
|
180
|
+
results = run_workflow(
|
|
181
|
+
spec,
|
|
182
|
+
execute_node=execute_node,
|
|
183
|
+
map_concurrent=map_concurrent,
|
|
184
|
+
on_progress=on_progress,
|
|
185
|
+
on_node_status=on_node_status,
|
|
186
|
+
reused_results=reused,
|
|
187
|
+
token_budget=token_budget if token_budget and token_budget > 0 else 0,
|
|
188
|
+
tokens_spent=tokens_spent,
|
|
189
|
+
)
|
|
190
|
+
return format_summary(spec, results)
|