Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions dev-packages/bun-integration-tests/node-suites/excludes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export const NO_AUTO_INSTRUMENTATION = [
'suites/tracing/mastra/test.ts',
'suites/tracing/mcp-handler-exact-once/test.ts',
'suites/tracing/mcp-server/**',
'suites/tracing/mistral-v2/test.ts',
'suites/tracing/mistral/test.ts',
'suites/tracing/mongodb-v4/test.ts',
'suites/tracing/mongodb-v5/test.ts',
Expand Down Expand Up @@ -210,6 +211,10 @@ const BUN_BUILD_EAGER_SUBSCRIPTION = ['suites/tracing/orchestrion-lazy-registrat
// `http.server.request.start`.
const BUN_BUILD_NO_HTTP_SERVER_INTEGRATION = ['suites/express/multiple-init/test.ts'];

// `@mistralai/mistralai` v3 statically imports its optional peer `@livekit/rtc-node`, so Bun cannot
// bundle the scenarios. `mistral-v2` still covers Mistral here.
const BUN_BUILD_UNBUNDLEABLE_DEPENDENCY = ['suites/tracing/mistral/test.ts'];

// Some or all tests fail with the bundled scenarios. The cause is not investigated yet. In
// `express/tracing` only the request data tests fail: they set `httpIntegration` options, and with
// `@sentry/bun` the request body comes from `bunHttpServerIntegration`.
Expand Down Expand Up @@ -247,5 +252,6 @@ export const BUN_BUILD_EXCLUDE = [
'**/node_modules/**',
...BUN_BUILD_EAGER_SUBSCRIPTION,
...BUN_BUILD_NO_HTTP_SERVER_INTEGRATION,
...BUN_BUILD_UNBUNDLEABLE_DEPENDENCY,
...BUN_BUILD_NOT_TRIAGED,
];
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const NOT_TRIAGED = [
'suites/tracing/koa/test.ts',
'suites/tracing/langchain/test.ts',
'suites/tracing/langgraph/test.ts',
'suites/tracing/mistral-v2/test.ts',
'suites/tracing/mistral/test.ts',
'suites/tracing/mongodb/test.ts',
'suites/tracing/mongoose-v5/test.ts',
Expand Down
2 changes: 1 addition & 1 deletion dev-packages/node-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"@langchain/core": "^0.3.80",
"@langchain/langgraph": "^0.2.32",
"@langchain/openai": "^0.5.0",
"@mistralai/mistralai": "2.6.4",
"@mistralai/mistralai": "3.3.0",
"@modelcontextprotocol/client": "^2.0.0",
"@modelcontextprotocol/server": "^2.0.0",
"@nestjs/common": "^11",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import {
GEN_AI_OPERATION_NAME,
GEN_AI_RESPONSE_ID,
GEN_AI_RESPONSE_STREAMING,
GEN_AI_USAGE_TOTAL_TOKENS,
SENTRY_ORIGIN,
} from '@sentry/conventions/attributes';
import { afterAll, describe, expect } from 'vitest';
import { cleanupChildProcesses, createEsmTests } from '../../../utils/runner';

const ORIGIN = 'auto.ai.mistralai';
const MISTRAL_V2 = { additionalDependencies: { '@mistralai/mistralai': '2.6.4' } };

// The `mistral` suite runs on the latest major; this keeps the still-supported v2 covered. The
// scenarios are shared, since the request and response shapes we read are the same across majors.
describe('Mistral integration (v2)', () => {
afterAll(() => {
cleanupChildProcesses();
});

createEsmTests(
__dirname,
'../mistral/scenario-chat.mjs',
'../mistral/instrument.mjs',
(createRunner, test) => {
test('creates chat and streamed chat spans on @mistralai/mistralai v2', async () => {
await createRunner()
.expect({
span: container => {
const chatSpan = container.items.find(
s => s.attributes[GEN_AI_RESPONSE_ID]?.value === 'chatcmpl-mock123',
);
expect(chatSpan).toBeDefined();
expect(chatSpan!.attributes[GEN_AI_OPERATION_NAME]?.value).toBe('chat');
expect(chatSpan!.attributes[SENTRY_ORIGIN]?.value).toBe(ORIGIN);
expect(chatSpan!.attributes[GEN_AI_USAGE_TOTAL_TOKENS]?.value).toBe(25);

const streamSpan = container.items.find(
s => s.attributes[GEN_AI_RESPONSE_ID]?.value === 'chatcmpl-stream-123',
);
expect(streamSpan).toBeDefined();
expect(streamSpan!.attributes[GEN_AI_RESPONSE_STREAMING]?.value).toBe(true);
expect(streamSpan!.attributes[GEN_AI_USAGE_TOTAL_TOKENS]?.value).toBe(30);
},
})
.start()
.completed();
});
},
MISTRAL_V2,
);

createEsmTests(
__dirname,
'../mistral/scenario-embeddings.mjs',
'../mistral/instrument.mjs',
(createRunner, test) => {
test('creates embeddings spans on @mistralai/mistralai v2', async () => {
await createRunner()
.expect({
span: container => {
const embeddingsSpan = container.items.find(
s => s.attributes[GEN_AI_OPERATION_NAME]?.value === 'embeddings',
);
expect(embeddingsSpan).toBeDefined();
expect(embeddingsSpan!.attributes[SENTRY_ORIGIN]?.value).toBe(ORIGIN);
},
})
.start()
.completed();
});
},
MISTRAL_V2,
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const ORIGIN = 'auto.ai.mistralai';
// Not exported from `@sentry/conventions` yet; the SDK defines it in `ai/core/gen-ai-attributes`.
const GEN_AI_REQUEST_STREAM = 'gen_ai.request.stream';

// ESM-only: `@mistralai/mistralai` v2 ships no CJS build, so CJS consumers load it via `require(esm)`,
// ESM-only: `@mistralai/mistralai` v2+ ships no CJS build, so CJS consumers load it via `require(esm)`,
// whose auto-instrumentation is inconsistent across Node versions. The SDK's native mode is ESM, so we
// only run the suite there.
describe('Mistral integration', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/server-utils/src/orchestrion/config/mistral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { InstrumentationConfig } from '../apmTypes';

import { getModuleNames } from './module-names';

// `@mistralai/mistralai` v2 is ESM-only, so there is a single built file per resource (no dual CJS/ESM
// `@mistralai/mistralai` v2+ is ESM-only, so there is a single built file per resource (no dual CJS/ESM
// variants). Each SDK resource class exposes async methods that return a thenable, so `kind: 'Auto'`
// resolves to `wrapPromise`; the `.stream` methods resolve to an async-iterable `EventStream`.
const MODULE = { name: '@mistralai/mistralai', versionRange: '>=2.0.0 <3' } as const;
const MODULE = { name: '@mistralai/mistralai', versionRange: '>=2.0.0 <4' } as const;

const CHAT_FILE = { ...MODULE, filePath: 'esm/sdk/chat.js' } as const;
const AGENTS_FILE = { ...MODULE, filePath: 'esm/sdk/agents.js' } as const;
Expand Down
100 changes: 92 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading