jangada-ai 0.1.0 → 1.0.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.
Files changed (78) hide show
  1. package/README.md +6 -2
  2. package/dist/{anthropic-BOBKTM1i.js → anthropic-BlqXqf9N.js} +44 -6
  3. package/dist/{anthropic-D5xT9Yc4.cjs → anthropic-CYKRUh9e.cjs} +57 -19
  4. package/dist/base-8WLtVj6O.js +254 -0
  5. package/dist/base-bplcDr6J.cjs +277 -0
  6. package/dist/bedrock-Dxpg5jFC.cjs +475 -0
  7. package/dist/bedrock-infoTG03.js +475 -0
  8. package/dist/client-BFoano5Y.js +792 -0
  9. package/dist/client-BmJIzbSw.d.ts +357 -0
  10. package/dist/client-C7tNbVHu.cjs +851 -0
  11. package/dist/client-CoQl5mod.d.ts +584 -0
  12. package/dist/client-DgU6xftB.d.cts +584 -0
  13. package/dist/client-Y9MDtyQ4.d.cts +357 -0
  14. package/dist/{env-c3s1IX0t.js → context-C7qrmHGJ.js} +101 -15
  15. package/dist/context-DN___2Xb.d.cts +56 -0
  16. package/dist/context-DN___2Xb.d.ts +56 -0
  17. package/dist/{env-BgCjpek9.cjs → context-JTZvYRrC.cjs} +132 -16
  18. package/dist/env-B1ffNsxb.cjs +26 -0
  19. package/dist/env-BH4ulZ4_.js +15 -0
  20. package/dist/errors-BJIPDLwX.cjs +320 -0
  21. package/dist/errors-hp-4UePr.js +207 -0
  22. package/dist/eval/index.cjs +275 -0
  23. package/dist/eval/index.d.cts +87 -0
  24. package/dist/eval/index.d.ts +87 -0
  25. package/dist/eval/index.js +270 -0
  26. package/dist/files-DhchXoMT.cjs +363 -0
  27. package/dist/files-lcQv3hAq.js +340 -0
  28. package/dist/{gemini-Cko-M_l8.cjs → gemini-Dj5mMQH_.cjs} +257 -26
  29. package/dist/{gemini-CyhOfOSH.js → gemini-UV1iF24m.js} +245 -14
  30. package/dist/gemini-schema-BLKtypnG.js +21 -0
  31. package/dist/gemini-schema-BwcTPvV1.cjs +26 -0
  32. package/dist/index.cjs +2819 -99
  33. package/dist/index.d.cts +622 -551
  34. package/dist/index.d.ts +622 -551
  35. package/dist/index.js +2714 -35
  36. package/dist/mcp/index.cjs +21 -0
  37. package/dist/mcp/index.d.cts +4 -0
  38. package/dist/mcp/index.d.ts +4 -0
  39. package/dist/mcp/index.js +4 -0
  40. package/dist/mistral-CdX-9oKB.cjs +882 -0
  41. package/dist/mistral-NBf2U9m7.js +882 -0
  42. package/dist/node/index.cjs +891 -3
  43. package/dist/node/index.d.cts +298 -2
  44. package/dist/node/index.d.ts +298 -2
  45. package/dist/node/index.js +886 -2
  46. package/dist/observability-D1Eiz3hh.cjs +369 -0
  47. package/dist/{message-D3MSjqww.d.ts → observability-DLUNn71i.d.cts} +80 -1
  48. package/dist/{message-D3MSjqww.d.cts → observability-DLUNn71i.d.ts} +80 -1
  49. package/dist/observability-DQW4up31.js +316 -0
  50. package/dist/ollama-CURVIQcv.cjs +627 -0
  51. package/dist/ollama-CpdaRdg-.js +627 -0
  52. package/dist/openai-compat-BWdb9UUW.cjs +1288 -0
  53. package/dist/openai-compat-Qlv_JgU5.js +1284 -0
  54. package/dist/prebuilt/index.cjs +1645 -0
  55. package/dist/prebuilt/index.d.cts +293 -0
  56. package/dist/prebuilt/index.d.ts +293 -0
  57. package/dist/prebuilt/index.js +1594 -0
  58. package/dist/rag/index.cjs +1140 -0
  59. package/dist/rag/index.d.cts +387 -0
  60. package/dist/rag/index.d.ts +387 -0
  61. package/dist/rag/index.js +1122 -0
  62. package/dist/schema-BBiyhRZk.d.cts +63 -0
  63. package/dist/schema-BBiyhRZk.d.ts +63 -0
  64. package/dist/schema-DCaQOk49.js +104 -0
  65. package/dist/schema-qS-xTTIs.cjs +121 -0
  66. package/dist/server-B_XDzBbl.d.ts +198 -0
  67. package/dist/server-C8hINWgp.d.cts +198 -0
  68. package/dist/server-CKj0B5mk.cjs +820 -0
  69. package/dist/server-DOnplmbD.js +791 -0
  70. package/dist/tools-4-yoaMWI.d.ts +147 -0
  71. package/dist/tools-DjzQr-Np.d.cts +147 -0
  72. package/dist/version-Ch4xT-gQ.cjs +292 -0
  73. package/dist/version-CrHu1Pq_.js +185 -0
  74. package/package.json +67 -1
  75. package/dist/base-C-SPiVRW.js +0 -728
  76. package/dist/base-oJ61mpAL.cjs +0 -985
  77. package/dist/openai-compat-CFXijT4g.js +0 -538
  78. package/dist/openai-compat-CqvE3LDu.cjs +0 -542
package/README.md CHANGED
@@ -7,7 +7,7 @@ erro, structured output com Zod, tools, streaming e custo em cada resposta.
7
7
  Port da lib Python [`jangada-ai`](https://pypi.org/project/jangada-ai/).
8
8
  Documentação: [docs.jangada.dev.br](https://docs.jangada.dev.br).
9
9
 
10
- > Versão 0.1.0: núcleo e 8 providers. MCP, agentes, RAG e o resto chegam nas próximas versões (veja o [roadmap de paridade](https://docs.jangada.dev.br/javascript)).
10
+ > Versão 1.0.0: paridade com a lib Python (providers, tools, MCP, agentes, RAG, eval, A2A e mais).
11
11
 
12
12
  ```bash
13
13
  npm install jangada-ai
@@ -29,7 +29,11 @@ console.log(comp.text, comp.cost);
29
29
  ```
30
30
 
31
31
  Providers: `openai`, `azure`, `groq`, `openrouter`, `deepseek`, `anthropic`,
32
- `gemini`, `vertex`. Exemplos em [`examples/`](examples/).
32
+ `gemini`, `vertex`, `bedrock`, `mistral`, `ollama`.
33
+
34
+ Subpaths: `jangada-ai/node` (arquivos, `.env`, `serveMcp`, `serveA2a`),
35
+ `jangada-ai/mcp`, `jangada-ai/rag`, `jangada-ai/eval`, `jangada-ai/prebuilt` e
36
+ `jangada-ai/a2a`. Exemplos em [`examples/`](examples/).
33
37
 
34
38
  ## Desenvolvimento
35
39
 
@@ -1,5 +1,8 @@
1
- import { F as ProviderError, H as classify, N as OutputValidationError, R as ServerError, V as UnsupportedError, d as NativeTool, j as LLMError, n as applyProfile, s as splitTools, t as Provider } from "./base-C-SPiVRW.js";
2
- import { c as imageBase64, i as Completion, s as ToolCall } from "./env-c3s1IX0t.js";
1
+ import { _ as UnsupportedError, d as ProviderError, l as OutputValidationError, m as ServerError, s as LLMError, v as classify } from "./errors-hp-4UePr.js";
2
+ import { s as splitMcp } from "./client-BFoano5Y.js";
3
+ import { d as imageBase64, s as Completion, u as ToolCall } from "./context-C7qrmHGJ.js";
4
+ import { c as NativeTool, i as splitTools } from "./version-CrHu1Pq_.js";
5
+ import { n as applyProfile, t as Provider } from "./base-8WLtVj6O.js";
3
6
  // src/providers/anthropic.ts
4
7
  /**
5
8
  * Provider Anthropic (Claude): texto, vision, tools, tools nativas (server tools),
@@ -10,7 +13,8 @@ import { c as imageBase64, i as Completion, s as ToolCall } from "./env-c3s1IX0t
10
13
  * Schema. Nos modelos que REJEITAM forced tool use (Opus 5.5, Sonnet 5.5, Fable 5.1,
11
14
  * Mythos 5.1) cai para `tool_choice: auto` + strict tool use, a migração oficial.
12
15
  *
13
- * Fica para a Fase 3: MCP remoto (Messages API beta).
16
+ * MCP remoto: `mcpServers` com `MCPServer` vai na Messages API (`mcp_servers` +
17
+ * `mcp_toolset`, header beta `mcp-client-2025-11-20`). Sessão client-side não dá.
14
18
  *
15
19
  * Espelha `jangada_ai/providers/anthropic.py`.
16
20
  */
@@ -18,6 +22,7 @@ const THINKING_KEY = "anthropic_thinking_blocks";
18
22
  const CONTENT_KEY = "anthropic_content";
19
23
  const CONTAINER_KEY = "anthropic_container";
20
24
  const MAX_PAUSE = 5;
25
+ const MCP_BETA = "mcp-client-2025-11-20";
21
26
  const NATIVE_VERSIONS = {
22
27
  web_search: ["web_search_20250305", "web_search"],
23
28
  web_fetch: ["web_fetch_20250910", "web_fetch"],
@@ -71,6 +76,7 @@ var AnthropicProvider = class AnthropicProvider extends Provider {
71
76
  ]);
72
77
  nativeToolPassthrough = true;
73
78
  nativeToolAliases = ["claude"];
79
+ supportsMcp = true;
74
80
  async buildClient() {
75
81
  let mod;
76
82
  try {
@@ -232,8 +238,39 @@ var AnthropicProvider = class AnthropicProvider extends Provider {
232
238
  const container = AnthropicProvider.containerFrom(messages, tools);
233
239
  if (container) kw.container = container;
234
240
  }
241
+ if (options.mcpServers?.length) this.applyMcp(kw, options.mcpServers);
235
242
  return kw;
236
243
  }
244
+ /**
245
+ * MCP remoto via Messages API (server-side, beta). Sessão client-side não dá.
246
+ * Allowlist no shape `mcp-client-2025-11-20`: `default_config` desabilitado e cada
247
+ * tool permitida habilitada em `configs`.
248
+ */
249
+ applyMcp(kw, mcpServers) {
250
+ const { remote, sessions } = splitMcp(mcpServers);
251
+ if (sessions.length) throw new UnsupportedError("Anthropic só aceita MCP remoto por URL (passe MCPServer). Para MCP client-side (sessão), use o Gemini ou MCPClient + runAgent.", { provider: this.name });
252
+ kw.mcp_servers = remote.map((s) => ({
253
+ type: "url",
254
+ url: s.url,
255
+ name: s.name,
256
+ ...s.authorizationToken ? { authorization_token: s.authorizationToken } : {}
257
+ }));
258
+ const toolsets = remote.map((s) => ({
259
+ type: "mcp_toolset",
260
+ mcp_server_name: s.name,
261
+ ...s.allowedTools?.length ? {
262
+ default_config: { enabled: false },
263
+ configs: Object.fromEntries(s.allowedTools.map((t) => [t, { enabled: true }]))
264
+ } : {}
265
+ }));
266
+ kw.tools = [...kw.tools ?? [], ...toolsets];
267
+ }
268
+ /** Opções da requisição: `signal` e, com MCP, o header beta. */
269
+ reqOptions(options) {
270
+ const o = { signal: options.signal };
271
+ if (options.mcpServers?.length) o.headers = { "anthropic-beta": MCP_BETA };
272
+ return o;
273
+ }
237
274
  static thinkingBlocks(content) {
238
275
  const out = [];
239
276
  for (const b of content) {
@@ -419,7 +456,7 @@ var AnthropicProvider = class AnthropicProvider extends Provider {
419
456
  let resp;
420
457
  for (let i = 0; i <= MAX_PAUSE; i++) {
421
458
  try {
422
- resp = await client.messages.create(kw, { signal: options.signal });
459
+ resp = await client.messages.create(kw, this.reqOptions(options));
423
460
  } catch (e) {
424
461
  throw this.err(e, options);
425
462
  }
@@ -434,7 +471,8 @@ var AnthropicProvider = class AnthropicProvider extends Provider {
434
471
  const kw = this.kwargs(messages, {
435
472
  ...options,
436
473
  tools: void 0,
437
- toolChoice: void 0
474
+ toolChoice: void 0,
475
+ mcpServers: void 0
438
476
  });
439
477
  const extract = {
440
478
  name: "extract",
@@ -483,7 +521,7 @@ var AnthropicProvider = class AnthropicProvider extends Provider {
483
521
  let resp;
484
522
  for (let i = 0; i <= MAX_PAUSE; i++) {
485
523
  try {
486
- const s = client.messages.stream(kw, { signal: options.signal });
524
+ const s = client.messages.stream(kw, this.reqOptions(options));
487
525
  for await (const ev of s) {
488
526
  if (get(ev, "type") !== "content_block_delta") continue;
489
527
  const delta = get(ev, "delta");
@@ -1,5 +1,8 @@
1
- const require_base = require("./base-oJ61mpAL.cjs");
2
- const require_env = require("./env-BgCjpek9.cjs");
1
+ const require_errors = require("./errors-BJIPDLwX.cjs");
2
+ const require_client = require("./client-C7tNbVHu.cjs");
3
+ const require_context = require("./context-JTZvYRrC.cjs");
4
+ const require_version = require("./version-Ch4xT-gQ.cjs");
5
+ const require_base = require("./base-bplcDr6J.cjs");
3
6
  // src/providers/anthropic.ts
4
7
  /**
5
8
  * Provider Anthropic (Claude): texto, vision, tools, tools nativas (server tools),
@@ -10,7 +13,8 @@ const require_env = require("./env-BgCjpek9.cjs");
10
13
  * Schema. Nos modelos que REJEITAM forced tool use (Opus 5.5, Sonnet 5.5, Fable 5.1,
11
14
  * Mythos 5.1) cai para `tool_choice: auto` + strict tool use, a migração oficial.
12
15
  *
13
- * Fica para a Fase 3: MCP remoto (Messages API beta).
16
+ * MCP remoto: `mcpServers` com `MCPServer` vai na Messages API (`mcp_servers` +
17
+ * `mcp_toolset`, header beta `mcp-client-2025-11-20`). Sessão client-side não dá.
14
18
  *
15
19
  * Espelha `jangada_ai/providers/anthropic.py`.
16
20
  */
@@ -18,6 +22,7 @@ const THINKING_KEY = "anthropic_thinking_blocks";
18
22
  const CONTENT_KEY = "anthropic_content";
19
23
  const CONTAINER_KEY = "anthropic_container";
20
24
  const MAX_PAUSE = 5;
25
+ const MCP_BETA = "mcp-client-2025-11-20";
21
26
  const NATIVE_VERSIONS = {
22
27
  web_search: ["web_search_20250305", "web_search"],
23
28
  web_fetch: ["web_fetch_20250910", "web_fetch"],
@@ -71,6 +76,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
71
76
  ]);
72
77
  nativeToolPassthrough = true;
73
78
  nativeToolAliases = ["claude"];
79
+ supportsMcp = true;
74
80
  async buildClient() {
75
81
  let mod;
76
82
  try {
@@ -97,7 +103,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
97
103
  source: {
98
104
  type: "base64",
99
105
  media_type: p.mimeType,
100
- data: require_env.imageBase64(p)
106
+ data: require_context.imageBase64(p)
101
107
  }
102
108
  });
103
109
  else if (p.type === "tool_call") {
@@ -156,7 +162,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
156
162
  return out;
157
163
  }
158
164
  formatTools(tools) {
159
- const { functions, natives } = require_base.splitTools(tools);
165
+ const { functions, natives } = require_version.splitTools(tools);
160
166
  const out = functions.map((t) => ({
161
167
  name: t.name,
162
168
  description: t.description,
@@ -175,13 +181,13 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
175
181
  const tipo = o.version ?? tipoPadrao;
176
182
  delete o.version;
177
183
  delete o.container;
178
- if (o.files !== void 0) throw new require_base.UnsupportedError("codeExecution({ files }) não existe na Anthropic: envie os arquivos como blocos container_upload (Files API) na mensagem.", { provider: this.name });
184
+ if (o.files !== void 0) throw new require_errors.UnsupportedError("codeExecution({ files }) não existe na Anthropic: envie os arquivos como blocos container_upload (Files API) na mensagem.", { provider: this.name });
179
185
  const loc = o.user_location;
180
186
  if (loc && typeof loc === "object" && !("type" in loc)) o.user_location = {
181
187
  type: "approximate",
182
188
  ...loc
183
189
  };
184
- if (o.allowed_domains && o.blocked_domains) throw new require_base.UnsupportedError(`${nt.kind}: a Anthropic não aceita allowedDomains e blockedDomains juntos (400). Use só um.`, { provider: this.name });
190
+ if (o.allowed_domains && o.blocked_domains) throw new require_errors.UnsupportedError(`${nt.kind}: a Anthropic não aceita allowedDomains e blockedDomains juntos (400). Use só um.`, { provider: this.name });
185
191
  return {
186
192
  type: tipo,
187
193
  name: nome,
@@ -190,7 +196,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
190
196
  }
191
197
  /** Container do code_execution: o explícito ou o último do histórico. */
192
198
  static containerFrom(messages, tools) {
193
- for (const t of tools) if (t instanceof require_base.NativeTool && t.kind === "code_execution") {
199
+ for (const t of tools) if (t instanceof require_version.NativeTool && t.kind === "code_execution") {
194
200
  const explicito = t.options.container;
195
201
  if (typeof explicito === "string" && explicito) return explicito;
196
202
  for (const m of [...messages].reverse()) {
@@ -226,14 +232,45 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
226
232
  kw.tools = this.formatTools(tools);
227
233
  if (options.toolChoice !== void 0 && options.toolChoice !== null) {
228
234
  const tc = AnthropicProvider.toolChoice(options.toolChoice);
229
- if (this.forbidsForcedTools() && (tc.type === "any" || tc.type === "tool")) throw new require_base.UnsupportedError(`${this.model} não suporta forced tool use (toolChoice=${JSON.stringify(options.toolChoice)}): a API retorna 400. Use toolChoice 'auto' (com strict tool use, se quiser garantir o schema) ou structured output via parse().`, { provider: this.name });
235
+ if (this.forbidsForcedTools() && (tc.type === "any" || tc.type === "tool")) throw new require_errors.UnsupportedError(`${this.model} não suporta forced tool use (toolChoice=${JSON.stringify(options.toolChoice)}): a API retorna 400. Use toolChoice 'auto' (com strict tool use, se quiser garantir o schema) ou structured output via parse().`, { provider: this.name });
230
236
  kw.tool_choice = tc;
231
237
  }
232
238
  const container = AnthropicProvider.containerFrom(messages, tools);
233
239
  if (container) kw.container = container;
234
240
  }
241
+ if (options.mcpServers?.length) this.applyMcp(kw, options.mcpServers);
235
242
  return kw;
236
243
  }
244
+ /**
245
+ * MCP remoto via Messages API (server-side, beta). Sessão client-side não dá.
246
+ * Allowlist no shape `mcp-client-2025-11-20`: `default_config` desabilitado e cada
247
+ * tool permitida habilitada em `configs`.
248
+ */
249
+ applyMcp(kw, mcpServers) {
250
+ const { remote, sessions } = require_client.splitMcp(mcpServers);
251
+ if (sessions.length) throw new require_errors.UnsupportedError("Anthropic só aceita MCP remoto por URL (passe MCPServer). Para MCP client-side (sessão), use o Gemini ou MCPClient + runAgent.", { provider: this.name });
252
+ kw.mcp_servers = remote.map((s) => ({
253
+ type: "url",
254
+ url: s.url,
255
+ name: s.name,
256
+ ...s.authorizationToken ? { authorization_token: s.authorizationToken } : {}
257
+ }));
258
+ const toolsets = remote.map((s) => ({
259
+ type: "mcp_toolset",
260
+ mcp_server_name: s.name,
261
+ ...s.allowedTools?.length ? {
262
+ default_config: { enabled: false },
263
+ configs: Object.fromEntries(s.allowedTools.map((t) => [t, { enabled: true }]))
264
+ } : {}
265
+ }));
266
+ kw.tools = [...kw.tools ?? [], ...toolsets];
267
+ }
268
+ /** Opções da requisição: `signal` e, com MCP, o header beta. */
269
+ reqOptions(options) {
270
+ const o = { signal: options.signal };
271
+ if (options.mcpServers?.length) o.headers = { "anthropic-beta": MCP_BETA };
272
+ return o;
273
+ }
237
274
  static thinkingBlocks(content) {
238
275
  const out = [];
239
276
  for (const b of content) {
@@ -254,8 +291,8 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
254
291
  try {
255
292
  return this.buildCompletion(resp);
256
293
  } catch (e) {
257
- if (e instanceof require_base.LLMError) throw e;
258
- throw new require_base.ProviderError(`[${this.name}] resposta em formato inesperado: ${e instanceof Error ? `${e.name}: ${e.message}` : e}`, {
294
+ if (e instanceof require_errors.LLMError) throw e;
295
+ throw new require_errors.ProviderError(`[${this.name}] resposta em formato inesperado: ${e instanceof Error ? `${e.name}: ${e.message}` : e}`, {
259
296
  provider: this.name,
260
297
  original: e
261
298
  });
@@ -263,9 +300,9 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
263
300
  }
264
301
  buildCompletion(resp) {
265
302
  const content = get(resp, "content");
266
- if (!Array.isArray(content)) throw new require_base.ServerError(`[${this.name}] resposta sem conteúdo (content=${content}).`, { provider: this.name });
303
+ if (!Array.isArray(content)) throw new require_errors.ServerError(`[${this.name}] resposta sem conteúdo (content=${content}).`, { provider: this.name });
267
304
  const text = content.map((b) => get(b, "type") === "text" ? get(b, "text") ?? "" : "").join("");
268
- const toolCalls = content.filter((b) => get(b, "type") === "tool_use" && get(b, "name")).map((b) => new require_env.ToolCall(String(get(b, "id") ?? ""), String(get(b, "name")), { ...get(b, "input") ?? {} }));
305
+ const toolCalls = content.filter((b) => get(b, "type") === "tool_use" && get(b, "name")).map((b) => new require_context.ToolCall(String(get(b, "id") ?? ""), String(get(b, "name")), { ...get(b, "input") ?? {} }));
269
306
  const thinking = AnthropicProvider.thinkingBlocks(content);
270
307
  if (thinking.length && toolCalls[0]) toolCalls[0].metadata[THINKING_KEY] = thinking;
271
308
  const { citations, serverCalls, preservar } = AnthropicProvider.nativeOutputs(content);
@@ -295,7 +332,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
295
332
  }
296
333
  }
297
334
  const stop = get(resp, "stop_reason") ?? null;
298
- return new require_env.Completion({
335
+ return new require_context.Completion({
299
336
  text,
300
337
  model: this.model,
301
338
  provider: this.name,
@@ -419,7 +456,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
419
456
  let resp;
420
457
  for (let i = 0; i <= MAX_PAUSE; i++) {
421
458
  try {
422
- resp = await client.messages.create(kw, { signal: options.signal });
459
+ resp = await client.messages.create(kw, this.reqOptions(options));
423
460
  } catch (e) {
424
461
  throw this.err(e, options);
425
462
  }
@@ -434,7 +471,8 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
434
471
  const kw = this.kwargs(messages, {
435
472
  ...options,
436
473
  tools: void 0,
437
- toolChoice: void 0
474
+ toolChoice: void 0,
475
+ mcpServers: void 0
438
476
  });
439
477
  const extract = {
440
478
  name: "extract",
@@ -465,7 +503,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
465
503
  const comp = this.completion(resp);
466
504
  require_base.Provider.checkTruncation(comp, this.name);
467
505
  const toolUse = (get(resp, "content") ?? []).find((b) => get(b, "type") === "tool_use");
468
- if (!toolUse) throw new require_base.OutputValidationError(`[${this.name}] o modelo não devolveu o objeto estruturado (stop_reason=${JSON.stringify(comp.finishReason ?? "sem tool_use")}): ${JSON.stringify(comp.text.slice(0, 200))}`, { provider: this.name });
506
+ if (!toolUse) throw new require_errors.OutputValidationError(`[${this.name}] o modelo não devolveu o objeto estruturado (stop_reason=${JSON.stringify(comp.finishReason ?? "sem tool_use")}): ${JSON.stringify(comp.text.slice(0, 200))}`, { provider: this.name });
469
507
  const input = get(toolUse, "input");
470
508
  comp.text = JSON.stringify(input);
471
509
  comp.parsed = await schema.validate(input);
@@ -483,7 +521,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
483
521
  let resp;
484
522
  for (let i = 0; i <= MAX_PAUSE; i++) {
485
523
  try {
486
- const s = client.messages.stream(kw, { signal: options.signal });
524
+ const s = client.messages.stream(kw, this.reqOptions(options));
487
525
  for await (const ev of s) {
488
526
  if (get(ev, "type") !== "content_block_delta") continue;
489
527
  const delta = get(ev, "delta");
@@ -511,7 +549,7 @@ var AnthropicProvider = class AnthropicProvider extends require_base.Provider {
511
549
  };
512
550
  }
513
551
  err(e, options) {
514
- return options.signal?.aborted ? e : require_base.classify(e, this.name);
552
+ return options.signal?.aborted ? e : require_errors.classify(e, this.name);
515
553
  }
516
554
  };
517
555
  exports.AnthropicProvider = AnthropicProvider;
@@ -0,0 +1,254 @@
1
+ import { _ as UnsupportedError, g as TruncatedError } from "./errors-hp-4UePr.js";
2
+ import { c as NativeTool } from "./version-CrHu1Pq_.js";
3
+ import { n as getEnv } from "./env-BH4ulZ4_.js";
4
+ // src/profiles.ts
5
+ const RULES = [];
6
+ /** Adiciona uma regra de perfil (entra no início: tem prioridade). */
7
+ function registerProfile(provider, pattern, profile) {
8
+ const rx = pattern instanceof RegExp ? new RegExp(pattern.source, pattern.flags.replace(/[gy]/g, "")) : new RegExp(pattern);
9
+ RULES.unshift({
10
+ provider: provider.toLowerCase(),
11
+ rx,
12
+ profile
13
+ });
14
+ }
15
+ const ALIASES = {
16
+ vertex: "gemini",
17
+ azure: "openai"
18
+ };
19
+ /** Faz `provider` herdar as regras de perfil de `target`. */
20
+ function registerAlias(provider, target) {
21
+ ALIASES[provider.toLowerCase()] = target.toLowerCase();
22
+ }
23
+ const has = (o, k) => o[k] !== void 0 && o[k] !== null;
24
+ /**
25
+ * Aplica todas as regras que casam com (provider, model). Devolve uma CÓPIA dos
26
+ * params e os avisos. `profileModel` sobrepõe o nome usado para casar as regras
27
+ * (útil no Azure, onde `model` é o nome do deployment).
28
+ */
29
+ function applyProfile(provider, model, params, options) {
30
+ const out = { ...params };
31
+ const warnings = [];
32
+ const prov = provider.toLowerCase();
33
+ const provs = /* @__PURE__ */ new Set([prov, ALIASES[prov] ?? prov]);
34
+ const alvo = options?.profileModel ?? model;
35
+ for (const { provider: p, rx, profile } of [...RULES]) {
36
+ if (!provs.has(p) || !rx.test(alvo)) continue;
37
+ const note = profile.note ?? "";
38
+ for (const key of profile.drop ?? []) if (has(out, key)) {
39
+ delete out[key];
40
+ warnings.push(`${model}: '${key}' removido (${note})`);
41
+ }
42
+ for (const [old, novo] of Object.entries(profile.rename ?? {})) if (has(out, old)) {
43
+ out[novo] = out[old];
44
+ delete out[old];
45
+ warnings.push(`${model}: '${old}' -> '${novo}' (${note})`);
46
+ }
47
+ if (profile.transform) warnings.push(...profile.transform(out, alvo));
48
+ }
49
+ return {
50
+ params: out,
51
+ warnings
52
+ };
53
+ }
54
+ const LEVEL_TO_BUDGET = {
55
+ MINIMAL: 0,
56
+ LOW: 1024,
57
+ MEDIUM: 8192,
58
+ HIGH: 24576
59
+ };
60
+ const MIN_BUDGET_25_PRO = 128;
61
+ function gemini3Thinking(params, model) {
62
+ if (!("thinkingBudget" in params)) return [];
63
+ const budget = params.thinkingBudget;
64
+ delete params.thinkingBudget;
65
+ if (!has(params, "thinkingLevel")) {
66
+ let level;
67
+ if (!budget || budget < 0 || budget <= 1024) level = "LOW";
68
+ else if (budget <= 8192 && model.toLowerCase().includes("flash")) level = "MEDIUM";
69
+ else level = "HIGH";
70
+ params.thinkingLevel = level;
71
+ }
72
+ return [`thinkingBudget -> thinkingLevel='${params.thinkingLevel}' (Gemini 3.x não aceita budget)`];
73
+ }
74
+ function gemini25Thinking(params, model) {
75
+ if (!("thinkingLevel" in params)) return [];
76
+ const level = String(params.thinkingLevel).toUpperCase();
77
+ delete params.thinkingLevel;
78
+ if (!has(params, "thinkingBudget")) {
79
+ let budget = LEVEL_TO_BUDGET[level] ?? -1;
80
+ if (budget === 0 && /2\.5-pro/.test(model)) budget = MIN_BUDGET_25_PRO;
81
+ params.thinkingBudget = budget;
82
+ }
83
+ return [`thinkingLevel='${level}' -> thinkingBudget=${params.thinkingBudget} (Gemini 2.5 não aceita level)`];
84
+ }
85
+ const OPENAI_REASONING_DROP = [
86
+ "temperature",
87
+ "top_p",
88
+ "presence_penalty",
89
+ "frequency_penalty",
90
+ "logprobs",
91
+ "logit_bias",
92
+ "n"
93
+ ];
94
+ registerProfile("openai", /^gpt-(?:[5-9]|[1-9]\d)(?!\d)(?!.*chat)/, {
95
+ drop: OPENAI_REASONING_DROP,
96
+ rename: { max_tokens: "max_completion_tokens" },
97
+ note: "modelo de raciocínio gpt-5+"
98
+ });
99
+ registerProfile("openai", /^o[134](-|$)/, {
100
+ drop: OPENAI_REASONING_DROP,
101
+ rename: { max_tokens: "max_completion_tokens" },
102
+ note: "modelo de raciocínio série o"
103
+ });
104
+ registerProfile("gemini", /gemini-(?:[3-9]|[1-9]\d)(?!\d)/, {
105
+ drop: [
106
+ "temperature",
107
+ "topP",
108
+ "topK",
109
+ "candidateCount"
110
+ ],
111
+ transform: gemini3Thinking,
112
+ note: "Gemini 3.x+/4 usa defaults de sampling"
113
+ });
114
+ registerProfile("gemini", /gemini-2\.5/, {
115
+ transform: gemini25Thinking,
116
+ note: "Gemini 2.5 usa thinkingBudget"
117
+ });
118
+ // src/providers/base.ts
119
+ /**
120
+ * Contrato base do provider: texto, structured output e streaming (tudo async).
121
+ * Espelha `jangada_ai/providers/base.py`, sem as versões sync.
122
+ *
123
+ * Invariantes para quem escreve um adapter:
124
+ * - o SDK só entra via `await import()` dentro de `buildClient()`;
125
+ * - toda chamada ao SDK fica em try/catch e relança com `classify(e, this.name)`;
126
+ * - params: `translate()` (canônico → nativo) e depois `applyProfile()`.
127
+ */
128
+ var Provider = class {
129
+ /** Variável de ambiente com a chave, usada quando `apiKey` não é passado. */
130
+ envKey = null;
131
+ /** Tipos canônicos que o adapter sabe traduzir (`web_search`, `code_execution`...). */
132
+ nativeToolKinds = /* @__PURE__ */ new Set();
133
+ /** Aceita `nativeTool(<este provider>, spec)` (payload nativo repassado cru)? */
134
+ nativeToolPassthrough = false;
135
+ /** Nomes extras aceitos em `nativeTool(provider, ...)` além de `name`. */
136
+ nativeToolAliases = [];
137
+ /** `parse()` aceita tools nativas junto? */
138
+ nativeToolsWithParse = false;
139
+ /** Aceita `mcpServers` em `complete`/`streamComplete`? */
140
+ supportsMcp = false;
141
+ model;
142
+ apiKey;
143
+ profileModel;
144
+ clientOptions;
145
+ clientPromise = null;
146
+ constructor(model, options = {}) {
147
+ this.model = model;
148
+ this.apiKey = options.apiKey;
149
+ this.profileModel = options.profileModel;
150
+ this.clientOptions = { ...options.clientOptions ?? {} };
151
+ }
152
+ /**
153
+ * Valida as tools NATIVAS antes de ir ao SDK: tipo não suportado, `nativeTool()`
154
+ * de outro provider ou `parse()` com nativas onde a API não deixa →
155
+ * `UnsupportedError` com dica.
156
+ */
157
+ checkNativeTools(tools, method = "complete") {
158
+ const natives = (tools ?? []).filter((t) => t instanceof NativeTool);
159
+ if (!natives.length) return;
160
+ const fail = (msg) => {
161
+ throw new UnsupportedError(msg, { provider: this.name });
162
+ };
163
+ if (method === "parse" && !this.nativeToolsWithParse) fail(`${this.name} não aceita tools nativas junto com structured output (parse). Use complete({ tools }) e depois parse() sobre o texto.`);
164
+ const nomes = /* @__PURE__ */ new Set([this.name, ...this.nativeToolAliases]);
165
+ for (const t of natives) {
166
+ if (t.kind === "native") {
167
+ if (t.provider && nomes.has(t.provider)) {
168
+ if (this.nativeToolPassthrough) continue;
169
+ fail(`'${this.name}' não aceita payload nativo de tool (nativeTool): a API não tem tools server-side.`);
170
+ }
171
+ fail(`nativeTool('${t.provider}', ...) não se aplica ao provider '${this.name}' (o payload nativo só vale no provider indicado).`);
172
+ }
173
+ if (!this.nativeToolKinds.has(t.kind)) {
174
+ const suportadas = [...this.nativeToolKinds].sort().join(", ") || "nenhuma";
175
+ fail(`tool nativa '${t.kind}' não é suportada por '${this.name}' (suportadas aqui: ${suportadas}). Use nativeTool('${this.name}', <payload nativo>) se o SDK tiver algo equivalente.`);
176
+ }
177
+ }
178
+ }
179
+ /** Mensagem do `UnsupportedError` quando o provider não tem MCP. */
180
+ mcpUnsupportedMessage() {
181
+ return `O provider '${this.name}' não suporta MCP (mcpServers). Use Anthropic, OpenAI, Azure, Groq ou Gemini, ou rode o loop client-side com MCPClient + runAgent (funciona em qualquer provider).`;
182
+ }
183
+ /** Recusa `mcpServers` em provider sem suporte (antes de ir ao SDK). */
184
+ checkMcp(mcpServers) {
185
+ if (mcpServers?.length && !this.supportsMcp) throw new UnsupportedError(this.mcpUnsupportedMessage(), { provider: this.name });
186
+ }
187
+ /** Cliente nativo, criado uma vez e reaproveitado. */
188
+ client() {
189
+ if (!this.clientPromise) this.clientPromise = this.buildClient().catch((e) => {
190
+ this.clientPromise = null;
191
+ throw e;
192
+ });
193
+ return this.clientPromise;
194
+ }
195
+ /** Para testes: injeta um cliente nativo falso. */
196
+ setClient(client) {
197
+ this.clientPromise = Promise.resolve(client);
198
+ }
199
+ resolveApiKey() {
200
+ if (this.apiKey) return this.apiKey;
201
+ return this.envKey ? getEnv(this.envKey) : void 0;
202
+ }
203
+ /**
204
+ * Streaming com a resposta completa no fim (texto, tools, usage). Padrão: chamada
205
+ * normal, entregue como um único pedaço de texto + `"done"`. Quem consegue montar
206
+ * a `Completion` a partir do stream sobrescreve.
207
+ */
208
+ async *streamEvents(messages, options) {
209
+ const comp = await this.complete(messages, options);
210
+ if (comp.text) yield {
211
+ type: "text",
212
+ text: comp.text
213
+ };
214
+ yield {
215
+ type: "done",
216
+ text: "",
217
+ completion: comp
218
+ };
219
+ }
220
+ transcribe(_audio, _options) {
221
+ return Promise.reject(new UnsupportedError(`O provider '${this.name}' não suporta transcrição de áudio.`, { provider: this.name }));
222
+ }
223
+ embed(_texts, _options) {
224
+ return Promise.reject(new UnsupportedError(`O provider '${this.name}' não gera embeddings.`, { provider: this.name }));
225
+ }
226
+ ocr(_source, _options) {
227
+ return Promise.reject(new UnsupportedError(`O provider '${this.name}' não faz OCR.`, { provider: this.name }));
228
+ }
229
+ /** Fecha o cliente nativo (se ele tiver `close()`). Idempotente. */
230
+ async close() {
231
+ const p = this.clientPromise;
232
+ this.clientPromise = null;
233
+ if (!p) return;
234
+ try {
235
+ const c = await p;
236
+ if (typeof c?.close === "function") await c.close();
237
+ } catch {}
238
+ }
239
+ /**
240
+ * Lança `TruncatedError` quando a resposta foi cortada por maxTokens. Chamado em
241
+ * `parse` ANTES de validar o JSON, para o erro ser claro ("aumente maxTokens").
242
+ */
243
+ static checkTruncation(comp, provider) {
244
+ if (comp.finishReason === "length") {
245
+ const out = comp.usage?.outputTokens;
246
+ const onde = out ? ` em ${out} tokens de saída` : "";
247
+ throw new TruncatedError(`resposta truncada${onde}: o modelo atingiu maxTokens antes de fechar o JSON. Aumente maxTokens (ex.: params: { maxTokens: 8192 }).`, { provider });
248
+ }
249
+ }
250
+ toString() {
251
+ return `<${this.constructor.name} model=${JSON.stringify(this.model)}>`;
252
+ }
253
+ };
254
+ export { registerProfile as i, applyProfile as n, registerAlias as r, Provider as t };