@within-7/minto 0.3.0 → 0.3.3
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/dist/components/SubagentProgress.js +10 -2
- package/dist/components/SubagentProgress.js.map +2 -2
- package/dist/constants/prompts.js +22 -1
- package/dist/constants/prompts.js.map +2 -2
- package/dist/entrypoints/cli.js +15 -9
- package/dist/entrypoints/cli.js.map +2 -2
- package/dist/permissions.js +121 -2
- package/dist/permissions.js.map +2 -2
- package/dist/screens/ResumeConversation.js +2 -0
- package/dist/screens/ResumeConversation.js.map +2 -2
- package/dist/services/taskStore.js +205 -0
- package/dist/services/taskStore.js.map +7 -0
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js +40 -3
- package/dist/tools/AskUserQuestionTool/AskUserQuestionTool.js.map +2 -2
- package/dist/tools/BashTool/BashTool.js +21 -4
- package/dist/tools/BashTool/BashTool.js.map +2 -2
- package/dist/tools/BashTool/prompt.js +6 -0
- package/dist/tools/BashTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/FileEditTool.js +24 -9
- package/dist/tools/FileEditTool/FileEditTool.js.map +2 -2
- package/dist/tools/FileEditTool/prompt.js +4 -1
- package/dist/tools/FileEditTool/prompt.js.map +2 -2
- package/dist/tools/FileEditTool/utils.js +10 -4
- package/dist/tools/FileEditTool/utils.js.map +2 -2
- package/dist/tools/FileReadTool/FileReadTool.js +1 -1
- package/dist/tools/FileReadTool/FileReadTool.js.map +1 -1
- package/dist/tools/FileReadTool/prompt.js +16 -1
- package/dist/tools/FileReadTool/prompt.js.map +2 -2
- package/dist/tools/FileWriteTool/FileWriteTool.js +1 -1
- package/dist/tools/FileWriteTool/FileWriteTool.js.map +1 -1
- package/dist/tools/FileWriteTool/prompt.js +8 -1
- package/dist/tools/FileWriteTool/prompt.js.map +2 -2
- package/dist/tools/GlobTool/prompt.js +12 -1
- package/dist/tools/GlobTool/prompt.js.map +2 -2
- package/dist/tools/GrepTool/GrepTool.js +333 -65
- package/dist/tools/GrepTool/GrepTool.js.map +2 -2
- package/dist/tools/GrepTool/prompt.js +15 -8
- package/dist/tools/GrepTool/prompt.js.map +2 -2
- package/dist/tools/NotebookEditTool/NotebookEditTool.js +57 -45
- package/dist/tools/NotebookEditTool/NotebookEditTool.js.map +2 -2
- package/dist/tools/NotebookEditTool/prompt.js +1 -1
- package/dist/tools/NotebookEditTool/prompt.js.map +1 -1
- package/dist/tools/TaskCreateTool/TaskCreateTool.js +102 -0
- package/dist/tools/TaskCreateTool/TaskCreateTool.js.map +7 -0
- package/dist/tools/TaskCreateTool/prompt.js +47 -0
- package/dist/tools/TaskCreateTool/prompt.js.map +7 -0
- package/dist/tools/TaskGetTool/TaskGetTool.js +115 -0
- package/dist/tools/TaskGetTool/TaskGetTool.js.map +7 -0
- package/dist/tools/TaskGetTool/prompt.js +28 -0
- package/dist/tools/TaskGetTool/prompt.js.map +7 -0
- package/dist/tools/TaskListTool/TaskListTool.js +102 -0
- package/dist/tools/TaskListTool/TaskListTool.js.map +7 -0
- package/dist/tools/TaskListTool/prompt.js +27 -0
- package/dist/tools/TaskListTool/prompt.js.map +7 -0
- package/dist/tools/TaskStopTool/TaskStopTool.js +150 -0
- package/dist/tools/TaskStopTool/TaskStopTool.js.map +7 -0
- package/dist/tools/TaskStopTool/prompt.js +15 -0
- package/dist/tools/TaskStopTool/prompt.js.map +7 -0
- package/dist/tools/TaskTool/TaskTool.js +41 -1
- package/dist/tools/TaskTool/TaskTool.js.map +2 -2
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js +134 -0
- package/dist/tools/TaskUpdateTool/TaskUpdateTool.js.map +7 -0
- package/dist/tools/TaskUpdateTool/prompt.js +81 -0
- package/dist/tools/TaskUpdateTool/prompt.js.map +7 -0
- package/dist/tools/URLFetcherTool/prompt.js +1 -1
- package/dist/tools/URLFetcherTool/prompt.js.map +1 -1
- package/dist/tools.js +12 -0
- package/dist/tools.js.map +2 -2
- package/dist/utils/config.js.map +2 -2
- package/dist/utils/model.js +15 -2
- package/dist/utils/model.js.map +2 -2
- package/dist/utils/ripgrep.js +53 -1
- package/dist/utils/ripgrep.js.map +2 -2
- package/dist/utils/terminal.js +12 -0
- package/dist/utils/terminal.js.map +2 -2
- package/dist/utils/tooling/safeRender.js +13 -14
- package/dist/utils/tooling/safeRender.js.map +2 -2
- package/dist/version.js +2 -2
- package/dist/version.js.map +1 -1
- package/package.json +20 -28
|
@@ -21,17 +21,19 @@ const inputSchema = z.strictObject({
|
|
|
21
21
|
notebook_path: z.string().describe(
|
|
22
22
|
"The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)"
|
|
23
23
|
),
|
|
24
|
-
|
|
24
|
+
cell_id: z.string().optional().describe(
|
|
25
|
+
"The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified."
|
|
26
|
+
),
|
|
25
27
|
new_source: z.string().describe("The new source for the cell"),
|
|
26
28
|
cell_type: z.enum(["code", "markdown"]).optional().describe(
|
|
27
29
|
"The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required."
|
|
28
30
|
),
|
|
29
|
-
edit_mode: z.
|
|
31
|
+
edit_mode: z.enum(["replace", "insert", "delete"]).optional().describe(
|
|
30
32
|
"The type of edit to make (replace, insert, delete). Defaults to replace."
|
|
31
33
|
)
|
|
32
34
|
});
|
|
33
35
|
const NotebookEditTool = {
|
|
34
|
-
name: "
|
|
36
|
+
name: "NotebookEdit",
|
|
35
37
|
async description() {
|
|
36
38
|
return DESCRIPTION;
|
|
37
39
|
},
|
|
@@ -54,21 +56,21 @@ const NotebookEditTool = {
|
|
|
54
56
|
needsPermissions({ notebook_path }) {
|
|
55
57
|
return !hasWritePermission(notebook_path);
|
|
56
58
|
},
|
|
57
|
-
renderResultForAssistant({
|
|
59
|
+
renderResultForAssistant({ cell_id, edit_mode, new_source, error }) {
|
|
58
60
|
if (error) {
|
|
59
61
|
return error;
|
|
60
62
|
}
|
|
61
63
|
switch (edit_mode) {
|
|
62
64
|
case "replace":
|
|
63
|
-
return `Updated cell ${
|
|
65
|
+
return `Updated cell ${cell_id} with ${new_source}`;
|
|
64
66
|
case "insert":
|
|
65
|
-
return `Inserted cell ${
|
|
67
|
+
return `Inserted cell after ${cell_id || "beginning"} with ${new_source}`;
|
|
66
68
|
case "delete":
|
|
67
|
-
return `Deleted cell ${
|
|
69
|
+
return `Deleted cell ${cell_id}`;
|
|
68
70
|
}
|
|
69
71
|
},
|
|
70
72
|
renderToolUseMessage(input, { verbose }) {
|
|
71
|
-
return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)},
|
|
73
|
+
return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell_id: ${input.cell_id || "(beginning)"}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? "replace"}`;
|
|
72
74
|
},
|
|
73
75
|
renderToolUseRejectedMessage() {
|
|
74
76
|
return /* @__PURE__ */ React.createElement(FallbackToolUseRejectedMessage, null);
|
|
@@ -77,15 +79,15 @@ const NotebookEditTool = {
|
|
|
77
79
|
if (!output) {
|
|
78
80
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Notebook cell updated"));
|
|
79
81
|
}
|
|
80
|
-
const {
|
|
82
|
+
const { cell_id, new_source, language, error } = output;
|
|
81
83
|
if (error) {
|
|
82
84
|
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, { color: "red" }, error));
|
|
83
85
|
}
|
|
84
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Updated cell ",
|
|
86
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Text, null, "Updated cell ", cell_id, ":"), /* @__PURE__ */ React.createElement(Box, { marginLeft: 2 }, /* @__PURE__ */ React.createElement(HighlightedCode, { code: new_source, language })));
|
|
85
87
|
},
|
|
86
88
|
async validateInput({
|
|
87
89
|
notebook_path,
|
|
88
|
-
|
|
90
|
+
cell_id,
|
|
89
91
|
cell_type,
|
|
90
92
|
edit_mode = "replace"
|
|
91
93
|
}) {
|
|
@@ -102,18 +104,6 @@ const NotebookEditTool = {
|
|
|
102
104
|
message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`
|
|
103
105
|
};
|
|
104
106
|
}
|
|
105
|
-
if (cell_number < 0) {
|
|
106
|
-
return {
|
|
107
|
-
result: false,
|
|
108
|
-
message: "Cell number must be non-negative."
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
if (edit_mode !== "replace" && edit_mode !== "insert" && edit_mode !== "delete") {
|
|
112
|
-
return {
|
|
113
|
-
result: false,
|
|
114
|
-
message: "Edit mode must be replace, insert, or delete."
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
107
|
if (edit_mode === "insert" && !cell_type) {
|
|
118
108
|
return {
|
|
119
109
|
result: false,
|
|
@@ -129,48 +119,70 @@ const NotebookEditTool = {
|
|
|
129
119
|
message: "Notebook is not valid JSON."
|
|
130
120
|
};
|
|
131
121
|
}
|
|
132
|
-
if (edit_mode === "
|
|
133
|
-
return {
|
|
134
|
-
result: false,
|
|
135
|
-
message: `Cell number is out of bounds. For insert mode, the maximum value is ${notebook.cells.length} (to append at the end).`
|
|
136
|
-
};
|
|
137
|
-
} else if ((edit_mode === "replace" || edit_mode === "delete") && (cell_number >= notebook.cells.length || !notebook.cells[cell_number])) {
|
|
122
|
+
if ((edit_mode === "replace" || edit_mode === "delete") && !cell_id) {
|
|
138
123
|
return {
|
|
139
124
|
result: false,
|
|
140
|
-
message:
|
|
125
|
+
message: "cell_id is required for replace and delete operations."
|
|
141
126
|
};
|
|
142
127
|
}
|
|
128
|
+
if (cell_id) {
|
|
129
|
+
const cellIndex = notebook.cells.findIndex(
|
|
130
|
+
(cell, index) => cell.id === cell_id || String(index) === cell_id
|
|
131
|
+
);
|
|
132
|
+
if (cellIndex === -1 && edit_mode !== "insert") {
|
|
133
|
+
return {
|
|
134
|
+
result: false,
|
|
135
|
+
message: `Cell with ID '${cell_id}' not found in notebook. Available cells: ${notebook.cells.length}`
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
143
139
|
return { result: true };
|
|
144
140
|
},
|
|
145
|
-
async *call({
|
|
146
|
-
notebook_path,
|
|
147
|
-
cell_number,
|
|
148
|
-
new_source,
|
|
149
|
-
cell_type,
|
|
150
|
-
edit_mode
|
|
151
|
-
}) {
|
|
141
|
+
async *call({ notebook_path, cell_id, new_source, cell_type, edit_mode }) {
|
|
152
142
|
const fullPath = isAbsolute(notebook_path) ? notebook_path : resolve(getCwd(), notebook_path);
|
|
153
143
|
try {
|
|
154
144
|
const enc = detectFileEncoding(fullPath);
|
|
155
145
|
const content = readFileSync(fullPath, enc);
|
|
156
146
|
const notebook = JSON.parse(content);
|
|
157
147
|
const language = notebook.metadata.language_info?.name ?? "python";
|
|
148
|
+
const findCellIndex = (id) => {
|
|
149
|
+
if (!id) return 0;
|
|
150
|
+
const byId = notebook.cells.findIndex(
|
|
151
|
+
(cell) => cell.id === id
|
|
152
|
+
);
|
|
153
|
+
if (byId !== -1) return byId;
|
|
154
|
+
const numIndex = parseInt(id, 10);
|
|
155
|
+
if (!isNaN(numIndex) && numIndex >= 0 && numIndex < notebook.cells.length) {
|
|
156
|
+
return numIndex;
|
|
157
|
+
}
|
|
158
|
+
return -1;
|
|
159
|
+
};
|
|
160
|
+
const cellIndex = findCellIndex(cell_id);
|
|
158
161
|
if (edit_mode === "delete") {
|
|
159
|
-
|
|
162
|
+
if (cellIndex === -1) {
|
|
163
|
+
throw new Error(`Cell with ID '${cell_id}' not found`);
|
|
164
|
+
}
|
|
165
|
+
notebook.cells.splice(cellIndex, 1);
|
|
160
166
|
} else if (edit_mode === "insert") {
|
|
167
|
+
const insertIndex = cell_id ? cellIndex + 1 : 0;
|
|
168
|
+
const newCellId = `cell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
161
169
|
const new_cell = {
|
|
170
|
+
id: newCellId,
|
|
162
171
|
cell_type,
|
|
163
172
|
// validateInput ensures cell_type is not undefined
|
|
164
173
|
source: new_source,
|
|
165
174
|
metadata: {}
|
|
166
175
|
};
|
|
167
176
|
notebook.cells.splice(
|
|
168
|
-
|
|
177
|
+
insertIndex,
|
|
169
178
|
0,
|
|
170
|
-
cell_type
|
|
179
|
+
cell_type === "markdown" ? new_cell : { ...new_cell, outputs: [] }
|
|
171
180
|
);
|
|
172
181
|
} else {
|
|
173
|
-
|
|
182
|
+
if (cellIndex === -1) {
|
|
183
|
+
throw new Error(`Cell with ID '${cell_id}' not found`);
|
|
184
|
+
}
|
|
185
|
+
const targetCell = notebook.cells[cellIndex];
|
|
174
186
|
targetCell.source = new_source;
|
|
175
187
|
targetCell.execution_count = void 0;
|
|
176
188
|
targetCell.outputs = [];
|
|
@@ -184,7 +196,7 @@ const NotebookEditTool = {
|
|
|
184
196
|
recordFileEdit(fullPath, updatedNotebook);
|
|
185
197
|
emitReminderEvent("file:edited", {
|
|
186
198
|
filePath: fullPath,
|
|
187
|
-
|
|
199
|
+
cellId: cell_id,
|
|
188
200
|
newSource: new_source,
|
|
189
201
|
cellType: cell_type,
|
|
190
202
|
editMode: edit_mode || "replace",
|
|
@@ -192,7 +204,7 @@ const NotebookEditTool = {
|
|
|
192
204
|
operation: "notebook_edit"
|
|
193
205
|
});
|
|
194
206
|
const data = {
|
|
195
|
-
|
|
207
|
+
cell_id: cell_id || "0",
|
|
196
208
|
new_source,
|
|
197
209
|
cell_type: cell_type ?? "code",
|
|
198
210
|
language,
|
|
@@ -207,7 +219,7 @@ const NotebookEditTool = {
|
|
|
207
219
|
} catch (error) {
|
|
208
220
|
if (error instanceof Error) {
|
|
209
221
|
const data2 = {
|
|
210
|
-
|
|
222
|
+
cell_id: cell_id || "0",
|
|
211
223
|
new_source,
|
|
212
224
|
cell_type: cell_type ?? "code",
|
|
213
225
|
language: "python",
|
|
@@ -222,7 +234,7 @@ const NotebookEditTool = {
|
|
|
222
234
|
return;
|
|
223
235
|
}
|
|
224
236
|
const data = {
|
|
225
|
-
|
|
237
|
+
cell_id: cell_id || "0",
|
|
226
238
|
new_source,
|
|
227
239
|
cell_type: cell_type ?? "code",
|
|
228
240
|
language: "python",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/NotebookEditTool/NotebookEditTool.tsx"],
|
|
4
|
-
"sourcesContent": ["import { existsSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { HighlightedCode } from '@components/HighlightedCode'\nimport type { Tool } from '@tool'\nimport { NotebookCellType, NotebookContent } from '@minto-types/notebook'\nimport {\n detectFileEncoding,\n detectLineEndings,\n writeTextContent,\n} from '@utils/file'\nimport { safeParseJSON } from '@utils/json'\nimport { getCwd } from '@utils/state'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { FileEditTool } from '@tools/FileEditTool/FileEditTool'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)',\n ),\n cell_number: z.number().describe('The index of the cell to edit (0-based)'),\n new_source: z.string().describe('The new source for the cell'),\n cell_type: z\n .enum(['code', 'markdown'])\n .optional()\n .describe(\n 'The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.',\n ),\n edit_mode: z\n .string()\n .optional()\n .describe(\n 'The type of edit to make (replace, insert, delete). Defaults to replace.',\n ),\n})\n\nexport const NotebookEditTool = {\n name: 'NotebookEditCell',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Edit Notebook'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // NotebookEditTool modifies state/files, not safe for concurrent execution\n },\n needsPermissions({ notebook_path }) {\n return !hasWritePermission(notebook_path)\n },\n renderResultForAssistant({ cell_number, edit_mode, new_source, error }) {\n if (error) {\n return error\n }\n switch (edit_mode) {\n case 'replace':\n return `Updated cell ${cell_number} with ${new_source}`\n case 'insert':\n return `Inserted cell ${cell_number} with ${new_source}`\n case 'delete':\n return `Deleted cell ${cell_number}`\n }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell: ${input.cell_number}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? 'replace'}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text>Notebook cell updated</Text>\n </Box>\n )\n }\n\n const { cell_number, new_source, language, error } = output\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text>Updated cell {cell_number}:</Text>\n <Box marginLeft={2}>\n <HighlightedCode code={new_source} language={language} />\n </Box>\n </Box>\n )\n },\n async validateInput({\n notebook_path,\n cell_number,\n cell_type,\n edit_mode = 'replace',\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullPath)) {\n return {\n result: false,\n message: 'Notebook file does not exist.',\n }\n }\n\n if (extname(fullPath) !== '.ipynb') {\n return {\n result: false,\n message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`,\n }\n }\n\n if (cell_number < 0) {\n return {\n result: false,\n message: 'Cell number must be non-negative.',\n }\n }\n\n if (\n edit_mode !== 'replace' &&\n edit_mode !== 'insert' &&\n edit_mode !== 'delete'\n ) {\n return {\n result: false,\n message: 'Edit mode must be replace, insert, or delete.',\n }\n }\n\n if (edit_mode === 'insert' && !cell_type) {\n return {\n result: false,\n message: 'Cell type is required when using edit_mode=insert.',\n }\n }\n\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = safeParseJSON(content) as NotebookContent | null\n if (!notebook) {\n return {\n result: false,\n message: 'Notebook is not valid JSON.',\n }\n }\n\n if (edit_mode === 'insert' && cell_number > notebook.cells.length) {\n return {\n result: false,\n message: `Cell number is out of bounds. For insert mode, the maximum value is ${notebook.cells.length} (to append at the end).`,\n }\n } else if (\n (edit_mode === 'replace' || edit_mode === 'delete') &&\n (cell_number >= notebook.cells.length || !notebook.cells[cell_number])\n ) {\n return {\n result: false,\n message: `Cell number is out of bounds. Notebook has ${notebook.cells.length} cells.`,\n }\n }\n\n return { result: true }\n },\n async *call({\n notebook_path,\n cell_number,\n new_source,\n cell_type,\n edit_mode,\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n try {\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n\n if (edit_mode === 'delete') {\n // Delete the specified cell\n notebook.cells.splice(cell_number, 1)\n } else if (edit_mode === 'insert') {\n // Insert the new cell\n const new_cell = {\n cell_type: cell_type!, // validateInput ensures cell_type is not undefined\n source: new_source,\n metadata: {},\n }\n notebook.cells.splice(\n cell_number,\n 0,\n cell_type == 'markdown' ? new_cell : { ...new_cell, outputs: [] },\n )\n } else {\n // Find the specified cell\n const targetCell = notebook.cells[cell_number]! // validateInput ensures cell_number is in bounds\n targetCell.source = new_source\n // Reset execution count and clear outputs since cell was modified\n targetCell.execution_count = undefined\n targetCell.outputs = []\n if (cell_type && cell_type !== targetCell.cell_type) {\n targetCell.cell_type = cell_type\n }\n }\n // Write back to file\n const endings = detectLineEndings(fullPath)\n const updatedNotebook = JSON.stringify(notebook, null, 1)\n writeTextContent(fullPath, updatedNotebook, enc, endings!)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, updatedNotebook)\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath: fullPath,\n cellNumber: cell_number,\n newSource: new_source,\n cellType: cell_type,\n editMode: edit_mode || 'replace',\n timestamp: Date.now(),\n operation: 'notebook_edit',\n })\n const data = {\n cell_number,\n new_source,\n cell_type: cell_type ?? 'code',\n language,\n edit_mode: edit_mode ?? 'replace',\n error: '',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n } catch (error) {\n if (error instanceof Error) {\n const data = {\n cell_number,\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: error.message,\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n return\n }\n const data = {\n cell_number,\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: 'Unknown error occurred while editing notebook',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n {\n cell_number: number\n new_source: string\n cell_type: NotebookCellType\n language: string\n edit_mode: string\n error?: string\n }\n>\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,KAAK,YAAY;AAC1B,SAAS,SAAS,YAAY,UAAU,eAAe;AACvD,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAC/C,SAAS,uBAAuB;AAGhC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AACvB,SAAS,aAAa,cAAc;AACpC,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAE7B,MAAM,cAAc,EAAE,aAAa;AAAA,EACjC,eAAe,EACZ,OAAO,EACP;AAAA,IACC;AAAA,EACF;AAAA,EACF,
|
|
4
|
+
"sourcesContent": ["import { existsSync, readFileSync } from 'fs'\nimport { Box, Text } from 'ink'\nimport { extname, isAbsolute, relative, resolve } from 'path'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { HighlightedCode } from '@components/HighlightedCode'\nimport type { Tool } from '@tool'\nimport { NotebookCellType, NotebookContent } from '@minto-types/notebook'\nimport {\n detectFileEncoding,\n detectLineEndings,\n writeTextContent,\n} from '@utils/file'\nimport { safeParseJSON } from '@utils/json'\nimport { getCwd } from '@utils/state'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { hasWritePermission } from '@utils/permissions/filesystem'\nimport { emitReminderEvent } from '@services/systemReminder'\nimport { recordFileEdit } from '@services/fileFreshness'\nimport { FileEditTool } from '@tools/FileEditTool/FileEditTool'\n\nconst inputSchema = z.strictObject({\n notebook_path: z\n .string()\n .describe(\n 'The absolute path to the Jupyter notebook file to edit (must be absolute, not relative)',\n ),\n cell_id: z\n .string()\n .optional()\n .describe(\n 'The ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified.',\n ),\n new_source: z.string().describe('The new source for the cell'),\n cell_type: z\n .enum(['code', 'markdown'])\n .optional()\n .describe(\n 'The type of the cell (code or markdown). If not specified, it defaults to the current cell type. If using edit_mode=insert, this is required.',\n ),\n edit_mode: z\n .enum(['replace', 'insert', 'delete'])\n .optional()\n .describe(\n 'The type of edit to make (replace, insert, delete). Defaults to replace.',\n ),\n})\n\nexport const NotebookEditTool = {\n name: 'NotebookEdit',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Edit Notebook'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false // NotebookEditTool modifies state/files, not safe for concurrent execution\n },\n needsPermissions({ notebook_path }) {\n return !hasWritePermission(notebook_path)\n },\n renderResultForAssistant({ cell_id, edit_mode, new_source, error }) {\n if (error) {\n return error\n }\n switch (edit_mode) {\n case 'replace':\n return `Updated cell ${cell_id} with ${new_source}`\n case 'insert':\n return `Inserted cell after ${cell_id || 'beginning'} with ${new_source}`\n case 'delete':\n return `Deleted cell ${cell_id}`\n }\n },\n renderToolUseMessage(input, { verbose }) {\n return `notebook_path: ${verbose ? input.notebook_path : relative(getCwd(), input.notebook_path)}, cell_id: ${input.cell_id || '(beginning)'}, content: ${input.new_source.slice(0, 30)}\u2026, cell_type: ${input.cell_type}, edit_mode: ${input.edit_mode ?? 'replace'}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output) {\n // Guard against undefined or null output\n if (!output) {\n return (\n <Box flexDirection=\"column\">\n <Text>Notebook cell updated</Text>\n </Box>\n )\n }\n\n const { cell_id, new_source, language, error } = output\n\n if (error) {\n return (\n <Box flexDirection=\"column\">\n <Text color=\"red\">{error}</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"column\">\n <Text>Updated cell {cell_id}:</Text>\n <Box marginLeft={2}>\n <HighlightedCode code={new_source} language={language} />\n </Box>\n </Box>\n )\n },\n async validateInput({\n notebook_path,\n cell_id,\n cell_type,\n edit_mode = 'replace',\n }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n if (!existsSync(fullPath)) {\n return {\n result: false,\n message: 'Notebook file does not exist.',\n }\n }\n\n if (extname(fullPath) !== '.ipynb') {\n return {\n result: false,\n message: `File must be a Jupyter notebook (.ipynb file). For editing other file types, use the ${FileEditTool.name} tool.`,\n }\n }\n\n if (edit_mode === 'insert' && !cell_type) {\n return {\n result: false,\n message: 'Cell type is required when using edit_mode=insert.',\n }\n }\n\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = safeParseJSON(content) as NotebookContent | null\n if (!notebook) {\n return {\n result: false,\n message: 'Notebook is not valid JSON.',\n }\n }\n\n // For replace and delete, cell_id is required and must exist\n if ((edit_mode === 'replace' || edit_mode === 'delete') && !cell_id) {\n return {\n result: false,\n message: 'cell_id is required for replace and delete operations.',\n }\n }\n\n // Validate cell_id exists in notebook (if provided)\n if (cell_id) {\n const cellIndex = notebook.cells.findIndex(\n (cell: { id?: string }, index: number) =>\n cell.id === cell_id || String(index) === cell_id,\n )\n if (cellIndex === -1 && edit_mode !== 'insert') {\n return {\n result: false,\n message: `Cell with ID '${cell_id}' not found in notebook. Available cells: ${notebook.cells.length}`,\n }\n }\n }\n\n return { result: true }\n },\n async *call({ notebook_path, cell_id, new_source, cell_type, edit_mode }) {\n const fullPath = isAbsolute(notebook_path)\n ? notebook_path\n : resolve(getCwd(), notebook_path)\n\n try {\n const enc = detectFileEncoding(fullPath)\n const content = readFileSync(fullPath, enc)\n const notebook = JSON.parse(content) as NotebookContent\n const language = notebook.metadata.language_info?.name ?? 'python'\n\n // Find cell index by ID (or treat cell_id as index string for backward compatibility)\n const findCellIndex = (id: string | undefined): number => {\n if (!id) return 0 // Insert at beginning if no cell_id\n const byId = notebook.cells.findIndex(\n (cell: { id?: string }) => cell.id === id,\n )\n if (byId !== -1) return byId\n // Fallback: treat as numeric index for backward compatibility\n const numIndex = parseInt(id, 10)\n if (\n !isNaN(numIndex) &&\n numIndex >= 0 &&\n numIndex < notebook.cells.length\n ) {\n return numIndex\n }\n return -1\n }\n\n const cellIndex = findCellIndex(cell_id)\n\n if (edit_mode === 'delete') {\n // Delete the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n notebook.cells.splice(cellIndex, 1)\n } else if (edit_mode === 'insert') {\n // Insert the new cell after the specified cell (or at beginning if no cell_id)\n const insertIndex = cell_id ? cellIndex + 1 : 0\n const newCellId = `cell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n const new_cell = {\n id: newCellId,\n cell_type: cell_type!, // validateInput ensures cell_type is not undefined\n source: new_source,\n metadata: {},\n }\n notebook.cells.splice(\n insertIndex,\n 0,\n cell_type === 'markdown' ? new_cell : { ...new_cell, outputs: [] },\n )\n } else {\n // Replace: Find the specified cell\n if (cellIndex === -1) {\n throw new Error(`Cell with ID '${cell_id}' not found`)\n }\n const targetCell = notebook.cells[cellIndex]!\n targetCell.source = new_source\n // Reset execution count and clear outputs since cell was modified\n targetCell.execution_count = undefined\n targetCell.outputs = []\n if (cell_type && cell_type !== targetCell.cell_type) {\n targetCell.cell_type = cell_type\n }\n }\n // Write back to file\n const endings = detectLineEndings(fullPath)\n const updatedNotebook = JSON.stringify(notebook, null, 1)\n writeTextContent(fullPath, updatedNotebook, enc, endings!)\n\n // Record Agent edit operation for file freshness tracking\n recordFileEdit(fullPath, updatedNotebook)\n\n // Emit file edited event for system reminders\n emitReminderEvent('file:edited', {\n filePath: fullPath,\n cellId: cell_id,\n newSource: new_source,\n cellType: cell_type,\n editMode: edit_mode || 'replace',\n timestamp: Date.now(),\n operation: 'notebook_edit',\n })\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language,\n edit_mode: edit_mode ?? 'replace',\n error: '',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n } catch (error) {\n if (error instanceof Error) {\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: error.message,\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n return\n }\n const data = {\n cell_id: cell_id || '0',\n new_source,\n cell_type: cell_type ?? 'code',\n language: 'python',\n edit_mode: 'replace',\n error: 'Unknown error occurred while editing notebook',\n }\n yield {\n type: 'result',\n data,\n resultForAssistant: this.renderResultForAssistant(data),\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n {\n cell_id: string\n new_source: string\n cell_type: NotebookCellType\n language: string\n edit_mode: string\n error?: string\n }\n>\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["data"]
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const DESCRIPTION = "Replace the contents of a specific cell in a Jupyter notebook.";
|
|
2
|
-
const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The
|
|
2
|
+
const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_id is the ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified. Use edit_mode=insert to add a new cell at the index specified by cell_id. Use edit_mode=delete to delete the cell at the index specified by cell_id.`;
|
|
3
3
|
export {
|
|
4
4
|
DESCRIPTION,
|
|
5
5
|
PROMPT
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/NotebookEditTool/prompt.ts"],
|
|
4
|
-
"sourcesContent": ["export const DESCRIPTION =\n 'Replace the contents of a specific cell in a Jupyter notebook.'\nexport const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The
|
|
4
|
+
"sourcesContent": ["export const DESCRIPTION =\n 'Replace the contents of a specific cell in a Jupyter notebook.'\nexport const PROMPT = `Completely replaces the contents of a specific cell in a Jupyter notebook (.ipynb file) with new source. Jupyter notebooks are interactive documents that combine code, text, and visualizations, commonly used for data analysis and scientific computing. The notebook_path parameter must be an absolute path, not a relative path. The cell_id is the ID of the cell to edit. When inserting a new cell, the new cell will be inserted after the cell with this ID, or at the beginning if not specified. Use edit_mode=insert to add a new cell at the index specified by cell_id. Use edit_mode=delete to delete the cell at the index specified by cell_id.`\n"],
|
|
5
5
|
"mappings": "AAAO,MAAM,cACX;AACK,MAAM,SAAS;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { FallbackToolUseRejectedMessage } from "../../components/FallbackToolUseRejectedMessage.js";
|
|
5
|
+
import { createTask } from "../../services/taskStore.js";
|
|
6
|
+
import { DESCRIPTION, PROMPT } from "./prompt.js";
|
|
7
|
+
import { getTheme } from "../../utils/theme.js";
|
|
8
|
+
const inputSchema = z.strictObject({
|
|
9
|
+
subject: z.string().describe("A brief title for the task"),
|
|
10
|
+
description: z.string().describe("A detailed description of what needs to be done"),
|
|
11
|
+
activeForm: z.string().optional().describe(
|
|
12
|
+
'Present continuous form shown in spinner when in_progress (e.g., "Running tests")'
|
|
13
|
+
),
|
|
14
|
+
metadata: z.record(z.unknown()).optional().describe("Arbitrary metadata to attach to the task")
|
|
15
|
+
});
|
|
16
|
+
const TaskCreateTool = {
|
|
17
|
+
name: "TaskCreate",
|
|
18
|
+
async description() {
|
|
19
|
+
return DESCRIPTION;
|
|
20
|
+
},
|
|
21
|
+
async prompt() {
|
|
22
|
+
return PROMPT;
|
|
23
|
+
},
|
|
24
|
+
inputSchema,
|
|
25
|
+
userFacingName() {
|
|
26
|
+
return "Create Task";
|
|
27
|
+
},
|
|
28
|
+
async isEnabled() {
|
|
29
|
+
return true;
|
|
30
|
+
},
|
|
31
|
+
isReadOnly() {
|
|
32
|
+
return false;
|
|
33
|
+
},
|
|
34
|
+
isConcurrencySafe() {
|
|
35
|
+
return false;
|
|
36
|
+
},
|
|
37
|
+
needsPermissions() {
|
|
38
|
+
return false;
|
|
39
|
+
},
|
|
40
|
+
renderToolUseMessage(input) {
|
|
41
|
+
const subject = input.subject || "";
|
|
42
|
+
const truncated = subject.length > 50 ? subject.slice(0, 50) + "..." : subject;
|
|
43
|
+
return `subject: "${truncated}"`;
|
|
44
|
+
},
|
|
45
|
+
renderToolUseRejectedMessage() {
|
|
46
|
+
return /* @__PURE__ */ React.createElement(FallbackToolUseRejectedMessage, null);
|
|
47
|
+
},
|
|
48
|
+
renderToolResultMessage(output) {
|
|
49
|
+
if (!output || !output.taskId) {
|
|
50
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, null, "Task created"));
|
|
51
|
+
}
|
|
52
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: getTheme().success }, "Task #", output.taskId, " created: ", output.subject));
|
|
53
|
+
},
|
|
54
|
+
renderResultForAssistant(result) {
|
|
55
|
+
return `Task #${result.taskId} created successfully: ${result.subject}`;
|
|
56
|
+
},
|
|
57
|
+
async validateInput({ subject, description }) {
|
|
58
|
+
if (!subject?.trim()) {
|
|
59
|
+
return {
|
|
60
|
+
result: false,
|
|
61
|
+
message: "Task subject cannot be empty"
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!description?.trim()) {
|
|
65
|
+
return {
|
|
66
|
+
result: false,
|
|
67
|
+
message: "Task description cannot be empty"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
return { result: true };
|
|
71
|
+
},
|
|
72
|
+
async *call(input) {
|
|
73
|
+
try {
|
|
74
|
+
const task = createTask({
|
|
75
|
+
subject: input.subject,
|
|
76
|
+
description: input.description,
|
|
77
|
+
activeForm: input.activeForm,
|
|
78
|
+
metadata: input.metadata
|
|
79
|
+
});
|
|
80
|
+
const result = {
|
|
81
|
+
taskId: task.id,
|
|
82
|
+
subject: task.subject
|
|
83
|
+
};
|
|
84
|
+
yield {
|
|
85
|
+
type: "result",
|
|
86
|
+
data: result,
|
|
87
|
+
resultForAssistant: this.renderResultForAssistant(result)
|
|
88
|
+
};
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
91
|
+
yield {
|
|
92
|
+
type: "result",
|
|
93
|
+
data: { error: errorMessage },
|
|
94
|
+
resultForAssistant: `Error creating task: ${errorMessage}`
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
export {
|
|
100
|
+
TaskCreateTool
|
|
101
|
+
};
|
|
102
|
+
//# sourceMappingURL=TaskCreateTool.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/tools/TaskCreateTool/TaskCreateTool.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { createTask } from '@services/taskStore'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { getTheme } from '@utils/theme'\n\nconst inputSchema = z.strictObject({\n subject: z.string().describe('A brief title for the task'),\n description: z\n .string()\n .describe('A detailed description of what needs to be done'),\n activeForm: z\n .string()\n .optional()\n .describe(\n 'Present continuous form shown in spinner when in_progress (e.g., \"Running tests\")',\n ),\n metadata: z\n .record(z.unknown())\n .optional()\n .describe('Arbitrary metadata to attach to the task'),\n})\n\nexport const TaskCreateTool = {\n name: 'TaskCreate',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Create Task'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return false\n },\n isConcurrencySafe() {\n return false\n },\n needsPermissions() {\n return false\n },\n renderToolUseMessage(input: z.infer<typeof inputSchema>) {\n const subject = input.subject || ''\n const truncated =\n subject.length > 50 ? subject.slice(0, 50) + '...' : subject\n return `subject: \"${truncated}\"`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output: { taskId: string; subject: string }) {\n if (!output || !output.taskId) {\n return (\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text>Task created</Text>\n </Box>\n )\n }\n\n return (\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().success}>\n Task #{output.taskId} created: {output.subject}\n </Text>\n </Box>\n )\n },\n renderResultForAssistant(result: { taskId: string; subject: string }) {\n return `Task #${result.taskId} created successfully: ${result.subject}`\n },\n async validateInput({ subject, description }: z.infer<typeof inputSchema>) {\n if (!subject?.trim()) {\n return {\n result: false,\n message: 'Task subject cannot be empty',\n }\n }\n if (!description?.trim()) {\n return {\n result: false,\n message: 'Task description cannot be empty',\n }\n }\n return { result: true }\n },\n async *call(input: z.infer<typeof inputSchema>) {\n try {\n const task = createTask({\n subject: input.subject,\n description: input.description,\n activeForm: input.activeForm,\n metadata: input.metadata,\n })\n\n const result = {\n taskId: task.id,\n subject: task.subject,\n }\n\n yield {\n type: 'result',\n data: result,\n resultForAssistant: this.renderResultForAssistant(result),\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n yield {\n type: 'result',\n data: { error: errorMessage },\n resultForAssistant: `Error creating task: ${errorMessage}`,\n }\n }\n },\n} satisfies Tool<\n typeof inputSchema,\n { taskId: string; subject: string } | { error: string }\n>\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,KAAK,YAAY;AAC1B,YAAY,WAAW;AACvB,SAAS,SAAS;AAClB,SAAS,sCAAsC;AAE/C,SAAS,kBAAkB;AAC3B,SAAS,aAAa,cAAc;AACpC,SAAS,gBAAgB;AAEzB,MAAM,cAAc,EAAE,aAAa;AAAA,EACjC,SAAS,EAAE,OAAO,EAAE,SAAS,4BAA4B;AAAA,EACzD,aAAa,EACV,OAAO,EACP,SAAS,iDAAiD;AAAA,EAC7D,YAAY,EACT,OAAO,EACP,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,UAAU,EACP,OAAO,EAAE,QAAQ,CAAC,EAClB,SAAS,EACT,SAAS,0CAA0C;AACxD,CAAC;AAEM,MAAM,iBAAiB;AAAA,EAC5B,MAAM;AAAA,EACN,MAAM,cAAc;AAClB,WAAO;AAAA,EACT;AAAA,EACA,MAAM,SAAS;AACb,WAAO;AAAA,EACT;AAAA,EACA;AAAA,EACA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,MAAM,YAAY;AAChB,WAAO;AAAA,EACT;AAAA,EACA,aAAa;AACX,WAAO;AAAA,EACT;AAAA,EACA,oBAAoB;AAClB,WAAO;AAAA,EACT;AAAA,EACA,mBAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EACA,qBAAqB,OAAoC;AACvD,UAAM,UAAU,MAAM,WAAW;AACjC,UAAM,YACJ,QAAQ,SAAS,KAAK,QAAQ,MAAM,GAAG,EAAE,IAAI,QAAQ;AACvD,WAAO,aAAa,SAAS;AAAA,EAC/B;AAAA,EACA,+BAA+B;AAC7B,WAAO,oCAAC,oCAA+B;AAAA,EACzC;AAAA,EACA,wBAAwB,QAA6C;AACnE,QAAI,CAAC,UAAU,CAAC,OAAO,QAAQ;AAC7B,aACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,YAAK,cAAY,CACpB;AAAA,IAEJ;AAEA,WACE,oCAAC,OAAI,eAAc,SACjB,oCAAC,YAAK,qBAAoB,GAC1B,oCAAC,QAAK,OAAO,SAAS,EAAE,WAAS,UACxB,OAAO,QAAO,cAAW,OAAO,OACzC,CACF;AAAA,EAEJ;AAAA,EACA,yBAAyB,QAA6C;AACpE,WAAO,SAAS,OAAO,MAAM,0BAA0B,OAAO,OAAO;AAAA,EACvE;AAAA,EACA,MAAM,cAAc,EAAE,SAAS,YAAY,GAAgC;AACzE,QAAI,CAAC,SAAS,KAAK,GAAG;AACpB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AACA,QAAI,CAAC,aAAa,KAAK,GAAG;AACxB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,IACF;AACA,WAAO,EAAE,QAAQ,KAAK;AAAA,EACxB;AAAA,EACA,OAAO,KAAK,OAAoC;AAC9C,QAAI;AACF,YAAM,OAAO,WAAW;AAAA,QACtB,SAAS,MAAM;AAAA,QACf,aAAa,MAAM;AAAA,QACnB,YAAY,MAAM;AAAA,QAClB,UAAU,MAAM;AAAA,MAClB,CAAC;AAED,YAAM,SAAS;AAAA,QACb,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,MAChB;AAEA,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,MAAM;AAAA,QACN,oBAAoB,KAAK,yBAAyB,MAAM;AAAA,MAC1D;AAAA,IACF,SAAS,OAAO;AACd,YAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,YAAM;AAAA,QACJ,MAAM;AAAA,QACN,MAAM,EAAE,OAAO,aAAa;AAAA,QAC5B,oBAAoB,wBAAwB,YAAY;AAAA,MAC1D;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const PROMPT = `Use this tool to create a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
2
|
+
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
3
|
+
|
|
4
|
+
## When to Use This Tool
|
|
5
|
+
|
|
6
|
+
Use this tool proactively in these scenarios:
|
|
7
|
+
|
|
8
|
+
- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions
|
|
9
|
+
- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations
|
|
10
|
+
- Plan mode - When using plan mode, create a task list to track the work
|
|
11
|
+
- User explicitly requests todo list - When the user directly asks you to use the todo list
|
|
12
|
+
- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)
|
|
13
|
+
- After receiving new instructions - Immediately capture user requirements as tasks
|
|
14
|
+
- When you start working on a task - Mark it as in_progress BEFORE beginning work
|
|
15
|
+
- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation
|
|
16
|
+
|
|
17
|
+
## When NOT to Use This Tool
|
|
18
|
+
|
|
19
|
+
Skip using this tool when:
|
|
20
|
+
- There is only a single, straightforward task
|
|
21
|
+
- The task is trivial and tracking it provides no organizational benefit
|
|
22
|
+
- The task can be completed in less than 3 trivial steps
|
|
23
|
+
- The task is purely conversational or informational
|
|
24
|
+
|
|
25
|
+
NOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.
|
|
26
|
+
|
|
27
|
+
## Task Fields
|
|
28
|
+
|
|
29
|
+
- **subject**: A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")
|
|
30
|
+
- **description**: Detailed description of what needs to be done, including context and acceptance criteria
|
|
31
|
+
- **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.
|
|
32
|
+
|
|
33
|
+
**IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative ("Run tests") while activeForm should be present continuous ("Running tests"). All tasks are created with status \`pending\`.
|
|
34
|
+
|
|
35
|
+
## Tips
|
|
36
|
+
|
|
37
|
+
- Create tasks with clear, specific subjects that describe the outcome
|
|
38
|
+
- Include enough detail in the description for another agent to understand and complete the task
|
|
39
|
+
- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
|
|
40
|
+
- Check TaskList first to avoid creating duplicate tasks
|
|
41
|
+
`;
|
|
42
|
+
const DESCRIPTION = "Create a new task to track progress on complex work";
|
|
43
|
+
export {
|
|
44
|
+
DESCRIPTION,
|
|
45
|
+
PROMPT
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=prompt.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/tools/TaskCreateTool/prompt.ts"],
|
|
4
|
+
"sourcesContent": ["export const PROMPT = `Use this tool to create a structured task list for your current coding session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.\nIt also helps the user understand the progress of the task and overall progress of their requests.\n\n## When to Use This Tool\n\nUse this tool proactively in these scenarios:\n\n- Complex multi-step tasks - When a task requires 3 or more distinct steps or actions\n- Non-trivial and complex tasks - Tasks that require careful planning or multiple operations\n- Plan mode - When using plan mode, create a task list to track the work\n- User explicitly requests todo list - When the user directly asks you to use the todo list\n- User provides multiple tasks - When users provide a list of things to be done (numbered or comma-separated)\n- After receiving new instructions - Immediately capture user requirements as tasks\n- When you start working on a task - Mark it as in_progress BEFORE beginning work\n- After completing a task - Mark it as completed and add any new follow-up tasks discovered during implementation\n\n## When NOT to Use This Tool\n\nSkip using this tool when:\n- There is only a single, straightforward task\n- The task is trivial and tracking it provides no organizational benefit\n- The task can be completed in less than 3 trivial steps\n- The task is purely conversational or informational\n\nNOTE that you should not use this tool if there is only one trivial task to do. In this case you are better off just doing the task directly.\n\n## Task Fields\n\n- **subject**: A brief, actionable title in imperative form (e.g., \"Fix authentication bug in login flow\")\n- **description**: Detailed description of what needs to be done, including context and acceptance criteria\n- **activeForm**: Present continuous form shown in spinner when task is in_progress (e.g., \"Fixing authentication bug\"). This is displayed to the user while you work on the task.\n\n**IMPORTANT**: Always provide activeForm when creating tasks. The subject should be imperative (\"Run tests\") while activeForm should be present continuous (\"Running tests\"). All tasks are created with status \\`pending\\`.\n\n## Tips\n\n- Create tasks with clear, specific subjects that describe the outcome\n- Include enough detail in the description for another agent to understand and complete the task\n- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed\n- Check TaskList first to avoid creating duplicate tasks\n`\n\nexport const DESCRIPTION = 'Create a new task to track progress on complex work'\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0Cf,MAAM,cAAc;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Box, Text } from "ink";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { FallbackToolUseRejectedMessage } from "../../components/FallbackToolUseRejectedMessage.js";
|
|
5
|
+
import { getTaskById } from "../../services/taskStore.js";
|
|
6
|
+
import { DESCRIPTION, PROMPT } from "./prompt.js";
|
|
7
|
+
import { getTheme } from "../../utils/theme.js";
|
|
8
|
+
const inputSchema = z.strictObject({
|
|
9
|
+
taskId: z.string().describe("The ID of the task to retrieve")
|
|
10
|
+
});
|
|
11
|
+
const TaskGetTool = {
|
|
12
|
+
name: "TaskGet",
|
|
13
|
+
async description() {
|
|
14
|
+
return DESCRIPTION;
|
|
15
|
+
},
|
|
16
|
+
async prompt() {
|
|
17
|
+
return PROMPT;
|
|
18
|
+
},
|
|
19
|
+
inputSchema,
|
|
20
|
+
userFacingName() {
|
|
21
|
+
return "Get Task";
|
|
22
|
+
},
|
|
23
|
+
async isEnabled() {
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
isReadOnly() {
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
isConcurrencySafe() {
|
|
30
|
+
return true;
|
|
31
|
+
},
|
|
32
|
+
needsPermissions() {
|
|
33
|
+
return false;
|
|
34
|
+
},
|
|
35
|
+
renderToolUseMessage(input) {
|
|
36
|
+
return `taskId: ${input.taskId}`;
|
|
37
|
+
},
|
|
38
|
+
renderToolUseRejectedMessage() {
|
|
39
|
+
return /* @__PURE__ */ React.createElement(FallbackToolUseRejectedMessage, null);
|
|
40
|
+
},
|
|
41
|
+
renderToolResultMessage(output) {
|
|
42
|
+
if (!output || "error" in output) {
|
|
43
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { color: getTheme().error }, output && "error" in output ? output.error : "Task not found"));
|
|
44
|
+
}
|
|
45
|
+
const statusColor = output.status === "completed" ? getTheme().success : output.status === "in_progress" ? getTheme().warning : getTheme().secondaryText;
|
|
46
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, { flexDirection: "row" }, /* @__PURE__ */ React.createElement(Text, null, "\xA0\xA0\u23BF \xA0"), /* @__PURE__ */ React.createElement(Text, { bold: true }, "#", output.id), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, null, output.subject)), /* @__PURE__ */ React.createElement(Box, { flexDirection: "row", paddingLeft: 5 }, /* @__PURE__ */ React.createElement(Text, { color: statusColor }, "[", output.status, "]"), output.owner && /* @__PURE__ */ React.createElement(Text, { color: getTheme().secondaryText }, " owner: ", output.owner)));
|
|
47
|
+
},
|
|
48
|
+
renderResultForAssistant(result) {
|
|
49
|
+
if ("error" in result) {
|
|
50
|
+
return `Error: ${result.error}`;
|
|
51
|
+
}
|
|
52
|
+
const lines = [
|
|
53
|
+
`Task #${result.id}:`,
|
|
54
|
+
` Subject: ${result.subject}`,
|
|
55
|
+
` Status: ${result.status}`,
|
|
56
|
+
` Description: ${result.description}`
|
|
57
|
+
];
|
|
58
|
+
if (result.activeForm) {
|
|
59
|
+
lines.push(` Active Form: ${result.activeForm}`);
|
|
60
|
+
}
|
|
61
|
+
if (result.owner) {
|
|
62
|
+
lines.push(` Owner: ${result.owner}`);
|
|
63
|
+
}
|
|
64
|
+
if (result.blocks && result.blocks.length > 0) {
|
|
65
|
+
lines.push(` Blocks: [${result.blocks.join(", ")}]`);
|
|
66
|
+
}
|
|
67
|
+
if (result.blockedBy && result.blockedBy.length > 0) {
|
|
68
|
+
lines.push(` Blocked By: [${result.blockedBy.join(", ")}]`);
|
|
69
|
+
}
|
|
70
|
+
if (result.metadata && Object.keys(result.metadata).length > 0) {
|
|
71
|
+
lines.push(` Metadata: ${JSON.stringify(result.metadata)}`);
|
|
72
|
+
}
|
|
73
|
+
return lines.join("\n");
|
|
74
|
+
},
|
|
75
|
+
async validateInput({ taskId }) {
|
|
76
|
+
if (!taskId?.trim()) {
|
|
77
|
+
return {
|
|
78
|
+
result: false,
|
|
79
|
+
message: "Task ID is required"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return { result: true };
|
|
83
|
+
},
|
|
84
|
+
async *call(input) {
|
|
85
|
+
try {
|
|
86
|
+
const task = getTaskById(input.taskId);
|
|
87
|
+
if (!task) {
|
|
88
|
+
const result = { error: `Task with ID '${input.taskId}' not found` };
|
|
89
|
+
yield {
|
|
90
|
+
type: "result",
|
|
91
|
+
data: result,
|
|
92
|
+
resultForAssistant: this.renderResultForAssistant(result)
|
|
93
|
+
};
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
yield {
|
|
97
|
+
type: "result",
|
|
98
|
+
data: task,
|
|
99
|
+
resultForAssistant: this.renderResultForAssistant(task)
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
103
|
+
const result = { error: errorMessage };
|
|
104
|
+
yield {
|
|
105
|
+
type: "result",
|
|
106
|
+
data: result,
|
|
107
|
+
resultForAssistant: `Error getting task: ${errorMessage}`
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
export {
|
|
113
|
+
TaskGetTool
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=TaskGetTool.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/tools/TaskGetTool/TaskGetTool.tsx"],
|
|
4
|
+
"sourcesContent": ["import { Box, Text } from 'ink'\nimport * as React from 'react'\nimport { z } from 'zod'\nimport { FallbackToolUseRejectedMessage } from '@components/FallbackToolUseRejectedMessage'\nimport { Tool } from '@tool'\nimport { getTaskById, Task } from '@services/taskStore'\nimport { DESCRIPTION, PROMPT } from './prompt'\nimport { getTheme } from '@utils/theme'\n\nconst inputSchema = z.strictObject({\n taskId: z.string().describe('The ID of the task to retrieve'),\n})\n\nexport const TaskGetTool = {\n name: 'TaskGet',\n async description() {\n return DESCRIPTION\n },\n async prompt() {\n return PROMPT\n },\n inputSchema,\n userFacingName() {\n return 'Get Task'\n },\n async isEnabled() {\n return true\n },\n isReadOnly() {\n return true\n },\n isConcurrencySafe() {\n return true\n },\n needsPermissions() {\n return false\n },\n renderToolUseMessage(input: z.infer<typeof inputSchema>) {\n return `taskId: ${input.taskId}`\n },\n renderToolUseRejectedMessage() {\n return <FallbackToolUseRejectedMessage />\n },\n renderToolResultMessage(output: Task | { error: string }) {\n if (!output || 'error' in output) {\n return (\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text color={getTheme().error}>\n {output && 'error' in output ? output.error : 'Task not found'}\n </Text>\n </Box>\n )\n }\n\n const statusColor =\n output.status === 'completed'\n ? getTheme().success\n : output.status === 'in_progress'\n ? getTheme().warning\n : getTheme().secondaryText\n\n return (\n <Box flexDirection=\"column\">\n <Box flexDirection=\"row\">\n <Text> \u23BF </Text>\n <Text bold>#{output.id}</Text>\n <Text> </Text>\n <Text>{output.subject}</Text>\n </Box>\n <Box flexDirection=\"row\" paddingLeft={5}>\n <Text color={statusColor}>[{output.status}]</Text>\n {output.owner && (\n <Text color={getTheme().secondaryText}> owner: {output.owner}</Text>\n )}\n </Box>\n </Box>\n )\n },\n renderResultForAssistant(result: Task | { error: string }) {\n if ('error' in result) {\n return `Error: ${result.error}`\n }\n\n const lines: string[] = [\n `Task #${result.id}:`,\n ` Subject: ${result.subject}`,\n ` Status: ${result.status}`,\n ` Description: ${result.description}`,\n ]\n\n if (result.activeForm) {\n lines.push(` Active Form: ${result.activeForm}`)\n }\n if (result.owner) {\n lines.push(` Owner: ${result.owner}`)\n }\n if (result.blocks && result.blocks.length > 0) {\n lines.push(` Blocks: [${result.blocks.join(', ')}]`)\n }\n if (result.blockedBy && result.blockedBy.length > 0) {\n lines.push(` Blocked By: [${result.blockedBy.join(', ')}]`)\n }\n if (result.metadata && Object.keys(result.metadata).length > 0) {\n lines.push(` Metadata: ${JSON.stringify(result.metadata)}`)\n }\n\n return lines.join('\\n')\n },\n async validateInput({ taskId }: z.infer<typeof inputSchema>) {\n if (!taskId?.trim()) {\n return {\n result: false,\n message: 'Task ID is required',\n }\n }\n return { result: true }\n },\n async *call(input: z.infer<typeof inputSchema>) {\n try {\n const task = getTaskById(input.taskId)\n\n if (!task) {\n const result = { error: `Task with ID '${input.taskId}' not found` }\n yield {\n type: 'result',\n data: result,\n resultForAssistant: this.renderResultForAssistant(result),\n }\n return\n }\n\n yield {\n type: 'result',\n data: task,\n resultForAssistant: this.renderResultForAssistant(task),\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error occurred'\n const result = { error: errorMessage }\n yield {\n type: 'result',\n data: result,\n resultForAssistant: `Error getting task: ${errorMessage}`,\n }\n }\n },\n} satisfies Tool<typeof inputSchema, Task | { error: string }>\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|