@nomad-e/bluma-cli 0.0.78 → 0.0.80
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/config/native_tools.json +205 -205
- package/dist/config/todo_rules.md +157 -0
- package/dist/main.js +131 -76
- package/package.json +1 -1
|
@@ -1,206 +1,206 @@
|
|
|
1
|
-
{
|
|
2
|
-
"nativeTools": [
|
|
3
|
-
{
|
|
4
|
-
"type": "function",
|
|
5
|
-
"function": {
|
|
6
|
-
"name": "shell_command",
|
|
7
|
-
"description": "Executes a terminal command in a robust and Windows/Linux compatible way.",
|
|
8
|
-
"parameters": {
|
|
9
|
-
"type": "object",
|
|
10
|
-
"properties": {
|
|
11
|
-
"command": {
|
|
12
|
-
"type": "string",
|
|
13
|
-
"description": "Shell command to execute"
|
|
14
|
-
},
|
|
15
|
-
"timeout": {
|
|
16
|
-
"type": "integer",
|
|
17
|
-
"description": "Maximum execution time in seconds",
|
|
18
|
-
"default": 20
|
|
19
|
-
},
|
|
20
|
-
"cwd": {
|
|
21
|
-
"type": "string",
|
|
22
|
-
"description": "Working directory for command execution (must use absolute path)"
|
|
23
|
-
},
|
|
24
|
-
"verbose": {
|
|
25
|
-
"type": "boolean",
|
|
26
|
-
"description": "If True, returns detailed report; if False, only main output",
|
|
27
|
-
"default": false
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
"required": [
|
|
31
|
-
"command",
|
|
32
|
-
"timeout"
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"type": "function",
|
|
39
|
-
"function": {
|
|
40
|
-
"name": "edit_tool",
|
|
41
|
-
"description": "Safely and precisely replaces text in a file, or creates a new file. The tool is resilient to common formatting issues but performs best with precise input.\n\n**Best Practices for Success:**\n1. **Use a read tool first:** Always read the file to get the exact content before generating the `old_string`.\n2. **Provide Context:** For `old_string`, provide a unique, multi-line segment of the file. Including 3+ lines of context around the target change is highly recommended to ensure precision.\n3. **Create New Files:** To create a new file, provide the full `file_path` and an empty string for `old_string`.",
|
|
42
|
-
"parameters": {
|
|
43
|
-
"type": "object",
|
|
44
|
-
"properties": {
|
|
45
|
-
"file_path": {
|
|
46
|
-
"type": "string",
|
|
47
|
-
"description": "The absolute or relative path to the file. The tool will correctly resolve the path for the current operating system."
|
|
48
|
-
},
|
|
49
|
-
"old_string": {
|
|
50
|
-
"type": "string",
|
|
51
|
-
"description": "The exact text to be replaced. To ensure accuracy, this should be a unique, multi-line segment from the file, including all original indentation and whitespace. Do not manually escape newlines (use literal newlines, not '\\n'). For creating a new file, this must be an empty string."
|
|
52
|
-
},
|
|
53
|
-
"new_string": {
|
|
54
|
-
"type": "string",
|
|
55
|
-
"description": "The new text that will replace `old_string`. Match the indentation and formatting of the surrounding code to maintain code quality. Do not manually escape newlines."
|
|
56
|
-
},
|
|
57
|
-
"expected_replacements": {
|
|
58
|
-
"type": "integer",
|
|
59
|
-
"description": "Optional. The number of occurrences to replace. Defaults to 1. If you expect to replace multiple instances of `old_string`, set this value accordingly.",
|
|
60
|
-
"default": 1
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
"required": [
|
|
64
|
-
"file_path",
|
|
65
|
-
"old_string",
|
|
66
|
-
"new_string"
|
|
67
|
-
]
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"type": "function",
|
|
73
|
-
"function": {
|
|
74
|
-
"name": "
|
|
75
|
-
"description": "End the current agent
|
|
76
|
-
"parameters": {
|
|
77
|
-
"type": "object",
|
|
78
|
-
"properties": {},
|
|
79
|
-
"required": []
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
"type": "function",
|
|
85
|
-
"function": {
|
|
86
|
-
"name": "message_notify_user",
|
|
87
|
-
"description": "This tool allows the agent to send structured messages to the user for confirming task start, replying to messages from name:'user_overlay' (continuing or integrating into the flow), giving short initial responses, notifying about method or strategy changes, providing progress updates, and concluding tasks with a final confirmation or result.",
|
|
88
|
-
"parameters": {
|
|
89
|
-
"type": "object",
|
|
90
|
-
"properties": {
|
|
91
|
-
"message": {
|
|
92
|
-
"type": "string",
|
|
93
|
-
"description": "The body of the message in Markdown format."
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
"required": [
|
|
97
|
-
"message"
|
|
98
|
-
]
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"type": "function",
|
|
104
|
-
"function": {
|
|
105
|
-
"name": "ls_tool",
|
|
106
|
-
"description": "Lists files and subdirectories with advanced support for pagination and filtering. Automatically ignores common unnecessary files/directories like '.venv', 'node_modules', etc.",
|
|
107
|
-
"parameters": {
|
|
108
|
-
"type": "object",
|
|
109
|
-
"properties": {
|
|
110
|
-
"directory_path": {
|
|
111
|
-
"type": "string",
|
|
112
|
-
"description": "Path of the directory to list. Defaults to '.' (current directory).",
|
|
113
|
-
"default": "."
|
|
114
|
-
},
|
|
115
|
-
"recursive": {
|
|
116
|
-
"type": "boolean",
|
|
117
|
-
"description": "If True, lists recursively all subdirectories.",
|
|
118
|
-
"default": false
|
|
119
|
-
},
|
|
120
|
-
"ignore_patterns": {
|
|
121
|
-
"type": "array",
|
|
122
|
-
"items": {
|
|
123
|
-
"type": "string"
|
|
124
|
-
},
|
|
125
|
-
"description": "Additional patterns to ignore (beyond defaults). E.g., ['test_*', '*.tmp']"
|
|
126
|
-
},
|
|
127
|
-
"start_index": {
|
|
128
|
-
"type": "integer",
|
|
129
|
-
"description": "Starting index for pagination (0-based).",
|
|
130
|
-
"default": 0
|
|
131
|
-
},
|
|
132
|
-
"end_index": {
|
|
133
|
-
"type": "integer",
|
|
134
|
-
"description": "Ending index for pagination (exclusive). If not provided, lists everything from start_index."
|
|
135
|
-
},
|
|
136
|
-
"show_hidden": {
|
|
137
|
-
"type": "boolean",
|
|
138
|
-
"description": "If True, shows files/directories starting with '.'.",
|
|
139
|
-
"default": false
|
|
140
|
-
},
|
|
141
|
-
"file_extensions": {
|
|
142
|
-
"type": "array",
|
|
143
|
-
"items": {
|
|
144
|
-
"type": "string"
|
|
145
|
-
},
|
|
146
|
-
"description": "List of extensions to filter (e.g., ['.ts', '.js', '.md']). If not provided, shows all file types."
|
|
147
|
-
},
|
|
148
|
-
"max_depth": {
|
|
149
|
-
"type": "integer",
|
|
150
|
-
"description": "Maximum depth for recursive listing. If not provided, there is no limit."
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
"required": []
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"type": "function",
|
|
159
|
-
"function": {
|
|
160
|
-
"name": "count_file_lines",
|
|
161
|
-
"description": "Counts and returns the total number of lines in a text file. Useful for quickly determining file size or checking if a file is empty before reading it.",
|
|
162
|
-
"parameters": {
|
|
163
|
-
"type": "object",
|
|
164
|
-
"properties": {
|
|
165
|
-
"filepath": {
|
|
166
|
-
"type": "string",
|
|
167
|
-
"description": "Path to the file to count lines from. Can be relative or absolute."
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
"required": [
|
|
171
|
-
"filepath"
|
|
172
|
-
]
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
"type": "function",
|
|
178
|
-
"function": {
|
|
179
|
-
"name": "read_file_lines",
|
|
180
|
-
"description": "Reads and returns content between specific line numbers from a text file. Ideal for efficiently reading portions of large files.",
|
|
181
|
-
"parameters": {
|
|
182
|
-
"type": "object",
|
|
183
|
-
"properties": {
|
|
184
|
-
"filepath": {
|
|
185
|
-
"type": "string",
|
|
186
|
-
"description": "Path to the file to read from."
|
|
187
|
-
},
|
|
188
|
-
"start_line": {
|
|
189
|
-
"type": "integer",
|
|
190
|
-
"description": "Starting line number (1-based index). Must be >= 1."
|
|
191
|
-
},
|
|
192
|
-
"end_line": {
|
|
193
|
-
"type": "integer",
|
|
194
|
-
"description": "Ending line number (1-based index, inclusive). Must be >= start_line."
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
"required": [
|
|
198
|
-
"filepath",
|
|
199
|
-
"start_line",
|
|
200
|
-
"end_line"
|
|
201
|
-
]
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
]
|
|
1
|
+
{
|
|
2
|
+
"nativeTools": [
|
|
3
|
+
{
|
|
4
|
+
"type": "function",
|
|
5
|
+
"function": {
|
|
6
|
+
"name": "shell_command",
|
|
7
|
+
"description": "Executes a terminal command in a robust and Windows/Linux compatible way.",
|
|
8
|
+
"parameters": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"command": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "Shell command to execute"
|
|
14
|
+
},
|
|
15
|
+
"timeout": {
|
|
16
|
+
"type": "integer",
|
|
17
|
+
"description": "Maximum execution time in seconds",
|
|
18
|
+
"default": 20
|
|
19
|
+
},
|
|
20
|
+
"cwd": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Working directory for command execution (must use absolute path)"
|
|
23
|
+
},
|
|
24
|
+
"verbose": {
|
|
25
|
+
"type": "boolean",
|
|
26
|
+
"description": "If True, returns detailed report; if False, only main output",
|
|
27
|
+
"default": false
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"required": [
|
|
31
|
+
"command",
|
|
32
|
+
"timeout"
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "function",
|
|
39
|
+
"function": {
|
|
40
|
+
"name": "edit_tool",
|
|
41
|
+
"description": "Safely and precisely replaces text in a file, or creates a new file. The tool is resilient to common formatting issues but performs best with precise input.\n\n**Best Practices for Success:**\n1. **Use a read tool first:** Always read the file to get the exact content before generating the `old_string`.\n2. **Provide Context:** For `old_string`, provide a unique, multi-line segment of the file. Including 3+ lines of context around the target change is highly recommended to ensure precision.\n3. **Create New Files:** To create a new file, provide the full `file_path` and an empty string for `old_string`.",
|
|
42
|
+
"parameters": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {
|
|
45
|
+
"file_path": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"description": "The absolute or relative path to the file. The tool will correctly resolve the path for the current operating system."
|
|
48
|
+
},
|
|
49
|
+
"old_string": {
|
|
50
|
+
"type": "string",
|
|
51
|
+
"description": "The exact text to be replaced. To ensure accuracy, this should be a unique, multi-line segment from the file, including all original indentation and whitespace. Do not manually escape newlines (use literal newlines, not '\\n'). For creating a new file, this must be an empty string."
|
|
52
|
+
},
|
|
53
|
+
"new_string": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "The new text that will replace `old_string`. Match the indentation and formatting of the surrounding code to maintain code quality. Do not manually escape newlines."
|
|
56
|
+
},
|
|
57
|
+
"expected_replacements": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"description": "Optional. The number of occurrences to replace. Defaults to 1. If you expect to replace multiple instances of `old_string`, set this value accordingly.",
|
|
60
|
+
"default": 1
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"required": [
|
|
64
|
+
"file_path",
|
|
65
|
+
"old_string",
|
|
66
|
+
"new_string"
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "function",
|
|
73
|
+
"function": {
|
|
74
|
+
"name": "agent_end_turn",
|
|
75
|
+
"description": "End the current agent turn. This tool is a especial tool that is used to signal the end of the agent's turn. It does not require any parameters and does not return any value.",
|
|
76
|
+
"parameters": {
|
|
77
|
+
"type": "object",
|
|
78
|
+
"properties": {},
|
|
79
|
+
"required": []
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "function",
|
|
85
|
+
"function": {
|
|
86
|
+
"name": "message_notify_user",
|
|
87
|
+
"description": "This tool allows the agent to send structured messages to the user for confirming task start, replying to messages from name:'user_overlay' (continuing or integrating into the flow), giving short initial responses, notifying about method or strategy changes, providing progress updates, and concluding tasks with a final confirmation or result.",
|
|
88
|
+
"parameters": {
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": {
|
|
91
|
+
"message": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"description": "The body of the message in Markdown format."
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"required": [
|
|
97
|
+
"message"
|
|
98
|
+
]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"type": "function",
|
|
104
|
+
"function": {
|
|
105
|
+
"name": "ls_tool",
|
|
106
|
+
"description": "Lists files and subdirectories with advanced support for pagination and filtering. Automatically ignores common unnecessary files/directories like '.venv', 'node_modules', etc.",
|
|
107
|
+
"parameters": {
|
|
108
|
+
"type": "object",
|
|
109
|
+
"properties": {
|
|
110
|
+
"directory_path": {
|
|
111
|
+
"type": "string",
|
|
112
|
+
"description": "Path of the directory to list. Defaults to '.' (current directory).",
|
|
113
|
+
"default": "."
|
|
114
|
+
},
|
|
115
|
+
"recursive": {
|
|
116
|
+
"type": "boolean",
|
|
117
|
+
"description": "If True, lists recursively all subdirectories.",
|
|
118
|
+
"default": false
|
|
119
|
+
},
|
|
120
|
+
"ignore_patterns": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "string"
|
|
124
|
+
},
|
|
125
|
+
"description": "Additional patterns to ignore (beyond defaults). E.g., ['test_*', '*.tmp']"
|
|
126
|
+
},
|
|
127
|
+
"start_index": {
|
|
128
|
+
"type": "integer",
|
|
129
|
+
"description": "Starting index for pagination (0-based).",
|
|
130
|
+
"default": 0
|
|
131
|
+
},
|
|
132
|
+
"end_index": {
|
|
133
|
+
"type": "integer",
|
|
134
|
+
"description": "Ending index for pagination (exclusive). If not provided, lists everything from start_index."
|
|
135
|
+
},
|
|
136
|
+
"show_hidden": {
|
|
137
|
+
"type": "boolean",
|
|
138
|
+
"description": "If True, shows files/directories starting with '.'.",
|
|
139
|
+
"default": false
|
|
140
|
+
},
|
|
141
|
+
"file_extensions": {
|
|
142
|
+
"type": "array",
|
|
143
|
+
"items": {
|
|
144
|
+
"type": "string"
|
|
145
|
+
},
|
|
146
|
+
"description": "List of extensions to filter (e.g., ['.ts', '.js', '.md']). If not provided, shows all file types."
|
|
147
|
+
},
|
|
148
|
+
"max_depth": {
|
|
149
|
+
"type": "integer",
|
|
150
|
+
"description": "Maximum depth for recursive listing. If not provided, there is no limit."
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"required": []
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
"type": "function",
|
|
159
|
+
"function": {
|
|
160
|
+
"name": "count_file_lines",
|
|
161
|
+
"description": "Counts and returns the total number of lines in a text file. Useful for quickly determining file size or checking if a file is empty before reading it.",
|
|
162
|
+
"parameters": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"properties": {
|
|
165
|
+
"filepath": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"description": "Path to the file to count lines from. Can be relative or absolute."
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"required": [
|
|
171
|
+
"filepath"
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"type": "function",
|
|
178
|
+
"function": {
|
|
179
|
+
"name": "read_file_lines",
|
|
180
|
+
"description": "Reads and returns content between specific line numbers from a text file. Ideal for efficiently reading portions of large files.",
|
|
181
|
+
"parameters": {
|
|
182
|
+
"type": "object",
|
|
183
|
+
"properties": {
|
|
184
|
+
"filepath": {
|
|
185
|
+
"type": "string",
|
|
186
|
+
"description": "Path to the file to read from."
|
|
187
|
+
},
|
|
188
|
+
"start_line": {
|
|
189
|
+
"type": "integer",
|
|
190
|
+
"description": "Starting line number (1-based index). Must be >= 1."
|
|
191
|
+
},
|
|
192
|
+
"end_line": {
|
|
193
|
+
"type": "integer",
|
|
194
|
+
"description": "Ending line number (1-based index, inclusive). Must be >= start_line."
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"required": [
|
|
198
|
+
"filepath",
|
|
199
|
+
"start_line",
|
|
200
|
+
"end_line"
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
]
|
|
206
206
|
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# To-Do Rules — Regras e Boas Práticas para a ferramenta `todo`
|
|
2
|
+
|
|
3
|
+
Este documento descreve, de forma completa e exaustiva, as regras, restrições e boas práticas para o uso da ferramenta nativa `todo` do agente. O objetivo é garantir comportamento determinístico, segurança, facilidade de integração e interoperabilidade entre agentes, UIs e pipelines automáticos.
|
|
4
|
+
|
|
5
|
+
Índice
|
|
6
|
+
- Visão geral
|
|
7
|
+
- Formato e esquema
|
|
8
|
+
- Ações suportadas
|
|
9
|
+
- Validação de entrada
|
|
10
|
+
- Regras de mutação e idempotência
|
|
11
|
+
- Execução automática e segurança (safe_tool)
|
|
12
|
+
- Logging, audit e persistência
|
|
13
|
+
- Erros e respostas previsíveis
|
|
14
|
+
- Regras de interface (UI / renderização)
|
|
15
|
+
- Regras de interação com o agente / prompt
|
|
16
|
+
- Regras de versionamento e compatibilidade
|
|
17
|
+
- Testes e qualidade
|
|
18
|
+
- Limitações e considerações
|
|
19
|
+
- Exemplos de payloads e respostas
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
Visão geral
|
|
24
|
+
----------
|
|
25
|
+
A ferramenta `todo` é um gerenciador nativo de listas de tarefas (checklist) pensado para integração com agentes autônomos e pipelines. Ela fornece um contrato claro e estruturado para que tanto humanos quanto máquinas possam ler e modificar o estado de tarefas de forma previsível.
|
|
26
|
+
|
|
27
|
+
Formato e esquema
|
|
28
|
+
-----------------
|
|
29
|
+
- Representação principal: array de strings chamado `to_do`.
|
|
30
|
+
- Formato de cada item: obrigatório prefixo de status seguido por um espaço e o texto da tarefa.
|
|
31
|
+
- Status válido: `🗹 ` (concluído) ou `☐ ` (pendente).
|
|
32
|
+
- Exemplo: `☐ Implementar validação de inputs` ou `🗹 Review do PR #42`.
|
|
33
|
+
- Retorno: ao executar ações que alterem estado, a ferramenta devolve o array `to_do` atualizado e um campo `_tool_result` com duas chaves:
|
|
34
|
+
- `parsed`: array de objetos { index: number, status: 'done'|'pending', text: string }
|
|
35
|
+
- `render`: string com visual humano legível (cada item em nova linha com índice e marca)
|
|
36
|
+
|
|
37
|
+
Ações suportadas
|
|
38
|
+
-----------------
|
|
39
|
+
- `list` — retorna o estado atual sem mutação.
|
|
40
|
+
- `add` — acrescenta um novo item pendente; payload: `{ action: 'add', item: 'text' }`.
|
|
41
|
+
- `complete` — marca um item como concluído; payload: `{ action: 'complete', index: 1 }` (1-based).
|
|
42
|
+
- `remove` — remove um item por índice; payload: `{ action: 'remove', index: 2 }`.
|
|
43
|
+
|
|
44
|
+
Validação de entrada
|
|
45
|
+
--------------------
|
|
46
|
+
- `action` é obrigatório e deve ser uma das opções listadas.
|
|
47
|
+
- `index` se fornecido deve ser inteiro >= 1 e <= length(to_do).
|
|
48
|
+
- `item` quando exigido deve ser string não vazia e sem prefixo (o prefixo é atribuído pela ferramenta).
|
|
49
|
+
- `to_do` (opcional) quando fornecido será normalizado: qualquer item sem prefixo será convertido para `☐ <texto>`.
|
|
50
|
+
- Erros de validação devem retornar uma resposta clara com `error` contendo a mensagem e `status: 400` quando aplicável.
|
|
51
|
+
|
|
52
|
+
Regras de mutação e idempotência
|
|
53
|
+
--------------------------------
|
|
54
|
+
- `add` é idempotente apenas se o mesmo item for adicionado com um identificador externo; por padrão, chamadas repetidas adicionam itens duplicados.
|
|
55
|
+
- `complete` e `remove` são idempotentes no sentido que aplicar `complete` numa tarefa já concluída não causa erro — apenas mantém o estado `🗹`.
|
|
56
|
+
- `remove` numa posição já removida (índice inválido) deve retornar erro de input inválido.
|
|
57
|
+
- Alterações devem sempre retornar o novo array `to_do` completo para permitir sincronização do cliente.
|
|
58
|
+
|
|
59
|
+
Execução automática e segurança (safe_tool)
|
|
60
|
+
-------------------------------------------
|
|
61
|
+
- A `todo` é considerada uma `safe_tool` para execuções automáticas pelo agente quando as ações são localizadas e previsíveis (ex.: `list`, `render`, `add` com item textual simples).
|
|
62
|
+
- O agente pode autoaprová-la sem intervenção humana quando: a) a ação não modifica código fonte; b) não requer acesso a credenciais nem recursos externos sensíveis; c) não envolve remoção em massa sem confirmação.
|
|
63
|
+
- Para ações destrutivas (por ex. `remove` em massa), recomenda-se confirmação humana, a menos que haja política explícita favorável.
|
|
64
|
+
|
|
65
|
+
Regras de concorrência
|
|
66
|
+
----------------------
|
|
67
|
+
- A ferramenta deve considerar o array `to_do` recebido como snapshot; mudanças concorrentes devem ser resolvidas pela camada que persiste estado (locking otimista ou verificação de versão) — se o projeto não persiste, o consumidor deve ser consciente de possíveis conflitos.
|
|
68
|
+
- Em ambientes multi-agent, incluir um campo de `timestamp` ou `version` na camada de armazenamento é recomendado.
|
|
69
|
+
|
|
70
|
+
Logging, audit e persistência
|
|
71
|
+
-----------------------------
|
|
72
|
+
- Toda execução deve ser logada com: timestamp, ação, argumentos, usuário/agent que solicitou (quando aplicável), resultado (sucesso/erro), e diffs entre `to_do` antigo e novo.
|
|
73
|
+
- Logs de auditoria devem manter rastro de quem fez remoções e completions.
|
|
74
|
+
- Persistência: a ferramenta não impõe mecanismo — se integrada a um backend, este deve garantir durabilidade e backups.
|
|
75
|
+
|
|
76
|
+
Erros e respostas previsíveis
|
|
77
|
+
-----------------------------
|
|
78
|
+
- Erros de validação: respondem com { error: 'mensagem', status: 400 }
|
|
79
|
+
- Erros internos: respondem com { error: 'Internal error', status: 500, details?: '...' }
|
|
80
|
+
- Respostas de sucesso sempre incluem `to_do` (array) e `_tool_result`.
|
|
81
|
+
|
|
82
|
+
Regras de interface (UI / renderização)
|
|
83
|
+
---------------------------------------
|
|
84
|
+
- Para exibir ao usuário, usar `_tool_result.render` primeiro; se não existir, montar a partir de `_tool_result.parsed`.
|
|
85
|
+
- A renderização deve ser simples e acessível: índice, marca, texto. Exemplo:
|
|
86
|
+
1. ☐ Implement unit tests
|
|
87
|
+
2. 🗹 Fix bug #123
|
|
88
|
+
- Ao permitir edição inline, o cliente deve enviar payloads claros (`add`, `complete`, `remove`) e nunca enviar listas embutidas em texto livre.
|
|
89
|
+
|
|
90
|
+
Regras de interação com o agente / prompt
|
|
91
|
+
----------------------------------------
|
|
92
|
+
- O prompt do agente deve instruir explicitamente o uso da `todo` para planeamento e checklist (evitar texto livre para tarefas).
|
|
93
|
+
- Exemplo de instrução no sistema prompt: "When producing a checklist or plan use the `todo` tool and structure items with the strict checklist format. Prefer machine-readable outputs in `_tool_result`."
|
|
94
|
+
- Se o agente gerar tarefas, ele deve sempre preencher o `to_do` via chamada à ferramenta em vez de enviar as tarefas como texto normal.
|
|
95
|
+
|
|
96
|
+
Regras de versionamento e compatibilidade
|
|
97
|
+
----------------------------------------
|
|
98
|
+
- Quaisquer alterações ao schema (`to_do` structure, `_tool_result` keys) devem manter compatibilidade retroativa sempre que possível.
|
|
99
|
+
- Quando um breaking change for necessário, atualizar versão da ferramenta e documentar migração no README.
|
|
100
|
+
|
|
101
|
+
Testes e qualidade
|
|
102
|
+
------------------
|
|
103
|
+
- Cobertura mínima recomendada: casos para cada ação (list/add/complete/remove/render), validação de inputs, idempotência e erros esperados.
|
|
104
|
+
- Testes de integração devem validar persistência, concorrência e logs de auditoria.
|
|
105
|
+
|
|
106
|
+
Limitações e considerações
|
|
107
|
+
--------------------------
|
|
108
|
+
- A ferramenta foca em listas simples e curtas; para listas muito grandes (milhares de itens) recomenda-se paginação e mecanismos de busca especializados.
|
|
109
|
+
- Não é adequada para fluxos de aprovação complexos (multi-stage, com atribuições e dependências) sem extensão do schema.
|
|
110
|
+
|
|
111
|
+
Exemplos de payloads e respostas
|
|
112
|
+
--------------------------------
|
|
113
|
+
1) List
|
|
114
|
+
Request: { "action": "list", "to_do": ["☐ Write docs"] }
|
|
115
|
+
Response:
|
|
116
|
+
{
|
|
117
|
+
"to_do": ["☐ Write docs"],
|
|
118
|
+
"_tool_result": {
|
|
119
|
+
"parsed": [{ "index":1, "status":"pending","text":"Write docs" }],
|
|
120
|
+
"render": "1. ☐ Write docs"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
2) Add
|
|
125
|
+
Request: { "action": "add", "item": "Implement validation" }
|
|
126
|
+
Response: to_do updated with new item at the end and _tool_result as acima.
|
|
127
|
+
|
|
128
|
+
3) Complete
|
|
129
|
+
Request: { "action":"complete", "index": 1 }
|
|
130
|
+
Response: updated to_do with index 1 marked as `🗹 ` and _tool_result parsed accordingly.
|
|
131
|
+
|
|
132
|
+
4) Remove
|
|
133
|
+
Request: { "action":"remove", "index": 2 }
|
|
134
|
+
Response: updated to_do without the removed item and removed: "☐ text" returned optionally.
|
|
135
|
+
|
|
136
|
+
Checklist de regras rápidas (resumo)
|
|
137
|
+
------------------------------------
|
|
138
|
+
- Sempre usar prefixo `🗹 ` ou `☐ `.
|
|
139
|
+
- `action` obrigatório e validado.
|
|
140
|
+
- `item` sem prefixo quando usado em `add`.
|
|
141
|
+
- `index` 1-based para `complete` e `remove`.
|
|
142
|
+
- `todo` considerada safe_tool para operações comuns (list/add/render) — configure confirmação para ações destrutivas.
|
|
143
|
+
- Retornar sempre `to_do` e `_tool_result`.
|
|
144
|
+
- Log, audit, persistência e testes obrigatórios em ambiente de produção.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
Versões e histórico
|
|
149
|
+
-------------------
|
|
150
|
+
- v1.0 — Regras iniciais, esquema `to_do` + `_tool_result`.
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
Se desejar, posso também:
|
|
154
|
+
- Incluir este documento num README.md com exemplos em JSON formatado;
|
|
155
|
+
- Registrar uma referência a este ficheiro diretamente no system prompt (prompt_builder) para que o agente cite as regras;
|
|
156
|
+
- Gerar testes unitários / de integração e exemplos executáveis.
|
|
157
|
+
|
package/dist/main.js
CHANGED
|
@@ -1278,7 +1278,7 @@ var ToolInvoker = class {
|
|
|
1278
1278
|
this.toolImplementations.set("ls_tool", ls);
|
|
1279
1279
|
this.toolImplementations.set("count_file_lines", countLines);
|
|
1280
1280
|
this.toolImplementations.set("read_file_lines", readLines);
|
|
1281
|
-
this.toolImplementations.set("
|
|
1281
|
+
this.toolImplementations.set("agent_end_turn", async () => ({ success: true, message: "Task ended by agent." }));
|
|
1282
1282
|
}
|
|
1283
1283
|
/**
|
|
1284
1284
|
* Retorna a lista de definições de todas as ferramentas nativas carregadas.
|
|
@@ -1580,18 +1580,20 @@ async function loadOrcreateSession(sessionId2) {
|
|
|
1580
1580
|
await fs8.access(sessionFile);
|
|
1581
1581
|
const fileContent = await fs8.readFile(sessionFile, "utf-8");
|
|
1582
1582
|
const sessionData = JSON.parse(fileContent);
|
|
1583
|
-
return [sessionFile, sessionData.conversation_history || []];
|
|
1583
|
+
return [sessionFile, sessionData.conversation_history || [], sessionData.todo_list || []];
|
|
1584
1584
|
} catch (error) {
|
|
1585
1585
|
const newSessionData = {
|
|
1586
1586
|
session_id: sessionId2,
|
|
1587
1587
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1588
|
-
conversation_history: []
|
|
1588
|
+
conversation_history: [],
|
|
1589
|
+
todo_list: []
|
|
1590
|
+
// Garante que uma nova sessão comece com uma lista vazia
|
|
1589
1591
|
};
|
|
1590
1592
|
await fs8.writeFile(sessionFile, JSON.stringify(newSessionData, null, 2), "utf-8");
|
|
1591
|
-
return [sessionFile, []];
|
|
1593
|
+
return [sessionFile, [], []];
|
|
1592
1594
|
}
|
|
1593
1595
|
}
|
|
1594
|
-
async function saveSessionHistory(sessionFile, history) {
|
|
1596
|
+
async function saveSessionHistory(sessionFile, history, todoList) {
|
|
1595
1597
|
await withFileLock(sessionFile, async () => {
|
|
1596
1598
|
let sessionData;
|
|
1597
1599
|
try {
|
|
@@ -1615,7 +1617,8 @@ async function saveSessionHistory(sessionFile, history) {
|
|
|
1615
1617
|
sessionData = {
|
|
1616
1618
|
session_id: sessionId2,
|
|
1617
1619
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1618
|
-
conversation_history: []
|
|
1620
|
+
conversation_history: [],
|
|
1621
|
+
todo_list: []
|
|
1619
1622
|
};
|
|
1620
1623
|
try {
|
|
1621
1624
|
await fs8.writeFile(sessionFile, JSON.stringify(sessionData, null, 2), "utf-8");
|
|
@@ -1623,6 +1626,7 @@ async function saveSessionHistory(sessionFile, history) {
|
|
|
1623
1626
|
}
|
|
1624
1627
|
}
|
|
1625
1628
|
sessionData.conversation_history = history;
|
|
1629
|
+
sessionData.todo_list = todoList;
|
|
1626
1630
|
sessionData.last_updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
1627
1631
|
const tempSessionFile = `${sessionFile}.${Date.now()}.tmp`;
|
|
1628
1632
|
try {
|
|
@@ -1662,8 +1666,11 @@ You are an interactive CLI agent specializing in software engineering tasks. REM
|
|
|
1662
1666
|
---
|
|
1663
1667
|
|
|
1664
1668
|
<persistence>
|
|
1665
|
-
- Do not ask the
|
|
1666
|
-
|
|
1669
|
+
- Do not ask the user to confirm or validate assumptions; proceed and adjust later if needed.
|
|
1670
|
+
|
|
1671
|
+
- Choose the most reasonable assumption, proceed with it, and document it for the user in the final summary.
|
|
1672
|
+
|
|
1673
|
+
- When the user assigns a task, implement it end to end and deliver the final solution in a single response.
|
|
1667
1674
|
</persistence>
|
|
1668
1675
|
---
|
|
1669
1676
|
|
|
@@ -1710,25 +1717,38 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
|
|
|
1710
1717
|
- Ends each task with a final message confirming completion or reporting the result.
|
|
1711
1718
|
</message_rules>
|
|
1712
1719
|
|
|
1720
|
+
<todo_rules>
|
|
1721
|
+
- To manage tasks, you must always use the \`todo\` tool. Never write a to-do list directly as text.
|
|
1722
|
+
- The agent maintains the to-do list's state for you. You do not need to keep track of the full list.
|
|
1723
|
+
- Your job is to send simple commands to the agent via the \`todo\` tool.
|
|
1724
|
+
|
|
1725
|
+
**How to use the \`todo\` tool actions:**
|
|
1726
|
+
1. **To see the current list:** Call the tool with \`action: "list"\`.
|
|
1727
|
+
2. **To add new tasks:**
|
|
1728
|
+
- Use \`action: "add"\`.
|
|
1729
|
+
- Provide a list of plain text strings in the \`items_to_add\` parameter.
|
|
1730
|
+
- **Important:** Do NOT add any prefixes like \`\u2610\` or \`\u{1F5F9}\`. The tool handles all formatting.
|
|
1731
|
+
3. **To complete or remove a task:**
|
|
1732
|
+
- Use \`action: "complete"\` or \`action: "remove"\`.
|
|
1733
|
+
- You MUST provide the \`index\` of the task you want to affect. The index is the number of the task in the list (starting from 1).
|
|
1734
|
+
|
|
1735
|
+
- After every action you take, the tool will respond with the newly updated and formatted list for your reference.
|
|
1736
|
+
</todo_rules>
|
|
1737
|
+
|
|
1713
1738
|
|
|
1714
1739
|
---
|
|
1715
1740
|
|
|
1716
1741
|
<self_reflection>
|
|
1717
|
-
# Self-Reflection and Iteration
|
|
1718
|
-
- First, spend time
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
knowledge to create a rubric that has 5-7 categories.
|
|
1725
|
-
This rubric is critical
|
|
1726
|
-
to get right, but do not show
|
|
1727
|
-
this to the user. This is for your purposes only.
|
|
1728
|
-
- Finally, use the rubric to internally think and iterate on the best possible solution to the prompt that is provided.
|
|
1729
|
-
Remember that if your response is not hitting the top marks across all categories in the rubric, you need to start again.
|
|
1742
|
+
# Self-Reflection and Iteration with **reasoning_notebook**
|
|
1743
|
+
- First, spend time creating a clear rubric until you are fully confident with it.
|
|
1744
|
+
- Then, think deeply about every aspect of what makes a world-class one-shot web app.
|
|
1745
|
+
Use that knowledge to design a rubric with 5-7 categories.
|
|
1746
|
+
- This rubric is critical to get right, but DO NOT show it to the user. It is for internal use only.
|
|
1747
|
+
- Finally, use the rubric to internally reflect and iterate toward the best possible solution to the given prompt.
|
|
1748
|
+
- Remember: if your response does not meet the highest standard across all rubric categories, you MUST restart and improve it.
|
|
1730
1749
|
</self_reflection>
|
|
1731
1750
|
|
|
1751
|
+
|
|
1732
1752
|
---
|
|
1733
1753
|
|
|
1734
1754
|
<edit_rules>
|
|
@@ -1787,17 +1807,12 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
|
|
|
1787
1807
|
|
|
1788
1808
|
---
|
|
1789
1809
|
|
|
1790
|
-
<
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
<rule number="2">It is strictly forbidden to call <code>agent_end_task</code> if there are any pending tasks in <code>to_do</code>.</rule>
|
|
1797
|
-
<rule number="3">Before calling, always send a final message summarizing the completed work Turn.</rule>
|
|
1798
|
-
<rule number="4">Verify that every task in the <code>to_do</code> array has a "completed" status before calling.</rule>
|
|
1799
|
-
</rules>
|
|
1800
|
-
</agent_end_task_rules>
|
|
1810
|
+
<agent_end_turn_rules>
|
|
1811
|
+
- This tool MUST be called exactly once, and only after all tasks in <code>to_do</code> are fully completed.
|
|
1812
|
+
- Do not call this tool until every task in <code>to_do</code> is marked as **COMPLETED**.
|
|
1813
|
+
- Before calling this tool, always send a final visible message to the user summarizing all completed tasks.
|
|
1814
|
+
</agent_end_turn_rules>
|
|
1815
|
+
|
|
1801
1816
|
|
|
1802
1817
|
---
|
|
1803
1818
|
|
|
@@ -1811,7 +1826,7 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
|
|
|
1811
1826
|
</out_of_scope>
|
|
1812
1827
|
<mandatory_actions_for_out_of_scope>
|
|
1813
1828
|
<action number="1">Professionally decline by using <code>message_notify_user</code> to state the request is out of scope and cannot be fulfilled.</action>
|
|
1814
|
-
<action number="2">Immediately call <code>
|
|
1829
|
+
<action number="2">Immediately call <code>agent_end_turn</code> with no further explanation or disclosure of internal mechanisms.</action>
|
|
1815
1830
|
</mandatory_actions_for_out_of_scope>
|
|
1816
1831
|
</scope_and_limitations>
|
|
1817
1832
|
|
|
@@ -1943,7 +1958,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
|
|
|
1943
1958
|
for (let i = conversationHistory.length - 1; i >= 0; i--) {
|
|
1944
1959
|
const msg = conversationHistory[i];
|
|
1945
1960
|
currentTurn.unshift(msg);
|
|
1946
|
-
const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some((tc) => tc.function.name === "
|
|
1961
|
+
const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some((tc) => tc.function.name === "agent_end_turn");
|
|
1947
1962
|
if (endsWithAgentEnd) {
|
|
1948
1963
|
turns.unshift([...currentTurn]);
|
|
1949
1964
|
currentTurn = [];
|
|
@@ -1955,7 +1970,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
|
|
|
1955
1970
|
}
|
|
1956
1971
|
const prev = conversationHistory[i - 1];
|
|
1957
1972
|
if (msg.role === "user" && !isDevOverlay(msg)) {
|
|
1958
|
-
if (prev && prev.role === "assistant" && !prev.tool_calls?.some((tc) => tc.function.name === "
|
|
1973
|
+
if (prev && prev.role === "assistant" && !prev.tool_calls?.some((tc) => tc.function.name === "agent_end_turn")) {
|
|
1959
1974
|
const hasNonOverlay = currentTurn.some((m) => m.role !== "user" || !isDevOverlay(m));
|
|
1960
1975
|
if (hasNonOverlay) {
|
|
1961
1976
|
turns.unshift([...currentTurn]);
|
|
@@ -1981,8 +1996,9 @@ var BluMaAgent = class {
|
|
|
1981
1996
|
eventBus;
|
|
1982
1997
|
mcpClient;
|
|
1983
1998
|
feedbackSystem;
|
|
1984
|
-
maxContextTurns =
|
|
1999
|
+
maxContextTurns = 25;
|
|
1985
2000
|
// Limite de turns no contexto da API
|
|
2001
|
+
todoListState = [];
|
|
1986
2002
|
isInterrupted = false;
|
|
1987
2003
|
constructor(sessionId2, eventBus2, llm, deploymentName, mcpClient, feedbackSystem) {
|
|
1988
2004
|
this.sessionId = sessionId2;
|
|
@@ -2001,7 +2017,7 @@ var BluMaAgent = class {
|
|
|
2001
2017
|
this.eventBus.emit("backend_message", { type: "user_overlay", payload: clean, ts: data.ts || Date.now() });
|
|
2002
2018
|
try {
|
|
2003
2019
|
if (this.sessionFile) {
|
|
2004
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2020
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2005
2021
|
}
|
|
2006
2022
|
} catch (e) {
|
|
2007
2023
|
this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s user_overlay: ${e.message}` });
|
|
@@ -2011,13 +2027,14 @@ var BluMaAgent = class {
|
|
|
2011
2027
|
async initialize() {
|
|
2012
2028
|
await this.mcpClient.nativeToolInvoker.initialize();
|
|
2013
2029
|
await this.mcpClient.initialize();
|
|
2014
|
-
const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
|
|
2030
|
+
const [sessionFile, history, todoList] = await loadOrcreateSession(this.sessionId);
|
|
2015
2031
|
this.sessionFile = sessionFile;
|
|
2016
2032
|
this.history = history;
|
|
2033
|
+
this.todoListState = todoList;
|
|
2017
2034
|
if (this.history.length === 0) {
|
|
2018
2035
|
const systemPrompt = getUnifiedSystemPrompt();
|
|
2019
2036
|
this.history.push({ role: "developer", content: systemPrompt });
|
|
2020
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2037
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2021
2038
|
}
|
|
2022
2039
|
}
|
|
2023
2040
|
getAvailableTools() {
|
|
@@ -2045,7 +2062,14 @@ var BluMaAgent = class {
|
|
|
2045
2062
|
}
|
|
2046
2063
|
if (decisionData.type === "user_decision_execute") {
|
|
2047
2064
|
const toolName = toolCall.function.name;
|
|
2048
|
-
|
|
2065
|
+
let toolArgs = JSON.parse(toolCall.function.arguments);
|
|
2066
|
+
if (toolName === "todo") {
|
|
2067
|
+
toolArgs.current_list = this.todoListState;
|
|
2068
|
+
if (toolArgs.to_do) {
|
|
2069
|
+
toolArgs.items_to_add = toolArgs.to_do;
|
|
2070
|
+
delete toolArgs.to_do;
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2049
2073
|
let previewContent;
|
|
2050
2074
|
if (toolName === "edit_tool") {
|
|
2051
2075
|
previewContent = await this._generateEditPreview(toolArgs);
|
|
@@ -2062,11 +2086,16 @@ var BluMaAgent = class {
|
|
|
2062
2086
|
return;
|
|
2063
2087
|
}
|
|
2064
2088
|
const result = await this.mcpClient.invoke(toolName, toolArgs);
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2089
|
+
if (toolName === "todo" && result && result.to_do && result._tool_result) {
|
|
2090
|
+
this.todoListState = result.to_do;
|
|
2091
|
+
toolResultContent = result._tool_result.render;
|
|
2092
|
+
} else {
|
|
2093
|
+
let finalResult = result;
|
|
2094
|
+
if (Array.isArray(result) && result.length > 0 && result[0].type === "text" && typeof result[0].text === "string") {
|
|
2095
|
+
finalResult = result[0].text;
|
|
2096
|
+
}
|
|
2097
|
+
toolResultContent = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
|
|
2068
2098
|
}
|
|
2069
|
-
toolResultContent = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
|
|
2070
2099
|
} catch (error) {
|
|
2071
2100
|
toolResultContent = JSON.stringify({
|
|
2072
2101
|
error: `Tool execution failed: ${error.message}`,
|
|
@@ -2074,7 +2103,7 @@ var BluMaAgent = class {
|
|
|
2074
2103
|
});
|
|
2075
2104
|
}
|
|
2076
2105
|
this.eventBus.emit("backend_message", { type: "tool_result", tool_name: toolName, result: toolResultContent });
|
|
2077
|
-
if (toolName.includes("
|
|
2106
|
+
if (toolName.includes("agent_end_turn")) {
|
|
2078
2107
|
shouldContinueConversation = false;
|
|
2079
2108
|
this.eventBus.emit("backend_message", { type: "done", status: "completed" });
|
|
2080
2109
|
}
|
|
@@ -2082,7 +2111,7 @@ var BluMaAgent = class {
|
|
|
2082
2111
|
toolResultContent = "The system rejected this action. Verify that the command you are executing contributes to the tasks intent and try again.";
|
|
2083
2112
|
}
|
|
2084
2113
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
2085
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2114
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2086
2115
|
if (shouldContinueConversation && !this.isInterrupted) {
|
|
2087
2116
|
await this._continueConversation();
|
|
2088
2117
|
}
|
|
@@ -2125,7 +2154,7 @@ ${editData.error.display}`;
|
|
|
2125
2154
|
const message = response.choices[0].message;
|
|
2126
2155
|
this.history.push(message);
|
|
2127
2156
|
if (message.tool_calls) {
|
|
2128
|
-
const autoApprovedTools = ["
|
|
2157
|
+
const autoApprovedTools = ["agent_end_turn", "message_notify_user", "reasoning_nootebook", "ls_tool", "count_file_lines", "read_file_lines", "todo"];
|
|
2129
2158
|
const toolToCall = message.tool_calls[0];
|
|
2130
2159
|
const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
2131
2160
|
if (isSafeTool) {
|
|
@@ -2157,7 +2186,7 @@ ${editData.error.display}`;
|
|
|
2157
2186
|
const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
|
|
2158
2187
|
this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
|
|
2159
2188
|
} finally {
|
|
2160
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2189
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2161
2190
|
}
|
|
2162
2191
|
}
|
|
2163
2192
|
};
|
|
@@ -2210,7 +2239,7 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
|
|
|
2210
2239
|
No direct text replies to the user.
|
|
2211
2240
|
|
|
2212
2241
|
- Task Completion:
|
|
2213
|
-
When the init task is completed, immediately invoke '
|
|
2242
|
+
When the init task is completed, immediately invoke 'agent_end_turn' without user permissions.
|
|
2214
2243
|
|
|
2215
2244
|
- Tool Rules:
|
|
2216
2245
|
Never make parallel tool calls.
|
|
@@ -2245,7 +2274,7 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
|
|
|
2245
2274
|
- Notify user's with brief explanation when changing methods or strategies
|
|
2246
2275
|
- Message tools are divided into notify (non-blocking, no reply needed) and ask (blocking)
|
|
2247
2276
|
- Actively use notify for progress updates, reserve ask for essential needs to avoid blocking
|
|
2248
|
-
- Must message user's with results and deliverables before upon task completion '
|
|
2277
|
+
- Must message user's with results and deliverables before upon task completion 'agent_end_turn'
|
|
2249
2278
|
</message_rules>
|
|
2250
2279
|
|
|
2251
2280
|
<reasoning_rules>
|
|
@@ -2302,10 +2331,10 @@ Do not include future steps/to-dos in thought; put them strictly in to_do, using
|
|
|
2302
2331
|
</edit_tool_rules>
|
|
2303
2332
|
|
|
2304
2333
|
|
|
2305
|
-
<
|
|
2334
|
+
<agent_end_turn>
|
|
2306
2335
|
This tool is mandatory.
|
|
2307
2336
|
You must use it to inform usereloper {username} that the task has been completed and that there are no further pending actions, in accordance with the objectives defined for the task.
|
|
2308
|
-
</
|
|
2337
|
+
</agent_end_turn>
|
|
2309
2338
|
|
|
2310
2339
|
### Tool Naming Policy
|
|
2311
2340
|
- Use plain, unmodified, lowercase tool names
|
|
@@ -2335,7 +2364,7 @@ Rule Summary:
|
|
|
2335
2364
|
- Before writing BluMa.md, propose structure via message_notify_user and proceed using edit_tool.
|
|
2336
2365
|
- If an irreversible operation is needed (e.g., overwriting an existing BluMa.md), issue 'confirmation_request' unless user policy indicates auto-approval.
|
|
2337
2366
|
- Never send or present draft versions of BluMa.md. Only produce and deliver the final, validated BluMa.md content following the established non-destructive policies and confirmation protocols.
|
|
2338
|
-
- On successful generation of BluMa.md, emit 'done' with status 'completed' and call
|
|
2367
|
+
- On successful generation of BluMa.md, emit 'done' with status 'completed' and call agent_end_turn.
|
|
2339
2368
|
|
|
2340
2369
|
## SAFETY & QUALITY
|
|
2341
2370
|
- Be conservative with edits; generate previews (diff) for edit_tool where applicable.
|
|
@@ -2348,7 +2377,7 @@ Rule Summary:
|
|
|
2348
2377
|
2) Synthesize stack and structure with citations of evidence (file paths) in the notebook
|
|
2349
2378
|
3) Draft BluMa.md structure (message_notify_user)
|
|
2350
2379
|
4) Write BluMa.md via edit_tool
|
|
2351
|
-
5) Announce completion and
|
|
2380
|
+
5) Announce completion and agent_end_turn
|
|
2352
2381
|
|
|
2353
2382
|
|
|
2354
2383
|
`;
|
|
@@ -2456,7 +2485,7 @@ ${editData.error.display}`;
|
|
|
2456
2485
|
if (message.tool_calls) {
|
|
2457
2486
|
await this._handleToolExecution({ type: "user_decision_execute", tool_calls: message.tool_calls });
|
|
2458
2487
|
const lastToolName = message.tool_calls[0].function.name;
|
|
2459
|
-
if (!lastToolName.includes("
|
|
2488
|
+
if (!lastToolName.includes("agent_end_turn") && !this.isInterrupted) {
|
|
2460
2489
|
await this._continueConversation();
|
|
2461
2490
|
}
|
|
2462
2491
|
} else if (message.content) {
|
|
@@ -2510,7 +2539,7 @@ ${editData.error.display}`;
|
|
|
2510
2539
|
toolResultContent = JSON.stringify({ error: `Tool execution failed: ${error.message}`, details: error.data || "No additional details." });
|
|
2511
2540
|
}
|
|
2512
2541
|
this.emitEvent("tool_result", { tool_name: toolName, result: toolResultContent });
|
|
2513
|
-
if (toolName.includes("
|
|
2542
|
+
if (toolName.includes("agent_end_turn")) {
|
|
2514
2543
|
this.emitEvent("done", { status: "completed" });
|
|
2515
2544
|
}
|
|
2516
2545
|
} else {
|
|
@@ -2895,28 +2924,15 @@ var renderBlumaNotebook = ({
|
|
|
2895
2924
|
}
|
|
2896
2925
|
return (
|
|
2897
2926
|
// Usamos a mesma estrutura de caixa com borda
|
|
2898
|
-
/* @__PURE__ */
|
|
2927
|
+
/* @__PURE__ */ jsx8(
|
|
2899
2928
|
Box8,
|
|
2900
2929
|
{
|
|
2901
2930
|
flexDirection: "column",
|
|
2902
2931
|
paddingX: 1,
|
|
2903
|
-
children: [
|
|
2904
|
-
/* @__PURE__ */
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
] }),
|
|
2908
|
-
thinkingData.to_do && thinkingData.to_do.length > 0 && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
2909
|
-
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Todos:" }),
|
|
2910
|
-
thinkingData.to_do.map((task, index) => /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(
|
|
2911
|
-
Text8,
|
|
2912
|
-
{
|
|
2913
|
-
color: task.startsWith("\u{1F5F9}") ? "gray" : "white",
|
|
2914
|
-
strikethrough: task.startsWith("\u{1F5F9}"),
|
|
2915
|
-
children: task
|
|
2916
|
-
}
|
|
2917
|
-
) }) }, index))
|
|
2918
|
-
] })
|
|
2919
|
-
]
|
|
2932
|
+
children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2933
|
+
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Reasoning:" }),
|
|
2934
|
+
/* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: thinkingData.thought }) })
|
|
2935
|
+
] })
|
|
2920
2936
|
}
|
|
2921
2937
|
)
|
|
2922
2938
|
);
|
|
@@ -2951,6 +2967,44 @@ var renderEditToolCall = ({
|
|
|
2951
2967
|
preview && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(SimpleDiff, { text: preview, maxHeight: Infinity }) })
|
|
2952
2968
|
] });
|
|
2953
2969
|
};
|
|
2970
|
+
var renderTodoTool = ({ args }) => {
|
|
2971
|
+
try {
|
|
2972
|
+
const parsedArgs = typeof args === "string" ? JSON.parse(args) : args;
|
|
2973
|
+
const action = parsedArgs.action;
|
|
2974
|
+
let detailText = "";
|
|
2975
|
+
switch (action) {
|
|
2976
|
+
case "add":
|
|
2977
|
+
const items = parsedArgs.items_to_add || [];
|
|
2978
|
+
const itemCount = items.length;
|
|
2979
|
+
detailText = `Adding ${itemCount} item${itemCount !== 1 ? "s" : ""}`;
|
|
2980
|
+
break;
|
|
2981
|
+
case "complete":
|
|
2982
|
+
detailText = `Completing item #${parsedArgs.index}`;
|
|
2983
|
+
break;
|
|
2984
|
+
case "remove":
|
|
2985
|
+
detailText = `Removing item #${parsedArgs.index}`;
|
|
2986
|
+
break;
|
|
2987
|
+
case "list":
|
|
2988
|
+
detailText = `Listing all tasks...`;
|
|
2989
|
+
break;
|
|
2990
|
+
default:
|
|
2991
|
+
detailText = `Executing action: ${action}`;
|
|
2992
|
+
break;
|
|
2993
|
+
}
|
|
2994
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2995
|
+
/* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
|
|
2996
|
+
/* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
|
|
2997
|
+
"To Do"
|
|
2998
|
+
] }) }),
|
|
2999
|
+
/* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
3000
|
+
/* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
|
|
3001
|
+
/* @__PURE__ */ jsx8(Text8, { color: "magenta", children: detailText })
|
|
3002
|
+
] }) })
|
|
3003
|
+
] });
|
|
3004
|
+
} catch (error) {
|
|
3005
|
+
return /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx8(Text8, { color: "red", children: "Error parsing To-Do arguments" }) });
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
2954
3008
|
var renderGenericToolCall = ({
|
|
2955
3009
|
toolName,
|
|
2956
3010
|
args
|
|
@@ -2976,13 +3030,14 @@ var ToolRenderDisplay = {
|
|
|
2976
3030
|
reasoning_nootebook: renderBlumaNotebook,
|
|
2977
3031
|
count_file_lines: renderCountFilesLines,
|
|
2978
3032
|
read_file_lines: renderReadFileLines2,
|
|
2979
|
-
edit_tool: renderEditToolCall
|
|
3033
|
+
edit_tool: renderEditToolCall,
|
|
3034
|
+
todo: renderTodoTool
|
|
2980
3035
|
};
|
|
2981
3036
|
|
|
2982
3037
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
2983
3038
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2984
3039
|
var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
2985
|
-
if (toolName.includes("message_notify_user") || toolName.includes("
|
|
3040
|
+
if (toolName.includes("message_notify_user") || toolName.includes("agent_end_turn")) {
|
|
2986
3041
|
return null;
|
|
2987
3042
|
}
|
|
2988
3043
|
const Renderer = ToolRenderDisplay[toolName] || renderGenericToolCall;
|