From fb8cf57bb79f15b25348b98f271b957add757278 Mon Sep 17 00:00:00 2001 From: Henri Date: Wed, 17 Jan 2024 15:11:51 +0100 Subject: [PATCH 01/10] Fix mistral client when using recent node "fetch" variable needs to be declared before being assigned, otherwise you get a "Uncaught ReferenceError" error --- src/client.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client.js b/src/client.js index d0a801b..b36cf6d 100644 --- a/src/client.js +++ b/src/client.js @@ -1,5 +1,8 @@ let isNode = false; +// initializeFetch() will populate this variable with a fetch implementation +let fetch; + const VERSION = '0.0.3'; const RETRY_STATUS_CODES = [429, 500, 502, 503, 504]; const ENDPOINT = 'https://api.mistral.ai'; From be90bbe27bb3af7cd14d205fc0a728ab6c9dd811 Mon Sep 17 00:00:00 2001 From: Alex Leventer <3254549+alexleventer@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:13:44 -0700 Subject: [PATCH 02/10] Update package.json version to match user-agent version num --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dae5bc3..70008ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mistralai/mistralai", - "version": "0.0.1", + "version": "0.0.3", "description": "", "author": "bam4d@mistral.ai", "license": "ISC", From 7f0ec341033146ab260b58fb35f50999d5664dd8 Mon Sep 17 00:00:00 2001 From: Dardan Bujupaj Date: Wed, 7 Feb 2024 20:19:21 +0100 Subject: [PATCH 03/10] add usage property to completion chunk type --- src/client.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client.d.ts b/src/client.d.ts index 5a82b60..d59bca3 100644 --- a/src/client.d.ts +++ b/src/client.d.ts @@ -68,6 +68,7 @@ declare module '@mistralai/mistralai' { created: number; model: string; choices: ChatCompletionResponseChunkChoice[]; + usage: TokenUsage | null; } export interface Embedding { From f57a8684a550097a374537e7c8de70b3e2ac91b5 Mon Sep 17 00:00:00 2001 From: Benjamin Michotte Date: Mon, 4 Mar 2024 15:54:36 +0100 Subject: [PATCH 04/10] add tool_calls in the signature of chat response --- src/client.d.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/client.d.ts b/src/client.d.ts index 45adc72..9061d0e 100644 --- a/src/client.d.ts +++ b/src/client.d.ts @@ -76,6 +76,7 @@ declare module '@mistralai/mistralai' { message: { role: string; content: string; + tool_calls: null | ToolCalls[]; }; finish_reason: string; } @@ -133,7 +134,7 @@ declare module '@mistralai/mistralai' { private _makeChatCompletionRequest( model: string, messages: Array<{ role: string; name?: string, content: string | string[], tool_calls?: ToolCalls[]; }>, - tools?: Array<{ type: string; function:Function; }>, + tools?: Array<{ type: string; function: Function; }>, temperature?: number, maxTokens?: number, topP?: number, @@ -153,7 +154,7 @@ declare module '@mistralai/mistralai' { chat(options: { model: string; messages: Array<{ role: string; name?: string, content: string | string[], tool_calls?: ToolCalls[]; }>; - tools?: Array<{ type: string; function:Function; }>; + tools?: Array<{ type: string; function: Function; }>; temperature?: number; maxTokens?: number; topP?: number; @@ -164,13 +165,13 @@ declare module '@mistralai/mistralai' { safeMode?: boolean; safePrompt?: boolean; toolChoice?: ToolChoice; - responseFormat?: ResponseFormat; + responseFormat?: ResponseFormat; }): Promise; chatStream(options: { model: string; messages: Array<{ role: string; name?: string, content: string | string[], tool_calls?: ToolCalls[]; }>; - tools?: Array<{ type: string; function:Function; }>; + tools?: Array<{ type: string; function: Function; }>; temperature?: number; maxTokens?: number; topP?: number; From 52a8a4bad93d1c3551b0893c7efa3c2e0e93dd96 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Mon, 29 Apr 2024 13:00:11 +0700 Subject: [PATCH 05/10] feat: update fetch configuration logic --- package.json | 2 +- src/client.js | 42 ++++++++++++++++++++---------------------- tests/client.test.js | 18 +++++++++--------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 70008ea..dae5bc3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mistralai/mistralai", - "version": "0.0.3", + "version": "0.0.1", "description": "", "author": "bam4d@mistral.ai", "license": "ISC", diff --git a/src/client.js b/src/client.js index 20fd639..42549ce 100644 --- a/src/client.js +++ b/src/client.js @@ -1,28 +1,14 @@ -let isNode = false; - -// initializeFetch() will populate this variable with a fetch implementation -let fetch; - const VERSION = '0.0.3'; const RETRY_STATUS_CODES = [429, 500, 502, 503, 504]; const ENDPOINT = 'https://api.mistral.ai'; -/** - * Initialize fetch - * @return {Promise} - */ -async function initializeFetch() { - if (typeof window === 'undefined' || - typeof globalThis.fetch === 'undefined') { - const nodeFetch = await import('node-fetch'); - fetch = nodeFetch.default; - isNode = true; - } else { - fetch = globalThis.fetch; - } -} +const isNode = typeof process !== 'undefined' && + process.versions != null && + process.versions.node != null; +const haveNativeFetch = typeof globalThis.fetch !== 'undefined'; -initializeFetch(); +const configuredFetch = isNode && !haveNativeFetch ? + (await import('node-fetch')).default : globalThis.fetch; /** * MistralAPIError @@ -70,6 +56,16 @@ class MistralClient { } } + /** + * @return {Promise} + * @private + * @param {...*} args - fetch args + * hook point for non-global fetch override + */ + async _fetch(...args) { + return configuredFetch(...args); + } + /** * * @param {*} method @@ -93,11 +89,13 @@ class MistralClient { for (let attempts = 0; attempts < this.maxRetries; attempts++) { try { - const response = await fetch(url, options); + const response = await this._fetch(url, options); if (response.ok) { if (request?.stream) { - if (isNode) { + if (isNode && !haveNativeFetch || + // The test mocks do not return a body with getReader + typeof response.body.getReader === 'undefined') { return response.body; } else { const reader = response.body.getReader(); diff --git a/tests/client.test.js b/tests/client.test.js index 30d85ec..54b52b6 100644 --- a/tests/client.test.js +++ b/tests/client.test.js @@ -20,7 +20,7 @@ describe('Mistral Client', () => { it('should return a chat response object', async() => { // Mock the fetch function const mockResponse = mockChatResponsePayload(); - globalThis.fetch = mockFetch(200, mockResponse); + client._fetch = mockFetch(200, mockResponse); const response = await client.chat({ model: 'mistral-small', @@ -37,7 +37,7 @@ describe('Mistral Client', () => { it('should return a chat response object if safeMode is set', async() => { // Mock the fetch function const mockResponse = mockChatResponsePayload(); - globalThis.fetch = mockFetch(200, mockResponse); + client._fetch = mockFetch(200, mockResponse); const response = await client.chat({ model: 'mistral-small', @@ -55,7 +55,7 @@ describe('Mistral Client', () => { it('should return a chat response object if safePrompt is set', async() => { // Mock the fetch function const mockResponse = mockChatResponsePayload(); - globalThis.fetch = mockFetch(200, mockResponse); + client._fetch = mockFetch(200, mockResponse); const response = await client.chat({ model: 'mistral-small', @@ -75,7 +75,7 @@ describe('Mistral Client', () => { it('should return parsed, streamed response', async() => { // Mock the fetch function const mockResponse = mockChatResponseStreamingPayload(); - globalThis.fetch = mockFetchStream(200, mockResponse); + client._fetch = mockFetchStream(200, mockResponse); const response = await client.chatStream({ model: 'mistral-small', @@ -98,7 +98,7 @@ describe('Mistral Client', () => { it('should return parsed, streamed response with safeMode', async() => { // Mock the fetch function const mockResponse = mockChatResponseStreamingPayload(); - globalThis.fetch = mockFetchStream(200, mockResponse); + client._fetch = mockFetchStream(200, mockResponse); const response = await client.chatStream({ model: 'mistral-small', @@ -122,7 +122,7 @@ describe('Mistral Client', () => { it('should return parsed, streamed response with safePrompt', async() => { // Mock the fetch function const mockResponse = mockChatResponseStreamingPayload(); - globalThis.fetch = mockFetchStream(200, mockResponse); + client._fetch = mockFetchStream(200, mockResponse); const response = await client.chatStream({ model: 'mistral-small', @@ -148,7 +148,7 @@ describe('Mistral Client', () => { it('should return embeddings', async() => { // Mock the fetch function const mockResponse = mockEmbeddingResponsePayload(); - globalThis.fetch = mockFetch(200, mockResponse); + client._fetch = mockFetch(200, mockResponse); const response = await client.embeddings(mockEmbeddingRequest); expect(response).toEqual(mockResponse); @@ -159,7 +159,7 @@ describe('Mistral Client', () => { it('should return batched embeddings', async() => { // Mock the fetch function const mockResponse = mockEmbeddingResponsePayload(10); - globalThis.fetch = mockFetch(200, mockResponse); + client._fetch = mockFetch(200, mockResponse); const response = await client.embeddings(mockEmbeddingRequest); expect(response).toEqual(mockResponse); @@ -170,7 +170,7 @@ describe('Mistral Client', () => { it('should return a list of models', async() => { // Mock the fetch function const mockResponse = mockListModels(); - globalThis.fetch = mockFetch(200, mockResponse); + client._fetch = mockFetch(200, mockResponse); const response = await client.listModels(); expect(response).toEqual(mockResponse); From cf56320c12562e7c97776385e4aaa668b32d3bd5 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 30 Apr 2024 06:34:35 +0700 Subject: [PATCH 06/10] feat: apply @fuegoio's simplification --- src/client.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/client.js b/src/client.js index 42549ce..07b7a11 100644 --- a/src/client.js +++ b/src/client.js @@ -2,13 +2,8 @@ const VERSION = '0.0.3'; const RETRY_STATUS_CODES = [429, 500, 502, 503, 504]; const ENDPOINT = 'https://api.mistral.ai'; -const isNode = typeof process !== 'undefined' && - process.versions != null && - process.versions.node != null; -const haveNativeFetch = typeof globalThis.fetch !== 'undefined'; - -const configuredFetch = isNode && !haveNativeFetch ? - (await import('node-fetch')).default : globalThis.fetch; +const configuredFetch = globalThis.fetch ?? + (await import('node-fetch')).default; /** * MistralAPIError @@ -93,9 +88,8 @@ class MistralClient { if (response.ok) { if (request?.stream) { - if (isNode && !haveNativeFetch || - // The test mocks do not return a body with getReader - typeof response.body.getReader === 'undefined') { + // When using node-fetch or test mocks getReader is not defined + if (typeof response.body.getReader === 'undefined') { return response.body; } else { const reader = response.body.getReader(); From 6e2dd95eea9bad0b473bc40115068c9f6ac93356 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 30 Apr 2024 06:40:59 +0700 Subject: [PATCH 07/10] fix: typo --- src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.js b/src/client.js index 07b7a11..ae70018 100644 --- a/src/client.js +++ b/src/client.js @@ -88,7 +88,7 @@ class MistralClient { if (response.ok) { if (request?.stream) { - // When using node-fetch or test mocks getReader is not defined + // When using node-fetch or test mocks, getReader is not defined if (typeof response.body.getReader === 'undefined') { return response.body; } else { From ded00ec12d5ff8a48af31ae6818a617058df8323 Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 30 Apr 2024 11:39:41 +0700 Subject: [PATCH 08/10] fix: future proof for commonjs --- src/client.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/client.js b/src/client.js index ae70018..6828820 100644 --- a/src/client.js +++ b/src/client.js @@ -2,8 +2,10 @@ const VERSION = '0.0.3'; const RETRY_STATUS_CODES = [429, 500, 502, 503, 504]; const ENDPOINT = 'https://api.mistral.ai'; -const configuredFetch = globalThis.fetch ?? - (await import('node-fetch')).default; +// We can't use a top level await if eventually this is to be converted +// to typescript and compiled to commonjs, or similarly using babel. +const configuredFetch = Promise.resolve( + globalThis.fetch ?? import('node-fetch').then((m) => m.default)); /** * MistralAPIError @@ -58,7 +60,8 @@ class MistralClient { * hook point for non-global fetch override */ async _fetch(...args) { - return configuredFetch(...args); + const fetchFunc = await configuredFetch; + return fetchFunc(...args); } /** From 6d8cbaf36668963f4ed95cca829c7fa88d71868c Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 30 Apr 2024 11:41:52 +0700 Subject: [PATCH 09/10] Revert "add tool_calls in the signature of chat response" This reverts commit f57a8684a550097a374537e7c8de70b3e2ac91b5. --- src/client.d.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/client.d.ts b/src/client.d.ts index 7209de4..2aad979 100644 --- a/src/client.d.ts +++ b/src/client.d.ts @@ -76,7 +76,6 @@ declare module '@mistralai/mistralai' { message: { role: string; content: string; - tool_calls: null | ToolCalls[]; }; finish_reason: string; } @@ -135,7 +134,7 @@ declare module '@mistralai/mistralai' { private _makeChatCompletionRequest( model: string, messages: Array<{ role: string; name?: string, content: string | string[], tool_calls?: ToolCalls[]; }>, - tools?: Array<{ type: string; function: Function; }>, + tools?: Array<{ type: string; function:Function; }>, temperature?: number, maxTokens?: number, topP?: number, @@ -155,7 +154,7 @@ declare module '@mistralai/mistralai' { chat(options: { model: string; messages: Array<{ role: string; name?: string, content: string | string[], tool_calls?: ToolCalls[]; }>; - tools?: Array<{ type: string; function: Function; }>; + tools?: Array<{ type: string; function:Function; }>; temperature?: number; maxTokens?: number; topP?: number; @@ -166,13 +165,13 @@ declare module '@mistralai/mistralai' { safeMode?: boolean; safePrompt?: boolean; toolChoice?: ToolChoice; - responseFormat?: ResponseFormat; + responseFormat?: ResponseFormat; }): Promise; chatStream(options: { model: string; messages: Array<{ role: string; name?: string, content: string | string[], tool_calls?: ToolCalls[]; }>; - tools?: Array<{ type: string; function: Function; }>; + tools?: Array<{ type: string; function:Function; }>; temperature?: number; maxTokens?: number; topP?: number; From 848d53929ec7ecc38a2075eb2d44db30f6a8a9ff Mon Sep 17 00:00:00 2001 From: Nicholas Dudfield Date: Tue, 30 Apr 2024 11:42:54 +0700 Subject: [PATCH 10/10] Revert "add usage property to completion chunk type" This reverts commit 7f0ec341033146ab260b58fb35f50999d5664dd8. --- src/client.d.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client.d.ts b/src/client.d.ts index 2aad979..45adc72 100644 --- a/src/client.d.ts +++ b/src/client.d.ts @@ -105,7 +105,6 @@ declare module '@mistralai/mistralai' { created: number; model: string; choices: ChatCompletionResponseChunkChoice[]; - usage: TokenUsage | null; } export interface Embedding {