Skip to content
Draft
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
1 change: 1 addition & 0 deletions dev-packages/node-integration-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@langchain/core": "^0.3.80",
"@langchain/langgraph": "^0.2.32",
"@langchain/openai": "^0.5.0",
"@mistralai/mistralai": "2.6.4",
"@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,16 @@
import * as Sentry from '@sentry/node';
import { loggingTransport } from '@sentry-internal/node-integration-tests';

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
transport: loggingTransport,
traceLifecycle: 'stream',
integrations: [
Sentry.mistralAIIntegration({
recordInputs: true,
recordOutputs: true,
}),
],
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as Sentry from '@sentry/node';
import { loggingTransport } from '@sentry-internal/node-integration-tests';

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
dataCollection: { genAI: { inputs: true, outputs: true } },
transport: loggingTransport,
traceLifecycle: 'stream',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as Sentry from '@sentry/node';
import { loggingTransport } from '@sentry-internal/node-integration-tests';

Sentry.init({
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
dataCollection: { genAI: { inputs: false, outputs: false } },
transport: loggingTransport,
traceLifecycle: 'stream',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { Mistral } from '@mistralai/mistralai';
import * as Sentry from '@sentry/node';
import express from 'express';

function startMockServer() {
const app = express();
app.use(express.json());

app.post('/v1/agents/completions', (req, res) => {
const { agent_id: agentId, stream } = req.body;

if (agentId === 'error-agent') {
res.status(404).set('x-request-id', 'mock-request-123').end('Agent not found');
return;
}

if (stream) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

const chunks = [
{
id: 'agentcmpl-stream-123',
object: 'chat.completion.chunk',
created: 1677652300,
model: 'mistral-large-latest',
choices: [
{
index: 0,
delta: { role: 'assistant', content: '' },
finish_reason: null,
},
],
},
{
id: 'agentcmpl-stream-123',
object: 'chat.completion.chunk',
created: 1677652300,
model: 'mistral-large-latest',
choices: [
{
index: 0,
delta: { content: 'Hello from Mistral agent streaming!' },
finish_reason: null,
},
],
},
{
id: 'agentcmpl-stream-123',
object: 'chat.completion.chunk',
created: 1677652300,
model: 'mistral-large-latest',
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
usage: { prompt_tokens: 12, completion_tokens: 18, total_tokens: 30 },
},
];

chunks.forEach((chunk, index) => {
setTimeout(() => {
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
if (index === chunks.length - 1) {
res.write('data: [DONE]\n\n');
res.end();
}
}, index * 10);
});
} else {
res.send({
id: 'agentcmpl-mock123',
object: 'chat.completion',
created: 1677652288,
model: 'mistral-large-latest',
choices: [
{
index: 0,
message: {
role: 'assistant',
content: 'Hello from Mistral agent!',
},
finish_reason: 'stop',
},
],
usage: { prompt_tokens: 10, completion_tokens: 15, total_tokens: 25 },
});
}
});

return new Promise(resolve => {
const server = app.listen(0, () => {
resolve(server);
});
});
}

async function run() {
const server = await startMockServer();

await Sentry.startSpan({ op: 'function', name: 'main' }, async () => {
const client = new Mistral({
apiKey: 'mock-api-key',
serverURL: `http://localhost:${server.address().port}`,
});

await client.agents.complete({
agentId: 'ag-mock-123',
messages: [{ role: 'user', content: 'Who is the best French painter?' }],
});

const stream = await client.agents.stream({
agentId: 'ag-mock-123',
messages: [{ role: 'user', content: 'Tell me about streaming' }],
});

for await (const event of stream) {
void event;
}
});

await Sentry.flush(2000);
server.close();
}

run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { Mistral } from '@mistralai/mistralai';
import * as Sentry from '@sentry/node';
import express from 'express';

function startMockServer() {
const app = express();
app.use(express.json());

app.post('/v1/chat/completions', (req, res) => {
const { model, stream } = req.body;

// error-model returns 404 (not retried by the SDK) so the span records an error
if (model === 'error-model') {
res.status(404).set('x-request-id', 'mock-request-123').end('Model not found');
return;
}

if (stream) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

const chunks = [
{
id: 'chatcmpl-stream-123',
object: 'chat.completion.chunk',
created: 1677652300,
model,
choices: [
{
index: 0,
delta: { role: 'assistant', content: '' },
finish_reason: null,
},
],
},
{
id: 'chatcmpl-stream-123',
object: 'chat.completion.chunk',
created: 1677652300,
model,
choices: [
{
index: 0,
delta: { content: 'Hello from Mistral streaming!' },
finish_reason: null,
},
],
},
{
id: 'chatcmpl-stream-123',
object: 'chat.completion.chunk',
created: 1677652300,
model,
choices: [{ index: 0, delta: {}, finish_reason: 'stop' }],
usage: { prompt_tokens: 12, completion_tokens: 18, total_tokens: 30 },
},
];

chunks.forEach((chunk, index) => {
setTimeout(() => {
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
if (index === chunks.length - 1) {
res.write('data: [DONE]\n\n');
res.end();
}
}, index * 10);
});
} else {
res.send({
id: 'chatcmpl-mock123',
object: 'chat.completion',
created: 1677652288,
model,
choices: [
{
index: 0,
message: { role: 'assistant', content: 'Hello from Mistral mock!' },
finish_reason: 'stop',
},
],
usage: { prompt_tokens: 10, completion_tokens: 15, total_tokens: 25 },
});
}
});

return new Promise(resolve => {
const server = app.listen(0, () => {
resolve(server);
});
});
}

async function run() {
const server = await startMockServer();

await Sentry.startSpan({ op: 'function', name: 'main' }, async () => {
const client = new Mistral({
apiKey: 'mock-api-key',
serverURL: `http://localhost:${server.address().port}`,
});

await client.chat.complete({
model: 'mistral-small-latest',
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: 'What is the capital of France?' },
],
temperature: 0.7,
maxTokens: 100,
});

try {
await client.chat.complete({
model: 'error-model',
messages: [{ role: 'user', content: 'This will fail' }],
});
} catch {
// expected
}

const stream = await client.chat.stream({
model: 'mistral-large-latest',
messages: [{ role: 'user', content: 'Tell me about streaming' }],
temperature: 0.8,
});

for await (const event of stream) {
void event;
}
});

await Sentry.flush(2000);
server.close();
}

run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Mistral } from '@mistralai/mistralai';
import * as Sentry from '@sentry/node';
import express from 'express';

function startMockServer() {
const app = express();
app.use(express.json());

app.post('/v1/embeddings', (req, res) => {
const { model, inputs } = req.body;

if (model === 'error-model') {
res.status(404).set('x-request-id', 'mock-request-123').end('Model not found');
return;
}

// Distinct id per call shape so tests can target the single-input span unambiguously.
res.send({
id: Array.isArray(inputs) ? 'embd-mock-multi' : 'embd-mock123',
object: 'list',
model,
data: [{ object: 'embedding', embedding: [0.1, 0.2, 0.3], index: 0 }],
usage: { prompt_tokens: 8, total_tokens: 8 },
});
});

return new Promise(resolve => {
const server = app.listen(0, () => {
resolve(server);
});
});
}

async function run() {
const server = await startMockServer();

await Sentry.startSpan({ op: 'function', name: 'main' }, async () => {
const client = new Mistral({
apiKey: 'mock-api-key',
serverURL: `http://localhost:${server.address().port}`,
});

await client.embeddings.create({
model: 'mistral-embed',
inputs: 'Embedding test!',
});

try {
await client.embeddings.create({
model: 'error-model',
inputs: 'Error embedding test!',
});
} catch {
// expected
}

await client.embeddings.create({
model: 'mistral-embed',
inputs: ['First input text', 'Second input text'],
});
});

await Sentry.flush(2000);
server.close();
}

run();
Loading
Loading