@luanpoppe/ai 1.0.5 → 1.0.7

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/.env.example ADDED
@@ -0,0 +1,10 @@
1
+ # Variáveis de ambiente necessárias APENAS para os testes E2E
2
+
3
+ # OpenAI API Key (obrigatória para testes com GPT)
4
+ OPENAI_API_KEY=sk-...
5
+
6
+ # Google Gemini Token (obrigatória para testes com Gemini)
7
+ GOOGLE_GEMINI_TOKEN=...
8
+
9
+ # Obrigatória para testes com OpenRouter
10
+ OPENROUTER_API_KEY=...
@@ -1,5 +1,8 @@
1
1
  type ChatGPTModels = "gpt-4" | "gpt-4o" | "gpt-4.1" | "gpt-5" | "gpt-5.1" | "gpt-5-mini" | "gpt-5-nano";
2
2
  type GeminiModels = "gemini-2.5-flash" | "gemini-2.5-pro" | "gemini-3-flash" | "gemini-3-pro";
3
- export type AIModelNames = ChatGPTModels | GeminiModels;
3
+ type AnthropicModels = "claude-opus-4.5" | "claude-haiku-4.5" | "claude-sonnet-4.5" | "claude-opus-4.1" | "claude-opus-4" | "claude-sonnet-4";
4
+ type OpenRouterProvidersModels = `google/${GeminiModels}` | `openai/${ChatGPTModels}` | `anthropic/${AnthropicModels}`;
5
+ type OpenRouterModels = `openrouter:${OpenRouterProvidersModels}` | `openrouter/${OpenRouterProvidersModels}`;
6
+ export type AIModelNames = ChatGPTModels | GeminiModels | OpenRouterModels;
4
7
  export {};
5
8
  //# sourceMappingURL=model-names.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-names.d.ts","sourceRoot":"","sources":["../../src/@types/model-names.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GACd,OAAO,GACP,QAAQ,GACR,SAAS,GACT,OAAO,GACP,SAAS,GACT,YAAY,GACZ,YAAY,CAAC;AAEjB,KAAK,YAAY,GACb,kBAAkB,GAClB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,CAAC;AAEnB,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,YAAY,CAAC"}
1
+ {"version":3,"file":"model-names.d.ts","sourceRoot":"","sources":["../../src/@types/model-names.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GACd,OAAO,GACP,QAAQ,GACR,SAAS,GACT,OAAO,GACP,SAAS,GACT,YAAY,GACZ,YAAY,CAAC;AAEjB,KAAK,YAAY,GACb,kBAAkB,GAClB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,CAAC;AAEnB,KAAK,eAAe,GAAG,iBAAiB,GACpC,kBAAkB,GAClB,mBAAmB,GACnB,iBAAiB,GACjB,eAAe,GACf,iBAAiB,CAAC;AAEtB,KAAK,yBAAyB,GAC1B,UAAU,YAAY,EAAE,GACxB,UAAU,aAAa,EAAE,GACzB,aAAa,eAAe,EAAE,CAAA;AAElC,KAAK,gBAAgB,GACjB,cAAc,yBAAyB,EAAE,GACzC,cAAc,yBAAyB,EAAE,CAAC;AAE9C,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,YAAY,GAAG,gBAAgB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ import { LangchainTools } from "./langchain/tools";
9
9
  type LangchainConstructor = {
10
10
  googleGeminiToken?: string;
11
11
  openAIApiKey?: string;
12
+ openRouterApiKey?: string;
12
13
  };
13
14
  export type LangchainCallParams = {
14
15
  agent?: {
@@ -36,8 +37,14 @@ export declare class Langchain {
36
37
  constructor(tokens: LangchainConstructor);
37
38
  call(params: LangchainCallParams): LangchainCallReturn;
38
39
  callStructuredOutput<T extends z.ZodSchema>(params: LangchainCallStructuredOutputParams<T>): LangchainCallStructuredOutputReturn<typeof params.outputSchema>;
40
+ /**
41
+ * Normaliza schemas Zod para compatibilidade com OpenAI/OpenRouter
42
+ * OpenAI exige que todos os campos em properties estejam no array required
43
+ * quando usa response_format: 'extract'
44
+ */
45
+ private normalizeSchemaForOpenAI;
39
46
  getRawAgent(params: LangchainCallParams, outputSchema?: z.ZodSchema | undefined): {
40
- agent: import("langchain").ReactAgent<Record<string, any>, import("@langchain/core/utils/types").InteropZodObject | import("langchain").AnyAnnotationRoot | undefined, import("@langchain/core/utils/types").InteropZodObject | import("langchain").AnyAnnotationRoot, readonly AgentMiddleware<any, any, any>[]>;
47
+ agent: import("langchain").ReactAgent<import("langchain").AgentTypeConfig<Record<string, any>, import("@langchain/core/utils/types").InteropZodObject | import("langchain").AnyAnnotationRoot | undefined, import("@langchain/core/utils/types").InteropZodObject | import("langchain").AnyAnnotationRoot, readonly AgentMiddleware<any, any, any, readonly (ClientTool | ServerTool)[]>[], readonly (ClientTool | ServerTool)[]>>;
41
48
  };
42
49
  private getModel;
43
50
  private standardAgent;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,CAAC,MAAM,KAAK,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,WAAW,EAIZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;QAC/B,KAAK,CAAC,EAAE,CAAC,UAAU,GAAG,UAAU,CAAC,EAAE,CAAC;KACrC,CAAC;IAEF,WAAW,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC;IAEvD,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,MAAM,mCAAmC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,IACnE,mBAAmB,GAAG;IACpB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC;AAEJ,MAAM,MAAM,mCAAmC,CAAC,CAAC,IAAI,OAAO,CAAC;IAC3D,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CACtB,CAAC,CAAC;AAEH,qBAAa,SAAS;IACR,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,oBAAoB;IAE1C,IAAI,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB;IAiBtD,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAC9C,MAAM,EAAE,mCAAmC,CAAC,CAAC,CAAC,GAC7C,mCAAmC,CAAC,OAAO,MAAM,CAAC,YAAY,CAAC;IAiBlE,WAAW,CACT,MAAM,EAAE,mBAAmB,EAC3B,YAAY,CAAC,EAAE,CAAC,CAAC,SAAS,GAAG,SAAS;;;IAUxC,OAAO,CAAC,QAAQ;IAwBhB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,mBAAmB;CAU5B;AAED,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,CAAC,MAAM,KAAK,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,WAAW,EAIZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,KAAK,oBAAoB,GAAG;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,CAAC,EAAE;QACN,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;QAC/B,KAAK,CAAC,EAAE,CAAC,UAAU,GAAG,UAAU,CAAC,EAAE,CAAC;KACrC,CAAC;IAEF,WAAW,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC;IAEvD,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,OAAO,CAAC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,MAAM,mCAAmC,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,IACnE,mBAAmB,GAAG;IACpB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC;AAEJ,MAAM,MAAM,mCAAmC,CAAC,CAAC,IAAI,OAAO,CAAC;IAC3D,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CACtB,CAAC,CAAC;AAEH,qBAAa,SAAS;IACR,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,oBAAoB;IAE1C,IAAI,CAAC,MAAM,EAAE,mBAAmB,GAAG,mBAAmB;IAiBtD,oBAAoB,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAC9C,MAAM,EAAE,mCAAmC,CAAC,CAAC,CAAC,GAC7C,mCAAmC,CAAC,OAAO,MAAM,CAAC,YAAY,CAAC;IAwBlE;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAsChC,WAAW,CACT,MAAM,EAAE,mBAAmB,EAC3B,YAAY,CAAC,EAAE,CAAC,CAAC,SAAS,GAAG,SAAS;;;IAUxC,OAAO,CAAC,QAAQ;IAiChB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,mBAAmB;CAU5B;AAED,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.LangchainTools = exports.LangchainMessages = exports.LangchainModels = exports.Langchain = void 0;
4
7
  const models_1 = require("./langchain/models");
5
8
  Object.defineProperty(exports, "LangchainModels", { enumerable: true, get: function () { return models_1.LangchainModels; } });
9
+ const zod_1 = __importDefault(require("zod"));
6
10
  const langchain_1 = require("langchain");
7
11
  const messages_1 = require("./langchain/messages");
8
12
  Object.defineProperty(exports, "LangchainMessages", { enumerable: true, get: function () { return messages_1.LangchainMessages; } });
@@ -26,10 +30,13 @@ class Langchain {
26
30
  };
27
31
  }
28
32
  async callStructuredOutput(params) {
29
- const { outputSchema, messages } = params;
33
+ const { outputSchema, messages, aiModel } = params;
34
+ // Normaliza o schema para compatibilidade com OpenAI/OpenRouter
35
+ // OpenAI exige que todos os campos em properties estejam no array required
36
+ const normalizedSchema = this.normalizeSchemaForOpenAI(outputSchema, aiModel);
30
37
  const agent = (0, langchain_1.createAgent)({
31
38
  ...this.standardAgent(params),
32
- responseFormat: outputSchema,
39
+ responseFormat: normalizedSchema,
33
40
  });
34
41
  const response = await agent.invoke({
35
42
  messages,
@@ -37,6 +44,40 @@ class Langchain {
37
44
  const parsedResponse = outputSchema.parse(response?.structuredResponse);
38
45
  return { response: parsedResponse };
39
46
  }
47
+ /**
48
+ * Normaliza schemas Zod para compatibilidade com OpenAI/OpenRouter
49
+ * OpenAI exige que todos os campos em properties estejam no array required
50
+ * quando usa response_format: 'extract'
51
+ */
52
+ normalizeSchemaForOpenAI(schema, aiModel) {
53
+ // Apenas normaliza para modelos OpenAI/OpenRouter
54
+ const isOpenAIModel = aiModel.startsWith("gpt") ||
55
+ aiModel.startsWith("openrouter:openai/") ||
56
+ aiModel.startsWith("openrouter/openai/");
57
+ if (!isOpenAIModel) {
58
+ return schema;
59
+ }
60
+ // Se o schema é um objeto Zod, precisamos normalizar campos opcionais
61
+ if (schema instanceof zod_1.default.ZodObject) {
62
+ const shape = schema.shape;
63
+ const newShape = {};
64
+ // Converte campos opcionais para nullable para compatibilidade com OpenAI
65
+ // OpenAI requer que todos os campos estejam no array required
66
+ for (const [key, value] of Object.entries(shape)) {
67
+ if (value instanceof zod_1.default.ZodOptional) {
68
+ // Converte .optional() para .nullable() para compatibilidade com OpenAI
69
+ const innerType = value._def.innerType;
70
+ // Usa z.union para criar um tipo nullable
71
+ newShape[key] = zod_1.default.union([innerType, zod_1.default.null()]);
72
+ }
73
+ else {
74
+ newShape[key] = value;
75
+ }
76
+ }
77
+ return zod_1.default.object(newShape);
78
+ }
79
+ return schema;
80
+ }
40
81
  getRawAgent(params, outputSchema) {
41
82
  const agent = (0, langchain_1.createAgent)({
42
83
  ...this.standardAgent(params),
@@ -59,6 +100,14 @@ class Langchain {
59
100
  config.apiKey = this.tokens.googleGeminiToken;
60
101
  return models_1.LangchainModels.gemini(config);
61
102
  }
103
+ if (aiModel.startsWith("openrouter:") || aiModel.startsWith("openrouter/")) {
104
+ const modelName = aiModel.replace(/^openrouter[:/]/, "");
105
+ return models_1.LangchainModels.openrouter({
106
+ ...config,
107
+ model: modelName,
108
+ apiKey: this.tokens.openRouterApiKey,
109
+ });
110
+ }
62
111
  throw new Error("Model not supported");
63
112
  }
64
113
  standardAgent(params) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -9,5 +9,9 @@ export type LLMModelConfig = {
9
9
  export declare class LangchainModels {
10
10
  static gpt(params: LLMModelConfig): ChatOpenAI<import("@langchain/openai").ChatOpenAICallOptions>;
11
11
  static gemini(params: LLMModelConfig): ChatGoogleGenerativeAI;
12
+ static openrouter(params: LLMModelConfig & {
13
+ httpReferer?: string;
14
+ title?: string;
15
+ }): ChatOpenAI<import("@langchain/openai").ChatOpenAICallOptions>;
12
16
  }
13
17
  //# sourceMappingURL=models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/langchain/models.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,qBAAa,eAAe;IAC1B,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc;IAgBjC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc;CAkBrC"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/langchain/models.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAoB,MAAM,mBAAmB,CAAC;AAEjE,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF,qBAAa,eAAe;IAC1B,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc;IAgBjC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc;IAmBpC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,cAAc,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;CAqBpF"}
@@ -32,6 +32,23 @@ class LangchainModels {
32
32
  options.temperature = temperature;
33
33
  return new google_genai_1.ChatGoogleGenerativeAI(options);
34
34
  }
35
+ static openrouter(params) {
36
+ const { apiKey, maxTokens, model, temperature, httpReferer, title } = params;
37
+ if (!apiKey)
38
+ throw new Error("OpenRouter API key is not passed in the model parameters");
39
+ const options = {
40
+ model,
41
+ apiKey,
42
+ configuration: {
43
+ baseURL: "https://openrouter.ai/api/v1",
44
+ },
45
+ };
46
+ if (maxTokens)
47
+ options.maxTokens = maxTokens;
48
+ if (temperature)
49
+ options.temperature = temperature;
50
+ return new openai_1.ChatOpenAI(options);
51
+ }
35
52
  }
36
53
  exports.LangchainModels = LangchainModels;
37
54
  //# sourceMappingURL=models.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/langchain/models.ts"],"names":[],"mappings":";;;AAAA,0DAGiC;AACjC,8CAAiE;AASjE,MAAa,eAAe;IAC1B,MAAM,CAAC,GAAG,CAAC,MAAsB;QAC/B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;QACzD,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAE1E,MAAM,OAAO,GAAqB;YAChC,KAAK;YACL,MAAM;SACP,CAAC;QAEF,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7C,IAAI,WAAW;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEnD,OAAO,IAAI,mBAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,MAAsB;QAClC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;QAEzD,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;QAEJ,MAAM,OAAO,GAAgC;YAC3C,KAAK;YACL,MAAM;SACP,CAAC;QAEF,IAAI,SAAS;YAAE,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;QACnD,IAAI,WAAW;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEnD,OAAO,IAAI,qCAAsB,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;CACF;AAnCD,0CAmCC"}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../../src/langchain/models.ts"],"names":[],"mappings":";;;AAAA,0DAGiC;AACjC,8CAAiE;AASjE,MAAa,eAAe;IAC1B,MAAM,CAAC,GAAG,CAAC,MAAsB;QAC/B,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;QACzD,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAE1E,MAAM,OAAO,GAAqB;YAChC,KAAK;YACL,MAAM;SACP,CAAC;QAEF,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7C,IAAI,WAAW;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEnD,OAAO,IAAI,mBAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,MAAsB;QAClC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;QAEzD,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;QAEJ,MAAM,OAAO,GAAgC;YAC3C,KAAK;YACL,MAAM;SACP,CAAC;QAEF,IAAI,SAAS;YAAE,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;QACnD,IAAI,WAAW;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEnD,OAAO,IAAI,qCAAsB,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,CAAC,UAAU,CAAC,MAAiE;QACjF,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;QAE7E,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,KAAK,CACb,0DAA0D,CAC3D,CAAC;QAEJ,MAAM,OAAO,GAAqB;YAChC,KAAK;YACL,MAAM;YACN,aAAa,EAAE;gBACb,OAAO,EAAE,8BAA8B;aACxC;SACF,CAAC;QAEF,IAAI,SAAS;YAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7C,IAAI,WAAW;YAAE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAEnD,OAAO,IAAI,mBAAU,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;CACF;AAzDD,0CAyDC"}
@@ -7,6 +7,6 @@ export type CreateToolParams = {
7
7
  schema: z.ZodSchema;
8
8
  };
9
9
  export declare class LangchainTools {
10
- createTool(params: CreateToolParams): import("langchain").DynamicStructuredTool<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, unknown, unknown, unknown>;
10
+ createTool(params: CreateToolParams): import("langchain").DynamicStructuredTool<z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>, unknown, unknown, unknown, string>;
11
11
  }
12
12
  //# sourceMappingURL=tools.d.ts.map
package/package.json CHANGED
@@ -1,25 +1,35 @@
1
1
  {
2
2
  "name": "@luanpoppe/ai",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "keywords": [],
7
7
  "author": "",
8
8
  "license": "ISC",
9
9
  "dependencies": {
10
- "@langchain/core": "^1.1.8",
11
- "@langchain/google-genai": "^2.1.3",
12
- "@langchain/openai": "^1.2.0",
13
- "langchain": "^1.2.3",
14
- "zod": "^4.2.1"
10
+ "@langchain/core": "^1.1.16",
11
+ "@langchain/google-genai": "^2.1.12",
12
+ "@langchain/openai": "^1.2.3",
13
+ "langchain": "^1.2.12",
14
+ "zod": "^4.3.6"
15
15
  },
16
16
  "devDependencies": {
17
- "@types/node": "^25.0.3",
17
+ "@types/node": "^25.0.10",
18
+ "@vitest/coverage-v8": "^4.0.18",
19
+ "@vitest/ui": "^4.0.18",
20
+ "dotenv": "^16.4.7",
18
21
  "tsx": "^4.21.0",
19
- "typescript": "^5.9.3"
22
+ "typescript": "^5.9.3",
23
+ "vitest": "^4.0.18"
20
24
  },
21
25
  "scripts": {
22
26
  "build": "tsc",
23
- "pub": "pnpm build && pnpm publish --access=public"
27
+ "pub": "pnpm build && pnpm publish --access=public",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "test:ui": "vitest --ui",
31
+ "test:coverage": "vitest --coverage",
32
+ "test:e2e": "vitest run tests/e2e",
33
+ "test:unit": "vitest run tests/unit"
24
34
  }
25
35
  }
@@ -13,4 +13,20 @@ type GeminiModels =
13
13
  | "gemini-3-flash"
14
14
  | "gemini-3-pro";
15
15
 
16
- export type AIModelNames = ChatGPTModels | GeminiModels;
16
+ type AnthropicModels = "claude-opus-4.5"
17
+ | "claude-haiku-4.5"
18
+ | "claude-sonnet-4.5"
19
+ | "claude-opus-4.1"
20
+ | "claude-opus-4"
21
+ | "claude-sonnet-4";
22
+
23
+ type OpenRouterProvidersModels =
24
+ | `google/${GeminiModels}`
25
+ | `openai/${ChatGPTModels}`
26
+ | `anthropic/${AnthropicModels}`
27
+
28
+ type OpenRouterModels =
29
+ | `openrouter:${OpenRouterProvidersModels}`
30
+ | `openrouter/${OpenRouterProvidersModels}`;
31
+
32
+ export type AIModelNames = ChatGPTModels | GeminiModels | OpenRouterModels;
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ import { LangchainTools } from "./langchain/tools";
16
16
  type LangchainConstructor = {
17
17
  googleGeminiToken?: string;
18
18
  openAIApiKey?: string;
19
+ openRouterApiKey?: string;
19
20
  };
20
21
 
21
22
  export type LangchainCallParams = {
@@ -47,7 +48,7 @@ export type LangchainCallStructuredOutputReturn<T> = Promise<{
47
48
  }>;
48
49
 
49
50
  export class Langchain {
50
- constructor(private tokens: LangchainConstructor) {}
51
+ constructor(private tokens: LangchainConstructor) { }
51
52
 
52
53
  async call(params: LangchainCallParams): LangchainCallReturn {
53
54
  const { messages } = params;
@@ -69,11 +70,18 @@ export class Langchain {
69
70
  async callStructuredOutput<T extends z.ZodSchema>(
70
71
  params: LangchainCallStructuredOutputParams<T>
71
72
  ): LangchainCallStructuredOutputReturn<typeof params.outputSchema> {
72
- const { outputSchema, messages } = params;
73
+ const { outputSchema, messages, aiModel } = params;
74
+
75
+ // Normaliza o schema para compatibilidade com OpenAI/OpenRouter
76
+ // OpenAI exige que todos os campos em properties estejam no array required
77
+ const normalizedSchema = this.normalizeSchemaForOpenAI(
78
+ outputSchema,
79
+ aiModel
80
+ );
73
81
 
74
82
  const agent = createAgent({
75
83
  ...this.standardAgent(params),
76
- responseFormat: outputSchema as any,
84
+ responseFormat: normalizedSchema as any,
77
85
  });
78
86
 
79
87
  const response = await agent.invoke({
@@ -85,6 +93,49 @@ export class Langchain {
85
93
  return { response: parsedResponse };
86
94
  }
87
95
 
96
+ /**
97
+ * Normaliza schemas Zod para compatibilidade com OpenAI/OpenRouter
98
+ * OpenAI exige que todos os campos em properties estejam no array required
99
+ * quando usa response_format: 'extract'
100
+ */
101
+ private normalizeSchemaForOpenAI<T extends z.ZodSchema>(
102
+ schema: T,
103
+ aiModel: string
104
+ ): z.ZodSchema {
105
+ // Apenas normaliza para modelos OpenAI/OpenRouter
106
+ const isOpenAIModel =
107
+ aiModel.startsWith("gpt") ||
108
+ aiModel.startsWith("openrouter:openai/") ||
109
+ aiModel.startsWith("openrouter/openai/");
110
+
111
+ if (!isOpenAIModel) {
112
+ return schema;
113
+ }
114
+
115
+ // Se o schema é um objeto Zod, precisamos normalizar campos opcionais
116
+ if (schema instanceof z.ZodObject) {
117
+ const shape = schema.shape;
118
+ const newShape: Record<string, z.ZodTypeAny> = {};
119
+
120
+ // Converte campos opcionais para nullable para compatibilidade com OpenAI
121
+ // OpenAI requer que todos os campos estejam no array required
122
+ for (const [key, value] of Object.entries(shape)) {
123
+ if (value instanceof z.ZodOptional) {
124
+ // Converte .optional() para .nullable() para compatibilidade com OpenAI
125
+ const innerType = value._def.innerType as z.ZodTypeAny;
126
+ // Usa z.union para criar um tipo nullable
127
+ newShape[key] = z.union([innerType, z.null()]);
128
+ } else {
129
+ newShape[key] = value;
130
+ }
131
+ }
132
+
133
+ return z.object(newShape);
134
+ }
135
+
136
+ return schema;
137
+ }
138
+
88
139
  getRawAgent(
89
140
  params: LangchainCallParams,
90
141
  outputSchema?: z.ZodSchema | undefined
@@ -118,6 +169,15 @@ export class Langchain {
118
169
  return LangchainModels.gemini(config);
119
170
  }
120
171
 
172
+ if (aiModel.startsWith("openrouter:") || aiModel.startsWith("openrouter/")) {
173
+ const modelName = aiModel.replace(/^openrouter[:/]/, "");
174
+ return LangchainModels.openrouter({
175
+ ...config,
176
+ model: modelName,
177
+ apiKey: this.tokens.openRouterApiKey,
178
+ });
179
+ }
180
+
121
181
  throw new Error("Model not supported");
122
182
  }
123
183
 
@@ -46,4 +46,26 @@ export class LangchainModels {
46
46
 
47
47
  return new ChatGoogleGenerativeAI(options);
48
48
  }
49
+
50
+ static openrouter(params: LLMModelConfig & { httpReferer?: string; title?: string }) {
51
+ const { apiKey, maxTokens, model, temperature, httpReferer, title } = params;
52
+
53
+ if (!apiKey)
54
+ throw new Error(
55
+ "OpenRouter API key is not passed in the model parameters"
56
+ );
57
+
58
+ const options: ChatOpenAIFields = {
59
+ model,
60
+ apiKey,
61
+ configuration: {
62
+ baseURL: "https://openrouter.ai/api/v1",
63
+ },
64
+ };
65
+
66
+ if (maxTokens) options.maxTokens = maxTokens;
67
+ if (temperature) options.temperature = temperature;
68
+
69
+ return new ChatOpenAI(options);
70
+ }
49
71
  }
@@ -0,0 +1,47 @@
1
+ # Testes End-to-End (E2E)
2
+
3
+ Estes testes fazem chamadas reais para as APIs das LLMs (OpenAI e Google Gemini).
4
+
5
+ ## Configuração
6
+
7
+ ### Onde colocar o arquivo .env?
8
+
9
+ **Coloque o arquivo `.env` na raiz do pacote `packages/ai/`** (não dentro de `tests/e2e/`).
10
+
11
+ 1. Copie o arquivo de exemplo:
12
+ ```bash
13
+ cd packages/ai
14
+ cp tests/e2e/env.example .env
15
+ ```
16
+
17
+ 2. Preencha as variáveis de ambiente no arquivo `.env`:
18
+ - `OPENAI_API_KEY`: Sua chave da API da OpenAI (necessária para testes com GPT)
19
+ - `GOOGLE_GEMINI_TOKEN`: Seu token da API do Google Gemini (necessária para testes com Gemini)
20
+ - `OPENROUTER_API_KEY`: Sua chave da API do OpenRouter (necessária para testes com OpenRouter)
21
+
22
+ ### Como funciona?
23
+
24
+ O arquivo `.env` é carregado automaticamente pelo `dotenv` configurado no `vitest.config.ts`. O arquivo `.env` deve estar em `packages/ai/.env` e será carregado quando você executar `pnpm test:e2e`.
25
+
26
+ ## Executando os testes
27
+
28
+ ### Todos os testes E2E
29
+ ```bash
30
+ pnpm test:e2e
31
+ ```
32
+
33
+ ### Apenas testes unitários
34
+ ```bash
35
+ pnpm test:unit
36
+ ```
37
+
38
+ ### Todos os testes (unitários + E2E)
39
+ ```bash
40
+ pnpm test
41
+ ```
42
+
43
+ ## Notas
44
+
45
+ - Os testes E2E são marcados com `skipIf` e só serão executados se as respectivas API keys estiverem configuradas
46
+ - Os testes E2E têm timeout de 30 segundos devido às chamadas de API
47
+ - **Atenção**: Estes testes consomem créditos das suas APIs. Use com moderação em desenvolvimento