botinabox 2.4.3 → 2.5.1

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 (276) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +190 -190
  3. package/bin/botinabox.mjs +1 -1
  4. package/dist/cli.js +0 -0
  5. package/dist/connectors/google/index.d.ts +67 -1
  6. package/dist/connectors/google/index.js +240 -0
  7. package/dist/index.js +19 -5
  8. package/package.json +100 -99
  9. package/dist/channels/discord/adapter.d.ts +0 -32
  10. package/dist/channels/discord/adapter.js +0 -70
  11. package/dist/channels/discord/inbound.d.ts +0 -25
  12. package/dist/channels/discord/inbound.js +0 -24
  13. package/dist/channels/discord/models.d.ts +0 -8
  14. package/dist/channels/discord/models.js +0 -5
  15. package/dist/channels/discord/outbound.d.ts +0 -14
  16. package/dist/channels/discord/outbound.js +0 -38
  17. package/dist/channels/slack/adapter.d.ts +0 -33
  18. package/dist/channels/slack/adapter.js +0 -74
  19. package/dist/channels/slack/inbound.d.ts +0 -59
  20. package/dist/channels/slack/inbound.js +0 -96
  21. package/dist/channels/slack/models.d.ts +0 -9
  22. package/dist/channels/slack/models.js +0 -5
  23. package/dist/channels/slack/outbound.d.ts +0 -12
  24. package/dist/channels/slack/outbound.js +0 -18
  25. package/dist/channels/slack/transcribe.d.ts +0 -41
  26. package/dist/channels/slack/transcribe.js +0 -106
  27. package/dist/channels/webhook/adapter.d.ts +0 -23
  28. package/dist/channels/webhook/adapter.js +0 -86
  29. package/dist/channels/webhook/hmac.d.ts +0 -13
  30. package/dist/channels/webhook/hmac.js +0 -26
  31. package/dist/channels/webhook/models.d.ts +0 -9
  32. package/dist/channels/webhook/models.js +0 -5
  33. package/dist/channels/webhook/server.d.ts +0 -20
  34. package/dist/channels/webhook/server.js +0 -91
  35. package/dist/chat-pipeline-C-XlLGNl.d.ts +0 -648
  36. package/dist/chat-pipeline-CR1KF6eX.d.ts +0 -652
  37. package/dist/chat-pipeline-DisuC8SB.d.ts +0 -643
  38. package/dist/chunk-2LGXQPEA.js +0 -41
  39. package/dist/chunk-3X3YKI4T.js +0 -357
  40. package/dist/chunk-D47AIFOD.js +0 -351
  41. package/dist/chunk-DSNJKNEW.js +0 -328
  42. package/dist/chunk-GS2JFL6I.js +0 -144
  43. package/dist/chunk-J6S6QMUY.js +0 -144
  44. package/dist/chunk-QLA6YOFN.js +0 -22
  45. package/dist/chunk-UACT2WXX.js +0 -381
  46. package/dist/cli/templates/config.yml.d.ts +0 -7
  47. package/dist/cli/templates/config.yml.js +0 -61
  48. package/dist/cli/templates/env.d.ts +0 -1
  49. package/dist/cli/templates/env.js +0 -30
  50. package/dist/cli/templates/index.ts.d.ts +0 -2
  51. package/dist/cli/templates/index.ts.js +0 -30
  52. package/dist/cli/templates/package.json.d.ts +0 -5
  53. package/dist/cli/templates/package.json.js +0 -28
  54. package/dist/connector-DDahQw-2.d.ts +0 -63
  55. package/dist/connectors/google/calendar-connector.d.ts +0 -40
  56. package/dist/connectors/google/calendar-connector.js +0 -243
  57. package/dist/connectors/google/gmail-connector.d.ts +0 -42
  58. package/dist/connectors/google/gmail-connector.js +0 -345
  59. package/dist/connectors/google/oauth.d.ts +0 -48
  60. package/dist/connectors/google/oauth.js +0 -112
  61. package/dist/connectors/google/types.d.ts +0 -78
  62. package/dist/connectors/google/types.js +0 -2
  63. package/dist/core/chat/auto-discovery.d.ts +0 -16
  64. package/dist/core/chat/auto-discovery.js +0 -54
  65. package/dist/core/chat/channel-registry.d.ts +0 -45
  66. package/dist/core/chat/channel-registry.js +0 -96
  67. package/dist/core/chat/chat-pipeline.d.ts +0 -113
  68. package/dist/core/chat/chat-pipeline.js +0 -395
  69. package/dist/core/chat/chat-responder.d.ts +0 -90
  70. package/dist/core/chat/chat-responder.js +0 -185
  71. package/dist/core/chat/formatter.d.ts +0 -11
  72. package/dist/core/chat/formatter.js +0 -60
  73. package/dist/core/chat/index.d.ts +0 -24
  74. package/dist/core/chat/index.js +0 -18
  75. package/dist/core/chat/message-interpreter.d.ts +0 -91
  76. package/dist/core/chat/message-interpreter.js +0 -166
  77. package/dist/core/chat/message-store.d.ts +0 -66
  78. package/dist/core/chat/message-store.js +0 -131
  79. package/dist/core/chat/notification-queue.d.ts +0 -34
  80. package/dist/core/chat/notification-queue.js +0 -111
  81. package/dist/core/chat/pipeline.d.ts +0 -38
  82. package/dist/core/chat/pipeline.js +0 -89
  83. package/dist/core/chat/policies.d.ts +0 -16
  84. package/dist/core/chat/policies.js +0 -25
  85. package/dist/core/chat/routing.d.ts +0 -17
  86. package/dist/core/chat/routing.js +0 -36
  87. package/dist/core/chat/session-key.d.ts +0 -30
  88. package/dist/core/chat/session-key.js +0 -65
  89. package/dist/core/chat/session-manager.d.ts +0 -17
  90. package/dist/core/chat/session-manager.js +0 -23
  91. package/dist/core/chat/text-chunker.d.ts +0 -9
  92. package/dist/core/chat/text-chunker.js +0 -48
  93. package/dist/core/chat/triage-router.d.ts +0 -75
  94. package/dist/core/chat/triage-router.js +0 -142
  95. package/dist/core/chat/types.d.ts +0 -5
  96. package/dist/core/chat/types.js +0 -5
  97. package/dist/core/config/defaults.d.ts +0 -2
  98. package/dist/core/config/defaults.js +0 -38
  99. package/dist/core/config/index.d.ts +0 -6
  100. package/dist/core/config/index.js +0 -4
  101. package/dist/core/config/interpolate.d.ts +0 -5
  102. package/dist/core/config/interpolate.js +0 -27
  103. package/dist/core/config/loader.d.ts +0 -24
  104. package/dist/core/config/loader.js +0 -59
  105. package/dist/core/config/schema.d.ts +0 -5
  106. package/dist/core/config/schema.js +0 -119
  107. package/dist/core/data/core-entity-contexts.d.ts +0 -14
  108. package/dist/core/data/core-entity-contexts.js +0 -197
  109. package/dist/core/data/core-migrations.d.ts +0 -5
  110. package/dist/core/data/core-migrations.js +0 -45
  111. package/dist/core/data/core-schema.d.ts +0 -6
  112. package/dist/core/data/core-schema.js +0 -454
  113. package/dist/core/data/data-store.d.ts +0 -67
  114. package/dist/core/data/data-store.js +0 -218
  115. package/dist/core/data/domain-entity-contexts.d.ts +0 -29
  116. package/dist/core/data/domain-entity-contexts.js +0 -321
  117. package/dist/core/data/domain-schema.d.ts +0 -36
  118. package/dist/core/data/domain-schema.js +0 -323
  119. package/dist/core/data/index.d.ts +0 -7
  120. package/dist/core/data/index.js +0 -7
  121. package/dist/core/data/types.d.ts +0 -111
  122. package/dist/core/data/types.js +0 -1
  123. package/dist/core/hooks/hook-bus.d.ts +0 -18
  124. package/dist/core/hooks/hook-bus.js +0 -120
  125. package/dist/core/hooks/index.d.ts +0 -2
  126. package/dist/core/hooks/index.js +0 -1
  127. package/dist/core/hooks/types.d.ts +0 -19
  128. package/dist/core/hooks/types.js +0 -1
  129. package/dist/core/index.d.ts +0 -4
  130. package/dist/core/index.js +0 -4
  131. package/dist/core/llm/auto-discovery.d.ts +0 -11
  132. package/dist/core/llm/auto-discovery.js +0 -49
  133. package/dist/core/llm/cost-tracker.d.ts +0 -6
  134. package/dist/core/llm/cost-tracker.js +0 -38
  135. package/dist/core/llm/index.d.ts +0 -4
  136. package/dist/core/llm/index.js +0 -3
  137. package/dist/core/llm/model-router.d.ts +0 -25
  138. package/dist/core/llm/model-router.js +0 -49
  139. package/dist/core/llm/provider-registry.d.ts +0 -9
  140. package/dist/core/llm/provider-registry.js +0 -25
  141. package/dist/core/llm/types.d.ts +0 -2
  142. package/dist/core/llm/types.js +0 -2
  143. package/dist/core/orchestrator/adapters/api-adapter.d.ts +0 -34
  144. package/dist/core/orchestrator/adapters/api-adapter.js +0 -88
  145. package/dist/core/orchestrator/adapters/cli-adapter.d.ts +0 -22
  146. package/dist/core/orchestrator/adapters/cli-adapter.js +0 -69
  147. package/dist/core/orchestrator/adapters/deterministic-adapter.d.ts +0 -35
  148. package/dist/core/orchestrator/adapters/deterministic-adapter.js +0 -75
  149. package/dist/core/orchestrator/adapters/env-whitelist.d.ts +0 -4
  150. package/dist/core/orchestrator/adapters/env-whitelist.js +0 -27
  151. package/dist/core/orchestrator/adapters/output-extractor.d.ts +0 -11
  152. package/dist/core/orchestrator/adapters/output-extractor.js +0 -59
  153. package/dist/core/orchestrator/adapters/process-manager.d.ts +0 -15
  154. package/dist/core/orchestrator/adapters/process-manager.js +0 -26
  155. package/dist/core/orchestrator/adapters/tool-loop.d.ts +0 -22
  156. package/dist/core/orchestrator/adapters/tool-loop.js +0 -66
  157. package/dist/core/orchestrator/agent-registry.d.ts +0 -31
  158. package/dist/core/orchestrator/agent-registry.js +0 -135
  159. package/dist/core/orchestrator/budget-controller.d.ts +0 -19
  160. package/dist/core/orchestrator/budget-controller.js +0 -73
  161. package/dist/core/orchestrator/chain-guard.d.ts +0 -14
  162. package/dist/core/orchestrator/chain-guard.js +0 -23
  163. package/dist/core/orchestrator/circuit-breaker.d.ts +0 -65
  164. package/dist/core/orchestrator/circuit-breaker.js +0 -159
  165. package/dist/core/orchestrator/claude-stream-parser.d.ts +0 -31
  166. package/dist/core/orchestrator/claude-stream-parser.js +0 -99
  167. package/dist/core/orchestrator/config-revisions.d.ts +0 -6
  168. package/dist/core/orchestrator/config-revisions.js +0 -17
  169. package/dist/core/orchestrator/dependency-resolver.d.ts +0 -20
  170. package/dist/core/orchestrator/dependency-resolver.js +0 -78
  171. package/dist/core/orchestrator/governance-gate.d.ts +0 -110
  172. package/dist/core/orchestrator/governance-gate.js +0 -170
  173. package/dist/core/orchestrator/learning-pipeline.d.ts +0 -109
  174. package/dist/core/orchestrator/learning-pipeline.js +0 -249
  175. package/dist/core/orchestrator/loop-detector.d.ts +0 -51
  176. package/dist/core/orchestrator/loop-detector.js +0 -133
  177. package/dist/core/orchestrator/ndjson-logger.d.ts +0 -6
  178. package/dist/core/orchestrator/ndjson-logger.js +0 -18
  179. package/dist/core/orchestrator/permission-relay.d.ts +0 -72
  180. package/dist/core/orchestrator/permission-relay.js +0 -164
  181. package/dist/core/orchestrator/run-manager.d.ts +0 -31
  182. package/dist/core/orchestrator/run-manager.js +0 -178
  183. package/dist/core/orchestrator/scheduler.d.ts +0 -70
  184. package/dist/core/orchestrator/scheduler.js +0 -198
  185. package/dist/core/orchestrator/secret-store.d.ts +0 -57
  186. package/dist/core/orchestrator/secret-store.js +0 -171
  187. package/dist/core/orchestrator/session-manager.d.ts +0 -13
  188. package/dist/core/orchestrator/session-manager.js +0 -66
  189. package/dist/core/orchestrator/task-queue.d.ts +0 -34
  190. package/dist/core/orchestrator/task-queue.js +0 -83
  191. package/dist/core/orchestrator/template-interpolate.d.ts +0 -5
  192. package/dist/core/orchestrator/template-interpolate.js +0 -18
  193. package/dist/core/orchestrator/user-registry.d.ts +0 -47
  194. package/dist/core/orchestrator/user-registry.js +0 -76
  195. package/dist/core/orchestrator/wakeup-queue.d.ts +0 -9
  196. package/dist/core/orchestrator/wakeup-queue.js +0 -45
  197. package/dist/core/orchestrator/workflow-engine.d.ts +0 -47
  198. package/dist/core/orchestrator/workflow-engine.js +0 -204
  199. package/dist/core/security/audit.d.ts +0 -20
  200. package/dist/core/security/audit.js +0 -33
  201. package/dist/core/security/column-validator.d.ts +0 -20
  202. package/dist/core/security/column-validator.js +0 -37
  203. package/dist/core/security/index.d.ts +0 -5
  204. package/dist/core/security/index.js +0 -5
  205. package/dist/core/security/process-env.d.ts +0 -13
  206. package/dist/core/security/process-env.js +0 -49
  207. package/dist/core/security/sanitizer.d.ts +0 -11
  208. package/dist/core/security/sanitizer.js +0 -39
  209. package/dist/core/security/types.d.ts +0 -11
  210. package/dist/core/security/types.js +0 -1
  211. package/dist/core/update/auto-update.d.ts +0 -21
  212. package/dist/core/update/auto-update.js +0 -102
  213. package/dist/core/update/backup-manager.d.ts +0 -7
  214. package/dist/core/update/backup-manager.js +0 -24
  215. package/dist/core/update/index.d.ts +0 -8
  216. package/dist/core/update/index.js +0 -6
  217. package/dist/core/update/migration-hooks.d.ts +0 -11
  218. package/dist/core/update/migration-hooks.js +0 -10
  219. package/dist/core/update/types.d.ts +0 -11
  220. package/dist/core/update/types.js +0 -1
  221. package/dist/core/update/update-checker.d.ts +0 -11
  222. package/dist/core/update/update-checker.js +0 -63
  223. package/dist/core/update/update-manager.d.ts +0 -25
  224. package/dist/core/update/update-manager.js +0 -101
  225. package/dist/core/update/version-utils.d.ts +0 -6
  226. package/dist/core/update/version-utils.js +0 -34
  227. package/dist/gmail-connector-2FVYTQJH.js +0 -6
  228. package/dist/gmail-connector-MNUBRNFM.js +0 -6
  229. package/dist/gmail-connector-PS2VLGNE.js +0 -6
  230. package/dist/gmail-connector-ULSMN6X2.js +0 -6
  231. package/dist/gmail-connector-URRFX6A3.js +0 -6
  232. package/dist/inbound-AFBUPSPG.js +0 -10
  233. package/dist/inbound-AFOHYNUY.js +0 -6
  234. package/dist/inbound-CGIXRXGC.js +0 -8
  235. package/dist/inbound-MCOLRH6U.js +0 -10
  236. package/dist/inbound-SNEMBLGA.js +0 -6
  237. package/dist/inbound-ZJHAYVMF.js +0 -10
  238. package/dist/provider-qqJYv9nv.d.ts +0 -75
  239. package/dist/providers/anthropic/models.d.ts +0 -2
  240. package/dist/providers/anthropic/models.js +0 -29
  241. package/dist/providers/anthropic/provider.d.ts +0 -13
  242. package/dist/providers/anthropic/provider.js +0 -119
  243. package/dist/providers/anthropic/tool-converter.d.ts +0 -10
  244. package/dist/providers/anthropic/tool-converter.js +0 -7
  245. package/dist/providers/ollama/provider.d.ts +0 -17
  246. package/dist/providers/ollama/provider.js +0 -185
  247. package/dist/providers/openai/models.d.ts +0 -2
  248. package/dist/providers/openai/models.js +0 -29
  249. package/dist/providers/openai/provider.d.ts +0 -13
  250. package/dist/providers/openai/provider.js +0 -163
  251. package/dist/providers/openai/tool-converter.d.ts +0 -10
  252. package/dist/providers/openai/tool-converter.js +0 -10
  253. package/dist/shared/constants.d.ts +0 -50
  254. package/dist/shared/constants.js +0 -64
  255. package/dist/shared/index.d.ts +0 -14
  256. package/dist/shared/index.js +0 -14
  257. package/dist/shared/types/agent.d.ts +0 -36
  258. package/dist/shared/types/agent.js +0 -2
  259. package/dist/shared/types/channel.d.ts +0 -70
  260. package/dist/shared/types/channel.js +0 -2
  261. package/dist/shared/types/config.d.ts +0 -111
  262. package/dist/shared/types/config.js +0 -2
  263. package/dist/shared/types/connector.d.ts +0 -77
  264. package/dist/shared/types/connector.js +0 -2
  265. package/dist/shared/types/execution.d.ts +0 -29
  266. package/dist/shared/types/execution.js +0 -2
  267. package/dist/shared/types/provider.d.ts +0 -73
  268. package/dist/shared/types/provider.js +0 -2
  269. package/dist/shared/types/task.d.ts +0 -47
  270. package/dist/shared/types/task.js +0 -2
  271. package/dist/shared/types/workflow.d.ts +0 -39
  272. package/dist/shared/types/workflow.js +0 -2
  273. package/dist/shared/utils.d.ts +0 -6
  274. package/dist/shared/utils.js +0 -13
  275. package/dist/update-check.d.ts +0 -5
  276. 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
- }