@nomad-e/bluma-cli 0.0.77 → 0.0.79
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 +127 -74
- 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 {
|
|
@@ -1710,25 +1714,38 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
|
|
|
1710
1714
|
- Ends each task with a final message confirming completion or reporting the result.
|
|
1711
1715
|
</message_rules>
|
|
1712
1716
|
|
|
1717
|
+
<todo_rules>
|
|
1718
|
+
- To manage tasks, you must always use the \`todo\` tool. Never write a to-do list directly as text.
|
|
1719
|
+
- The agent maintains the to-do list's state for you. You do not need to keep track of the full list.
|
|
1720
|
+
- Your job is to send simple commands to the agent via the \`todo\` tool.
|
|
1721
|
+
|
|
1722
|
+
**How to use the \`todo\` tool actions:**
|
|
1723
|
+
1. **To see the current list:** Call the tool with \`action: "list"\`.
|
|
1724
|
+
2. **To add new tasks:**
|
|
1725
|
+
- Use \`action: "add"\`.
|
|
1726
|
+
- Provide a list of plain text strings in the \`items_to_add\` parameter.
|
|
1727
|
+
- **Important:** Do NOT add any prefixes like \`\u2610\` or \`\u{1F5F9}\`. The tool handles all formatting.
|
|
1728
|
+
3. **To complete or remove a task:**
|
|
1729
|
+
- Use \`action: "complete"\` or \`action: "remove"\`.
|
|
1730
|
+
- 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).
|
|
1731
|
+
|
|
1732
|
+
- After every action you take, the tool will respond with the newly updated and formatted list for your reference.
|
|
1733
|
+
</todo_rules>
|
|
1734
|
+
|
|
1713
1735
|
|
|
1714
1736
|
---
|
|
1715
1737
|
|
|
1716
1738
|
<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.
|
|
1739
|
+
# Self-Reflection and Iteration with **reasoning_notebook**
|
|
1740
|
+
- First, spend time creating a clear rubric until you are fully confident with it.
|
|
1741
|
+
- Then, think deeply about every aspect of what makes a world-class one-shot web app.
|
|
1742
|
+
Use that knowledge to design a rubric with 5-7 categories.
|
|
1743
|
+
- This rubric is critical to get right, but DO NOT show it to the user. It is for internal use only.
|
|
1744
|
+
- Finally, use the rubric to internally reflect and iterate toward the best possible solution to the given prompt.
|
|
1745
|
+
- Remember: if your response does not meet the highest standard across all rubric categories, you MUST restart and improve it.
|
|
1730
1746
|
</self_reflection>
|
|
1731
1747
|
|
|
1748
|
+
|
|
1732
1749
|
---
|
|
1733
1750
|
|
|
1734
1751
|
<edit_rules>
|
|
@@ -1787,17 +1804,12 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
|
|
|
1787
1804
|
|
|
1788
1805
|
---
|
|
1789
1806
|
|
|
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>
|
|
1807
|
+
<agent_end_turn_rules>
|
|
1808
|
+
- This tool MUST be called exactly once, and only after all tasks in <code>to_do</code> are fully completed.
|
|
1809
|
+
- Do not call this tool until every task in <code>to_do</code> is marked as **COMPLETED**.
|
|
1810
|
+
- Before calling this tool, always send a final visible message to the user summarizing all completed tasks.
|
|
1811
|
+
</agent_end_turn_rules>
|
|
1812
|
+
|
|
1801
1813
|
|
|
1802
1814
|
---
|
|
1803
1815
|
|
|
@@ -1811,7 +1823,7 @@ Ensure that each task contributes to a cohesive, functional, and visually appeal
|
|
|
1811
1823
|
</out_of_scope>
|
|
1812
1824
|
<mandatory_actions_for_out_of_scope>
|
|
1813
1825
|
<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>
|
|
1826
|
+
<action number="2">Immediately call <code>agent_end_turn</code> with no further explanation or disclosure of internal mechanisms.</action>
|
|
1815
1827
|
</mandatory_actions_for_out_of_scope>
|
|
1816
1828
|
</scope_and_limitations>
|
|
1817
1829
|
|
|
@@ -1943,7 +1955,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
|
|
|
1943
1955
|
for (let i = conversationHistory.length - 1; i >= 0; i--) {
|
|
1944
1956
|
const msg = conversationHistory[i];
|
|
1945
1957
|
currentTurn.unshift(msg);
|
|
1946
|
-
const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some((tc) => tc.function.name === "
|
|
1958
|
+
const endsWithAgentEnd = msg.role === "assistant" && msg.tool_calls?.some((tc) => tc.function.name === "agent_end_turn");
|
|
1947
1959
|
if (endsWithAgentEnd) {
|
|
1948
1960
|
turns.unshift([...currentTurn]);
|
|
1949
1961
|
currentTurn = [];
|
|
@@ -1955,7 +1967,7 @@ function createApiContextWindow(fullHistory, maxTurns) {
|
|
|
1955
1967
|
}
|
|
1956
1968
|
const prev = conversationHistory[i - 1];
|
|
1957
1969
|
if (msg.role === "user" && !isDevOverlay(msg)) {
|
|
1958
|
-
if (prev && prev.role === "assistant" && !prev.tool_calls?.some((tc) => tc.function.name === "
|
|
1970
|
+
if (prev && prev.role === "assistant" && !prev.tool_calls?.some((tc) => tc.function.name === "agent_end_turn")) {
|
|
1959
1971
|
const hasNonOverlay = currentTurn.some((m) => m.role !== "user" || !isDevOverlay(m));
|
|
1960
1972
|
if (hasNonOverlay) {
|
|
1961
1973
|
turns.unshift([...currentTurn]);
|
|
@@ -1981,7 +1993,9 @@ var BluMaAgent = class {
|
|
|
1981
1993
|
eventBus;
|
|
1982
1994
|
mcpClient;
|
|
1983
1995
|
feedbackSystem;
|
|
1984
|
-
maxContextTurns =
|
|
1996
|
+
maxContextTurns = 25;
|
|
1997
|
+
// Limite de turns no contexto da API
|
|
1998
|
+
todoListState = [];
|
|
1985
1999
|
isInterrupted = false;
|
|
1986
2000
|
constructor(sessionId2, eventBus2, llm, deploymentName, mcpClient, feedbackSystem) {
|
|
1987
2001
|
this.sessionId = sessionId2;
|
|
@@ -2000,7 +2014,7 @@ var BluMaAgent = class {
|
|
|
2000
2014
|
this.eventBus.emit("backend_message", { type: "user_overlay", payload: clean, ts: data.ts || Date.now() });
|
|
2001
2015
|
try {
|
|
2002
2016
|
if (this.sessionFile) {
|
|
2003
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2017
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2004
2018
|
}
|
|
2005
2019
|
} catch (e) {
|
|
2006
2020
|
this.eventBus.emit("backend_message", { type: "error", message: `Falha ao salvar hist\xF3rico ap\xF3s user_overlay: ${e.message}` });
|
|
@@ -2010,13 +2024,14 @@ var BluMaAgent = class {
|
|
|
2010
2024
|
async initialize() {
|
|
2011
2025
|
await this.mcpClient.nativeToolInvoker.initialize();
|
|
2012
2026
|
await this.mcpClient.initialize();
|
|
2013
|
-
const [sessionFile, history] = await loadOrcreateSession(this.sessionId);
|
|
2027
|
+
const [sessionFile, history, todoList] = await loadOrcreateSession(this.sessionId);
|
|
2014
2028
|
this.sessionFile = sessionFile;
|
|
2015
2029
|
this.history = history;
|
|
2030
|
+
this.todoListState = todoList;
|
|
2016
2031
|
if (this.history.length === 0) {
|
|
2017
2032
|
const systemPrompt = getUnifiedSystemPrompt();
|
|
2018
2033
|
this.history.push({ role: "developer", content: systemPrompt });
|
|
2019
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2034
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2020
2035
|
}
|
|
2021
2036
|
}
|
|
2022
2037
|
getAvailableTools() {
|
|
@@ -2044,7 +2059,14 @@ var BluMaAgent = class {
|
|
|
2044
2059
|
}
|
|
2045
2060
|
if (decisionData.type === "user_decision_execute") {
|
|
2046
2061
|
const toolName = toolCall.function.name;
|
|
2047
|
-
|
|
2062
|
+
let toolArgs = JSON.parse(toolCall.function.arguments);
|
|
2063
|
+
if (toolName === "todo") {
|
|
2064
|
+
toolArgs.current_list = this.todoListState;
|
|
2065
|
+
if (toolArgs.to_do) {
|
|
2066
|
+
toolArgs.items_to_add = toolArgs.to_do;
|
|
2067
|
+
delete toolArgs.to_do;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2048
2070
|
let previewContent;
|
|
2049
2071
|
if (toolName === "edit_tool") {
|
|
2050
2072
|
previewContent = await this._generateEditPreview(toolArgs);
|
|
@@ -2061,11 +2083,16 @@ var BluMaAgent = class {
|
|
|
2061
2083
|
return;
|
|
2062
2084
|
}
|
|
2063
2085
|
const result = await this.mcpClient.invoke(toolName, toolArgs);
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2086
|
+
if (toolName === "todo" && result && result.to_do && result._tool_result) {
|
|
2087
|
+
this.todoListState = result.to_do;
|
|
2088
|
+
toolResultContent = result._tool_result.render;
|
|
2089
|
+
} else {
|
|
2090
|
+
let finalResult = result;
|
|
2091
|
+
if (Array.isArray(result) && result.length > 0 && result[0].type === "text" && typeof result[0].text === "string") {
|
|
2092
|
+
finalResult = result[0].text;
|
|
2093
|
+
}
|
|
2094
|
+
toolResultContent = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
|
|
2067
2095
|
}
|
|
2068
|
-
toolResultContent = typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult);
|
|
2069
2096
|
} catch (error) {
|
|
2070
2097
|
toolResultContent = JSON.stringify({
|
|
2071
2098
|
error: `Tool execution failed: ${error.message}`,
|
|
@@ -2073,7 +2100,7 @@ var BluMaAgent = class {
|
|
|
2073
2100
|
});
|
|
2074
2101
|
}
|
|
2075
2102
|
this.eventBus.emit("backend_message", { type: "tool_result", tool_name: toolName, result: toolResultContent });
|
|
2076
|
-
if (toolName.includes("
|
|
2103
|
+
if (toolName.includes("agent_end_turn")) {
|
|
2077
2104
|
shouldContinueConversation = false;
|
|
2078
2105
|
this.eventBus.emit("backend_message", { type: "done", status: "completed" });
|
|
2079
2106
|
}
|
|
@@ -2081,7 +2108,7 @@ var BluMaAgent = class {
|
|
|
2081
2108
|
toolResultContent = "The system rejected this action. Verify that the command you are executing contributes to the tasks intent and try again.";
|
|
2082
2109
|
}
|
|
2083
2110
|
this.history.push({ role: "tool", tool_call_id: toolCall.id, content: toolResultContent });
|
|
2084
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2111
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2085
2112
|
if (shouldContinueConversation && !this.isInterrupted) {
|
|
2086
2113
|
await this._continueConversation();
|
|
2087
2114
|
}
|
|
@@ -2124,7 +2151,7 @@ ${editData.error.display}`;
|
|
|
2124
2151
|
const message = response.choices[0].message;
|
|
2125
2152
|
this.history.push(message);
|
|
2126
2153
|
if (message.tool_calls) {
|
|
2127
|
-
const autoApprovedTools = ["
|
|
2154
|
+
const autoApprovedTools = ["agent_end_turn", "message_notify_user", "reasoning_nootebook", "ls_tool", "count_file_lines", "read_file_lines", "todo"];
|
|
2128
2155
|
const toolToCall = message.tool_calls[0];
|
|
2129
2156
|
const isSafeTool = autoApprovedTools.some((safeTool) => toolToCall.function.name.includes(safeTool));
|
|
2130
2157
|
if (isSafeTool) {
|
|
@@ -2156,7 +2183,7 @@ ${editData.error.display}`;
|
|
|
2156
2183
|
const errorMessage = error instanceof Error ? error.message : "An unknown API error occurred.";
|
|
2157
2184
|
this.eventBus.emit("backend_message", { type: "error", message: errorMessage });
|
|
2158
2185
|
} finally {
|
|
2159
|
-
await saveSessionHistory(this.sessionFile, this.history);
|
|
2186
|
+
await saveSessionHistory(this.sessionFile, this.history, this.todoListState);
|
|
2160
2187
|
}
|
|
2161
2188
|
}
|
|
2162
2189
|
};
|
|
@@ -2209,7 +2236,7 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
|
|
|
2209
2236
|
No direct text replies to the user.
|
|
2210
2237
|
|
|
2211
2238
|
- Task Completion:
|
|
2212
|
-
When the init task is completed, immediately invoke '
|
|
2239
|
+
When the init task is completed, immediately invoke 'agent_end_turn' without user permissions.
|
|
2213
2240
|
|
|
2214
2241
|
- Tool Rules:
|
|
2215
2242
|
Never make parallel tool calls.
|
|
@@ -2244,7 +2271,7 @@ You extend the BluMa multi-agent architecture and handle the project bootstrappi
|
|
|
2244
2271
|
- Notify user's with brief explanation when changing methods or strategies
|
|
2245
2272
|
- Message tools are divided into notify (non-blocking, no reply needed) and ask (blocking)
|
|
2246
2273
|
- Actively use notify for progress updates, reserve ask for essential needs to avoid blocking
|
|
2247
|
-
- Must message user's with results and deliverables before upon task completion '
|
|
2274
|
+
- Must message user's with results and deliverables before upon task completion 'agent_end_turn'
|
|
2248
2275
|
</message_rules>
|
|
2249
2276
|
|
|
2250
2277
|
<reasoning_rules>
|
|
@@ -2301,10 +2328,10 @@ Do not include future steps/to-dos in thought; put them strictly in to_do, using
|
|
|
2301
2328
|
</edit_tool_rules>
|
|
2302
2329
|
|
|
2303
2330
|
|
|
2304
|
-
<
|
|
2331
|
+
<agent_end_turn>
|
|
2305
2332
|
This tool is mandatory.
|
|
2306
2333
|
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.
|
|
2307
|
-
</
|
|
2334
|
+
</agent_end_turn>
|
|
2308
2335
|
|
|
2309
2336
|
### Tool Naming Policy
|
|
2310
2337
|
- Use plain, unmodified, lowercase tool names
|
|
@@ -2334,7 +2361,7 @@ Rule Summary:
|
|
|
2334
2361
|
- Before writing BluMa.md, propose structure via message_notify_user and proceed using edit_tool.
|
|
2335
2362
|
- If an irreversible operation is needed (e.g., overwriting an existing BluMa.md), issue 'confirmation_request' unless user policy indicates auto-approval.
|
|
2336
2363
|
- 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.
|
|
2337
|
-
- On successful generation of BluMa.md, emit 'done' with status 'completed' and call
|
|
2364
|
+
- On successful generation of BluMa.md, emit 'done' with status 'completed' and call agent_end_turn.
|
|
2338
2365
|
|
|
2339
2366
|
## SAFETY & QUALITY
|
|
2340
2367
|
- Be conservative with edits; generate previews (diff) for edit_tool where applicable.
|
|
@@ -2347,7 +2374,7 @@ Rule Summary:
|
|
|
2347
2374
|
2) Synthesize stack and structure with citations of evidence (file paths) in the notebook
|
|
2348
2375
|
3) Draft BluMa.md structure (message_notify_user)
|
|
2349
2376
|
4) Write BluMa.md via edit_tool
|
|
2350
|
-
5) Announce completion and
|
|
2377
|
+
5) Announce completion and agent_end_turn
|
|
2351
2378
|
|
|
2352
2379
|
|
|
2353
2380
|
`;
|
|
@@ -2455,7 +2482,7 @@ ${editData.error.display}`;
|
|
|
2455
2482
|
if (message.tool_calls) {
|
|
2456
2483
|
await this._handleToolExecution({ type: "user_decision_execute", tool_calls: message.tool_calls });
|
|
2457
2484
|
const lastToolName = message.tool_calls[0].function.name;
|
|
2458
|
-
if (!lastToolName.includes("
|
|
2485
|
+
if (!lastToolName.includes("agent_end_turn") && !this.isInterrupted) {
|
|
2459
2486
|
await this._continueConversation();
|
|
2460
2487
|
}
|
|
2461
2488
|
} else if (message.content) {
|
|
@@ -2509,7 +2536,7 @@ ${editData.error.display}`;
|
|
|
2509
2536
|
toolResultContent = JSON.stringify({ error: `Tool execution failed: ${error.message}`, details: error.data || "No additional details." });
|
|
2510
2537
|
}
|
|
2511
2538
|
this.emitEvent("tool_result", { tool_name: toolName, result: toolResultContent });
|
|
2512
|
-
if (toolName.includes("
|
|
2539
|
+
if (toolName.includes("agent_end_turn")) {
|
|
2513
2540
|
this.emitEvent("done", { status: "completed" });
|
|
2514
2541
|
}
|
|
2515
2542
|
} else {
|
|
@@ -2894,28 +2921,15 @@ var renderBlumaNotebook = ({
|
|
|
2894
2921
|
}
|
|
2895
2922
|
return (
|
|
2896
2923
|
// Usamos a mesma estrutura de caixa com borda
|
|
2897
|
-
/* @__PURE__ */
|
|
2924
|
+
/* @__PURE__ */ jsx8(
|
|
2898
2925
|
Box8,
|
|
2899
2926
|
{
|
|
2900
2927
|
flexDirection: "column",
|
|
2901
2928
|
paddingX: 1,
|
|
2902
|
-
children: [
|
|
2903
|
-
/* @__PURE__ */
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
] }),
|
|
2907
|
-
thinkingData.to_do && thinkingData.to_do.length > 0 && /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
|
|
2908
|
-
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Todos:" }),
|
|
2909
|
-
thinkingData.to_do.map((task, index) => /* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { children: /* @__PURE__ */ jsx8(
|
|
2910
|
-
Text8,
|
|
2911
|
-
{
|
|
2912
|
-
color: task.startsWith("\u{1F5F9}") ? "gray" : "white",
|
|
2913
|
-
strikethrough: task.startsWith("\u{1F5F9}"),
|
|
2914
|
-
children: task
|
|
2915
|
-
}
|
|
2916
|
-
) }) }, index))
|
|
2917
|
-
] })
|
|
2918
|
-
]
|
|
2929
|
+
children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2930
|
+
/* @__PURE__ */ jsx8(Text8, { color: "white", bold: true, children: "Reasoning:" }),
|
|
2931
|
+
/* @__PURE__ */ jsx8(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { color: "gray", children: thinkingData.thought }) })
|
|
2932
|
+
] })
|
|
2919
2933
|
}
|
|
2920
2934
|
)
|
|
2921
2935
|
);
|
|
@@ -2950,6 +2964,44 @@ var renderEditToolCall = ({
|
|
|
2950
2964
|
preview && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(SimpleDiff, { text: preview, maxHeight: Infinity }) })
|
|
2951
2965
|
] });
|
|
2952
2966
|
};
|
|
2967
|
+
var renderTodoTool = ({ args }) => {
|
|
2968
|
+
try {
|
|
2969
|
+
const parsedArgs = typeof args === "string" ? JSON.parse(args) : args;
|
|
2970
|
+
const action = parsedArgs.action;
|
|
2971
|
+
let detailText = "";
|
|
2972
|
+
switch (action) {
|
|
2973
|
+
case "add":
|
|
2974
|
+
const items = parsedArgs.items_to_add || [];
|
|
2975
|
+
const itemCount = items.length;
|
|
2976
|
+
detailText = `Adding ${itemCount} item${itemCount !== 1 ? "s" : ""}`;
|
|
2977
|
+
break;
|
|
2978
|
+
case "complete":
|
|
2979
|
+
detailText = `Completing item #${parsedArgs.index}`;
|
|
2980
|
+
break;
|
|
2981
|
+
case "remove":
|
|
2982
|
+
detailText = `Removing item #${parsedArgs.index}`;
|
|
2983
|
+
break;
|
|
2984
|
+
case "list":
|
|
2985
|
+
detailText = `Listing all tasks...`;
|
|
2986
|
+
break;
|
|
2987
|
+
default:
|
|
2988
|
+
detailText = `Executing action: ${action}`;
|
|
2989
|
+
break;
|
|
2990
|
+
}
|
|
2991
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2992
|
+
/* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsxs8(Text8, { bold: true, children: [
|
|
2993
|
+
/* @__PURE__ */ jsx8(Text8, { color: "green", children: "\u25CF " }),
|
|
2994
|
+
"To Do"
|
|
2995
|
+
] }) }),
|
|
2996
|
+
/* @__PURE__ */ jsx8(Box8, { marginLeft: 2, paddingX: 1, children: /* @__PURE__ */ jsxs8(Text8, { children: [
|
|
2997
|
+
/* @__PURE__ */ jsx8(Text8, { color: "gray", children: "\u21B3 " }),
|
|
2998
|
+
/* @__PURE__ */ jsx8(Text8, { color: "magenta", children: detailText })
|
|
2999
|
+
] }) })
|
|
3000
|
+
] });
|
|
3001
|
+
} catch (error) {
|
|
3002
|
+
return /* @__PURE__ */ jsx8(Box8, { borderStyle: "round", borderColor: "red", paddingX: 1, children: /* @__PURE__ */ jsx8(Text8, { color: "red", children: "Error parsing To-Do arguments" }) });
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
2953
3005
|
var renderGenericToolCall = ({
|
|
2954
3006
|
toolName,
|
|
2955
3007
|
args
|
|
@@ -2975,13 +3027,14 @@ var ToolRenderDisplay = {
|
|
|
2975
3027
|
reasoning_nootebook: renderBlumaNotebook,
|
|
2976
3028
|
count_file_lines: renderCountFilesLines,
|
|
2977
3029
|
read_file_lines: renderReadFileLines2,
|
|
2978
|
-
edit_tool: renderEditToolCall
|
|
3030
|
+
edit_tool: renderEditToolCall,
|
|
3031
|
+
todo: renderTodoTool
|
|
2979
3032
|
};
|
|
2980
3033
|
|
|
2981
3034
|
// src/app/ui/components/ToolCallDisplay.tsx
|
|
2982
3035
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2983
3036
|
var ToolCallDisplayComponent = ({ toolName, args, preview }) => {
|
|
2984
|
-
if (toolName.includes("message_notify_user") || toolName.includes("
|
|
3037
|
+
if (toolName.includes("message_notify_user") || toolName.includes("agent_end_turn")) {
|
|
2985
3038
|
return null;
|
|
2986
3039
|
}
|
|
2987
3040
|
const Renderer = ToolRenderDisplay[toolName] || renderGenericToolCall;
|