botinabox 2.7.11 → 2.8.1
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.
- package/dist/channel-DziSPayj.d.ts +73 -0
- package/dist/channels/discord/index.d.ts +1 -1
- package/dist/channels/slack/index.d.ts +75 -4
- package/dist/channels/slack/index.js +136 -4
- package/dist/channels/webhook/index.d.ts +1 -1
- package/dist/chat-pipeline-BGgmH_ap.d.ts +655 -0
- package/dist/chunk-OEMM2LEA.js +223 -0
- package/dist/connectors/google/index.d.ts +83 -1
- package/dist/connectors/google/index.js +100 -0
- package/dist/inbound-5FKJBWPL.js +11 -0
- package/dist/index.d.ts +6 -6
- package/dist/provider-BHkqkSdq.d.ts +89 -0
- package/dist/providers/anthropic/index.d.ts +1 -1
- package/dist/providers/ollama/index.d.ts +1 -1
- package/dist/providers/openai/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// src/channels/slack/transcribe.ts
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import { writeFileSync, unlinkSync, mkdirSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
import os from "os";
|
|
7
|
+
import { createRequire } from "module";
|
|
8
|
+
var TEMP_DIR = join(os.tmpdir(), "botinabox-audio");
|
|
9
|
+
async function transcribeAudio(audioBuffer, filename, opts) {
|
|
10
|
+
let whisper;
|
|
11
|
+
try {
|
|
12
|
+
const require2 = createRequire(import.meta.url);
|
|
13
|
+
const mod = require2("whisper-node");
|
|
14
|
+
whisper = mod.whisper ?? mod.default ?? mod;
|
|
15
|
+
} catch {
|
|
16
|
+
console.warn("[botinabox] whisper-node not installed \u2014 voice transcription unavailable. Run: npm install whisper-node && npx whisper-node download");
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
execFileSync("ffmpeg", ["-version"], { stdio: "ignore" });
|
|
21
|
+
} catch {
|
|
22
|
+
console.warn("[botinabox] ffmpeg not found \u2014 required for audio conversion. Install: brew install ffmpeg");
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const id = randomUUID().slice(0, 8);
|
|
26
|
+
const ext = filename.split(".").pop() ?? "aac";
|
|
27
|
+
mkdirSync(TEMP_DIR, { recursive: true });
|
|
28
|
+
const inputPath = join(TEMP_DIR, `${id}.${ext}`);
|
|
29
|
+
const wavPath = join(TEMP_DIR, `${id}.wav`);
|
|
30
|
+
try {
|
|
31
|
+
writeFileSync(inputPath, audioBuffer);
|
|
32
|
+
execFileSync("ffmpeg", ["-y", "-i", inputPath, "-ar", "16000", "-ac", "1", "-c:a", "pcm_s16le", wavPath], {
|
|
33
|
+
stdio: "ignore",
|
|
34
|
+
timeout: 3e4
|
|
35
|
+
});
|
|
36
|
+
const segments = await whisper(wavPath, {
|
|
37
|
+
modelName: opts?.modelName ?? "base.en",
|
|
38
|
+
whisperOptions: {
|
|
39
|
+
language: opts?.language ?? "auto"
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
if (!segments || segments.length === 0) return null;
|
|
43
|
+
return segments.map((s) => s.speech).join(" ").trim();
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error("[botinabox] Transcription failed:", err);
|
|
46
|
+
return null;
|
|
47
|
+
} finally {
|
|
48
|
+
try {
|
|
49
|
+
unlinkSync(inputPath);
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
unlinkSync(wavPath);
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function downloadAudio(url, token) {
|
|
59
|
+
try {
|
|
60
|
+
const resp = await fetch(url, {
|
|
61
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
62
|
+
});
|
|
63
|
+
if (!resp.ok) {
|
|
64
|
+
console.error(`[botinabox] Audio download failed: ${resp.status} ${resp.statusText}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return Buffer.from(await resp.arrayBuffer());
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error("[botinabox] Audio download error:", err);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/channels/slack/media-type.ts
|
|
75
|
+
var FILETYPE_MAP = {
|
|
76
|
+
// image
|
|
77
|
+
jpg: "image",
|
|
78
|
+
jpeg: "image",
|
|
79
|
+
png: "image",
|
|
80
|
+
gif: "image",
|
|
81
|
+
webp: "image",
|
|
82
|
+
heic: "image",
|
|
83
|
+
svg: "image",
|
|
84
|
+
bmp: "image",
|
|
85
|
+
// video
|
|
86
|
+
mp4: "video",
|
|
87
|
+
mov: "video",
|
|
88
|
+
webm: "video",
|
|
89
|
+
avi: "video",
|
|
90
|
+
mkv: "video",
|
|
91
|
+
// audio (also handled by voice-message path — included for completeness)
|
|
92
|
+
aac: "audio",
|
|
93
|
+
m4a: "audio",
|
|
94
|
+
mp3: "audio",
|
|
95
|
+
wav: "audio",
|
|
96
|
+
ogg: "audio",
|
|
97
|
+
flac: "audio",
|
|
98
|
+
// pdf
|
|
99
|
+
pdf: "pdf",
|
|
100
|
+
// doc
|
|
101
|
+
gdoc: "doc",
|
|
102
|
+
docx: "doc",
|
|
103
|
+
doc: "doc",
|
|
104
|
+
md: "doc",
|
|
105
|
+
txt: "doc",
|
|
106
|
+
rtf: "doc",
|
|
107
|
+
// excel
|
|
108
|
+
gsheet: "excel",
|
|
109
|
+
xlsx: "excel",
|
|
110
|
+
xls: "excel",
|
|
111
|
+
csv: "excel",
|
|
112
|
+
tsv: "excel",
|
|
113
|
+
// presentation
|
|
114
|
+
gslide: "presentation",
|
|
115
|
+
pptx: "presentation",
|
|
116
|
+
ppt: "presentation",
|
|
117
|
+
key: "presentation",
|
|
118
|
+
// html
|
|
119
|
+
html: "html",
|
|
120
|
+
htm: "html"
|
|
121
|
+
};
|
|
122
|
+
function slackFiletypeToMediaType(filetype) {
|
|
123
|
+
if (!filetype) return "misc";
|
|
124
|
+
return FILETYPE_MAP[filetype.toLowerCase()] ?? "misc";
|
|
125
|
+
}
|
|
126
|
+
var URL_REGEX = /https?:\/\/[^\s<>"')]+/g;
|
|
127
|
+
function extractUrls(text) {
|
|
128
|
+
if (!text) return [];
|
|
129
|
+
const matches = text.match(URL_REGEX);
|
|
130
|
+
if (!matches) return [];
|
|
131
|
+
return Array.from(new Set(matches.map((u) => u.replace(/[.,;:!?)]+$/, ""))));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/channels/slack/inbound.ts
|
|
135
|
+
var AUDIO_TYPES = /* @__PURE__ */ new Set(["aac", "mp4", "m4a", "ogg", "webm", "mp3", "wav"]);
|
|
136
|
+
function extractVoiceTranscript(file) {
|
|
137
|
+
const isAudio = file.subtype === "slack_audio" || AUDIO_TYPES.has(file.filetype ?? "");
|
|
138
|
+
if (!isAudio) return null;
|
|
139
|
+
const transcript = file.transcription?.preview?.content ?? (typeof file.preview === "string" ? file.preview : null);
|
|
140
|
+
return transcript ?? null;
|
|
141
|
+
}
|
|
142
|
+
function parseSlackEvent(event) {
|
|
143
|
+
const id = event.client_msg_id ?? event.ts ?? event.event_ts ?? `slack-${Date.now()}`;
|
|
144
|
+
const channel = event.channel ?? "unknown";
|
|
145
|
+
const from = event.user ?? "unknown";
|
|
146
|
+
const threadId = event.thread_ts !== void 0 ? event.thread_ts : void 0;
|
|
147
|
+
const receivedAt = event.ts ? new Date(parseFloat(event.ts) * 1e3).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
|
|
148
|
+
let body = event.text ?? "";
|
|
149
|
+
if (event.subtype === "file_share" && event.files?.length) {
|
|
150
|
+
for (const file of event.files) {
|
|
151
|
+
const transcript = extractVoiceTranscript(file);
|
|
152
|
+
if (transcript) {
|
|
153
|
+
body = body ? `${body}
|
|
154
|
+
|
|
155
|
+
[Voice message] ${transcript}` : `[Voice message] ${transcript}`;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (event.subtype === "file_share" && event.files?.length && !body) {
|
|
161
|
+
const hasAudio = event.files.some(
|
|
162
|
+
(f) => f.subtype === "slack_audio" || AUDIO_TYPES.has(f.filetype ?? "")
|
|
163
|
+
);
|
|
164
|
+
if (hasAudio) {
|
|
165
|
+
body = "[Voice message \u2014 no transcript available]";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const attachments = [];
|
|
169
|
+
if (event.subtype === "file_share" && event.files?.length) {
|
|
170
|
+
for (const file of event.files) {
|
|
171
|
+
const isAudio = file.subtype === "slack_audio" || AUDIO_TYPES.has(file.filetype ?? "");
|
|
172
|
+
if (isAudio) continue;
|
|
173
|
+
attachments.push({
|
|
174
|
+
type: slackFiletypeToMediaType(file.filetype),
|
|
175
|
+
url: file.url_private,
|
|
176
|
+
mimeType: file.mimetype,
|
|
177
|
+
filename: file.name ?? file.title,
|
|
178
|
+
size: file.size
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const urls = extractUrls(body);
|
|
183
|
+
for (const url of urls) {
|
|
184
|
+
attachments.push({ type: "link", url });
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
id,
|
|
188
|
+
channel,
|
|
189
|
+
from,
|
|
190
|
+
body,
|
|
191
|
+
threadId,
|
|
192
|
+
attachments: attachments.length > 0 ? attachments : void 0,
|
|
193
|
+
receivedAt,
|
|
194
|
+
raw: event
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function enrichVoiceMessage(msg, botToken) {
|
|
198
|
+
if (!msg.body.includes("[Voice message \u2014 no transcript available]")) return msg;
|
|
199
|
+
const raw = msg.raw;
|
|
200
|
+
const files = raw?.files;
|
|
201
|
+
if (!files?.length) return msg;
|
|
202
|
+
const audioFile = files.find(
|
|
203
|
+
(f) => f.subtype === "slack_audio" || AUDIO_TYPES.has(f.filetype ?? "")
|
|
204
|
+
);
|
|
205
|
+
if (!audioFile?.url_private) return msg;
|
|
206
|
+
const buffer = await downloadAudio(audioFile.url_private, botToken);
|
|
207
|
+
if (!buffer) return msg;
|
|
208
|
+
const filename = audioFile.name ?? `voice.${audioFile.filetype ?? "aac"}`;
|
|
209
|
+
const transcript = await transcribeAudio(buffer, filename);
|
|
210
|
+
if (!transcript) return msg;
|
|
211
|
+
return {
|
|
212
|
+
...msg,
|
|
213
|
+
body: `[Voice message] ${transcript}`
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export {
|
|
218
|
+
transcribeAudio,
|
|
219
|
+
downloadAudio,
|
|
220
|
+
extractVoiceTranscript,
|
|
221
|
+
parseSlackEvent,
|
|
222
|
+
enrichVoiceMessage
|
|
223
|
+
};
|
|
@@ -284,4 +284,86 @@ declare class GoogleDriveConnector implements Connector<DriveFileRecord> {
|
|
|
284
284
|
private mapFile;
|
|
285
285
|
}
|
|
286
286
|
|
|
287
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Google Drive file read primitives — download or export files to raw bytes.
|
|
289
|
+
*
|
|
290
|
+
* Signature-agnostic primitives that produce `{ buffer, mimeType, filename }`
|
|
291
|
+
* tuples for use in attachment enrichment pipelines and other file consumers.
|
|
292
|
+
*/
|
|
293
|
+
/**
|
|
294
|
+
* Raw file bytes fetched from Google Drive, plus the metadata needed to
|
|
295
|
+
* decide what to do with them (MIME type → extractor, filename → display).
|
|
296
|
+
*/
|
|
297
|
+
interface DriveFileBytes {
|
|
298
|
+
buffer: Buffer;
|
|
299
|
+
mimeType: string;
|
|
300
|
+
filename: string;
|
|
301
|
+
/** Size in bytes as reported by the download response. */
|
|
302
|
+
size: number;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Supported export target formats for Google-native file types
|
|
306
|
+
* (Docs, Sheets, Slides, Drawings).
|
|
307
|
+
*/
|
|
308
|
+
type GoogleDocExportAs = 'docx' | 'xlsx' | 'pptx' | 'png' | 'pdf' | 'txt' | 'csv' | 'html';
|
|
309
|
+
/**
|
|
310
|
+
* Download a binary Drive file as raw bytes.
|
|
311
|
+
*
|
|
312
|
+
* Use this for files uploaded to Drive in their native format (pdf, docx,
|
|
313
|
+
* xlsx, pptx, jpg, png, mp4, etc.) — anything where the Drive `mimeType`
|
|
314
|
+
* is NOT `application/vnd.google-apps.*`.
|
|
315
|
+
*
|
|
316
|
+
* For Google-native formats (Docs, Sheets, Slides, Drawings) use
|
|
317
|
+
* `exportGoogleDoc` instead — `files.get` with `alt: 'media'` fails on
|
|
318
|
+
* those with `fileNotDownloadable`.
|
|
319
|
+
*
|
|
320
|
+
* @param drive - googleapis `drive_v3.Drive` instance (kept as `any` to avoid hard type import)
|
|
321
|
+
* @param fileId - Drive file ID
|
|
322
|
+
* @returns Promise resolving to `DriveFileBytes` with buffer, mimeType, filename, and size
|
|
323
|
+
*/
|
|
324
|
+
declare function downloadDriveFile(drive: any, fileId: string): Promise<DriveFileBytes>;
|
|
325
|
+
/**
|
|
326
|
+
* Export a Google-native document to a downloadable format.
|
|
327
|
+
*
|
|
328
|
+
* The `exportAs` argument picks the target MIME type:
|
|
329
|
+
* - docx → application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
|
330
|
+
* - xlsx → application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
|
331
|
+
* - pptx → application/vnd.openxmlformats-officedocument.presentationml.presentation
|
|
332
|
+
* - png → image/png
|
|
333
|
+
* - pdf → application/pdf
|
|
334
|
+
* - txt → text/plain
|
|
335
|
+
* - csv → text/csv (only valid for spreadsheets)
|
|
336
|
+
* - html → text/html
|
|
337
|
+
*
|
|
338
|
+
* Throws if the source file is not a Google-native type, or if the
|
|
339
|
+
* requested export is not supported for that type (e.g., csv on a Doc).
|
|
340
|
+
*
|
|
341
|
+
* @param drive - googleapis `drive_v3.Drive` instance
|
|
342
|
+
* @param fileId - Drive file ID
|
|
343
|
+
* @param exportAs - Target export format
|
|
344
|
+
* @returns Promise resolving to `DriveFileBytes` with exported content
|
|
345
|
+
*/
|
|
346
|
+
declare function exportGoogleDoc(drive: any, fileId: string, exportAs: GoogleDocExportAs): Promise<DriveFileBytes>;
|
|
347
|
+
/**
|
|
348
|
+
* High-level dispatcher. Fetches file metadata, inspects the mimeType,
|
|
349
|
+
* and picks `downloadDriveFile` (binary) or `exportGoogleDoc` (native)
|
|
350
|
+
* automatically.
|
|
351
|
+
*
|
|
352
|
+
* Google-native → exported format mapping:
|
|
353
|
+
* - Docs → docx
|
|
354
|
+
* - Sheets → xlsx
|
|
355
|
+
* - Slides → pptx
|
|
356
|
+
* - Drawings → png
|
|
357
|
+
* - Scripts → throws (not supported)
|
|
358
|
+
* - Forms/Site → throws (not supported)
|
|
359
|
+
*
|
|
360
|
+
* Consumers that want a different export target (e.g., gdoc → pdf for
|
|
361
|
+
* Claude's native PDF reading) should call `exportGoogleDoc` directly.
|
|
362
|
+
*
|
|
363
|
+
* @param drive - googleapis `drive_v3.Drive` instance
|
|
364
|
+
* @param fileId - Drive file ID
|
|
365
|
+
* @returns Promise resolving to `DriveFileBytes` with automatically chosen format
|
|
366
|
+
*/
|
|
367
|
+
declare function readDriveFile(drive: any, fileId: string): Promise<DriveFileBytes>;
|
|
368
|
+
|
|
369
|
+
export { type CalendarAttendee, type CalendarConnectorOpts, type CalendarEventRecord, type DriveConnectorOpts, type DriveFileBytes, type DriveFileRecord, type DriveOwner, type EmailAddress, type EmailAttachment, type EmailRecord, type GmailConnectorOpts, GoogleCalendarConnector, type GoogleConnectorConfig, type GoogleDocExportAs, GoogleDriveConnector, GoogleGmailConnector, type GoogleOAuthConfig, type GoogleServiceAccountConfig, type GoogleTokens, createOAuth2Client, createServiceAccountClient, downloadDriveFile, exchangeCode, exportGoogleDoc, getAuthUrl, loadTokens, readDriveFile, refreshIfNeeded, saveTokens };
|
|
@@ -474,15 +474,115 @@ var GoogleDriveConnector = class {
|
|
|
474
474
|
function errorMessage2(err) {
|
|
475
475
|
return err instanceof Error ? err.message : String(err);
|
|
476
476
|
}
|
|
477
|
+
|
|
478
|
+
// src/connectors/google/drive-read.ts
|
|
479
|
+
var GOOGLE_NATIVE_PREFIX = "application/vnd.google-apps.";
|
|
480
|
+
var GOOGLE_DOC = "application/vnd.google-apps.document";
|
|
481
|
+
var GOOGLE_SHEET = "application/vnd.google-apps.spreadsheet";
|
|
482
|
+
var GOOGLE_SLIDES = "application/vnd.google-apps.presentation";
|
|
483
|
+
var GOOGLE_DRAWING = "application/vnd.google-apps.drawing";
|
|
484
|
+
var EXPORT_MIME = {
|
|
485
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
486
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
487
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
488
|
+
png: "image/png",
|
|
489
|
+
pdf: "application/pdf",
|
|
490
|
+
txt: "text/plain",
|
|
491
|
+
csv: "text/csv",
|
|
492
|
+
html: "text/html"
|
|
493
|
+
};
|
|
494
|
+
var EXPORT_EXTENSION = {
|
|
495
|
+
docx: "docx",
|
|
496
|
+
xlsx: "xlsx",
|
|
497
|
+
pptx: "pptx",
|
|
498
|
+
png: "png",
|
|
499
|
+
pdf: "pdf",
|
|
500
|
+
txt: "txt",
|
|
501
|
+
csv: "csv",
|
|
502
|
+
html: "html"
|
|
503
|
+
};
|
|
504
|
+
async function downloadDriveFile(drive, fileId) {
|
|
505
|
+
const metaRes = await drive.files.get({
|
|
506
|
+
fileId,
|
|
507
|
+
fields: "name,mimeType,size"
|
|
508
|
+
});
|
|
509
|
+
const { name: filename, mimeType, size } = metaRes.data;
|
|
510
|
+
const response = await drive.files.get(
|
|
511
|
+
{ fileId, alt: "media" },
|
|
512
|
+
{ responseType: "arraybuffer" }
|
|
513
|
+
);
|
|
514
|
+
const buffer = Buffer.from(response.data);
|
|
515
|
+
return {
|
|
516
|
+
buffer,
|
|
517
|
+
mimeType: mimeType ?? "application/octet-stream",
|
|
518
|
+
filename: filename ?? "document",
|
|
519
|
+
size: size ? parseInt(String(size), 10) : buffer.length
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
async function exportGoogleDoc(drive, fileId, exportAs) {
|
|
523
|
+
const metaRes = await drive.files.get({
|
|
524
|
+
fileId,
|
|
525
|
+
fields: "name,mimeType"
|
|
526
|
+
});
|
|
527
|
+
const { name: filename, mimeType } = metaRes.data;
|
|
528
|
+
if (!mimeType?.startsWith(GOOGLE_NATIVE_PREFIX)) {
|
|
529
|
+
throw new Error(
|
|
530
|
+
`Cannot export non-Google-native file. mimeType: ${mimeType}. Use downloadDriveFile instead.`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
const targetMimeType = EXPORT_MIME[exportAs];
|
|
534
|
+
const response = await drive.files.export(
|
|
535
|
+
{ fileId, mimeType: targetMimeType },
|
|
536
|
+
{ responseType: "arraybuffer" }
|
|
537
|
+
);
|
|
538
|
+
const buffer = Buffer.from(response.data);
|
|
539
|
+
const extension = EXPORT_EXTENSION[exportAs];
|
|
540
|
+
let finalFilename = filename ?? "document";
|
|
541
|
+
if (!finalFilename.endsWith(`.${extension}`)) {
|
|
542
|
+
finalFilename = `${finalFilename}.${extension}`;
|
|
543
|
+
}
|
|
544
|
+
return {
|
|
545
|
+
buffer,
|
|
546
|
+
mimeType: targetMimeType,
|
|
547
|
+
filename: finalFilename,
|
|
548
|
+
size: buffer.length
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
async function readDriveFile(drive, fileId) {
|
|
552
|
+
const metaRes = await drive.files.get({
|
|
553
|
+
fileId,
|
|
554
|
+
fields: "name,mimeType,size"
|
|
555
|
+
});
|
|
556
|
+
const { mimeType } = metaRes.data;
|
|
557
|
+
if (mimeType?.startsWith(GOOGLE_NATIVE_PREFIX)) {
|
|
558
|
+
if (mimeType === GOOGLE_DOC) {
|
|
559
|
+
return exportGoogleDoc(drive, fileId, "docx");
|
|
560
|
+
}
|
|
561
|
+
if (mimeType === GOOGLE_SHEET) {
|
|
562
|
+
return exportGoogleDoc(drive, fileId, "xlsx");
|
|
563
|
+
}
|
|
564
|
+
if (mimeType === GOOGLE_SLIDES) {
|
|
565
|
+
return exportGoogleDoc(drive, fileId, "pptx");
|
|
566
|
+
}
|
|
567
|
+
if (mimeType === GOOGLE_DRAWING) {
|
|
568
|
+
return exportGoogleDoc(drive, fileId, "png");
|
|
569
|
+
}
|
|
570
|
+
throw new Error(`Unsupported Google-native type: ${mimeType}`);
|
|
571
|
+
}
|
|
572
|
+
return downloadDriveFile(drive, fileId);
|
|
573
|
+
}
|
|
477
574
|
export {
|
|
478
575
|
GoogleCalendarConnector,
|
|
479
576
|
GoogleDriveConnector,
|
|
480
577
|
GoogleGmailConnector,
|
|
481
578
|
createOAuth2Client,
|
|
482
579
|
createServiceAccountClient,
|
|
580
|
+
downloadDriveFile,
|
|
483
581
|
exchangeCode,
|
|
582
|
+
exportGoogleDoc,
|
|
484
583
|
getAuthUrl,
|
|
485
584
|
loadTokens,
|
|
585
|
+
readDriveFile,
|
|
486
586
|
refreshIfNeeded,
|
|
487
587
|
saveTokens
|
|
488
588
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { C as ChannelAdapter, H as HealthStatus, I as InboundMessage } from './channel-
|
|
2
|
-
export { A as Attachment, a as
|
|
3
|
-
import { T as TokenUsage, L as LLMProvider, M as ModelInfo, R as ResolvedModel, C as ChatMessage } from './provider-
|
|
4
|
-
export { a as ChatParams, b as ChatResult, c as ContentBlock, d as ToolUse } from './provider-
|
|
1
|
+
import { C as ChannelAdapter, H as HealthStatus, I as InboundMessage } from './channel-DziSPayj.js';
|
|
2
|
+
export { A as Attachment, a as AttachmentMediaType, b as ChannelCapabilities, c as ChannelConfig, d as ChannelMeta, e as ChatType, F as FormattingMode, O as OutboundPayload, S as SendResult } from './channel-DziSPayj.js';
|
|
3
|
+
import { T as TokenUsage, L as LLMProvider, M as ModelInfo, R as ResolvedModel, C as ChatMessage } from './provider-BHkqkSdq.js';
|
|
4
|
+
export { a as ChatParams, b as ChatResult, c as ContentBlock, d as ToolUse } from './provider-BHkqkSdq.js';
|
|
5
5
|
import { C as ConnectorConfig } from './connector-B4Mj0P1b.js';
|
|
6
6
|
export { A as AuthResult, a as Connector, b as ConnectorMeta, P as PushResult, S as SyncOptions, c as SyncResult } from './connector-B4Mj0P1b.js';
|
|
7
|
-
import { C as ChatResponderConfig, D as DataStore, H as HookBus, M as MessageStore, a as ChatResponder, b as MessageInterpreter, E as Extractor } from './chat-pipeline-
|
|
8
|
-
export { c as ChatPipeline, d as ChatPipelineConfig, e as DataStoreError, f as EntityContextDef, g as EntityFileSpec, h as EntitySource, i as ExtractedFile, j as ExtractedMemory, k as ExtractedTask, l as ExtractedUserContext, F as Filter, m as HookHandler, n as HookOptions, o as HookRegistration, I as InterpretationResult, L as LLMCallFn, p as MessageInterpreterConfig, P as PkLookup, Q as QueryOptions, R as RelationDef, q as RoutingDecision, r as RoutingRule, s as Row, S as SeedItem, t as SqliteAdapter, u as StoreResult, v as StoredAttachment, T as TableDefinition, w as TableInfoRow, x as TriageRouter, y as TriageRouterConfig, U as Unsubscribe } from './chat-pipeline-
|
|
7
|
+
import { C as ChatResponderConfig, D as DataStore, H as HookBus, M as MessageStore, a as ChatResponder, b as MessageInterpreter, E as Extractor } from './chat-pipeline-BGgmH_ap.js';
|
|
8
|
+
export { c as ChatPipeline, d as ChatPipelineConfig, e as DataStoreError, f as EntityContextDef, g as EntityFileSpec, h as EntitySource, i as ExtractedFile, j as ExtractedMemory, k as ExtractedTask, l as ExtractedUserContext, F as Filter, m as HookHandler, n as HookOptions, o as HookRegistration, I as InterpretationResult, L as LLMCallFn, p as MessageInterpreterConfig, P as PkLookup, Q as QueryOptions, R as RelationDef, q as RoutingDecision, r as RoutingRule, s as Row, S as SeedItem, t as SqliteAdapter, u as StoreResult, v as StoredAttachment, T as TableDefinition, w as TableInfoRow, x as TriageRouter, y as TriageRouterConfig, U as Unsubscribe } from './chat-pipeline-BGgmH_ap.js';
|
|
9
9
|
import 'better-sqlite3';
|
|
10
10
|
|
|
11
11
|
/** Execution adapter types — Story 1.5 / 3.4 / 3.5 */
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** LLM provider types — Story 1.5 / 2.1 */
|
|
2
|
+
interface ToolDefinition {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
parameters: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
interface ChatMessage {
|
|
8
|
+
role: "user" | "assistant" | "system";
|
|
9
|
+
content: string | ContentBlock[];
|
|
10
|
+
}
|
|
11
|
+
type ContentBlock = {
|
|
12
|
+
type: "text";
|
|
13
|
+
text: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: "tool_use";
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
input: unknown;
|
|
19
|
+
} | {
|
|
20
|
+
type: "tool_result";
|
|
21
|
+
tool_use_id: string;
|
|
22
|
+
content: string;
|
|
23
|
+
} | {
|
|
24
|
+
type: "image";
|
|
25
|
+
source: {
|
|
26
|
+
type: "base64";
|
|
27
|
+
media_type: string;
|
|
28
|
+
data: string;
|
|
29
|
+
};
|
|
30
|
+
} | {
|
|
31
|
+
type: "document";
|
|
32
|
+
source: {
|
|
33
|
+
type: "base64";
|
|
34
|
+
media_type: "application/pdf";
|
|
35
|
+
data: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
interface ChatParams {
|
|
39
|
+
messages: ChatMessage[];
|
|
40
|
+
system?: string;
|
|
41
|
+
tools?: ToolDefinition[];
|
|
42
|
+
maxTokens?: number;
|
|
43
|
+
temperature?: number;
|
|
44
|
+
model: string;
|
|
45
|
+
abortSignal?: AbortSignal;
|
|
46
|
+
}
|
|
47
|
+
interface TokenUsage {
|
|
48
|
+
inputTokens: number;
|
|
49
|
+
outputTokens: number;
|
|
50
|
+
cacheReadTokens?: number;
|
|
51
|
+
cacheWriteTokens?: number;
|
|
52
|
+
}
|
|
53
|
+
interface ChatResult {
|
|
54
|
+
content: string;
|
|
55
|
+
toolUses?: ToolUse[];
|
|
56
|
+
usage: TokenUsage;
|
|
57
|
+
model: string;
|
|
58
|
+
stopReason: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence";
|
|
59
|
+
}
|
|
60
|
+
interface ToolUse {
|
|
61
|
+
id: string;
|
|
62
|
+
name: string;
|
|
63
|
+
input: unknown;
|
|
64
|
+
}
|
|
65
|
+
interface ModelInfo {
|
|
66
|
+
id: string;
|
|
67
|
+
displayName: string;
|
|
68
|
+
contextWindow: number;
|
|
69
|
+
maxOutputTokens: number;
|
|
70
|
+
capabilities: Array<"chat" | "tools" | "vision" | "streaming">;
|
|
71
|
+
/** Cost in micro-cents per 1M tokens */
|
|
72
|
+
inputCostPerMToken?: number;
|
|
73
|
+
outputCostPerMToken?: number;
|
|
74
|
+
}
|
|
75
|
+
interface ResolvedModel {
|
|
76
|
+
provider: string;
|
|
77
|
+
model: string;
|
|
78
|
+
}
|
|
79
|
+
interface LLMProvider {
|
|
80
|
+
id: string;
|
|
81
|
+
displayName: string;
|
|
82
|
+
models: ModelInfo[];
|
|
83
|
+
chat(params: ChatParams): Promise<ChatResult>;
|
|
84
|
+
chatStream(params: ChatParams): AsyncGenerator<string, ChatResult, unknown>;
|
|
85
|
+
/** Convert ToolDefinition[] to provider-native format */
|
|
86
|
+
serializeTools(tools: ToolDefinition[]): unknown;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type { ChatMessage as C, LLMProvider as L, ModelInfo as M, ResolvedModel as R, TokenUsage as T, ChatParams as a, ChatResult as b, ContentBlock as c, ToolUse as d, ToolDefinition as e };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LLMProvider, M as ModelInfo, e as ToolDefinition, a as ChatParams, b as ChatResult } from '../../provider-
|
|
1
|
+
import { L as LLMProvider, M as ModelInfo, e as ToolDefinition, a as ChatParams, b as ChatResult } from '../../provider-BHkqkSdq.js';
|
|
2
2
|
|
|
3
3
|
declare class AnthropicProvider implements LLMProvider {
|
|
4
4
|
readonly id = "anthropic";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LLMProvider, M as ModelInfo, e as ToolDefinition, a as ChatParams, b as ChatResult } from '../../provider-
|
|
1
|
+
import { L as LLMProvider, M as ModelInfo, e as ToolDefinition, a as ChatParams, b as ChatResult } from '../../provider-BHkqkSdq.js';
|
|
2
2
|
|
|
3
3
|
declare class OllamaProvider implements LLMProvider {
|
|
4
4
|
readonly id = "ollama";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { L as LLMProvider, M as ModelInfo, e as ToolDefinition, a as ChatParams, b as ChatResult } from '../../provider-
|
|
1
|
+
import { L as LLMProvider, M as ModelInfo, e as ToolDefinition, a as ChatParams, b as ChatResult } from '../../provider-BHkqkSdq.js';
|
|
2
2
|
|
|
3
3
|
declare class OpenAIProvider implements LLMProvider {
|
|
4
4
|
readonly id = "openai";
|