expxagents 0.17.5 → 0.17.6
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.
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import { spawn } from 'child_process';
|
|
4
3
|
import * as readline from 'readline';
|
|
5
4
|
import yaml from 'js-yaml';
|
|
6
5
|
// Walk squadsDir recursively, return all squad summaries
|
|
@@ -51,56 +50,100 @@ function discoverAllSquads(squadsDir) {
|
|
|
51
50
|
walk(squadsDir);
|
|
52
51
|
return result;
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const squadList = squads
|
|
53
|
+
function buildClassificationPrompt(squads) {
|
|
54
|
+
const list = squads
|
|
57
55
|
.map((s) => `- code: ${s.code}, name: "${s.name}", description: "${s.description}"`)
|
|
58
56
|
.join('\n');
|
|
59
|
-
|
|
57
|
+
return `Você é um classificador de squads de IA para uma software house.
|
|
60
58
|
Para cada squad abaixo, identifique o Setor, Grupo e Sessão mais adequados.
|
|
61
59
|
|
|
62
|
-
Setores comuns: marketing, comercial, desenvolvimento, suporte, financeiro, rh,
|
|
60
|
+
Setores comuns: marketing, comercial, desenvolvimento, suporte, financeiro, rh, operacoes, estrategia, design, juridico, administrativo
|
|
63
61
|
|
|
64
62
|
Retorne APENAS um JSON válido (sem markdown, sem explicações), no seguinte formato:
|
|
65
|
-
[
|
|
66
|
-
{
|
|
67
|
-
"code": "<squad-code>",
|
|
68
|
-
"setor": "<setor-em-lowercase-sem-acentos>",
|
|
69
|
-
"grupo": "<grupo-em-lowercase-sem-acentos>",
|
|
70
|
-
"sessao": "<sessao-em-lowercase-sem-acentos>",
|
|
71
|
-
"confidence": "high"
|
|
72
|
-
}
|
|
73
|
-
]
|
|
63
|
+
[{"code":"<squad-code>","setor":"<setor>","grupo":"<grupo>","sessao":"<sessao>","confidence":"high"}]
|
|
74
64
|
|
|
75
|
-
Use "confidence":
|
|
76
|
-
Use hifens em vez de espaços (ex: "redes-sociais"
|
|
65
|
+
Use "confidence":"low" quando não tiver certeza.
|
|
66
|
+
Use hifens em vez de espaços (ex: "redes-sociais").
|
|
77
67
|
|
|
78
|
-
Squads
|
|
79
|
-
${
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
try {
|
|
91
|
-
// Extract JSON from output (Claude may include reasoning text)
|
|
92
|
-
const jsonMatch = output.match(/\[[\s\S]*\]/);
|
|
93
|
-
if (!jsonMatch) {
|
|
94
|
-
reject(new Error('No JSON array found in Claude output'));
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
resolve(JSON.parse(jsonMatch[0]));
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
reject(new Error(`Failed to parse Claude output: ${err.message}`));
|
|
101
|
-
}
|
|
102
|
-
});
|
|
68
|
+
Squads:
|
|
69
|
+
${list}`;
|
|
70
|
+
}
|
|
71
|
+
// Call Anthropic API directly — fast, no interactive session needed
|
|
72
|
+
async function inferBatchWithApi(squads) {
|
|
73
|
+
const { default: Anthropic } = await import('@anthropic-ai/sdk');
|
|
74
|
+
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
75
|
+
const response = await client.messages.create({
|
|
76
|
+
model: 'claude-haiku-4-5-20251001',
|
|
77
|
+
max_tokens: 2048,
|
|
78
|
+
messages: [{ role: 'user', content: buildClassificationPrompt(squads) }],
|
|
103
79
|
});
|
|
80
|
+
const text = response.content
|
|
81
|
+
.map((b) => (b.type === 'text' ? b.text : ''))
|
|
82
|
+
.join('');
|
|
83
|
+
const jsonMatch = text.match(/\[[\s\S]*\]/);
|
|
84
|
+
if (!jsonMatch)
|
|
85
|
+
throw new Error('No JSON array in API response');
|
|
86
|
+
return JSON.parse(jsonMatch[0]);
|
|
87
|
+
}
|
|
88
|
+
// Heuristic fallback — keyword-based, no AI required
|
|
89
|
+
function inferHeuristic(squad) {
|
|
90
|
+
const text = `${squad.code} ${squad.name} ${squad.description}`.toLowerCase();
|
|
91
|
+
const RULES = [
|
|
92
|
+
{ setor: 'marketing', grupo: 'redes-sociais', sessao: 'instagram', keywords: ['instagram', 'reels', 'stories'] },
|
|
93
|
+
{ setor: 'marketing', grupo: 'redes-sociais', sessao: 'linkedin', keywords: ['linkedin'] },
|
|
94
|
+
{ setor: 'marketing', grupo: 'redes-sociais', sessao: 'twitter', keywords: ['twitter', 'x.com', 'tweet'] },
|
|
95
|
+
{ setor: 'marketing', grupo: 'conteudo', sessao: 'blog', keywords: ['blog', 'artigo', 'post'] },
|
|
96
|
+
{ setor: 'marketing', grupo: 'email', sessao: 'campanhas', keywords: ['email', 'newsletter', 'campanha'] },
|
|
97
|
+
{ setor: 'marketing', grupo: 'ads', sessao: 'google', keywords: ['google ads', 'adwords', 'sem'] },
|
|
98
|
+
{ setor: 'marketing', grupo: 'ads', sessao: 'meta', keywords: ['meta ads', 'facebook ads'] },
|
|
99
|
+
{ setor: 'comercial', grupo: 'vendas', sessao: 'prospecao', keywords: ['sdr', 'prospeccao', 'leads', 'prospect'] },
|
|
100
|
+
{ setor: 'comercial', grupo: 'vendas', sessao: 'proposta', keywords: ['proposta', 'cotacao', 'orcamento'] },
|
|
101
|
+
{ setor: 'comercial', grupo: 'crm', sessao: 'gestao', keywords: ['crm', 'pipeline', 'funil'] },
|
|
102
|
+
{ setor: 'desenvolvimento', grupo: 'produto', sessao: 'frontend', keywords: ['frontend', 'react', 'vue', 'angular', 'ui'] },
|
|
103
|
+
{ setor: 'desenvolvimento', grupo: 'produto', sessao: 'backend', keywords: ['backend', 'api', 'server', 'banco de dados'] },
|
|
104
|
+
{ setor: 'desenvolvimento', grupo: 'produto', sessao: 'devops', keywords: ['devops', 'ci/cd', 'deploy', 'docker', 'kubernetes'] },
|
|
105
|
+
{ setor: 'desenvolvimento', grupo: 'qualidade', sessao: 'qa', keywords: ['qa', 'teste', 'qualidade', 'bug'] },
|
|
106
|
+
{ setor: 'suporte', grupo: 'atendimento', sessao: 'l1', keywords: ['suporte', 'atendimento', 'helpdesk', 'l1', 'l2'] },
|
|
107
|
+
{ setor: 'rh', grupo: 'recrutamento', sessao: 'selecao', keywords: ['recrutamento', 'selecao', 'entrevista', 'vaga'] },
|
|
108
|
+
{ setor: 'rh', grupo: 'pessoas', sessao: 'cultura', keywords: ['cultura', 'onboarding', 'treinamento', 'clima'] },
|
|
109
|
+
{ setor: 'financeiro', grupo: 'contabilidade', sessao: 'fiscal', keywords: ['financeiro', 'contabil', 'fiscal', 'nfe', 'fatura'] },
|
|
110
|
+
{ setor: 'juridico', grupo: 'contratos', sessao: 'analise', keywords: ['juridico', 'contrato', 'legal', 'compliance'] },
|
|
111
|
+
{ setor: 'design', grupo: 'visual', sessao: 'identidade', keywords: ['design', 'branding', 'identidade', 'logo', 'marca'] },
|
|
112
|
+
{ setor: 'estrategia', grupo: 'planejamento', sessao: 'okr', keywords: ['estrategia', 'okr', 'planejamento', 'kpi', 'meta'] },
|
|
113
|
+
{ setor: 'operacoes', grupo: 'processos', sessao: 'gestao', keywords: ['operacoes', 'processo', 'workflow', 'automacao'] },
|
|
114
|
+
];
|
|
115
|
+
for (const rule of RULES) {
|
|
116
|
+
if (rule.keywords.some((kw) => text.includes(kw))) {
|
|
117
|
+
return { code: squad.code, setor: rule.setor, grupo: rule.grupo, sessao: rule.sessao, confidence: 'low' };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { code: squad.code, setor: 'geral', grupo: 'squads', sessao: 'default', confidence: 'low' };
|
|
121
|
+
}
|
|
122
|
+
// Classify all squads: try Anthropic API in batches, fall back to heuristic
|
|
123
|
+
async function inferHierarchyWithClaude(squads) {
|
|
124
|
+
const hasApiKey = !!process.env.ANTHROPIC_API_KEY;
|
|
125
|
+
if (!hasApiKey) {
|
|
126
|
+
console.log(' ANTHROPIC_API_KEY não definida — usando classificação heurística.\n');
|
|
127
|
+
return squads.map(inferHeuristic);
|
|
128
|
+
}
|
|
129
|
+
const BATCH_SIZE = 10;
|
|
130
|
+
const results = [];
|
|
131
|
+
const batches = Math.ceil(squads.length / BATCH_SIZE);
|
|
132
|
+
for (let i = 0; i < squads.length; i += BATCH_SIZE) {
|
|
133
|
+
const batch = squads.slice(i, i + BATCH_SIZE);
|
|
134
|
+
const batchNum = Math.floor(i / BATCH_SIZE) + 1;
|
|
135
|
+
process.stdout.write(` Classificando batch ${batchNum}/${batches} (${batch.length} squads)...`);
|
|
136
|
+
try {
|
|
137
|
+
const batchResults = await inferBatchWithApi(batch);
|
|
138
|
+
results.push(...batchResults);
|
|
139
|
+
process.stdout.write(' ✓\n');
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
process.stdout.write(` falhou (${err.message}) — usando heurística para este batch.\n`);
|
|
143
|
+
results.push(...batch.map(inferHeuristic));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return results;
|
|
104
147
|
}
|
|
105
148
|
function ask(rl, question) {
|
|
106
149
|
return new Promise((resolve) => rl.question(question, resolve));
|