botinabox 1.8.2 → 1.8.4

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 (247) hide show
  1. package/dist/channels/discord/adapter.d.ts +32 -0
  2. package/dist/channels/discord/adapter.js +70 -0
  3. package/dist/channels/discord/inbound.d.ts +25 -0
  4. package/dist/channels/discord/inbound.js +24 -0
  5. package/dist/channels/discord/models.d.ts +8 -0
  6. package/dist/channels/discord/models.js +5 -0
  7. package/dist/channels/discord/outbound.d.ts +14 -0
  8. package/dist/channels/discord/outbound.js +38 -0
  9. package/dist/channels/slack/adapter.d.ts +33 -0
  10. package/dist/channels/slack/adapter.js +74 -0
  11. package/dist/channels/slack/inbound.d.ts +59 -0
  12. package/dist/channels/slack/inbound.js +96 -0
  13. package/dist/channels/slack/models.d.ts +9 -0
  14. package/dist/channels/slack/models.js +5 -0
  15. package/dist/channels/slack/outbound.d.ts +12 -0
  16. package/dist/channels/slack/outbound.js +18 -0
  17. package/dist/channels/slack/transcribe.d.ts +41 -0
  18. package/dist/channels/slack/transcribe.js +106 -0
  19. package/dist/channels/webhook/adapter.d.ts +23 -0
  20. package/dist/channels/webhook/adapter.js +86 -0
  21. package/dist/channels/webhook/hmac.d.ts +13 -0
  22. package/dist/channels/webhook/hmac.js +26 -0
  23. package/dist/channels/webhook/models.d.ts +9 -0
  24. package/dist/channels/webhook/models.js +5 -0
  25. package/dist/channels/webhook/server.d.ts +20 -0
  26. package/dist/channels/webhook/server.js +91 -0
  27. package/dist/cli/templates/config.yml.d.ts +7 -0
  28. package/dist/cli/templates/config.yml.js +61 -0
  29. package/dist/cli/templates/env.d.ts +1 -0
  30. package/dist/cli/templates/env.js +30 -0
  31. package/dist/cli/templates/index.ts.d.ts +2 -0
  32. package/dist/cli/templates/index.ts.js +30 -0
  33. package/dist/cli/templates/package.json.d.ts +5 -0
  34. package/dist/cli/templates/package.json.js +28 -0
  35. package/dist/connectors/google/calendar-connector.d.ts +40 -0
  36. package/dist/connectors/google/calendar-connector.js +243 -0
  37. package/dist/connectors/google/gmail-connector.d.ts +42 -0
  38. package/dist/connectors/google/gmail-connector.js +345 -0
  39. package/dist/connectors/google/oauth.d.ts +48 -0
  40. package/dist/connectors/google/oauth.js +112 -0
  41. package/dist/connectors/google/types.d.ts +78 -0
  42. package/dist/connectors/google/types.js +2 -0
  43. package/dist/core/chat/auto-discovery.d.ts +16 -0
  44. package/dist/core/chat/auto-discovery.js +54 -0
  45. package/dist/core/chat/channel-registry.d.ts +45 -0
  46. package/dist/core/chat/channel-registry.js +96 -0
  47. package/dist/core/chat/chat-pipeline.d.ts +113 -0
  48. package/dist/core/chat/chat-pipeline.js +350 -0
  49. package/dist/core/chat/chat-responder.d.ts +90 -0
  50. package/dist/core/chat/chat-responder.js +185 -0
  51. package/dist/core/chat/formatter.d.ts +11 -0
  52. package/dist/core/chat/formatter.js +60 -0
  53. package/dist/core/chat/index.d.ts +24 -0
  54. package/dist/core/chat/index.js +18 -0
  55. package/dist/core/chat/message-interpreter.d.ts +91 -0
  56. package/dist/core/chat/message-interpreter.js +166 -0
  57. package/dist/core/chat/message-store.d.ts +66 -0
  58. package/dist/core/chat/message-store.js +131 -0
  59. package/dist/core/chat/notification-queue.d.ts +34 -0
  60. package/dist/core/chat/notification-queue.js +111 -0
  61. package/dist/core/chat/pipeline.d.ts +38 -0
  62. package/dist/core/chat/pipeline.js +89 -0
  63. package/dist/core/chat/policies.d.ts +16 -0
  64. package/dist/core/chat/policies.js +25 -0
  65. package/dist/core/chat/routing.d.ts +17 -0
  66. package/dist/core/chat/routing.js +36 -0
  67. package/dist/core/chat/session-key.d.ts +30 -0
  68. package/dist/core/chat/session-key.js +65 -0
  69. package/dist/core/chat/session-manager.d.ts +17 -0
  70. package/dist/core/chat/session-manager.js +23 -0
  71. package/dist/core/chat/text-chunker.d.ts +9 -0
  72. package/dist/core/chat/text-chunker.js +48 -0
  73. package/dist/core/chat/triage-router.d.ts +75 -0
  74. package/dist/core/chat/triage-router.js +142 -0
  75. package/dist/core/chat/types.d.ts +5 -0
  76. package/dist/core/chat/types.js +5 -0
  77. package/dist/core/config/defaults.d.ts +2 -0
  78. package/dist/core/config/defaults.js +38 -0
  79. package/dist/core/config/index.d.ts +6 -0
  80. package/dist/core/config/index.js +4 -0
  81. package/dist/core/config/interpolate.d.ts +5 -0
  82. package/dist/core/config/interpolate.js +27 -0
  83. package/dist/core/config/loader.d.ts +24 -0
  84. package/dist/core/config/loader.js +59 -0
  85. package/dist/core/config/schema.d.ts +5 -0
  86. package/dist/core/config/schema.js +119 -0
  87. package/dist/core/data/core-entity-contexts.d.ts +14 -0
  88. package/dist/core/data/core-entity-contexts.js +197 -0
  89. package/dist/core/data/core-migrations.d.ts +5 -0
  90. package/dist/core/data/core-migrations.js +45 -0
  91. package/dist/core/data/core-schema.d.ts +6 -0
  92. package/dist/core/data/core-schema.js +454 -0
  93. package/dist/core/data/data-store.d.ts +67 -0
  94. package/dist/core/data/data-store.js +218 -0
  95. package/dist/core/data/domain-entity-contexts.d.ts +29 -0
  96. package/dist/core/data/domain-entity-contexts.js +321 -0
  97. package/dist/core/data/domain-schema.d.ts +36 -0
  98. package/dist/core/data/domain-schema.js +323 -0
  99. package/dist/core/data/index.d.ts +7 -0
  100. package/dist/core/data/index.js +7 -0
  101. package/dist/core/data/types.d.ts +111 -0
  102. package/dist/core/data/types.js +1 -0
  103. package/dist/core/hooks/hook-bus.d.ts +18 -0
  104. package/dist/core/hooks/hook-bus.js +120 -0
  105. package/dist/core/hooks/index.d.ts +2 -0
  106. package/dist/core/hooks/index.js +1 -0
  107. package/dist/core/hooks/types.d.ts +19 -0
  108. package/dist/core/hooks/types.js +1 -0
  109. package/dist/core/index.d.ts +4 -0
  110. package/dist/core/index.js +4 -0
  111. package/dist/core/llm/auto-discovery.d.ts +11 -0
  112. package/dist/core/llm/auto-discovery.js +49 -0
  113. package/dist/core/llm/cost-tracker.d.ts +6 -0
  114. package/dist/core/llm/cost-tracker.js +38 -0
  115. package/dist/core/llm/index.d.ts +4 -0
  116. package/dist/core/llm/index.js +3 -0
  117. package/dist/core/llm/model-router.d.ts +25 -0
  118. package/dist/core/llm/model-router.js +49 -0
  119. package/dist/core/llm/provider-registry.d.ts +9 -0
  120. package/dist/core/llm/provider-registry.js +25 -0
  121. package/dist/core/llm/types.d.ts +2 -0
  122. package/dist/core/llm/types.js +2 -0
  123. package/dist/core/orchestrator/adapters/api-adapter.d.ts +34 -0
  124. package/dist/core/orchestrator/adapters/api-adapter.js +88 -0
  125. package/dist/core/orchestrator/adapters/cli-adapter.d.ts +22 -0
  126. package/dist/core/orchestrator/adapters/cli-adapter.js +69 -0
  127. package/dist/core/orchestrator/adapters/deterministic-adapter.d.ts +35 -0
  128. package/dist/core/orchestrator/adapters/deterministic-adapter.js +75 -0
  129. package/dist/core/orchestrator/adapters/env-whitelist.d.ts +4 -0
  130. package/dist/core/orchestrator/adapters/env-whitelist.js +27 -0
  131. package/dist/core/orchestrator/adapters/output-extractor.d.ts +11 -0
  132. package/dist/core/orchestrator/adapters/output-extractor.js +59 -0
  133. package/dist/core/orchestrator/adapters/process-manager.d.ts +15 -0
  134. package/dist/core/orchestrator/adapters/process-manager.js +26 -0
  135. package/dist/core/orchestrator/adapters/tool-loop.d.ts +22 -0
  136. package/dist/core/orchestrator/adapters/tool-loop.js +66 -0
  137. package/dist/core/orchestrator/agent-registry.d.ts +31 -0
  138. package/dist/core/orchestrator/agent-registry.js +135 -0
  139. package/dist/core/orchestrator/budget-controller.d.ts +19 -0
  140. package/dist/core/orchestrator/budget-controller.js +73 -0
  141. package/dist/core/orchestrator/chain-guard.d.ts +14 -0
  142. package/dist/core/orchestrator/chain-guard.js +23 -0
  143. package/dist/core/orchestrator/circuit-breaker.d.ts +65 -0
  144. package/dist/core/orchestrator/circuit-breaker.js +159 -0
  145. package/dist/core/orchestrator/claude-stream-parser.d.ts +31 -0
  146. package/dist/core/orchestrator/claude-stream-parser.js +99 -0
  147. package/dist/core/orchestrator/config-revisions.d.ts +6 -0
  148. package/dist/core/orchestrator/config-revisions.js +17 -0
  149. package/dist/core/orchestrator/dependency-resolver.d.ts +20 -0
  150. package/dist/core/orchestrator/dependency-resolver.js +78 -0
  151. package/dist/core/orchestrator/governance-gate.d.ts +110 -0
  152. package/dist/core/orchestrator/governance-gate.js +170 -0
  153. package/dist/core/orchestrator/learning-pipeline.d.ts +109 -0
  154. package/dist/core/orchestrator/learning-pipeline.js +249 -0
  155. package/dist/core/orchestrator/loop-detector.d.ts +51 -0
  156. package/dist/core/orchestrator/loop-detector.js +133 -0
  157. package/dist/core/orchestrator/ndjson-logger.d.ts +6 -0
  158. package/dist/core/orchestrator/ndjson-logger.js +18 -0
  159. package/dist/core/orchestrator/permission-relay.d.ts +72 -0
  160. package/dist/core/orchestrator/permission-relay.js +164 -0
  161. package/dist/core/orchestrator/run-manager.d.ts +31 -0
  162. package/dist/core/orchestrator/run-manager.js +178 -0
  163. package/dist/core/orchestrator/scheduler.d.ts +70 -0
  164. package/dist/core/orchestrator/scheduler.js +198 -0
  165. package/dist/core/orchestrator/secret-store.d.ts +57 -0
  166. package/dist/core/orchestrator/secret-store.js +171 -0
  167. package/dist/core/orchestrator/session-manager.d.ts +13 -0
  168. package/dist/core/orchestrator/session-manager.js +66 -0
  169. package/dist/core/orchestrator/task-queue.d.ts +34 -0
  170. package/dist/core/orchestrator/task-queue.js +83 -0
  171. package/dist/core/orchestrator/template-interpolate.d.ts +5 -0
  172. package/dist/core/orchestrator/template-interpolate.js +18 -0
  173. package/dist/core/orchestrator/user-registry.d.ts +47 -0
  174. package/dist/core/orchestrator/user-registry.js +76 -0
  175. package/dist/core/orchestrator/wakeup-queue.d.ts +9 -0
  176. package/dist/core/orchestrator/wakeup-queue.js +45 -0
  177. package/dist/core/orchestrator/workflow-engine.d.ts +47 -0
  178. package/dist/core/orchestrator/workflow-engine.js +204 -0
  179. package/dist/core/security/audit.d.ts +20 -0
  180. package/dist/core/security/audit.js +33 -0
  181. package/dist/core/security/column-validator.d.ts +20 -0
  182. package/dist/core/security/column-validator.js +37 -0
  183. package/dist/core/security/index.d.ts +5 -0
  184. package/dist/core/security/index.js +5 -0
  185. package/dist/core/security/process-env.d.ts +13 -0
  186. package/dist/core/security/process-env.js +49 -0
  187. package/dist/core/security/sanitizer.d.ts +11 -0
  188. package/dist/core/security/sanitizer.js +39 -0
  189. package/dist/core/security/types.d.ts +11 -0
  190. package/dist/core/security/types.js +1 -0
  191. package/dist/core/update/auto-update.d.ts +21 -0
  192. package/dist/core/update/auto-update.js +102 -0
  193. package/dist/core/update/backup-manager.d.ts +7 -0
  194. package/dist/core/update/backup-manager.js +24 -0
  195. package/dist/core/update/index.d.ts +8 -0
  196. package/dist/core/update/index.js +6 -0
  197. package/dist/core/update/migration-hooks.d.ts +11 -0
  198. package/dist/core/update/migration-hooks.js +10 -0
  199. package/dist/core/update/types.d.ts +11 -0
  200. package/dist/core/update/types.js +1 -0
  201. package/dist/core/update/update-checker.d.ts +11 -0
  202. package/dist/core/update/update-checker.js +63 -0
  203. package/dist/core/update/update-manager.d.ts +25 -0
  204. package/dist/core/update/update-manager.js +101 -0
  205. package/dist/core/update/version-utils.d.ts +6 -0
  206. package/dist/core/update/version-utils.js +34 -0
  207. package/dist/index.d.ts +9 -0
  208. package/dist/index.js +90 -18
  209. package/dist/providers/anthropic/models.d.ts +2 -0
  210. package/dist/providers/anthropic/models.js +29 -0
  211. package/dist/providers/anthropic/provider.d.ts +13 -0
  212. package/dist/providers/anthropic/provider.js +119 -0
  213. package/dist/providers/anthropic/tool-converter.d.ts +10 -0
  214. package/dist/providers/anthropic/tool-converter.js +7 -0
  215. package/dist/providers/ollama/provider.d.ts +17 -0
  216. package/dist/providers/ollama/provider.js +185 -0
  217. package/dist/providers/openai/models.d.ts +2 -0
  218. package/dist/providers/openai/models.js +29 -0
  219. package/dist/providers/openai/provider.d.ts +13 -0
  220. package/dist/providers/openai/provider.js +163 -0
  221. package/dist/providers/openai/tool-converter.d.ts +10 -0
  222. package/dist/providers/openai/tool-converter.js +10 -0
  223. package/dist/shared/constants.d.ts +50 -0
  224. package/dist/shared/constants.js +64 -0
  225. package/dist/shared/index.d.ts +14 -0
  226. package/dist/shared/index.js +14 -0
  227. package/dist/shared/types/agent.d.ts +36 -0
  228. package/dist/shared/types/agent.js +2 -0
  229. package/dist/shared/types/channel.d.ts +70 -0
  230. package/dist/shared/types/channel.js +2 -0
  231. package/dist/shared/types/config.d.ts +111 -0
  232. package/dist/shared/types/config.js +2 -0
  233. package/dist/shared/types/connector.d.ts +77 -0
  234. package/dist/shared/types/connector.js +2 -0
  235. package/dist/shared/types/execution.d.ts +29 -0
  236. package/dist/shared/types/execution.js +2 -0
  237. package/dist/shared/types/provider.d.ts +73 -0
  238. package/dist/shared/types/provider.js +2 -0
  239. package/dist/shared/types/task.d.ts +47 -0
  240. package/dist/shared/types/task.js +2 -0
  241. package/dist/shared/types/workflow.d.ts +39 -0
  242. package/dist/shared/types/workflow.js +2 -0
  243. package/dist/shared/utils.d.ts +6 -0
  244. package/dist/shared/utils.js +13 -0
  245. package/dist/update-check.d.ts +5 -0
  246. package/dist/update-check.js +56 -0
  247. package/package.json +1 -1
@@ -0,0 +1,11 @@
1
+ export interface PackageUpdate {
2
+ name: string;
3
+ installedVersion: string;
4
+ latestVersion: string;
5
+ updateType: 'patch' | 'minor' | 'major';
6
+ }
7
+ export interface UpdateManifest {
8
+ checkedAt: string;
9
+ packages: PackageUpdate[];
10
+ hasUpdates: boolean;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { UpdateManifest } from './types.js';
2
+ export declare class UpdateChecker {
3
+ private nodeModulesPath;
4
+ private opts?;
5
+ private readonly fetchFn;
6
+ constructor(nodeModulesPath: string, opts?: {
7
+ fetch?: typeof globalThis.fetch;
8
+ } | undefined);
9
+ getInstalledPackages(): string[];
10
+ check(packageNames?: string[]): Promise<UpdateManifest>;
11
+ }
@@ -0,0 +1,63 @@
1
+ import { readFileSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { classifyUpdate, compareVersions } from './version-utils.js';
4
+ export class UpdateChecker {
5
+ nodeModulesPath;
6
+ opts;
7
+ fetchFn;
8
+ constructor(nodeModulesPath, opts) {
9
+ this.nodeModulesPath = nodeModulesPath;
10
+ this.opts = opts;
11
+ this.fetchFn = opts?.fetch ?? globalThis.fetch;
12
+ }
13
+ getInstalledPackages() {
14
+ try {
15
+ const botinaboxPath = join(this.nodeModulesPath, '@botinabox');
16
+ const entries = readdirSync(botinaboxPath, { withFileTypes: true });
17
+ return entries
18
+ .filter((e) => e.isDirectory())
19
+ .map((e) => e.name);
20
+ }
21
+ catch {
22
+ return [];
23
+ }
24
+ }
25
+ async check(packageNames) {
26
+ const installed = packageNames ?? this.getInstalledPackages();
27
+ const updates = [];
28
+ for (const pkg of installed) {
29
+ try {
30
+ const pkgJsonPath = join(this.nodeModulesPath, '@botinabox', pkg, 'package.json');
31
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
32
+ const installedVersion = pkgJson.version ?? '0.0.0';
33
+ const response = await this.fetchFn(`https://registry.npmjs.org/@botinabox/${pkg}`);
34
+ if (!response.ok)
35
+ continue;
36
+ const data = await response.json();
37
+ const latestVersion = data['dist-tags']?.['latest'];
38
+ if (!latestVersion)
39
+ continue;
40
+ if (compareVersions(latestVersion, installedVersion) > 0) {
41
+ const updateType = classifyUpdate(installedVersion, latestVersion);
42
+ if (updateType !== 'none') {
43
+ updates.push({
44
+ name: `@botinabox/${pkg}`,
45
+ installedVersion,
46
+ latestVersion,
47
+ updateType,
48
+ });
49
+ }
50
+ }
51
+ }
52
+ catch {
53
+ // Gracefully skip on error
54
+ continue;
55
+ }
56
+ }
57
+ return {
58
+ checkedAt: new Date().toISOString(),
59
+ packages: updates,
60
+ hasUpdates: updates.length > 0,
61
+ };
62
+ }
63
+ }
@@ -0,0 +1,25 @@
1
+ import type { DataStore } from '../data/data-store.js';
2
+ import type { HookBus } from '../hooks/hook-bus.js';
3
+ import type { PackageUpdate, UpdateManifest } from './types.js';
4
+ import { UpdateChecker } from './update-checker.js';
5
+ type UpdatePolicy = 'auto-all' | 'auto-compatible' | 'auto-patch' | 'notify' | 'manual';
6
+ export declare class UpdateManager {
7
+ private checker;
8
+ private db;
9
+ private hooks;
10
+ private opts?;
11
+ private backupManager;
12
+ constructor(checker: UpdateChecker, db: DataStore, hooks: HookBus, opts?: {
13
+ projectRoot?: string;
14
+ policy?: UpdatePolicy;
15
+ maintenanceWindow?: {
16
+ utcHourStart: number;
17
+ utcHourEnd: number;
18
+ };
19
+ } | undefined);
20
+ checkAndNotify(): Promise<UpdateManifest>;
21
+ applyUpdates(updates: PackageUpdate[]): Promise<void>;
22
+ isInMaintenanceWindow(): boolean;
23
+ filterByPolicy(updates: PackageUpdate[]): PackageUpdate[];
24
+ }
25
+ export {};
@@ -0,0 +1,101 @@
1
+ import { execSync } from 'child_process';
2
+ import { BackupManager } from './backup-manager.js';
3
+ export class UpdateManager {
4
+ checker;
5
+ db;
6
+ hooks;
7
+ opts;
8
+ backupManager;
9
+ constructor(checker, db, hooks, opts) {
10
+ this.checker = checker;
11
+ this.db = db;
12
+ this.hooks = hooks;
13
+ this.opts = opts;
14
+ this.backupManager = new BackupManager(opts?.projectRoot ?? process.cwd());
15
+ }
16
+ async checkAndNotify() {
17
+ const manifest = await this.checker.check();
18
+ if (manifest.hasUpdates) {
19
+ await this.hooks.emit('update.available', { manifest });
20
+ }
21
+ return manifest;
22
+ }
23
+ async applyUpdates(updates) {
24
+ const filtered = this.filterByPolicy(updates);
25
+ if (filtered.length === 0)
26
+ return;
27
+ if (!this.isInMaintenanceWindow()) {
28
+ await this.hooks.emit('update.deferred', { reason: 'outside maintenance window' });
29
+ return;
30
+ }
31
+ let backupPath;
32
+ const historyIds = [];
33
+ try {
34
+ backupPath = await this.backupManager.backup();
35
+ for (const update of filtered) {
36
+ const row = await this.db.insert('update_history', {
37
+ from_version: update.installedVersion,
38
+ to_version: update.latestVersion,
39
+ status: 'pending',
40
+ });
41
+ historyIds.push(row['id']);
42
+ }
43
+ execSync('pnpm install', {
44
+ cwd: this.opts?.projectRoot ?? process.cwd(),
45
+ stdio: 'ignore',
46
+ });
47
+ for (const id of historyIds) {
48
+ await this.db.update('update_history', { id }, { status: 'succeeded' });
49
+ }
50
+ await this.backupManager.cleanup(backupPath);
51
+ await this.hooks.emit('update.completed', { updates: filtered });
52
+ }
53
+ catch (err) {
54
+ for (const id of historyIds) {
55
+ await this.db.update('update_history', { id }, {
56
+ status: 'failed',
57
+ migration_log: String(err),
58
+ });
59
+ }
60
+ if (backupPath) {
61
+ try {
62
+ await this.backupManager.restore(backupPath);
63
+ await this.backupManager.cleanup(backupPath);
64
+ }
65
+ catch {
66
+ // best effort restore
67
+ }
68
+ }
69
+ await this.hooks.emit('update.failed', { updates: filtered, error: String(err) });
70
+ }
71
+ }
72
+ isInMaintenanceWindow() {
73
+ const window = this.opts?.maintenanceWindow;
74
+ if (!window)
75
+ return true; // No window configured = always allowed
76
+ const nowHour = new Date().getUTCHours();
77
+ const { utcHourStart, utcHourEnd } = window;
78
+ if (utcHourStart <= utcHourEnd) {
79
+ return nowHour >= utcHourStart && nowHour < utcHourEnd;
80
+ }
81
+ else {
82
+ // Wraps midnight
83
+ return nowHour >= utcHourStart || nowHour < utcHourEnd;
84
+ }
85
+ }
86
+ filterByPolicy(updates) {
87
+ const policy = this.opts?.policy ?? 'notify';
88
+ switch (policy) {
89
+ case 'auto-all':
90
+ return updates;
91
+ case 'auto-compatible':
92
+ return updates.filter((u) => u.updateType !== 'major');
93
+ case 'auto-patch':
94
+ return updates.filter((u) => u.updateType === 'patch');
95
+ case 'notify':
96
+ case 'manual':
97
+ default:
98
+ return [];
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Simple semver utilities — no external deps.
3
+ */
4
+ export declare function parseVersion(v: string): [number, number, number];
5
+ export declare function compareVersions(a: string, b: string): -1 | 0 | 1;
6
+ export declare function classifyUpdate(from: string, to: string): 'patch' | 'minor' | 'major' | 'none';
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Simple semver utilities — no external deps.
3
+ */
4
+ export function parseVersion(v) {
5
+ // Strip leading 'v' and any pre-release suffix
6
+ const cleaned = v.replace(/^v/, '').split('-')[0] ?? v;
7
+ const parts = cleaned.split('.');
8
+ const major = parseInt(parts[0] ?? '0', 10) || 0;
9
+ const minor = parseInt(parts[1] ?? '0', 10) || 0;
10
+ const patch = parseInt(parts[2] ?? '0', 10) || 0;
11
+ return [major, minor, patch];
12
+ }
13
+ export function compareVersions(a, b) {
14
+ const [aMaj, aMin, aPat] = parseVersion(a);
15
+ const [bMaj, bMin, bPat] = parseVersion(b);
16
+ if (aMaj !== bMaj)
17
+ return aMaj < bMaj ? -1 : 1;
18
+ if (aMin !== bMin)
19
+ return aMin < bMin ? -1 : 1;
20
+ if (aPat !== bPat)
21
+ return aPat < bPat ? -1 : 1;
22
+ return 0;
23
+ }
24
+ export function classifyUpdate(from, to) {
25
+ const [fMaj, fMin] = parseVersion(from);
26
+ const [tMaj, tMin] = parseVersion(to);
27
+ if (compareVersions(from, to) === 0)
28
+ return 'none';
29
+ if (tMaj !== fMaj)
30
+ return 'major';
31
+ if (tMin !== fMin)
32
+ return 'minor';
33
+ return 'patch';
34
+ }
package/dist/index.d.ts CHANGED
@@ -1343,6 +1343,8 @@ declare class ChatPipeline {
1343
1343
  private readonly tasks;
1344
1344
  private readonly wakeups;
1345
1345
  private readonly threadChannelMap;
1346
+ /** Last dispatch promise — exposed for testing. */
1347
+ lastDispatch: Promise<void>;
1346
1348
  constructor(db: DataStore, hooks: HookBus, config: ChatPipelineConfig);
1347
1349
  /**
1348
1350
  * Resolve the Slack channel ID for a thread (for response delivery).
@@ -1358,8 +1360,15 @@ declare class ChatPipeline {
1358
1360
  private isDuplicate;
1359
1361
  /**
1360
1362
  * Async interpretation + task dispatch (Layers 3-5).
1363
+ *
1364
+ * ALWAYS creates a task programmatically — task creation does not depend
1365
+ * on LLM classification. Interpretation enriches but never gates dispatch.
1361
1366
  */
1362
1367
  private interpretAndDispatch;
1368
+ /**
1369
+ * Programmatic task creation — guaranteed, no LLM dependency.
1370
+ */
1371
+ private guaranteedTaskDispatch;
1363
1372
  /**
1364
1373
  * Route and dispatch extracted tasks.
1365
1374
  */
package/dist/index.js CHANGED
@@ -1470,11 +1470,10 @@ Return a JSON object with these fields:
1470
1470
  }
1471
1471
 
1472
1472
  Rules:
1473
- - "tasks": actionable requests the user wants done. NOT conversational messages.
1473
+ - "tasks": ALWAYS create at least one task from every message. The task title should capture the user's intent. If the message is just a greeting or acknowledgment, create a task with title "Respond to greeting" or similar. Tasks are cheap \u2014 the execution layer decides whether action is needed.
1474
1474
  - "memories": information, notes, random thoughts to remember. Parse thematically \u2014 one message can have multiple memories.
1475
1475
  - "user_context": personality traits, preferences, or learnings about the user.
1476
- - "is_task_request": true if the message contains at least one actionable task.
1477
- - If the message is just a greeting or conversation, return empty arrays and is_task_request: false.
1476
+ - "is_task_request": ALWAYS true. Every message gets a task. The execution layer handles triage.
1478
1477
  - Return ONLY valid JSON, no markdown or explanation.`;
1479
1478
  var MessageInterpreter = class {
1480
1479
  constructor(db, hooks, config) {
@@ -1577,7 +1576,8 @@ var MessageInterpreter = class {
1577
1576
  system: INTERPRET_SYSTEM,
1578
1577
  maxTokens: 1e3
1579
1578
  });
1580
- const parsed = JSON.parse(result.content);
1579
+ const raw = result.content.replace(/^```(?:json)?\s*\n?/i, "").replace(/\n?```\s*$/i, "").trim();
1580
+ const parsed = JSON.parse(raw);
1581
1581
  return {
1582
1582
  tasks: (parsed.tasks ?? []).map((t) => ({
1583
1583
  title: t.title,
@@ -1654,6 +1654,8 @@ var ChatPipeline = class {
1654
1654
  // In-memory thread → channel mapping for response routing
1655
1655
  // (before thread_task_map exists)
1656
1656
  threadChannelMap = /* @__PURE__ */ new Map();
1657
+ /** Last dispatch promise — exposed for testing. */
1658
+ lastDispatch = Promise.resolve();
1657
1659
  /**
1658
1660
  * Resolve the Slack channel ID for a thread (for response delivery).
1659
1661
  */
@@ -1703,7 +1705,9 @@ ${historyContext}` : void 0
1703
1705
  skipFilter: true,
1704
1706
  skipRedundancyCheck: true
1705
1707
  });
1706
- void this.interpretAndDispatch(messageId, msg, threadTs, channelId);
1708
+ const dispatchPromise = this.interpretAndDispatch(messageId, msg, threadTs, channelId);
1709
+ this.lastDispatch = dispatchPromise;
1710
+ void dispatchPromise;
1707
1711
  });
1708
1712
  this.hooks.register("run.completed", async (ctx) => {
1709
1713
  const taskId = ctx.taskId;
@@ -1722,7 +1726,9 @@ ${historyContext}` : void 0
1722
1726
  threadId: mapping.thread_ts,
1723
1727
  agentId: ctx.agentId,
1724
1728
  taskId,
1725
- source: "agent"
1729
+ source: "agent",
1730
+ skipRedundancyCheck: true
1731
+ // Task results are always delivered
1726
1732
  });
1727
1733
  }, { priority: 90 });
1728
1734
  }
@@ -1746,28 +1752,94 @@ ${historyContext}` : void 0
1746
1752
  }
1747
1753
  /**
1748
1754
  * Async interpretation + task dispatch (Layers 3-5).
1755
+ *
1756
+ * ALWAYS creates a task programmatically — task creation does not depend
1757
+ * on LLM classification. Interpretation enriches but never gates dispatch.
1749
1758
  */
1750
1759
  async interpretAndDispatch(messageId, msg, threadTs, channelId) {
1760
+ await this.guaranteedTaskDispatch(msg, threadTs, channelId);
1751
1761
  try {
1752
1762
  const result = await this.interpreter.interpret(messageId);
1753
- if (result.tasks.length > 0 || result.memories.length > 0) {
1754
- const summary = this.buildSummary(result);
1755
- await this.responder.sendResponse({
1756
- text: summary,
1757
- channel: this.channel,
1758
- threadId: threadTs,
1759
- source: "interpretation"
1760
- });
1761
- }
1762
- if (result.isTaskRequest && result.tasks.length > 0) {
1763
- await this.dispatchTasks(result, msg, threadTs, channelId);
1763
+ if (result.memories.length > 0 || result.userContext.length > 0) {
1764
+ try {
1765
+ const parts = [];
1766
+ if (result.memories.length > 0) {
1767
+ parts.push(`Noted ${result.memories.length} thing${result.memories.length > 1 ? "s" : ""} to remember.`);
1768
+ }
1769
+ if (parts.length > 0) {
1770
+ await this.responder.sendResponse({
1771
+ text: parts.join(" "),
1772
+ channel: this.channel,
1773
+ threadId: threadTs,
1774
+ source: "interpretation"
1775
+ });
1776
+ }
1777
+ } catch {
1778
+ }
1764
1779
  }
1765
1780
  } catch (err) {
1781
+ const errMsg = err instanceof Error ? err.message : String(err);
1766
1782
  await this.hooks.emit("interpretation.error", {
1767
1783
  messageId,
1768
- error: err instanceof Error ? err.message : String(err)
1784
+ error: errMsg
1785
+ });
1786
+ }
1787
+ }
1788
+ /**
1789
+ * Programmatic task creation — guaranteed, no LLM dependency.
1790
+ */
1791
+ async guaranteedTaskDispatch(msg, threadTs, channelId) {
1792
+ const { agentSlug: targetSlug } = await this.router.route(msg);
1793
+ if (!targetSlug) return;
1794
+ const agents = await this.db.query("agents", { where: { slug: targetSlug } });
1795
+ const targetAgent = agents[0];
1796
+ if (!targetAgent) return;
1797
+ const handlerAgentId = targetAgent.id;
1798
+ if (threadTs) {
1799
+ const existing = await this.db.query("thread_task_map", {
1800
+ where: { thread_ts: threadTs, channel_id: channelId }
1801
+ });
1802
+ if (existing.length > 0) {
1803
+ const taskId2 = existing[0].task_id;
1804
+ const task = await this.tasks.get(taskId2);
1805
+ if (task && task.status !== "done" && task.status !== "cancelled") {
1806
+ const updatedDesc = `${task.description ?? ""}
1807
+
1808
+ ---
1809
+ **Follow-up (${(/* @__PURE__ */ new Date()).toISOString()}):**
1810
+ ${msg.body}`;
1811
+ await this.tasks.update(taskId2, { description: updatedDesc });
1812
+ await this.wakeups.enqueue(handlerAgentId, "chat_followup", { taskId: taskId2 });
1813
+ return;
1814
+ }
1815
+ }
1816
+ }
1817
+ const description = `## Chat Message
1818
+
1819
+ **Channel:** ${channelId}
1820
+ **Thread:** ${threadTs}
1821
+ **From:** ${msg.from}
1822
+ **Time:** ${msg.receivedAt}
1823
+
1824
+ ---
1825
+
1826
+ ${msg.body}`;
1827
+ const taskId = randomUUID();
1828
+ if (threadTs) {
1829
+ await this.db.insert("thread_task_map", {
1830
+ thread_ts: threadTs,
1831
+ channel_id: channelId,
1832
+ task_id: taskId
1769
1833
  });
1770
1834
  }
1835
+ await this.tasks.create({
1836
+ id: taskId,
1837
+ title: msg.body.slice(0, 120),
1838
+ description,
1839
+ assignee_id: handlerAgentId,
1840
+ priority: 5
1841
+ });
1842
+ await this.wakeups.enqueue(handlerAgentId, "chat_dispatch", { taskId });
1771
1843
  }
1772
1844
  /**
1773
1845
  * Route and dispatch extracted tasks.
@@ -0,0 +1,2 @@
1
+ import type { ModelInfo } from "../../shared/index.js";
2
+ export declare const MODELS: ModelInfo[];
@@ -0,0 +1,29 @@
1
+ export const MODELS = [
2
+ {
3
+ id: 'claude-opus-4-6',
4
+ displayName: 'Claude Opus 4.6',
5
+ contextWindow: 200000,
6
+ maxOutputTokens: 32000,
7
+ inputCostPerMToken: 15,
8
+ outputCostPerMToken: 75,
9
+ capabilities: ['chat', 'tools', 'vision', 'streaming'],
10
+ },
11
+ {
12
+ id: 'claude-sonnet-4-6',
13
+ displayName: 'Claude Sonnet 4.6',
14
+ contextWindow: 200000,
15
+ maxOutputTokens: 16000,
16
+ inputCostPerMToken: 3,
17
+ outputCostPerMToken: 15,
18
+ capabilities: ['chat', 'tools', 'vision', 'streaming'],
19
+ },
20
+ {
21
+ id: 'claude-haiku-4-5',
22
+ displayName: 'Claude Haiku 4.5',
23
+ contextWindow: 200000,
24
+ maxOutputTokens: 8192,
25
+ inputCostPerMToken: 0.8,
26
+ outputCostPerMToken: 4,
27
+ capabilities: ['chat', 'tools', 'vision', 'streaming'],
28
+ },
29
+ ];
@@ -0,0 +1,13 @@
1
+ import type { LLMProvider, ChatParams, ChatResult, ModelInfo, ToolDefinition } from "../../shared/index.js";
2
+ export declare class AnthropicProvider implements LLMProvider {
3
+ readonly id = "anthropic";
4
+ readonly displayName = "Anthropic";
5
+ readonly models: ModelInfo[];
6
+ private client;
7
+ constructor({ apiKey }: {
8
+ apiKey: string;
9
+ });
10
+ serializeTools(tools: ToolDefinition[]): unknown;
11
+ chat(params: ChatParams): Promise<ChatResult>;
12
+ chatStream(params: ChatParams): AsyncGenerator<string, ChatResult, unknown>;
13
+ }
@@ -0,0 +1,119 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ import { MODELS } from './models.js';
3
+ import { convertTools } from './tool-converter.js';
4
+ export class AnthropicProvider {
5
+ id = 'anthropic';
6
+ displayName = 'Anthropic';
7
+ models = MODELS;
8
+ client;
9
+ constructor({ apiKey }) {
10
+ this.client = new Anthropic({ apiKey });
11
+ }
12
+ serializeTools(tools) {
13
+ return convertTools(tools);
14
+ }
15
+ async chat(params) {
16
+ const { messages, system, tools, maxTokens, temperature, model, abortSignal } = params;
17
+ const anthropicMessages = messages
18
+ .filter((m) => m.role !== 'system')
19
+ .map((m) => ({
20
+ role: m.role,
21
+ content: typeof m.content === 'string' ? m.content : m.content,
22
+ }));
23
+ const response = await this.client.messages.create({
24
+ model,
25
+ max_tokens: maxTokens ?? 4096,
26
+ messages: anthropicMessages,
27
+ ...(system ? { system } : {}),
28
+ ...(tools && tools.length > 0 ? { tools: convertTools(tools) } : {}),
29
+ ...(temperature !== undefined ? { temperature } : {}),
30
+ }, { signal: abortSignal });
31
+ let content = '';
32
+ const toolUses = [];
33
+ for (const block of response.content) {
34
+ if (block.type === 'text') {
35
+ content += block.text;
36
+ }
37
+ else if (block.type === 'tool_use') {
38
+ toolUses.push({
39
+ id: block.id,
40
+ name: block.name,
41
+ input: block.input,
42
+ });
43
+ }
44
+ }
45
+ const stopReason = mapStopReason(response.stop_reason);
46
+ return {
47
+ content,
48
+ toolUses: toolUses.length > 0 ? toolUses : undefined,
49
+ usage: {
50
+ inputTokens: response.usage.input_tokens,
51
+ outputTokens: response.usage.output_tokens,
52
+ },
53
+ model: response.model,
54
+ stopReason,
55
+ };
56
+ }
57
+ async *chatStream(params) {
58
+ const { messages, system, tools, maxTokens, temperature, model, abortSignal } = params;
59
+ const anthropicMessages = messages
60
+ .filter((m) => m.role !== 'system')
61
+ .map((m) => ({
62
+ role: m.role,
63
+ content: typeof m.content === 'string' ? m.content : m.content,
64
+ }));
65
+ const stream = this.client.messages.stream({
66
+ model,
67
+ max_tokens: maxTokens ?? 4096,
68
+ messages: anthropicMessages,
69
+ ...(system ? { system } : {}),
70
+ ...(tools && tools.length > 0 ? { tools: convertTools(tools) } : {}),
71
+ ...(temperature !== undefined ? { temperature } : {}),
72
+ }, { signal: abortSignal });
73
+ for await (const event of stream) {
74
+ if (event.type === 'content_block_delta' &&
75
+ event.delta.type === 'text_delta') {
76
+ yield event.delta.text;
77
+ }
78
+ }
79
+ const finalMessage = await stream.finalMessage();
80
+ let content = '';
81
+ const toolUses = [];
82
+ for (const block of finalMessage.content) {
83
+ if (block.type === 'text') {
84
+ content += block.text;
85
+ }
86
+ else if (block.type === 'tool_use') {
87
+ toolUses.push({
88
+ id: block.id,
89
+ name: block.name,
90
+ input: block.input,
91
+ });
92
+ }
93
+ }
94
+ return {
95
+ content,
96
+ toolUses: toolUses.length > 0 ? toolUses : undefined,
97
+ usage: {
98
+ inputTokens: finalMessage.usage.input_tokens,
99
+ outputTokens: finalMessage.usage.output_tokens,
100
+ },
101
+ model: finalMessage.model,
102
+ stopReason: mapStopReason(finalMessage.stop_reason),
103
+ };
104
+ }
105
+ }
106
+ function mapStopReason(reason) {
107
+ switch (reason) {
108
+ case 'end_turn':
109
+ return 'end_turn';
110
+ case 'tool_use':
111
+ return 'tool_use';
112
+ case 'max_tokens':
113
+ return 'max_tokens';
114
+ case 'stop_sequence':
115
+ return 'stop_sequence';
116
+ default:
117
+ return 'end_turn';
118
+ }
119
+ }
@@ -0,0 +1,10 @@
1
+ import type { ToolDefinition } from "../../shared/index.js";
2
+ export interface AnthropicTool {
3
+ name: string;
4
+ description: string;
5
+ input_schema: {
6
+ type: 'object';
7
+ [key: string]: unknown;
8
+ };
9
+ }
10
+ export declare function convertTools(tools: ToolDefinition[]): AnthropicTool[];
@@ -0,0 +1,7 @@
1
+ export function convertTools(tools) {
2
+ return tools.map((tool) => ({
3
+ name: tool.name,
4
+ description: tool.description,
5
+ input_schema: { type: 'object', ...tool.parameters },
6
+ }));
7
+ }
@@ -0,0 +1,17 @@
1
+ import type { LLMProvider, ChatParams, ChatResult, ModelInfo, ToolDefinition } from "../../shared/index.js";
2
+ export declare class OllamaProvider implements LLMProvider {
3
+ readonly id = "ollama";
4
+ readonly displayName = "Ollama";
5
+ private baseUrl;
6
+ private cachedModels;
7
+ private cacheTimestamp;
8
+ private readonly cacheTtlMs;
9
+ constructor({ baseUrl }?: {
10
+ baseUrl?: string;
11
+ });
12
+ get models(): ModelInfo[];
13
+ serializeTools(_tools: ToolDefinition[]): unknown;
14
+ getModels(): Promise<ModelInfo[]>;
15
+ chat(params: ChatParams): Promise<ChatResult>;
16
+ chatStream(params: ChatParams): AsyncGenerator<string, ChatResult, unknown>;
17
+ }