power-loop 0.2.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.
- llm_client/__init__.py +0 -0
- llm_client/capabilities.py +162 -0
- llm_client/interface.py +470 -0
- llm_client/llm_factory.py +981 -0
- llm_client/llm_tooling.py +645 -0
- llm_client/llm_utils.py +205 -0
- llm_client/multimodal.py +237 -0
- llm_client/qwen_image.py +576 -0
- llm_client/web_search.py +149 -0
- power_loop/__init__.py +326 -0
- power_loop/agent/__init__.py +6 -0
- power_loop/agent/sink.py +247 -0
- power_loop/agent/stateful_loop.py +363 -0
- power_loop/agent/system_prompt.py +396 -0
- power_loop/agent/types.py +41 -0
- power_loop/contracts/__init__.py +132 -0
- power_loop/contracts/errors.py +140 -0
- power_loop/contracts/event_payloads.py +278 -0
- power_loop/contracts/events.py +86 -0
- power_loop/contracts/handlers.py +45 -0
- power_loop/contracts/hook_contexts.py +265 -0
- power_loop/contracts/hooks.py +64 -0
- power_loop/contracts/messages.py +90 -0
- power_loop/contracts/protocols.py +48 -0
- power_loop/contracts/tools.py +56 -0
- power_loop/core/agent_context.py +94 -0
- power_loop/core/events.py +124 -0
- power_loop/core/hooks.py +122 -0
- power_loop/core/phase.py +217 -0
- power_loop/core/pipeline.py +880 -0
- power_loop/core/runner.py +60 -0
- power_loop/core/state.py +208 -0
- power_loop/runtime/budget.py +179 -0
- power_loop/runtime/cancellation.py +127 -0
- power_loop/runtime/compact.py +300 -0
- power_loop/runtime/env.py +103 -0
- power_loop/runtime/memory.py +107 -0
- power_loop/runtime/provider.py +176 -0
- power_loop/runtime/retry.py +182 -0
- power_loop/runtime/session_store.py +636 -0
- power_loop/runtime/skills.py +201 -0
- power_loop/runtime/spec.py +233 -0
- power_loop/runtime/structured.py +225 -0
- power_loop/tools/__init__.py +51 -0
- power_loop/tools/default_manifest.py +244 -0
- power_loop/tools/default_tools.py +766 -0
- power_loop/tools/registry.py +162 -0
- power_loop/tools/spawn_agent.py +173 -0
- power_loop-0.2.0.dist-info/METADATA +632 -0
- power_loop-0.2.0.dist-info/RECORD +53 -0
- power_loop-0.2.0.dist-info/WHEEL +5 -0
- power_loop-0.2.0.dist-info/licenses/LICENSE +21 -0
- power_loop-0.2.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
|
|
5
|
+
from power_loop.tools.registry import ToolRegistry, build_registry
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def create_default_tool_registry(
|
|
9
|
+
*,
|
|
10
|
+
preset: str | None = None,
|
|
11
|
+
include: Sequence[str] | None = None,
|
|
12
|
+
exclude: Sequence[str] | None = None,
|
|
13
|
+
) -> ToolRegistry:
|
|
14
|
+
"""Create a :class:`ToolRegistry` pre-loaded with default tools.
|
|
15
|
+
|
|
16
|
+
All three filter arguments are optional and forwarded to
|
|
17
|
+
:func:`~power_loop.tools.default_manifest.get_tool_definitions`.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
preset: ``"core"`` (bash/read/write/edit/patch/glob/grep/skill),
|
|
21
|
+
``"explore"`` (read-only subset), or ``"full"`` (all 11 tools).
|
|
22
|
+
Defaults to ``"full"`` when *include* is also ``None``.
|
|
23
|
+
include: Explicit tool names to register (overrides *preset*).
|
|
24
|
+
exclude: Tool names to drop from the selected set.
|
|
25
|
+
|
|
26
|
+
Examples::
|
|
27
|
+
|
|
28
|
+
# All default tools
|
|
29
|
+
reg = create_default_tool_registry()
|
|
30
|
+
|
|
31
|
+
# Only core coding tools
|
|
32
|
+
reg = create_default_tool_registry(preset="core")
|
|
33
|
+
|
|
34
|
+
# Cherry-pick
|
|
35
|
+
reg = create_default_tool_registry(include=["bash", "read_file", "grep"])
|
|
36
|
+
|
|
37
|
+
# Full minus background tasks
|
|
38
|
+
reg = create_default_tool_registry(exclude=["background_run", "check_background"])
|
|
39
|
+
"""
|
|
40
|
+
from power_loop.tools.default_manifest import get_tool_definitions
|
|
41
|
+
from power_loop.tools.default_tools import DEFAULT_TOOL_HANDLERS
|
|
42
|
+
|
|
43
|
+
definitions = get_tool_definitions(preset=preset, include=include, exclude=exclude)
|
|
44
|
+
return build_registry(definitions, DEFAULT_TOOL_HANDLERS)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
__all__ = [
|
|
48
|
+
"ToolRegistry",
|
|
49
|
+
"build_registry",
|
|
50
|
+
"create_default_tool_registry",
|
|
51
|
+
]
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Sequence
|
|
4
|
+
|
|
5
|
+
from power_loop.contracts.tools import ToolDefinition
|
|
6
|
+
|
|
7
|
+
# Tool definitions copied from zero-code BASE_TOOLS entries for the default core tool set.
|
|
8
|
+
DEFAULT_TOOL_DEFINITIONS: list[ToolDefinition] = [
|
|
9
|
+
ToolDefinition(
|
|
10
|
+
name="write_file",
|
|
11
|
+
description=(
|
|
12
|
+
"Create or overwrite a file with the given content. Creates parent directories automatically. "
|
|
13
|
+
"IMPORTANT: Both 'path' and 'content' parameters are REQUIRED and must be provided in a single valid JSON object. "
|
|
14
|
+
"For large files, write the complete content in one call — do not split across multiple calls."
|
|
15
|
+
),
|
|
16
|
+
input_schema={
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"path": {"type": "string"},
|
|
20
|
+
"content": {"type": "string"},
|
|
21
|
+
},
|
|
22
|
+
"required": ["path", "content"],
|
|
23
|
+
},
|
|
24
|
+
required_params=("path", "content"),
|
|
25
|
+
),
|
|
26
|
+
ToolDefinition(
|
|
27
|
+
name="read_file",
|
|
28
|
+
description="Read file contents with line numbers, or list directory entries.",
|
|
29
|
+
input_schema={
|
|
30
|
+
"type": "object",
|
|
31
|
+
"properties": {
|
|
32
|
+
"path": {"type": "string"},
|
|
33
|
+
"offset": {"type": "integer"},
|
|
34
|
+
"limit": {"type": "integer"},
|
|
35
|
+
},
|
|
36
|
+
"required": ["path"],
|
|
37
|
+
},
|
|
38
|
+
required_params=("path",),
|
|
39
|
+
),
|
|
40
|
+
ToolDefinition(
|
|
41
|
+
name="edit_file",
|
|
42
|
+
description="Replace exact text in a file (old_text->new_text).",
|
|
43
|
+
input_schema={
|
|
44
|
+
"type": "object",
|
|
45
|
+
"properties": {
|
|
46
|
+
"path": {"type": "string"},
|
|
47
|
+
"old_text": {"type": "string"},
|
|
48
|
+
"new_text": {"type": "string"},
|
|
49
|
+
"replace_all": {"type": "boolean"},
|
|
50
|
+
},
|
|
51
|
+
"required": ["path", "old_text", "new_text"],
|
|
52
|
+
},
|
|
53
|
+
required_params=("path", "old_text", "new_text"),
|
|
54
|
+
),
|
|
55
|
+
ToolDefinition(
|
|
56
|
+
name="apply_patch",
|
|
57
|
+
description="Apply a patch to a file using @@ context lines for positioning and +/- for line changes.",
|
|
58
|
+
input_schema={
|
|
59
|
+
"type": "object",
|
|
60
|
+
"properties": {
|
|
61
|
+
"path": {"type": "string"},
|
|
62
|
+
"patch": {"type": "string"},
|
|
63
|
+
},
|
|
64
|
+
"required": ["path", "patch"],
|
|
65
|
+
},
|
|
66
|
+
required_params=("path", "patch"),
|
|
67
|
+
),
|
|
68
|
+
ToolDefinition(
|
|
69
|
+
name="bash",
|
|
70
|
+
description="Run a shell command in a persistent bash session rooted at workspace.",
|
|
71
|
+
input_schema={
|
|
72
|
+
"type": "object",
|
|
73
|
+
"properties": {
|
|
74
|
+
"command": {"type": "string"},
|
|
75
|
+
"restart": {"type": "boolean"},
|
|
76
|
+
"timeout": {"type": "integer"},
|
|
77
|
+
},
|
|
78
|
+
"required": ["command"],
|
|
79
|
+
},
|
|
80
|
+
required_params=("command",),
|
|
81
|
+
),
|
|
82
|
+
ToolDefinition(
|
|
83
|
+
name="glob",
|
|
84
|
+
description="Find files by glob pattern, sorted by modification time (newest first).",
|
|
85
|
+
input_schema={
|
|
86
|
+
"type": "object",
|
|
87
|
+
"properties": {
|
|
88
|
+
"pattern": {"type": "string"},
|
|
89
|
+
"path": {"type": "string"},
|
|
90
|
+
},
|
|
91
|
+
"required": ["pattern"],
|
|
92
|
+
},
|
|
93
|
+
required_params=("pattern",),
|
|
94
|
+
),
|
|
95
|
+
ToolDefinition(
|
|
96
|
+
name="grep",
|
|
97
|
+
description="Search file contents by regex pattern.",
|
|
98
|
+
input_schema={
|
|
99
|
+
"type": "object",
|
|
100
|
+
"properties": {
|
|
101
|
+
"pattern": {"type": "string"},
|
|
102
|
+
"path": {"type": "string"},
|
|
103
|
+
"include": {"type": "string"},
|
|
104
|
+
"max_results": {"type": "integer"},
|
|
105
|
+
},
|
|
106
|
+
"required": ["pattern"],
|
|
107
|
+
},
|
|
108
|
+
required_params=("pattern",),
|
|
109
|
+
),
|
|
110
|
+
ToolDefinition(
|
|
111
|
+
name="load_skill",
|
|
112
|
+
description="Load specialized knowledge by name.",
|
|
113
|
+
input_schema={
|
|
114
|
+
"type": "object",
|
|
115
|
+
"properties": {
|
|
116
|
+
"name": {"type": "string"},
|
|
117
|
+
},
|
|
118
|
+
"required": ["name"],
|
|
119
|
+
},
|
|
120
|
+
required_params=("name",),
|
|
121
|
+
),
|
|
122
|
+
ToolDefinition(
|
|
123
|
+
name="todo",
|
|
124
|
+
description="Update the current task list (todo manager). Only one item can be in_progress at a time.",
|
|
125
|
+
input_schema={
|
|
126
|
+
"type": "object",
|
|
127
|
+
"properties": {
|
|
128
|
+
"items": {
|
|
129
|
+
"type": "array",
|
|
130
|
+
"items": {
|
|
131
|
+
"type": "object",
|
|
132
|
+
"properties": {
|
|
133
|
+
"id": {"type": "string"},
|
|
134
|
+
"text": {"type": "string"},
|
|
135
|
+
"status": {"type": "string", "enum": ["pending", "in_progress", "completed"]},
|
|
136
|
+
},
|
|
137
|
+
"required": ["id", "text", "status"],
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"required": ["items"],
|
|
142
|
+
},
|
|
143
|
+
required_params=("items",),
|
|
144
|
+
),
|
|
145
|
+
ToolDefinition(
|
|
146
|
+
name="background_run",
|
|
147
|
+
description="Run a shell command in a private background worker (non-interactive).",
|
|
148
|
+
input_schema={
|
|
149
|
+
"type": "object",
|
|
150
|
+
"properties": {
|
|
151
|
+
"command": {"type": "string"},
|
|
152
|
+
},
|
|
153
|
+
"required": ["command"],
|
|
154
|
+
},
|
|
155
|
+
required_params=("command",),
|
|
156
|
+
),
|
|
157
|
+
ToolDefinition(
|
|
158
|
+
name="check_background",
|
|
159
|
+
description="Check your private background tasks. If task_id is omitted, list all tasks.",
|
|
160
|
+
input_schema={
|
|
161
|
+
"type": "object",
|
|
162
|
+
"properties": {
|
|
163
|
+
"task_id": {"type": "string"},
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
required_params=(),
|
|
167
|
+
),
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
# Indexed lookup for selective registration.
|
|
171
|
+
DEFAULT_TOOL_DEFINITIONS_MAP: dict[str, ToolDefinition] = {d.name: d for d in DEFAULT_TOOL_DEFINITIONS}
|
|
172
|
+
|
|
173
|
+
# ---------------------------------------------------------------------------
|
|
174
|
+
# Tool presets (matching zero-code's BASE_TOOLS / EXPLORE_TOOLS categories)
|
|
175
|
+
# ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
# Core coding tools — the minimal set for an agent that reads, writes, and runs code.
|
|
178
|
+
CORE_TOOL_NAMES: tuple[str, ...] = (
|
|
179
|
+
"bash",
|
|
180
|
+
"read_file",
|
|
181
|
+
"write_file",
|
|
182
|
+
"edit_file",
|
|
183
|
+
"apply_patch",
|
|
184
|
+
"glob",
|
|
185
|
+
"grep",
|
|
186
|
+
"load_skill",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Read-only / exploration tools — no file mutation. Matches zero-code EXPLORE_TOOLS.
|
|
190
|
+
EXPLORE_TOOL_NAMES: tuple[str, ...] = (
|
|
191
|
+
"bash",
|
|
192
|
+
"read_file",
|
|
193
|
+
"glob",
|
|
194
|
+
"grep",
|
|
195
|
+
"load_skill",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Full set — everything including todo and background tasks.
|
|
199
|
+
FULL_TOOL_NAMES: tuple[str, ...] = tuple(d.name for d in DEFAULT_TOOL_DEFINITIONS)
|
|
200
|
+
|
|
201
|
+
TOOL_PRESETS: dict[str, tuple[str, ...]] = {
|
|
202
|
+
"core": CORE_TOOL_NAMES,
|
|
203
|
+
"explore": EXPLORE_TOOL_NAMES,
|
|
204
|
+
"full": FULL_TOOL_NAMES,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def get_tool_definitions(
|
|
209
|
+
*,
|
|
210
|
+
preset: str | None = None,
|
|
211
|
+
include: Sequence[str] | None = None,
|
|
212
|
+
exclude: Sequence[str] | None = None,
|
|
213
|
+
) -> list[ToolDefinition]:
|
|
214
|
+
"""Return a filtered list of default tool definitions.
|
|
215
|
+
|
|
216
|
+
Priority: *include* > *preset* > all.
|
|
217
|
+
*exclude* is applied last regardless.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
preset: One of "core", "explore", "full".
|
|
221
|
+
include: Explicit tool names to include (ignores preset).
|
|
222
|
+
exclude: Tool names to drop from the result.
|
|
223
|
+
"""
|
|
224
|
+
if include is not None:
|
|
225
|
+
names = list(include)
|
|
226
|
+
elif preset is not None:
|
|
227
|
+
names_tuple = TOOL_PRESETS.get(preset)
|
|
228
|
+
if names_tuple is None:
|
|
229
|
+
raise ValueError(f"Unknown preset '{preset}'. Choose from: {', '.join(TOOL_PRESETS)}")
|
|
230
|
+
names = list(names_tuple)
|
|
231
|
+
else:
|
|
232
|
+
names = [d.name for d in DEFAULT_TOOL_DEFINITIONS]
|
|
233
|
+
|
|
234
|
+
if exclude:
|
|
235
|
+
exclude_set = set(exclude)
|
|
236
|
+
names = [n for n in names if n not in exclude_set]
|
|
237
|
+
|
|
238
|
+
result: list[ToolDefinition] = []
|
|
239
|
+
for name in names:
|
|
240
|
+
defn = DEFAULT_TOOL_DEFINITIONS_MAP.get(name)
|
|
241
|
+
if defn is None:
|
|
242
|
+
raise ValueError(f"Unknown default tool: '{name}'")
|
|
243
|
+
result.append(defn)
|
|
244
|
+
return result
|