@diegoaltoworks/chatter 1.0.0 → 2.1.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.
Files changed (77) hide show
  1. package/README.md +3 -1
  2. package/dist/channels/gates.d.ts +21 -2
  3. package/dist/channels/gates.d.ts.map +1 -1
  4. package/dist/channels/index.d.ts +5 -3
  5. package/dist/channels/index.d.ts.map +1 -1
  6. package/dist/channels/index.js +31 -13
  7. package/dist/channels/index.mjs +30 -13
  8. package/dist/channels/matrix/channel.d.ts +2 -0
  9. package/dist/channels/matrix/channel.d.ts.map +1 -1
  10. package/dist/channels/matrix/handler.d.ts +9 -0
  11. package/dist/channels/matrix/handler.d.ts.map +1 -1
  12. package/dist/channels/matrix/index.d.ts +1 -1
  13. package/dist/channels/matrix/index.d.ts.map +1 -1
  14. package/dist/channels/matrix/index.js +75 -20
  15. package/dist/channels/matrix/index.mjs +74 -20
  16. package/dist/channels/matrix/updates.d.ts +8 -2
  17. package/dist/channels/matrix/updates.d.ts.map +1 -1
  18. package/dist/channels/pipeline.d.ts +34 -4
  19. package/dist/channels/pipeline.d.ts.map +1 -1
  20. package/dist/channels/polling.d.ts +11 -0
  21. package/dist/channels/polling.d.ts.map +1 -1
  22. package/dist/channels/telegram/channel.d.ts +2 -0
  23. package/dist/channels/telegram/channel.d.ts.map +1 -1
  24. package/dist/channels/telegram/handler.d.ts +9 -0
  25. package/dist/channels/telegram/handler.d.ts.map +1 -1
  26. package/dist/channels/telegram/index.d.ts +1 -1
  27. package/dist/channels/telegram/index.d.ts.map +1 -1
  28. package/dist/channels/telegram/index.js +73 -24
  29. package/dist/channels/telegram/index.mjs +72 -24
  30. package/dist/channels/telegram/updates.d.ts +8 -2
  31. package/dist/channels/telegram/updates.d.ts.map +1 -1
  32. package/dist/channels/telegram/webhook.d.ts +10 -0
  33. package/dist/channels/telegram/webhook.d.ts.map +1 -1
  34. package/dist/channels/whatsapp/channel.d.ts +8 -0
  35. package/dist/channels/whatsapp/channel.d.ts.map +1 -1
  36. package/dist/channels/whatsapp/inbound.d.ts +2 -0
  37. package/dist/channels/whatsapp/inbound.d.ts.map +1 -1
  38. package/dist/channels/whatsapp/index.js +45 -18
  39. package/dist/channels/whatsapp/index.mjs +45 -18
  40. package/dist/core/answer.d.ts +9 -2
  41. package/dist/core/answer.d.ts.map +1 -1
  42. package/dist/core/chunking.d.ts +31 -0
  43. package/dist/core/chunking.d.ts.map +1 -0
  44. package/dist/core/guardrails.d.ts +11 -1
  45. package/dist/core/guardrails.d.ts.map +1 -1
  46. package/dist/core/llm.d.ts +3 -1
  47. package/dist/core/llm.d.ts.map +1 -1
  48. package/dist/core/retrieval.d.ts +39 -0
  49. package/dist/core/retrieval.d.ts.map +1 -1
  50. package/dist/history/index.js +12 -9
  51. package/dist/history/index.mjs +12 -9
  52. package/dist/index.d.ts +4 -2
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +261 -52
  55. package/dist/index.mjs +254 -47
  56. package/dist/mcp-server.d.ts.map +1 -1
  57. package/dist/mcp-server.js +217 -30
  58. package/dist/mcp-server.mjs +216 -29
  59. package/dist/personas/index.d.ts +1 -1
  60. package/dist/personas/index.d.ts.map +1 -1
  61. package/dist/personas/index.js +21 -7
  62. package/dist/personas/index.mjs +21 -7
  63. package/dist/personas/resolver.d.ts +35 -8
  64. package/dist/personas/resolver.d.ts.map +1 -1
  65. package/dist/personas/timeContext.d.ts.map +1 -1
  66. package/dist/routes/demo.d.ts.map +1 -1
  67. package/dist/routes/openai.d.ts.map +1 -1
  68. package/dist/routes/private.d.ts.map +1 -1
  69. package/dist/routes/public.d.ts.map +1 -1
  70. package/dist/scheduler/index.js +12 -9
  71. package/dist/scheduler/index.mjs +12 -9
  72. package/dist/server.d.ts.map +1 -1
  73. package/dist/server.js +251 -50
  74. package/dist/server.mjs +246 -45
  75. package/dist/types.d.ts +39 -1
  76. package/dist/types.d.ts.map +1 -1
  77. package/package.json +13 -13
package/dist/index.js CHANGED
@@ -94,6 +94,126 @@ var init_buildLock = __esm({
94
94
  }
95
95
  });
96
96
 
97
+ // src/core/chunking.ts
98
+ function headingOf(line) {
99
+ const match = HEADING.exec(line);
100
+ if (!match) return void 0;
101
+ const title = (match[2] ?? "").replace(/[ \t]+#+$/, "").replace(/^#+$/, "").trim();
102
+ return { level: match[1].length, title };
103
+ }
104
+ function startsTable(lines, i) {
105
+ return lines[i].includes("|") && i + 1 < lines.length && TABLE_DELIMITER.test(lines[i + 1]);
106
+ }
107
+ function fenceEnd(lines, start) {
108
+ const opener = FENCE.exec(lines[start]);
109
+ if (!opener) return start + 1;
110
+ const marker = opener[1];
111
+ const closer = new RegExp(`^ {0,3}${marker[0] === "`" ? "`" : "~"}{${marker.length},}[ \\t]*$`);
112
+ for (let i = start + 1; i < lines.length; i++) if (closer.test(lines[i])) return i + 1;
113
+ return lines.length;
114
+ }
115
+ function listEnd(lines, start) {
116
+ let end = start + 1;
117
+ for (let i = start + 1; i < lines.length; i++) {
118
+ const line = lines[i];
119
+ if (isBlank(line)) {
120
+ let next = i + 1;
121
+ while (next < lines.length && isBlank(lines[next])) next++;
122
+ if (next < lines.length && (LIST_ITEM.test(lines[next]) || isIndented(lines[next]))) {
123
+ i = next - 1;
124
+ continue;
125
+ }
126
+ break;
127
+ }
128
+ if (headingOf(line) && !isIndented(line)) break;
129
+ if (FENCE.test(line) && !isIndented(line)) break;
130
+ end = i + 1;
131
+ }
132
+ return end;
133
+ }
134
+ function tableEnd(lines, start) {
135
+ let end = start + 2;
136
+ while (end < lines.length && !isBlank(lines[end]) && lines[end].includes("|")) end++;
137
+ return end;
138
+ }
139
+ function paragraphEnd(lines, start) {
140
+ let end = start + 1;
141
+ while (end < lines.length && !isBlank(lines[end]) && !headingOf(lines[end]) && !FENCE.test(lines[end]) && !LIST_ITEM.test(lines[end])) {
142
+ end++;
143
+ }
144
+ return end;
145
+ }
146
+ function scan(text) {
147
+ const lines = text.replace(/\r\n?/g, "\n").split("\n");
148
+ const sections = [{ trail: [], blocks: [] }];
149
+ const stack = [];
150
+ let i = 0;
151
+ while (i < lines.length) {
152
+ const line = lines[i];
153
+ if (isBlank(line)) {
154
+ i++;
155
+ continue;
156
+ }
157
+ const heading = FENCE.test(line) ? void 0 : headingOf(line);
158
+ if (heading) {
159
+ while (stack.length && stack[stack.length - 1].level >= heading.level) stack.pop();
160
+ stack.push(heading);
161
+ sections.push({ trail: stack.map((h) => h.title), heading: line, blocks: [] });
162
+ i++;
163
+ continue;
164
+ }
165
+ let end;
166
+ if (FENCE.test(line)) end = fenceEnd(lines, i);
167
+ else if (LIST_ITEM.test(line)) end = listEnd(lines, i);
168
+ else if (startsTable(lines, i)) end = tableEnd(lines, i);
169
+ else end = paragraphEnd(lines, i);
170
+ sections[sections.length - 1].blocks.push({ lines: lines.slice(i, end) });
171
+ i = end;
172
+ }
173
+ return sections;
174
+ }
175
+ function chunkSections(text, max = 900) {
176
+ const cap = Math.max(1, max);
177
+ const out = [];
178
+ const emit = (parts, section) => {
179
+ const body = parts.join("\n\n");
180
+ if (body.trim() === "") return;
181
+ out.push({ text: body, section: [...section], position: out.length });
182
+ };
183
+ for (const section of scan(text)) {
184
+ let parts = section.heading ? [section.heading.trim()] : [];
185
+ let size = parts.join("\n\n").length;
186
+ let hasBlock = false;
187
+ for (const block of section.blocks) {
188
+ const piece = block.lines.join("\n");
189
+ const added = piece.length + (parts.length ? 2 : 0);
190
+ if (hasBlock && size + added > cap) {
191
+ emit(parts, section.trail);
192
+ parts = [];
193
+ size = 0;
194
+ hasBlock = false;
195
+ }
196
+ size += piece.length + (parts.length ? 2 : 0);
197
+ parts.push(piece);
198
+ hasBlock = true;
199
+ }
200
+ emit(parts, section.trail);
201
+ }
202
+ return out;
203
+ }
204
+ var FENCE, HEADING, LIST_ITEM, TABLE_DELIMITER, isBlank, isIndented;
205
+ var init_chunking = __esm({
206
+ "src/core/chunking.ts"() {
207
+ "use strict";
208
+ FENCE = /^ {0,3}(`{3,}|~{3,})/;
209
+ HEADING = /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?[ \t]*$/;
210
+ LIST_ITEM = /^[ \t]*(?:[-*+]|\d{1,9}[.)])[ \t]+\S/;
211
+ TABLE_DELIMITER = /^[ \t]*\|?[ \t]*:?-+:?[ \t]*(?:\|[ \t]*:?-+:?[ \t]*)*\|?[ \t]*$/;
212
+ isBlank = (line) => line.trim() === "";
213
+ isIndented = (line) => /^(?: {2,}|\t)/.test(line);
214
+ }
215
+ });
216
+
97
217
  // src/core/loaders.ts
98
218
  function walk(dir) {
99
219
  const items = [];
@@ -199,11 +319,13 @@ async function sha256(input) {
199
319
  const hash = await crypto.subtle.digest("SHA-256", data);
200
320
  return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
201
321
  }
202
- var EMB_MODEL, DEFAULT_KNOWLEDGE_DIR, DATABASE_CONFIG_REQUIRED_MESSAGE, VectorStore;
322
+ var import_node_path3, EMB_MODEL, DEFAULT_KNOWLEDGE_DIR, DATABASE_CONFIG_REQUIRED_MESSAGE, VectorStore;
203
323
  var init_retrieval = __esm({
204
324
  "src/core/retrieval.ts"() {
205
325
  "use strict";
326
+ import_node_path3 = require("node:path");
206
327
  init_buildLock();
328
+ init_chunking();
207
329
  init_loaders();
208
330
  init_logger();
209
331
  EMB_MODEL = "text-embedding-3-large";
@@ -214,6 +336,7 @@ var init_retrieval = __esm({
214
336
  this.embed = embed;
215
337
  this.db = options.databaseClient;
216
338
  this.knowledgeDir = options.knowledgeDir || DEFAULT_KNOWLEDGE_DIR;
339
+ this.chunking = options.chunking ?? "lines";
217
340
  this.logger = options.logger ?? createConsoleLogger();
218
341
  this.buildLock = options.buildLock ?? createTursoBuildLock(this.db);
219
342
  this.instanceId = options.instanceId ?? crypto.randomUUID();
@@ -227,6 +350,7 @@ var init_retrieval = __esm({
227
350
  */
228
351
  db;
229
352
  knowledgeDir;
353
+ chunking;
230
354
  logger;
231
355
  buildLock;
232
356
  instanceId;
@@ -287,11 +411,41 @@ var init_retrieval = __esm({
287
411
  this.logger.info("No knowledge documents and no existing chunks - nothing to build");
288
412
  return;
289
413
  }
414
+ this.logger.info(`Chunking mode: ${this.chunking}`);
415
+ if (this.chunking === "sections") await this.ensureSectionColumns();
290
416
  const rows = [];
291
417
  for (const d of docs) {
292
- for (const part of chunk(d.text)) {
293
- const id = await sha256(`${d.bucket}|${d.source}|${part}`);
294
- rows.push({ id, bucket: d.bucket, source: d.source, text: part });
418
+ if (this.chunking === "sections") {
419
+ const source = (0, import_node_path3.relative)(this.knowledgeDir, d.source).split(import_node_path3.sep).join("/");
420
+ for (const c of chunkSections(d.text)) {
421
+ const section = c.section.join(" > ");
422
+ const id = await sha256(`${d.bucket}|${source}|${section}|${c.text}`);
423
+ const context = section ? `${source} > ${section}` : source;
424
+ rows.push({
425
+ id,
426
+ bucket: d.bucket,
427
+ source,
428
+ text: c.text,
429
+ embedText: `${context}
430
+
431
+ ${c.text}`,
432
+ section,
433
+ position: c.position
434
+ });
435
+ }
436
+ } else {
437
+ for (const part of chunk(d.text)) {
438
+ const id = await sha256(`${d.bucket}|${d.source}|${part}`);
439
+ rows.push({
440
+ id,
441
+ bucket: d.bucket,
442
+ source: d.source,
443
+ text: part,
444
+ embedText: part,
445
+ section: null,
446
+ position: null
447
+ });
448
+ }
295
449
  }
296
450
  }
297
451
  this.logger.info(`Created ${rows.length} chunks from knowledge documents`);
@@ -300,11 +454,17 @@ var init_retrieval = __esm({
300
454
  for (let i = 0; i < rows.length; i += UPSERT_BATCH) {
301
455
  const batch = rows.slice(i, i + UPSERT_BATCH);
302
456
  await this.db.batch(
303
- batch.map((r) => ({
304
- sql: `INSERT INTO chunks(id,bucket,source,text) VALUES(?,?,?,?)
305
- ON CONFLICT(id) DO NOTHING`,
306
- args: [r.id, r.bucket, r.source, r.text]
307
- })),
457
+ batch.map(
458
+ (r) => this.chunking === "sections" ? {
459
+ sql: `INSERT INTO chunks(id,bucket,source,text,section,position) VALUES(?,?,?,?,?,?)
460
+ ON CONFLICT(id) DO NOTHING`,
461
+ args: [r.id, r.bucket, r.source, r.text, r.section, r.position]
462
+ } : {
463
+ sql: `INSERT INTO chunks(id,bucket,source,text) VALUES(?,?,?,?)
464
+ ON CONFLICT(id) DO NOTHING`,
465
+ args: [r.id, r.bucket, r.source, r.text]
466
+ }
467
+ ),
308
468
  "write"
309
469
  );
310
470
  }
@@ -325,7 +485,7 @@ var init_retrieval = __esm({
325
485
  return;
326
486
  }
327
487
  this.logger.info(`Embedding ${missing.length} new/updated chunks with ${EMB_MODEL}...`);
328
- const textById = new Map(rows.map((r) => [r.id, r.text]));
488
+ const textById = new Map(rows.map((r) => [r.id, r.embedText]));
329
489
  const BATCH = 96;
330
490
  for (let i = 0; i < missing.length; i += BATCH) {
331
491
  const batchIds = missing.slice(i, i + BATCH);
@@ -346,6 +506,18 @@ var init_retrieval = __esm({
346
506
  }
347
507
  this.logger.info(`Successfully embedded ${missing.length} new chunks`);
348
508
  }
509
+ /**
510
+ * Adds the nullable `section`/`position` columns to a `chunks` table that
511
+ * every released version created without them. Checked via table_info so it
512
+ * is a no-op once present; only `'sections'` mode ever calls it.
513
+ */
514
+ async ensureSectionColumns() {
515
+ const info = await this.db.execute("PRAGMA table_info(chunks)");
516
+ const have = new Set(info.rows.map((r) => String(r.name)));
517
+ if (!have.has("section")) await this.db.execute("ALTER TABLE chunks ADD COLUMN section TEXT");
518
+ if (!have.has("position"))
519
+ await this.db.execute("ALTER TABLE chunks ADD COLUMN position INTEGER");
520
+ }
349
521
  // Remove chunks from database that no longer exist in markdown files
350
522
  async cleanupStaleChunks(currentIds) {
351
523
  const result = await this.db.execute("SELECT id FROM chunks");
@@ -392,25 +564,34 @@ var init_retrieval = __esm({
392
564
  * interpolated. An empty list retrieves nothing, and short-circuits before
393
565
  * the embedding call.
394
566
  */
395
- async query(q, k = 6, allowed = ["base"]) {
567
+ async queryChunks(q, k = 6, allowed = ["base"]) {
396
568
  if (allowed.length === 0) return [];
397
569
  const [qv] = await this.embed([q]);
398
570
  const placeholders = allowed.map(() => "?").join(",");
399
571
  const res = await this.db.execute({
400
- sql: `SELECT c.id, c.text, e.embedding
572
+ sql: `SELECT c.*, e.embedding
401
573
  FROM chunks c
402
574
  JOIN embeddings e ON e.id = c.id
403
575
  WHERE c.bucket IN (${placeholders})`,
404
576
  args: allowed
405
577
  });
406
- const scored = [];
407
- for (const row of res.rows) {
578
+ const scored = res.rows.map((row) => {
408
579
  const emb = JSON.parse(String(row.embedding));
409
- const s = _VectorStore.cosine(qv, emb);
410
- scored.push({ s, text: String(row.text) });
411
- }
412
- scored.sort((a, b) => b.s - a.s);
413
- return scored.slice(0, k).map((r) => r.text);
580
+ const trail = row.section == null ? "" : String(row.section);
581
+ return {
582
+ text: String(row.text),
583
+ bucket: String(row.bucket ?? ""),
584
+ source: String(row.source ?? ""),
585
+ section: trail ? trail.split(" > ") : [],
586
+ score: _VectorStore.cosine(qv, emb)
587
+ };
588
+ });
589
+ scored.sort((a, b) => b.score - a.score);
590
+ return scored.slice(0, k);
591
+ }
592
+ /** Same results as {@link queryChunks}, as bare text. */
593
+ async query(q, k = 6, allowed = ["base"]) {
594
+ return (await this.queryChunks(q, k, allowed)).map((c) => c.text);
414
595
  }
415
596
  };
416
597
  }
@@ -538,6 +719,7 @@ __export(index_exports, {
538
719
  DEFAULT_KNOWLEDGE_DIR: () => DEFAULT_KNOWLEDGE_DIR,
539
720
  DEFAULT_MODEL: () => DEFAULT_MODEL,
540
721
  DEFAULT_PROMPTS_DIR: () => DEFAULT_PROMPTS_DIR,
722
+ DEFAULT_REFUSAL: () => DEFAULT_REFUSAL,
541
723
  PromptLoader: () => PromptLoader,
542
724
  VectorStore: () => VectorStore,
543
725
  answerOnce: () => answerOnce,
@@ -545,6 +727,7 @@ __export(index_exports, {
545
727
  applyTransformReply: () => applyTransformReply,
546
728
  canAcquireBuildLock: () => canAcquireBuildLock,
547
729
  chatBodyLimit: () => chatBodyLimit,
730
+ chunkSections: () => chunkSections,
548
731
  completeOnce: () => completeOnce,
549
732
  completeStream: () => completeStream,
550
733
  cors: () => cors,
@@ -719,9 +902,10 @@ function detectLeakage(text) {
719
902
  function scrubOutput(text) {
720
903
  return text.replace(/sk-[A-Za-z0-9]{15,}/g, "[REDACTED]").replace(/AIza[0-9A-Za-z_-]{30,}/g, "[REDACTED]");
721
904
  }
722
- function guardOutput(text) {
905
+ var DEFAULT_REFUSAL = "Sorry, I can't share internal instructions. How else can I help?";
906
+ function guardOutput(text, refusal) {
723
907
  if (detectLeakage(text)) {
724
- return "Sorry, I can't share internal instructions. How else can I help?";
908
+ return typeof refusal === "string" && refusal.trim() ? refusal : DEFAULT_REFUSAL;
725
909
  }
726
910
  return scrubOutput(text);
727
911
  }
@@ -733,7 +917,8 @@ async function completeOnce({
733
917
  system,
734
918
  messages,
735
919
  temperature = 0.2,
736
- model = DEFAULT_MODEL
920
+ model = DEFAULT_MODEL,
921
+ refusal
737
922
  }) {
738
923
  const res = await client.chat.completions.create({
739
924
  model,
@@ -742,7 +927,7 @@ async function completeOnce({
742
927
  });
743
928
  const text = res.choices[0]?.message?.content ?? "";
744
929
  return {
745
- content: guardOutput(text),
930
+ content: guardOutput(text, refusal),
746
931
  usage: res.usage || { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
747
932
  };
748
933
  }
@@ -767,12 +952,12 @@ async function* completeStream({
767
952
 
768
953
  // src/core/answer.ts
769
954
  var noUsage = () => ({ prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 });
770
- async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }) {
955
+ async function runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal) {
771
956
  const result = await answerFn({ system, messages, mode, sender, conversationId });
772
957
  const raw = typeof result === "string" ? result : result?.content;
773
958
  const usage = typeof result === "string" ? void 0 : result?.usage;
774
959
  return {
775
- content: guardOutput(typeof raw === "string" ? raw : ""),
960
+ content: guardOutput(typeof raw === "string" ? raw : "", refusal),
776
961
  usage: usage ?? noUsage()
777
962
  };
778
963
  }
@@ -785,12 +970,13 @@ async function answerOnce({
785
970
  sender,
786
971
  conversationId,
787
972
  temperature,
788
- model
973
+ model,
974
+ refusal
789
975
  }) {
790
976
  if (answerFn) {
791
- return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId });
977
+ return runAnswerFn(answerFn, { system, messages, mode, sender, conversationId }, refusal);
792
978
  }
793
- return completeOnce({ client, system, messages, temperature, model });
979
+ return completeOnce({ client, system, messages, temperature, model, refusal });
794
980
  }
795
981
  async function applyTransformReply(transformReply, input, logger) {
796
982
  if (!transformReply) return input.text;
@@ -814,16 +1000,15 @@ async function* answerStream({
814
1000
  sender,
815
1001
  conversationId,
816
1002
  temperature,
817
- model
1003
+ model,
1004
+ refusal
818
1005
  }) {
819
1006
  if (answerFn) {
820
- const { content } = await runAnswerFn(answerFn, {
821
- system,
822
- messages,
823
- mode,
824
- sender,
825
- conversationId
826
- });
1007
+ const { content } = await runAnswerFn(
1008
+ answerFn,
1009
+ { system, messages, mode, sender, conversationId },
1010
+ refusal
1011
+ );
827
1012
  if (content) yield content;
828
1013
  return;
829
1014
  }
@@ -863,6 +1048,7 @@ async function resolveBuckets({
863
1048
 
864
1049
  // src/index.ts
865
1050
  init_buildLock();
1051
+ init_chunking();
866
1052
  init_loaders();
867
1053
  init_logger();
868
1054
 
@@ -1351,6 +1537,7 @@ async function createMCPServer(config) {
1351
1537
  store = new VectorStore2(createOpenAIEmbedder2(client), {
1352
1538
  databaseClient: db,
1353
1539
  knowledgeDir: config.knowledgeDir || DEFAULT_KNOWLEDGE_DIR2,
1540
+ chunking: config.chunking,
1354
1541
  logger: log
1355
1542
  });
1356
1543
  }
@@ -1422,7 +1609,8 @@ async function createMCPServer(config) {
1422
1609
  messages: conversationMessages,
1423
1610
  mode: "public",
1424
1611
  conversationId: convId,
1425
- model
1612
+ model,
1613
+ refusal: config.refusal
1426
1614
  });
1427
1615
  const replyText = await applyTransformReply(
1428
1616
  config.transformReply,
@@ -1512,7 +1700,8 @@ async function createMCPServer(config) {
1512
1700
  messages: conversationMessages,
1513
1701
  mode: "private",
1514
1702
  conversationId: convId,
1515
- model
1703
+ model,
1704
+ refusal: config.refusal
1516
1705
  });
1517
1706
  const replyText = await applyTransformReply(
1518
1707
  config.transformReply,
@@ -2011,7 +2200,8 @@ function demoRoutes(deps) {
2011
2200
  system,
2012
2201
  messages,
2013
2202
  mode: "public",
2014
- model
2203
+ model,
2204
+ refusal: config.refusal
2015
2205
  })) {
2016
2206
  await s.write(`data: ${JSON.stringify({ delta })}
2017
2207
 
@@ -2026,7 +2216,8 @@ function demoRoutes(deps) {
2026
2216
  system,
2027
2217
  messages,
2028
2218
  mode: "public",
2029
- model
2219
+ model,
2220
+ refusal: config.refusal
2030
2221
  });
2031
2222
  const reply = await applyTransformReply(
2032
2223
  config.transformReply,
@@ -2167,7 +2358,8 @@ function openaiRoutes(deps) {
2167
2358
  sender,
2168
2359
  conversationId,
2169
2360
  temperature,
2170
- model: serverModel
2361
+ model: serverModel,
2362
+ refusal: config.refusal
2171
2363
  })) {
2172
2364
  await s.write(chunk2({ content: delta }, null));
2173
2365
  }
@@ -2184,7 +2376,8 @@ function openaiRoutes(deps) {
2184
2376
  sender,
2185
2377
  conversationId,
2186
2378
  temperature,
2187
- model: serverModel
2379
+ model: serverModel,
2380
+ refusal: config.refusal
2188
2381
  });
2189
2382
  const reply = await applyTransformReply(
2190
2383
  config.transformReply,
@@ -2275,7 +2468,8 @@ function privateRoutes(deps) {
2275
2468
  messages,
2276
2469
  mode: "private",
2277
2470
  sender,
2278
- model
2471
+ model,
2472
+ refusal: config.refusal
2279
2473
  })) {
2280
2474
  await s.write(`data: ${JSON.stringify({ delta })}
2281
2475
 
@@ -2291,7 +2485,8 @@ function privateRoutes(deps) {
2291
2485
  messages,
2292
2486
  mode: "private",
2293
2487
  sender,
2294
- model
2488
+ model,
2489
+ refusal: config.refusal
2295
2490
  });
2296
2491
  const reply = await applyTransformReply(
2297
2492
  config.transformReply,
@@ -2360,7 +2555,8 @@ function publicRoutes(deps) {
2360
2555
  system,
2361
2556
  messages,
2362
2557
  mode: "public",
2363
- model
2558
+ model,
2559
+ refusal: config.refusal
2364
2560
  })) {
2365
2561
  await s.write(`data: ${JSON.stringify({ delta })}
2366
2562
 
@@ -2369,7 +2565,15 @@ function publicRoutes(deps) {
2369
2565
  await s.write("event: end\ndata: {}\n\n");
2370
2566
  });
2371
2567
  }
2372
- const out = await answerOnce({ answerFn, client, system, messages, mode: "public", model });
2568
+ const out = await answerOnce({
2569
+ answerFn,
2570
+ client,
2571
+ system,
2572
+ messages,
2573
+ mode: "public",
2574
+ model,
2575
+ refusal: config.refusal
2576
+ });
2373
2577
  const reply = await applyTransformReply(
2374
2578
  config.transformReply,
2375
2579
  { channel: "widget-public", text: out.content },
@@ -2381,7 +2585,7 @@ function publicRoutes(deps) {
2381
2585
  }
2382
2586
 
2383
2587
  // src/server.ts
2384
- var import_node_path4 = require("node:path");
2588
+ var import_node_path5 = require("node:path");
2385
2589
  var import_hono5 = require("hono");
2386
2590
  var import_openai2 = __toESM(require("openai"));
2387
2591
 
@@ -2485,7 +2689,7 @@ function loadServeStatic(runtime = detectRuntime()) {
2485
2689
 
2486
2690
  // src/core/widgets.ts
2487
2691
  var import_node_fs3 = require("node:fs");
2488
- var import_node_path3 = require("node:path");
2692
+ var import_node_path4 = require("node:path");
2489
2693
  var import_node_url = require("node:url");
2490
2694
  var import_meta = {};
2491
2695
  function resolveStatic(configStaticDir) {
@@ -2494,15 +2698,15 @@ function resolveStatic(configStaticDir) {
2494
2698
  }
2495
2699
  try {
2496
2700
  if (import_meta.url) {
2497
- const moduleDir = (0, import_node_path3.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
2498
- const staticDir = (0, import_node_path3.join)(moduleDir, "static");
2701
+ const moduleDir = (0, import_node_path4.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
2702
+ const staticDir = (0, import_node_path4.join)(moduleDir, "static");
2499
2703
  if ((0, import_node_fs3.existsSync)(staticDir)) return { staticDir };
2500
2704
  }
2501
2705
  } catch {
2502
2706
  }
2503
2707
  try {
2504
2708
  if (typeof __dirname !== "undefined") {
2505
- const staticDir = (0, import_node_path3.join)(__dirname, "static");
2709
+ const staticDir = (0, import_node_path4.join)(__dirname, "static");
2506
2710
  if ((0, import_node_fs3.existsSync)(staticDir)) return { staticDir };
2507
2711
  }
2508
2712
  } catch {
@@ -2541,6 +2745,7 @@ async function createServer(config) {
2541
2745
  store = new VectorStore2(createOpenAIEmbedder2(client), {
2542
2746
  databaseClient: db,
2543
2747
  knowledgeDir: config.knowledgeDir || DEFAULT_KNOWLEDGE_DIR2,
2748
+ chunking: config.chunking,
2544
2749
  logger
2545
2750
  });
2546
2751
  }
@@ -2591,7 +2796,7 @@ async function createServer(config) {
2591
2796
  }
2592
2797
  }
2593
2798
  if (serveStatic && staticDir) {
2594
- const relativePath = (0, import_node_path4.relative)(process.cwd(), staticDir);
2799
+ const relativePath = (0, import_node_path5.relative)(process.cwd(), staticDir);
2595
2800
  app.get("/chatter.js", serveStatic({ path: `${relativePath}/chatter.js` }));
2596
2801
  app.get("/chatter.css", serveStatic({ path: `${relativePath}/chatter.css` }));
2597
2802
  }
@@ -2638,6 +2843,7 @@ async function createServer(config) {
2638
2843
  app.get("/demo/react", serveStatic({ path: `${publicDir}/react-demo.html` }));
2639
2844
  }
2640
2845
  const senders = createSenderRegistry(logger);
2846
+ const identities = /* @__PURE__ */ new Map();
2641
2847
  const deps = {
2642
2848
  client,
2643
2849
  store,
@@ -2649,6 +2855,7 @@ async function createServer(config) {
2649
2855
  prompts,
2650
2856
  apiKeyManager,
2651
2857
  senders,
2858
+ identities,
2652
2859
  logger
2653
2860
  };
2654
2861
  if (enablePublic) {
@@ -2743,6 +2950,7 @@ function createShortener(config, fetchImpl = fetch) {
2743
2950
  DEFAULT_KNOWLEDGE_DIR,
2744
2951
  DEFAULT_MODEL,
2745
2952
  DEFAULT_PROMPTS_DIR,
2953
+ DEFAULT_REFUSAL,
2746
2954
  PromptLoader,
2747
2955
  VectorStore,
2748
2956
  answerOnce,
@@ -2750,6 +2958,7 @@ function createShortener(config, fetchImpl = fetch) {
2750
2958
  applyTransformReply,
2751
2959
  canAcquireBuildLock,
2752
2960
  chatBodyLimit,
2961
+ chunkSections,
2753
2962
  completeOnce,
2754
2963
  completeStream,
2755
2964
  cors,