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
- // Call Claude to infer hierarchy for a list of squads
55
- async function inferHierarchyWithClaude(squads) {
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
- const prompt = `Você é um classificador de squads de IA para uma software house.
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, operações, estrategia, design, juridico, administrativo
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": "low" quando não tiver certeza da classificação.
76
- Use hifens em vez de espaços (ex: "redes-sociais", não "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 para classificar:
79
- ${squadList}`;
80
- return new Promise((resolve, reject) => {
81
- let output = '';
82
- const child = spawn('claude', ['-p', prompt], { stdio: ['pipe', 'pipe', 'pipe'] });
83
- child.stdout?.on('data', (d) => { output += d.toString(); });
84
- child.on('error', reject);
85
- child.on('exit', (code) => {
86
- if (code !== 0) {
87
- reject(new Error(`Claude exited with code ${code}`));
88
- return;
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));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expxagents",
3
- "version": "0.17.5",
3
+ "version": "0.17.6",
4
4
  "description": "Multi-agent orchestration platform for AI squads",
5
5
  "author": "ExpxAgents",
6
6
  "license": "MIT",