bimmo-cli 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/agent.js +84 -7
- package/src/interface.js +174 -95
- package/src/providers/grok.js +11 -12
- package/src/providers/openai.js +18 -9
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bimmo-cli",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "🌿 Plataforma de
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "🌿 Plataforma de IA universal com Modo Normal, Agentes e Swarms. Suporte a Diffs coloridos, Auto-Edit (Auto/Manual) e Contexto Inteligente.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"bimmo": "bin/bimmo"
|
|
7
7
|
},
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"zai",
|
|
19
19
|
"agent",
|
|
20
20
|
"swarm",
|
|
21
|
-
"
|
|
21
|
+
"diff",
|
|
22
22
|
"multimodal",
|
|
23
23
|
"terminal"
|
|
24
24
|
],
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
41
|
"commander": "^12.1.0",
|
|
42
42
|
"conf": "^13.0.0",
|
|
43
|
+
"diff": "^7.0.0",
|
|
43
44
|
"figlet": "^1.7.0",
|
|
44
45
|
"inquirer": "^10.1.0",
|
|
45
46
|
"marked": "^14.0.0",
|
package/src/agent.js
CHANGED
|
@@ -3,10 +3,18 @@ import fs from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import { execSync } from 'child_process';
|
|
5
5
|
import { getConfig } from './config.js';
|
|
6
|
+
import * as diff from 'diff';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
6
9
|
|
|
7
10
|
const config = getConfig();
|
|
8
11
|
const tvly = config.tavilyKey ? tavily({ apiKey: config.tavilyKey }) : null;
|
|
9
12
|
|
|
13
|
+
// Estado global para controle de edições (temporário na sessão)
|
|
14
|
+
export const editState = {
|
|
15
|
+
autoAccept: false
|
|
16
|
+
};
|
|
17
|
+
|
|
10
18
|
export const tools = [
|
|
11
19
|
{
|
|
12
20
|
name: 'search_internet',
|
|
@@ -55,17 +63,69 @@ export const tools = [
|
|
|
55
63
|
parameters: {
|
|
56
64
|
type: 'object',
|
|
57
65
|
properties: {
|
|
58
|
-
path: { type: 'string', description: '
|
|
66
|
+
path: { type: 'string', description: 'Caminho de destino' },
|
|
59
67
|
content: { type: 'string', description: 'Conteúdo do arquivo' }
|
|
60
68
|
},
|
|
61
69
|
required: ['path', 'content']
|
|
62
70
|
},
|
|
63
71
|
execute: async ({ path: filePath, content }) => {
|
|
64
72
|
try {
|
|
65
|
-
const
|
|
73
|
+
const absolutePath = path.resolve(filePath);
|
|
74
|
+
const oldContent = fs.existsSync(absolutePath) ? fs.readFileSync(absolutePath, 'utf-8') : "";
|
|
75
|
+
|
|
76
|
+
// Gerar Diff
|
|
77
|
+
const differences = diff.diffLines(oldContent, content);
|
|
78
|
+
|
|
79
|
+
console.log(`\n${chalk.cyan('📝 Alterações propostas em:')} ${chalk.bold(filePath)}`);
|
|
80
|
+
console.log(chalk.gray('─'.repeat(40)));
|
|
81
|
+
|
|
82
|
+
let hasChanges = false;
|
|
83
|
+
differences.forEach((part) => {
|
|
84
|
+
if (part.added || part.removed) hasChanges = true;
|
|
85
|
+
const color = part.added ? chalk.green : part.removed ? chalk.red : chalk.gray;
|
|
86
|
+
const prefix = part.added ? '+' : part.removed ? '-' : ' ';
|
|
87
|
+
|
|
88
|
+
// Mostra apenas linhas com mudanças ou um pouco de contexto
|
|
89
|
+
if (part.added || part.removed) {
|
|
90
|
+
process.stdout.write(color(`${prefix} ${part.value}`));
|
|
91
|
+
} else {
|
|
92
|
+
// Mostra apenas as primeiras e últimas linhas de blocos sem mudança para encurtar
|
|
93
|
+
const lines = part.value.split('\n');
|
|
94
|
+
if (lines.length > 4) {
|
|
95
|
+
process.stdout.write(color(` ${lines[0]}\n ...\n ${lines[lines.length-2]}\n`));
|
|
96
|
+
} else {
|
|
97
|
+
process.stdout.write(color(` ${part.value}`));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
console.log(chalk.gray('\n' + '─'.repeat(40)));
|
|
102
|
+
|
|
103
|
+
if (!hasChanges) {
|
|
104
|
+
return "Nenhuma mudança detectada no arquivo.";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Lógica de Aprovação
|
|
108
|
+
if (!editState.autoAccept) {
|
|
109
|
+
const { approve } = await inquirer.prompt([{
|
|
110
|
+
type: 'list',
|
|
111
|
+
name: 'approve',
|
|
112
|
+
message: 'Deseja aplicar estas alterações?',
|
|
113
|
+
choices: [
|
|
114
|
+
{ name: '✅ Sim', value: 'yes' },
|
|
115
|
+
{ name: '❌ Não', value: 'no' },
|
|
116
|
+
{ name: '⚡ Sim para tudo (Auto-Accept)', value: 'all' }
|
|
117
|
+
]
|
|
118
|
+
}]);
|
|
119
|
+
|
|
120
|
+
if (approve === 'no') return "Alteração rejeitada pelo usuário.";
|
|
121
|
+
if (approve === 'all') editState.autoAccept = true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const dir = path.dirname(absolutePath);
|
|
66
125
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
67
|
-
fs.writeFileSync(
|
|
68
|
-
|
|
126
|
+
fs.writeFileSync(absolutePath, content);
|
|
127
|
+
|
|
128
|
+
return `Arquivo ${filePath} atualizado com sucesso.`;
|
|
69
129
|
} catch (err) {
|
|
70
130
|
return `Erro ao escrever arquivo: ${err.message}`;
|
|
71
131
|
}
|
|
@@ -83,8 +143,26 @@ export const tools = [
|
|
|
83
143
|
},
|
|
84
144
|
execute: async ({ command }) => {
|
|
85
145
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
146
|
+
console.log(`\n${chalk.yellow('⚠️ Comando proposto:')} ${chalk.bold(command)}`);
|
|
147
|
+
|
|
148
|
+
if (!editState.autoAccept) {
|
|
149
|
+
const { approve } = await inquirer.prompt([{
|
|
150
|
+
type: 'list',
|
|
151
|
+
name: 'approve',
|
|
152
|
+
message: 'Executar este comando?',
|
|
153
|
+
choices: [
|
|
154
|
+
{ name: '✅ Sim', value: 'yes' },
|
|
155
|
+
{ name: '❌ Não', value: 'no' },
|
|
156
|
+
{ name: '⚡ Sim para tudo (Auto-Accept)', value: 'all' }
|
|
157
|
+
]
|
|
158
|
+
}]);
|
|
159
|
+
|
|
160
|
+
if (approve === 'no') return "Comando rejeitado pelo usuário.";
|
|
161
|
+
if (approve === 'all') editState.autoAccept = true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const output = execSync(command, { encoding: 'utf-8', timeout: 60000 });
|
|
165
|
+
return output || 'Comando executado com sucesso (sem retorno).';
|
|
88
166
|
} catch (err) {
|
|
89
167
|
return `Erro ao executar comando: ${err.stderr || err.message}`;
|
|
90
168
|
}
|
|
@@ -97,7 +175,6 @@ export async function handleToolCalls(toolCalls) {
|
|
|
97
175
|
for (const call of toolCalls) {
|
|
98
176
|
const tool = tools.find(t => t.name === call.name);
|
|
99
177
|
if (tool) {
|
|
100
|
-
console.log(`\n ${tool.name === 'search_internet' ? '🌐' : '🛠️'} Executando: ${tool.name}...`);
|
|
101
178
|
const result = await tool.execute(call.args);
|
|
102
179
|
results.push({
|
|
103
180
|
callId: call.id,
|
package/src/interface.js
CHANGED
|
@@ -13,6 +13,7 @@ import { getConfig, configure, updateActiveModel, switchProfile } from './config
|
|
|
13
13
|
import { createProvider } from './providers/factory.js';
|
|
14
14
|
import { getProjectContext } from './project-context.js';
|
|
15
15
|
import { SwarmOrchestrator } from './orchestrator.js';
|
|
16
|
+
import { editState } from './agent.js';
|
|
16
17
|
|
|
17
18
|
marked.use(new TerminalRenderer({
|
|
18
19
|
heading: chalk.hex('#c084fc').bold,
|
|
@@ -25,7 +26,10 @@ const gray = chalk.gray;
|
|
|
25
26
|
const bold = chalk.bold;
|
|
26
27
|
const yellow = chalk.yellow;
|
|
27
28
|
|
|
28
|
-
let currentMode = 'chat';
|
|
29
|
+
let currentMode = 'chat';
|
|
30
|
+
let activePersona = null;
|
|
31
|
+
let exitCounter = 0;
|
|
32
|
+
let exitTimer = null;
|
|
29
33
|
|
|
30
34
|
async function processInput(input) {
|
|
31
35
|
const parts = input.split(' ');
|
|
@@ -93,10 +97,13 @@ async function processInput(input) {
|
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
function getModeStyle() {
|
|
100
|
+
const personaLabel = activePersona ? `[${activePersona.toUpperCase()}] ` : '';
|
|
96
101
|
switch (currentMode) {
|
|
97
|
-
case 'plan': return yellow.bold(
|
|
98
|
-
case 'edit':
|
|
99
|
-
|
|
102
|
+
case 'plan': return yellow.bold(`${personaLabel}[PLAN] `);
|
|
103
|
+
case 'edit':
|
|
104
|
+
const editSubMode = editState.autoAccept ? '(AUTO)' : '(MANUAL)';
|
|
105
|
+
return chalk.red.bold(`${personaLabel}[EDIT${editSubMode}] `);
|
|
106
|
+
default: return lavender.bold(`${personaLabel}[CHAT] `);
|
|
100
107
|
}
|
|
101
108
|
}
|
|
102
109
|
|
|
@@ -112,37 +119,64 @@ export async function startInteractive() {
|
|
|
112
119
|
|
|
113
120
|
let provider = createProvider(config);
|
|
114
121
|
const orchestrator = new SwarmOrchestrator(config);
|
|
115
|
-
|
|
122
|
+
let messages = [];
|
|
123
|
+
|
|
124
|
+
const resetMessages = () => {
|
|
125
|
+
messages = [];
|
|
126
|
+
const projectContext = getProjectContext();
|
|
127
|
+
messages.push({ role: 'system', content: projectContext });
|
|
128
|
+
if (activePersona) {
|
|
129
|
+
const agent = (config.agents || {})[activePersona];
|
|
130
|
+
if (agent) {
|
|
131
|
+
messages.push({ role: 'system', content: `Sua persona atual é: ${agent.name}. Sua tarefa: ${agent.role}` });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
116
135
|
|
|
117
|
-
|
|
118
|
-
messages.push({
|
|
119
|
-
role: 'system',
|
|
120
|
-
content: projectContext
|
|
121
|
-
});
|
|
136
|
+
resetMessages();
|
|
122
137
|
|
|
123
138
|
console.clear();
|
|
124
139
|
console.log(lavender(figlet.textSync('bimmo')));
|
|
125
140
|
console.log(lavender('─'.repeat(60)));
|
|
126
|
-
console.log(green(` Perfil
|
|
141
|
+
console.log(green(` Perfil: ${bold(config.activeProfile || 'Padrão')} • IA: ${bold(config.provider.toUpperCase())}`));
|
|
127
142
|
console.log(green(` Modelo: ${bold(config.model)}`));
|
|
128
|
-
console.log(gray(' /chat | /plan | /edit | /swarm | /
|
|
143
|
+
console.log(gray(' /chat | /plan | /edit | /swarm | /use [agente] | /help'));
|
|
129
144
|
console.log(lavender('─'.repeat(60)) + '\n');
|
|
130
145
|
|
|
131
|
-
console.log(lavender('👋 Olá!
|
|
146
|
+
console.log(lavender('👋 Olá! Estou pronto. No que posso ajudar?\n'));
|
|
147
|
+
|
|
148
|
+
process.on('SIGINT', () => {
|
|
149
|
+
exitCounter++;
|
|
150
|
+
if (exitCounter === 1) {
|
|
151
|
+
console.log(gray('\n(Pressione Ctrl+C novamente para sair)'));
|
|
152
|
+
if (exitTimer) clearTimeout(exitTimer);
|
|
153
|
+
exitTimer = setTimeout(() => { exitCounter = 0; }, 2000);
|
|
154
|
+
} else {
|
|
155
|
+
console.log(lavender('\n👋 BIMMO encerrando sessão. Até logo!\n'));
|
|
156
|
+
process.exit(0);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
132
159
|
|
|
133
160
|
readline.emitKeypressEvents(process.stdin);
|
|
134
161
|
if (process.stdin.isTTY) process.stdin.setRawMode(true);
|
|
135
162
|
|
|
136
163
|
while (true) {
|
|
137
164
|
const modeIndicator = getModeStyle();
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
165
|
+
let input;
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const answers = await inquirer.prompt([
|
|
169
|
+
{
|
|
170
|
+
type: 'input',
|
|
171
|
+
name: 'input',
|
|
172
|
+
message: modeIndicator + green('Você'),
|
|
173
|
+
prefix: '→',
|
|
174
|
+
}
|
|
175
|
+
]);
|
|
176
|
+
input = answers.input;
|
|
177
|
+
} catch (e) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
146
180
|
|
|
147
181
|
const rawInput = input.trim();
|
|
148
182
|
const cmd = rawInput.toLowerCase();
|
|
@@ -154,35 +188,65 @@ export async function startInteractive() {
|
|
|
154
188
|
|
|
155
189
|
if (cmd === '/chat') { currentMode = 'chat'; console.log(lavender('✓ Modo CHAT.\n')); continue; }
|
|
156
190
|
if (cmd === '/plan') { currentMode = 'plan'; console.log(yellow('✓ Modo PLAN.\n')); continue; }
|
|
157
|
-
|
|
191
|
+
|
|
192
|
+
if (cmd === '/edit') {
|
|
193
|
+
currentMode = 'edit';
|
|
194
|
+
console.log(chalk.red(`⚠️ Modo EDIT ativado (Sub-modo atual: ${editState.autoAccept ? 'AUTO' : 'MANUAL'}).\n`));
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (cmd === '/edit auto') {
|
|
198
|
+
currentMode = 'edit';
|
|
199
|
+
editState.autoAccept = true;
|
|
200
|
+
console.log(chalk.red('⚠️ Modo EDIT (AUTO) ativado. Mudanças serão aplicadas sem perguntar.\n'));
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (cmd === '/edit manual') {
|
|
204
|
+
currentMode = 'edit';
|
|
205
|
+
editState.autoAccept = false;
|
|
206
|
+
console.log(chalk.red('⚠️ Modo EDIT (MANUAL) ativado. Pedirei permissão para cada mudança.\n'));
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
158
209
|
|
|
159
210
|
if (cmd.startsWith('/switch ')) {
|
|
160
211
|
const profileName = rawInput.split(' ')[1];
|
|
161
212
|
if (profileName && switchProfile(profileName)) {
|
|
162
213
|
config = getConfig();
|
|
163
214
|
provider = createProvider(config);
|
|
164
|
-
console.log(green(`\n✓
|
|
165
|
-
|
|
166
|
-
} else {
|
|
167
|
-
console.log(chalk.red(`\n✖ Perfil "${profileName}" não encontrado.\n`));
|
|
215
|
+
console.log(green(`\n✓ Perfil "${bold(profileName)}" ativado!`));
|
|
216
|
+
continue;
|
|
168
217
|
}
|
|
218
|
+
console.log(chalk.red(`\n✖ Perfil não encontrado.\n`));
|
|
169
219
|
continue;
|
|
170
220
|
}
|
|
171
221
|
|
|
172
|
-
if (cmd.startsWith('/
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
222
|
+
if (cmd.startsWith('/use ')) {
|
|
223
|
+
const agentName = rawInput.split(' ')[1];
|
|
224
|
+
const agents = config.agents || {};
|
|
225
|
+
if (agentName === 'normal' || agentName === 'default') {
|
|
226
|
+
activePersona = null;
|
|
227
|
+
console.log(lavender(`\n✓ Voltando para o Modo Normal.\n`));
|
|
228
|
+
resetMessages();
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (agents[agentName]) {
|
|
232
|
+
activePersona = agentName;
|
|
233
|
+
const agent = agents[agentName];
|
|
234
|
+
if (switchProfile(agent.profile)) {
|
|
235
|
+
config = getConfig();
|
|
236
|
+
provider = createProvider(config);
|
|
237
|
+
}
|
|
238
|
+
currentMode = agent.mode || 'chat';
|
|
239
|
+
console.log(green(`\n✓ Agora você está falando com o Agente: ${bold(agentName)}`));
|
|
240
|
+
console.log(gray(` Task: ${agent.role.substring(0, 100)}...\n`));
|
|
241
|
+
resetMessages();
|
|
242
|
+
} else {
|
|
243
|
+
console.log(chalk.red(`\n✖ Agente "${agentName}" não encontrado.\n`));
|
|
179
244
|
}
|
|
180
245
|
continue;
|
|
181
246
|
}
|
|
182
247
|
|
|
183
248
|
if (cmd === '/clear') {
|
|
184
|
-
|
|
185
|
-
messages.push({ role: 'system', content: getProjectContext() });
|
|
249
|
+
resetMessages();
|
|
186
250
|
console.clear();
|
|
187
251
|
console.log(lavender('✓ Histórico limpo, contexto preservado.\n'));
|
|
188
252
|
continue;
|
|
@@ -190,73 +254,79 @@ export async function startInteractive() {
|
|
|
190
254
|
|
|
191
255
|
if (cmd === '/help') {
|
|
192
256
|
console.log(gray(`
|
|
193
|
-
Comandos
|
|
194
|
-
/chat
|
|
195
|
-
/
|
|
196
|
-
/
|
|
197
|
-
/
|
|
198
|
-
/
|
|
257
|
+
Comandos de Modo:
|
|
258
|
+
/chat → Modo conversa
|
|
259
|
+
/plan → Modo planejamento
|
|
260
|
+
/edit [auto/manual] → Modo edição (padrão manual)
|
|
261
|
+
/use [agente] → Usar um Agente Especialista
|
|
262
|
+
/use normal → Voltar para o chat normal
|
|
263
|
+
/swarm → Rodar fluxos complexos
|
|
264
|
+
|
|
265
|
+
Gerenciamento:
|
|
266
|
+
/switch [nome] → Mudar perfil de IA completo
|
|
267
|
+
/model [nome] → Mudar modelo atual
|
|
268
|
+
/config → Perfis e Agentes
|
|
199
269
|
/init → Inicializar .bimmorc.json
|
|
200
|
-
@
|
|
270
|
+
@arquivo → Ler arquivo ou imagem
|
|
201
271
|
`));
|
|
202
272
|
continue;
|
|
203
273
|
}
|
|
204
274
|
|
|
205
275
|
if (cmd === '/config') { await configure(); config = getConfig(); provider = createProvider(config); continue; }
|
|
206
276
|
|
|
277
|
+
if (cmd === '/init') {
|
|
278
|
+
const bimmoRcPath = path.join(process.cwd(), '.bimmorc.json');
|
|
279
|
+
if (fs.existsSync(bimmoRcPath)) {
|
|
280
|
+
const { overwrite } = await inquirer.prompt([{
|
|
281
|
+
type: 'confirm',
|
|
282
|
+
name: 'overwrite',
|
|
283
|
+
message: 'O arquivo .bimmorc.json já existe. Deseja sobrescrever?',
|
|
284
|
+
default: false
|
|
285
|
+
}]);
|
|
286
|
+
if (!overwrite) continue;
|
|
287
|
+
}
|
|
288
|
+
const initialConfig = {
|
|
289
|
+
projectName: path.basename(process.cwd()),
|
|
290
|
+
rules: ["Siga as convenções existentes.", "Prefira código modular."],
|
|
291
|
+
preferredTech: [],
|
|
292
|
+
ignorePatterns: ["node_modules", ".git"]
|
|
293
|
+
};
|
|
294
|
+
fs.writeFileSync(bimmoRcPath, JSON.stringify(initialConfig, null, 2));
|
|
295
|
+
console.log(green(`\n✅ .bimmorc.json criado com sucesso.\n`));
|
|
296
|
+
|
|
297
|
+
resetMessages();
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
|
|
207
301
|
if (cmd === '/swarm') {
|
|
208
302
|
const agents = config.agents || {};
|
|
209
303
|
const agentList = Object.keys(agents);
|
|
210
|
-
|
|
211
304
|
if (agentList.length < 2) {
|
|
212
|
-
console.log(chalk.yellow('\
|
|
305
|
+
console.log(chalk.yellow('\nCrie pelo menos 2 Agentes em /config primeiro.\n'));
|
|
213
306
|
continue;
|
|
214
307
|
}
|
|
215
|
-
|
|
216
308
|
const { swarmAction } = await inquirer.prompt([{
|
|
217
309
|
type: 'list',
|
|
218
310
|
name: 'swarmAction',
|
|
219
|
-
message: '
|
|
220
|
-
choices: ['
|
|
311
|
+
message: 'Tipo de Enxame:',
|
|
312
|
+
choices: ['Sequencial (A → B)', 'Hierárquico (Líder + Workers)', 'Voltar']
|
|
221
313
|
}]);
|
|
222
|
-
|
|
223
314
|
if (swarmAction === 'Voltar') continue;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
type: 'checkbox',
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
choices: agentList
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (selectedAgents.length < 2) {
|
|
236
|
-
console.log(chalk.red('\nSelecione pelo menos 2 agentes.\n'));
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
try {
|
|
241
|
-
const finalResult = await orchestrator.runSequential(selectedAgents, goal);
|
|
242
|
-
console.log(lavender('\n=== RESULTADO FINAL DO ENXAME ===\n'));
|
|
243
|
-
console.log(marked(finalResult));
|
|
244
|
-
} catch (e) {
|
|
245
|
-
console.error(chalk.red(`\nErro no Enxame: ${e.message}`));
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (swarmAction === 'Rodar Enxame Hierárquico') {
|
|
250
|
-
const { manager } = await inquirer.prompt([{ type: 'list', name: 'manager', message: 'Selecione o Agente Líder (Manager):', choices: agentList }]);
|
|
251
|
-
const { workers } = await inquirer.prompt([{ type: 'checkbox', name: 'workers', message: 'Selecione os Workers:', choices: agentList.filter(a => a !== manager) }]);
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
const finalResult = await orchestrator.runHierarchical(manager, workers, goal);
|
|
255
|
-
console.log(lavender('\n=== RESULTADO FINAL DO ENXAME ===\n'));
|
|
256
|
-
console.log(marked(finalResult));
|
|
257
|
-
} catch (e) {
|
|
258
|
-
console.error(chalk.red(`\nErro no Enxame: ${e.message}`));
|
|
315
|
+
const { goal } = await inquirer.prompt([{ type: 'input', name: 'goal', message: 'Objetivo do enxame:' }]);
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
let result;
|
|
319
|
+
if (swarmAction.includes('Sequencial')) {
|
|
320
|
+
const { selectedAgents } = await inquirer.prompt([{ type: 'checkbox', name: 'selectedAgents', message: 'Ordem dos agentes:', choices: agentList }]);
|
|
321
|
+
result = await orchestrator.runSequential(selectedAgents, goal);
|
|
322
|
+
} else {
|
|
323
|
+
const { manager } = await inquirer.prompt([{ type: 'list', name: 'manager', message: 'Líder:', choices: agentList }]);
|
|
324
|
+
const { workers } = await inquirer.prompt([{ type: 'checkbox', name: 'workers', message: 'Workers:', choices: agentList.filter(a => a !== manager) }]);
|
|
325
|
+
result = await orchestrator.runHierarchical(manager, workers, goal);
|
|
259
326
|
}
|
|
327
|
+
console.log(lavender('\n=== RESULTADO FINAL ===\n') + marked(result));
|
|
328
|
+
} catch (e) {
|
|
329
|
+
console.error(chalk.red(`\nErro: ${e.message}`));
|
|
260
330
|
}
|
|
261
331
|
continue;
|
|
262
332
|
}
|
|
@@ -264,14 +334,13 @@ Comandos Disponíveis:
|
|
|
264
334
|
if (rawInput === '') continue;
|
|
265
335
|
|
|
266
336
|
const controller = new AbortController();
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
process.on('SIGINT',
|
|
270
|
-
process.stdin.on('keypress', keypressHandler);
|
|
337
|
+
const localInterruptHandler = () => controller.abort();
|
|
338
|
+
process.removeAllListeners('SIGINT');
|
|
339
|
+
process.on('SIGINT', localInterruptHandler);
|
|
271
340
|
|
|
272
341
|
let modeInstr = "";
|
|
273
|
-
if (currentMode === 'plan') modeInstr = "\n[MODO PLAN]
|
|
274
|
-
else if (currentMode === 'edit') modeInstr =
|
|
342
|
+
if (currentMode === 'plan') modeInstr = "\n[MODO PLAN] Apenas analise.";
|
|
343
|
+
else if (currentMode === 'edit') modeInstr = `\n[MODO EDIT] Você tem permissão para usar ferramentas. (Auto-Accept: ${editState.autoAccept ? 'ON' : 'OFF'})`;
|
|
275
344
|
|
|
276
345
|
const content = await processInput(rawInput);
|
|
277
346
|
messages.push({
|
|
@@ -280,7 +349,7 @@ Comandos Disponíveis:
|
|
|
280
349
|
});
|
|
281
350
|
|
|
282
351
|
const spinner = ora({
|
|
283
|
-
text: lavender(`bimmo
|
|
352
|
+
text: lavender(`bimmo pensando... (Ctrl+C para interromper)`),
|
|
284
353
|
color: currentMode === 'edit' ? 'red' : 'magenta'
|
|
285
354
|
}).start();
|
|
286
355
|
|
|
@@ -296,14 +365,24 @@ Comandos Disponíveis:
|
|
|
296
365
|
} catch (err) {
|
|
297
366
|
spinner.stop();
|
|
298
367
|
if (controller.signal.aborted || err.name === 'AbortError') {
|
|
299
|
-
console.log(yellow('\n\n⚠️
|
|
368
|
+
console.log(yellow('\n\n⚠️ Interrompido.\n'));
|
|
300
369
|
messages.pop();
|
|
301
370
|
} else {
|
|
302
|
-
console.error(chalk.red('\n✖ Erro
|
|
371
|
+
console.error(chalk.red('\n✖ Erro:') + ' ' + err.message + '\n');
|
|
303
372
|
}
|
|
304
373
|
} finally {
|
|
305
|
-
process.
|
|
306
|
-
process.
|
|
374
|
+
process.removeListener('SIGINT', localInterruptHandler);
|
|
375
|
+
process.on('SIGINT', () => {
|
|
376
|
+
exitCounter++;
|
|
377
|
+
if (exitCounter === 1) {
|
|
378
|
+
console.log(gray('\n(Pressione Ctrl+C novamente para sair)'));
|
|
379
|
+
if (exitTimer) clearTimeout(exitTimer);
|
|
380
|
+
exitTimer = setTimeout(() => { exitCounter = 0; }, 2000);
|
|
381
|
+
} else {
|
|
382
|
+
console.log(lavender('\n👋 BIMMO encerrando sessão. Até logo!\n'));
|
|
383
|
+
process.exit(0);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
307
386
|
}
|
|
308
387
|
}
|
|
309
|
-
}
|
|
388
|
+
}
|
package/src/providers/grok.js
CHANGED
|
@@ -13,24 +13,23 @@ export class GrokProvider extends BaseProvider {
|
|
|
13
13
|
|
|
14
14
|
formatMessages(messages) {
|
|
15
15
|
return messages.map(msg => {
|
|
16
|
-
if (typeof msg.content === 'string') {
|
|
16
|
+
if (typeof msg.content === 'string' || msg.content === null) {
|
|
17
17
|
return msg;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return { type: 'text', text: part.text };
|
|
23
|
-
|
|
24
|
-
return {
|
|
20
|
+
if (Array.isArray(msg.content)) {
|
|
21
|
+
const content = msg.content.map(part => {
|
|
22
|
+
if (part.type === 'text') return { type: 'text', text: part.text };
|
|
23
|
+
if (part.type === 'image') return {
|
|
25
24
|
type: 'image_url',
|
|
26
|
-
image_url: {
|
|
27
|
-
url: `data:${part.mimeType};base64,${part.data}`
|
|
28
|
-
}
|
|
25
|
+
image_url: { url: `data:${part.mimeType};base64,${part.data}` }
|
|
29
26
|
};
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
return part;
|
|
28
|
+
});
|
|
29
|
+
return { ...msg, content };
|
|
30
|
+
}
|
|
32
31
|
|
|
33
|
-
return
|
|
32
|
+
return msg;
|
|
34
33
|
});
|
|
35
34
|
}
|
|
36
35
|
|
package/src/providers/openai.js
CHANGED
|
@@ -21,16 +21,25 @@ export class OpenAIProvider extends BaseProvider {
|
|
|
21
21
|
|
|
22
22
|
formatMessages(messages) {
|
|
23
23
|
return messages.map(msg => {
|
|
24
|
-
|
|
24
|
+
// Se content for string ou null (comum em tool calls), retorna como está
|
|
25
|
+
if (typeof msg.content === 'string' || msg.content === null) {
|
|
26
|
+
return msg;
|
|
27
|
+
}
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
type: '
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
// Se for um array (multimodal), processa as partes
|
|
30
|
+
if (Array.isArray(msg.content)) {
|
|
31
|
+
const content = msg.content.map(part => {
|
|
32
|
+
if (part.type === 'text') return { type: 'text', text: part.text };
|
|
33
|
+
if (part.type === 'image') return {
|
|
34
|
+
type: 'image_url',
|
|
35
|
+
image_url: { url: `data:${part.mimeType};base64,${part.data}` }
|
|
36
|
+
};
|
|
37
|
+
return part; // Mantém outras partes (como tool_result se houver)
|
|
38
|
+
});
|
|
39
|
+
return { ...msg, content };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return msg;
|
|
34
43
|
});
|
|
35
44
|
}
|
|
36
45
|
|