@contractspec/integration.providers-impls 3.8.9 → 3.8.10

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 (147) hide show
  1. package/dist/analytics.js +1 -2
  2. package/dist/calendar.js +1 -2
  3. package/dist/database.js +1 -2
  4. package/dist/email.js +1 -2
  5. package/dist/embedding.js +1 -2
  6. package/dist/health.js +1 -2
  7. package/dist/impls/async-event-queue.js +1 -48
  8. package/dist/impls/composio-fallback-resolver.js +1 -579
  9. package/dist/impls/composio-mcp.js +1 -163
  10. package/dist/impls/composio-proxies.js +1 -310
  11. package/dist/impls/composio-sdk.js +1 -77
  12. package/dist/impls/composio-types.js +1 -53
  13. package/dist/impls/elevenlabs-voice.js +1 -104
  14. package/dist/impls/fal-voice.js +1 -117
  15. package/dist/impls/fathom-meeting-recorder.js +2 -289
  16. package/dist/impls/fathom-meeting-recorder.mapper.js +1 -107
  17. package/dist/impls/fathom-meeting-recorder.utils.js +1 -74
  18. package/dist/impls/fathom-meeting-recorder.webhooks.js +1 -31
  19. package/dist/impls/fireflies-meeting-recorder.js +5 -203
  20. package/dist/impls/fireflies-meeting-recorder.queries.js +4 -14
  21. package/dist/impls/fireflies-meeting-recorder.utils.js +1 -44
  22. package/dist/impls/gcs-storage.js +1 -99
  23. package/dist/impls/gmail-inbound.js +1 -229
  24. package/dist/impls/gmail-outbound.js +25 -137
  25. package/dist/impls/google-calendar.js +1 -193
  26. package/dist/impls/gradium-voice.js +1 -95
  27. package/dist/impls/granola-meeting-recorder.js +3 -514
  28. package/dist/impls/granola-meeting-recorder.mcp.js +1 -280
  29. package/dist/impls/health/base-health-provider.js +1 -617
  30. package/dist/impls/health/hybrid-health-providers.js +1 -1089
  31. package/dist/impls/health/official-health-providers.js +1 -969
  32. package/dist/impls/health/provider-normalizers.js +1 -288
  33. package/dist/impls/health/providers.js +1 -1095
  34. package/dist/impls/health-provider-factory.js +1 -1309
  35. package/dist/impls/index.js +42 -7448
  36. package/dist/impls/jira.js +1 -126
  37. package/dist/impls/linear.js +1 -85
  38. package/dist/impls/messaging-github.js +1 -111
  39. package/dist/impls/messaging-slack.js +1 -81
  40. package/dist/impls/messaging-telegram.js +1 -48
  41. package/dist/impls/messaging-whatsapp-meta.js +1 -53
  42. package/dist/impls/messaging-whatsapp-twilio.js +1 -83
  43. package/dist/impls/mistral-conversational.js +2 -477
  44. package/dist/impls/mistral-conversational.session.js +2 -207
  45. package/dist/impls/mistral-embedding.js +1 -45
  46. package/dist/impls/mistral-llm.js +1 -271
  47. package/dist/impls/mistral-stt.js +1 -168
  48. package/dist/impls/notion.js +1 -162
  49. package/dist/impls/posthog-reader.js +1 -161
  50. package/dist/impls/posthog-utils.js +1 -40
  51. package/dist/impls/posthog.js +1 -324
  52. package/dist/impls/postmark-email.js +1 -62
  53. package/dist/impls/powens-client.js +1 -197
  54. package/dist/impls/powens-openbanking.js +1 -428
  55. package/dist/impls/provider-factory.js +18 -6268
  56. package/dist/impls/qdrant-vector.js +1 -80
  57. package/dist/impls/stripe-payments.js +1 -230
  58. package/dist/impls/supabase-psql.js +1 -152
  59. package/dist/impls/supabase-vector.js +9 -298
  60. package/dist/impls/tldv-meeting-recorder.js +2 -147
  61. package/dist/impls/twilio-sms.js +1 -67
  62. package/dist/index.js +42 -7495
  63. package/dist/llm.js +1 -2
  64. package/dist/meeting-recorder.js +1 -2
  65. package/dist/messaging.js +1 -2
  66. package/dist/node/analytics.js +1 -2
  67. package/dist/node/calendar.js +1 -2
  68. package/dist/node/database.js +1 -2
  69. package/dist/node/email.js +1 -2
  70. package/dist/node/embedding.js +1 -2
  71. package/dist/node/health.js +1 -2
  72. package/dist/node/impls/async-event-queue.js +1 -49
  73. package/dist/node/impls/composio-fallback-resolver.js +1 -580
  74. package/dist/node/impls/composio-mcp.js +1 -164
  75. package/dist/node/impls/composio-proxies.js +1 -311
  76. package/dist/node/impls/composio-sdk.js +1 -78
  77. package/dist/node/impls/composio-types.js +1 -54
  78. package/dist/node/impls/elevenlabs-voice.js +1 -105
  79. package/dist/node/impls/fal-voice.js +1 -118
  80. package/dist/node/impls/fathom-meeting-recorder.js +2 -290
  81. package/dist/node/impls/fathom-meeting-recorder.mapper.js +1 -108
  82. package/dist/node/impls/fathom-meeting-recorder.utils.js +1 -75
  83. package/dist/node/impls/fathom-meeting-recorder.webhooks.js +1 -32
  84. package/dist/node/impls/fireflies-meeting-recorder.js +5 -204
  85. package/dist/node/impls/fireflies-meeting-recorder.queries.js +4 -15
  86. package/dist/node/impls/fireflies-meeting-recorder.utils.js +1 -45
  87. package/dist/node/impls/gcs-storage.js +1 -100
  88. package/dist/node/impls/gmail-inbound.js +1 -230
  89. package/dist/node/impls/gmail-outbound.js +25 -138
  90. package/dist/node/impls/google-calendar.js +1 -194
  91. package/dist/node/impls/gradium-voice.js +1 -96
  92. package/dist/node/impls/granola-meeting-recorder.js +3 -515
  93. package/dist/node/impls/granola-meeting-recorder.mcp.js +1 -281
  94. package/dist/node/impls/health/base-health-provider.js +1 -618
  95. package/dist/node/impls/health/hybrid-health-providers.js +1 -1090
  96. package/dist/node/impls/health/official-health-providers.js +1 -970
  97. package/dist/node/impls/health/provider-normalizers.js +1 -289
  98. package/dist/node/impls/health/providers.js +1 -1096
  99. package/dist/node/impls/health-provider-factory.js +1 -1310
  100. package/dist/node/impls/index.js +42 -7449
  101. package/dist/node/impls/jira.js +1 -127
  102. package/dist/node/impls/linear.js +1 -86
  103. package/dist/node/impls/messaging-github.js +1 -112
  104. package/dist/node/impls/messaging-slack.js +1 -82
  105. package/dist/node/impls/messaging-telegram.js +1 -49
  106. package/dist/node/impls/messaging-whatsapp-meta.js +1 -54
  107. package/dist/node/impls/messaging-whatsapp-twilio.js +1 -84
  108. package/dist/node/impls/mistral-conversational.js +2 -478
  109. package/dist/node/impls/mistral-conversational.session.js +2 -208
  110. package/dist/node/impls/mistral-embedding.js +1 -46
  111. package/dist/node/impls/mistral-llm.js +1 -272
  112. package/dist/node/impls/mistral-stt.js +1 -169
  113. package/dist/node/impls/notion.js +1 -163
  114. package/dist/node/impls/posthog-reader.js +1 -162
  115. package/dist/node/impls/posthog-utils.js +1 -41
  116. package/dist/node/impls/posthog.js +1 -325
  117. package/dist/node/impls/postmark-email.js +1 -63
  118. package/dist/node/impls/powens-client.js +1 -198
  119. package/dist/node/impls/powens-openbanking.js +1 -429
  120. package/dist/node/impls/provider-factory.js +18 -6269
  121. package/dist/node/impls/qdrant-vector.js +1 -81
  122. package/dist/node/impls/stripe-payments.js +1 -231
  123. package/dist/node/impls/supabase-psql.js +1 -153
  124. package/dist/node/impls/supabase-vector.js +9 -299
  125. package/dist/node/impls/tldv-meeting-recorder.js +2 -148
  126. package/dist/node/impls/twilio-sms.js +1 -68
  127. package/dist/node/index.js +42 -7496
  128. package/dist/node/llm.js +1 -2
  129. package/dist/node/meeting-recorder.js +1 -2
  130. package/dist/node/messaging.js +1 -2
  131. package/dist/node/openbanking.js +1 -2
  132. package/dist/node/payments.js +1 -2
  133. package/dist/node/project-management.js +1 -2
  134. package/dist/node/secrets/provider.js +1 -14
  135. package/dist/node/sms.js +1 -2
  136. package/dist/node/storage.js +1 -2
  137. package/dist/node/vector-store.js +1 -2
  138. package/dist/node/voice.js +1 -2
  139. package/dist/openbanking.js +1 -2
  140. package/dist/payments.js +1 -2
  141. package/dist/project-management.js +1 -2
  142. package/dist/secrets/provider.js +1 -13
  143. package/dist/sms.js +1 -2
  144. package/dist/storage.js +1 -2
  145. package/dist/vector-store.js +1 -2
  146. package/dist/voice.js +1 -2
  147. package/package.json +16 -16
@@ -1,478 +1,3 @@
1
1
  // @bun
2
- var __require = import.meta.require;
3
-
4
- // src/impls/async-event-queue.ts
5
- class AsyncEventQueue {
6
- values = [];
7
- waiters = [];
8
- done = false;
9
- push(value) {
10
- if (this.done) {
11
- return;
12
- }
13
- const waiter = this.waiters.shift();
14
- if (waiter) {
15
- waiter({ value, done: false });
16
- return;
17
- }
18
- this.values.push(value);
19
- }
20
- close() {
21
- if (this.done) {
22
- return;
23
- }
24
- this.done = true;
25
- for (const waiter of this.waiters) {
26
- waiter({ value: undefined, done: true });
27
- }
28
- this.waiters.length = 0;
29
- }
30
- [Symbol.asyncIterator]() {
31
- return {
32
- next: async () => {
33
- const value = this.values.shift();
34
- if (value != null) {
35
- return { value, done: false };
36
- }
37
- if (this.done) {
38
- return { value: undefined, done: true };
39
- }
40
- return new Promise((resolve) => {
41
- this.waiters.push(resolve);
42
- });
43
- }
44
- };
45
- }
46
- }
47
-
48
- // src/impls/mistral-conversational.session.ts
49
- class MistralConversationSession {
50
- events;
51
- queue = new AsyncEventQueue;
52
- turns = [];
53
- history = [];
54
- sessionId = crypto.randomUUID();
55
- startedAt = Date.now();
56
- sessionConfig;
57
- defaultModel;
58
- complete;
59
- sttProvider;
60
- pending = Promise.resolve();
61
- closed = false;
62
- closedSummary;
63
- constructor(options) {
64
- this.sessionConfig = options.sessionConfig;
65
- this.defaultModel = options.defaultModel;
66
- this.complete = options.complete;
67
- this.sttProvider = options.sttProvider;
68
- this.events = this.queue;
69
- this.queue.push({
70
- type: "session_started",
71
- sessionId: this.sessionId
72
- });
73
- }
74
- sendAudio(chunk) {
75
- if (this.closed) {
76
- return;
77
- }
78
- this.pending = this.pending.then(async () => {
79
- const transcription = await this.sttProvider.transcribe({
80
- audio: {
81
- data: chunk,
82
- format: this.sessionConfig.inputFormat ?? "pcm",
83
- sampleRateHz: 16000
84
- },
85
- language: this.sessionConfig.language
86
- });
87
- const transcriptText = transcription.text.trim();
88
- if (transcriptText.length > 0) {
89
- await this.handleUserText(transcriptText);
90
- }
91
- }).catch((error) => {
92
- this.emitError(error);
93
- });
94
- }
95
- sendText(text) {
96
- if (this.closed) {
97
- return;
98
- }
99
- const normalized = text.trim();
100
- if (normalized.length === 0) {
101
- return;
102
- }
103
- this.pending = this.pending.then(() => this.handleUserText(normalized)).catch((error) => {
104
- this.emitError(error);
105
- });
106
- }
107
- interrupt() {
108
- if (this.closed) {
109
- return;
110
- }
111
- this.queue.push({
112
- type: "error",
113
- error: new Error("Interrupt is not supported for non-streaming sessions.")
114
- });
115
- }
116
- async close() {
117
- if (this.closedSummary) {
118
- return this.closedSummary;
119
- }
120
- this.closed = true;
121
- await this.pending;
122
- const durationMs = Date.now() - this.startedAt;
123
- const summary = {
124
- sessionId: this.sessionId,
125
- durationMs,
126
- turns: this.turns.map((turn) => ({
127
- role: turn.role === "assistant" ? "agent" : turn.role,
128
- text: turn.text,
129
- startMs: turn.startMs,
130
- endMs: turn.endMs
131
- })),
132
- transcript: this.turns.map((turn) => `${turn.role}: ${turn.text}`).join(`
133
- `)
134
- };
135
- this.closedSummary = summary;
136
- this.queue.push({
137
- type: "session_ended",
138
- reason: "closed_by_client",
139
- durationMs
140
- });
141
- this.queue.close();
142
- return summary;
143
- }
144
- async handleUserText(text) {
145
- if (this.closed) {
146
- return;
147
- }
148
- const userStart = Date.now();
149
- this.queue.push({ type: "user_speech_started" });
150
- this.queue.push({ type: "user_speech_ended", transcript: text });
151
- this.queue.push({
152
- type: "transcript",
153
- role: "user",
154
- text,
155
- timestamp: userStart
156
- });
157
- this.turns.push({
158
- role: "user",
159
- text,
160
- startMs: userStart,
161
- endMs: Date.now()
162
- });
163
- this.history.push({ role: "user", content: text });
164
- const assistantStart = Date.now();
165
- const assistantText = await this.complete(this.history, {
166
- ...this.sessionConfig,
167
- llmModel: this.sessionConfig.llmModel ?? this.defaultModel
168
- });
169
- if (this.closed) {
170
- return;
171
- }
172
- const normalizedAssistantText = assistantText.trim();
173
- const finalAssistantText = normalizedAssistantText.length > 0 ? normalizedAssistantText : "I was unable to produce a response.";
174
- this.queue.push({
175
- type: "agent_speech_started",
176
- text: finalAssistantText
177
- });
178
- this.queue.push({
179
- type: "transcript",
180
- role: "agent",
181
- text: finalAssistantText,
182
- timestamp: assistantStart
183
- });
184
- this.queue.push({ type: "agent_speech_ended" });
185
- this.turns.push({
186
- role: "assistant",
187
- text: finalAssistantText,
188
- startMs: assistantStart,
189
- endMs: Date.now()
190
- });
191
- this.history.push({ role: "assistant", content: finalAssistantText });
192
- }
193
- emitError(error) {
194
- if (this.closed) {
195
- return;
196
- }
197
- this.queue.push({ type: "error", error: toError(error) });
198
- }
199
- }
200
- function toError(error) {
201
- if (error instanceof Error) {
202
- return error;
203
- }
204
- return new Error(String(error));
205
- }
206
-
207
- // src/impls/mistral-stt.ts
208
- var DEFAULT_BASE_URL = "https://api.mistral.ai/v1";
209
- var DEFAULT_MODEL = "voxtral-mini-latest";
210
- var AUDIO_MIME_BY_FORMAT = {
211
- mp3: "audio/mpeg",
212
- wav: "audio/wav",
213
- ogg: "audio/ogg",
214
- pcm: "audio/pcm",
215
- opus: "audio/opus"
216
- };
217
-
218
- class MistralSttProvider {
219
- apiKey;
220
- defaultModel;
221
- defaultLanguage;
222
- baseUrl;
223
- fetchImpl;
224
- constructor(options) {
225
- if (!options.apiKey) {
226
- throw new Error("MistralSttProvider requires an apiKey");
227
- }
228
- this.apiKey = options.apiKey;
229
- this.defaultModel = options.defaultModel ?? DEFAULT_MODEL;
230
- this.defaultLanguage = options.defaultLanguage;
231
- this.baseUrl = normalizeBaseUrl(options.serverURL ?? DEFAULT_BASE_URL);
232
- this.fetchImpl = options.fetchImpl ?? fetch;
233
- }
234
- async transcribe(input) {
235
- const formData = new FormData;
236
- const model = input.model ?? this.defaultModel;
237
- const mimeType = AUDIO_MIME_BY_FORMAT[input.audio.format] ?? "audio/wav";
238
- const fileName = `audio.${input.audio.format}`;
239
- const audioBytes = new Uint8Array(input.audio.data);
240
- const blob = new Blob([audioBytes], { type: mimeType });
241
- formData.append("file", blob, fileName);
242
- formData.append("model", model);
243
- formData.append("response_format", "verbose_json");
244
- const language = input.language ?? this.defaultLanguage;
245
- if (language) {
246
- formData.append("language", language);
247
- }
248
- const response = await this.fetchImpl(`${this.baseUrl}/audio/transcriptions`, {
249
- method: "POST",
250
- headers: {
251
- Authorization: `Bearer ${this.apiKey}`
252
- },
253
- body: formData
254
- });
255
- if (!response.ok) {
256
- const body = await response.text();
257
- throw new Error(`Mistral transcription request failed (${response.status}): ${body}`);
258
- }
259
- const payload = await response.json();
260
- return toTranscriptionResult(payload, input);
261
- }
262
- }
263
- function toTranscriptionResult(payload, input) {
264
- const record = asRecord(payload);
265
- const text = readString(record, "text") ?? "";
266
- const language = readString(record, "language") ?? input.language ?? "unknown";
267
- const segments = parseSegments(record);
268
- if (segments.length === 0 && text.length > 0) {
269
- segments.push({
270
- text,
271
- startMs: 0,
272
- endMs: input.audio.durationMs ?? 0
273
- });
274
- }
275
- const durationMs = input.audio.durationMs ?? segments.reduce((max, segment) => Math.max(max, segment.endMs), 0);
276
- const topLevelWords = parseWordTimings(record.words);
277
- const flattenedWords = segments.flatMap((segment) => segment.wordTimings ?? []);
278
- const wordTimings = topLevelWords.length > 0 ? topLevelWords : flattenedWords.length > 0 ? flattenedWords : undefined;
279
- const speakers = dedupeSpeakers(segments);
280
- return {
281
- text,
282
- segments,
283
- language,
284
- durationMs,
285
- speakers: speakers.length > 0 ? speakers : undefined,
286
- wordTimings
287
- };
288
- }
289
- function parseSegments(record) {
290
- if (!Array.isArray(record.segments)) {
291
- return [];
292
- }
293
- const parsed = [];
294
- for (const entry of record.segments) {
295
- const segmentRecord = asRecord(entry);
296
- const text = readString(segmentRecord, "text");
297
- if (!text) {
298
- continue;
299
- }
300
- const startSeconds = readNumber(segmentRecord, "start") ?? 0;
301
- const endSeconds = readNumber(segmentRecord, "end") ?? startSeconds;
302
- parsed.push({
303
- text,
304
- startMs: secondsToMs(startSeconds),
305
- endMs: secondsToMs(endSeconds),
306
- speakerId: readString(segmentRecord, "speaker") ?? undefined,
307
- confidence: readNumber(segmentRecord, "confidence"),
308
- wordTimings: parseWordTimings(segmentRecord.words)
309
- });
310
- }
311
- return parsed;
312
- }
313
- function parseWordTimings(value) {
314
- if (!Array.isArray(value)) {
315
- return [];
316
- }
317
- const words = [];
318
- for (const entry of value) {
319
- const wordRecord = asRecord(entry);
320
- const word = readString(wordRecord, "word");
321
- const startSeconds = readNumber(wordRecord, "start");
322
- const endSeconds = readNumber(wordRecord, "end");
323
- if (!word || startSeconds == null || endSeconds == null) {
324
- continue;
325
- }
326
- words.push({
327
- word,
328
- startMs: secondsToMs(startSeconds),
329
- endMs: secondsToMs(endSeconds),
330
- confidence: readNumber(wordRecord, "confidence")
331
- });
332
- }
333
- return words;
334
- }
335
- function dedupeSpeakers(segments) {
336
- const seen = new Set;
337
- const speakers = [];
338
- for (const segment of segments) {
339
- if (!segment.speakerId || seen.has(segment.speakerId)) {
340
- continue;
341
- }
342
- seen.add(segment.speakerId);
343
- speakers.push({
344
- id: segment.speakerId,
345
- name: segment.speakerName
346
- });
347
- }
348
- return speakers;
349
- }
350
- function normalizeBaseUrl(url) {
351
- return url.endsWith("/") ? url.slice(0, -1) : url;
352
- }
353
- function asRecord(value) {
354
- if (value && typeof value === "object") {
355
- return value;
356
- }
357
- return {};
358
- }
359
- function readString(record, key) {
360
- const value = record[key];
361
- return typeof value === "string" ? value : undefined;
362
- }
363
- function readNumber(record, key) {
364
- const value = record[key];
365
- return typeof value === "number" ? value : undefined;
366
- }
367
- function secondsToMs(value) {
368
- return Math.round(value * 1000);
369
- }
370
-
371
- // src/impls/mistral-conversational.ts
372
- var DEFAULT_BASE_URL2 = "https://api.mistral.ai/v1";
373
- var DEFAULT_MODEL2 = "mistral-small-latest";
374
- var DEFAULT_VOICE = "default";
375
-
376
- class MistralConversationalProvider {
377
- apiKey;
378
- defaultModel;
379
- defaultVoiceId;
380
- baseUrl;
381
- fetchImpl;
382
- sttProvider;
383
- constructor(options) {
384
- if (!options.apiKey) {
385
- throw new Error("MistralConversationalProvider requires an apiKey");
386
- }
387
- this.apiKey = options.apiKey;
388
- this.defaultModel = options.defaultModel ?? DEFAULT_MODEL2;
389
- this.defaultVoiceId = options.defaultVoiceId ?? DEFAULT_VOICE;
390
- this.baseUrl = normalizeBaseUrl2(options.serverURL ?? DEFAULT_BASE_URL2);
391
- this.fetchImpl = options.fetchImpl ?? fetch;
392
- this.sttProvider = options.sttProvider ?? new MistralSttProvider({
393
- apiKey: options.apiKey,
394
- defaultModel: options.sttOptions?.defaultModel,
395
- defaultLanguage: options.sttOptions?.defaultLanguage,
396
- serverURL: options.sttOptions?.serverURL ?? options.serverURL,
397
- fetchImpl: this.fetchImpl
398
- });
399
- }
400
- async startSession(config) {
401
- return new MistralConversationSession({
402
- sessionConfig: {
403
- ...config,
404
- voiceId: config.voiceId || this.defaultVoiceId
405
- },
406
- defaultModel: this.defaultModel,
407
- complete: (history, sessionConfig) => this.completeConversation(history, sessionConfig),
408
- sttProvider: this.sttProvider
409
- });
410
- }
411
- async listVoices() {
412
- return [
413
- {
414
- id: this.defaultVoiceId,
415
- name: "Mistral Default Voice",
416
- description: "Default conversational voice profile.",
417
- capabilities: ["conversational"]
418
- }
419
- ];
420
- }
421
- async completeConversation(history, sessionConfig) {
422
- const model = sessionConfig.llmModel ?? this.defaultModel;
423
- const messages = [];
424
- if (sessionConfig.systemPrompt) {
425
- messages.push({ role: "system", content: sessionConfig.systemPrompt });
426
- }
427
- for (const item of history) {
428
- messages.push({ role: item.role, content: item.content });
429
- }
430
- const response = await this.fetchImpl(`${this.baseUrl}/chat/completions`, {
431
- method: "POST",
432
- headers: {
433
- Authorization: `Bearer ${this.apiKey}`,
434
- "Content-Type": "application/json"
435
- },
436
- body: JSON.stringify({
437
- model,
438
- messages
439
- })
440
- });
441
- if (!response.ok) {
442
- const body = await response.text();
443
- throw new Error(`Mistral conversational request failed (${response.status}): ${body}`);
444
- }
445
- const payload = await response.json();
446
- return readAssistantText(payload);
447
- }
448
- }
449
- function normalizeBaseUrl2(url) {
450
- return url.endsWith("/") ? url.slice(0, -1) : url;
451
- }
452
- function readAssistantText(payload) {
453
- const record = asRecord2(payload);
454
- const choices = Array.isArray(record.choices) ? record.choices : [];
455
- const firstChoice = asRecord2(choices[0]);
456
- const message = asRecord2(firstChoice.message);
457
- if (typeof message.content === "string") {
458
- return message.content;
459
- }
460
- if (Array.isArray(message.content)) {
461
- const textParts = message.content.map((part) => {
462
- const entry = asRecord2(part);
463
- const text = entry.text;
464
- return typeof text === "string" ? text : "";
465
- }).filter((text) => text.length > 0);
466
- return textParts.join("");
467
- }
468
- return "";
469
- }
470
- function asRecord2(value) {
471
- if (value && typeof value === "object") {
472
- return value;
473
- }
474
- return {};
475
- }
476
- export {
477
- MistralConversationalProvider
478
- };
2
+ var U=import.meta.require;class g{values=[];waiters=[];done=!1;push(e){if(this.done)return;let t=this.waiters.shift();if(t){t({value:e,done:!1});return}this.values.push(e)}close(){if(this.done)return;this.done=!0;for(let e of this.waiters)e({value:void 0,done:!0});this.waiters.length=0}[Symbol.asyncIterator](){return{next:async()=>{let e=this.values.shift();if(e!=null)return{value:e,done:!1};if(this.done)return{value:void 0,done:!0};return new Promise((t)=>{this.waiters.push(t)})}}}}class v{events;queue=new g;turns=[];history=[];sessionId=crypto.randomUUID();startedAt=Date.now();sessionConfig;defaultModel;complete;sttProvider;pending=Promise.resolve();closed=!1;closedSummary;constructor(e){this.sessionConfig=e.sessionConfig,this.defaultModel=e.defaultModel,this.complete=e.complete,this.sttProvider=e.sttProvider,this.events=this.queue,this.queue.push({type:"session_started",sessionId:this.sessionId})}sendAudio(e){if(this.closed)return;this.pending=this.pending.then(async()=>{let n=(await this.sttProvider.transcribe({audio:{data:e,format:this.sessionConfig.inputFormat??"pcm",sampleRateHz:16000},language:this.sessionConfig.language})).text.trim();if(n.length>0)await this.handleUserText(n)}).catch((t)=>{this.emitError(t)})}sendText(e){if(this.closed)return;let t=e.trim();if(t.length===0)return;this.pending=this.pending.then(()=>this.handleUserText(t)).catch((n)=>{this.emitError(n)})}interrupt(){if(this.closed)return;this.queue.push({type:"error",error:Error("Interrupt is not supported for non-streaming sessions.")})}async close(){if(this.closedSummary)return this.closedSummary;this.closed=!0,await this.pending;let e=Date.now()-this.startedAt,t={sessionId:this.sessionId,durationMs:e,turns:this.turns.map((n)=>({role:n.role==="assistant"?"agent":n.role,text:n.text,startMs:n.startMs,endMs:n.endMs})),transcript:this.turns.map((n)=>`${n.role}: ${n.text}`).join(`
3
+ `)};return this.closedSummary=t,this.queue.push({type:"session_ended",reason:"closed_by_client",durationMs:e}),this.queue.close(),t}async handleUserText(e){if(this.closed)return;let t=Date.now();this.queue.push({type:"user_speech_started"}),this.queue.push({type:"user_speech_ended",transcript:e}),this.queue.push({type:"transcript",role:"user",text:e,timestamp:t}),this.turns.push({role:"user",text:e,startMs:t,endMs:Date.now()}),this.history.push({role:"user",content:e});let n=Date.now(),s=await this.complete(this.history,{...this.sessionConfig,llmModel:this.sessionConfig.llmModel??this.defaultModel});if(this.closed)return;let r=s.trim(),i=r.length>0?r:"I was unable to produce a response.";this.queue.push({type:"agent_speech_started",text:i}),this.queue.push({type:"transcript",role:"agent",text:i,timestamp:n}),this.queue.push({type:"agent_speech_ended"}),this.turns.push({role:"assistant",text:i,startMs:n,endMs:Date.now()}),this.history.push({role:"assistant",content:i})}emitError(e){if(this.closed)return;this.queue.push({type:"error",error:M(e)})}}function M(e){if(e instanceof Error)return e;return Error(String(e))}var I={mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pcm:"audio/pcm",opus:"audio/opus"};class y{apiKey;defaultModel;defaultLanguage;baseUrl;fetchImpl;constructor(e){if(!e.apiKey)throw Error("MistralSttProvider requires an apiKey");this.apiKey=e.apiKey,this.defaultModel=e.defaultModel??"voxtral-mini-latest",this.defaultLanguage=e.defaultLanguage,this.baseUrl=b(e.serverURL??"https://api.mistral.ai/v1"),this.fetchImpl=e.fetchImpl??fetch}async transcribe(e){let t=new FormData,n=e.model??this.defaultModel,s=I[e.audio.format]??"audio/wav",r=`audio.${e.audio.format}`,i=new Uint8Array(e.audio.data),o=new Blob([i],{type:s});t.append("file",o,r),t.append("model",n),t.append("response_format","verbose_json");let d=e.language??this.defaultLanguage;if(d)t.append("language",d);let a=await this.fetchImpl(`${this.baseUrl}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`},body:t});if(!a.ok){let l=await a.text();throw Error(`Mistral transcription request failed (${a.status}): ${l}`)}let f=await a.json();return C(f,e)}}function C(e,t){let n=T(e),s=c(n,"text")??"",r=c(n,"language")??t.language??"unknown",i=k(n);if(i.length===0&&s.length>0)i.push({text:s,startMs:0,endMs:t.audio.durationMs??0});let o=t.audio.durationMs??i.reduce((m,S)=>Math.max(m,S.endMs),0),d=w(n.words),a=i.flatMap((m)=>m.wordTimings??[]),f=d.length>0?d:a.length>0?a:void 0,l=A(i);return{text:s,segments:i,language:r,durationMs:o,speakers:l.length>0?l:void 0,wordTimings:f}}function k(e){if(!Array.isArray(e.segments))return[];let t=[];for(let n of e.segments){let s=T(n),r=c(s,"text");if(!r)continue;let i=u(s,"start")??0,o=u(s,"end")??i;t.push({text:r,startMs:h(i),endMs:h(o),speakerId:c(s,"speaker")??void 0,confidence:u(s,"confidence"),wordTimings:w(s.words)})}return t}function w(e){if(!Array.isArray(e))return[];let t=[];for(let n of e){let s=T(n),r=c(s,"word"),i=u(s,"start"),o=u(s,"end");if(!r||i==null||o==null)continue;t.push({word:r,startMs:h(i),endMs:h(o),confidence:u(s,"confidence")})}return t}function A(e){let t=new Set,n=[];for(let s of e){if(!s.speakerId||t.has(s.speakerId))continue;t.add(s.speakerId),n.push({id:s.speakerId,name:s.speakerName})}return n}function b(e){return e.endsWith("/")?e.slice(0,-1):e}function T(e){if(e&&typeof e==="object")return e;return{}}function c(e,t){let n=e[t];return typeof n==="string"?n:void 0}function u(e,t){let n=e[t];return typeof n==="number"?n:void 0}function h(e){return Math.round(e*1000)}var P="https://api.mistral.ai/v1",x="mistral-small-latest",_="default";class E{apiKey;defaultModel;defaultVoiceId;baseUrl;fetchImpl;sttProvider;constructor(e){if(!e.apiKey)throw Error("MistralConversationalProvider requires an apiKey");this.apiKey=e.apiKey,this.defaultModel=e.defaultModel??x,this.defaultVoiceId=e.defaultVoiceId??_,this.baseUrl=R(e.serverURL??P),this.fetchImpl=e.fetchImpl??fetch,this.sttProvider=e.sttProvider??new y({apiKey:e.apiKey,defaultModel:e.sttOptions?.defaultModel,defaultLanguage:e.sttOptions?.defaultLanguage,serverURL:e.sttOptions?.serverURL??e.serverURL,fetchImpl:this.fetchImpl})}async startSession(e){return new v({sessionConfig:{...e,voiceId:e.voiceId||this.defaultVoiceId},defaultModel:this.defaultModel,complete:(t,n)=>this.completeConversation(t,n),sttProvider:this.sttProvider})}async listVoices(){return[{id:this.defaultVoiceId,name:"Mistral Default Voice",description:"Default conversational voice profile.",capabilities:["conversational"]}]}async completeConversation(e,t){let n=t.llmModel??this.defaultModel,s=[];if(t.systemPrompt)s.push({role:"system",content:t.systemPrompt});for(let o of e)s.push({role:o.role,content:o.content});let r=await this.fetchImpl(`${this.baseUrl}/chat/completions`,{method:"POST",headers:{Authorization:`Bearer ${this.apiKey}`,"Content-Type":"application/json"},body:JSON.stringify({model:n,messages:s})});if(!r.ok){let o=await r.text();throw Error(`Mistral conversational request failed (${r.status}): ${o}`)}let i=await r.json();return q(i)}}function R(e){return e.endsWith("/")?e.slice(0,-1):e}function q(e){let t=p(e),n=Array.isArray(t.choices)?t.choices:[],s=p(n[0]),r=p(s.message);if(typeof r.content==="string")return r.content;if(Array.isArray(r.content))return r.content.map((o)=>{let a=p(o).text;return typeof a==="string"?a:""}).filter((o)=>o.length>0).join("");return""}function p(e){if(e&&typeof e==="object")return e;return{}}export{E as MistralConversationalProvider};
@@ -1,208 +1,3 @@
1
1
  // @bun
2
- var __require = import.meta.require;
3
-
4
- // src/impls/async-event-queue.ts
5
- class AsyncEventQueue {
6
- values = [];
7
- waiters = [];
8
- done = false;
9
- push(value) {
10
- if (this.done) {
11
- return;
12
- }
13
- const waiter = this.waiters.shift();
14
- if (waiter) {
15
- waiter({ value, done: false });
16
- return;
17
- }
18
- this.values.push(value);
19
- }
20
- close() {
21
- if (this.done) {
22
- return;
23
- }
24
- this.done = true;
25
- for (const waiter of this.waiters) {
26
- waiter({ value: undefined, done: true });
27
- }
28
- this.waiters.length = 0;
29
- }
30
- [Symbol.asyncIterator]() {
31
- return {
32
- next: async () => {
33
- const value = this.values.shift();
34
- if (value != null) {
35
- return { value, done: false };
36
- }
37
- if (this.done) {
38
- return { value: undefined, done: true };
39
- }
40
- return new Promise((resolve) => {
41
- this.waiters.push(resolve);
42
- });
43
- }
44
- };
45
- }
46
- }
47
-
48
- // src/impls/mistral-conversational.session.ts
49
- class MistralConversationSession {
50
- events;
51
- queue = new AsyncEventQueue;
52
- turns = [];
53
- history = [];
54
- sessionId = crypto.randomUUID();
55
- startedAt = Date.now();
56
- sessionConfig;
57
- defaultModel;
58
- complete;
59
- sttProvider;
60
- pending = Promise.resolve();
61
- closed = false;
62
- closedSummary;
63
- constructor(options) {
64
- this.sessionConfig = options.sessionConfig;
65
- this.defaultModel = options.defaultModel;
66
- this.complete = options.complete;
67
- this.sttProvider = options.sttProvider;
68
- this.events = this.queue;
69
- this.queue.push({
70
- type: "session_started",
71
- sessionId: this.sessionId
72
- });
73
- }
74
- sendAudio(chunk) {
75
- if (this.closed) {
76
- return;
77
- }
78
- this.pending = this.pending.then(async () => {
79
- const transcription = await this.sttProvider.transcribe({
80
- audio: {
81
- data: chunk,
82
- format: this.sessionConfig.inputFormat ?? "pcm",
83
- sampleRateHz: 16000
84
- },
85
- language: this.sessionConfig.language
86
- });
87
- const transcriptText = transcription.text.trim();
88
- if (transcriptText.length > 0) {
89
- await this.handleUserText(transcriptText);
90
- }
91
- }).catch((error) => {
92
- this.emitError(error);
93
- });
94
- }
95
- sendText(text) {
96
- if (this.closed) {
97
- return;
98
- }
99
- const normalized = text.trim();
100
- if (normalized.length === 0) {
101
- return;
102
- }
103
- this.pending = this.pending.then(() => this.handleUserText(normalized)).catch((error) => {
104
- this.emitError(error);
105
- });
106
- }
107
- interrupt() {
108
- if (this.closed) {
109
- return;
110
- }
111
- this.queue.push({
112
- type: "error",
113
- error: new Error("Interrupt is not supported for non-streaming sessions.")
114
- });
115
- }
116
- async close() {
117
- if (this.closedSummary) {
118
- return this.closedSummary;
119
- }
120
- this.closed = true;
121
- await this.pending;
122
- const durationMs = Date.now() - this.startedAt;
123
- const summary = {
124
- sessionId: this.sessionId,
125
- durationMs,
126
- turns: this.turns.map((turn) => ({
127
- role: turn.role === "assistant" ? "agent" : turn.role,
128
- text: turn.text,
129
- startMs: turn.startMs,
130
- endMs: turn.endMs
131
- })),
132
- transcript: this.turns.map((turn) => `${turn.role}: ${turn.text}`).join(`
133
- `)
134
- };
135
- this.closedSummary = summary;
136
- this.queue.push({
137
- type: "session_ended",
138
- reason: "closed_by_client",
139
- durationMs
140
- });
141
- this.queue.close();
142
- return summary;
143
- }
144
- async handleUserText(text) {
145
- if (this.closed) {
146
- return;
147
- }
148
- const userStart = Date.now();
149
- this.queue.push({ type: "user_speech_started" });
150
- this.queue.push({ type: "user_speech_ended", transcript: text });
151
- this.queue.push({
152
- type: "transcript",
153
- role: "user",
154
- text,
155
- timestamp: userStart
156
- });
157
- this.turns.push({
158
- role: "user",
159
- text,
160
- startMs: userStart,
161
- endMs: Date.now()
162
- });
163
- this.history.push({ role: "user", content: text });
164
- const assistantStart = Date.now();
165
- const assistantText = await this.complete(this.history, {
166
- ...this.sessionConfig,
167
- llmModel: this.sessionConfig.llmModel ?? this.defaultModel
168
- });
169
- if (this.closed) {
170
- return;
171
- }
172
- const normalizedAssistantText = assistantText.trim();
173
- const finalAssistantText = normalizedAssistantText.length > 0 ? normalizedAssistantText : "I was unable to produce a response.";
174
- this.queue.push({
175
- type: "agent_speech_started",
176
- text: finalAssistantText
177
- });
178
- this.queue.push({
179
- type: "transcript",
180
- role: "agent",
181
- text: finalAssistantText,
182
- timestamp: assistantStart
183
- });
184
- this.queue.push({ type: "agent_speech_ended" });
185
- this.turns.push({
186
- role: "assistant",
187
- text: finalAssistantText,
188
- startMs: assistantStart,
189
- endMs: Date.now()
190
- });
191
- this.history.push({ role: "assistant", content: finalAssistantText });
192
- }
193
- emitError(error) {
194
- if (this.closed) {
195
- return;
196
- }
197
- this.queue.push({ type: "error", error: toError(error) });
198
- }
199
- }
200
- function toError(error) {
201
- if (error instanceof Error) {
202
- return error;
203
- }
204
- return new Error(String(error));
205
- }
206
- export {
207
- MistralConversationSession
208
- };
2
+ var l=import.meta.require;class n{values=[];waiters=[];done=!1;push(e){if(this.done)return;let s=this.waiters.shift();if(s){s({value:e,done:!1});return}this.values.push(e)}close(){if(this.done)return;this.done=!0;for(let e of this.waiters)e({value:void 0,done:!0});this.waiters.length=0}[Symbol.asyncIterator](){return{next:async()=>{let e=this.values.shift();if(e!=null)return{value:e,done:!1};if(this.done)return{value:void 0,done:!0};return new Promise((s)=>{this.waiters.push(s)})}}}}class a{events;queue=new n;turns=[];history=[];sessionId=crypto.randomUUID();startedAt=Date.now();sessionConfig;defaultModel;complete;sttProvider;pending=Promise.resolve();closed=!1;closedSummary;constructor(e){this.sessionConfig=e.sessionConfig,this.defaultModel=e.defaultModel,this.complete=e.complete,this.sttProvider=e.sttProvider,this.events=this.queue,this.queue.push({type:"session_started",sessionId:this.sessionId})}sendAudio(e){if(this.closed)return;this.pending=this.pending.then(async()=>{let t=(await this.sttProvider.transcribe({audio:{data:e,format:this.sessionConfig.inputFormat??"pcm",sampleRateHz:16000},language:this.sessionConfig.language})).text.trim();if(t.length>0)await this.handleUserText(t)}).catch((s)=>{this.emitError(s)})}sendText(e){if(this.closed)return;let s=e.trim();if(s.length===0)return;this.pending=this.pending.then(()=>this.handleUserText(s)).catch((t)=>{this.emitError(t)})}interrupt(){if(this.closed)return;this.queue.push({type:"error",error:Error("Interrupt is not supported for non-streaming sessions.")})}async close(){if(this.closedSummary)return this.closedSummary;this.closed=!0,await this.pending;let e=Date.now()-this.startedAt,s={sessionId:this.sessionId,durationMs:e,turns:this.turns.map((t)=>({role:t.role==="assistant"?"agent":t.role,text:t.text,startMs:t.startMs,endMs:t.endMs})),transcript:this.turns.map((t)=>`${t.role}: ${t.text}`).join(`
3
+ `)};return this.closedSummary=s,this.queue.push({type:"session_ended",reason:"closed_by_client",durationMs:e}),this.queue.close(),s}async handleUserText(e){if(this.closed)return;let s=Date.now();this.queue.push({type:"user_speech_started"}),this.queue.push({type:"user_speech_ended",transcript:e}),this.queue.push({type:"transcript",role:"user",text:e,timestamp:s}),this.turns.push({role:"user",text:e,startMs:s,endMs:Date.now()}),this.history.push({role:"user",content:e});let t=Date.now(),o=await this.complete(this.history,{...this.sessionConfig,llmModel:this.sessionConfig.llmModel??this.defaultModel});if(this.closed)return;let i=o.trim(),r=i.length>0?i:"I was unable to produce a response.";this.queue.push({type:"agent_speech_started",text:r}),this.queue.push({type:"transcript",role:"agent",text:r,timestamp:t}),this.queue.push({type:"agent_speech_ended"}),this.turns.push({role:"assistant",text:r,startMs:t,endMs:Date.now()}),this.history.push({role:"assistant",content:r})}emitError(e){if(this.closed)return;this.queue.push({type:"error",error:u(e)})}}function u(e){if(e instanceof Error)return e;return Error(String(e))}export{a as MistralConversationSession};