bcb-br-mcp 1.3.4 → 1.4.1
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/README.md +60 -4
- package/dist/cambio.d.ts +72 -0
- package/dist/cambio.d.ts.map +1 -0
- package/dist/cambio.js +284 -0
- package/dist/cambio.js.map +1 -0
- package/dist/catalog.d.ts +107 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +206 -0
- package/dist/catalog.js.map +1 -0
- package/dist/focus.d.ts +134 -0
- package/dist/focus.d.ts.map +1 -0
- package/dist/focus.js +683 -0
- package/dist/focus.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -346
- package/dist/index.js.map +1 -1
- package/dist/olinda.d.ts +59 -0
- package/dist/olinda.d.ts.map +1 -0
- package/dist/olinda.js +98 -0
- package/dist/olinda.js.map +1 -0
- package/dist/register.d.ts +61 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +116 -0
- package/dist/register.js.map +1 -0
- package/dist/shared.d.ts +89 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +151 -0
- package/dist/shared.js.map +1 -0
- package/dist/tools.d.ts +8128 -280
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +232 -153
- package/dist/tools.js.map +1 -1
- package/package.json +12 -11
- package/dist/worker.d.ts +0 -20
- package/dist/worker.d.ts.map +0 -1
- package/dist/worker.js +0 -240
- package/dist/worker.js.map +0 -1
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Índice de séries do Portal de Dados Abertos do BCB (CKAN) — busca real.
|
|
3
|
+
*
|
|
4
|
+
* Desenho fechado pelo decisor na fase bcb (arbitragem 5), e as restrições
|
|
5
|
+
* importam mais que o código:
|
|
6
|
+
*
|
|
7
|
+
* - Fonte é `package_list` do CKAN: UMA requisição (~310 KB) devolve o nome de
|
|
8
|
+
* todos os datasets do portal, e 3.555 deles são nomeados pelo próprio código
|
|
9
|
+
* da série (`{codigo}-{slug}`) — ~24× a cobertura do catálogo curado local.
|
|
10
|
+
* Nada de raspar o localizador JSP do SGS.
|
|
11
|
+
* - O catálogo é servido de cache com validade de 24 h e a renovação é
|
|
12
|
+
* BLOQUEANTE: quem faz a primeira busca depois do vencimento paga o ~0,8 s.
|
|
13
|
+
* Sem tarefa agendada e sem seed manual — se ninguém buscar, a origem não
|
|
14
|
+
* recebe requisição nenhuma. Descartado de propósito o
|
|
15
|
+
* stale-while-revalidate: com tráfego baixo ele entregaria retrato de semanas
|
|
16
|
+
* ao primeiro usuário para poupar 0,8 s de um único usuário por dia.
|
|
17
|
+
* - O cache guarda **só metadados** (código e slug), NUNCA observações. É por
|
|
18
|
+
* isso que ele não é a "base derivada" que a arbitragem 2 evitou: o servidor
|
|
19
|
+
* segue sendo *Produced Work* sob a ODbL, e valores de série continuam
|
|
20
|
+
* buscados ao vivo a cada pergunta.
|
|
21
|
+
* - `Disallow: /api/` + `Crawl-Delay: 10` no robots do portal do catálogo é o
|
|
22
|
+
* motivo de existir cache: ≤1 requisição por dia por instância, não uma por
|
|
23
|
+
* chamada.
|
|
24
|
+
*
|
|
25
|
+
* O cache é módulo-level, ou seja, por processo (stdio) e por isolate
|
|
26
|
+
* (Cloudflare). Isolate reciclado = catálogo buscado de novo; com o tráfego
|
|
27
|
+
* atual isso mantém a ordem de grandeza prometida (unidades de requisição por
|
|
28
|
+
* dia), e é a única forma de cache que não introduz armazenamento persistente.
|
|
29
|
+
*/
|
|
30
|
+
// Só primitivos: a curadoria de séries entra por parâmetro (e não por import de
|
|
31
|
+
// `tools.ts`) para a busca ser testável sem estado global e para não haver ciclo
|
|
32
|
+
// entre os módulos de tool.
|
|
33
|
+
import { fetchBcbApi, normalizeString } from "./shared.js";
|
|
34
|
+
export const CKAN_PACKAGE_LIST = "https://dadosabertos.bcb.gov.br/api/3/action/package_list";
|
|
35
|
+
export const CKAN_DATASET_BASE = "https://dadosabertos.bcb.gov.br/dataset";
|
|
36
|
+
/** Validade do catálogo em cache: 24 h (decisão do decisor). */
|
|
37
|
+
export const CATALOGO_TTL_MS = 24 * 60 * 60 * 1000;
|
|
38
|
+
let cache = null;
|
|
39
|
+
/** Renovação em voo: duas buscas simultâneas após o vencimento fazem 1 fetch. */
|
|
40
|
+
let renovacaoEmVoo = null;
|
|
41
|
+
/** Só para os testes: zera o cache do módulo. */
|
|
42
|
+
export function _resetCatalogo() {
|
|
43
|
+
cache = null;
|
|
44
|
+
renovacaoEmVoo = null;
|
|
45
|
+
}
|
|
46
|
+
/** Só para os testes: injeta um snapshot como se tivesse vindo da origem. */
|
|
47
|
+
export function _seedCatalogo(snapshot) {
|
|
48
|
+
cache = snapshot;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Conserta mojibake de ISO-8859-1 servido como UTF-8 ("Câmbio" -> "Câmbio").
|
|
52
|
+
* Os slugs do `package_list` são ASCII, então isto é defesa para os campos de
|
|
53
|
+
* texto do CKAN que já apareceram corrompidos na verificação de abertura.
|
|
54
|
+
*/
|
|
55
|
+
export function normalizarMojibake(texto) {
|
|
56
|
+
if (!/[ÃÂ][-¿]/.test(texto))
|
|
57
|
+
return texto;
|
|
58
|
+
try {
|
|
59
|
+
const bytes = Uint8Array.from(Array.from(texto, c => c.charCodeAt(0) & 0xff));
|
|
60
|
+
return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return texto;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Nome legível a partir do slug do dataset. O `package_list` devolve slug, não
|
|
68
|
+
* título: `---` é separador de campos e `-` separa palavras, e os acentos foram
|
|
69
|
+
* perdidos na origem — daí o nome reconstruído ser aproximado de propósito. Para
|
|
70
|
+
* as séries do catálogo curado o nome bom (com acento) prevalece; para as
|
|
71
|
+
* demais, quem quiser o nome oficial usa `bcb_serie_metadados`.
|
|
72
|
+
*/
|
|
73
|
+
export function nomeDoSlug(slug) {
|
|
74
|
+
const texto = normalizarMojibake(slug)
|
|
75
|
+
.replace(/^\d+-/, "") // o código já é campo próprio
|
|
76
|
+
.split(/-{2,}/) // `---` separa campos; um `-` só separa palavras
|
|
77
|
+
.map(parte => parte.replace(/-/g, " ").replace(/\s+/g, " ").trim())
|
|
78
|
+
.filter(Boolean)
|
|
79
|
+
.join(" - ");
|
|
80
|
+
return texto.charAt(0).toUpperCase() + texto.slice(1);
|
|
81
|
+
}
|
|
82
|
+
/** `1-taxa-de-cambio---livre---dolar-americano-venda---diario` -> {1, slug}. */
|
|
83
|
+
export function parsePackageList(nomes) {
|
|
84
|
+
if (!Array.isArray(nomes))
|
|
85
|
+
return { entradas: [], totalDatasets: 0 };
|
|
86
|
+
const entradas = [];
|
|
87
|
+
const vistos = new Set();
|
|
88
|
+
for (const bruto of nomes) {
|
|
89
|
+
if (typeof bruto !== "string")
|
|
90
|
+
continue;
|
|
91
|
+
const match = /^(\d+)-(.+)$/.exec(bruto);
|
|
92
|
+
if (!match)
|
|
93
|
+
continue;
|
|
94
|
+
const codigo = Number(match[1]);
|
|
95
|
+
if (!Number.isSafeInteger(codigo) || vistos.has(codigo))
|
|
96
|
+
continue;
|
|
97
|
+
vistos.add(codigo);
|
|
98
|
+
entradas.push({ codigo, slug: bruto });
|
|
99
|
+
}
|
|
100
|
+
entradas.sort((a, b) => a.codigo - b.codigo);
|
|
101
|
+
return { entradas, totalDatasets: nomes.length };
|
|
102
|
+
}
|
|
103
|
+
async function renovar(timeoutMs, maxRetries) {
|
|
104
|
+
const resposta = (await fetchBcbApi(CKAN_PACKAGE_LIST, timeoutMs, maxRetries));
|
|
105
|
+
if (!resposta || resposta.success === false || !Array.isArray(resposta.result)) {
|
|
106
|
+
throw new Error("Resposta inesperada do portal de dados abertos (package_list)");
|
|
107
|
+
}
|
|
108
|
+
const { entradas, totalDatasets } = parsePackageList(resposta.result);
|
|
109
|
+
if (entradas.length === 0)
|
|
110
|
+
throw new Error("Índice do portal veio sem nenhuma série identificável por código");
|
|
111
|
+
const agora = Date.now();
|
|
112
|
+
return {
|
|
113
|
+
entradas,
|
|
114
|
+
obtidoEm: new Date(agora).toISOString(),
|
|
115
|
+
totalDatasets,
|
|
116
|
+
expiraEm: agora + CATALOGO_TTL_MS
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Devolve o índice do portal, renovando de forma bloqueante quando vencido.
|
|
121
|
+
*
|
|
122
|
+
* Degradação: se a renovação falhar e houver retrato anterior, ele é servido
|
|
123
|
+
* COM aviso e com a data de obtenção visível — a API do BCB cai de verdade
|
|
124
|
+
* (ocorreu durante esta fase), e nesse caso é melhor um índice velho declarado
|
|
125
|
+
* do que busca nenhuma. Sem retrato anterior, devolve `snapshot: null` e quem
|
|
126
|
+
* chamou cai no catálogo curado.
|
|
127
|
+
*/
|
|
128
|
+
export async function obterCatalogo(timeoutMs, maxRetries) {
|
|
129
|
+
if (cache && Date.now() < cache.expiraEm)
|
|
130
|
+
return { snapshot: cache };
|
|
131
|
+
if (!renovacaoEmVoo) {
|
|
132
|
+
renovacaoEmVoo = renovar(timeoutMs, maxRetries)
|
|
133
|
+
.then(snapshot => {
|
|
134
|
+
cache = snapshot;
|
|
135
|
+
return snapshot;
|
|
136
|
+
})
|
|
137
|
+
.finally(() => {
|
|
138
|
+
renovacaoEmVoo = null;
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
return { snapshot: await renovacaoEmVoo };
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
const motivo = error instanceof Error ? error.message : String(error);
|
|
146
|
+
if (cache) {
|
|
147
|
+
return {
|
|
148
|
+
snapshot: cache,
|
|
149
|
+
aviso: `Índice do portal servido de cache VENCIDO (obtido em ${cache.obtidoEm}) — ` +
|
|
150
|
+
`a renovação falhou: ${motivo}`
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
snapshot: null,
|
|
155
|
+
aviso: `Índice do portal indisponível (${motivo}); a busca usou apenas o catálogo curado local.`
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function comoEncontrada(serie) {
|
|
160
|
+
return {
|
|
161
|
+
codigo: serie.codigo,
|
|
162
|
+
nome: serie.nome,
|
|
163
|
+
categoria: serie.categoria,
|
|
164
|
+
periodicidade: serie.periodicidade,
|
|
165
|
+
origem: "curado"
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function comoEncontradaDoIndice(entrada) {
|
|
169
|
+
return {
|
|
170
|
+
codigo: entrada.codigo,
|
|
171
|
+
nome: nomeDoSlug(entrada.slug),
|
|
172
|
+
origem: "indice",
|
|
173
|
+
dataset: `${CKAN_DATASET_BASE}/${entrada.slug}`
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Ranqueia os achados. O catálogo curado é a CAMADA DE DESTAQUE: quando uma
|
|
178
|
+
* série está nele, ela vem primeiro e com o nome bom, porque foi revisada à
|
|
179
|
+
* mão; o índice do portal entra depois, ordenado do slug mais curto (mais
|
|
180
|
+
* específico) para o mais longo, com desempate estável pelo código.
|
|
181
|
+
*/
|
|
182
|
+
export function buscarSeries(termo, curadoria, entradas, limite) {
|
|
183
|
+
const termoNorm = normalizeString(termo).trim();
|
|
184
|
+
const tokens = termoNorm.split(/\s+/).filter(Boolean);
|
|
185
|
+
// Busca por código: "433" deve achar a série 433, não as que contêm "433".
|
|
186
|
+
if (/^\d+$/.test(termoNorm)) {
|
|
187
|
+
const codigo = Number(termoNorm);
|
|
188
|
+
const curada = curadoria.find(s => s.codigo === codigo);
|
|
189
|
+
if (curada)
|
|
190
|
+
return { total: 1, series: [comoEncontrada(curada)] };
|
|
191
|
+
const doIndice = entradas?.find(e => e.codigo === codigo);
|
|
192
|
+
if (doIndice)
|
|
193
|
+
return { total: 1, series: [comoEncontradaDoIndice(doIndice)] };
|
|
194
|
+
return { total: 0, series: [] };
|
|
195
|
+
}
|
|
196
|
+
const casaTodosTokens = (texto) => tokens.every(t => texto.includes(t));
|
|
197
|
+
const curadas = curadoria.filter(s => casaTodosTokens(normalizeString(s.nome)) || casaTodosTokens(normalizeString(s.categoria)));
|
|
198
|
+
const codigosCurados = new Set(curadas.map(s => s.codigo));
|
|
199
|
+
const doIndice = (entradas ?? [])
|
|
200
|
+
.filter(e => !codigosCurados.has(e.codigo) && casaTodosTokens(normalizeString(e.slug)))
|
|
201
|
+
.sort((a, b) => a.slug.length - b.slug.length || a.codigo - b.codigo);
|
|
202
|
+
const total = curadas.length + doIndice.length;
|
|
203
|
+
const series = [...curadas.map(comoEncontrada), ...doIndice.map(comoEncontradaDoIndice)].slice(0, limite);
|
|
204
|
+
return { total, series };
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
|
package/dist/focus.d.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expectativas de Mercado (Focus) sob contrato consolidado.
|
|
3
|
+
*
|
|
4
|
+
* Desenho aprovado pelo decisor (arbitragem 3 + fronteira concreta da sessão de
|
|
5
|
+
* D3): NÃO espelhar os recursos OData. Três tools em vez de treze:
|
|
6
|
+
*
|
|
7
|
+
* - `bcb_focus_expectativas` — as cinco expectativas de calendário (mensal,
|
|
8
|
+
* trimestral, anual, inflação em 12 e em 24 meses) numa tool só, com
|
|
9
|
+
* `horizonte` como parâmetro. Os dois horizontes rolantes não têm data de
|
|
10
|
+
* referência (o alvo é "os próximos N meses", não um mês do calendário) e têm
|
|
11
|
+
* o campo `suavizada`, que os de calendário não têm: `referencia` é obrigatória
|
|
12
|
+
* nos três de calendário e recusada nos rolantes, com erro que diz o que usar.
|
|
13
|
+
* - `bcb_focus_selic` — separada porque o eixo temporal é a REUNIÃO do Copom, não
|
|
14
|
+
* o calendário. Consolidar aqui esconderia a diferença que importa.
|
|
15
|
+
* - `bcb_focus_referencias` — auxiliar de descoberta. Sem ela o agente adivinha
|
|
16
|
+
* strings de referência ("2026"? "12/2026"? "4/2026"?), que é o modo mais
|
|
17
|
+
* comum de a consulta voltar vazia.
|
|
18
|
+
*
|
|
19
|
+
* Top 5 é SINALIZADOR (`top5: true`), não tool espelhada — e não existe para
|
|
20
|
+
* toda combinação: a tabela de combinações válidas mora em `RECURSOS` e o erro
|
|
21
|
+
* diz qual usar.
|
|
22
|
+
*
|
|
23
|
+
* `ExpectativasMercadoInstituicoes` jamais entra (desativado pelo BCB por
|
|
24
|
+
* confidencialidade).
|
|
25
|
+
*/
|
|
26
|
+
import { type ToolDefinition, type ToolResult } from "./shared.js";
|
|
27
|
+
export type Horizonte = "mensal" | "trimestral" | "anual" | "inflacao_12m" | "inflacao_24m";
|
|
28
|
+
interface RecursoFocus {
|
|
29
|
+
/** Recurso OData das expectativas do consenso. */
|
|
30
|
+
consenso: string;
|
|
31
|
+
/** Recurso das expectativas do Top 5, quando existe para este horizonte. */
|
|
32
|
+
top5: string | null;
|
|
33
|
+
/** Nome do campo que carrega o alvo da expectativa. */
|
|
34
|
+
campoReferencia: string | null;
|
|
35
|
+
/** Formato da referência, para descrição e mensagem de erro. */
|
|
36
|
+
formatoReferencia: string | null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mapa horizonte -> recurso OData. É o ÚNICO lugar que conhece os nomes dos
|
|
40
|
+
* recursos: se a fonte renomear ou deixar de oferecer Top 5 em algum horizonte, a
|
|
41
|
+
* correção é uma linha aqui.
|
|
42
|
+
*
|
|
43
|
+
* Os nomes foram lidos do documento de serviço do OData contra a origem, não
|
|
44
|
+
* supostos. Repare na irregularidade da fonte, que é real e não erro de digitação:
|
|
45
|
+
* o mensal é `ExpectativaMercadoMensais` (singular) e o Top 5 trimestral é
|
|
46
|
+
* `ExpectativaMercadoTop5Trimestral` (singular nas duas pontas), enquanto todo o
|
|
47
|
+
* resto é plural.
|
|
48
|
+
*/
|
|
49
|
+
export declare const RECURSOS: Record<Horizonte, RecursoFocus>;
|
|
50
|
+
/** Recurso de Selic, fora do mapa de horizontes porque o eixo é a reunião do Copom. */
|
|
51
|
+
export declare const RECURSO_SELIC: {
|
|
52
|
+
readonly consenso: "ExpectativasMercadoSelic";
|
|
53
|
+
readonly top5: "ExpectativasMercadoTop5Selic";
|
|
54
|
+
};
|
|
55
|
+
/** Linha normalizada: um contrato para os cinco horizontes e para o Top 5. */
|
|
56
|
+
export interface ExpectativaNormalizada {
|
|
57
|
+
indicador: string | null;
|
|
58
|
+
indicadorDetalhe: string | null;
|
|
59
|
+
/** Data da coleta (campo `Data` da fonte) — o Focus é vintage por construção. */
|
|
60
|
+
coletadoEm: string | null;
|
|
61
|
+
/** Alvo da expectativa: data de referência, reunião do Copom, ou null nos rolantes. */
|
|
62
|
+
referencia: string | null;
|
|
63
|
+
media: number | null;
|
|
64
|
+
mediana: number | null;
|
|
65
|
+
desvioPadrao: number | null;
|
|
66
|
+
minimo: number | null;
|
|
67
|
+
maximo: number | null;
|
|
68
|
+
respondentes: number | null;
|
|
69
|
+
baseCalculo: number | null;
|
|
70
|
+
/** Só nos horizontes rolantes: se a série é a suavizada. */
|
|
71
|
+
suavizada?: boolean | null;
|
|
72
|
+
/** Só no Top 5: tipo de cálculo publicado pela fonte. */
|
|
73
|
+
tipoCalculo?: string | null;
|
|
74
|
+
/** Só no Top 5 da Selic: único recurso da fonte que publica este campo. */
|
|
75
|
+
coeficienteVariacao?: number | null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Normaliza uma linha do OData. Defensivo de propósito: os recursos não têm o
|
|
79
|
+
* mesmo conjunto de campos, o alvo aparece como `DataReferencia` (calendário) ou
|
|
80
|
+
* `Reuniao` (Selic), e a caixa dos nomes varia entre recursos.
|
|
81
|
+
*/
|
|
82
|
+
export declare function normalizarExpectativa(linha: Record<string, unknown>): ExpectativaNormalizada;
|
|
83
|
+
export interface ArgsExpectativas {
|
|
84
|
+
indicador: string;
|
|
85
|
+
horizonte: Horizonte;
|
|
86
|
+
referencia?: string;
|
|
87
|
+
dataInicial?: string;
|
|
88
|
+
dataFinal?: string;
|
|
89
|
+
top5?: boolean;
|
|
90
|
+
suavizada?: boolean;
|
|
91
|
+
limite?: number;
|
|
92
|
+
}
|
|
93
|
+
export declare function handleFocusExpectativas(args: ArgsExpectativas, timeoutMs?: number, maxRetries?: number): Promise<ToolResult>;
|
|
94
|
+
export interface ArgsSelic {
|
|
95
|
+
reuniao?: string;
|
|
96
|
+
dataInicial?: string;
|
|
97
|
+
dataFinal?: string;
|
|
98
|
+
top5?: boolean;
|
|
99
|
+
limite?: number;
|
|
100
|
+
}
|
|
101
|
+
export declare function handleFocusSelic(args: ArgsSelic, timeoutMs?: number, maxRetries?: number): Promise<ToolResult>;
|
|
102
|
+
/** Escopos de descoberta: os cinco horizontes mais a Selic, que é tool própria. */
|
|
103
|
+
export type EscopoReferencias = Horizonte | "selic";
|
|
104
|
+
export interface ArgsReferencias {
|
|
105
|
+
indicador?: string;
|
|
106
|
+
escopo?: EscopoReferencias;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Descobre os textos EXATOS de indicador e de referência, por escopo.
|
|
110
|
+
*
|
|
111
|
+
* O parâmetro chama-se `escopo`, e não `horizonte`, de propósito: os cinco
|
|
112
|
+
* horizontes de `bcb_focus_expectativas` mais a Selic — cujo eixo é a reunião do
|
|
113
|
+
* Copom, não o calendário — não formam um conjunto de horizontes. Esta tool cobre
|
|
114
|
+
* tudo o que o Focus publica, e cada bloco diz em `tool` quem o consome.
|
|
115
|
+
*
|
|
116
|
+
* O desenho consulta os próprios recursos de expectativa — e não o recurso
|
|
117
|
+
* `DatasReferencia`, que o nome sugere e que foi descartado com o spike contra a
|
|
118
|
+
* origem: ele publica `Indicador`, `periodo`, `DataReferencia1` e
|
|
119
|
+
* `DataReferencia2` (não existe `DataReferencia`), cobre 11 indicadores contra os
|
|
120
|
+
* 26 do recurso anual, não separa por escopo e, para o IPCA, para em 12/2026
|
|
121
|
+
* enquanto as expectativas mensais já carregam referência 07/2028. É um calendário
|
|
122
|
+
* de datas de referência, não um índice das referências consultáveis.
|
|
123
|
+
*
|
|
124
|
+
* A quebra POR ESCOPO é o ponto: o conjunto de indicadores varia muito entre eles
|
|
125
|
+
* (9 no mensal contra 26 no anual), e pedir um indicador no horizonte errado —
|
|
126
|
+
* "PIB Total" no mensal, por exemplo — é justamente o modo mais comum de a
|
|
127
|
+
* consulta voltar vazia sem explicação.
|
|
128
|
+
*/
|
|
129
|
+
export declare function handleFocusReferencias(args: ArgsReferencias, timeoutMs?: number, maxRetries?: number): Promise<ToolResult>;
|
|
130
|
+
export declare const FOCUS_TOOL_DEFINITIONS: ToolDefinition[];
|
|
131
|
+
/** Retorna null quando a tool não é deste módulo (o dispatcher central segue). */
|
|
132
|
+
export declare function dispatchFocusTool(toolName: string, args: Record<string, unknown>, timeoutMs?: number, maxRetries?: number): Promise<ToolResult> | null;
|
|
133
|
+
export {};
|
|
134
|
+
//# sourceMappingURL=focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../src/focus.ts"],"names":[],"mappings":"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"}
|