@theowlops/boombot 0.0.0-stage → 1.1.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.
- 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 +244 -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,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-page crawl engine (`research.crawl`).
|
|
3
|
+
*
|
|
4
|
+
* The crawl is a BFS over the resolved EXTRACT backend — no separate crawl
|
|
5
|
+
* infrastructure and no async job polling: each page is one extract call,
|
|
6
|
+
* links come from the returned markdown, and the whole run shares the same
|
|
7
|
+
* `sanitizeExtractUrl` choke point as `research.extract`. Free backend is
|
|
8
|
+
* Jina Reader; a configured Firecrawl key upgrades per-page quality without
|
|
9
|
+
* changing this engine.
|
|
10
|
+
*
|
|
11
|
+
* Caps (hard max in the engine, the tool layer advertises the same numbers):
|
|
12
|
+
* depth ≤ 2, maxPages ≤ 10. Only same-site links are followed — the site
|
|
13
|
+
* boundary is the start URL's hostname with an optional leading `www.`
|
|
14
|
+
* stripped on both sides.
|
|
15
|
+
*/
|
|
16
|
+
import type { CrawlOpts, CrawlResult, ExtractProvider } from './types.js';
|
|
17
|
+
export declare const CRAWL_HARD_MAX_PAGES = 10;
|
|
18
|
+
export declare const CRAWL_HARD_MAX_DEPTH = 2;
|
|
19
|
+
/**
|
|
20
|
+
* Extract absolute http(s) links from markdown, resolved against `baseUrl`.
|
|
21
|
+
* Fragment-only links (`#anchor`), non-http schemes and asset URLs are
|
|
22
|
+
* dropped. Duplicates are NOT removed here — the BFS dedupes by normalized
|
|
23
|
+
* URL across the whole run.
|
|
24
|
+
*/
|
|
25
|
+
export declare function extractLinks(markdown: string, baseUrl: string): string[];
|
|
26
|
+
/**
|
|
27
|
+
* Run the BFS crawl over `extract`. Every URL — the start URL included —
|
|
28
|
+
* goes through `sanitizeExtractUrl` before an extract call, so a link found
|
|
29
|
+
* inside a page can never smuggle a non-http(s) scheme or embedded
|
|
30
|
+
* credentials to the backend.
|
|
31
|
+
*
|
|
32
|
+
* Levels are extracted in parallel (`Promise.allSettled`, candidate order
|
|
33
|
+
* preserved); a failed page lands in `failedUrls` and never aborts the run.
|
|
34
|
+
* Abort between fetches returns the partial result with `aborted: true`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function crawlViaExtract(startUrl: string, extract: ExtractProvider, opts?: CrawlOpts): Promise<CrawlResult>;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-page crawl engine (`research.crawl`).
|
|
3
|
+
*
|
|
4
|
+
* The crawl is a BFS over the resolved EXTRACT backend — no separate crawl
|
|
5
|
+
* infrastructure and no async job polling: each page is one extract call,
|
|
6
|
+
* links come from the returned markdown, and the whole run shares the same
|
|
7
|
+
* `sanitizeExtractUrl` choke point as `research.extract`. Free backend is
|
|
8
|
+
* Jina Reader; a configured Firecrawl key upgrades per-page quality without
|
|
9
|
+
* changing this engine.
|
|
10
|
+
*
|
|
11
|
+
* Caps (hard max in the engine, the tool layer advertises the same numbers):
|
|
12
|
+
* depth ≤ 2, maxPages ≤ 10. Only same-site links are followed — the site
|
|
13
|
+
* boundary is the start URL's hostname with an optional leading `www.`
|
|
14
|
+
* stripped on both sides.
|
|
15
|
+
*/
|
|
16
|
+
import { normalizeUrl } from './config.js';
|
|
17
|
+
import { isHttpUrl, sanitizeExtractUrl } from './http.js';
|
|
18
|
+
export const CRAWL_HARD_MAX_PAGES = 10;
|
|
19
|
+
export const CRAWL_HARD_MAX_DEPTH = 2;
|
|
20
|
+
const DEFAULT_MAX_PAGES = 5;
|
|
21
|
+
const DEFAULT_DEPTH = 2;
|
|
22
|
+
const DEFAULT_PER_PAGE_CHARS = 2000;
|
|
23
|
+
/** Never follow links into binary/asset files — extract of those is noise. */
|
|
24
|
+
const NON_PAGE_ASSET_RE = /\.(png|jpe?g|gif|webp|svg|ico|css|js|mjs|json|xml|rss|atom|zip|gz|tar|rar|7z|pdf|docx?|xlsx?|pptx?|mp[34]|webm|woff2?|ttf|eot)$/i;
|
|
25
|
+
const MAX_FAILED_URLS = 10;
|
|
26
|
+
/**
|
|
27
|
+
* Extract absolute http(s) links from markdown, resolved against `baseUrl`.
|
|
28
|
+
* Fragment-only links (`#anchor`), non-http schemes and asset URLs are
|
|
29
|
+
* dropped. Duplicates are NOT removed here — the BFS dedupes by normalized
|
|
30
|
+
* URL across the whole run.
|
|
31
|
+
*/
|
|
32
|
+
export function extractLinks(markdown, baseUrl) {
|
|
33
|
+
let base;
|
|
34
|
+
try {
|
|
35
|
+
base = new URL(baseUrl);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const match of markdown.matchAll(/\[[^\]]*\]\(([^)\s]+)[^)]*\)/g)) {
|
|
42
|
+
const href = match[1];
|
|
43
|
+
if (href === undefined || href === '')
|
|
44
|
+
continue;
|
|
45
|
+
if (href.startsWith('#'))
|
|
46
|
+
continue;
|
|
47
|
+
let resolved;
|
|
48
|
+
try {
|
|
49
|
+
resolved = new URL(href, base);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (!isHttpUrl(resolved.toString()))
|
|
55
|
+
continue;
|
|
56
|
+
if (NON_PAGE_ASSET_RE.test(resolved.pathname))
|
|
57
|
+
continue;
|
|
58
|
+
out.push(resolved.toString());
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/** Site identity: hostname lower-cased with a leading `www.` stripped. */
|
|
63
|
+
function siteKey(url) {
|
|
64
|
+
const host = url.hostname.toLowerCase();
|
|
65
|
+
return host.startsWith('www.') ? host.slice(4) : host;
|
|
66
|
+
}
|
|
67
|
+
function isSameSite(a, b) {
|
|
68
|
+
try {
|
|
69
|
+
return siteKey(new URL(a)) === siteKey(new URL(b));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Run the BFS crawl over `extract`. Every URL — the start URL included —
|
|
77
|
+
* goes through `sanitizeExtractUrl` before an extract call, so a link found
|
|
78
|
+
* inside a page can never smuggle a non-http(s) scheme or embedded
|
|
79
|
+
* credentials to the backend.
|
|
80
|
+
*
|
|
81
|
+
* Levels are extracted in parallel (`Promise.allSettled`, candidate order
|
|
82
|
+
* preserved); a failed page lands in `failedUrls` and never aborts the run.
|
|
83
|
+
* Abort between fetches returns the partial result with `aborted: true`.
|
|
84
|
+
*/
|
|
85
|
+
export async function crawlViaExtract(startUrl, extract, opts = {}) {
|
|
86
|
+
const maxPages = Math.min(Math.max(opts.maxPages ?? DEFAULT_MAX_PAGES, 1), CRAWL_HARD_MAX_PAGES);
|
|
87
|
+
const depthLimit = Math.min(Math.max(opts.depth ?? DEFAULT_DEPTH, 1), CRAWL_HARD_MAX_DEPTH);
|
|
88
|
+
const perPageChars = Math.min(Math.max(opts.perPageChars ?? DEFAULT_PER_PAGE_CHARS, 200), 8000);
|
|
89
|
+
const signal = opts.signal;
|
|
90
|
+
const safeStart = sanitizeExtractUrl(startUrl);
|
|
91
|
+
const pages = [];
|
|
92
|
+
const failedUrls = [];
|
|
93
|
+
const visited = new Set();
|
|
94
|
+
let depthReached = 0;
|
|
95
|
+
let aborted = false;
|
|
96
|
+
const startKey = normalizeUrl(safeStart);
|
|
97
|
+
if (startKey !== undefined)
|
|
98
|
+
visited.add(startKey);
|
|
99
|
+
const extractPage = async (url, depth) => {
|
|
100
|
+
const safeUrl = sanitizeExtractUrl(url);
|
|
101
|
+
const result = await extract.extract(safeUrl, signal);
|
|
102
|
+
const truncated = result.truncated || result.markdown.length > perPageChars;
|
|
103
|
+
return {
|
|
104
|
+
page: {
|
|
105
|
+
url: safeUrl,
|
|
106
|
+
title: result.title,
|
|
107
|
+
markdown: truncated
|
|
108
|
+
? result.markdown.slice(0, perPageChars)
|
|
109
|
+
: result.markdown,
|
|
110
|
+
truncated,
|
|
111
|
+
depth,
|
|
112
|
+
},
|
|
113
|
+
// Link discovery reads the backend's own window (extract's
|
|
114
|
+
// MAX_CHARS), not the compact 2k slice the tool output shows.
|
|
115
|
+
fullMarkdown: result.markdown,
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
// Level 0: the start URL itself. A failure here is the whole crawl failing.
|
|
119
|
+
if (signal?.aborted) {
|
|
120
|
+
return { startUrl: safeStart, pages, depthReached, failedUrls, aborted: true };
|
|
121
|
+
}
|
|
122
|
+
const first = await extractPage(safeStart, 0);
|
|
123
|
+
pages.push(first.page);
|
|
124
|
+
depthReached = 0;
|
|
125
|
+
let frontier = extractLinks(first.fullMarkdown, safeStart);
|
|
126
|
+
// `depth` counts link-follow levels BEYOND the start page:
|
|
127
|
+
// depth 1 = start page only; depth 2 = follow its links once.
|
|
128
|
+
for (let depth = 1; depth < depthLimit; depth += 1) {
|
|
129
|
+
if (pages.length >= maxPages)
|
|
130
|
+
break;
|
|
131
|
+
if (signal?.aborted === true) {
|
|
132
|
+
aborted = true;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
// Candidates for this level: unseen, same-site, non-asset http(s) URLs.
|
|
136
|
+
const candidates = [];
|
|
137
|
+
for (const raw of frontier) {
|
|
138
|
+
if (candidates.length >= maxPages - pages.length)
|
|
139
|
+
break;
|
|
140
|
+
if (!isSameSite(safeStart, raw))
|
|
141
|
+
continue;
|
|
142
|
+
const key = normalizeUrl(raw);
|
|
143
|
+
if (key === undefined || visited.has(key))
|
|
144
|
+
continue;
|
|
145
|
+
visited.add(key);
|
|
146
|
+
candidates.push(raw);
|
|
147
|
+
}
|
|
148
|
+
if (candidates.length === 0)
|
|
149
|
+
break;
|
|
150
|
+
const settled = await Promise.allSettled(candidates.map((url) => extractPage(url, depth)));
|
|
151
|
+
const nextFrontier = [];
|
|
152
|
+
for (let i = 0; i < settled.length; i += 1) {
|
|
153
|
+
const outcome = settled[i];
|
|
154
|
+
const url = candidates[i];
|
|
155
|
+
if (outcome === undefined || url === undefined)
|
|
156
|
+
continue;
|
|
157
|
+
if (outcome.status === 'fulfilled') {
|
|
158
|
+
pages.push(outcome.value.page);
|
|
159
|
+
depthReached = Math.max(depthReached, depth);
|
|
160
|
+
if (pages.length < maxPages) {
|
|
161
|
+
nextFrontier.push(...extractLinks(outcome.value.fullMarkdown, url));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (failedUrls.length < MAX_FAILED_URLS) {
|
|
165
|
+
failedUrls.push(url);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
frontier = nextFrontier;
|
|
169
|
+
}
|
|
170
|
+
if (signal?.aborted === true)
|
|
171
|
+
aborted = true;
|
|
172
|
+
return {
|
|
173
|
+
startUrl: safeStart,
|
|
174
|
+
pages,
|
|
175
|
+
depthReached,
|
|
176
|
+
failedUrls,
|
|
177
|
+
aborted,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composition root helpers: build provider instances from config.
|
|
3
|
+
*
|
|
4
|
+
* Paid providers are only constructed when their key is present; the
|
|
5
|
+
* registry (`resolveSearchProviders` / `resolveExtractProvider`) then
|
|
6
|
+
* orders and selects them. Keys flow in memory only.
|
|
7
|
+
*/
|
|
8
|
+
import type { ExtractProvider, ResearchConfig, ResearchProvider } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Build search providers: paid instances only when their key is configured
|
|
11
|
+
* (tavily, exa, brave), plus the full free chain. Feed the result into
|
|
12
|
+
* `resolveSearchProviders(config, { paid, free })`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSearchProviders(config: ResearchConfig): {
|
|
15
|
+
readonly paid: readonly ResearchProvider[];
|
|
16
|
+
readonly free: readonly ResearchProvider[];
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Build extract providers: firecrawl only when its key is configured, jina
|
|
20
|
+
* always. Feed the result into
|
|
21
|
+
* `resolveExtractProvider(config, { firecrawl, jina })`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createExtractProviders(config: ResearchConfig): {
|
|
24
|
+
readonly firecrawl?: ExtractProvider;
|
|
25
|
+
readonly jina: ExtractProvider;
|
|
26
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composition root helpers: build provider instances from config.
|
|
3
|
+
*
|
|
4
|
+
* Paid providers are only constructed when their key is present; the
|
|
5
|
+
* registry (`resolveSearchProviders` / `resolveExtractProvider`) then
|
|
6
|
+
* orders and selects them. Keys flow in memory only.
|
|
7
|
+
*/
|
|
8
|
+
import { createArxivProvider, createBraveProvider, createDuckDuckGoProvider, createExaProvider, createFirecrawlProvider, createJinaProvider, createOpenAlexProvider, createSemanticScholarProvider, createTavilyProvider, createWikipediaProvider, } from './providers/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Build search providers: paid instances only when their key is configured
|
|
11
|
+
* (tavily, exa, brave), plus the full free chain. Feed the result into
|
|
12
|
+
* `resolveSearchProviders(config, { paid, free })`.
|
|
13
|
+
*/
|
|
14
|
+
export function createSearchProviders(config) {
|
|
15
|
+
const paid = [];
|
|
16
|
+
if (config.tavilyApiKey !== undefined) {
|
|
17
|
+
paid.push(createTavilyProvider({ apiKey: config.tavilyApiKey }));
|
|
18
|
+
}
|
|
19
|
+
if (config.exaApiKey !== undefined) {
|
|
20
|
+
paid.push(createExaProvider({ apiKey: config.exaApiKey }));
|
|
21
|
+
}
|
|
22
|
+
if (config.braveApiKey !== undefined) {
|
|
23
|
+
paid.push(createBraveProvider({ apiKey: config.braveApiKey }));
|
|
24
|
+
}
|
|
25
|
+
const free = [
|
|
26
|
+
createWikipediaProvider(),
|
|
27
|
+
createDuckDuckGoProvider(),
|
|
28
|
+
createArxivProvider(),
|
|
29
|
+
createOpenAlexProvider(),
|
|
30
|
+
createSemanticScholarProvider(),
|
|
31
|
+
];
|
|
32
|
+
return { paid, free };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build extract providers: firecrawl only when its key is configured, jina
|
|
36
|
+
* always. Feed the result into
|
|
37
|
+
* `resolveExtractProvider(config, { firecrawl, jina })`.
|
|
38
|
+
*/
|
|
39
|
+
export function createExtractProviders(config) {
|
|
40
|
+
return {
|
|
41
|
+
firecrawl: config.firecrawlApiKey !== undefined
|
|
42
|
+
? createFirecrawlProvider({ apiKey: config.firecrawlApiKey })
|
|
43
|
+
: undefined,
|
|
44
|
+
jina: createJinaProvider(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP helpers for all research providers.
|
|
3
|
+
*
|
|
4
|
+
* Philosophy: hand-rolled on the global `fetch` (Node 22), zero runtime
|
|
5
|
+
* dependencies, no vendor SDKs. Every network failure surfaces as a typed
|
|
6
|
+
* {@link ResearchError} so callers (and `withRetry`) can branch on `code`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const DEFAULT_USER_AGENT = "BoomBotResearch/1.0 (+https://github.com/TheBoomBot/BoomBot)";
|
|
9
|
+
export declare const DEFAULT_TIMEOUT_MS = 10000;
|
|
10
|
+
/** Machine-readable failure codes. Additive-first: new codes are added, never renamed. */
|
|
11
|
+
export type ResearchErrorCode = 'TIMEOUT' | 'ABORTED' | 'HTTP_4XX' | 'HTTP_5XX' | 'NETWORK_ERROR' | 'PARSE_ERROR' | 'INVALID_URL' | 'RESPONSE_TOO_LARGE';
|
|
12
|
+
export declare class ResearchError extends Error {
|
|
13
|
+
readonly code: ResearchErrorCode;
|
|
14
|
+
constructor(code: ResearchErrorCode, message: string, options?: ErrorOptions);
|
|
15
|
+
}
|
|
16
|
+
export interface FetchOptions {
|
|
17
|
+
readonly signal?: AbortSignal;
|
|
18
|
+
readonly headers?: Record<string, string>;
|
|
19
|
+
/** Per-request timeout in ms. Default {@link DEFAULT_TIMEOUT_MS}. */
|
|
20
|
+
readonly timeoutMs?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Hard cap on response body bytes. Default {@link DEFAULT_MAX_RESPONSE_BYTES}.
|
|
23
|
+
* A malicious or misbehaving server must not exhaust gateway memory with
|
|
24
|
+
* one unbounded response.
|
|
25
|
+
*/
|
|
26
|
+
readonly maxBytes?: number;
|
|
27
|
+
}
|
|
28
|
+
/** Default hard cap for a single response body: 5 MiB. */
|
|
29
|
+
export declare const DEFAULT_MAX_RESPONSE_BYTES = 5242880;
|
|
30
|
+
/** Max length accepted for a user-supplied extract URL. */
|
|
31
|
+
export declare const MAX_EXTRACT_URL_LENGTH = 2048;
|
|
32
|
+
export interface RetryOptions {
|
|
33
|
+
/** Number of retries after the first attempt. Default 1. */
|
|
34
|
+
readonly retries?: number;
|
|
35
|
+
}
|
|
36
|
+
/** Truncation marker appended by {@link truncate}. */
|
|
37
|
+
export declare const TRUNCATED_MARKER = " [truncated]";
|
|
38
|
+
/**
|
|
39
|
+
* Validate and sanitize a user-supplied URL before it is handed to an
|
|
40
|
+
* extract backend (`research.extract`, `research.deep`).
|
|
41
|
+
*
|
|
42
|
+
* - Must parse and use `http:`/`https:` — `file:`, `data:`, `javascript:`
|
|
43
|
+
* and friends are rejected outright.
|
|
44
|
+
* - Embedded credentials (`https://user:pass@host/…`) are STRIPPED: the
|
|
45
|
+
* URL is forwarded to a third-party reader (Jina/Firecrawl), and a
|
|
46
|
+
* secret in the userinfo would leak to that third party verbatim.
|
|
47
|
+
* - Length cap against parse/log abuse.
|
|
48
|
+
*
|
|
49
|
+
* Returns the sanitized URL string. Throws {@link ResearchError} with
|
|
50
|
+
* code `INVALID_URL` when the input is not an acceptable extract target.
|
|
51
|
+
*/
|
|
52
|
+
export declare function sanitizeExtractUrl(rawUrl: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Non-throwing check used for pre-filtering candidate URLs.
|
|
55
|
+
* Full validation (with sanitization) still happens in
|
|
56
|
+
* {@link sanitizeExtractUrl} at the extract choke point.
|
|
57
|
+
*/
|
|
58
|
+
export declare function isHttpUrl(value: string): boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Fetch `url` and return the body as text.
|
|
61
|
+
* Throws {@link ResearchError} with code `TIMEOUT` / `ABORTED` /
|
|
62
|
+
* `HTTP_4XX` / `HTTP_5XX` / `NETWORK_ERROR` / `RESPONSE_TOO_LARGE`.
|
|
63
|
+
* Never logs request details.
|
|
64
|
+
*/
|
|
65
|
+
export declare function fetchText(url: string, opts?: FetchOptions): Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Fetch `url` and parse the body as JSON.
|
|
68
|
+
* Throws {@link ResearchError} with code `PARSE_ERROR` when the body is not
|
|
69
|
+
* valid JSON, plus every error {@link fetchText} can throw.
|
|
70
|
+
*/
|
|
71
|
+
export declare function fetchJson(url: string, opts?: FetchOptions): Promise<unknown>;
|
|
72
|
+
/**
|
|
73
|
+
* POST `body` as JSON to `url` and parse the JSON response.
|
|
74
|
+
* Throws the same {@link ResearchError} codes as {@link fetchText} /
|
|
75
|
+
* {@link fetchJson}. Request bodies are never logged.
|
|
76
|
+
*/
|
|
77
|
+
export declare function postJson(url: string, body: unknown, opts?: FetchOptions): Promise<unknown>;
|
|
78
|
+
/**
|
|
79
|
+
* Run `fn`, retrying once (default) when it fails with a transient
|
|
80
|
+
* {@link ResearchError} (`NETWORK_ERROR` — see {@link RETRYABLE}). `TIMEOUT`,
|
|
81
|
+
* `HTTP_4XX`, `ABORTED`, `PARSE_ERROR` and non-`ResearchError` failures are
|
|
82
|
+
* rethrown immediately: retrying them cannot help, and a retried timeout
|
|
83
|
+
* just doubles the caller's wait.
|
|
84
|
+
*/
|
|
85
|
+
export declare function withRetry<T>(fn: () => Promise<T>, opts?: RetryOptions): Promise<T>;
|
|
86
|
+
/** Cut `text` to `maxChars` and append {@link TRUNCATED_MARKER}. */
|
|
87
|
+
export declare function truncate(text: string, maxChars: number): string;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP helpers for all research providers.
|
|
3
|
+
*
|
|
4
|
+
* Philosophy: hand-rolled on the global `fetch` (Node 22), zero runtime
|
|
5
|
+
* dependencies, no vendor SDKs. Every network failure surfaces as a typed
|
|
6
|
+
* {@link ResearchError} so callers (and `withRetry`) can branch on `code`.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_USER_AGENT = 'BoomBotResearch/1.0 (+https://github.com/TheBoomBot/BoomBot)';
|
|
9
|
+
export const DEFAULT_TIMEOUT_MS = 10_000;
|
|
10
|
+
export class ResearchError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message, options) {
|
|
13
|
+
super(message, options);
|
|
14
|
+
this.name = 'ResearchError';
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Default hard cap for a single response body: 5 MiB. */
|
|
19
|
+
export const DEFAULT_MAX_RESPONSE_BYTES = 5_242_880;
|
|
20
|
+
/** Max length accepted for a user-supplied extract URL. */
|
|
21
|
+
export const MAX_EXTRACT_URL_LENGTH = 2048;
|
|
22
|
+
/**
|
|
23
|
+
* Errors worth one more attempt.
|
|
24
|
+
*
|
|
25
|
+
* `TIMEOUT` is deliberately NOT here. Retrying a timeout doubles the wait for
|
|
26
|
+
* the caller — 10s became 20s, 15s became 30s — and the retry runs while the
|
|
27
|
+
* user is sitting on a tool call, which is where latency is felt most. A
|
|
28
|
+
* timeout says the engine is slow or unresponsive, and a second identical
|
|
29
|
+
* request rarely changes that; `NETWORK_ERROR` is the genuinely transient
|
|
30
|
+
* case a retry is for.
|
|
31
|
+
*/
|
|
32
|
+
const RETRYABLE = new Set(['NETWORK_ERROR']);
|
|
33
|
+
/** Truncation marker appended by {@link truncate}. */
|
|
34
|
+
export const TRUNCATED_MARKER = ' [truncated]';
|
|
35
|
+
function toResearchError(err, url) {
|
|
36
|
+
if (err instanceof DOMException && err.name === 'TimeoutError') {
|
|
37
|
+
return new ResearchError('TIMEOUT', `Request to ${url} timed out`);
|
|
38
|
+
}
|
|
39
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
40
|
+
return new ResearchError('ABORTED', `Request to ${url} was aborted`);
|
|
41
|
+
}
|
|
42
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
43
|
+
return new ResearchError('NETWORK_ERROR', `Network error fetching ${url}: ${detail}`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Read the response body as text with a hard byte cap.
|
|
47
|
+
*
|
|
48
|
+
* Streams the body and aborts the moment it exceeds `maxBytes` — the
|
|
49
|
+
* unbounded `response.text()` it replaces would buffer an arbitrarily
|
|
50
|
+
* large body into memory first (memory-DoS via a hostile server).
|
|
51
|
+
*/
|
|
52
|
+
async function readCappedText(response, url, maxBytes) {
|
|
53
|
+
const body = response.body;
|
|
54
|
+
if (body === null)
|
|
55
|
+
return '';
|
|
56
|
+
const reader = body.getReader();
|
|
57
|
+
const chunks = [];
|
|
58
|
+
let bytes = 0;
|
|
59
|
+
for (;;) {
|
|
60
|
+
let read;
|
|
61
|
+
try {
|
|
62
|
+
read = await reader.read();
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
throw toResearchError(err, url);
|
|
66
|
+
}
|
|
67
|
+
if (read.done)
|
|
68
|
+
break;
|
|
69
|
+
bytes += read.value.byteLength;
|
|
70
|
+
if (bytes > maxBytes) {
|
|
71
|
+
await reader.cancel().catch(() => undefined);
|
|
72
|
+
throw new ResearchError('RESPONSE_TOO_LARGE', `Response from ${url} exceeds ${maxBytes} bytes`);
|
|
73
|
+
}
|
|
74
|
+
chunks.push(read.value);
|
|
75
|
+
}
|
|
76
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Validate and sanitize a user-supplied URL before it is handed to an
|
|
80
|
+
* extract backend (`research.extract`, `research.deep`).
|
|
81
|
+
*
|
|
82
|
+
* - Must parse and use `http:`/`https:` — `file:`, `data:`, `javascript:`
|
|
83
|
+
* and friends are rejected outright.
|
|
84
|
+
* - Embedded credentials (`https://user:pass@host/…`) are STRIPPED: the
|
|
85
|
+
* URL is forwarded to a third-party reader (Jina/Firecrawl), and a
|
|
86
|
+
* secret in the userinfo would leak to that third party verbatim.
|
|
87
|
+
* - Length cap against parse/log abuse.
|
|
88
|
+
*
|
|
89
|
+
* Returns the sanitized URL string. Throws {@link ResearchError} with
|
|
90
|
+
* code `INVALID_URL` when the input is not an acceptable extract target.
|
|
91
|
+
*/
|
|
92
|
+
export function sanitizeExtractUrl(rawUrl) {
|
|
93
|
+
const trimmed = rawUrl.trim();
|
|
94
|
+
if (trimmed === '') {
|
|
95
|
+
throw new ResearchError('INVALID_URL', 'Extract URL must not be empty.');
|
|
96
|
+
}
|
|
97
|
+
if (trimmed.length > MAX_EXTRACT_URL_LENGTH) {
|
|
98
|
+
throw new ResearchError('INVALID_URL', `Extract URL exceeds ${MAX_EXTRACT_URL_LENGTH} characters.`);
|
|
99
|
+
}
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = new URL(trimmed);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
throw new ResearchError('INVALID_URL', 'Extract URL is not a valid URL.');
|
|
106
|
+
}
|
|
107
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
108
|
+
throw new ResearchError('INVALID_URL', `Extract URL must use http(s), got '${parsed.protocol}'.`);
|
|
109
|
+
}
|
|
110
|
+
// Never forward embedded credentials to a third-party extract service.
|
|
111
|
+
// Only rebuild the URL when credentials were actually present, so
|
|
112
|
+
// credential-free URLs pass through byte-identical (no normalization
|
|
113
|
+
// side effects for existing callers).
|
|
114
|
+
if (parsed.username !== '' || parsed.password !== '') {
|
|
115
|
+
parsed.username = '';
|
|
116
|
+
parsed.password = '';
|
|
117
|
+
return parsed.toString();
|
|
118
|
+
}
|
|
119
|
+
return trimmed;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Non-throwing check used for pre-filtering candidate URLs.
|
|
123
|
+
* Full validation (with sanitization) still happens in
|
|
124
|
+
* {@link sanitizeExtractUrl} at the extract choke point.
|
|
125
|
+
*/
|
|
126
|
+
export function isHttpUrl(value) {
|
|
127
|
+
try {
|
|
128
|
+
const parsed = new URL(value.trim());
|
|
129
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Fetch `url` and return the body as text.
|
|
137
|
+
* Throws {@link ResearchError} with code `TIMEOUT` / `ABORTED` /
|
|
138
|
+
* `HTTP_4XX` / `HTTP_5XX` / `NETWORK_ERROR` / `RESPONSE_TOO_LARGE`.
|
|
139
|
+
* Never logs request details.
|
|
140
|
+
*/
|
|
141
|
+
export async function fetchText(url, opts = {}) {
|
|
142
|
+
const timeoutSignal = AbortSignal.timeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
143
|
+
const signal = opts.signal !== undefined
|
|
144
|
+
? AbortSignal.any([opts.signal, timeoutSignal])
|
|
145
|
+
: timeoutSignal;
|
|
146
|
+
let response;
|
|
147
|
+
try {
|
|
148
|
+
response = await fetch(url, {
|
|
149
|
+
signal,
|
|
150
|
+
headers: { 'User-Agent': DEFAULT_USER_AGENT, ...opts.headers },
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
throw toResearchError(err, url);
|
|
155
|
+
}
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
const code = response.status >= 400 && response.status < 500 ? 'HTTP_4XX' : 'HTTP_5XX';
|
|
158
|
+
throw new ResearchError(code, `HTTP ${response.status} from ${url}`);
|
|
159
|
+
}
|
|
160
|
+
// Capped streaming read — a hostile server cannot force an unbounded
|
|
161
|
+
// buffer into gateway memory. Read errors surface via toResearchError
|
|
162
|
+
// inside readCappedText; RESPONSE_TOO_LARGE propagates unchanged.
|
|
163
|
+
return readCappedText(response, url, opts.maxBytes ?? DEFAULT_MAX_RESPONSE_BYTES);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Fetch `url` and parse the body as JSON.
|
|
167
|
+
* Throws {@link ResearchError} with code `PARSE_ERROR` when the body is not
|
|
168
|
+
* valid JSON, plus every error {@link fetchText} can throw.
|
|
169
|
+
*/
|
|
170
|
+
export async function fetchJson(url, opts = {}) {
|
|
171
|
+
const text = await fetchText(url, opts);
|
|
172
|
+
try {
|
|
173
|
+
return JSON.parse(text);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
177
|
+
throw new ResearchError('PARSE_ERROR', `Invalid JSON from ${url}: ${detail}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* POST `body` as JSON to `url` and parse the JSON response.
|
|
182
|
+
* Throws the same {@link ResearchError} codes as {@link fetchText} /
|
|
183
|
+
* {@link fetchJson}. Request bodies are never logged.
|
|
184
|
+
*/
|
|
185
|
+
export async function postJson(url, body, opts = {}) {
|
|
186
|
+
const timeoutSignal = AbortSignal.timeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
187
|
+
const signal = opts.signal !== undefined
|
|
188
|
+
? AbortSignal.any([opts.signal, timeoutSignal])
|
|
189
|
+
: timeoutSignal;
|
|
190
|
+
let response;
|
|
191
|
+
try {
|
|
192
|
+
response = await fetch(url, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
signal,
|
|
195
|
+
headers: {
|
|
196
|
+
'User-Agent': DEFAULT_USER_AGENT,
|
|
197
|
+
'Content-Type': 'application/json',
|
|
198
|
+
...opts.headers,
|
|
199
|
+
},
|
|
200
|
+
body: JSON.stringify(body),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
catch (err) {
|
|
204
|
+
throw toResearchError(err, url);
|
|
205
|
+
}
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
const code = response.status >= 400 && response.status < 500 ? 'HTTP_4XX' : 'HTTP_5XX';
|
|
208
|
+
throw new ResearchError(code, `HTTP ${response.status} from ${url}`);
|
|
209
|
+
}
|
|
210
|
+
const text = await readCappedText(response, url, opts.maxBytes ?? DEFAULT_MAX_RESPONSE_BYTES);
|
|
211
|
+
try {
|
|
212
|
+
return JSON.parse(text);
|
|
213
|
+
}
|
|
214
|
+
catch (err) {
|
|
215
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
216
|
+
throw new ResearchError('PARSE_ERROR', `Invalid JSON from ${url}: ${detail}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Run `fn`, retrying once (default) when it fails with a transient
|
|
221
|
+
* {@link ResearchError} (`NETWORK_ERROR` — see {@link RETRYABLE}). `TIMEOUT`,
|
|
222
|
+
* `HTTP_4XX`, `ABORTED`, `PARSE_ERROR` and non-`ResearchError` failures are
|
|
223
|
+
* rethrown immediately: retrying them cannot help, and a retried timeout
|
|
224
|
+
* just doubles the caller's wait.
|
|
225
|
+
*/
|
|
226
|
+
export async function withRetry(fn, opts = {}) {
|
|
227
|
+
const retries = opts.retries ?? 1;
|
|
228
|
+
let lastError;
|
|
229
|
+
for (let attempt = 0; attempt <= retries; attempt += 1) {
|
|
230
|
+
try {
|
|
231
|
+
return await fn();
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
lastError = err;
|
|
235
|
+
if (attempt >= retries)
|
|
236
|
+
break;
|
|
237
|
+
if (!(err instanceof ResearchError) || !RETRYABLE.has(err.code)) {
|
|
238
|
+
throw err;
|
|
239
|
+
}
|
|
240
|
+
// else: fall through to the next attempt
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
throw lastError;
|
|
244
|
+
}
|
|
245
|
+
/** Cut `text` to `maxChars` and append {@link TRUNCATED_MARKER}. */
|
|
246
|
+
export function truncate(text, maxChars) {
|
|
247
|
+
if (text.length <= maxChars)
|
|
248
|
+
return text;
|
|
249
|
+
return text.slice(0, maxChars) + TRUNCATED_MARKER;
|
|
250
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** `@boombot/core` — free-first web research for BoomBot. */
|
|
2
|
+
export type { CrawlOpts, CrawlPage, CrawlResult, ExtractOpts, ExtractResult, ExtractProvider, ResearchConfig, ResearchProvider, SearchOpts, SearchResult, } from './types.js';
|
|
3
|
+
export { dedupeByUrl, describeResearchConfig, isConfigured, loadResearchConfig, normalizeUrl, resolveExtractProvider, resolveSearchProviders, } from './config.js';
|
|
4
|
+
export { CRAWL_HARD_MAX_DEPTH, CRAWL_HARD_MAX_PAGES, crawlViaExtract, extractLinks, } from './crawl.js';
|
|
5
|
+
export { DEFAULT_MAX_RESPONSE_BYTES, DEFAULT_TIMEOUT_MS, DEFAULT_USER_AGENT, fetchJson, fetchText, isHttpUrl, MAX_EXTRACT_URL_LENGTH, postJson, ResearchError, sanitizeExtractUrl, TRUNCATED_MARKER, truncate, withRetry, } from './http.js';
|
|
6
|
+
export type { FetchOptions, ResearchErrorCode, RetryOptions } from './http.js';
|
|
7
|
+
export { createArxivProvider, createBraveProvider, createDuckDuckGoProvider, createExaProvider, createFirecrawlProvider, createJinaProvider, createOpenAlexProvider, createSemanticScholarProvider, createTavilyProvider, createWikipediaProvider, } from './providers/index.js';
|
|
8
|
+
export type { BraveProviderOptions, ExaProviderOptions, FirecrawlProviderOptions, OpenAlexProviderOptions, TavilyProviderOptions, WikipediaProviderOptions, } from './providers/index.js';
|
|
9
|
+
export { academicSearch, ResearchOrchestrator, searchChain, } from './orchestrator.js';
|
|
10
|
+
export type { DeepResearchOptions, DeepResearchResult, OrchestratorDeps, SourceAttribution, } from './orchestrator.js';
|
|
11
|
+
export { createExtractProviders, createSearchProviders } from './factory.js';
|
|
12
|
+
export { DOCX_MIME, DocumentParseError, PDF_MIME, detectDocumentKindFromUrl, extractDocument, parseDocument, sanitizeExtractedText, sniffDocumentType, } from './parse/index.js';
|
|
13
|
+
export type { DocxExtractedText, DocumentParseErrorCode, ParsedDocument, PdfCMap, PdfExtractedText, SupportedDocumentKind, } from './parse/index.js';
|
|
14
|
+
export { registerResearchTools } from './wiring.js';
|
|
15
|
+
export type { ResearchToolRegistry } from './wiring.js';
|
|
16
|
+
export { createResearchToolExecutor, RESEARCH_ACADEMIC_TOOL, RESEARCH_CRAWL_TOOL, RESEARCH_DEEP_TOOL, RESEARCH_EXTRACT_TOOL, RESEARCH_SEARCH_TOOL, researchToolDefinitions, } from './tools.js';
|
|
17
|
+
export type { ResearchToolExecutorDeps } from './tools.js';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** `@boombot/core` — free-first web research for BoomBot. */
|
|
2
|
+
export { dedupeByUrl, describeResearchConfig, isConfigured, loadResearchConfig, normalizeUrl, resolveExtractProvider, resolveSearchProviders, } from './config.js';
|
|
3
|
+
export { CRAWL_HARD_MAX_DEPTH, CRAWL_HARD_MAX_PAGES, crawlViaExtract, extractLinks, } from './crawl.js';
|
|
4
|
+
export { DEFAULT_MAX_RESPONSE_BYTES, DEFAULT_TIMEOUT_MS, DEFAULT_USER_AGENT, fetchJson, fetchText, isHttpUrl, MAX_EXTRACT_URL_LENGTH, postJson, ResearchError, sanitizeExtractUrl, TRUNCATED_MARKER, truncate, withRetry, } from './http.js';
|
|
5
|
+
export { createArxivProvider, createBraveProvider, createDuckDuckGoProvider, createExaProvider, createFirecrawlProvider, createJinaProvider, createOpenAlexProvider, createSemanticScholarProvider, createTavilyProvider, createWikipediaProvider, } from './providers/index.js';
|
|
6
|
+
export { academicSearch, ResearchOrchestrator, searchChain, } from './orchestrator.js';
|
|
7
|
+
export { createExtractProviders, createSearchProviders } from './factory.js';
|
|
8
|
+
export { DOCX_MIME, DocumentParseError, PDF_MIME, detectDocumentKindFromUrl, extractDocument, parseDocument, sanitizeExtractedText, sniffDocumentType, } from './parse/index.js';
|
|
9
|
+
export { registerResearchTools } from './wiring.js';
|
|
10
|
+
export { createResearchToolExecutor, RESEARCH_ACADEMIC_TOOL, RESEARCH_CRAWL_TOOL, RESEARCH_DEEP_TOOL, RESEARCH_EXTRACT_TOOL, RESEARCH_SEARCH_TOOL, researchToolDefinitions, } from './tools.js';
|