botinabox 2.8.0 → 2.9.0

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.
@@ -284,4 +284,86 @@ declare class GoogleDriveConnector implements Connector<DriveFileRecord> {
284
284
  private mapFile;
285
285
  }
286
286
 
287
- export { type CalendarAttendee, type CalendarConnectorOpts, type CalendarEventRecord, type DriveConnectorOpts, type DriveFileRecord, type DriveOwner, type EmailAddress, type EmailAttachment, type EmailRecord, type GmailConnectorOpts, GoogleCalendarConnector, type GoogleConnectorConfig, GoogleDriveConnector, GoogleGmailConnector, type GoogleOAuthConfig, type GoogleServiceAccountConfig, type GoogleTokens, createOAuth2Client, createServiceAccountClient, exchangeCode, getAuthUrl, loadTokens, refreshIfNeeded, saveTokens };
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-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';
1
+ import { C as ChannelAdapter, H as HealthStatus, I as InboundMessage } from './channel-CVm1AWUF.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-CVm1AWUF.js';
3
3
  import { T as TokenUsage, L as LLMProvider, M as ModelInfo, R as ResolvedModel, C as ChatMessage } from './provider-BHkqkSdq.js';
4
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-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';
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-aBSj7a4E.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-aBSj7a4E.js';
9
9
  import 'better-sqlite3';
10
10
 
11
11
  /** Execution adapter types — Story 1.5 / 3.4 / 3.5 */
@@ -1065,6 +1065,7 @@ type ContentBlock = {
1065
1065
  id?: string;
1066
1066
  name?: string;
1067
1067
  input?: unknown;
1068
+ source?: unknown;
1068
1069
  };
1069
1070
  type MessageParam = {
1070
1071
  role: string;
package/dist/index.js CHANGED
@@ -2161,7 +2161,8 @@ ${ctx2}`;
2161
2161
  history,
2162
2162
  msg.body,
2163
2163
  threadTs,
2164
- channelId
2164
+ channelId,
2165
+ msg.attachmentBlocks
2165
2166
  );
2166
2167
  await this.hooks.emit("typing.stop", { channel: this.channel, threadId: threadTs });
2167
2168
  if (text) {
@@ -2209,14 +2210,15 @@ ${ctx2}`;
2209
2210
  /**
2210
2211
  * Primary agent tool loop — adapted from ExecutionEngine pattern.
2211
2212
  */
2212
- async think(systemPrompt, history, currentMessage, threadTs, channelId) {
2213
+ async think(systemPrompt, history, currentMessage, threadTs, channelId, attachmentBlocks) {
2213
2214
  const model = this.config.model ?? "claude-sonnet-4-6";
2214
2215
  const maxIterations = this.config.maxIterations ?? DEFAULT_MAX_ITERATIONS;
2215
2216
  const maxTokens = this.config.maxTokens ?? DEFAULT_MAX_TOKENS;
2216
2217
  const tasksDispatched = [];
2218
+ const userContent = attachmentBlocks?.length ? [...attachmentBlocks, { type: "text", text: currentMessage }] : currentMessage;
2217
2219
  const messages = [
2218
2220
  ...history,
2219
- { role: "user", content: currentMessage }
2221
+ { role: "user", content: userContent }
2220
2222
  ];
2221
2223
  let finalText = "";
2222
2224
  for (let i = 0; i < maxIterations; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botinabox",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "Bot in a Box — framework for building multi-agent bots",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",