@theowlops/boombot 0.0.0-stage → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -3
- package/dist/LICENSE +21 -0
- package/dist/bin/boombot.js +16 -0
- package/dist/cli/api-key.js +123 -0
- package/dist/cli/bin-bun.js +17 -0
- package/dist/cli/bin.js +34 -0
- package/dist/cli/cli/cli-error.js +61 -0
- package/dist/cli/cli/dispatch.js +138 -0
- package/dist/cli/cli/help.js +83 -0
- package/dist/cli/cli/parser.js +89 -0
- package/dist/cli/cli/registry.js +185 -0
- package/dist/cli/cli/spec.js +41 -0
- package/dist/cli/cli/suggest.js +125 -0
- package/dist/cli/cli/version.js +30 -0
- package/dist/cli/cli/vocabulary.js +87 -0
- package/dist/cli/commands/doctor.js +365 -0
- package/dist/cli/commands/gateway.js +290 -0
- package/dist/cli/commands/migrate.js +270 -0
- package/dist/cli/commands/plugin.js +97 -0
- package/dist/cli/commands/setup.js +230 -0
- package/dist/cli/config-file.js +133 -0
- package/dist/cli/master-key.js +78 -0
- package/dist/cli/open-browser.js +59 -0
- package/dist/cli/web-assets.js +58 -0
- package/dist/gateway/auth.js +46 -0
- package/dist/gateway/config-format.js +202 -0
- package/dist/gateway/config.js +427 -0
- package/dist/gateway/context.js +1 -0
- package/dist/gateway/env-file.js +129 -0
- package/dist/gateway/events.js +172 -0
- package/dist/gateway/guard/tagging.js +505 -0
- package/dist/gateway/handlers/index.js +66 -0
- package/dist/gateway/handlers/memory.js +54 -0
- package/dist/gateway/handlers/providers.js +73 -0
- package/dist/gateway/handlers/registry.js +39 -0
- package/dist/gateway/handlers/sessions.js +188 -0
- package/dist/gateway/handlers/system.js +12 -0
- package/dist/gateway/handlers/tasks.js +191 -0
- package/dist/gateway/handlers/turn.js +100 -0
- package/dist/gateway/index.js +126 -0
- package/dist/gateway/main.js +23 -0
- package/dist/gateway/server.js +354 -0
- package/dist/gateway/services/context-limits.js +75 -0
- package/dist/gateway/services/history-normalizer.js +42 -0
- package/dist/gateway/services/image-pipeline.js +56 -0
- package/dist/gateway/services/key-roulette-client.js +43 -0
- package/dist/gateway/services/llm-client.js +593 -0
- package/dist/gateway/services/llm-decoder.js +200 -0
- package/dist/gateway/services/local-fallback.js +135 -0
- package/dist/gateway/services/memory.js +511 -0
- package/dist/gateway/services/persistent-memory.js +196 -0
- package/dist/gateway/services/providers.js +44 -0
- package/dist/gateway/services/tasks.js +237 -0
- package/dist/gateway/services/verification.js +124 -0
- package/dist/gateway/services/vision-payload.js +48 -0
- package/dist/gateway/services.js +257 -0
- package/dist/gateway/session-snapshot.js +19 -0
- package/dist/gateway/sessions.js +701 -0
- package/dist/gateway/static.js +239 -0
- package/dist/gateway/turns/clarify-tool.js +57 -0
- package/dist/gateway/turns/cronjob-tool.js +96 -0
- package/dist/gateway/turns/deferred-tools.js +154 -0
- package/dist/gateway/turns/execute-code-tool.js +84 -0
- package/dist/gateway/turns/file-tool-defs.js +178 -0
- package/dist/gateway/turns/file-tool-ops.js +178 -0
- package/dist/gateway/turns/file-tool-scan.js +182 -0
- package/dist/gateway/turns/file-tool.js +302 -0
- package/dist/gateway/turns/index.js +416 -0
- package/dist/gateway/turns/jev-middleware.js +91 -0
- package/dist/gateway/turns/local-reply.js +156 -0
- package/dist/gateway/turns/mcp-client.js +643 -0
- package/dist/gateway/turns/memory-tool.js +171 -0
- package/dist/gateway/turns/middleware.js +96 -0
- package/dist/gateway/turns/python-core.js +397 -0
- package/dist/gateway/turns/routing/index.js +3 -0
- package/dist/gateway/turns/routing/intent-classifier.js +60 -0
- package/dist/gateway/turns/routing/planner-adapter.js +91 -0
- package/dist/gateway/turns/routing/types.js +1 -0
- package/dist/gateway/turns/runtime-deps.js +228 -0
- package/dist/gateway/turns/self-config-tool.js +277 -0
- package/dist/gateway/turns/service-types.js +11 -0
- package/dist/gateway/turns/service.js +820 -0
- package/dist/gateway/turns/session-adapter.js +158 -0
- package/dist/gateway/turns/session-tool.js +49 -0
- package/dist/gateway/turns/shell-tool.js +190 -0
- package/dist/gateway/turns/skill-tool.js +239 -0
- package/dist/gateway/turns/spillover.js +201 -0
- package/dist/gateway/turns/subagent-tool.js +140 -0
- package/dist/gateway/turns/system-prompt.js +121 -0
- package/dist/gateway/turns/tool-schema.js +90 -0
- package/dist/gateway/turns/turn-utils.js +58 -0
- package/dist/gateway/turns/vision-tool.js +120 -0
- package/dist/gateway/types.js +1 -0
- package/dist/native/win32-x64/boombot-native-host.exe +0 -0
- package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
- package/dist/node_modules/@boombot/channels/handlers.js +109 -0
- package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
- package/dist/node_modules/@boombot/channels/index.js +12 -0
- package/dist/node_modules/@boombot/channels/package.json +9 -0
- package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
- package/dist/node_modules/@boombot/channels/service.js +608 -0
- package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
- package/dist/node_modules/@boombot/channels/tool.js +46 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
- package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
- package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
- package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
- package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
- package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
- package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
- package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
- package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
- package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
- package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
- package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
- package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
- package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
- package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
- package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
- package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
- package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
- package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
- package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
- package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
- package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
- package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
- package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
- package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
- package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
- package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
- package/dist/node_modules/@boombot/core/index.d.ts +9 -0
- package/dist/node_modules/@boombot/core/index.js +9 -0
- package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/jev/index.js +2 -0
- package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
- package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
- package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
- package/dist/node_modules/@boombot/core/jev/types.js +1 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
- package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
- package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
- package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
- package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
- package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
- package/dist/node_modules/@boombot/core/memory/index.js +23 -0
- package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
- package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
- package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
- package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
- package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
- package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
- package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
- package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
- package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
- package/dist/node_modules/@boombot/core/memory/search.js +158 -0
- package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
- package/dist/node_modules/@boombot/core/memory/store.js +289 -0
- package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
- package/dist/node_modules/@boombot/core/memory/types.js +21 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
- package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
- package/dist/node_modules/@boombot/core/package.json +9 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
- package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
- package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
- package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
- package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
- package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/config.js +206 -0
- package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
- package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
- package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
- package/dist/node_modules/@boombot/core/research/factory.js +46 -0
- package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
- package/dist/node_modules/@boombot/core/research/http.js +250 -0
- package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/index.js +10 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
- package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
- package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
- package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
- package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
- package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
- package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
- package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
- package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
- package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
- package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
- package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
- package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
- package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
- package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
- package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
- package/dist/node_modules/@boombot/core/research/tools.js +251 -0
- package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
- package/dist/node_modules/@boombot/core/research/types.js +8 -0
- package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
- package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
- package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
- package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
- package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
- package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
- package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
- package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
- package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
- package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
- package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
- package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
- package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
- package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
- package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
- package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
- package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
- package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
- package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
- package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
- package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
- package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
- package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
- package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
- package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
- package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
- package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
- package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
- package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
- package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
- package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
- package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
- package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
- package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
- package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
- package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
- package/dist/node_modules/@boombot/plugins/index.js +2 -0
- package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
- package/dist/node_modules/@boombot/plugins/installer.js +487 -0
- package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
- package/dist/node_modules/@boombot/plugins/manager.js +243 -0
- package/dist/node_modules/@boombot/plugins/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
- package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
- package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
- package/dist/node_modules/@boombot/protocol/index.js +3 -0
- package/dist/node_modules/@boombot/protocol/package.json +9 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
- package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
- package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
- package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
- package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
- package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
- package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
- package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
- package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
- package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
- package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
- package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
- package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
- package/dist/node_modules/@boombot/sandbox/index.js +13 -0
- package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
- package/dist/node_modules/@boombot/sandbox/native.js +224 -0
- package/dist/node_modules/@boombot/sandbox/package.json +9 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
- package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
- package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
- package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
- package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
- package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
- package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
- package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
- package/dist/node_modules/@boombot/security/index.d.ts +5 -0
- package/dist/node_modules/@boombot/security/index.js +9 -0
- package/dist/node_modules/@boombot/security/package.json +9 -0
- package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
- package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
- package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
- package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
- package/dist/node_modules/@boombot/security/security/approval.js +140 -0
- package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
- package/dist/node_modules/@boombot/security/security/audit.js +70 -0
- package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
- package/dist/node_modules/@boombot/security/security/index.js +12 -0
- package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
- package/dist/node_modules/@boombot/security/security/trust.js +87 -0
- package/dist/package.json +5 -0
- package/dist/proto/agent_core.proto +56 -0
- package/dist/python/agent-core-python/pyproject.toml +40 -0
- package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
- package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
- package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
- package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
- package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
- package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
- package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
- package/dist/python/agent-core-python/uv.lock +2856 -0
- package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
- package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
- package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
- package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
- package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
- package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
- package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
- package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
- package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
- package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
- package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
- package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
- package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
- package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
- package/dist/web/assets/index-BL8bi7Yt.css +1 -0
- package/dist/web/assets/index-CuPR73Tn.js +73 -0
- package/dist/web/favicon.svg +4 -0
- package/dist/web/index.html +26 -0
- package/dist/web/logo.jpg +0 -0
- package/dist/web/logo.png +0 -0
- package/package.json +51 -4
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import { buildAuthHeaders, deepMergeRecords, defaultBaseUrlFor, getProviderProfile, KeyRoulette, kindDefaultProfile, PROVIDER_KINDS, resolveRequestProfile, } from '@boombot/protocol';
|
|
2
|
+
import { normalizeHistoryForProvider } from './history-normalizer.js';
|
|
3
|
+
import { KeyRotatingLlmClient } from './key-roulette-client.js';
|
|
4
|
+
import { createLocalFallbackClient, getLocalFallbackConfig } from './local-fallback.js';
|
|
5
|
+
import { toAnthropicVisionContent, toOpenAiVisionContent } from './vision-payload.js';
|
|
6
|
+
import { decodeAnthropicChunk, decodeOpenAiChunk, isRecord, LlmResolutionError, newAnthropicDecodeState, } from './llm-decoder.js';
|
|
7
|
+
/**
|
|
8
|
+
* Re-exported from `./llm-decoder.js`, where the class is defined so the
|
|
9
|
+
* decoders can throw it without an import cycle. Existing import sites
|
|
10
|
+
* (`import { LlmResolutionError } from '.../llm-client.js'`) keep working.
|
|
11
|
+
*/
|
|
12
|
+
export { LlmResolutionError } from './llm-decoder.js';
|
|
13
|
+
const SETUP_HINT = 'Run `boombot setup` to configure a provider.';
|
|
14
|
+
/**
|
|
15
|
+
* Apply a resolved request profile to request headers and body.
|
|
16
|
+
*
|
|
17
|
+
* - `headers`: merged over the profile's headers, auth headers stay
|
|
18
|
+
* authoritative (a profile can add headers, never swap the credential).
|
|
19
|
+
* - Scalar params (`maxTokens`, `temperature`, `topP`) are mapped to the
|
|
20
|
+
* kind's wire names by the caller; `extraBody` is deep-merged last so it
|
|
21
|
+
* works as an escape hatch for provider-specific knobs.
|
|
22
|
+
*/
|
|
23
|
+
function applyProfileHeaders(authHeaders, profile) {
|
|
24
|
+
return { ...profile.headers, ...authHeaders };
|
|
25
|
+
}
|
|
26
|
+
function applyProfileBody(body, profile) {
|
|
27
|
+
return profile.extraBody === undefined ? body : deepMergeRecords(body, profile.extraBody);
|
|
28
|
+
}
|
|
29
|
+
function parseJsonObject(data, label) {
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = JSON.parse(data);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', `${label} stream sent a malformed event payload.`);
|
|
36
|
+
}
|
|
37
|
+
if (!isRecord(parsed)) {
|
|
38
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', `${label} stream sent a non-object event payload.`);
|
|
39
|
+
}
|
|
40
|
+
return parsed;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Minimal SSE reader over a fetch response body. Yields one entry per
|
|
44
|
+
* `data:` line; `event:` lines set the event name for the following data
|
|
45
|
+
* lines. Comment/heartbeat lines (`: ...`) and `id:`/`retry:` fields are
|
|
46
|
+
* ignored. A blank line resets the event name (dispatch boundary).
|
|
47
|
+
*/
|
|
48
|
+
async function* readSseEvents(body) {
|
|
49
|
+
const reader = body.getReader();
|
|
50
|
+
const decoder = new TextDecoder();
|
|
51
|
+
let buf = '';
|
|
52
|
+
let eventName;
|
|
53
|
+
const handleLine = function* (rawLine) {
|
|
54
|
+
const line = rawLine.replace(/\r$/, '');
|
|
55
|
+
if (line === '') {
|
|
56
|
+
eventName = undefined;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (line.startsWith(':'))
|
|
60
|
+
return;
|
|
61
|
+
if (line.startsWith('event:')) {
|
|
62
|
+
eventName = line.slice('event:'.length).trim();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (line.startsWith('data:')) {
|
|
66
|
+
// Per the SSE spec, a single leading space after the colon is stripped.
|
|
67
|
+
yield { event: eventName, data: line.slice('data:'.length).replace(/^ /, '') };
|
|
68
|
+
}
|
|
69
|
+
// 'id:' and 'retry:' carry nothing we need.
|
|
70
|
+
};
|
|
71
|
+
try {
|
|
72
|
+
for (;;) {
|
|
73
|
+
const { done, value } = await reader.read();
|
|
74
|
+
if (done)
|
|
75
|
+
break;
|
|
76
|
+
buf += decoder.decode(value, { stream: true });
|
|
77
|
+
let nl = buf.indexOf('\n');
|
|
78
|
+
while (nl !== -1) {
|
|
79
|
+
const line = buf.slice(0, nl);
|
|
80
|
+
buf = buf.slice(nl + 1);
|
|
81
|
+
yield* handleLine(line);
|
|
82
|
+
nl = buf.indexOf('\n');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
buf += decoder.decode();
|
|
86
|
+
if (buf.length > 0) {
|
|
87
|
+
for (const line of buf.split('\n')) {
|
|
88
|
+
yield* handleLine(line);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
if (error instanceof Error && error.name === 'AbortError')
|
|
94
|
+
throw error;
|
|
95
|
+
if (error instanceof LlmResolutionError)
|
|
96
|
+
throw error;
|
|
97
|
+
throw new LlmResolutionError('NETWORK_ERROR', `Provider stream failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
reader.releaseLock();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/** `fetch` wrapper that converts transport failures into coded errors. */
|
|
104
|
+
async function postJson(url, headers, body, label, signal, accept = 'text/event-stream') {
|
|
105
|
+
let res;
|
|
106
|
+
try {
|
|
107
|
+
res = await fetch(url, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
headers: { ...headers, 'Content-Type': 'application/json', Accept: accept },
|
|
110
|
+
body: JSON.stringify(body),
|
|
111
|
+
signal,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
// Cancellation must propagate untouched — the turn loop relies on it.
|
|
116
|
+
if (err instanceof Error && err.name === 'AbortError')
|
|
117
|
+
throw err;
|
|
118
|
+
throw new LlmResolutionError('NETWORK_ERROR', `${label} request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
119
|
+
}
|
|
120
|
+
if (!res.ok) {
|
|
121
|
+
throw await httpError(res, label);
|
|
122
|
+
}
|
|
123
|
+
if (res.body === null) {
|
|
124
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', `${label} returned an empty response body.`);
|
|
125
|
+
}
|
|
126
|
+
return res;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Build a coded error from a non-2xx response. The provider's error message
|
|
130
|
+
* is included (truncated); the raw body never is — some proxies reflect
|
|
131
|
+
* request data, which could contain secret material.
|
|
132
|
+
*/
|
|
133
|
+
async function httpError(res, label) {
|
|
134
|
+
let detail = '';
|
|
135
|
+
try {
|
|
136
|
+
const text = await res.text();
|
|
137
|
+
const parsed = JSON.parse(text);
|
|
138
|
+
if (isRecord(parsed)) {
|
|
139
|
+
const nested = isRecord(parsed['error']) ? parsed['error']['message'] : undefined;
|
|
140
|
+
const direct = parsed['message'];
|
|
141
|
+
const msg = typeof nested === 'string' ? nested : typeof direct === 'string' ? direct : '';
|
|
142
|
+
if (msg !== '')
|
|
143
|
+
detail = ` — ${msg.slice(0, 300)}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// Non-JSON error body: status code alone is enough.
|
|
148
|
+
}
|
|
149
|
+
return new LlmResolutionError('HTTP_ERROR', `${label} request failed with HTTP ${res.status}${detail}.`, res.status);
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// OpenAI-compatible chat completions
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
/**
|
|
155
|
+
* Anthropic / Vertex AI require tool names to match /^[a-zA-Z0-9_-]{1,128}$/.
|
|
156
|
+
* BoomBot uses dot-namespaced names like `shell.exec`, `file.read`.
|
|
157
|
+
* We encode `.` → `__dot__` on the wire and decode back after parsing.
|
|
158
|
+
*/
|
|
159
|
+
function sanitizeToolName(name) {
|
|
160
|
+
return name.replace(/\./g, '__dot__');
|
|
161
|
+
}
|
|
162
|
+
export function desanitizeToolName(name) {
|
|
163
|
+
return name.replace(/__dot__/g, '.');
|
|
164
|
+
}
|
|
165
|
+
function toOpenAiMessages(messages) {
|
|
166
|
+
return messages.map((m, idx) => {
|
|
167
|
+
if (m.role === 'tool') {
|
|
168
|
+
return { role: 'tool', tool_call_id: m.toolCallId ?? '', content: m.content };
|
|
169
|
+
}
|
|
170
|
+
if (m.role === 'assistant' && m.toolCalls !== undefined && m.toolCalls.length > 0) {
|
|
171
|
+
return {
|
|
172
|
+
role: 'assistant',
|
|
173
|
+
content: m.content,
|
|
174
|
+
tool_calls: m.toolCalls.map((tc) => ({
|
|
175
|
+
id: tc.id,
|
|
176
|
+
type: 'function',
|
|
177
|
+
function: { name: tc.name, arguments: JSON.stringify(tc.arguments) },
|
|
178
|
+
})),
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
// Mid-conversation system messages: map to user role so proxies (Anthropic/Gemini/9Router) accept them
|
|
182
|
+
if (m.role === 'system' && idx > 0) {
|
|
183
|
+
return {
|
|
184
|
+
role: 'user',
|
|
185
|
+
content: `[System Instruction: ${m.content}]`,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
role: m.role,
|
|
190
|
+
content: m.images?.length ? toOpenAiVisionContent(m.content, m.images) : m.content,
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
function toOpenAiTools(tools) {
|
|
195
|
+
return tools.map((t) => ({
|
|
196
|
+
type: 'function',
|
|
197
|
+
function: { name: t.name, description: t.description, parameters: t.parameters },
|
|
198
|
+
}));
|
|
199
|
+
}
|
|
200
|
+
class OpenAiEmbeddingClient {
|
|
201
|
+
baseUrl;
|
|
202
|
+
model;
|
|
203
|
+
authHeaders;
|
|
204
|
+
constructor(baseUrl, model, authHeaders) {
|
|
205
|
+
this.baseUrl = baseUrl;
|
|
206
|
+
this.model = model;
|
|
207
|
+
this.authHeaders = authHeaders;
|
|
208
|
+
}
|
|
209
|
+
async embed(inputs) {
|
|
210
|
+
if (inputs.length === 0)
|
|
211
|
+
return [];
|
|
212
|
+
const res = await postJson(`${this.baseUrl}/embeddings`, this.authHeaders, { model: this.model, input: inputs }, 'OpenAI-compatible embeddings', AbortSignal.timeout(5_000), 'application/json');
|
|
213
|
+
const payload = await res.json();
|
|
214
|
+
if (!isRecord(payload) || !Array.isArray(payload['data'])) {
|
|
215
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', 'Embedding provider returned an invalid payload.');
|
|
216
|
+
}
|
|
217
|
+
const items = payload['data']
|
|
218
|
+
.map((item) => {
|
|
219
|
+
if (!isRecord(item) || !Array.isArray(item['embedding']) || typeof item['index'] !== 'number')
|
|
220
|
+
return undefined;
|
|
221
|
+
const embedding = item['embedding'];
|
|
222
|
+
if (embedding.length === 0 || !embedding.every((value) => typeof value === 'number' && Number.isFinite(value)))
|
|
223
|
+
return undefined;
|
|
224
|
+
return { index: item['index'], embedding: embedding };
|
|
225
|
+
})
|
|
226
|
+
.filter((item) => item !== undefined)
|
|
227
|
+
.sort((a, b) => a.index - b.index);
|
|
228
|
+
if (items.length !== inputs.length
|
|
229
|
+
|| items.some((item, index) => item.index !== index || item.embedding.length !== items[0]?.embedding.length)) {
|
|
230
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', 'Embedding provider returned invalid vectors.');
|
|
231
|
+
}
|
|
232
|
+
return items.map((item) => item.embedding);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/** Streaming chat client for OpenAI-compatible `POST /chat/completions`. */
|
|
236
|
+
class OpenAiCompatChatClient {
|
|
237
|
+
baseUrl;
|
|
238
|
+
model;
|
|
239
|
+
authHeaders;
|
|
240
|
+
requestUsage;
|
|
241
|
+
profile;
|
|
242
|
+
constructor(baseUrl, model, authHeaders, requestUsage, profile) {
|
|
243
|
+
this.baseUrl = baseUrl;
|
|
244
|
+
this.model = model;
|
|
245
|
+
this.authHeaders = authHeaders;
|
|
246
|
+
this.requestUsage = requestUsage;
|
|
247
|
+
this.profile = profile;
|
|
248
|
+
}
|
|
249
|
+
async *complete(messages, tools, signal) {
|
|
250
|
+
const profile = this.profile;
|
|
251
|
+
const requestBody = applyProfileBody({
|
|
252
|
+
model: this.model,
|
|
253
|
+
messages: toOpenAiMessages(normalizeHistoryForProvider(messages, 'openai')),
|
|
254
|
+
stream: true,
|
|
255
|
+
...(profile.maxTokens !== undefined ? { max_tokens: profile.maxTokens } : {}),
|
|
256
|
+
...(profile.temperature !== undefined ? { temperature: profile.temperature } : {}),
|
|
257
|
+
...(profile.topP !== undefined ? { top_p: profile.topP } : {}),
|
|
258
|
+
...(profile.reasoning?.effort !== undefined ? { reasoning_effort: profile.reasoning.effort } : {}),
|
|
259
|
+
...(this.requestUsage ? { stream_options: { include_usage: true } } : {}),
|
|
260
|
+
...(tools.length > 0 ? { tools: toOpenAiTools(tools), tool_choice: 'auto' } : {}),
|
|
261
|
+
}, profile);
|
|
262
|
+
const res = await postJson(`${this.baseUrl}/chat/completions`, applyProfileHeaders(this.authHeaders, profile), requestBody, 'OpenAI-compatible', signal);
|
|
263
|
+
const body = res.body;
|
|
264
|
+
if (body === null) {
|
|
265
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', 'OpenAI-compatible returned an empty response body.');
|
|
266
|
+
}
|
|
267
|
+
for await (const ev of readSseEvents(body)) {
|
|
268
|
+
if (ev.data === '[DONE]')
|
|
269
|
+
break;
|
|
270
|
+
if (ev.data === '')
|
|
271
|
+
continue; // keepalive: no payload to parse
|
|
272
|
+
const payload = parseJsonObject(ev.data, 'OpenAI-compatible');
|
|
273
|
+
yield* decodeOpenAiChunk(payload);
|
|
274
|
+
}
|
|
275
|
+
yield { done: true };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// Anthropic Messages API
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
function toAnthropicPayload(messages) {
|
|
282
|
+
const systems = [];
|
|
283
|
+
const out = [];
|
|
284
|
+
// Consecutive tool results merge into ONE user message with several
|
|
285
|
+
// `tool_result` blocks (Anthropic shape); a 1:1 mapping would emit a run
|
|
286
|
+
// of single-block user messages instead.
|
|
287
|
+
let pendingToolResults = [];
|
|
288
|
+
const flushToolResults = () => {
|
|
289
|
+
if (pendingToolResults.length > 0) {
|
|
290
|
+
out.push({ role: 'user', content: pendingToolResults });
|
|
291
|
+
pendingToolResults = [];
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
for (const m of messages) {
|
|
295
|
+
if (m.role === 'system') {
|
|
296
|
+
systems.push(m.content);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (m.role === 'tool') {
|
|
300
|
+
pendingToolResults.push({
|
|
301
|
+
type: 'tool_result',
|
|
302
|
+
tool_use_id: m.toolCallId ?? '',
|
|
303
|
+
content: m.content,
|
|
304
|
+
});
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
flushToolResults();
|
|
308
|
+
if (m.role === 'assistant' && m.toolCalls !== undefined && m.toolCalls.length > 0) {
|
|
309
|
+
const content = [];
|
|
310
|
+
if (m.content !== '')
|
|
311
|
+
content.push({ type: 'text', text: m.content });
|
|
312
|
+
for (const tc of m.toolCalls) {
|
|
313
|
+
content.push({ type: 'tool_use', id: tc.id, name: sanitizeToolName(tc.name), input: tc.arguments });
|
|
314
|
+
}
|
|
315
|
+
out.push({ role: 'assistant', content });
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
out.push({
|
|
319
|
+
role: m.role,
|
|
320
|
+
content: m.images?.length ? toAnthropicVisionContent(m.content, m.images) : m.content,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
flushToolResults();
|
|
324
|
+
return { ...(systems.length > 0 ? { system: systems.join('\n\n') } : {}), messages: out };
|
|
325
|
+
}
|
|
326
|
+
function toAnthropicTools(tools) {
|
|
327
|
+
return tools.map((t) => ({ name: sanitizeToolName(t.name), description: t.description, input_schema: t.parameters }));
|
|
328
|
+
}
|
|
329
|
+
/** Streaming chat client for Anthropic `POST /messages` (SSE). */
|
|
330
|
+
class AnthropicChatClient {
|
|
331
|
+
baseUrl;
|
|
332
|
+
model;
|
|
333
|
+
authHeaders;
|
|
334
|
+
profile;
|
|
335
|
+
constructor(baseUrl, model, authHeaders, profile) {
|
|
336
|
+
this.baseUrl = baseUrl;
|
|
337
|
+
this.model = model;
|
|
338
|
+
this.authHeaders = authHeaders;
|
|
339
|
+
this.profile = profile;
|
|
340
|
+
}
|
|
341
|
+
async *complete(messages, tools, signal) {
|
|
342
|
+
const { system, messages: anthropicMessages } = toAnthropicPayload(normalizeHistoryForProvider(messages, 'anthropic'));
|
|
343
|
+
const profile = this.profile;
|
|
344
|
+
// Anthropic requires `max_tokens`; the default comes from the kind's
|
|
345
|
+
// tier-1 profile (no magic constant at the call site).
|
|
346
|
+
const maxTokens = profile.maxTokens ?? kindDefaultProfile('anthropic').maxTokens;
|
|
347
|
+
const requestBody = applyProfileBody({
|
|
348
|
+
model: this.model,
|
|
349
|
+
...(maxTokens !== undefined ? { max_tokens: maxTokens } : {}),
|
|
350
|
+
...(profile.temperature !== undefined ? { temperature: profile.temperature } : {}),
|
|
351
|
+
...(profile.topP !== undefined ? { top_p: profile.topP } : {}),
|
|
352
|
+
...(profile.reasoning?.budgetTokens !== undefined
|
|
353
|
+
? { thinking: { type: 'enabled', budget_tokens: profile.reasoning.budgetTokens } }
|
|
354
|
+
: {}),
|
|
355
|
+
...(system !== undefined ? { system } : {}),
|
|
356
|
+
messages: anthropicMessages,
|
|
357
|
+
stream: true,
|
|
358
|
+
...(tools.length > 0 ? { tools: toAnthropicTools(tools) } : {}),
|
|
359
|
+
}, profile);
|
|
360
|
+
const res = await postJson(`${this.baseUrl}/messages`, applyProfileHeaders(this.authHeaders, profile), requestBody, 'Anthropic', signal);
|
|
361
|
+
const body = res.body;
|
|
362
|
+
if (body === null) {
|
|
363
|
+
throw new LlmResolutionError('PROTOCOL_ERROR', 'Anthropic returned an empty response body.');
|
|
364
|
+
}
|
|
365
|
+
// Content blocks are numbered in start order; the decode state tracks the
|
|
366
|
+
// currently open block across payloads.
|
|
367
|
+
const state = newAnthropicDecodeState();
|
|
368
|
+
let done = false;
|
|
369
|
+
for await (const ev of readSseEvents(body)) {
|
|
370
|
+
if (ev.data === '')
|
|
371
|
+
continue; // keepalive: no payload to parse
|
|
372
|
+
const payload = parseJsonObject(ev.data, 'Anthropic');
|
|
373
|
+
for (const chunk of decodeAnthropicChunk(payload, state)) {
|
|
374
|
+
if (chunk.done === true) {
|
|
375
|
+
// `message_stop`: the decoder's stream-completion sentinel.
|
|
376
|
+
yield chunk;
|
|
377
|
+
done = true;
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
yield chunk;
|
|
381
|
+
}
|
|
382
|
+
if (done)
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
if (!done)
|
|
386
|
+
yield { done: true };
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// ---------------------------------------------------------------------------
|
|
390
|
+
// Resolution: active provider -> working LlmClient
|
|
391
|
+
// ---------------------------------------------------------------------------
|
|
392
|
+
function isKnownKind(kind) {
|
|
393
|
+
return PROVIDER_KINDS.includes(kind);
|
|
394
|
+
}
|
|
395
|
+
function canFailOver(error) {
|
|
396
|
+
return error instanceof LlmResolutionError &&
|
|
397
|
+
(error.code === 'NETWORK_ERROR' ||
|
|
398
|
+
(error.code === 'HTTP_ERROR' &&
|
|
399
|
+
error.status !== undefined &&
|
|
400
|
+
(error.status === 408 || error.status === 429 || error.status >= 500)));
|
|
401
|
+
}
|
|
402
|
+
class FallbackLlmClient {
|
|
403
|
+
clients;
|
|
404
|
+
constructor(clients) {
|
|
405
|
+
this.clients = clients;
|
|
406
|
+
}
|
|
407
|
+
async *complete(messages, tools, signal) {
|
|
408
|
+
for (const [index, resolveClient] of this.clients.entries()) {
|
|
409
|
+
let emitted = false;
|
|
410
|
+
const metadata = [];
|
|
411
|
+
try {
|
|
412
|
+
const client = await resolveClient();
|
|
413
|
+
for await (const chunk of client.complete(messages, tools, signal)) {
|
|
414
|
+
const hasOutput = chunk.delta !== undefined || chunk.toolCallDelta !== undefined;
|
|
415
|
+
if (!emitted && !hasOutput && chunk.done !== true) {
|
|
416
|
+
metadata.push(chunk);
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (!emitted) {
|
|
420
|
+
for (const pending of metadata)
|
|
421
|
+
yield pending;
|
|
422
|
+
metadata.length = 0;
|
|
423
|
+
}
|
|
424
|
+
emitted ||= hasOutput;
|
|
425
|
+
yield chunk;
|
|
426
|
+
}
|
|
427
|
+
for (const pending of metadata)
|
|
428
|
+
yield pending;
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
if (signal?.aborted === true || emitted || !canFailOver(error) || index === this.clients.length - 1) {
|
|
433
|
+
throw error;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async function resolveProviderClient(service, provider) {
|
|
440
|
+
const kind = provider.kind;
|
|
441
|
+
if (!isKnownKind(kind)) {
|
|
442
|
+
throw new LlmResolutionError('UNSUPPORTED_KIND', `Provider '${provider.name}' has unsupported kind '${String(kind)}'. ` +
|
|
443
|
+
`Supported kinds: ${PROVIDER_KINDS.join(', ')}.`);
|
|
444
|
+
}
|
|
445
|
+
// Declarative profile: base URL, auth, wire protocol, and tier-1 defaults
|
|
446
|
+
// all come from the provider's profile, not from switch statements.
|
|
447
|
+
const providerProfile = getProviderProfile(kind);
|
|
448
|
+
if (!providerProfile) {
|
|
449
|
+
throw new LlmResolutionError('UNSUPPORTED_KIND', `Provider '${provider.name}' has no registered profile for kind '${String(kind)}'.`);
|
|
450
|
+
}
|
|
451
|
+
const rawBase = provider.baseUrl ?? defaultBaseUrlFor(kind);
|
|
452
|
+
if (rawBase === null || rawBase === '') {
|
|
453
|
+
throw new LlmResolutionError('BAD_BASE_URL', `Provider '${provider.name}' (kind '${kind}') has no base URL and kind '${kind}' defines no default. ` +
|
|
454
|
+
`Set 'baseUrl' via provider.save.`);
|
|
455
|
+
}
|
|
456
|
+
const endpoint = parseHttpBaseUrl(rawBase, `Provider '${provider.name}' base URL`);
|
|
457
|
+
const model = provider.model ?? provider.models?.[0];
|
|
458
|
+
if (model === undefined || model === '') {
|
|
459
|
+
throw new LlmResolutionError('NO_MODEL', `Provider '${provider.name}' has no default model. Set 'model' via provider.save or ${SETUP_HINT}`);
|
|
460
|
+
}
|
|
461
|
+
if (provider.hasKey === false && providerProfile.keyless !== true) {
|
|
462
|
+
throw new LlmResolutionError('NO_API_KEY', `Provider '${provider.name}' has no API key stored. ${SETUP_HINT}`);
|
|
463
|
+
}
|
|
464
|
+
let apiKeys;
|
|
465
|
+
try {
|
|
466
|
+
if (typeof service.getApiKeys === 'function') {
|
|
467
|
+
apiKeys = await service.getApiKeys(provider.id);
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
const single = await service.getApiKey(provider.id);
|
|
471
|
+
apiKeys = single !== null && single !== undefined ? [single] : [];
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
throw new LlmResolutionError('KEY_DECRYPT_FAILED', `Stored API key for provider '${provider.name}' cannot be decrypted ` +
|
|
476
|
+
`(is BOOMBOT_MASTER_KEY correct?). Re-run \`boombot setup\` to store the key again.`);
|
|
477
|
+
}
|
|
478
|
+
if (apiKeys.length === 0 && providerProfile.keyless !== true) {
|
|
479
|
+
throw new LlmResolutionError('NO_API_KEY', `Provider '${provider.name}' has no API key stored. ${SETUP_HINT}`);
|
|
480
|
+
}
|
|
481
|
+
// Request profile, three tiers: kind defaults < provider.extra < model override.
|
|
482
|
+
const profile = resolveRequestProfile(kind, provider.extra, provider.modelProfiles, model);
|
|
483
|
+
const makeClient = (apiKey) => {
|
|
484
|
+
const headers = buildAuthHeaders(kind, apiKey === '' ? undefined : apiKey);
|
|
485
|
+
// The wire protocol comes from the provider profile: Anthropic Messages vs
|
|
486
|
+
// OpenAI-compatible chat completions. No kind switch.
|
|
487
|
+
return providerProfile.apiMode === 'anthropic_messages'
|
|
488
|
+
? new AnthropicChatClient(endpoint, model, headers, profile)
|
|
489
|
+
: new OpenAiCompatChatClient(endpoint, model, headers, providerProfile.requestUsage === true, profile);
|
|
490
|
+
};
|
|
491
|
+
if (apiKeys.length <= 1) {
|
|
492
|
+
// Single key (or a keyless local endpoint): the old behavior, no rotation.
|
|
493
|
+
return makeClient(apiKeys[0] ?? '');
|
|
494
|
+
}
|
|
495
|
+
// KeyRoulette: rotate the ring on 401/429 and persist the cursor, so a
|
|
496
|
+
// rate-limited or rejected key is skipped without failing the request.
|
|
497
|
+
const roulette = new KeyRoulette({
|
|
498
|
+
keys: apiKeys,
|
|
499
|
+
cursor: provider.keyCursor ?? 0,
|
|
500
|
+
onCursorAdvanced: (cursor) => service.setKeyCursor(provider.id, cursor),
|
|
501
|
+
});
|
|
502
|
+
return new KeyRotatingLlmClient(makeClient, roulette);
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Resolve the loop-facing LLM client for the currently active provider.
|
|
506
|
+
*
|
|
507
|
+
* This is the real implementation behind `ProviderServiceLike.resolveLlm()`
|
|
508
|
+
* (see `agent-worker/src/turns/runtime-deps.ts` and the wiring in
|
|
509
|
+
* `services/providers.ts`). It:
|
|
510
|
+
* 1. reads the active provider from the registry,
|
|
511
|
+
* 2. resolves its base URL (explicit `baseUrl`, else the kind default),
|
|
512
|
+
* 3. picks the chat model (`model`, else the first discovered model),
|
|
513
|
+
* 4. decrypts the API key ring (never logged, never echoed),
|
|
514
|
+
* 5. resolves the 3-tier request profile (kind defaults < provider.extra <
|
|
515
|
+
* per-model override),
|
|
516
|
+
* 6. returns a streaming HTTP client for the kind's wire protocol — wrapped
|
|
517
|
+
* in KeyRoulette rotation when the provider holds more than one key, so a
|
|
518
|
+
* 401/429 on one key retries the request with the next key.
|
|
519
|
+
*
|
|
520
|
+
* Every expected failure mode throws `LlmResolutionError` with a code and
|
|
521
|
+
* an operator-actionable message — never a bare `TypeError`, never a crash.
|
|
522
|
+
*/
|
|
523
|
+
export async function resolveLlmClient(service) {
|
|
524
|
+
const providers = await service.list();
|
|
525
|
+
const active = providers.find((p) => p.active);
|
|
526
|
+
if (active === undefined) {
|
|
527
|
+
throw new LlmResolutionError('NO_ACTIVE_PROVIDER', `No active LLM provider. ${SETUP_HINT}`);
|
|
528
|
+
}
|
|
529
|
+
const primary = await resolveProviderClient(service, active);
|
|
530
|
+
const fallbackIds = (process.env['BOOMBOT_PROVIDER_FALLBACKS'] ?? '')
|
|
531
|
+
.split(',')
|
|
532
|
+
.map((id) => id.trim())
|
|
533
|
+
.filter((id, index, ids) => id !== '' && id !== active.id && ids.indexOf(id) === index);
|
|
534
|
+
const localFallbackUrl = process.env['BOOMBOT_LOCAL_FALLBACK_URL']?.trim();
|
|
535
|
+
if (fallbackIds.length === 0 && !localFallbackUrl)
|
|
536
|
+
return primary;
|
|
537
|
+
const byId = new Map(providers.map((provider) => [provider.id, provider]));
|
|
538
|
+
const clientResolvers = [async () => primary];
|
|
539
|
+
for (const id of fallbackIds) {
|
|
540
|
+
const provider = byId.get(id);
|
|
541
|
+
if (provider === undefined) {
|
|
542
|
+
throw new LlmResolutionError('FALLBACK_NOT_FOUND', `Fallback provider '${id}' was not found.`);
|
|
543
|
+
}
|
|
544
|
+
clientResolvers.push(async () => resolveProviderClient(service, provider));
|
|
545
|
+
}
|
|
546
|
+
if (localFallbackUrl) {
|
|
547
|
+
const localConfig = getLocalFallbackConfig();
|
|
548
|
+
clientResolvers.push(async () => createLocalFallbackClient(localConfig.baseUrl, localConfig.model));
|
|
549
|
+
}
|
|
550
|
+
return new FallbackLlmClient(clientResolvers);
|
|
551
|
+
}
|
|
552
|
+
/** Resolve semantic skill matching without coupling it to the chat model. */
|
|
553
|
+
export async function resolveEmbeddingClient(service) {
|
|
554
|
+
const envKey = process.env['BOOMBOT_SKILL_EMBEDDING_API_KEY']?.trim();
|
|
555
|
+
if (envKey) {
|
|
556
|
+
const endpoint = parseHttpBaseUrl(process.env['BOOMBOT_SKILL_EMBEDDING_BASE_URL']?.trim() || 'https://api.openai.com/v1', 'skill embedding endpoint');
|
|
557
|
+
const model = process.env['BOOMBOT_SKILL_EMBEDDING_MODEL']?.trim() || 'text-embedding-3-small';
|
|
558
|
+
return new OpenAiEmbeddingClient(endpoint, model, { Authorization: `Bearer ${envKey}` });
|
|
559
|
+
}
|
|
560
|
+
const providers = await service.list();
|
|
561
|
+
const active = providers.find((provider) => provider.active);
|
|
562
|
+
if (active === undefined)
|
|
563
|
+
return undefined;
|
|
564
|
+
// Anthropic's Messages API has no compatible embeddings endpoint here.
|
|
565
|
+
const activeProfile = getProviderProfile(active.kind);
|
|
566
|
+
if (activeProfile?.apiMode === 'anthropic_messages')
|
|
567
|
+
return undefined;
|
|
568
|
+
const configuredModel = process.env['BOOMBOT_SKILL_EMBEDDING_MODEL']?.trim();
|
|
569
|
+
const discoveredModel = active.models?.find((model) => /embed/iu.test(model));
|
|
570
|
+
const model = configuredModel || discoveredModel || activeProfile?.defaultEmbeddingModel;
|
|
571
|
+
if (!model)
|
|
572
|
+
return undefined;
|
|
573
|
+
const rawBase = process.env['BOOMBOT_SKILL_EMBEDDING_BASE_URL']?.trim()
|
|
574
|
+
|| active.baseUrl
|
|
575
|
+
|| defaultBaseUrlFor(active.kind);
|
|
576
|
+
if (!rawBase)
|
|
577
|
+
return undefined;
|
|
578
|
+
const apiKey = await service.getApiKey(active.id);
|
|
579
|
+
if (apiKey === null && activeProfile?.keyless !== true)
|
|
580
|
+
return undefined;
|
|
581
|
+
return new OpenAiEmbeddingClient(parseHttpBaseUrl(rawBase, 'skill embedding endpoint'), model, buildAuthHeaders(active.kind, apiKey ?? undefined));
|
|
582
|
+
}
|
|
583
|
+
function parseHttpBaseUrl(raw, label) {
|
|
584
|
+
try {
|
|
585
|
+
const url = new URL(raw.replace(/\/+$/, ''));
|
|
586
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
587
|
+
throw new Error('not http(s)');
|
|
588
|
+
return url.toString().replace(/\/+$/, '');
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
throw new LlmResolutionError('BAD_BASE_URL', `${label} must be a valid HTTP(S) URL.`);
|
|
592
|
+
}
|
|
593
|
+
}
|