@cogitator-ai/channels 0.2.4 → 0.3.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 (129) hide show
  1. package/README.md +141 -39
  2. package/dist/assistant-config.d.ts +1 -0
  3. package/dist/assistant-config.d.ts.map +1 -1
  4. package/dist/assistant-config.js +1 -0
  5. package/dist/assistant-config.js.map +1 -1
  6. package/dist/channels/discord.d.ts +4 -0
  7. package/dist/channels/discord.d.ts.map +1 -1
  8. package/dist/channels/discord.js +123 -59
  9. package/dist/channels/discord.js.map +1 -1
  10. package/dist/channels/slack.d.ts +9 -0
  11. package/dist/channels/slack.d.ts.map +1 -1
  12. package/dist/channels/slack.js +153 -34
  13. package/dist/channels/slack.js.map +1 -1
  14. package/dist/channels/telegram.d.ts +13 -0
  15. package/dist/channels/telegram.d.ts.map +1 -1
  16. package/dist/channels/telegram.js +206 -111
  17. package/dist/channels/telegram.js.map +1 -1
  18. package/dist/channels/terminal.d.ts +10 -0
  19. package/dist/channels/terminal.d.ts.map +1 -1
  20. package/dist/channels/terminal.js +46 -10
  21. package/dist/channels/terminal.js.map +1 -1
  22. package/dist/channels/webchat.d.ts +7 -2
  23. package/dist/channels/webchat.d.ts.map +1 -1
  24. package/dist/channels/webchat.js +112 -50
  25. package/dist/channels/webchat.js.map +1 -1
  26. package/dist/channels/whatsapp.d.ts +19 -3
  27. package/dist/channels/whatsapp.d.ts.map +1 -1
  28. package/dist/channels/whatsapp.js +204 -66
  29. package/dist/channels/whatsapp.js.map +1 -1
  30. package/dist/cron.d.ts +2 -0
  31. package/dist/cron.d.ts.map +1 -0
  32. package/dist/cron.js +9 -0
  33. package/dist/cron.js.map +1 -0
  34. package/dist/envelope.d.ts.map +1 -1
  35. package/dist/envelope.js +7 -6
  36. package/dist/envelope.js.map +1 -1
  37. package/dist/formatters/code-protect.d.ts +2 -0
  38. package/dist/formatters/code-protect.d.ts.map +1 -0
  39. package/dist/formatters/code-protect.js +12 -0
  40. package/dist/formatters/code-protect.js.map +1 -0
  41. package/dist/formatters/markdown.d.ts +1 -1
  42. package/dist/formatters/markdown.d.ts.map +1 -1
  43. package/dist/formatters/markdown.js +79 -21
  44. package/dist/formatters/markdown.js.map +1 -1
  45. package/dist/formatters/whatsapp-markdown.d.ts.map +1 -1
  46. package/dist/formatters/whatsapp-markdown.js +7 -21
  47. package/dist/formatters/whatsapp-markdown.js.map +1 -1
  48. package/dist/gateway.d.ts +32 -3
  49. package/dist/gateway.d.ts.map +1 -1
  50. package/dist/gateway.js +275 -174
  51. package/dist/gateway.js.map +1 -1
  52. package/dist/heartbeat.d.ts +9 -2
  53. package/dist/heartbeat.d.ts.map +1 -1
  54. package/dist/heartbeat.js +121 -84
  55. package/dist/heartbeat.js.map +1 -1
  56. package/dist/inbound-debounce.js +2 -2
  57. package/dist/inbound-debounce.js.map +1 -1
  58. package/dist/index.d.ts +6 -3
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +2 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/media/audio-format.d.ts +3 -0
  63. package/dist/media/audio-format.d.ts.map +1 -0
  64. package/dist/media/audio-format.js +20 -0
  65. package/dist/media/audio-format.js.map +1 -0
  66. package/dist/media/deepgram-stt.d.ts +1 -1
  67. package/dist/media/deepgram-stt.d.ts.map +1 -1
  68. package/dist/media/deepgram-stt.js +4 -3
  69. package/dist/media/deepgram-stt.js.map +1 -1
  70. package/dist/media/media-processor.d.ts +12 -1
  71. package/dist/media/media-processor.d.ts.map +1 -1
  72. package/dist/media/media-processor.js +75 -18
  73. package/dist/media/media-processor.js.map +1 -1
  74. package/dist/media/whisper-api.d.ts.map +1 -1
  75. package/dist/media/whisper-api.js +20 -32
  76. package/dist/media/whisper-api.js.map +1 -1
  77. package/dist/media/whisper-local.d.ts +1 -0
  78. package/dist/media/whisper-local.d.ts.map +1 -1
  79. package/dist/media/whisper-local.js +100 -45
  80. package/dist/media/whisper-local.js.map +1 -1
  81. package/dist/message-queue.d.ts +1 -0
  82. package/dist/message-queue.d.ts.map +1 -1
  83. package/dist/message-queue.js +17 -10
  84. package/dist/message-queue.js.map +1 -1
  85. package/dist/middleware/auto-extract.d.ts +2 -0
  86. package/dist/middleware/auto-extract.d.ts.map +1 -1
  87. package/dist/middleware/auto-extract.js +94 -30
  88. package/dist/middleware/auto-extract.js.map +1 -1
  89. package/dist/middleware/dm-policy.d.ts +2 -1
  90. package/dist/middleware/dm-policy.d.ts.map +1 -1
  91. package/dist/middleware/dm-policy.js +26 -27
  92. package/dist/middleware/dm-policy.js.map +1 -1
  93. package/dist/middleware/owner-commands.d.ts +1 -1
  94. package/dist/middleware/owner-commands.d.ts.map +1 -1
  95. package/dist/middleware/owner-commands.js +8 -7
  96. package/dist/middleware/owner-commands.js.map +1 -1
  97. package/dist/middleware/pairing-codes.d.ts +12 -0
  98. package/dist/middleware/pairing-codes.d.ts.map +1 -0
  99. package/dist/middleware/pairing-codes.js +26 -0
  100. package/dist/middleware/pairing-codes.js.map +1 -0
  101. package/dist/middleware/pairing.d.ts +3 -3
  102. package/dist/middleware/pairing.d.ts.map +1 -1
  103. package/dist/middleware/pairing.js +18 -25
  104. package/dist/middleware/pairing.js.map +1 -1
  105. package/dist/middleware/rate-limit.d.ts +3 -1
  106. package/dist/middleware/rate-limit.d.ts.map +1 -1
  107. package/dist/middleware/rate-limit.js +21 -6
  108. package/dist/middleware/rate-limit.js.map +1 -1
  109. package/dist/runtime-builder.d.ts +11 -0
  110. package/dist/runtime-builder.d.ts.map +1 -1
  111. package/dist/runtime-builder.js +212 -62
  112. package/dist/runtime-builder.js.map +1 -1
  113. package/dist/simple-timer-store.d.ts +6 -0
  114. package/dist/simple-timer-store.d.ts.map +1 -1
  115. package/dist/simple-timer-store.js +8 -1
  116. package/dist/simple-timer-store.js.map +1 -1
  117. package/dist/stream-buffer.d.ts +14 -7
  118. package/dist/stream-buffer.d.ts.map +1 -1
  119. package/dist/stream-buffer.js +129 -84
  120. package/dist/stream-buffer.js.map +1 -1
  121. package/dist/tools/path-guard.d.ts +4 -0
  122. package/dist/tools/path-guard.d.ts.map +1 -0
  123. package/dist/tools/path-guard.js +53 -0
  124. package/dist/tools/path-guard.js.map +1 -0
  125. package/dist/tools/self-config.d.ts +12 -2
  126. package/dist/tools/self-config.d.ts.map +1 -1
  127. package/dist/tools/self-config.js +53 -16
  128. package/dist/tools/self-config.js.map +1 -1
  129. package/package.json +19 -12
@@ -1 +1 @@
1
- {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../src/middleware/pairing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pairing.js","sourceRoot":"","sources":["../../src/middleware/pairing.ts"],"names":[],"mappings":"AACA,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,YAAY,GAEb,MAAM,iBAAiB,CAAC;AAQzB,MAAM,OAAO,iBAAiB;IACnB,IAAI,GAAG,SAAS,CAAC;IACT,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAC7B,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC5C,UAAU,CAAS;IACnB,SAAS,CAAS;IAEnC,YAAY,MAAqB;QAC/B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;QAElD,KAAK,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,MAAM,GAAG,GAAG,GAAG,WAAW,IAAI,OAAO,EAAE,CAAC;YACxC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CACV,GAAmB,EACnB,GAAsB,EACtB,IAAyB;QAEzB,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAEhC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACpC,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CACxB,GAAG,CAAC,SAAS,EACb,sCAAsC,QAAQ,CAAC,IAAI,IAAI,CACxD,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE;YACrB,IAAI;YACJ,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,SAAS,EAAE,GAAG,GAAG,IAAI,CAAC,SAAS;SAChC,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CACxB,GAAG,CAAC,SAAS,EACb,sDAAsD,IAAI,IAAI,CAC/D,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,GAAmB,EAAE,GAAsB;QACtE,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE1D,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtB,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,kCAAkC,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE1B,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,kBAAkB,OAAO,IAAI,CAAC,CAAC;IAC3E,CAAC;IAED,UAAU,CAAC,WAAmB,EAAE,MAAc;QAC5C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,WAAW,IAAI,MAAM,EAAE,CAAC,CAAC;IACvD,CAAC;CACF;AAED,MAAM,UAAU,OAAO,CAAC,MAAqB;IAC3C,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC"}
@@ -6,9 +6,11 @@ export interface RateLimitConfig {
6
6
  export declare class RateLimitMiddleware implements GatewayMiddleware {
7
7
  private readonly config;
8
8
  readonly name = "rate-limit";
9
- private buckets;
9
+ private readonly buckets;
10
+ private lastSweep;
10
11
  constructor(config: RateLimitConfig);
11
12
  handle(msg: ChannelMessage, ctx: MiddlewareContext, next: () => Promise<void>): Promise<void>;
13
+ private sweep;
12
14
  }
13
15
  export declare function rateLimit(config: RateLimitConfig): GatewayMiddleware;
14
16
  //# sourceMappingURL=rate-limit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEhG,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAMD,qBAAa,mBAAoB,YAAW,iBAAiB;IAI/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,OAAO,CAAC,OAAO,CAAiC;gBAEnB,MAAM,EAAE,eAAe;IAE9C,MAAM,CACV,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC;CAwBjB;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB,CAEpE"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEhG,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AASD,qBAAa,mBAAoB,YAAW,iBAAiB;IAK/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,SAAS,CAAK;gBAEO,MAAM,EAAE,eAAe;IAE9C,MAAM,CACV,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,iBAAiB,EACtB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACxB,OAAO,CAAC,IAAI,CAAC;IA8BhB,OAAO,CAAC,KAAK;CASd;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,iBAAiB,CAEpE"}
@@ -1,29 +1,44 @@
1
+ const WINDOW_MS = 60_000;
1
2
  export class RateLimitMiddleware {
2
3
  config;
3
4
  name = 'rate-limit';
4
5
  buckets = new Map();
6
+ lastSweep = 0;
5
7
  constructor(config) {
6
8
  this.config = config;
7
9
  }
8
10
  async handle(msg, ctx, next) {
9
11
  const userKey = `${msg.channelType}:${msg.userId}`;
10
12
  const now = Date.now();
11
- const windowMs = 60_000;
13
+ this.sweep(now);
12
14
  let bucket = this.buckets.get(userKey);
13
15
  if (!bucket) {
14
- bucket = { timestamps: [] };
16
+ bucket = { timestamps: [], notified: false };
15
17
  this.buckets.set(userKey, bucket);
16
18
  }
17
- bucket.timestamps = bucket.timestamps.filter((t) => now - t < windowMs);
19
+ bucket.timestamps = bucket.timestamps.filter((t) => now - t < WINDOW_MS);
18
20
  if (bucket.timestamps.length >= this.config.maxPerMinute) {
19
- const replyText = this.config.message ??
20
- `Rate limit exceeded. Please wait a moment before sending another message.`;
21
- await ctx.channel.sendText(msg.channelId, replyText);
21
+ if (!bucket.notified) {
22
+ bucket.notified = true;
23
+ await ctx.channel.sendText(msg.channelId, this.config.message ??
24
+ 'Rate limit exceeded. Please wait a moment before sending another message.');
25
+ }
22
26
  return;
23
27
  }
28
+ bucket.notified = false;
24
29
  bucket.timestamps.push(now);
25
30
  await next();
26
31
  }
32
+ sweep(now) {
33
+ if (now - this.lastSweep < WINDOW_MS)
34
+ return;
35
+ this.lastSweep = now;
36
+ for (const [key, bucket] of this.buckets) {
37
+ if (bucket.timestamps.every((t) => now - t >= WINDOW_MS)) {
38
+ this.buckets.delete(key);
39
+ }
40
+ }
41
+ }
27
42
  }
28
43
  export function rateLimit(config) {
29
44
  return new RateLimitMiddleware(config);
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,mBAAmB;IAID;IAHpB,IAAI,GAAG,YAAY,CAAC;IACrB,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEhD,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAExD,KAAK,CAAC,MAAM,CACV,GAAmB,EACnB,GAAsB,EACtB,IAAyB;QAEzB,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,MAAM,CAAC;QAExB,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC;QAExE,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzD,MAAM,SAAS,GACb,IAAI,CAAC,MAAM,CAAC,OAAO;gBACnB,2EAA2E,CAAC;YAC9E,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACrD,OAAO;QACT,CAAC;QAED,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;CACF;AAED,MAAM,UAAU,SAAS,CAAC,MAAuB;IAC/C,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../../src/middleware/rate-limit.ts"],"names":[],"mappings":"AAYA,MAAM,SAAS,GAAG,MAAM,CAAC;AAEzB,MAAM,OAAO,mBAAmB;IAKD;IAJpB,IAAI,GAAG,YAAY,CAAC;IACZ,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IACjD,SAAS,GAAG,CAAC,CAAC;IAEtB,YAA6B,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAExD,KAAK,CAAC,MAAM,CACV,GAAmB,EACnB,GAAsB,EACtB,IAAyB;QAEzB,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAEhB,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC7C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;QAEzE,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACrB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACvB,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,CACxB,GAAG,CAAC,SAAS,EACb,IAAI,CAAC,MAAM,CAAC,OAAO;oBACjB,2EAA2E,CAC9E,CAAC;YACJ,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,GAAW;QACvB,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,GAAG,SAAS;YAAE,OAAO;QAC7C,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC;QACrB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,SAAS,CAAC,EAAE,CAAC;gBACzD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,MAAM,UAAU,SAAS,CAAC,MAAuB;IAC/C,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACzC,CAAC"}
@@ -17,16 +17,27 @@ export interface RuntimeBuilderOpts {
17
17
  stringifyYaml: (o: unknown) => string;
18
18
  validateConfig: (o: unknown) => unknown;
19
19
  };
20
+ /**
21
+ * Invoked when the assistant needs to restart (config change, `/restart`).
22
+ * Defaults to exiting the process with code 78, which `cogitator up` treats as a restart request.
23
+ */
24
+ onRestart?: () => void;
20
25
  }
26
+ export declare const RESTART_EXIT_CODE = 78;
21
27
  export declare class RuntimeBuilder {
22
28
  private config;
23
29
  private env;
24
30
  private opts?;
25
31
  constructor(config: AssistantConfig, env: Record<string, string | undefined>, opts?: RuntimeBuilderOpts | undefined);
26
32
  build(): Promise<BuiltRuntime>;
33
+ private requestRestart;
34
+ private collectOwnerIds;
35
+ private resolveFileSystemRoots;
36
+ private buildMemoryBackends;
27
37
  private createExtractorBackend;
28
38
  private wireBrowser;
29
39
  private ensurePlaywright;
40
+ private playwrightCacheDir;
30
41
  private wireRAG;
31
42
  private wireMCPServers;
32
43
  private resolveEmbeddingConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-builder.d.ts","sourceRoot":"","sources":["../src/runtime-builder.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,EACL,SAAS,EAUV,MAAM,oBAAoB,CAAC;AAY5B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAkBjD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAOD,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE;QACd,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QAClC,aAAa,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;QACtC,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;KACzC,CAAC;CACH;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI,CAAC;gBAFL,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,IAAI,CAAC,EAAE,kBAAkB,YAAA;IAG7B,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC;IA6PpC,OAAO,CAAC,sBAAsB;YAqBhB,WAAW;YAiEX,gBAAgB;YAchB,OAAO;YAqDP,cAAc;IA6B5B,OAAO,CAAC,sBAAsB;IAkC9B,OAAO,KAAK,WAAW,GAItB;IAED,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,iBAAiB;IA+FzB,OAAO,CAAC,gBAAgB;YAaV,kBAAkB;IAgBhC,OAAO,CAAC,eAAe;CAOxB"}
1
+ {"version":3,"file":"runtime-builder.d.ts","sourceRoot":"","sources":["../src/runtime-builder.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,EACL,SAAS,EAUV,MAAM,oBAAoB,CAAC;AAe5B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAkBjD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAEpD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAgBD,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE;QACd,SAAS,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;QAClC,aAAa,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;QACtC,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC;KACzC,CAAC;IACF;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,eAAO,MAAM,iBAAiB,KAAK,CAAC;AA2BpC,qBAAa,cAAc;IAEvB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI,CAAC;gBAFL,MAAM,EAAE,eAAe,EACvB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,IAAI,CAAC,EAAE,kBAAkB,YAAA;IAG7B,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC;IA6SpC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,sBAAsB;YAMhB,mBAAmB;IAoDjC,OAAO,CAAC,sBAAsB;YAqBhB,WAAW;YAiEX,gBAAgB;IAQ9B,OAAO,CAAC,kBAAkB;YAeZ,OAAO;YA4DP,cAAc;IAoC5B,OAAO,CAAC,sBAAsB;IAkC9B,OAAO,KAAK,WAAW,GAItB;IAED,OAAO,CAAC,cAAc;IAyBtB,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,cAAc;IAoBtB,OAAO,CAAC,iBAAiB;IA0FzB,OAAO,CAAC,gBAAgB;YAaV,kBAAkB;IAgBhC,OAAO,CAAC,eAAe;CAOxB"}
@@ -1,9 +1,12 @@
1
+ import { existsSync } from 'node:fs';
1
2
  import { homedir } from 'node:os';
2
3
  import { join } from 'node:path';
3
4
  import { Agent, Cogitator, builtinTools, createMemoryTools, createSchedulerTools, createCapabilitiesTool, createDeviceTools, createSelfTools, loadCustomTools, parseModel, tool as createTool, } from '@cogitator-ai/core';
4
- import { SQLiteAdapter, SQLiteGraphAdapter, CoreFactsStore, LLMEntityExtractor, createEmbeddingService, InMemoryEmbeddingAdapter, } from '@cogitator-ai/memory';
5
+ import { SQLiteAdapter, SQLiteGraphAdapter, PostgresAdapter, PostgresGraphAdapter, CoreFactsStore, LLMEntityExtractor, createEmbeddingService, InMemoryEmbeddingAdapter, } from '@cogitator-ai/memory';
5
6
  import { createSelfConfigTools } from './tools/self-config.js';
7
+ import { restrictFileTools } from './tools/path-guard.js';
6
8
  import { Gateway } from './gateway.js';
9
+ import { getNextCronMs } from './cron.js';
7
10
  import { HeartbeatScheduler } from './heartbeat.js';
8
11
  import { SimpleTimerStore } from './simple-timer-store.js';
9
12
  import { telegramChannel } from './channels/telegram.js';
@@ -13,13 +16,37 @@ import { terminalChannel } from './channels/terminal.js';
13
16
  import { ownerCommands } from './middleware/owner-commands.js';
14
17
  import { rateLimit } from './middleware/rate-limit.js';
15
18
  import { autoExtract } from './middleware/auto-extract.js';
16
- import { dmPolicy } from './middleware/dm-policy.js';
19
+ import { DmPolicyMiddleware } from './middleware/dm-policy.js';
17
20
  import { generateCapabilitiesDoc } from './capabilities.js';
18
21
  import { MediaProcessor } from './media/media-processor.js';
19
22
  import { LocalWhisper } from './media/whisper-local.js';
20
23
  import { createWhisperDownloadTool } from './media/whisper-tool.js';
21
24
  import { GroqSttProvider, OpenAISttProvider } from './media/whisper-api.js';
22
25
  import { DeepgramSttProvider } from './media/deepgram-stt.js';
26
+ export const RESTART_EXIT_CODE = 78;
27
+ const MODULE_NOT_FOUND_CODES = new Set(['ERR_MODULE_NOT_FOUND', 'MODULE_NOT_FOUND']);
28
+ function isModuleNotFound(err, specifier) {
29
+ if (!(err instanceof Error))
30
+ return false;
31
+ const code = err.code;
32
+ return !!code && MODULE_NOT_FOUND_CODES.has(code) && err.message.includes(specifier);
33
+ }
34
+ function expandHome(path) {
35
+ return path.startsWith('~') ? path.replace(/^~/, homedir()) : path;
36
+ }
37
+ function localIsoDate(date) {
38
+ const pad = (n) => String(n).padStart(2, '0');
39
+ return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
40
+ }
41
+ function formatDuration(ms) {
42
+ const minutes = Math.floor(ms / 60_000);
43
+ if (minutes < 60)
44
+ return `${minutes}m`;
45
+ const hours = Math.floor(minutes / 60);
46
+ if (hours < 24)
47
+ return `${hours}h ${minutes % 60}m`;
48
+ return `${Math.floor(hours / 24)}d ${hours % 24}h`;
49
+ }
23
50
  export class RuntimeBuilder {
24
51
  config;
25
52
  env;
@@ -32,17 +59,9 @@ export class RuntimeBuilder {
32
59
  async build() {
33
60
  const cogitator = this.buildCogitator();
34
61
  const cleanupResources = { mcpClients: [] };
35
- const memoryPath = this.config.memory.path ?? '~/.cogitator/memory.db';
36
- const resolvedPath = memoryPath.replace(/^~/, homedir());
37
- const memoryAdapter = new SQLiteAdapter({ provider: 'sqlite', path: resolvedPath });
38
- await memoryAdapter.connect();
62
+ const { memoryAdapter, graphAdapter, coreFactsPath } = await this.buildMemoryBackends(cleanupResources);
39
63
  cogitator.memory = memoryAdapter;
40
- let graphAdapter = null;
41
- if (this.config.memory.knowledgeGraph !== false) {
42
- graphAdapter = new SQLiteGraphAdapter({ path: resolvedPath });
43
- await graphAdapter.initialize();
44
- }
45
- const coreFacts = new CoreFactsStore({ path: resolvedPath });
64
+ const coreFacts = new CoreFactsStore({ path: coreFactsPath });
46
65
  await coreFacts.initialize();
47
66
  const tools = [];
48
67
  if (this.config.capabilities.webSearch) {
@@ -53,8 +72,10 @@ export class RuntimeBuilder {
53
72
  tools.push(found);
54
73
  }
55
74
  }
56
- if (this.config.capabilities.fileSystem) {
57
- tools.push(...builtinTools.filter((t) => t.name.startsWith('file_')));
75
+ const fsCfg = this.config.capabilities.fileSystem;
76
+ if (fsCfg) {
77
+ const fileTools = builtinTools.filter((t) => t.name.startsWith('file_'));
78
+ tools.push(...restrictFileTools(fileTools, this.resolveFileSystemRoots()));
58
79
  }
59
80
  if (this.config.capabilities.github) {
60
81
  const found = builtinTools.find((t) => t.name === 'github_api');
@@ -73,28 +94,29 @@ export class RuntimeBuilder {
73
94
  if (this.config.capabilities.scheduler) {
74
95
  timerStore = new SimpleTimerStore({
75
96
  persistPath: join(homedir(), '.cogitator', 'timers.json'),
97
+ resolveCronFiresAt: (cron, timezone) => getNextCronMs(cron, Date.now(), timezone),
76
98
  });
77
- const channelEntries = Object.entries(this.config.channels ?? {});
78
- const firstChannel = channelEntries[0];
79
- const firstOwnerId = firstChannel
80
- ? firstChannel[1]?.ownerIds?.[0]
81
- : undefined;
99
+ const [firstChannelName, firstChannel] = Object.entries(this.config.channels).find(([, value]) => value !== undefined) ?? [undefined, undefined];
82
100
  tools.push(...createSchedulerTools({
83
101
  store: timerStore,
84
- defaultChannel: firstChannel?.[0] ?? 'system',
85
- defaultUserId: firstOwnerId,
102
+ defaultChannel: firstChannelName ?? 'system',
103
+ defaultUserId: firstChannel?.ownerIds?.[0],
86
104
  }));
87
105
  }
88
106
  if (this.config.capabilities.deviceTools) {
89
107
  tools.push(...createDeviceTools());
90
108
  }
109
+ const ownerIds = this.collectOwnerIds();
110
+ const isOwner = (caller) => caller.channelType === 'terminal' ||
111
+ (!!caller.channelType && !!caller.userId && ownerIds[caller.channelType] === caller.userId);
91
112
  if (this.config.capabilities.selfConfig && this.opts?.configPath && this.opts.configHelpers) {
92
113
  tools.push(...createSelfConfigTools({
93
114
  configPath: this.opts.configPath,
94
115
  ...this.opts.configHelpers,
116
+ authorize: isOwner,
95
117
  onConfigUpdated: () => {
96
118
  console.log(`[${this.config.name}] Config updated, restarting...`);
97
- process.exit(78);
119
+ this.requestRestart();
98
120
  },
99
121
  }));
100
122
  }
@@ -117,47 +139,98 @@ export class RuntimeBuilder {
117
139
  await this.wireBrowser(tools, cleanupResources);
118
140
  await this.wireRAG(tools);
119
141
  await this.wireMCPServers(tools, cleanupResources);
120
- const coreFactsText = await coreFacts.formatForPrompt();
121
142
  const channels = this.buildChannels();
122
143
  const capDoc = generateCapabilitiesDoc({
123
144
  tools: tools.map((t) => ({ name: t.name, description: t.description })),
124
145
  channels: channels.map((c) => c.type),
125
146
  });
126
147
  tools.push(createCapabilitiesTool(capDoc));
127
- const instructions = this.buildInstructions(coreFactsText);
128
148
  const agent = new Agent({
129
149
  name: this.config.name,
130
150
  model: this.fullModelId,
131
- instructions,
151
+ instructions: this.buildInstructions(await coreFacts.formatForPrompt(), new Date()),
132
152
  tools,
133
153
  maxIterations: 15,
134
154
  });
155
+ const modelOverrides = new Map();
156
+ let globalModel = this.fullModelId;
157
+ const agentForUser = async (user) => {
158
+ const model = modelOverrides.get(`${user.channelType}:${user.id}`) ??
159
+ modelOverrides.get(user.id) ??
160
+ globalModel;
161
+ const instructions = this.buildInstructions(await coreFacts.formatForPrompt(), new Date());
162
+ return new Agent({ ...agent.config, id: agent.id, model, instructions });
163
+ };
135
164
  const middleware = [];
136
- const ownerIds = {};
137
- if (this.config.channels.telegram?.ownerIds?.[0]) {
138
- ownerIds.telegram = this.config.channels.telegram.ownerIds[0];
139
- }
140
- if (this.config.channels.discord?.ownerIds?.[0]) {
141
- ownerIds.discord = this.config.channels.discord.ownerIds[0];
142
- }
143
- if (this.config.channels.slack?.ownerIds?.[0]) {
144
- ownerIds.slack = this.config.channels.slack.ownerIds[0];
145
- }
165
+ let gatewayRef = null;
166
+ let dmPolicyMiddleware = null;
146
167
  if (this.config.security) {
147
- middleware.push(dmPolicy({
168
+ dmPolicyMiddleware = new DmPolicyMiddleware({
148
169
  mode: this.config.security.dmPolicy,
149
170
  allowlist: this.config.security.allowlist,
150
171
  groupPolicy: this.config.security.groupPolicy,
151
172
  groupAllowlist: this.config.security.groupAllowlist,
152
- storePath: this.config.security.storePath,
173
+ storePath: this.config.security.storePath
174
+ ? expandHome(this.config.security.storePath)
175
+ : undefined,
153
176
  ownerIds,
154
- }));
177
+ });
178
+ middleware.push(dmPolicyMiddleware);
155
179
  }
156
180
  if (Object.keys(ownerIds).length > 0) {
157
181
  middleware.push(ownerCommands({
158
182
  ownerIds,
159
183
  authorizedUserIds: this.config.security?.commandAccess?.authorized,
160
184
  publicCommands: this.config.security?.commandAccess?.publicCommands,
185
+ onStatus: () => {
186
+ if (!gatewayRef)
187
+ return 'Gateway is not running';
188
+ const stats = gatewayRef.stats;
189
+ return [
190
+ `Assistant: ${this.config.name}`,
191
+ `Model: ${globalModel}`,
192
+ `Uptime: ${formatDuration(stats.uptime)}`,
193
+ `Sessions: ${stats.activeSessions} active / ${stats.totalSessions} total`,
194
+ `Messages today: ${stats.messagesToday}`,
195
+ `Channels: ${stats.connectedChannels.join(', ')}`,
196
+ ].join('\n');
197
+ },
198
+ onSessions: () => {
199
+ const sessions = gatewayRef?.getSessions() ?? [];
200
+ if (sessions.length === 0)
201
+ return 'No sessions yet';
202
+ return sessions
203
+ .slice(0, 20)
204
+ .map((s) => `${s.active ? '●' : '○'} ${s.threadId}${s.userName ? ` (${s.userName})` : ''} — ${s.messageCount} msg, ${formatDuration(Date.now() - s.lastActiveAt)} ago`)
205
+ .join('\n');
206
+ },
207
+ onUsers: () => {
208
+ const owners = Object.entries(ownerIds).map(([type, id]) => `${type}:${id} (owner)`);
209
+ const approved = dmPolicyMiddleware
210
+ ? dmPolicyMiddleware
211
+ .getApprovedUsers()
212
+ .filter((key) => !owners.some((o) => o.startsWith(`${key} `)))
213
+ : [];
214
+ return [...owners, ...approved].join('\n') || 'No users';
215
+ },
216
+ onCompact: async (target, threadId) => {
217
+ if (!gatewayRef)
218
+ return 'Gateway is not running';
219
+ return gatewayRef.compactThread(target === 'current' ? threadId : target);
220
+ },
221
+ onModel: (model, forUser) => {
222
+ const fullModel = model.includes('/') ? model : `${this.config.llm.provider}/${model}`;
223
+ if (forUser) {
224
+ const key = forUser.replace(/^@/, '');
225
+ modelOverrides.set(key, fullModel);
226
+ return `Model for ${key} set to: ${fullModel}`;
227
+ }
228
+ globalModel = fullModel;
229
+ return `Model set to: ${fullModel}`;
230
+ },
231
+ onRestart: async () => {
232
+ setTimeout(() => this.requestRestart(), 500);
233
+ },
161
234
  }));
162
235
  }
163
236
  if (this.config.rateLimit) {
@@ -192,14 +265,12 @@ export class RuntimeBuilder {
192
265
  coreFacts,
193
266
  }));
194
267
  }
195
- const streamConfig = this.config.stream
196
- ? {
197
- flushInterval: this.config.stream.flushInterval ?? 600,
198
- minChunkSize: this.config.stream.minChunkSize ?? 30,
199
- }
200
- : { flushInterval: 600, minChunkSize: 30 };
268
+ const streamConfig = {
269
+ flushInterval: this.config.stream?.flushInterval ?? 600,
270
+ minChunkSize: this.config.stream?.minChunkSize ?? 30,
271
+ };
201
272
  const gateway = new Gateway({
202
- agent,
273
+ agent: agentForUser,
203
274
  cogitator,
204
275
  channels,
205
276
  middleware,
@@ -219,6 +290,7 @@ export class RuntimeBuilder {
219
290
  console.error(`[${this.config.name}] Error for ${msg.userId}:`, err.message);
220
291
  },
221
292
  });
293
+ gatewayRef = gateway;
222
294
  const scheduler = this.buildScheduler(timerStore, gateway);
223
295
  if (scheduler)
224
296
  scheduler.start();
@@ -227,9 +299,11 @@ export class RuntimeBuilder {
227
299
  scheduler.stop();
228
300
  await gateway.stop();
229
301
  await coreFacts.close();
230
- if (graphAdapter)
302
+ if (graphAdapter?.close)
231
303
  await graphAdapter.close();
232
304
  await memoryAdapter.disconnect();
305
+ if (cleanupResources.pgPool)
306
+ await cleanupResources.pgPool.end().catch(() => { });
233
307
  if (cleanupResources.browserSession) {
234
308
  await cleanupResources.browserSession.close().catch(() => { });
235
309
  }
@@ -240,6 +314,66 @@ export class RuntimeBuilder {
240
314
  };
241
315
  return { agent, cogitator, gateway, scheduler, cleanup };
242
316
  }
317
+ requestRestart() {
318
+ if (this.opts?.onRestart) {
319
+ this.opts.onRestart();
320
+ return;
321
+ }
322
+ process.exit(RESTART_EXIT_CODE);
323
+ }
324
+ collectOwnerIds() {
325
+ const ownerIds = {};
326
+ for (const [channel, cfg] of Object.entries(this.config.channels)) {
327
+ const owner = cfg?.ownerIds?.[0];
328
+ if (owner)
329
+ ownerIds[channel] = owner;
330
+ }
331
+ return ownerIds;
332
+ }
333
+ resolveFileSystemRoots() {
334
+ const fsCfg = this.config.capabilities.fileSystem;
335
+ const paths = fsCfg?.paths.length ? fsCfg.paths : [homedir()];
336
+ return paths.map(expandHome);
337
+ }
338
+ async buildMemoryBackends(resources) {
339
+ const memory = this.config.memory;
340
+ const sqlitePath = expandHome(memory.path ?? '~/.cogitator/memory.db');
341
+ const useGraph = memory.knowledgeGraph !== false;
342
+ if (memory.adapter === 'postgres') {
343
+ const connectionString = memory.connectionString ?? this.env.DATABASE_URL ?? this.env.POSTGRES_URL;
344
+ if (!connectionString) {
345
+ throw new Error('memory.adapter "postgres" requires memory.connectionString or DATABASE_URL in env');
346
+ }
347
+ const memoryAdapter = new PostgresAdapter({ provider: 'postgres', connectionString });
348
+ const connected = await memoryAdapter.connect();
349
+ if (!connected.success) {
350
+ throw new Error(`Failed to connect to Postgres: ${connected.error}`);
351
+ }
352
+ let graphAdapter = null;
353
+ if (useGraph) {
354
+ const pg = (await import('pg'));
355
+ const Pool = pg.Pool ?? pg.default?.Pool;
356
+ if (!Pool)
357
+ throw new Error('The "pg" package does not export Pool');
358
+ const pool = new Pool({ connectionString });
359
+ resources.pgPool = pool;
360
+ graphAdapter = new PostgresGraphAdapter({ pool });
361
+ await graphAdapter.initialize();
362
+ }
363
+ return { memoryAdapter, graphAdapter, coreFactsPath: sqlitePath };
364
+ }
365
+ const memoryAdapter = new SQLiteAdapter({ provider: 'sqlite', path: sqlitePath });
366
+ const connected = await memoryAdapter.connect();
367
+ if (connected && !connected.success) {
368
+ throw new Error(`Failed to open SQLite memory at ${sqlitePath}: ${connected.error}`);
369
+ }
370
+ let graphAdapter = null;
371
+ if (useGraph) {
372
+ graphAdapter = new SQLiteGraphAdapter({ path: sqlitePath });
373
+ await graphAdapter.initialize();
374
+ }
375
+ return { memoryAdapter, graphAdapter, coreFactsPath: sqlitePath };
376
+ }
243
377
  createExtractorBackend(cogitator) {
244
378
  const llmBackend = cogitator.getLLMBackend(this.fullModelId);
245
379
  const modelName = parseModel(this.fullModelId).model;
@@ -310,15 +444,24 @@ export class RuntimeBuilder {
310
444
  }
311
445
  }
312
446
  async ensurePlaywright() {
313
- const { existsSync } = await import('node:fs');
314
- const { join } = await import('node:path');
315
- const cacheDir = process.env.PLAYWRIGHT_BROWSERS_PATH ?? join(homedir(), 'Library', 'Caches', 'ms-playwright');
316
- if (existsSync(cacheDir))
447
+ if (existsSync(this.playwrightCacheDir()))
317
448
  return;
318
449
  console.log('[RuntimeBuilder] Installing Playwright chromium...');
319
450
  const { execSync } = await import('node:child_process');
320
451
  execSync('npx playwright install chromium', { stdio: 'inherit' });
321
452
  }
453
+ playwrightCacheDir() {
454
+ if (process.env.PLAYWRIGHT_BROWSERS_PATH)
455
+ return process.env.PLAYWRIGHT_BROWSERS_PATH;
456
+ switch (process.platform) {
457
+ case 'darwin':
458
+ return join(homedir(), 'Library', 'Caches', 'ms-playwright');
459
+ case 'win32':
460
+ return join(process.env.LOCALAPPDATA ?? join(homedir(), 'AppData', 'Local'), 'ms-playwright');
461
+ default:
462
+ return join(process.env.XDG_CACHE_HOME ?? join(homedir(), '.cache'), 'ms-playwright');
463
+ }
464
+ }
322
465
  async wireRAG(tools) {
323
466
  if (!this.config.capabilities.rag)
324
467
  return;
@@ -356,8 +499,12 @@ export class RuntimeBuilder {
356
499
  execute: ingestTool.execute,
357
500
  }));
358
501
  }
359
- catch {
360
- console.warn('[RuntimeBuilder] RAG capability requires @cogitator-ai/rag package');
502
+ catch (err) {
503
+ if (isModuleNotFound(err, '@cogitator-ai/rag')) {
504
+ console.warn('[RuntimeBuilder] RAG capability requires @cogitator-ai/rag package');
505
+ return;
506
+ }
507
+ console.warn('[RuntimeBuilder] RAG capability failed:', err instanceof Error ? err.message : String(err));
361
508
  }
362
509
  }
363
510
  async wireMCPServers(tools, resources) {
@@ -382,8 +529,12 @@ export class RuntimeBuilder {
382
529
  }
383
530
  }
384
531
  }
385
- catch {
386
- console.warn('[RuntimeBuilder] MCP servers require @cogitator-ai/mcp package');
532
+ catch (err) {
533
+ if (isModuleNotFound(err, '@cogitator-ai/mcp')) {
534
+ console.warn('[RuntimeBuilder] MCP servers require @cogitator-ai/mcp package');
535
+ return;
536
+ }
537
+ console.warn('[RuntimeBuilder] MCP setup failed:', err instanceof Error ? err.message : String(err));
387
538
  }
388
539
  }
389
540
  resolveEmbeddingConfig() {
@@ -488,11 +639,13 @@ export class RuntimeBuilder {
488
639
  await gateway.injectMessage(msg);
489
640
  },
490
641
  pollInterval: 30_000,
642
+ onError: (err, entry) => {
643
+ console.error(`[${this.config.name}] Scheduler error${entry ? ` for ${entry.id}` : ''}:`, err.message);
644
+ },
491
645
  });
492
646
  }
493
- buildInstructions(coreFactsText) {
647
+ buildInstructions(coreFactsText, now) {
494
648
  let instructions = this.config.personality;
495
- const now = new Date();
496
649
  const dateStr = now.toLocaleDateString('en-US', {
497
650
  weekday: 'long',
498
651
  year: 'numeric',
@@ -505,11 +658,8 @@ export class RuntimeBuilder {
505
658
  instructions += `\n\n## What I know about the user\n${coreFactsText}`;
506
659
  }
507
660
  instructions += `\n\nIMPORTANT: Use your tools when relevant. Don't guess answers when tools can provide accurate data.`;
508
- const fsCfg = this.config.capabilities.fileSystem;
509
- if (fsCfg) {
510
- const paths = typeof fsCfg === 'object' && 'paths' in fsCfg
511
- ? fsCfg.paths.map((p) => p.replace(/^~/, homedir()))
512
- : [homedir()];
661
+ if (this.config.capabilities.fileSystem) {
662
+ const paths = this.resolveFileSystemRoots();
513
663
  instructions += `\nYou have filesystem access. Allowed paths: ${paths.join(', ')}. Use file_read, file_write, file_list tools. Always use absolute paths.`;
514
664
  }
515
665
  if (this.config.capabilities.browser) {
@@ -532,7 +682,7 @@ When to use — IMMEDIATELY call schedule_task when the user:
532
682
  Examples:
533
683
  - "Remind me to check Slack in 5 min" → schedule_task({description: "Check Slack", delay: "5m"})
534
684
  - "Every morning at 9" → schedule_task({description: "Morning briefing", cron: "0 9 * * *"})
535
- - "At 3pm today" → schedule_task({description: "...", at: "${new Date().toISOString().split('T')[0]}T15:00:00"})
685
+ - "At 3pm today" → schedule_task({description: "...", at: "${localIsoDate(now)}T15:00:00"})
536
686
 
537
687
  The channel and userId are filled automatically from the current conversation — do NOT pass them manually.
538
688
  When the task fires, you will execute it — describe what to DO, not just what to say.