botinabox 2.5.2 → 2.6.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 (277) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +190 -190
  3. package/bin/botinabox.mjs +1 -1
  4. package/dist/{chunk-UACT2WXX.js → chunk-7AGWGYZC.js} +43 -5
  5. package/dist/cli.js +1 -1
  6. package/dist/connectors/google/index.d.ts +10 -1
  7. package/dist/connectors/google/index.js +1 -1
  8. package/dist/{gmail-connector-2FVYTQJH.js → gmail-connector-VP5FF56J.js} +2 -1
  9. package/dist/index.d.ts +64 -1
  10. package/dist/index.js +44 -10
  11. package/package.json +100 -100
  12. package/dist/channels/discord/adapter.d.ts +0 -32
  13. package/dist/channels/discord/adapter.js +0 -70
  14. package/dist/channels/discord/inbound.d.ts +0 -25
  15. package/dist/channels/discord/inbound.js +0 -24
  16. package/dist/channels/discord/models.d.ts +0 -8
  17. package/dist/channels/discord/models.js +0 -5
  18. package/dist/channels/discord/outbound.d.ts +0 -14
  19. package/dist/channels/discord/outbound.js +0 -38
  20. package/dist/channels/slack/adapter.d.ts +0 -33
  21. package/dist/channels/slack/adapter.js +0 -74
  22. package/dist/channels/slack/inbound.d.ts +0 -59
  23. package/dist/channels/slack/inbound.js +0 -96
  24. package/dist/channels/slack/models.d.ts +0 -9
  25. package/dist/channels/slack/models.js +0 -5
  26. package/dist/channels/slack/outbound.d.ts +0 -12
  27. package/dist/channels/slack/outbound.js +0 -18
  28. package/dist/channels/slack/transcribe.d.ts +0 -41
  29. package/dist/channels/slack/transcribe.js +0 -106
  30. package/dist/channels/webhook/adapter.d.ts +0 -23
  31. package/dist/channels/webhook/adapter.js +0 -86
  32. package/dist/channels/webhook/hmac.d.ts +0 -13
  33. package/dist/channels/webhook/hmac.js +0 -26
  34. package/dist/channels/webhook/models.d.ts +0 -9
  35. package/dist/channels/webhook/models.js +0 -5
  36. package/dist/channels/webhook/server.d.ts +0 -20
  37. package/dist/channels/webhook/server.js +0 -91
  38. package/dist/chat-pipeline-C-XlLGNl.d.ts +0 -648
  39. package/dist/chat-pipeline-CR1KF6eX.d.ts +0 -652
  40. package/dist/chat-pipeline-DisuC8SB.d.ts +0 -643
  41. package/dist/chunk-2LGXQPEA.js +0 -41
  42. package/dist/chunk-3X3YKI4T.js +0 -357
  43. package/dist/chunk-D47AIFOD.js +0 -351
  44. package/dist/chunk-DSNJKNEW.js +0 -328
  45. package/dist/chunk-GS2JFL6I.js +0 -144
  46. package/dist/chunk-J6S6QMUY.js +0 -144
  47. package/dist/chunk-QLA6YOFN.js +0 -22
  48. package/dist/cli/templates/config.yml.d.ts +0 -7
  49. package/dist/cli/templates/config.yml.js +0 -61
  50. package/dist/cli/templates/env.d.ts +0 -1
  51. package/dist/cli/templates/env.js +0 -30
  52. package/dist/cli/templates/index.ts.d.ts +0 -2
  53. package/dist/cli/templates/index.ts.js +0 -30
  54. package/dist/cli/templates/package.json.d.ts +0 -5
  55. package/dist/cli/templates/package.json.js +0 -28
  56. package/dist/connector-DDahQw-2.d.ts +0 -63
  57. package/dist/connectors/google/calendar-connector.d.ts +0 -40
  58. package/dist/connectors/google/calendar-connector.js +0 -243
  59. package/dist/connectors/google/gmail-connector.d.ts +0 -42
  60. package/dist/connectors/google/gmail-connector.js +0 -345
  61. package/dist/connectors/google/oauth.d.ts +0 -48
  62. package/dist/connectors/google/oauth.js +0 -112
  63. package/dist/connectors/google/types.d.ts +0 -78
  64. package/dist/connectors/google/types.js +0 -2
  65. package/dist/core/chat/auto-discovery.d.ts +0 -16
  66. package/dist/core/chat/auto-discovery.js +0 -54
  67. package/dist/core/chat/channel-registry.d.ts +0 -45
  68. package/dist/core/chat/channel-registry.js +0 -96
  69. package/dist/core/chat/chat-pipeline.d.ts +0 -113
  70. package/dist/core/chat/chat-pipeline.js +0 -395
  71. package/dist/core/chat/chat-responder.d.ts +0 -90
  72. package/dist/core/chat/chat-responder.js +0 -185
  73. package/dist/core/chat/formatter.d.ts +0 -11
  74. package/dist/core/chat/formatter.js +0 -60
  75. package/dist/core/chat/index.d.ts +0 -24
  76. package/dist/core/chat/index.js +0 -18
  77. package/dist/core/chat/message-interpreter.d.ts +0 -91
  78. package/dist/core/chat/message-interpreter.js +0 -166
  79. package/dist/core/chat/message-store.d.ts +0 -66
  80. package/dist/core/chat/message-store.js +0 -131
  81. package/dist/core/chat/notification-queue.d.ts +0 -34
  82. package/dist/core/chat/notification-queue.js +0 -111
  83. package/dist/core/chat/pipeline.d.ts +0 -38
  84. package/dist/core/chat/pipeline.js +0 -89
  85. package/dist/core/chat/policies.d.ts +0 -16
  86. package/dist/core/chat/policies.js +0 -25
  87. package/dist/core/chat/routing.d.ts +0 -17
  88. package/dist/core/chat/routing.js +0 -36
  89. package/dist/core/chat/session-key.d.ts +0 -30
  90. package/dist/core/chat/session-key.js +0 -65
  91. package/dist/core/chat/session-manager.d.ts +0 -17
  92. package/dist/core/chat/session-manager.js +0 -23
  93. package/dist/core/chat/text-chunker.d.ts +0 -9
  94. package/dist/core/chat/text-chunker.js +0 -48
  95. package/dist/core/chat/triage-router.d.ts +0 -75
  96. package/dist/core/chat/triage-router.js +0 -142
  97. package/dist/core/chat/types.d.ts +0 -5
  98. package/dist/core/chat/types.js +0 -5
  99. package/dist/core/config/defaults.d.ts +0 -2
  100. package/dist/core/config/defaults.js +0 -38
  101. package/dist/core/config/index.d.ts +0 -6
  102. package/dist/core/config/index.js +0 -4
  103. package/dist/core/config/interpolate.d.ts +0 -5
  104. package/dist/core/config/interpolate.js +0 -27
  105. package/dist/core/config/loader.d.ts +0 -24
  106. package/dist/core/config/loader.js +0 -59
  107. package/dist/core/config/schema.d.ts +0 -5
  108. package/dist/core/config/schema.js +0 -119
  109. package/dist/core/data/core-entity-contexts.d.ts +0 -14
  110. package/dist/core/data/core-entity-contexts.js +0 -197
  111. package/dist/core/data/core-migrations.d.ts +0 -5
  112. package/dist/core/data/core-migrations.js +0 -45
  113. package/dist/core/data/core-schema.d.ts +0 -6
  114. package/dist/core/data/core-schema.js +0 -454
  115. package/dist/core/data/data-store.d.ts +0 -67
  116. package/dist/core/data/data-store.js +0 -218
  117. package/dist/core/data/domain-entity-contexts.d.ts +0 -29
  118. package/dist/core/data/domain-entity-contexts.js +0 -321
  119. package/dist/core/data/domain-schema.d.ts +0 -36
  120. package/dist/core/data/domain-schema.js +0 -323
  121. package/dist/core/data/index.d.ts +0 -7
  122. package/dist/core/data/index.js +0 -7
  123. package/dist/core/data/types.d.ts +0 -111
  124. package/dist/core/data/types.js +0 -1
  125. package/dist/core/hooks/hook-bus.d.ts +0 -18
  126. package/dist/core/hooks/hook-bus.js +0 -120
  127. package/dist/core/hooks/index.d.ts +0 -2
  128. package/dist/core/hooks/index.js +0 -1
  129. package/dist/core/hooks/types.d.ts +0 -19
  130. package/dist/core/hooks/types.js +0 -1
  131. package/dist/core/index.d.ts +0 -4
  132. package/dist/core/index.js +0 -4
  133. package/dist/core/llm/auto-discovery.d.ts +0 -11
  134. package/dist/core/llm/auto-discovery.js +0 -49
  135. package/dist/core/llm/cost-tracker.d.ts +0 -6
  136. package/dist/core/llm/cost-tracker.js +0 -38
  137. package/dist/core/llm/index.d.ts +0 -4
  138. package/dist/core/llm/index.js +0 -3
  139. package/dist/core/llm/model-router.d.ts +0 -25
  140. package/dist/core/llm/model-router.js +0 -49
  141. package/dist/core/llm/provider-registry.d.ts +0 -9
  142. package/dist/core/llm/provider-registry.js +0 -25
  143. package/dist/core/llm/types.d.ts +0 -2
  144. package/dist/core/llm/types.js +0 -2
  145. package/dist/core/orchestrator/adapters/api-adapter.d.ts +0 -34
  146. package/dist/core/orchestrator/adapters/api-adapter.js +0 -88
  147. package/dist/core/orchestrator/adapters/cli-adapter.d.ts +0 -22
  148. package/dist/core/orchestrator/adapters/cli-adapter.js +0 -69
  149. package/dist/core/orchestrator/adapters/deterministic-adapter.d.ts +0 -35
  150. package/dist/core/orchestrator/adapters/deterministic-adapter.js +0 -75
  151. package/dist/core/orchestrator/adapters/env-whitelist.d.ts +0 -4
  152. package/dist/core/orchestrator/adapters/env-whitelist.js +0 -27
  153. package/dist/core/orchestrator/adapters/output-extractor.d.ts +0 -11
  154. package/dist/core/orchestrator/adapters/output-extractor.js +0 -59
  155. package/dist/core/orchestrator/adapters/process-manager.d.ts +0 -15
  156. package/dist/core/orchestrator/adapters/process-manager.js +0 -26
  157. package/dist/core/orchestrator/adapters/tool-loop.d.ts +0 -22
  158. package/dist/core/orchestrator/adapters/tool-loop.js +0 -66
  159. package/dist/core/orchestrator/agent-registry.d.ts +0 -31
  160. package/dist/core/orchestrator/agent-registry.js +0 -135
  161. package/dist/core/orchestrator/budget-controller.d.ts +0 -19
  162. package/dist/core/orchestrator/budget-controller.js +0 -73
  163. package/dist/core/orchestrator/chain-guard.d.ts +0 -14
  164. package/dist/core/orchestrator/chain-guard.js +0 -23
  165. package/dist/core/orchestrator/circuit-breaker.d.ts +0 -65
  166. package/dist/core/orchestrator/circuit-breaker.js +0 -159
  167. package/dist/core/orchestrator/claude-stream-parser.d.ts +0 -31
  168. package/dist/core/orchestrator/claude-stream-parser.js +0 -99
  169. package/dist/core/orchestrator/config-revisions.d.ts +0 -6
  170. package/dist/core/orchestrator/config-revisions.js +0 -17
  171. package/dist/core/orchestrator/dependency-resolver.d.ts +0 -20
  172. package/dist/core/orchestrator/dependency-resolver.js +0 -78
  173. package/dist/core/orchestrator/governance-gate.d.ts +0 -110
  174. package/dist/core/orchestrator/governance-gate.js +0 -170
  175. package/dist/core/orchestrator/learning-pipeline.d.ts +0 -109
  176. package/dist/core/orchestrator/learning-pipeline.js +0 -249
  177. package/dist/core/orchestrator/loop-detector.d.ts +0 -51
  178. package/dist/core/orchestrator/loop-detector.js +0 -133
  179. package/dist/core/orchestrator/ndjson-logger.d.ts +0 -6
  180. package/dist/core/orchestrator/ndjson-logger.js +0 -18
  181. package/dist/core/orchestrator/permission-relay.d.ts +0 -72
  182. package/dist/core/orchestrator/permission-relay.js +0 -164
  183. package/dist/core/orchestrator/run-manager.d.ts +0 -31
  184. package/dist/core/orchestrator/run-manager.js +0 -178
  185. package/dist/core/orchestrator/scheduler.d.ts +0 -70
  186. package/dist/core/orchestrator/scheduler.js +0 -198
  187. package/dist/core/orchestrator/secret-store.d.ts +0 -57
  188. package/dist/core/orchestrator/secret-store.js +0 -171
  189. package/dist/core/orchestrator/session-manager.d.ts +0 -13
  190. package/dist/core/orchestrator/session-manager.js +0 -66
  191. package/dist/core/orchestrator/task-queue.d.ts +0 -34
  192. package/dist/core/orchestrator/task-queue.js +0 -83
  193. package/dist/core/orchestrator/template-interpolate.d.ts +0 -5
  194. package/dist/core/orchestrator/template-interpolate.js +0 -18
  195. package/dist/core/orchestrator/user-registry.d.ts +0 -47
  196. package/dist/core/orchestrator/user-registry.js +0 -76
  197. package/dist/core/orchestrator/wakeup-queue.d.ts +0 -9
  198. package/dist/core/orchestrator/wakeup-queue.js +0 -45
  199. package/dist/core/orchestrator/workflow-engine.d.ts +0 -47
  200. package/dist/core/orchestrator/workflow-engine.js +0 -204
  201. package/dist/core/security/audit.d.ts +0 -20
  202. package/dist/core/security/audit.js +0 -33
  203. package/dist/core/security/column-validator.d.ts +0 -20
  204. package/dist/core/security/column-validator.js +0 -37
  205. package/dist/core/security/index.d.ts +0 -5
  206. package/dist/core/security/index.js +0 -5
  207. package/dist/core/security/process-env.d.ts +0 -13
  208. package/dist/core/security/process-env.js +0 -49
  209. package/dist/core/security/sanitizer.d.ts +0 -11
  210. package/dist/core/security/sanitizer.js +0 -39
  211. package/dist/core/security/types.d.ts +0 -11
  212. package/dist/core/security/types.js +0 -1
  213. package/dist/core/update/auto-update.d.ts +0 -21
  214. package/dist/core/update/auto-update.js +0 -102
  215. package/dist/core/update/backup-manager.d.ts +0 -7
  216. package/dist/core/update/backup-manager.js +0 -24
  217. package/dist/core/update/index.d.ts +0 -8
  218. package/dist/core/update/index.js +0 -6
  219. package/dist/core/update/migration-hooks.d.ts +0 -11
  220. package/dist/core/update/migration-hooks.js +0 -10
  221. package/dist/core/update/types.d.ts +0 -11
  222. package/dist/core/update/types.js +0 -1
  223. package/dist/core/update/update-checker.d.ts +0 -11
  224. package/dist/core/update/update-checker.js +0 -63
  225. package/dist/core/update/update-manager.d.ts +0 -25
  226. package/dist/core/update/update-manager.js +0 -101
  227. package/dist/core/update/version-utils.d.ts +0 -6
  228. package/dist/core/update/version-utils.js +0 -34
  229. package/dist/gmail-connector-MNUBRNFM.js +0 -6
  230. package/dist/gmail-connector-PS2VLGNE.js +0 -6
  231. package/dist/gmail-connector-ULSMN6X2.js +0 -6
  232. package/dist/gmail-connector-URRFX6A3.js +0 -6
  233. package/dist/inbound-AFBUPSPG.js +0 -10
  234. package/dist/inbound-AFOHYNUY.js +0 -6
  235. package/dist/inbound-CGIXRXGC.js +0 -8
  236. package/dist/inbound-MCOLRH6U.js +0 -10
  237. package/dist/inbound-SNEMBLGA.js +0 -6
  238. package/dist/inbound-ZJHAYVMF.js +0 -10
  239. package/dist/provider-qqJYv9nv.d.ts +0 -75
  240. package/dist/providers/anthropic/models.d.ts +0 -2
  241. package/dist/providers/anthropic/models.js +0 -29
  242. package/dist/providers/anthropic/provider.d.ts +0 -13
  243. package/dist/providers/anthropic/provider.js +0 -119
  244. package/dist/providers/anthropic/tool-converter.d.ts +0 -10
  245. package/dist/providers/anthropic/tool-converter.js +0 -7
  246. package/dist/providers/ollama/provider.d.ts +0 -17
  247. package/dist/providers/ollama/provider.js +0 -185
  248. package/dist/providers/openai/models.d.ts +0 -2
  249. package/dist/providers/openai/models.js +0 -29
  250. package/dist/providers/openai/provider.d.ts +0 -13
  251. package/dist/providers/openai/provider.js +0 -163
  252. package/dist/providers/openai/tool-converter.d.ts +0 -10
  253. package/dist/providers/openai/tool-converter.js +0 -10
  254. package/dist/shared/constants.d.ts +0 -50
  255. package/dist/shared/constants.js +0 -64
  256. package/dist/shared/index.d.ts +0 -14
  257. package/dist/shared/index.js +0 -14
  258. package/dist/shared/types/agent.d.ts +0 -36
  259. package/dist/shared/types/agent.js +0 -2
  260. package/dist/shared/types/channel.d.ts +0 -70
  261. package/dist/shared/types/channel.js +0 -2
  262. package/dist/shared/types/config.d.ts +0 -111
  263. package/dist/shared/types/config.js +0 -2
  264. package/dist/shared/types/connector.d.ts +0 -77
  265. package/dist/shared/types/connector.js +0 -2
  266. package/dist/shared/types/execution.d.ts +0 -29
  267. package/dist/shared/types/execution.js +0 -2
  268. package/dist/shared/types/provider.d.ts +0 -73
  269. package/dist/shared/types/provider.js +0 -2
  270. package/dist/shared/types/task.d.ts +0 -47
  271. package/dist/shared/types/task.js +0 -2
  272. package/dist/shared/types/workflow.d.ts +0 -39
  273. package/dist/shared/types/workflow.js +0 -2
  274. package/dist/shared/utils.d.ts +0 -6
  275. package/dist/shared/utils.js +0 -13
  276. package/dist/update-check.d.ts +0 -5
  277. package/dist/update-check.js +0 -56
@@ -1,49 +0,0 @@
1
- import { readdir, readFile } from "node:fs/promises";
2
- import { join } from "node:path";
3
- /**
4
- * Scans nodeModulesPath/@botinabox/{pkg}/package.json for each package in the scope.
5
- * If pkg.botinabox?.type === 'provider', dynamically imports the package
6
- * and returns the discovered LLMProvider instances.
7
- *
8
- * The optional importer parameter allows injection for testing.
9
- */
10
- export async function discoverProviders(nodeModulesPath, importer = (name) => import(name)) {
11
- const scopeDir = join(nodeModulesPath, "@botinabox");
12
- let entries;
13
- try {
14
- entries = await readdir(scopeDir);
15
- }
16
- catch {
17
- // No @botinabox scope directory — gracefully return empty
18
- return [];
19
- }
20
- const providers = [];
21
- for (const entry of entries) {
22
- const pkgPath = join(scopeDir, entry, "package.json");
23
- let pkg;
24
- try {
25
- const raw = await readFile(pkgPath, "utf8");
26
- pkg = JSON.parse(raw);
27
- }
28
- catch {
29
- continue;
30
- }
31
- const botinabox = pkg.botinabox;
32
- if (botinabox?.type !== "provider") {
33
- continue;
34
- }
35
- const packageName = pkg.name;
36
- if (!packageName) {
37
- continue;
38
- }
39
- try {
40
- const mod = await importer(packageName);
41
- const provider = "default" in mod && mod.default ? mod.default : mod;
42
- providers.push(provider);
43
- }
44
- catch {
45
- // Failed to import — skip silently
46
- }
47
- }
48
- return providers;
49
- }
@@ -1,6 +0,0 @@
1
- import type { HookBus } from "../hooks/hook-bus.js";
2
- import type { DataStore } from "../data/data-store.js";
3
- import type { ModelInfo } from "./types.js";
4
- export declare function setupCostTracker(hooks: HookBus, db: DataStore, opts?: {
5
- modelCatalog?: ModelInfo[];
6
- }): void;
@@ -1,38 +0,0 @@
1
- function calculateCostCents(usage, model) {
2
- if (!model?.inputCostPerMToken)
3
- return 0;
4
- const inputCost = (usage.inputTokens / 1_000_000) * model.inputCostPerMToken;
5
- const outputCost = (usage.outputTokens / 1_000_000) * (model.outputCostPerMToken ?? 0);
6
- return Math.round((inputCost + outputCost) * 100);
7
- }
8
- export function setupCostTracker(hooks, db, opts) {
9
- const catalog = opts?.modelCatalog ?? [];
10
- hooks.register("run.completed", async (payload) => {
11
- const ctx = payload;
12
- if (!ctx.usage)
13
- return;
14
- const modelId = ctx.usage.model ?? ctx.model;
15
- const providerId = ctx.usage.provider ?? ctx.provider;
16
- if (!modelId || !providerId)
17
- return;
18
- const modelInfo = catalog.find((m) => m.id === modelId);
19
- const costCents = calculateCostCents(ctx.usage, modelInfo);
20
- await db.insert("cost_events", {
21
- agent_id: ctx.agentId ?? null,
22
- run_id: ctx.runId ?? null,
23
- provider: providerId,
24
- model: modelId,
25
- input_tokens: ctx.usage.inputTokens,
26
- output_tokens: ctx.usage.outputTokens,
27
- cost_cents: costCents,
28
- });
29
- if (ctx.agentId) {
30
- const agent = await db.get("agents", ctx.agentId);
31
- if (agent) {
32
- await db.update("agents", ctx.agentId, {
33
- spent_monthly_cents: (agent.spent_monthly_cents ?? 0) + costCents,
34
- });
35
- }
36
- }
37
- }, { priority: 20 });
38
- }
@@ -1,4 +0,0 @@
1
- export { ProviderRegistry } from "./provider-registry.js";
2
- export { ModelRouter } from "./model-router.js";
3
- export { discoverProviders } from "./auto-discovery.js";
4
- export type { LLMProvider, ModelInfo, ResolvedModel, ChatParams, ChatResult, ChatMessage, ContentBlock, TokenUsage, ToolDefinition, ToolUse, } from "./types.js";
@@ -1,3 +0,0 @@
1
- export { ProviderRegistry } from "./provider-registry.js";
2
- export { ModelRouter } from "./model-router.js";
3
- export { discoverProviders } from "./auto-discovery.js";
@@ -1,25 +0,0 @@
1
- import type { ModelConfig } from "../../shared/index.js";
2
- import type { ModelInfo, ResolvedModel } from "./types.js";
3
- import type { ProviderRegistry } from "./provider-registry.js";
4
- export declare class ModelRouter {
5
- private readonly registry;
6
- private readonly config;
7
- constructor(registry: ProviderRegistry, config: ModelConfig);
8
- /**
9
- * Resolve a model ID or alias to a ResolvedModel.
10
- * 1. Look up alias in config.aliases (or use as-is)
11
- * 2. Search all registered providers for a model with that id
12
- */
13
- resolve(modelIdOrAlias: string): ResolvedModel | undefined;
14
- /**
15
- * Try primary model, then each in config.fallbackChain.
16
- * Throws if none found.
17
- */
18
- resolveWithFallback(modelIdOrAlias: string): ResolvedModel;
19
- /**
20
- * Use config.routing[purpose] ?? config.default, then resolveWithFallback.
21
- */
22
- resolveForPurpose(purpose: string): ResolvedModel;
23
- /** Returns all models from all registered providers. */
24
- listAvailable(): ModelInfo[];
25
- }
@@ -1,49 +0,0 @@
1
- export class ModelRouter {
2
- registry;
3
- config;
4
- constructor(registry, config) {
5
- this.registry = registry;
6
- this.config = config;
7
- }
8
- /**
9
- * Resolve a model ID or alias to a ResolvedModel.
10
- * 1. Look up alias in config.aliases (or use as-is)
11
- * 2. Search all registered providers for a model with that id
12
- */
13
- resolve(modelIdOrAlias) {
14
- const modelId = this.config.aliases[modelIdOrAlias] ?? modelIdOrAlias;
15
- for (const provider of this.registry.list()) {
16
- const found = provider.models.find((m) => m.id === modelId);
17
- if (found) {
18
- return { provider: provider.id, model: found.id };
19
- }
20
- }
21
- return undefined;
22
- }
23
- /**
24
- * Try primary model, then each in config.fallbackChain.
25
- * Throws if none found.
26
- */
27
- resolveWithFallback(modelIdOrAlias) {
28
- const primary = this.resolve(modelIdOrAlias);
29
- if (primary)
30
- return primary;
31
- for (const fallback of this.config.fallbackChain) {
32
- const resolved = this.resolve(fallback);
33
- if (resolved)
34
- return resolved;
35
- }
36
- throw new Error(`No available model found for "${modelIdOrAlias}" and fallback chain [${this.config.fallbackChain.join(", ")}]`);
37
- }
38
- /**
39
- * Use config.routing[purpose] ?? config.default, then resolveWithFallback.
40
- */
41
- resolveForPurpose(purpose) {
42
- const modelIdOrAlias = this.config.routing[purpose] ?? this.config.default;
43
- return this.resolveWithFallback(modelIdOrAlias);
44
- }
45
- /** Returns all models from all registered providers. */
46
- listAvailable() {
47
- return this.registry.listModels();
48
- }
49
- }
@@ -1,9 +0,0 @@
1
- import type { LLMProvider, ModelInfo } from "./types.js";
2
- export declare class ProviderRegistry {
3
- private providers;
4
- register(provider: LLMProvider): void;
5
- unregister(id: string): void;
6
- get(id: string): LLMProvider | undefined;
7
- list(): LLMProvider[];
8
- listModels(): ModelInfo[];
9
- }
@@ -1,25 +0,0 @@
1
- export class ProviderRegistry {
2
- providers = new Map();
3
- register(provider) {
4
- if (this.providers.has(provider.id)) {
5
- throw new Error(`Provider already registered: ${provider.id}`);
6
- }
7
- this.providers.set(provider.id, provider);
8
- }
9
- unregister(id) {
10
- this.providers.delete(id);
11
- }
12
- get(id) {
13
- return this.providers.get(id);
14
- }
15
- list() {
16
- return Array.from(this.providers.values());
17
- }
18
- listModels() {
19
- const models = [];
20
- for (const provider of this.providers.values()) {
21
- models.push(...provider.models);
22
- }
23
- return models;
24
- }
25
- }
@@ -1,2 +0,0 @@
1
- /** LLM module types — re-exports from @botinabox/shared */
2
- export type { LLMProvider, ModelInfo, ResolvedModel, ChatParams, ChatResult, ChatMessage, ContentBlock, TokenUsage, ToolDefinition, ToolUse, } from "../../shared/index.js";
@@ -1,2 +0,0 @@
1
- /** LLM module types — re-exports from @botinabox/shared */
2
- export {};
@@ -1,34 +0,0 @@
1
- import type { ModelRouter } from '../../llm/model-router.js';
2
- import type { ChatMessage, TokenUsage } from "../../../shared/index.js";
3
- export declare class ApiExecutionAdapter {
4
- private modelRouter;
5
- readonly type = "api";
6
- constructor(modelRouter: ModelRouter);
7
- execute(ctx: {
8
- agent: {
9
- id: string;
10
- model?: string;
11
- adapter_config?: string;
12
- };
13
- task: {
14
- description?: string;
15
- context?: string;
16
- };
17
- sessionParams?: {
18
- history?: ChatMessage[];
19
- };
20
- contextFiles?: string[];
21
- abortSignal?: AbortSignal;
22
- onLog?: (stream: 'stdout' | 'stderr', chunk: string) => void;
23
- }): Promise<{
24
- output: string;
25
- exitCode: number;
26
- usage: TokenUsage & {
27
- provider: string;
28
- model: string;
29
- };
30
- sessionParams: {
31
- history: ChatMessage[];
32
- };
33
- }>;
34
- }
@@ -1,88 +0,0 @@
1
- import { readFileSync, existsSync } from 'node:fs';
2
- import { toolLoop } from './tool-loop.js';
3
- export class ApiExecutionAdapter {
4
- modelRouter;
5
- type = 'api';
6
- constructor(modelRouter) {
7
- this.modelRouter = modelRouter;
8
- }
9
- async execute(ctx) {
10
- const modelId = ctx.agent.model ?? 'default';
11
- const resolved = this.modelRouter.resolve(modelId) ?? this.modelRouter.resolveForPurpose('default');
12
- const { provider, model } = resolved;
13
- // Get the LLM provider
14
- const registry = this.modelRouter.registry;
15
- const providerImpl = registry.list().find((p) => p.id === provider);
16
- if (!providerImpl) {
17
- throw new Error(`Provider not found: ${provider}`);
18
- }
19
- // Build system prompt
20
- let systemPrompt = '';
21
- // Load context files
22
- if (ctx.contextFiles && ctx.contextFiles.length > 0) {
23
- const fileContents = [];
24
- for (const filePath of ctx.contextFiles) {
25
- if (existsSync(filePath)) {
26
- const content = readFileSync(filePath, 'utf8');
27
- fileContents.push(`<file path="${filePath}">\n${content}\n</file>`);
28
- }
29
- }
30
- if (fileContents.length > 0) {
31
- systemPrompt = fileContents.join('\n\n');
32
- }
33
- }
34
- // Build messages from history + task
35
- const messages = [
36
- ...(ctx.sessionParams?.history ?? []),
37
- ];
38
- const taskContent = [
39
- ctx.task.description,
40
- ctx.task.context,
41
- ].filter(Boolean).join('\n\n');
42
- if (taskContent) {
43
- messages.push({ role: 'user', content: taskContent });
44
- }
45
- let outputText = '';
46
- let totalUsage = { inputTokens: 0, outputTokens: 0 };
47
- const history = [...messages];
48
- try {
49
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
- const callLLM = (params) => providerImpl.chat(params);
51
- for await (const event of toolLoop({
52
- model,
53
- messages,
54
- systemPrompt: systemPrompt || undefined,
55
- maxIterations: 20,
56
- signal: ctx.abortSignal,
57
- }, callLLM)) {
58
- if (event.type === 'text') {
59
- outputText += event.content;
60
- ctx.onLog?.('stdout', event.content);
61
- }
62
- else if (event.type === 'done') {
63
- totalUsage = {
64
- inputTokens: (totalUsage.inputTokens ?? 0) + (event.result.usage.inputTokens ?? 0),
65
- outputTokens: (totalUsage.outputTokens ?? 0) + (event.result.usage.outputTokens ?? 0),
66
- };
67
- }
68
- }
69
- history.push({ role: 'assistant', content: outputText });
70
- return {
71
- output: outputText,
72
- exitCode: 0,
73
- usage: { ...totalUsage, provider, model },
74
- sessionParams: { history },
75
- };
76
- }
77
- catch (err) {
78
- const message = err instanceof Error ? err.message : String(err);
79
- ctx.onLog?.('stderr', message);
80
- return {
81
- output: message,
82
- exitCode: 1,
83
- usage: { inputTokens: 0, outputTokens: 0, provider, model },
84
- sessionParams: { history },
85
- };
86
- }
87
- }
88
- }
@@ -1,22 +0,0 @@
1
- export declare class CliExecutionAdapter {
2
- readonly type = "cli";
3
- execute(ctx: {
4
- agent: {
5
- id: string;
6
- cwd?: string;
7
- adapter_config?: string;
8
- skip_permissions?: boolean;
9
- };
10
- task: {
11
- title: string;
12
- description?: string;
13
- context?: string;
14
- };
15
- logPath?: string;
16
- onLog?: (stream: string, chunk: string) => void;
17
- abortSignal?: AbortSignal;
18
- }): Promise<{
19
- output: string;
20
- exitCode: number;
21
- }>;
22
- }
@@ -1,69 +0,0 @@
1
- import { createWriteStream } from 'node:fs';
2
- import { spawnProcess, killProcessGroup } from './process-manager.js';
3
- import { extractOutput } from './output-extractor.js';
4
- export class CliExecutionAdapter {
5
- type = 'cli';
6
- async execute(ctx) {
7
- const cwd = ctx.agent.cwd ?? process.cwd();
8
- let config = {};
9
- if (ctx.agent.adapter_config) {
10
- try {
11
- config = JSON.parse(ctx.agent.adapter_config);
12
- }
13
- catch {
14
- // Ignore invalid config
15
- }
16
- }
17
- const skipPermissions = ctx.agent.skip_permissions ?? config['skip_permissions'] ?? false;
18
- const args = [];
19
- if (skipPermissions) {
20
- args.push('--dangerously-skip-permissions');
21
- }
22
- // Build prompt from task
23
- const prompt = [
24
- ctx.task.title,
25
- ctx.task.description,
26
- ctx.task.context,
27
- ]
28
- .filter(Boolean)
29
- .join('\n\n');
30
- // Append prompt as final argument (--print mode)
31
- args.push('--print', prompt);
32
- const child = spawnProcess('claude', args, { cwd });
33
- const stdoutChunks = [];
34
- let logStream = null;
35
- if (ctx.logPath) {
36
- logStream = createWriteStream(ctx.logPath, { flags: 'a' });
37
- }
38
- // Set up abort handler
39
- const abortHandler = () => {
40
- if (child.pid != null) {
41
- killProcessGroup(child.pid);
42
- }
43
- };
44
- ctx.abortSignal?.addEventListener('abort', abortHandler);
45
- child.stdout?.on('data', (chunk) => {
46
- stdoutChunks.push(chunk);
47
- const str = chunk.toString('utf8');
48
- ctx.onLog?.('stdout', str);
49
- logStream?.write(chunk);
50
- });
51
- child.stderr?.on('data', (chunk) => {
52
- const str = chunk.toString('utf8');
53
- ctx.onLog?.('stderr', str);
54
- });
55
- const exitCode = await new Promise((resolve) => {
56
- child.on('close', (code) => {
57
- resolve(code ?? 1);
58
- });
59
- child.on('error', () => {
60
- resolve(1);
61
- });
62
- });
63
- ctx.abortSignal?.removeEventListener('abort', abortHandler);
64
- logStream?.end();
65
- const rawOutput = Buffer.concat(stdoutChunks).toString('utf8');
66
- const output = extractOutput(rawOutput);
67
- return { output, exitCode };
68
- }
69
- }
@@ -1,35 +0,0 @@
1
- /**
2
- * DeterministicAdapter — executes scripts without LLM calls.
3
- * Story 6.1
4
- *
5
- * For tasks that don't require reasoning: routing, validation,
6
- * data fetching, file transforms. Runs a user-specified command
7
- * (Python, Node, bash) as a subprocess with task context on stdin.
8
- */
9
- export interface DeterministicConfig {
10
- command: string;
11
- args?: string[];
12
- env?: Record<string, string>;
13
- timeoutMs?: number;
14
- inputMode?: 'stdin' | 'arg';
15
- }
16
- export declare class DeterministicAdapter {
17
- readonly type = "deterministic";
18
- execute(ctx: {
19
- agent: {
20
- id: string;
21
- cwd?: string;
22
- adapter_config?: string;
23
- };
24
- task: {
25
- title: string;
26
- description?: string;
27
- context?: string;
28
- };
29
- abortSignal?: AbortSignal;
30
- onLog?: (stream: string, chunk: string) => void;
31
- }): Promise<{
32
- output: string;
33
- exitCode: number;
34
- }>;
35
- }
@@ -1,75 +0,0 @@
1
- /**
2
- * DeterministicAdapter — executes scripts without LLM calls.
3
- * Story 6.1
4
- *
5
- * For tasks that don't require reasoning: routing, validation,
6
- * data fetching, file transforms. Runs a user-specified command
7
- * (Python, Node, bash) as a subprocess with task context on stdin.
8
- */
9
- import { spawnProcess, killProcessGroup } from './process-manager.js';
10
- const DEFAULT_TIMEOUT_MS = 30_000;
11
- export class DeterministicAdapter {
12
- type = 'deterministic';
13
- async execute(ctx) {
14
- const cwd = ctx.agent.cwd ?? process.cwd();
15
- let config = { command: 'echo' };
16
- if (ctx.agent.adapter_config) {
17
- try {
18
- config = JSON.parse(ctx.agent.adapter_config);
19
- }
20
- catch {
21
- throw new Error('Invalid adapter_config for deterministic adapter');
22
- }
23
- }
24
- if (!config.command) {
25
- throw new Error('Deterministic adapter requires a command');
26
- }
27
- const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
28
- // Build task payload as JSON for the script
29
- const payload = JSON.stringify({
30
- taskId: ctx.task.title,
31
- description: ctx.task.description ?? '',
32
- context: ctx.task.context ?? '',
33
- });
34
- // Build args — append payload as final arg in 'arg' mode
35
- const args = [...(config.args ?? [])];
36
- if (config.inputMode === 'arg') {
37
- args.push(payload);
38
- }
39
- const child = spawnProcess(config.command, args, {
40
- cwd,
41
- extraEnv: config.env,
42
- });
43
- // Write payload to stdin in default mode
44
- if (config.inputMode !== 'arg' && child.stdin) {
45
- child.stdin.write(payload);
46
- child.stdin.end();
47
- }
48
- const stdoutChunks = [];
49
- child.stdout?.on('data', (chunk) => {
50
- stdoutChunks.push(chunk);
51
- ctx.onLog?.('stdout', chunk.toString('utf8'));
52
- });
53
- child.stderr?.on('data', (chunk) => {
54
- ctx.onLog?.('stderr', chunk.toString('utf8'));
55
- });
56
- // Set up abort + timeout
57
- const abortHandler = () => {
58
- if (child.pid != null)
59
- killProcessGroup(child.pid);
60
- };
61
- ctx.abortSignal?.addEventListener('abort', abortHandler);
62
- const timeout = setTimeout(() => {
63
- if (child.pid != null)
64
- killProcessGroup(child.pid);
65
- }, timeoutMs);
66
- const exitCode = await new Promise((resolve) => {
67
- child.on('close', (code) => resolve(code ?? 1));
68
- child.on('error', () => resolve(1));
69
- });
70
- clearTimeout(timeout);
71
- ctx.abortSignal?.removeEventListener('abort', abortHandler);
72
- const output = Buffer.concat(stdoutChunks).toString('utf8');
73
- return { output, exitCode };
74
- }
75
- }
@@ -1,4 +0,0 @@
1
- /**
2
- * Filter the process environment to only allowed keys, then merge in extras.
3
- */
4
- export declare function filterEnv(allowed?: string[], extra?: Record<string, string>): Record<string, string>;
@@ -1,27 +0,0 @@
1
- const DEFAULT_ALLOWED_ENV = [
2
- 'PATH',
3
- 'HOME',
4
- 'SHELL',
5
- 'LANG',
6
- 'USER',
7
- 'TERM',
8
- 'NODE_PATH',
9
- 'TMPDIR',
10
- ];
11
- /**
12
- * Filter the process environment to only allowed keys, then merge in extras.
13
- */
14
- export function filterEnv(allowed, extra) {
15
- const allowedKeys = allowed ?? DEFAULT_ALLOWED_ENV;
16
- const result = {};
17
- for (const key of allowedKeys) {
18
- const val = process.env[key];
19
- if (val !== undefined) {
20
- result[key] = val;
21
- }
22
- }
23
- if (extra) {
24
- Object.assign(result, extra);
25
- }
26
- return result;
27
- }
@@ -1,11 +0,0 @@
1
- export declare const MAX_OUTPUT_BYTES: number;
2
- /**
3
- * Extract final output from NDJSON log content.
4
- * Finds last line with {type:'result'} or {role:'assistant'}.
5
- * Caps at 4MB.
6
- */
7
- export declare function extractOutput(ndjsonContent: string): string;
8
- /**
9
- * Read file and extract output.
10
- */
11
- export declare function extractOutputFromFile(logPath: string): string;
@@ -1,59 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- export const MAX_OUTPUT_BYTES = 4 * 1024 * 1024; // 4MB
3
- /**
4
- * Extract final output from NDJSON log content.
5
- * Finds last line with {type:'result'} or {role:'assistant'}.
6
- * Caps at 4MB.
7
- */
8
- export function extractOutput(ndjsonContent) {
9
- const lines = ndjsonContent.split('\n').filter((l) => l.trim().length > 0);
10
- let lastOutput;
11
- for (const line of lines) {
12
- try {
13
- const parsed = JSON.parse(line);
14
- if (parsed['type'] === 'result') {
15
- const content = parsed['result'] ?? parsed['content'] ?? parsed['output'];
16
- if (typeof content === 'string') {
17
- lastOutput = content;
18
- }
19
- }
20
- else if (parsed['role'] === 'assistant') {
21
- const content = parsed['content'];
22
- if (typeof content === 'string') {
23
- lastOutput = content;
24
- }
25
- }
26
- else if (parsed['type'] === 'assistant') {
27
- const message = parsed['message'];
28
- if (message && Array.isArray(message['content'])) {
29
- for (const block of message['content']) {
30
- if (typeof block === 'object' &&
31
- block !== null &&
32
- block['type'] === 'text') {
33
- lastOutput = block['text'];
34
- }
35
- }
36
- }
37
- }
38
- }
39
- catch {
40
- // Skip non-JSON lines
41
- }
42
- }
43
- if (!lastOutput) {
44
- // Fall back to raw content
45
- lastOutput = ndjsonContent;
46
- }
47
- // Cap at 4MB
48
- if (Buffer.byteLength(lastOutput, 'utf8') > MAX_OUTPUT_BYTES) {
49
- return Buffer.from(lastOutput, 'utf8').subarray(0, MAX_OUTPUT_BYTES).toString('utf8');
50
- }
51
- return lastOutput;
52
- }
53
- /**
54
- * Read file and extract output.
55
- */
56
- export function extractOutputFromFile(logPath) {
57
- const content = readFileSync(logPath, 'utf8');
58
- return extractOutput(content);
59
- }