@blaxel/langgraph 0.2.49 → 0.2.50-preview.115

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 (39) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/.tsbuildinfo +1 -1
  3. package/dist/cjs/model/cohere.js +185 -3
  4. package/dist/cjs/model/google-genai.js +75 -12
  5. package/dist/cjs/model.js +27 -1
  6. package/dist/cjs/telemetry.js +2 -3
  7. package/dist/cjs/types/model/google-genai.d.ts +20 -3
  8. package/dist/cjs/types/model/xai.d.ts +2 -1
  9. package/dist/cjs/types/tools.d.ts +6 -2
  10. package/dist/esm/.tsbuildinfo +1 -1
  11. package/dist/esm/model/cohere.js +185 -3
  12. package/dist/esm/model/google-genai.js +74 -11
  13. package/dist/esm/model.js +27 -1
  14. package/dist/esm/telemetry.js +2 -3
  15. package/package.json +11 -10
  16. package/dist/cjs/model/google-genai/chat_models.js +0 -760
  17. package/dist/cjs/model/google-genai/embeddings.js +0 -111
  18. package/dist/cjs/model/google-genai/index.js +0 -18
  19. package/dist/cjs/model/google-genai/output_parsers.js +0 -51
  20. package/dist/cjs/model/google-genai/types.js +0 -2
  21. package/dist/cjs/model/google-genai/utils/common.js +0 -387
  22. package/dist/cjs/model/google-genai/utils/tools.js +0 -110
  23. package/dist/cjs/model/google-genai/utils/zod_to_genai_parameters.js +0 -46
  24. package/dist/cjs/types/model/google-genai/chat_models.d.ts +0 -557
  25. package/dist/cjs/types/model/google-genai/embeddings.d.ts +0 -94
  26. package/dist/cjs/types/model/google-genai/index.d.ts +0 -2
  27. package/dist/cjs/types/model/google-genai/output_parsers.d.ts +0 -20
  28. package/dist/cjs/types/model/google-genai/types.d.ts +0 -3
  29. package/dist/cjs/types/model/google-genai/utils/common.d.ts +0 -22
  30. package/dist/cjs/types/model/google-genai/utils/tools.d.ts +0 -10
  31. package/dist/cjs/types/model/google-genai/utils/zod_to_genai_parameters.d.ts +0 -13
  32. package/dist/esm/model/google-genai/chat_models.js +0 -756
  33. package/dist/esm/model/google-genai/embeddings.js +0 -107
  34. package/dist/esm/model/google-genai/index.js +0 -2
  35. package/dist/esm/model/google-genai/output_parsers.js +0 -47
  36. package/dist/esm/model/google-genai/types.js +0 -1
  37. package/dist/esm/model/google-genai/utils/common.js +0 -378
  38. package/dist/esm/model/google-genai/utils/tools.js +0 -107
  39. package/dist/esm/model/google-genai/utils/zod_to_genai_parameters.js +0 -41
@@ -11,7 +11,9 @@ export const createCohereFetcher = () => {
11
11
  // Extract all fields from args
12
12
  const { url, method, headers: argsHeaders, body, contentType, queryParameters, timeoutMs, withCredentials, abortSignal, requestType, responseType, duplex } = args;
13
13
  // Build URL with query parameters
14
- let requestUrl = url;
14
+ // Rewrite /v1/chat to /v2/chat for Cohere API v2 compatibility
15
+ let requestUrl = url.replace('/v1/chat', '/v2/chat');
16
+ const isV2Endpoint = requestUrl.includes('/v2/chat');
15
17
  if (queryParameters) {
16
18
  const params = new URLSearchParams();
17
19
  Object.entries(queryParameters).forEach(([key, value]) => {
@@ -57,7 +59,77 @@ export const createCohereFetcher = () => {
57
59
  let requestBody;
58
60
  if (body !== undefined) {
59
61
  if (requestType === 'json' || !requestType) {
60
- requestBody = JSON.stringify(body);
62
+ // Transform body for Cohere v2 API compatibility (only if using v2 endpoint)
63
+ let transformedBody = body;
64
+ if (isV2Endpoint && typeof body === 'object' && body !== null && !Array.isArray(body)) {
65
+ const bodyObj = body;
66
+ transformedBody = { ...bodyObj };
67
+ const transformedObj = transformedBody;
68
+ // Remove v1-only fields that are not supported in v2
69
+ const fieldsToRemove = ['chat_history'];
70
+ for (const field of fieldsToRemove) {
71
+ if (field in transformedObj) {
72
+ delete transformedObj[field];
73
+ }
74
+ }
75
+ // Convert 'message' to 'messages' format if message exists and messages doesn't
76
+ if ('message' in transformedObj && !('messages' in transformedObj)) {
77
+ const message = transformedObj.message;
78
+ if (typeof message === 'string' && message.trim().length > 0) {
79
+ // Convert single message string to messages array format
80
+ transformedObj.messages = [
81
+ {
82
+ role: 'user',
83
+ content: message,
84
+ },
85
+ ];
86
+ }
87
+ // Remove the old message field
88
+ delete transformedObj.message;
89
+ }
90
+ // Handle tool_results - v2 might use a different format, remove for now
91
+ if ('tool_results' in transformedObj) {
92
+ delete transformedObj.tool_results;
93
+ }
94
+ // Transform tools array to ensure each tool has a 'type' field (required by Cohere v2)
95
+ if ('tools' in transformedObj && Array.isArray(transformedObj.tools)) {
96
+ const tools = transformedObj.tools;
97
+ transformedObj.tools = tools.map((tool) => {
98
+ if (typeof tool === 'object' && tool !== null) {
99
+ const toolObj = tool;
100
+ // If tool already has 'type' field, keep it
101
+ if ('type' in toolObj) {
102
+ return toolObj;
103
+ }
104
+ // If tool has 'function' field (OpenAI format), wrap it with type
105
+ if ('function' in toolObj) {
106
+ return {
107
+ type: 'function',
108
+ function: toolObj.function,
109
+ };
110
+ }
111
+ // If tool has name/description/parameters (direct format), wrap it
112
+ if ('name' in toolObj && ('description' in toolObj || 'parameters' in toolObj)) {
113
+ return {
114
+ type: 'function',
115
+ function: {
116
+ name: toolObj.name,
117
+ description: toolObj.description || '',
118
+ parameters: toolObj.parameters || toolObj.inputSchema || {},
119
+ },
120
+ };
121
+ }
122
+ // Default: add type field
123
+ return {
124
+ type: 'function',
125
+ ...toolObj,
126
+ };
127
+ }
128
+ return tool;
129
+ });
130
+ }
131
+ }
132
+ requestBody = JSON.stringify(transformedBody);
61
133
  }
62
134
  else if (requestType === 'bytes' && body instanceof Uint8Array) {
63
135
  // Create a new ArrayBuffer from the Uint8Array to avoid SharedArrayBuffer issues
@@ -70,7 +142,82 @@ export const createCohereFetcher = () => {
70
142
  requestBody = body;
71
143
  }
72
144
  else if (typeof body === 'string') {
73
- requestBody = body;
145
+ // Parse and transform JSON strings (only if using v2 endpoint)
146
+ if (isV2Endpoint) {
147
+ try {
148
+ const parsed = JSON.parse(body);
149
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
150
+ const transformed = { ...parsed };
151
+ // Remove v1-only fields
152
+ if ('chat_history' in transformed) {
153
+ delete transformed.chat_history;
154
+ }
155
+ if ('tool_results' in transformed) {
156
+ delete transformed.tool_results;
157
+ }
158
+ // Convert 'message' to 'messages' format if message exists and messages doesn't
159
+ if ('message' in transformed && !('messages' in transformed)) {
160
+ const message = transformed.message;
161
+ if (typeof message === 'string' && message.trim().length > 0) {
162
+ transformed.messages = [
163
+ {
164
+ role: 'user',
165
+ content: message,
166
+ },
167
+ ];
168
+ }
169
+ delete transformed.message;
170
+ }
171
+ // Transform tools array to ensure each tool has a 'type' field (required by Cohere v2)
172
+ if ('tools' in transformed && Array.isArray(transformed.tools)) {
173
+ const tools = transformed.tools;
174
+ transformed.tools = tools.map((tool) => {
175
+ if (typeof tool === 'object' && tool !== null) {
176
+ const toolObj = tool;
177
+ // If tool already has 'type' field, keep it
178
+ if ('type' in toolObj) {
179
+ return toolObj;
180
+ }
181
+ // If tool has 'function' field (OpenAI format), wrap it with type
182
+ if ('function' in toolObj) {
183
+ return {
184
+ type: 'function',
185
+ function: toolObj.function,
186
+ };
187
+ }
188
+ // If tool has name/description/parameters (direct format), wrap it
189
+ if ('name' in toolObj && ('description' in toolObj || 'parameters' in toolObj)) {
190
+ return {
191
+ type: 'function',
192
+ function: {
193
+ name: toolObj.name,
194
+ description: toolObj.description || '',
195
+ parameters: toolObj.parameters || toolObj.inputSchema || {},
196
+ },
197
+ };
198
+ }
199
+ // Default: add type field
200
+ return {
201
+ type: 'function',
202
+ ...toolObj,
203
+ };
204
+ }
205
+ return tool;
206
+ });
207
+ }
208
+ requestBody = JSON.stringify(transformed);
209
+ }
210
+ else {
211
+ requestBody = body;
212
+ }
213
+ }
214
+ catch {
215
+ requestBody = body;
216
+ }
217
+ }
218
+ else {
219
+ requestBody = body;
220
+ }
74
221
  }
75
222
  else {
76
223
  requestBody = JSON.stringify(body);
@@ -123,6 +270,41 @@ export const createCohereFetcher = () => {
123
270
  else {
124
271
  // Default to JSON
125
272
  responseBody = await response.json();
273
+ // Transform v2 response format to v1 format for ChatCohere compatibility
274
+ if (isV2Endpoint && typeof responseBody === 'object' && responseBody !== null) {
275
+ const responseObj = responseBody;
276
+ if ('message' in responseObj && typeof responseObj.message === 'object' && responseObj.message !== null) {
277
+ const v2Message = responseObj.message;
278
+ // Extract text from content array
279
+ let text = '';
280
+ if (Array.isArray(v2Message.content)) {
281
+ const contentArray = v2Message.content;
282
+ // Find the text content block
283
+ const textBlock = contentArray.find((item) => item.type === 'text' && item.text);
284
+ if (textBlock && textBlock.text) {
285
+ text = textBlock.text;
286
+ }
287
+ else {
288
+ // Fallback: join all text-like content
289
+ text = contentArray
290
+ .map((item) => item.text || item.thinking || '')
291
+ .filter(Boolean)
292
+ .join('\n');
293
+ }
294
+ }
295
+ else if (typeof v2Message.content === 'string') {
296
+ text = v2Message.content;
297
+ }
298
+ // Transform to v1-like format that ChatCohere expects
299
+ const transformedResponse = {
300
+ ...responseObj,
301
+ text: text,
302
+ // Keep the original message structure in case ChatCohere needs it
303
+ message: responseObj.message,
304
+ };
305
+ responseBody = transformedResponse;
306
+ }
307
+ }
126
308
  }
127
309
  // Return success response in the format CohereClient expects
128
310
  return {
@@ -1,26 +1,89 @@
1
1
  import { authenticate, settings } from "@blaxel/core";
2
- import { ChatGoogleGenerativeAI } from "./google-genai/index.js";
2
+ import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
3
+ import { GoogleGenerativeAI as GenerativeAI } from "@google/generative-ai";
3
4
  /**
4
5
  * Custom ChatGoogleGenerativeAI that ensures authentication before each request
6
+ * and supports custom headers without modifying the library code
5
7
  */
6
8
  export class AuthenticatedChatGoogleGenerativeAI extends ChatGoogleGenerativeAI {
9
+ customHeaders;
10
+ constructorParams;
11
+ constructor(fields) {
12
+ super(fields);
13
+ // Store constructor parameters for recreating the client
14
+ this.constructorParams = {
15
+ apiKey: fields.apiKey,
16
+ apiVersion: fields.apiVersion,
17
+ baseUrl: fields.baseUrl,
18
+ model: fields.model,
19
+ safetySettings: fields.safetySettings,
20
+ stopSequences: fields.stopSequences,
21
+ maxOutputTokens: fields.maxOutputTokens,
22
+ temperature: fields.temperature,
23
+ topP: fields.topP,
24
+ topK: fields.topK,
25
+ json: fields.json,
26
+ thinkingConfig: fields.thinkingConfig,
27
+ };
28
+ this.customHeaders = fields.customHeaders;
29
+ // Initialize client with custom headers if provided
30
+ if (this.customHeaders) {
31
+ this.recreateClient();
32
+ }
33
+ }
34
+ /**
35
+ * Recreates the client with updated custom headers
36
+ * Uses type assertion to access the private client property
37
+ */
38
+ recreateClient() {
39
+ const apiKey = this.constructorParams.apiKey || this.apiKey;
40
+ if (!apiKey)
41
+ return;
42
+ // Get the processed model name from the base class (it removes "models/" prefix)
43
+ const model = this.model || this.constructorParams.model.replace(/^models\//, "");
44
+ const modelParams = {
45
+ model,
46
+ safetySettings: this.constructorParams.safetySettings,
47
+ generationConfig: {
48
+ candidateCount: 1,
49
+ stopSequences: this.constructorParams.stopSequences,
50
+ maxOutputTokens: this.constructorParams.maxOutputTokens,
51
+ temperature: this.constructorParams.temperature,
52
+ topP: this.constructorParams.topP,
53
+ topK: this.constructorParams.topK,
54
+ ...(this.constructorParams.json ? { responseMimeType: "application/json" } : {}),
55
+ ...(this.constructorParams.thinkingConfig
56
+ ? { thinkingConfig: this.constructorParams.thinkingConfig }
57
+ : {}),
58
+ },
59
+ };
60
+ const requestOptions = {
61
+ apiVersion: this.constructorParams.apiVersion,
62
+ baseUrl: this.constructorParams.baseUrl,
63
+ customHeaders: this.customHeaders,
64
+ };
65
+ // Use type assertion to access private client property
66
+ this.client = new GenerativeAI(apiKey).getGenerativeModel(modelParams, requestOptions);
67
+ }
7
68
  async _generate(messages, options, runManager) {
8
69
  // Authenticate before making the request
9
70
  await authenticate();
10
- this.customHeaders = {};
11
- for (const header in settings.headers) {
12
- this.customHeaders[header] = settings.headers[header];
13
- }
14
- this.client = this.initClient();
71
+ // Update custom headers from settings
72
+ this.customHeaders = { ...settings.headers };
73
+ // Recreate client with updated headers
74
+ this.recreateClient();
15
75
  return await super._generate(messages, options || {}, runManager);
16
76
  }
17
77
  async *_streamResponseChunks(messages, options, runManager) {
18
78
  // Authenticate before making the request
19
79
  await authenticate();
20
- this.customHeaders = {};
21
- for (const header in settings.headers) {
22
- this.customHeaders[header] = settings.headers[header];
23
- }
24
- yield* super._streamResponseChunks(messages, options || {}, runManager);
80
+ // Update custom headers from settings
81
+ this.customHeaders = { ...settings.headers };
82
+ // Recreate client with updated headers
83
+ this.recreateClient();
84
+ yield* super._streamResponseChunks(messages, options, runManager);
85
+ }
86
+ bindTools(tools, kwargs) {
87
+ return super.bindTools(tools, kwargs);
25
88
  }
26
89
  }
package/dist/esm/model.js CHANGED
@@ -3,9 +3,9 @@ import { ChatAnthropic } from "@langchain/anthropic";
3
3
  import { ChatCohere } from "@langchain/cohere";
4
4
  import { ChatDeepSeek } from "@langchain/deepseek";
5
5
  import { ChatOpenAI } from "@langchain/openai";
6
+ import { AuthenticatedChatGoogleGenerativeAI } from "./model/google-genai.js";
6
7
  import { CohereClient } from "cohere-ai";
7
8
  import { createCohereFetcher } from "./model/cohere.js";
8
- import { AuthenticatedChatGoogleGenerativeAI } from "./model/google-genai.js";
9
9
  import { ChatXAI } from "./model/xai.js";
10
10
  /**
11
11
  * Creates a custom fetch function that adds dynamic headers to each request
@@ -20,6 +20,24 @@ const authenticatedFetch = () => {
20
20
  ...dynamicHeaders,
21
21
  ...(init?.headers || {}),
22
22
  };
23
+ // Ensure Content-Type is set for JSON requests if body exists and Content-Type is not already set
24
+ if (init?.body && !headers['Content-Type'] && !headers['content-type']) {
25
+ // If body is an object, it will be serialized to JSON by fetch
26
+ // If body is a string, check if it looks like JSON
27
+ if (typeof init.body === 'string') {
28
+ const trimmed = init.body.trim();
29
+ if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
30
+ headers['Content-Type'] = 'application/json';
31
+ }
32
+ }
33
+ else {
34
+ // For non-string bodies (FormData, Blob, etc.), let fetch handle it
35
+ // For objects, assume JSON
36
+ if (typeof init.body === 'object' && !(init.body instanceof FormData) && !(init.body instanceof Blob)) {
37
+ headers['Content-Type'] = 'application/json';
38
+ }
39
+ }
40
+ }
23
41
  // Make the request with merged headers
24
42
  return await fetch(input, {
25
43
  ...init,
@@ -60,6 +78,11 @@ export const blModel = async (model, options) => {
60
78
  });
61
79
  }
62
80
  else if (type === "cohere") {
81
+ // ChatCohere requires a custom client with fetcher for:
82
+ // 1. Dynamic authentication headers (settings.headers)
83
+ // 2. Custom environment URL (url)
84
+ // 3. URL rewriting (v1 -> v2) and body transformation for v2 compatibility
85
+ // @ts-ignore Error in langgraph
63
86
  return new ChatCohere({
64
87
  apiKey: "replaced",
65
88
  model: modelData?.spec?.runtime?.model,
@@ -72,6 +95,7 @@ export const blModel = async (model, options) => {
72
95
  });
73
96
  }
74
97
  else if (type === "deepseek") {
98
+ // @ts-ignore Error in langgraph
75
99
  return new ChatDeepSeek({
76
100
  apiKey: "replaced",
77
101
  model: modelData?.spec?.runtime?.model,
@@ -84,9 +108,11 @@ export const blModel = async (model, options) => {
84
108
  });
85
109
  }
86
110
  else if (type === "anthropic") {
111
+ // @ts-ignore Error in langgraph
87
112
  return new ChatAnthropic({
88
113
  anthropicApiUrl: url,
89
114
  model: modelData?.spec?.runtime?.model,
115
+ apiKey: "replaced",
90
116
  clientOptions: {
91
117
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
92
118
  fetch: authenticatedFetch(),
@@ -1,15 +1,14 @@
1
1
  import * as RunnableModule from "@langchain/core/runnables";
2
2
  import * as ToolsModule from "@langchain/core/tools";
3
+ import * as AgentsModule from "@langchain/core/agents";
3
4
  import * as VectorStoresModule from "@langchain/core/vectorstores";
4
5
  import { registerInstrumentations } from "@opentelemetry/instrumentation";
5
6
  import { LangChainInstrumentation } from "@traceloop/instrumentation-langchain";
6
- import * as AgentsModule from "langchain/agents";
7
- import * as ChainsModule from "langchain/chains";
8
7
  const langchain = new LangChainInstrumentation();
9
8
  langchain.manuallyInstrument({
9
+ // @ts-ignore - Type definitions may be incorrect, but the method accepts these parameters at runtime
10
10
  runnablesModule: RunnableModule,
11
11
  toolsModule: ToolsModule,
12
- chainsModule: ChainsModule,
13
12
  agentsModule: AgentsModule,
14
13
  vectorStoreModule: VectorStoresModule,
15
14
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaxel/langgraph",
3
- "version": "0.2.49",
3
+ "version": "0.2.50-preview.115",
4
4
  "description": "Blaxel SDK for TypeScript",
5
5
  "license": "MIT",
6
6
  "author": "Blaxel, INC (https://blaxel.ai)",
@@ -41,18 +41,19 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@google/generative-ai": "^0.24.1",
44
- "@langchain/anthropic": "^0.3.20",
45
- "@langchain/cohere": "^0.3.3",
46
- "@langchain/core": "^0.3.51",
47
- "@langchain/deepseek": "^0.0.1",
48
- "@langchain/openai": "^0.5.10",
44
+ "@langchain/anthropic": "^1.1.1",
45
+ "@langchain/cohere": "^1.0.0",
46
+ "@langchain/core": "^1.0.6",
47
+ "@langchain/deepseek": "^1.0.1",
48
+ "@langchain/google-genai": "^1.0.3",
49
+ "@langchain/openai": "^1.1.2",
49
50
  "@opentelemetry/instrumentation": "^0.200.0",
50
- "@traceloop/instrumentation-langchain": "^0.13.0",
51
- "cohere-ai": "^7.17.1",
52
- "langchain": "^0.3.24",
51
+ "@traceloop/instrumentation-langchain": "^0.20.0",
52
+ "cohere-ai": "^7.19.0",
53
+ "langchain": "^1.0.6",
53
54
  "zod": "^3.24.3",
54
55
  "zod-to-json-schema": "^3.24.5",
55
- "@blaxel/core": "0.2.49"
56
+ "@blaxel/core": "0.2.50-preview.115"
56
57
  },
57
58
  "devDependencies": {
58
59
  "@eslint/js": "^9.26.0",