botinabox 1.9.2 → 1.10.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.
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  parseDiscordEvent
3
3
  } from "../../chunk-DLJKZD3Q.js";
4
+ import "../../chunk-3RG5ZIWI.js";
4
5
 
5
6
  // src/channels/discord/outbound.ts
6
7
  var DISCORD_MAX_LENGTH = 2e3;
@@ -80,7 +81,7 @@ var DiscordAdapter = class {
80
81
  /** Simulate receiving an inbound message (for testing/webhooks). */
81
82
  async receive(event) {
82
83
  if (this.onMessage) {
83
- const { parseDiscordEvent: parseDiscordEvent2 } = await import("../../inbound-SNEMBLGA.js");
84
+ const { parseDiscordEvent: parseDiscordEvent2 } = await import("../../inbound-WU7X2HGA.js");
84
85
  const msg = parseDiscordEvent2(event);
85
86
  await this.onMessage(msg);
86
87
  }
@@ -1,5 +1,5 @@
1
1
  import { C as ChannelAdapter, c as ChannelMeta, a as ChannelCapabilities, I as InboundMessage, b as ChannelConfig, H as HealthStatus, O as OutboundPayload, S as SendResult } from '../../channel-06G0vbIn.js';
2
- import { H as HookBus, a as ChatPipeline } from '../../chat-pipeline-DisuC8SB.js';
2
+ import { H as HookBus, a as ChatPipeline } from '../../chat-pipeline-C-XlLGNl.js';
3
3
  import 'better-sqlite3';
4
4
  import '../../provider-DLGUfnNx.js';
5
5
 
@@ -8,6 +8,7 @@ import {
8
8
  import {
9
9
  chunkText
10
10
  } from "../../chunk-ZTZFPTOQ.js";
11
+ import "../../chunk-3RG5ZIWI.js";
11
12
 
12
13
  // src/channels/slack/outbound.ts
13
14
  function formatForSlack(text) {
@@ -70,8 +71,8 @@ var SlackAdapter = class {
70
71
  /** Simulate receiving an inbound message (for testing/webhooks). */
71
72
  async receive(event) {
72
73
  if (this.onMessage) {
73
- const { parseSlackEvent: parseSlackEvent2 } = await import("../../inbound-ZJHAYVMF.js");
74
- const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-ZJHAYVMF.js");
74
+ const { parseSlackEvent: parseSlackEvent2 } = await import("../../inbound-IBKXBFZF.js");
75
+ const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-IBKXBFZF.js");
75
76
  let msg = parseSlackEvent2(event);
76
77
  if (msg.body.includes("[Voice message") && this.config?.botToken) {
77
78
  msg = await enrichVoiceMessage2(msg, this.config.botToken);
@@ -94,7 +95,7 @@ var SlackBoltAdapter = class {
94
95
  async start() {
95
96
  const boltModule = "@slack/bolt";
96
97
  const bolt = await import(boltModule);
97
- const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-ZJHAYVMF.js");
98
+ const { enrichVoiceMessage: enrichVoiceMessage2 } = await import("../../inbound-IBKXBFZF.js");
98
99
  const boltApp = new bolt.App({
99
100
  token: this.config.botToken,
100
101
  appToken: this.config.appToken,
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/channels/webhook/server.ts
2
4
  import { createServer } from "http";
3
5
 
@@ -0,0 +1,648 @@
1
+ import * as better_sqlite3 from 'better-sqlite3';
2
+ import { I as InboundMessage } from './channel-06G0vbIn.js';
3
+ import { C as ChatMessage } from './provider-DLGUfnNx.js';
4
+
5
+ type HookHandler = (context: Record<string, unknown>) => Promise<void> | void;
6
+ type Unsubscribe = () => void;
7
+ interface HookOptions {
8
+ /** 0–100, default 50. Lower = runs first. */
9
+ priority?: number;
10
+ /** Auto-unsubscribe after first invocation. */
11
+ once?: boolean;
12
+ /** Only fire if context matches all filter key/value pairs. */
13
+ filter?: Record<string, unknown>;
14
+ }
15
+ interface HookRegistration {
16
+ event: string;
17
+ handler: HookHandler;
18
+ priority: number;
19
+ once: boolean;
20
+ filter?: Record<string, unknown>;
21
+ /** Internal auto-increment for stable sort within same priority */
22
+ id: number;
23
+ }
24
+
25
+ /**
26
+ * Priority-ordered event bus for decoupled inter-layer communication.
27
+ * Story 1.1 — handlers run in priority order, errors are isolated,
28
+ * and registrations are unsubscribable.
29
+ */
30
+ declare class HookBus {
31
+ private readonly registrations;
32
+ private nextId;
33
+ register(event: string, handler: HookHandler, opts?: HookOptions): Unsubscribe;
34
+ emit(event: string, context: Record<string, unknown>): Promise<void>;
35
+ /** Emit synchronously (use only when async is not needed) */
36
+ emitSync(event: string, context: Record<string, unknown>): void;
37
+ hasListeners(event: string): boolean;
38
+ listRegistered(): string[];
39
+ /** Remove all handlers for an event, or all handlers if no event given */
40
+ clear(event?: string): void;
41
+ }
42
+
43
+ interface TableDefinition {
44
+ columns: Record<string, string>;
45
+ primaryKey?: string | string[];
46
+ tableConstraints?: string[];
47
+ relations?: Record<string, RelationDef>;
48
+ render?: string | ((rows: Row[]) => string);
49
+ outputFile?: string;
50
+ filter?: (rows: Row[]) => Row[];
51
+ }
52
+ interface RelationDef {
53
+ type: 'belongsTo' | 'hasMany';
54
+ table: string;
55
+ foreignKey: string;
56
+ references?: string;
57
+ }
58
+ interface EntityContextDef {
59
+ table: string;
60
+ directory: string;
61
+ slugColumn: string;
62
+ files: Record<string, EntityFileSpec>;
63
+ indexFile?: string;
64
+ /** Custom index render function. If omitted, a default listing is generated. */
65
+ indexRender?: (rows: Row[]) => string;
66
+ protectedFiles?: string[];
67
+ /** When true, this entity's data is never rendered into other entities' context files. */
68
+ protected?: boolean;
69
+ /** Enable at-rest encryption. Requires encryptionKey in Lattice options. */
70
+ encrypted?: boolean | {
71
+ columns: string[];
72
+ };
73
+ }
74
+ interface EntityFileSpec {
75
+ source: EntitySource;
76
+ render: string | ((rows: Row[]) => string);
77
+ junctionColumns?: string[];
78
+ omitIfEmpty?: boolean;
79
+ }
80
+ type EntitySource = {
81
+ type: 'self';
82
+ } | {
83
+ type: 'hasMany';
84
+ table: string;
85
+ foreignKey: string;
86
+ filters?: Filter[];
87
+ softDelete?: boolean;
88
+ orderBy?: string;
89
+ limit?: number;
90
+ } | {
91
+ type: 'manyToMany';
92
+ junctionTable: string;
93
+ localKey: string;
94
+ remoteKey: string;
95
+ remoteTable: string;
96
+ filters?: Filter[];
97
+ softDelete?: boolean;
98
+ orderBy?: string;
99
+ limit?: number;
100
+ } | {
101
+ type: 'belongsTo';
102
+ table: string;
103
+ foreignKey: string;
104
+ } | {
105
+ type: 'enriched';
106
+ include: Record<string, EntitySource>;
107
+ } | {
108
+ type: 'custom';
109
+ resolve: (row: Row, adapter: SqliteAdapter) => Row[];
110
+ };
111
+ interface Filter {
112
+ col: string;
113
+ op: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'in' | 'isNull' | 'isNotNull';
114
+ val?: unknown;
115
+ }
116
+ interface QueryOptions {
117
+ where?: Record<string, unknown>;
118
+ filters?: Filter[];
119
+ orderBy?: string | Array<{
120
+ col: string;
121
+ dir: 'asc' | 'desc';
122
+ }>;
123
+ orderDir?: 'asc' | 'desc';
124
+ limit?: number;
125
+ offset?: number;
126
+ }
127
+ type Row = Record<string, unknown>;
128
+ type PkLookup = string | Record<string, unknown>;
129
+ interface SqliteAdapter {
130
+ run(sql: string, params?: unknown[]): better_sqlite3.RunResult;
131
+ get<T = Row>(sql: string, params?: unknown[]): T | undefined;
132
+ all<T = Row>(sql: string, params?: unknown[]): T[];
133
+ tableInfo(table: string): TableInfoRow[];
134
+ invalidateTableCache(table: string): void;
135
+ }
136
+ interface TableInfoRow {
137
+ cid: number;
138
+ name: string;
139
+ type: string;
140
+ notnull: number;
141
+ dflt_value: unknown;
142
+ pk: number;
143
+ }
144
+ interface SeedItem {
145
+ table: string;
146
+ rows: Row[];
147
+ naturalKey?: string | string[];
148
+ junctions?: Array<{
149
+ table: string;
150
+ items: Array<Row>;
151
+ }>;
152
+ softDeleteMissing?: boolean;
153
+ }
154
+
155
+ declare class DataStoreError extends Error {
156
+ constructor(message: string);
157
+ }
158
+ /**
159
+ * Thin wrapper around Lattice that provides the botinabox DataStore API.
160
+ *
161
+ * Delegates all data operations to the latticesql package. Application-level
162
+ * events (task.created, run.completed, etc.) remain on the HookBus — they are
163
+ * emitted by orchestrator modules, not the data layer.
164
+ */
165
+ declare class DataStore {
166
+ private lattice;
167
+ private readonly hooks;
168
+ private readonly outputDir;
169
+ private _initialized;
170
+ private readonly deferredStatements;
171
+ constructor(opts: {
172
+ dbPath: string;
173
+ outputDir?: string;
174
+ wal?: boolean;
175
+ hooks?: HookBus;
176
+ });
177
+ /**
178
+ * Register a table definition. Must be called before init().
179
+ *
180
+ * tableConstraints may contain both inline constraints (FOREIGN KEY, UNIQUE)
181
+ * and standalone SQL statements (CREATE INDEX). Standalone statements are
182
+ * deferred and executed after init() creates the tables.
183
+ */
184
+ define(name: string, def: TableDefinition): void;
185
+ /**
186
+ * Register an entity context definition for per-entity file rendering.
187
+ */
188
+ defineEntityContext(name: string, def: EntityContextDef): void;
189
+ init(opts?: {
190
+ migrations?: Array<{
191
+ version: string;
192
+ sql: string;
193
+ }>;
194
+ }): Promise<void>;
195
+ private assertInitialized;
196
+ insert(table: string, row: Row): Promise<Row>;
197
+ upsert(table: string, row: Row): Promise<Row>;
198
+ update(table: string, pk: PkLookup, changes: Row): Promise<Row>;
199
+ delete(table: string, pk: PkLookup): Promise<void>;
200
+ /**
201
+ * Get a single row by primary key.
202
+ * Returns undefined if not found (Lattice returns null).
203
+ */
204
+ get(table: string, pk: PkLookup): Promise<Row | undefined>;
205
+ query(table: string, opts?: QueryOptions): Promise<Row[]>;
206
+ count(table: string, opts?: QueryOptions): Promise<number>;
207
+ link(junctionTable: string, row: Row): Promise<void>;
208
+ unlink(junctionTable: string, row: Row): Promise<void>;
209
+ migrate(migrations: Array<{
210
+ version: string;
211
+ sql: string;
212
+ }>): Promise<void>;
213
+ seed(items: SeedItem[]): Promise<void>;
214
+ render(): Promise<void>;
215
+ reconcile(): Promise<void>;
216
+ tableInfo(table: string): TableInfoRow[];
217
+ close(): void;
218
+ on(event: string, handler: (context: Record<string, unknown>) => void): void;
219
+ }
220
+
221
+ /**
222
+ * MessageStore — store-before-respond guarantee for all chat interactions.
223
+ * Story 7.1
224
+ *
225
+ * Every inbound message (with attachments) is stored BEFORE the bot responds.
226
+ * Every outbound message is stored BEFORE it is sent to the user.
227
+ * Storage confirmation is required before any response flows.
228
+ */
229
+
230
+ interface StoredAttachment {
231
+ fileType: string;
232
+ filename?: string;
233
+ mimeType?: string;
234
+ sizeBytes?: number;
235
+ contents?: string;
236
+ summary?: string;
237
+ url?: string;
238
+ }
239
+ interface StoreResult {
240
+ messageId: string;
241
+ attachmentIds: string[];
242
+ }
243
+ declare class MessageStore {
244
+ private db;
245
+ private hooks;
246
+ constructor(db: DataStore, hooks: HookBus);
247
+ /**
248
+ * Store an inbound message and its attachments.
249
+ * Must complete successfully before any bot response is generated.
250
+ */
251
+ storeInbound(msg: InboundMessage): Promise<StoreResult>;
252
+ /**
253
+ * Store an outbound message BEFORE sending it.
254
+ * Returns the message ID for confirmation tracking.
255
+ */
256
+ storeOutbound(opts: {
257
+ channel: string;
258
+ text: string;
259
+ threadId?: string;
260
+ agentId?: string;
261
+ agentSlug?: string;
262
+ taskId?: string;
263
+ }): Promise<string>;
264
+ /**
265
+ * Store an attachment linked to a message.
266
+ */
267
+ storeAttachment(messageId: string, att: StoredAttachment): Promise<string>;
268
+ /**
269
+ * Get recent messages in a thread for context building.
270
+ */
271
+ getThreadHistory(threadId: string, limit?: number): Promise<Array<Record<string, unknown>>>;
272
+ /**
273
+ * Get recent outbound messages in a thread for redundancy checking.
274
+ */
275
+ getRecentOutbound(threadId: string, limit?: number): Promise<Array<Record<string, unknown>>>;
276
+ /**
277
+ * Get recent messages in a channel (all threads combined).
278
+ * More reliable than getThreadHistory for DMs where thread_ids are inconsistent.
279
+ */
280
+ getChannelHistory(channel: string, limit?: number): Promise<Array<Record<string, unknown>>>;
281
+ /**
282
+ * Get recent messages from a specific user across all threads.
283
+ */
284
+ getUserHistory(userId: string, channel: string, limit?: number): Promise<Array<Record<string, unknown>>>;
285
+ /**
286
+ * Get attachments for a message.
287
+ */
288
+ getAttachments(messageId: string): Promise<Array<Record<string, unknown>>>;
289
+ }
290
+
291
+ /**
292
+ * ChatResponder — fast conversational layer with LLM-filtered responses.
293
+ * Story 7.2
294
+ *
295
+ * Provides rapid (<2s) conversational responses using a cheap LLM (Haiku).
296
+ * The responder has awareness of tools and capabilities but does NOT execute
297
+ * anything — it keeps the conversation going while work happens async.
298
+ *
299
+ * All outbound messages (direct, post-interpretation, task execution) are
300
+ * filtered through this layer for human readability and redundancy checking.
301
+ */
302
+
303
+ interface ChatResponderConfig {
304
+ /** System prompt for the conversational responder */
305
+ systemPrompt?: string;
306
+ /** Max tokens for context window. Default: 4000 */
307
+ contextWindowTokens?: number;
308
+ /** Max recent outbound messages to check for redundancy. Default: 10 */
309
+ redundancyWindow?: number;
310
+ /** Model to use for responses. Default: 'fast' (resolved via ModelRouter) */
311
+ model?: string;
312
+ /** Caller-provided LLM call function */
313
+ llmCall: (params: {
314
+ model: string;
315
+ messages: ChatMessage[];
316
+ system?: string;
317
+ maxTokens?: number;
318
+ }) => Promise<{
319
+ content: string;
320
+ }>;
321
+ }
322
+ declare class ChatResponder {
323
+ private db;
324
+ private hooks;
325
+ private messageStore;
326
+ private readonly systemPrompt;
327
+ private readonly contextWindowTokens;
328
+ private readonly redundancyWindow;
329
+ private readonly model;
330
+ private readonly llmCall;
331
+ constructor(db: DataStore, hooks: HookBus, messageStore: MessageStore, config: ChatResponderConfig);
332
+ /**
333
+ * Generate a fast conversational response to an inbound message.
334
+ * Uses rolling context window from thread history.
335
+ */
336
+ respond(opts: {
337
+ messageBody: string;
338
+ threadId: string;
339
+ channel: string;
340
+ userName?: string;
341
+ capabilities?: string;
342
+ additionalContext?: string;
343
+ }): Promise<string>;
344
+ /**
345
+ * Filter any outbound message through the LLM for human readability.
346
+ * This is the single funnel ALL responses pass through.
347
+ */
348
+ filterResponse(text: string, context?: {
349
+ channel?: string;
350
+ threadId?: string;
351
+ source?: string;
352
+ }): Promise<string>;
353
+ /**
354
+ * Check if a candidate outbound message is redundant with recent messages.
355
+ * Returns true if the message should be suppressed.
356
+ */
357
+ isRedundant(text: string, threadId: string): Promise<boolean>;
358
+ /**
359
+ * Full send pipeline: check redundancy → filter → store → deliver.
360
+ * Returns the message ID, or undefined if suppressed as redundant.
361
+ */
362
+ sendResponse(opts: {
363
+ text: string;
364
+ channel: string;
365
+ threadId: string;
366
+ agentId?: string;
367
+ agentSlug?: string;
368
+ taskId?: string;
369
+ source?: string;
370
+ skipRedundancyCheck?: boolean;
371
+ skipFilter?: boolean;
372
+ }): Promise<string | undefined>;
373
+ /**
374
+ * Build a context window from thread history, trimmed to token limit.
375
+ */
376
+ private buildContextWindow;
377
+ }
378
+
379
+ /**
380
+ * TriageRouter — content-based routing with deterministic-first resolution.
381
+ * Story 6.3
382
+ *
383
+ * Replaces the simple channel→agent binding with intelligent routing:
384
+ * 1. Keyword/regex rules evaluated first (deterministic, ~4ms)
385
+ * 2. LLM classification only for ambiguous messages (async, ~2-4s)
386
+ * 3. Ownership chain logged for every routing decision
387
+ *
388
+ * Key constraint: specialists return to triage, never to another specialist.
389
+ */
390
+
391
+ interface RoutingRule {
392
+ /** Target agent slug */
393
+ agentSlug: string;
394
+ /** Keywords that trigger this rule (case-insensitive) */
395
+ keywords?: string[];
396
+ /** Regex patterns that trigger this rule */
397
+ patterns?: string[];
398
+ /** Priority — lower number wins ties. Default: 50 */
399
+ priority?: number;
400
+ }
401
+ interface RoutingDecision {
402
+ timestamp: string;
403
+ source: string;
404
+ target: string;
405
+ reason: string;
406
+ method: 'deterministic' | 'llm';
407
+ messageId?: string;
408
+ channel?: string;
409
+ }
410
+ interface TriageRouterConfig {
411
+ /** Static routing rules evaluated deterministically */
412
+ rules: RoutingRule[];
413
+ /** Fallback agent if no rule matches and LLM is unavailable */
414
+ fallbackAgent?: string;
415
+ /** Whether to use LLM for ambiguous messages. Default: true */
416
+ llmFallback?: boolean;
417
+ /** Log decisions to the database. Default: true */
418
+ persist?: boolean;
419
+ }
420
+ declare class TriageRouter {
421
+ private db;
422
+ private hooks;
423
+ private readonly rules;
424
+ private readonly fallbackAgent?;
425
+ private readonly llmFallback;
426
+ private readonly persist;
427
+ private readonly compiledRules;
428
+ constructor(db: DataStore, hooks: HookBus, config: TriageRouterConfig);
429
+ /**
430
+ * Route an inbound message to the best agent.
431
+ * Returns the agent slug and the routing decision.
432
+ */
433
+ route(msg: InboundMessage): Promise<{
434
+ agentSlug: string | undefined;
435
+ decision: RoutingDecision;
436
+ }>;
437
+ /**
438
+ * Query the ownership chain for a given message or channel.
439
+ */
440
+ getDecisionHistory(filter?: {
441
+ channel?: string;
442
+ limit?: number;
443
+ }): Promise<RoutingDecision[]>;
444
+ /**
445
+ * LLM classification — emits a hook for external LLM integration.
446
+ * Returns agent slug + reason, or undefined if LLM is unavailable.
447
+ */
448
+ private classifyWithLLM;
449
+ private buildDecision;
450
+ private logDecision;
451
+ }
452
+
453
+ /**
454
+ * MessageInterpreter — async structured extraction from messages.
455
+ * Story 7.3
456
+ *
457
+ * After every message is stored, the interpreter runs async to extract
458
+ * structured data types: tasks, memories, files, user context, and custom types.
459
+ *
460
+ * Uses a cheap LLM (Haiku) for classification and extraction.
461
+ * Pluggable extractors allow apps to add custom data types.
462
+ */
463
+
464
+ interface ExtractedTask {
465
+ title: string;
466
+ description?: string;
467
+ dueDate?: string;
468
+ scheduled?: boolean;
469
+ priority?: number;
470
+ }
471
+ interface ExtractedMemory {
472
+ summary: string;
473
+ contents: string;
474
+ tags?: string[];
475
+ category?: string;
476
+ }
477
+ interface ExtractedFile {
478
+ filename: string;
479
+ fileType: string;
480
+ contents: string;
481
+ summary: string;
482
+ }
483
+ interface ExtractedUserContext {
484
+ trait: string;
485
+ value: string;
486
+ }
487
+ interface InterpretationResult {
488
+ messageId: string;
489
+ tasks: ExtractedTask[];
490
+ memories: ExtractedMemory[];
491
+ files: ExtractedFile[];
492
+ userContext: ExtractedUserContext[];
493
+ custom: Record<string, unknown[]>;
494
+ isTaskRequest: boolean;
495
+ }
496
+ type LLMCallFn = (params: {
497
+ model: string;
498
+ messages: ChatMessage[];
499
+ system?: string;
500
+ maxTokens?: number;
501
+ }) => Promise<{
502
+ content: string;
503
+ }>;
504
+ /**
505
+ * Pluggable extractor interface for custom data types.
506
+ */
507
+ interface Extractor {
508
+ readonly type: string;
509
+ extract(message: {
510
+ body: string;
511
+ attachments?: Array<Record<string, unknown>>;
512
+ }, llmCall: LLMCallFn): Promise<unknown[]>;
513
+ }
514
+ interface MessageInterpreterConfig {
515
+ /** Additional custom extractors beyond built-in ones */
516
+ extractors?: Extractor[];
517
+ /** Model for interpretation LLM calls. Default: 'fast' */
518
+ model?: string;
519
+ /** LLM call function */
520
+ llmCall: LLMCallFn;
521
+ /** Auto-create tasks from extracted tasks. Default: false */
522
+ autoCreateTasks?: boolean;
523
+ }
524
+ declare class MessageInterpreter {
525
+ private db;
526
+ private hooks;
527
+ private readonly extractors;
528
+ private readonly model;
529
+ private readonly llmCall;
530
+ private readonly autoCreateTasks;
531
+ constructor(db: DataStore, hooks: HookBus, config: MessageInterpreterConfig);
532
+ /**
533
+ * Interpret a stored message asynchronously.
534
+ * Extracts tasks, memories, files, user context, and custom types.
535
+ */
536
+ interpret(messageId: string): Promise<InterpretationResult>;
537
+ /**
538
+ * Extract structured data from message text using LLM.
539
+ */
540
+ private extractWithLLM;
541
+ }
542
+
543
+ /**
544
+ * ChatPipeline — configurable 6-layer chat orchestration.
545
+ * Story 7.4
546
+ *
547
+ * Replaces duplicated handler code across apps with a single configurable
548
+ * pipeline. Apps provide: system prompt, routing rules, LLM call function,
549
+ * and optional message filter. Everything else is framework-level.
550
+ *
551
+ * Layers:
552
+ * 1. Dedup + Storage (MessageStore)
553
+ * 2. Fast Response (ChatResponder)
554
+ * 3. Interpretation (MessageInterpreter)
555
+ * 4. Post-Interpretation Response
556
+ * 5. Task Dispatch (TriageRouter)
557
+ * 6. Task Execution Response
558
+ */
559
+
560
+ interface ChatPipelineConfig {
561
+ /** LLM call function for chat responses and interpretation */
562
+ llmCall: ChatResponderConfig['llmCall'];
563
+ /** System prompt for the conversational responder */
564
+ systemPrompt: string;
565
+ /** Agent routing rules for task dispatch */
566
+ routingRules: RoutingRule[];
567
+ /** Default agent when no rule matches */
568
+ fallbackAgent: string;
569
+ /** Optional message filter — return false to ignore a message */
570
+ messageFilter?: (msg: InboundMessage) => boolean;
571
+ /** Optional capabilities description for the responder */
572
+ capabilities?: string;
573
+ /** Channel this pipeline handles (default: 'slack') */
574
+ channel?: string;
575
+ /** Custom extractors for MessageInterpreter */
576
+ extractors?: Extractor[];
577
+ /** Dedup window in ms (default: 300_000 = 5 min) */
578
+ dedupWindowMs?: number;
579
+ /** Model for fast responses (default: 'fast') */
580
+ model?: string;
581
+ /** Enable LLM fallback routing (default: false) */
582
+ llmRouting?: boolean;
583
+ /** TaskQueue instance — required for task dispatch */
584
+ tasks: {
585
+ create(task: Record<string, unknown>): Promise<string>;
586
+ update(id: string, changes: Record<string, unknown>): Promise<void>;
587
+ get(id: string): Promise<Record<string, unknown> | undefined>;
588
+ };
589
+ /** WakeupQueue instance — required for agent waking */
590
+ wakeups: {
591
+ enqueue(agentId: string, source: string, context?: Record<string, unknown>): Promise<string>;
592
+ };
593
+ }
594
+ declare class ChatPipeline {
595
+ private db;
596
+ private hooks;
597
+ readonly messageStore: MessageStore;
598
+ readonly responder: ChatResponder;
599
+ readonly interpreter: MessageInterpreter;
600
+ readonly router: TriageRouter;
601
+ private readonly channel;
602
+ private readonly messageFilter?;
603
+ private readonly capabilities?;
604
+ private readonly dedupWindowMs;
605
+ private readonly tasks;
606
+ private readonly wakeups;
607
+ private readonly threadChannelMap;
608
+ /** Last dispatch promise — exposed for testing. */
609
+ lastDispatch: Promise<void>;
610
+ constructor(db: DataStore, hooks: HookBus, config: ChatPipelineConfig);
611
+ /**
612
+ * Resolve the Slack channel ID for a thread (for response delivery).
613
+ */
614
+ resolveChannel(threadId: string, taskId?: string): Promise<string | undefined>;
615
+ /**
616
+ * Register the 6-layer pipeline on the HookBus.
617
+ */
618
+ private registerHandlers;
619
+ /**
620
+ * Check and record message dedup (SHA256 hash, configurable window).
621
+ */
622
+ private isDuplicate;
623
+ /**
624
+ * Async interpretation + task dispatch (Layers 3-5).
625
+ *
626
+ * ALWAYS creates a task programmatically — task creation does not depend
627
+ * on LLM classification. Interpretation enriches but never gates dispatch.
628
+ */
629
+ private interpretAndDispatch;
630
+ /**
631
+ * Programmatic task creation — guaranteed, no LLM dependency.
632
+ */
633
+ private guaranteedTaskDispatch;
634
+ /**
635
+ * Route and dispatch extracted tasks.
636
+ */
637
+ private dispatchTasks;
638
+ /**
639
+ * Resolve Slack channel ID from thread_task_map or in-memory fallback.
640
+ */
641
+ private resolveChannelId;
642
+ /**
643
+ * Build human-readable interpretation summary.
644
+ */
645
+ private buildSummary;
646
+ }
647
+
648
+ export { type ChatResponderConfig as C, DataStore as D, type EntityContextDef as E, type Filter as F, HookBus as H, type InterpretationResult as I, type LLMCallFn as L, MessageInterpreter as M, type PkLookup as P, type QueryOptions as Q, type RelationDef as R, type SeedItem as S, type TableDefinition as T, type Unsubscribe as U, ChatPipeline as a, type ChatPipelineConfig as b, ChatResponder as c, DataStoreError as d, type EntityFileSpec as e, type EntitySource as f, type ExtractedFile as g, type ExtractedMemory as h, type ExtractedTask as i, type ExtractedUserContext as j, type Extractor as k, type HookHandler as l, type HookOptions as m, type HookRegistration as n, type MessageInterpreterConfig as o, MessageStore as p, type RoutingDecision as q, type RoutingRule as r, type Row as s, type SqliteAdapter as t, type StoreResult as u, type StoredAttachment as v, type TableInfoRow as w, TriageRouter as x, type TriageRouterConfig as y };
@@ -0,0 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
package/dist/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import "./chunk-3RG5ZIWI.js";
2
3
 
3
4
  // src/cli.ts
4
5
  import * as readline from "readline";
@@ -178,7 +179,7 @@ async function authGoogle(args) {
178
179
  });
179
180
  }
180
181
  };
181
- const { GoogleGmailConnector } = await import("./gmail-connector-ULSMN6X2.js");
182
+ const { GoogleGmailConnector } = await import("./gmail-connector-Z7SO6VOS.js");
182
183
  const connector = new GoogleGmailConnector({ tokenLoader, tokenSaver });
183
184
  connector.config = {
184
185
  account,
@@ -8,6 +8,7 @@ import {
8
8
  refreshIfNeeded,
9
9
  saveTokens
10
10
  } from "../../chunk-XYF5PSB2.js";
11
+ import "../../chunk-3RG5ZIWI.js";
11
12
 
12
13
  // src/connectors/google/calendar-connector.ts
13
14
  var GoogleCalendarConnector = class {
@@ -0,0 +1,7 @@
1
+ import {
2
+ GoogleGmailConnector
3
+ } from "./chunk-XYF5PSB2.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+ export {
6
+ GoogleGmailConnector
7
+ };
@@ -0,0 +1,11 @@
1
+ import {
2
+ enrichVoiceMessage,
3
+ extractVoiceTranscript,
4
+ parseSlackEvent
5
+ } from "./chunk-NNPCKR6G.js";
6
+ import "./chunk-3RG5ZIWI.js";
7
+ export {
8
+ enrichVoiceMessage,
9
+ extractVoiceTranscript,
10
+ parseSlackEvent
11
+ };
@@ -0,0 +1,7 @@
1
+ import {
2
+ parseDiscordEvent
3
+ } from "./chunk-DLJKZD3Q.js";
4
+ import "./chunk-3RG5ZIWI.js";
5
+ export {
6
+ parseDiscordEvent
7
+ };
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ import { T as TokenUsage, L as LLMProvider, M as ModelInfo, R as ResolvedModel,
4
4
  export { a as ChatParams, b as ChatResult, c as ContentBlock, d as ToolUse } from './provider-DLGUfnNx.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 } from './chat-pipeline-DisuC8SB.js';
8
- export { a as ChatPipeline, b as ChatPipelineConfig, c as ChatResponder, d as DataStoreError, E as EntityContextDef, e as EntityFileSpec, f as EntitySource, g as ExtractedFile, h as ExtractedMemory, i as ExtractedTask, j as ExtractedUserContext, k as Extractor, F as Filter, l as HookHandler, m as HookOptions, n as HookRegistration, I as InterpretationResult, L as LLMCallFn, M as MessageInterpreter, o as MessageInterpreterConfig, p as MessageStore, 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-DisuC8SB.js';
7
+ import { C as ChatResponderConfig, D as DataStore, H as HookBus } from './chat-pipeline-C-XlLGNl.js';
8
+ export { a as ChatPipeline, b as ChatPipelineConfig, c as ChatResponder, d as DataStoreError, E as EntityContextDef, e as EntityFileSpec, f as EntitySource, g as ExtractedFile, h as ExtractedMemory, i as ExtractedTask, j as ExtractedUserContext, k as Extractor, F as Filter, l as HookHandler, m as HookOptions, n as HookRegistration, I as InterpretationResult, L as LLMCallFn, M as MessageInterpreter, o as MessageInterpreterConfig, p as MessageStore, 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-C-XlLGNl.js';
9
9
  import 'better-sqlite3';
10
10
 
11
11
  /** Execution adapter types — Story 1.5 / 3.4 / 3.5 */
@@ -1835,6 +1835,8 @@ type ToolHandler = (input: Record<string, unknown>, context: {
1835
1835
  taskId: string;
1836
1836
  agentId: string;
1837
1837
  hooks: HookBus;
1838
+ /** Resolve a relative file path to an absolute path (environment-aware). */
1839
+ resolveFilePath?: (path: string) => string;
1838
1840
  }) => Promise<string>;
1839
1841
  interface ExecutionEngineConfig {
1840
1842
  /** Anthropic client instance */
@@ -1869,6 +1871,8 @@ interface ExecutionEngineConfig {
1869
1871
  systemPromptSuffix?: string;
1870
1872
  /** Include system context (users, files, etc). Default: true */
1871
1873
  includeSystemContext?: boolean;
1874
+ /** Resolve file paths from DB-relative to absolute (for cross-environment support). */
1875
+ resolveFilePath?: (path: string) => string;
1872
1876
  }
1873
1877
  declare function registerExecutionEngine(opts: {
1874
1878
  db: DataStore;
@@ -1877,6 +1881,16 @@ declare function registerExecutionEngine(opts: {
1877
1881
  config: ExecutionEngineConfig;
1878
1882
  }): Promise<void>;
1879
1883
 
1884
+ declare const sendFileTool: {
1885
+ definition: ToolDefinition;
1886
+ handler: ToolHandler;
1887
+ };
1888
+
1889
+ declare const readFileTool: {
1890
+ definition: ToolDefinition;
1891
+ handler: ToolHandler;
1892
+ };
1893
+
1880
1894
  interface SecretInput {
1881
1895
  name: string;
1882
1896
  type?: string;
@@ -1965,4 +1979,4 @@ declare function isLoginRequired(stdout: string): boolean;
1965
1979
  /** Rewrite local image paths to prevent CLI auto-embedding as vision content. */
1966
1980
  declare function deactivateLocalImagePaths(prompt: string): string;
1967
1981
 
1968
- export { AGENT_STATUSES, type AgentConfig, type AgentDefinition, type AgentFilter, type AgentRecord, AgentRegistry, type AgentStatus, ApiExecutionAdapter, type ApprovalResponse, type ApprovalStatus, AuditEmitter, type AuditEvent, BackupManager, type BotConfig, BreakerState, type BudgetCheck, type BudgetConfig, BudgetController, CORE_MIGRATIONS, ChannelAdapter, ChannelRegistry, ChannelRegistryError, ChatMessage, ChatResponderConfig, ChatSessionManager, CircuitBreaker, type CircuitBreakerConfig, CliExecutionAdapter, type ColumnValidator, ColumnValidatorImpl, type ConfigLoadError, type ConfigLoadResult, ConnectorConfig, DEFAULTS, DEFAULT_CONFIG, type DataConfig, DataStore, type DefaultLLMCallConfig, DeterministicAdapter, type DeterministicConfig, type DomainEntityContextOptions, type DomainSchemaOptions, DriftGate, EVENTS, type EntityColumnDef, type EntityConfig, type ExecutionAdapter, type ExecutionEngineConfig, type FeedbackEntry, type GateFinding, type GateInput, type GateResult, GateRunner, type GateVerdict, GovernanceGate, HealthStatus, HookBus, InboundMessage, LLMProvider, LearningPipeline, type LearningPipelineConfig, type LoopDetection, LoopDetector, type LoopDetectorConfig, LoopType, MAX_CHAIN_DEPTH, MessagePipeline, type ModelConfig, ModelInfo, ModelRouter, NdjsonLogger, NotificationQueue, type PackageMigration, type PackageUpdate, type ParsedStream, type PermissionPrompt, type PermissionProvider, PermissionRelay, type PermissionRelayConfig, type PlaybookEntry, ProviderRegistry, QAGate, QualityGate, RUN_STATUSES, type RenderConfig, ResolvedModel, type RetryPolicy, type RunContext, RunManager, type RunResult, type RunStatus, type SanitizerOptions, type Schedule, type ScheduleDef, Scheduler, type SchemaError, type SecretInput, type SecretMeta, SecretStore, type SecurityConfig, SessionKey, SessionManager, type SkillEntry, type StepRef, type SystemContextOptions, TASK_STATUSES, type TaskDefinition, TaskQueue, type TaskRecord, type TaskStatus, TokenUsage, type ToolDefinition, type ToolHandler, UpdateChecker, type UpdateConfig, UpdateManager, type UpdateManifest, type UsageSummary, type User, type UserInput, UserRegistry, WakeupQueue, type WorkflowConfigEntry, type WorkflowDefinition$1 as WorkflowDefinition, WorkflowEngine, type WorkflowRunRecord, type WorkflowRunStatus, type WorkflowStep$1 as WorkflowStep, type WorkflowStepConfig, type WorkflowTrigger, _resetConfig, areDependenciesMet, autoUpdate, buildAgentBindings, buildChainOrigin, buildProcessEnv, buildSystemContext, checkAllowlist, checkChainDepth, checkMentionGate, chunkText, classifyUpdate, compareVersions, createConfigRevision, createDefaultLLMCall, deactivateLocalImagePaths, defineCoreEntityContexts, defineCoreTables, defineDomainEntityContexts, defineDomainTables, detectCycle, discoverChannels, discoverProviders, formatText, getConfig, initConfig, interpolate, interpolateEnv, isLoginRequired, isMaxTurns, loadConfig, parseClaudeStream, parseVersion, registerExecutionEngine, runPackageMigrations, sanitize, topologicalSort, truncateAtWord, validateConfig };
1982
+ export { AGENT_STATUSES, type AgentConfig, type AgentDefinition, type AgentFilter, type AgentRecord, AgentRegistry, type AgentStatus, ApiExecutionAdapter, type ApprovalResponse, type ApprovalStatus, AuditEmitter, type AuditEvent, BackupManager, type BotConfig, BreakerState, type BudgetCheck, type BudgetConfig, BudgetController, CORE_MIGRATIONS, ChannelAdapter, ChannelRegistry, ChannelRegistryError, ChatMessage, ChatResponderConfig, ChatSessionManager, CircuitBreaker, type CircuitBreakerConfig, CliExecutionAdapter, type ColumnValidator, ColumnValidatorImpl, type ConfigLoadError, type ConfigLoadResult, ConnectorConfig, DEFAULTS, DEFAULT_CONFIG, type DataConfig, DataStore, type DefaultLLMCallConfig, DeterministicAdapter, type DeterministicConfig, type DomainEntityContextOptions, type DomainSchemaOptions, DriftGate, EVENTS, type EntityColumnDef, type EntityConfig, type ExecutionAdapter, type ExecutionEngineConfig, type FeedbackEntry, type GateFinding, type GateInput, type GateResult, GateRunner, type GateVerdict, GovernanceGate, HealthStatus, HookBus, InboundMessage, LLMProvider, LearningPipeline, type LearningPipelineConfig, type LoopDetection, LoopDetector, type LoopDetectorConfig, LoopType, MAX_CHAIN_DEPTH, MessagePipeline, type ModelConfig, ModelInfo, ModelRouter, NdjsonLogger, NotificationQueue, type PackageMigration, type PackageUpdate, type ParsedStream, type PermissionPrompt, type PermissionProvider, PermissionRelay, type PermissionRelayConfig, type PlaybookEntry, ProviderRegistry, QAGate, QualityGate, RUN_STATUSES, type RenderConfig, ResolvedModel, type RetryPolicy, type RunContext, RunManager, type RunResult, type RunStatus, type SanitizerOptions, type Schedule, type ScheduleDef, Scheduler, type SchemaError, type SecretInput, type SecretMeta, SecretStore, type SecurityConfig, SessionKey, SessionManager, type SkillEntry, type StepRef, type SystemContextOptions, TASK_STATUSES, type TaskDefinition, TaskQueue, type TaskRecord, type TaskStatus, TokenUsage, type ToolDefinition, type ToolHandler, UpdateChecker, type UpdateConfig, UpdateManager, type UpdateManifest, type UsageSummary, type User, type UserInput, UserRegistry, WakeupQueue, type WorkflowConfigEntry, type WorkflowDefinition$1 as WorkflowDefinition, WorkflowEngine, type WorkflowRunRecord, type WorkflowRunStatus, type WorkflowStep$1 as WorkflowStep, type WorkflowStepConfig, type WorkflowTrigger, _resetConfig, areDependenciesMet, autoUpdate, buildAgentBindings, buildChainOrigin, buildProcessEnv, buildSystemContext, checkAllowlist, checkChainDepth, checkMentionGate, chunkText, classifyUpdate, compareVersions, createConfigRevision, createDefaultLLMCall, deactivateLocalImagePaths, defineCoreEntityContexts, defineCoreTables, defineDomainEntityContexts, defineDomainTables, detectCycle, discoverChannels, discoverProviders, formatText, getConfig, initConfig, interpolate, interpolateEnv, isLoginRequired, isMaxTurns, loadConfig, parseClaudeStream, parseVersion, readFileTool, registerExecutionEngine, runPackageMigrations, sanitize, sendFileTool, topologicalSort, truncateAtWord, validateConfig };
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  chunkText
3
3
  } from "./chunk-ZTZFPTOQ.js";
4
+ import {
5
+ __require
6
+ } from "./chunk-3RG5ZIWI.js";
4
7
 
5
8
  // src/shared/constants.ts
6
9
  var EVENTS = {
@@ -1287,6 +1290,17 @@ var MessageStore = class {
1287
1290
  });
1288
1291
  return messages;
1289
1292
  }
1293
+ /**
1294
+ * Get recent messages in a channel (all threads combined).
1295
+ * More reliable than getThreadHistory for DMs where thread_ids are inconsistent.
1296
+ */
1297
+ async getChannelHistory(channel, limit = 50) {
1298
+ return this.db.query("messages", {
1299
+ where: { channel },
1300
+ orderBy: "created_at",
1301
+ limit
1302
+ });
1303
+ }
1290
1304
  /**
1291
1305
  * Get recent messages from a specific user across all threads.
1292
1306
  */
@@ -1345,10 +1359,9 @@ var ChatResponder = class {
1345
1359
  * Uses rolling context window from thread history.
1346
1360
  */
1347
1361
  async respond(opts) {
1348
- const history = await this.messageStore.getThreadHistory(
1349
- opts.threadId,
1362
+ const history = await this.messageStore.getChannelHistory(
1363
+ opts.channel,
1350
1364
  50
1351
- // get more, trim by tokens
1352
1365
  );
1353
1366
  const messages = this.buildContextWindow(history, opts.messageBody);
1354
1367
  let system = this.systemPrompt;
@@ -6113,7 +6126,7 @@ ${systemContext}` : "",
6113
6126
  try {
6114
6127
  const result = await handler(
6115
6128
  toolUse.input,
6116
- { taskId, agentId: assigneeId, hooks }
6129
+ { taskId, agentId: assigneeId, hooks, resolveFilePath: config.resolveFilePath }
6117
6130
  );
6118
6131
  toolResults.push({ type: "tool_result", tool_use_id: toolUse.id, content: result });
6119
6132
  } catch (err) {
@@ -6142,6 +6155,102 @@ ${systemContext}` : "",
6142
6155
  });
6143
6156
  }
6144
6157
 
6158
+ // src/core/orchestrator/tools/send-file.ts
6159
+ import { existsSync as existsSync3 } from "fs";
6160
+ import { basename } from "path";
6161
+ var sendFileTool = {
6162
+ definition: {
6163
+ name: "send_file",
6164
+ description: "Send/deliver/attach a file to the user on Slack. Use this when the user asks for a document, contract, report, or any file. The file_path is in the Files section of your system context.",
6165
+ input_schema: {
6166
+ type: "object",
6167
+ properties: {
6168
+ file_path: { type: "string", description: "Path to the file (from system context)" }
6169
+ },
6170
+ required: ["file_path"]
6171
+ }
6172
+ },
6173
+ handler: async (input, context) => {
6174
+ const rawPath = input.file_path;
6175
+ const filePath = context.resolveFilePath?.(rawPath) ?? rawPath;
6176
+ if (!existsSync3(filePath)) return `Error: file not found at ${filePath}`;
6177
+ await context.hooks.emit("file.deliver", {
6178
+ filePath,
6179
+ fileName: basename(filePath),
6180
+ taskId: context.taskId
6181
+ });
6182
+ return `File "${basename(filePath)}" sent to user.`;
6183
+ }
6184
+ };
6185
+
6186
+ // src/core/orchestrator/tools/read-file.ts
6187
+ import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
6188
+ var readFileTool = {
6189
+ definition: {
6190
+ name: "read_file",
6191
+ description: "Read/review the contents of a file. Use this when the user asks about what a document contains, wants you to review a contract, check terms, summarize a report, etc. Supports .docx (Word), .txt, .md, .json, .csv. The file_path is in the Files section of your system context.",
6192
+ input_schema: {
6193
+ type: "object",
6194
+ properties: {
6195
+ file_path: { type: "string", description: "Path to the file (from system context)" }
6196
+ },
6197
+ required: ["file_path"]
6198
+ }
6199
+ },
6200
+ handler: async (input, context) => {
6201
+ const rawPath = input.file_path;
6202
+ const filePath = context.resolveFilePath?.(rawPath) ?? rawPath;
6203
+ if (!existsSync4(filePath)) return `Error: file not found at ${filePath}`;
6204
+ try {
6205
+ if (filePath.endsWith(".docx")) {
6206
+ return extractDocxText(filePath);
6207
+ }
6208
+ return readFileSync6(filePath, "utf8").slice(0, 8e3);
6209
+ } catch (err) {
6210
+ return `Error reading file: ${err instanceof Error ? err.message : String(err)}`;
6211
+ }
6212
+ }
6213
+ };
6214
+ function extractDocxText(filePath) {
6215
+ const data = readFileSync6(filePath);
6216
+ try {
6217
+ const zip = parseZipEntries(data);
6218
+ const docEntry = zip.find((e) => e.name === "word/document.xml");
6219
+ if (!docEntry) return "Error: could not find document.xml in docx";
6220
+ const xml = docEntry.data.toString("utf8");
6221
+ return xml.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim().slice(0, 8e3);
6222
+ } catch {
6223
+ return "Error: could not parse docx file";
6224
+ }
6225
+ }
6226
+ function parseZipEntries(buf) {
6227
+ const entries = [];
6228
+ let offset = 0;
6229
+ while (offset < buf.length - 4) {
6230
+ if (buf[offset] !== 80 || buf[offset + 1] !== 75 || buf[offset + 2] !== 3 || buf[offset + 3] !== 4) {
6231
+ break;
6232
+ }
6233
+ const compressionMethod = buf.readUInt16LE(offset + 8);
6234
+ const compressedSize = buf.readUInt32LE(offset + 18);
6235
+ const nameLen = buf.readUInt16LE(offset + 26);
6236
+ const extraLen = buf.readUInt16LE(offset + 28);
6237
+ const name = buf.slice(offset + 30, offset + 30 + nameLen).toString("utf8");
6238
+ const dataStart = offset + 30 + nameLen + extraLen;
6239
+ if (compressionMethod === 0) {
6240
+ entries.push({ name, data: buf.slice(dataStart, dataStart + compressedSize) });
6241
+ } else if (compressionMethod === 8) {
6242
+ try {
6243
+ const { inflateRawSync } = __require("zlib");
6244
+ const inflated = inflateRawSync(buf.slice(dataStart, dataStart + compressedSize));
6245
+ entries.push({ name, data: inflated });
6246
+ } catch {
6247
+ }
6248
+ }
6249
+ offset = dataStart + compressedSize;
6250
+ }
6251
+ return entries;
6252
+ }
6253
+
6145
6254
  // src/core/orchestrator/user-registry.ts
6146
6255
  import { v4 as uuidv4 } from "uuid";
6147
6256
  var UserRegistry = class {
@@ -6555,9 +6664,11 @@ export {
6555
6664
  loadConfig,
6556
6665
  parseClaudeStream,
6557
6666
  parseVersion,
6667
+ readFileTool,
6558
6668
  registerExecutionEngine,
6559
6669
  runPackageMigrations,
6560
6670
  sanitize,
6671
+ sendFileTool,
6561
6672
  topologicalSort,
6562
6673
  truncateAtWord,
6563
6674
  validateConfig
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/providers/anthropic/provider.ts
2
4
  import Anthropic from "@anthropic-ai/sdk";
3
5
 
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/providers/ollama/provider.ts
2
4
  var OllamaProvider = class {
3
5
  id = "ollama";
@@ -1,3 +1,5 @@
1
+ import "../../chunk-3RG5ZIWI.js";
2
+
1
3
  // src/providers/openai/provider.ts
2
4
  import OpenAI from "openai";
3
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botinabox",
3
- "version": "1.9.2",
3
+ "version": "1.10.0",
4
4
  "description": "Bot in a Box — framework for building multi-agent bots",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",