ghostcode-canary 0.1.25-canary.0
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.
- package/LICENSE +201 -0
- package/PAT.txt +1 -0
- package/README.md +95 -0
- package/cli.js +92 -0
- package/error/err1.txt +12 -0
- package/package.json +31 -0
- package/setup.js +67 -0
- package/src/ghostcode/__init__.py +3 -0
- package/src/ghostcode/__main__.py +3 -0
- package/src/ghostcode/_version.py +17 -0
- package/src/ghostcode/agents/__init__.py +20 -0
- package/src/ghostcode/agents/code.py +104 -0
- package/src/ghostcode/agents/explore.py +50 -0
- package/src/ghostcode/ai/__init__.py +0 -0
- package/src/ghostcode/ai/anthropic_client.py +8 -0
- package/src/ghostcode/ai/base.py +33 -0
- package/src/ghostcode/ai/factory.py +38 -0
- package/src/ghostcode/ai/groq_client.py +7 -0
- package/src/ghostcode/ai/nvidia_client.py +7 -0
- package/src/ghostcode/ai/ollama_client.py +7 -0
- package/src/ghostcode/ai/openai_client.py +7 -0
- package/src/ghostcode/ai/openai_compat.py +139 -0
- package/src/ghostcode/ai/opencode_go_client.py +7 -0
- package/src/ghostcode/ai/opencode_zen_client.py +7 -0
- package/src/ghostcode/ai/openrouter_client.py +7 -0
- package/src/ghostcode/ai/registry.py +169 -0
- package/src/ghostcode/app.py +148 -0
- package/src/ghostcode/config.py +24 -0
- package/src/ghostcode/core/__init__.py +5 -0
- package/src/ghostcode/core/commands.py +55 -0
- package/src/ghostcode/core/file_ops.py +127 -0
- package/src/ghostcode/core/hooks.py +122 -0
- package/src/ghostcode/core/memory.py +137 -0
- package/src/ghostcode/core/prompt.py +73 -0
- package/src/ghostcode/core/reminders.py +61 -0
- package/src/ghostcode/core/security.py +119 -0
- package/src/ghostcode/core/tasks.py +125 -0
- package/src/ghostcode/tools/__init__.py +2 -0
- package/src/ghostcode/tools/defs.py +325 -0
- package/src/ghostcode/tools/executor.py +261 -0
- package/src/ghostcode/tui/__init__.py +0 -0
- package/src/ghostcode/tui/app.py +12 -0
- package/src/ghostcode/tui/dialogs.py +241 -0
- package/src/ghostcode/tui/screens.py +799 -0
- package/src/ghostcode/tui/widgets.py +32 -0
- package/src/ghostcode/utils/__init__.py +0 -0
- package/src/ghostcode/utils/config_loader.py +102 -0
- package/src/ghostcode/utils/logger.py +16 -0
- package/src/pyproject.toml +18 -0
- package/token.txt +1 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import time
|
|
3
|
+
import uuid
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TaskStatus(Enum):
|
|
8
|
+
PENDING = "pending"
|
|
9
|
+
RUNNING = "running"
|
|
10
|
+
COMPLETED = "completed"
|
|
11
|
+
FAILED = "failed"
|
|
12
|
+
STOPPED = "stopped"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Task:
|
|
16
|
+
def __init__(self, description: str, prompt: str, subagent_type: str = "worker"):
|
|
17
|
+
self.id = str(uuid.uuid4())[:8]
|
|
18
|
+
self.description = description
|
|
19
|
+
self.prompt = prompt
|
|
20
|
+
self.subagent_type = subagent_type
|
|
21
|
+
self.status = TaskStatus.PENDING
|
|
22
|
+
self.result: str | None = None
|
|
23
|
+
self.error: str | None = None
|
|
24
|
+
self.created_at = time.time()
|
|
25
|
+
self.completed_at: float | None = None
|
|
26
|
+
self.tool_uses = 0
|
|
27
|
+
self.duration_ms: int | None = None
|
|
28
|
+
|
|
29
|
+
def to_dict(self) -> dict:
|
|
30
|
+
return {
|
|
31
|
+
"id": self.id,
|
|
32
|
+
"description": self.description,
|
|
33
|
+
"prompt": self.prompt,
|
|
34
|
+
"subagent_type": self.subagent_type,
|
|
35
|
+
"status": self.status.value,
|
|
36
|
+
"result": self.result,
|
|
37
|
+
"error": self.error,
|
|
38
|
+
"created_at": self.created_at,
|
|
39
|
+
"completed_at": self.completed_at,
|
|
40
|
+
"tool_uses": self.tool_uses,
|
|
41
|
+
"duration_ms": self.duration_ms,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
def to_notification(self) -> str:
|
|
45
|
+
return (
|
|
46
|
+
f"<task-notification>\n"
|
|
47
|
+
f"<task-id>{self.id}</task-id>\n"
|
|
48
|
+
f"<status>{self.status.value}</status>\n"
|
|
49
|
+
f"<summary>{self.description} — {self.status.value}</summary>\n"
|
|
50
|
+
f"<result>{self.result or ''}</result>\n"
|
|
51
|
+
f"<usage>\n"
|
|
52
|
+
f" <tool_uses>{self.tool_uses}</tool_uses>\n"
|
|
53
|
+
f" <duration_ms>{self.duration_ms or 0}</duration_ms>\n"
|
|
54
|
+
f"</usage>\n"
|
|
55
|
+
f"</task-notification>"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class TaskManager:
|
|
60
|
+
def __init__(self):
|
|
61
|
+
self._tasks: dict[str, Task] = {}
|
|
62
|
+
self._pending_callbacks: dict[str, list] = {}
|
|
63
|
+
|
|
64
|
+
def create(self, description: str, prompt: str, subagent_type: str = "worker") -> Task:
|
|
65
|
+
task = Task(description, prompt, subagent_type)
|
|
66
|
+
self._tasks[task.id] = task
|
|
67
|
+
return task
|
|
68
|
+
|
|
69
|
+
def get(self, task_id: str) -> Task | None:
|
|
70
|
+
return self._tasks.get(task_id)
|
|
71
|
+
|
|
72
|
+
def update(self, task_id: str, status: TaskStatus, result: str | None = None, error: str | None = None):
|
|
73
|
+
task = self._tasks.get(task_id)
|
|
74
|
+
if not task:
|
|
75
|
+
return
|
|
76
|
+
task.status = status
|
|
77
|
+
if result is not None:
|
|
78
|
+
task.result = result
|
|
79
|
+
if error is not None:
|
|
80
|
+
task.error = error
|
|
81
|
+
if status in (TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.STOPPED):
|
|
82
|
+
task.completed_at = time.time()
|
|
83
|
+
task.duration_ms = int((task.completed_at - task.created_at) * 1000)
|
|
84
|
+
# fire callbacks
|
|
85
|
+
cb_list = self._pending_callbacks.pop(task_id, [])
|
|
86
|
+
for cb in cb_list:
|
|
87
|
+
try:
|
|
88
|
+
if asyncio.iscoroutinefunction(cb):
|
|
89
|
+
asyncio.ensure_future(cb(task))
|
|
90
|
+
else:
|
|
91
|
+
cb(task)
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
def stop(self, task_id: str) -> bool:
|
|
96
|
+
task = self._tasks.get(task_id)
|
|
97
|
+
if not task or task.status not in (TaskStatus.PENDING, TaskStatus.RUNNING):
|
|
98
|
+
return False
|
|
99
|
+
self.update(task_id, TaskStatus.STOPPED)
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
def list_tasks(self, status_filter: str | None = None) -> list[dict]:
|
|
103
|
+
tasks = list(self._tasks.values())
|
|
104
|
+
if status_filter:
|
|
105
|
+
tasks = [t for t in tasks if t.status.value == status_filter]
|
|
106
|
+
tasks.sort(key=lambda t: t.created_at, reverse=True)
|
|
107
|
+
return [t.to_dict() for t in tasks]
|
|
108
|
+
|
|
109
|
+
def on_complete(self, task_id: str, callback):
|
|
110
|
+
task = self._tasks.get(task_id)
|
|
111
|
+
if not task:
|
|
112
|
+
return
|
|
113
|
+
if task.status in (TaskStatus.COMPLETED, TaskStatus.FAILED, TaskStatus.STOPPED):
|
|
114
|
+
try:
|
|
115
|
+
if asyncio.iscoroutinefunction(callback):
|
|
116
|
+
asyncio.ensure_future(callback(task))
|
|
117
|
+
else:
|
|
118
|
+
callback(task)
|
|
119
|
+
except Exception:
|
|
120
|
+
pass
|
|
121
|
+
return
|
|
122
|
+
self._pending_callbacks.setdefault(task_id, []).append(callback)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
task_manager = TaskManager()
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
TOOL_DEFINITIONS = [
|
|
2
|
+
{
|
|
3
|
+
"type": "function",
|
|
4
|
+
"function": {
|
|
5
|
+
"name": "read_file",
|
|
6
|
+
"description": "Reads a file from the local filesystem. Returns file content as text. Use for code files, configs, and any text-based file. Supports large files with offset/limit params. Also reads images and Jupyter notebooks.",
|
|
7
|
+
"parameters": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"properties": {
|
|
10
|
+
"file_path": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "Absolute path to the file. Must be absolute, not relative.",
|
|
13
|
+
},
|
|
14
|
+
"offset": {
|
|
15
|
+
"type": "integer",
|
|
16
|
+
"description": "Line number to start reading from (1-indexed). Useful for large files.",
|
|
17
|
+
},
|
|
18
|
+
"limit": {
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"description": "Maximum number of lines to return. Defaults to all lines if omitted.",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
"required": ["file_path"],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"type": "function",
|
|
29
|
+
"function": {
|
|
30
|
+
"name": "write_file",
|
|
31
|
+
"description": "Writes a file to the local filesystem. Creates parent directories if needed. Overwrites existing content. Use for creating new files or complete rewrites. For small targeted changes, prefer edit_file. Never create *.md or README files unless asked.",
|
|
32
|
+
"parameters": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"properties": {
|
|
35
|
+
"file_path": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "Absolute or relative path to write to.",
|
|
38
|
+
},
|
|
39
|
+
"content": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"description": "The full content to write to the file.",
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"required": ["file_path", "content"],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"type": "function",
|
|
50
|
+
"function": {
|
|
51
|
+
"name": "edit_file",
|
|
52
|
+
"description": "Performs exact string replacements in files. Replace the first occurrence of old_string with new_string. Use for targeted edits — only sends the diff. The old_string must match exactly; include enough surrounding context to make it unique. Prefer editing existing files over creating new ones.",
|
|
53
|
+
"parameters": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"properties": {
|
|
56
|
+
"file_path": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"description": "Absolute or relative path to the file to edit.",
|
|
59
|
+
},
|
|
60
|
+
"old_string": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"description": "The exact text to replace (first occurrence only). Include enough surrounding lines for uniqueness. Must match indentation exactly.",
|
|
63
|
+
},
|
|
64
|
+
"new_string": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"description": "The replacement text.",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
"required": ["file_path", "old_string", "new_string"],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"type": "function",
|
|
75
|
+
"function": {
|
|
76
|
+
"name": "run_command",
|
|
77
|
+
"description": "Executes a given shell command and returns its stdout + stderr output. Use for running tests, build commands, git operations, and other CLI tools. Commands run in the specified working directory.",
|
|
78
|
+
"parameters": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"properties": {
|
|
81
|
+
"command": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"description": "The shell command to execute.",
|
|
84
|
+
},
|
|
85
|
+
"workdir": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"description": "Working directory for the command (default: current directory). Always specify explicitly when the command depends on a specific directory.",
|
|
88
|
+
},
|
|
89
|
+
"timeout": {
|
|
90
|
+
"type": "integer",
|
|
91
|
+
"description": "Timeout in milliseconds (default: 120000, max: 600000).",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
"required": ["command"],
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"type": "function",
|
|
100
|
+
"function": {
|
|
101
|
+
"name": "list_files",
|
|
102
|
+
"description": "List files and directories at the given path. Optionally filter by glob pattern. Use to explore directory structure before reading specific files. Returns files sorted by modification time.",
|
|
103
|
+
"parameters": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"properties": {
|
|
106
|
+
"path": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"description": "Directory path (default: current directory).",
|
|
109
|
+
},
|
|
110
|
+
"pattern": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"description": "Optional glob pattern filter (e.g. '*.py' for Python files, '**/*.ts' for all TypeScript recursively).",
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
"required": [],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"type": "function",
|
|
121
|
+
"function": {
|
|
122
|
+
"name": "grep_search",
|
|
123
|
+
"description": "A powerful content search tool using regex. Searches file contents and returns matching lines with file paths and line numbers. Use for finding relevant code, references, and patterns across the codebase. ALWAYS use this instead of invoking grep/rg via shell. Supports full regex syntax. Filter files with the include parameter (e.g. '*.py', '*.{ts,tsx}'). Results are capped at 200 matches.",
|
|
124
|
+
"parameters": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"properties": {
|
|
127
|
+
"pattern": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"description": "Regex pattern to search for in file contents. Uses ripgrep syntax — escape literal braces.",
|
|
130
|
+
},
|
|
131
|
+
"include": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"description": "Optional file glob pattern to filter by (e.g. '*.py', '*.{ts,tsx}').",
|
|
134
|
+
},
|
|
135
|
+
"path": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"description": "Directory to search (default: current directory).",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
"required": ["pattern"],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"type": "function",
|
|
146
|
+
"function": {
|
|
147
|
+
"name": "web_search",
|
|
148
|
+
"description": "Search the web for current information. Use for finding docs, APIs, news, and other information not available locally. Results include titles and snippets from relevant pages.",
|
|
149
|
+
"parameters": {
|
|
150
|
+
"type": "object",
|
|
151
|
+
"properties": {
|
|
152
|
+
"query": {
|
|
153
|
+
"type": "string",
|
|
154
|
+
"description": "Search query string.",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
"required": ["query"],
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"type": "function",
|
|
163
|
+
"function": {
|
|
164
|
+
"name": "web_fetch",
|
|
165
|
+
"description": "Fetch and extract content from a URL. Returns the page content up to 50000 chars. Use for reading documentation, blog posts, and web APIs.",
|
|
166
|
+
"parameters": {
|
|
167
|
+
"type": "object",
|
|
168
|
+
"properties": {
|
|
169
|
+
"url": {
|
|
170
|
+
"type": "string",
|
|
171
|
+
"description": "The fully-formed valid URL to fetch content from.",
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
"required": ["url"],
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"type": "function",
|
|
180
|
+
"function": {
|
|
181
|
+
"name": "todo_write",
|
|
182
|
+
"description": "Create and manage a structured task list for the current session. Use at the start of complex multi-step tasks (3+ steps). Helps track progress and demonstrate thoroughness. Each task has a content, status (pending/in_progress/completed/cancelled), and priority. Mark items complete as you finish them. Exactly one task should be in_progress at a time. Skip for trivial/single-step tasks.",
|
|
183
|
+
"parameters": {
|
|
184
|
+
"type": "object",
|
|
185
|
+
"properties": {
|
|
186
|
+
"todos": {
|
|
187
|
+
"type": "array",
|
|
188
|
+
"items": {
|
|
189
|
+
"type": "object",
|
|
190
|
+
"properties": {
|
|
191
|
+
"content": {"type": "string", "description": "Brief imperative description of the task item."},
|
|
192
|
+
"status": {"type": "string", "enum": ["pending", "in_progress", "completed", "cancelled"], "description": "Current status."},
|
|
193
|
+
"priority": {"type": "string", "enum": ["high", "medium", "low"], "description": "Priority level."},
|
|
194
|
+
},
|
|
195
|
+
"required": ["content", "status", "priority"],
|
|
196
|
+
},
|
|
197
|
+
"description": "List of todo items. Use proactively for complex work.",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
"required": ["todos"],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"type": "function",
|
|
206
|
+
"function": {
|
|
207
|
+
"name": "memory_save",
|
|
208
|
+
"description": "Save a persistent file-based memory across sessions. Each memory is one file holding one fact. A good memory is applicable (improves future actions), durable (matters beyond this session), and legible (readable without the original session). Types: user (who the user is), feedback (corrections, preferences), project (goals, constraints), reference (external resources). Save corrections in the same reply — before treating your turn as finished. Do not save what the repo already records.",
|
|
209
|
+
"parameters": {
|
|
210
|
+
"type": "object",
|
|
211
|
+
"properties": {
|
|
212
|
+
"name": {"type": "string", "description": "Short kebab-case slug (e.g. 'user-prefers-pytest')."},
|
|
213
|
+
"content": {"type": "string", "description": "The fact to remember. Include why it matters and how to apply it. Write in connected full sentences."},
|
|
214
|
+
"type": {"type": "string", "enum": ["user", "feedback", "project", "reference"], "description": "Memory type — determines when it's recalled."},
|
|
215
|
+
"description": {"type": "string", "description": "One-line summary used for relevance during recall."},
|
|
216
|
+
"pinned": {"type": "boolean", "description": "If true, applies to ALL future sessions, not just this project. Pin memories that should always apply."},
|
|
217
|
+
},
|
|
218
|
+
"required": ["name", "content"],
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"type": "function",
|
|
224
|
+
"function": {
|
|
225
|
+
"name": "memory_list",
|
|
226
|
+
"description": "List all saved memories, optionally filtered by type. Use to see what memories exist before deciding what to search or update.",
|
|
227
|
+
"parameters": {
|
|
228
|
+
"type": "object",
|
|
229
|
+
"properties": {
|
|
230
|
+
"type": {"type": "string", "enum": ["user", "feedback", "project", "reference"], "description": "Optional memory type filter."},
|
|
231
|
+
},
|
|
232
|
+
"required": [],
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"type": "function",
|
|
238
|
+
"function": {
|
|
239
|
+
"name": "memory_search",
|
|
240
|
+
"description": "Search through saved memories across all sessions. Use before asking the user questions — you may already know the answer. Returns matching memories with their content.",
|
|
241
|
+
"parameters": {
|
|
242
|
+
"type": "object",
|
|
243
|
+
"properties": {
|
|
244
|
+
"query": {"type": "string", "description": "Search query to find relevant memories."},
|
|
245
|
+
},
|
|
246
|
+
"required": ["query"],
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"type": "function",
|
|
252
|
+
"function": {
|
|
253
|
+
"name": "memory_delete",
|
|
254
|
+
"description": "Delete a memory by name/slug. Use when a memory turns out to be wrong, outdated, or superseded.",
|
|
255
|
+
"parameters": {
|
|
256
|
+
"type": "object",
|
|
257
|
+
"properties": {
|
|
258
|
+
"name": {"type": "string", "description": "The kebab-case slug of the memory to delete."},
|
|
259
|
+
},
|
|
260
|
+
"required": ["name"],
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
"type": "function",
|
|
266
|
+
"function": {
|
|
267
|
+
"name": "task_create",
|
|
268
|
+
"description": "Create a subagent task to do work asynchronously. Use for parallel research, isolated implementation, or background verification. The task runs independently and reports via notification when complete. Brief the subagent like a smart colleague who hasn't seen the conversation — include file paths, what to do, what done looks like. Don't duplicate work a subagent is doing.",
|
|
269
|
+
"parameters": {
|
|
270
|
+
"type": "object",
|
|
271
|
+
"properties": {
|
|
272
|
+
"description": {"type": "string", "description": "Short actionable description of the task (shown in task list)."},
|
|
273
|
+
"prompt": {"type": "string", "description": "Self-contained instructions for the subagent. Include file paths, what to do, what done looks like."},
|
|
274
|
+
"subagent_type": {"type": "string", "enum": ["worker", "fork", "explore"], "description": "Type of subagent: worker for implementation, fork for research (inherits context), explore for codebase search."},
|
|
275
|
+
},
|
|
276
|
+
"required": ["description", "prompt"],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"type": "function",
|
|
282
|
+
"function": {
|
|
283
|
+
"name": "task_stop",
|
|
284
|
+
"description": "Stop a running subagent task by ID. Use when requirements change mid-task or a worker is going in the wrong direction.",
|
|
285
|
+
"parameters": {
|
|
286
|
+
"type": "object",
|
|
287
|
+
"properties": {
|
|
288
|
+
"task_id": {"type": "string", "description": "The task ID to stop."},
|
|
289
|
+
},
|
|
290
|
+
"required": ["task_id"],
|
|
291
|
+
},
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"type": "function",
|
|
296
|
+
"function": {
|
|
297
|
+
"name": "task_list",
|
|
298
|
+
"description": "List all subagent tasks and their statuses. Optionally filter by status. Returns task IDs, descriptions, statuses, and durations.",
|
|
299
|
+
"parameters": {
|
|
300
|
+
"type": "object",
|
|
301
|
+
"properties": {
|
|
302
|
+
"status": {"type": "string", "enum": ["pending", "running", "completed", "failed", "stopped"], "description": "Optional status filter."},
|
|
303
|
+
},
|
|
304
|
+
"required": [],
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
]
|
|
309
|
+
|
|
310
|
+
# compact versions for tool lists with token constraints
|
|
311
|
+
COMPACT_TOOL_DEFINITIONS = [
|
|
312
|
+
{
|
|
313
|
+
"type": "function",
|
|
314
|
+
"function": {
|
|
315
|
+
"name": t["function"]["name"],
|
|
316
|
+
"description": t["function"]["description"].split(".")[0] + ".",
|
|
317
|
+
"parameters": {
|
|
318
|
+
"type": "object",
|
|
319
|
+
"properties": {k: {"type": v.get("type", "string")} for k, v in t["function"]["parameters"]["properties"].items()},
|
|
320
|
+
"required": t["function"]["parameters"]["required"],
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
for t in TOOL_DEFINITIONS
|
|
325
|
+
]
|