@poolzin/pool-bot 2026.1.39 → 2026.2.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/assets/chrome-extension/README.md +3 -3
- package/assets/chrome-extension/background.js +5 -5
- package/assets/chrome-extension/manifest.json +3 -3
- package/assets/chrome-extension/options.html +4 -4
- package/assets/chrome-extension/options.js +1 -1
- package/dist/acp/client.js +3 -3
- package/dist/acp/types.js +1 -1
- package/dist/agents/agent-paths.js +3 -3
- package/dist/agents/auth-profiles/paths.js +3 -3
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +10 -12
- package/dist/agents/cli-runner.js +2 -2
- package/dist/agents/cloudflare-ai-gateway.js +31 -0
- package/dist/agents/compaction.js +16 -2
- package/dist/agents/context-window-guard.js +13 -10
- package/dist/agents/context.js +4 -4
- package/dist/agents/docs-path.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/minimax-vlm.js +1 -1
- package/dist/agents/model-auth.js +12 -1
- package/dist/agents/model-catalog.js +4 -4
- package/dist/agents/model-selection.js +31 -4
- package/dist/agents/models-config.js +3 -3
- package/dist/agents/models-config.providers.js +147 -39
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers/openai.js +1 -1
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +9 -8
- package/dist/agents/pi-embedded-runner/model.js +63 -4
- package/dist/agents/pi-embedded-runner/run/attempt.js +27 -17
- package/dist/agents/pi-embedded-runner/run.js +203 -50
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-runner/tool-result-truncation.js +275 -0
- package/dist/agents/pi-embedded-runner/utils.js +1 -1
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-model-discovery.js +10 -0
- package/dist/agents/pi-tool-definition-adapter.js +50 -9
- package/dist/agents/pi-tools.before-tool-call.js +67 -0
- package/dist/agents/pi-tools.js +20 -10
- package/dist/agents/pi-tools.read.js +2 -2
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-file-repair.js +83 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/session-transcript-repair.js +68 -0
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills/frontmatter.js +1 -1
- package/dist/agents/skills/workspace.js +2 -2
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/system-prompt.js +28 -4
- package/dist/agents/together-models.js +127 -0
- package/dist/agents/tool-images.js +1 -1
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +25 -1
- package/dist/agents/tools/browser-tool.js +3 -3
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +2 -2
- package/dist/agents/tools/memory-tool.js +93 -5
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/commands-registry.data.js +1 -1
- package/dist/auto-reply/envelope.js +50 -72
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +3 -2
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/commands-session.js +2 -2
- package/dist/auto-reply/reply/get-reply-run.js +16 -5
- package/dist/auto-reply/reply/groups.js +1 -1
- package/dist/auto-reply/reply/inbound-context.js +9 -1
- package/dist/auto-reply/reply/inbound-meta.js +130 -0
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/reply/untrusted-context.js +15 -0
- package/dist/auto-reply/status.js +1 -1
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +51 -8
- package/dist/browser/config.js +2 -11
- package/dist/browser/extension-relay.js +104 -43
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server-context.js +2 -2
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui.js +3 -3
- package/dist/channels/plugins/catalog.js +2 -2
- package/dist/channels/plugins/onboarding/imessage.js +1 -1
- package/dist/channels/plugins/onboarding/signal.js +1 -1
- package/dist/channels/plugins/onboarding/slack.js +4 -4
- package/dist/channels/plugins/onboarding/whatsapp.js +3 -3
- package/dist/channels/plugins/pairing-message.js +1 -1
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/browser-cli-extension.js +2 -2
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/docs-cli.js +1 -1
- package/dist/cli/gateway-cli/dev.js +1 -1
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +30 -20
- package/dist/cli/nodes-cli/register.canvas.js +1 -1
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/plugins-cli.js +1 -1
- package/dist/cli/run-main.js +2 -2
- package/dist/cli/security-cli.js +1 -1
- package/dist/cli/tagline.js +1 -1
- package/dist/cli/update-cli.js +173 -52
- package/dist/cli/webhooks-cli.js +5 -5
- package/dist/commands/agent.js +1 -0
- package/dist/commands/agents.commands.add.js +1 -1
- package/dist/commands/auth-choice.apply.api-providers.js +305 -17
- package/dist/commands/auth-choice.apply.js +4 -1
- package/dist/commands/auth-choice.apply.plugin-provider.js +2 -2
- package/dist/commands/auth-choice.apply.xai.js +63 -0
- package/dist/commands/auth-choice.preferred-provider.js +7 -1
- package/dist/commands/configure.wizard.js +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/docs.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-gateway-services.js +3 -3
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/doctor-update.js +3 -3
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.probe.js +2 -2
- package/dist/commands/models/list.registry.js +4 -4
- package/dist/commands/models/list.status-command.js +44 -24
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-auth.config-core.js +366 -28
- package/dist/commands/onboard-auth.credentials.js +71 -9
- package/dist/commands/onboard-auth.js +3 -3
- package/dist/commands/onboard-auth.models.js +26 -24
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +146 -9
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/commands/status-all/report-lines.js +1 -1
- package/dist/commands/status.command.js +1 -1
- package/dist/commands/uninstall.js +3 -3
- package/dist/compat/legacy-names.js +1 -1
- package/dist/config/defaults.js +3 -2
- package/dist/config/io.js +3 -3
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +3 -3
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/types.memory.js +1 -0
- package/dist/config/version.js +4 -4
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +171 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/daemon/constants.js +7 -7
- package/dist/daemon/inspect.js +6 -6
- package/dist/daemon/systemd-unit.js +1 -1
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/live-image-probe.js +1 -66
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/openai-http.js +2 -2
- package/dist/gateway/openresponses-http.js +4 -4
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-discovery.js +2 -2
- package/dist/gateway/server-http.js +110 -12
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +7 -3
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/hooks/frontmatter.js +1 -1
- package/dist/hooks/hooks-status.js +1 -1
- package/dist/hooks/install.js +2 -2
- package/dist/hooks/loader.js +1 -1
- package/dist/hooks/workspace.js +3 -3
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/index.js +2 -2
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/bonjour.js +3 -3
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/path-env.js +3 -3
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/provider-usage.fetch.minimax.js +1 -1
- package/dist/infra/restart.js +1 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/tailscale.js +1 -1
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/macos/relay.js +2 -2
- package/dist/media/fetch.js +81 -58
- package/dist/media/input-files.js +1 -1
- package/dist/media/mime.js +4 -0
- package/dist/media/png-encode.js +74 -0
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +4 -4
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/backend-config.js +207 -0
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +29 -17
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +155 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/memory/types.js +1 -0
- package/dist/node-host/runner.js +36 -26
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/pairing/pairing-messages.js +1 -1
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/discovery.js +1 -1
- package/dist/plugins/install.js +2 -2
- package/dist/plugins/source-display.js +51 -0
- package/dist/plugins/update.js +1 -1
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/audit.js +2 -2
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/shared/text/reasoning-tags.js +52 -7
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +145 -0
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +38 -11
- package/dist/telegram/bot-message-dispatch.js +48 -15
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/test-helpers/workspace.js +11 -0
- package/dist/test-utils/channel-plugins.js +82 -0
- package/dist/test-utils/ports.js +73 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/shell-argv.js +61 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +55 -14
- package/dist/version.js +42 -5
- package/dist/web/qr-image.js +1 -61
- package/dist/wizard/onboarding.finalize.js +7 -7
- package/dist/wizard/onboarding.js +3 -3
- package/docs/RELEASE_WORKFOTS_COMPARISON.md +3 -3
- package/docs/_config.yml +2 -2
- package/docs/_layouts/default.html +9 -9
- package/docs/concepts/typebox.md +1 -1
- package/docs/docs.json +1 -1
- package/docs/northflank.mdx +7 -7
- package/docs/railway.mdx +3 -3
- package/docs/render.mdx +5 -5
- package/docs/start/lore.md +2 -2
- package/extensions/bluebubbles/index.ts +2 -2
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/bluebubbles/src/accounts.ts +8 -8
- package/extensions/bluebubbles/src/actions.test.ts +22 -22
- package/extensions/bluebubbles/src/actions.ts +5 -5
- package/extensions/bluebubbles/src/attachments.ts +2 -2
- package/extensions/bluebubbles/src/channel.ts +16 -16
- package/extensions/bluebubbles/src/chat.ts +2 -2
- package/extensions/bluebubbles/src/media-send.ts +2 -2
- package/extensions/bluebubbles/src/monitor.test.ts +46 -46
- package/extensions/bluebubbles/src/monitor.ts +5 -5
- package/extensions/bluebubbles/src/onboarding.ts +7 -7
- package/extensions/bluebubbles/src/reactions.ts +2 -2
- package/extensions/bluebubbles/src/send.ts +2 -2
- package/extensions/copilot-proxy/README.md +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/index.ts +2 -2
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/diagnostics-otel/src/service.ts +3 -3
- package/extensions/discord/index.ts +2 -2
- package/extensions/discord/package.json +1 -1
- package/extensions/google-antigravity-auth/README.md +1 -1
- package/extensions/google-antigravity-auth/index.ts +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/README.md +1 -1
- package/extensions/google-gemini-cli-auth/oauth.ts +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/index.ts +3 -3
- package/extensions/googlechat/package.json +1 -1
- package/extensions/googlechat/src/accounts.ts +8 -8
- package/extensions/googlechat/src/actions.ts +6 -6
- package/extensions/googlechat/src/channel.ts +21 -21
- package/extensions/googlechat/src/monitor.ts +8 -8
- package/extensions/googlechat/src/onboarding.ts +10 -10
- package/extensions/imessage/index.ts +2 -2
- package/extensions/imessage/package.json +1 -1
- package/extensions/line/index.ts +2 -2
- package/extensions/line/package.json +1 -1
- package/extensions/line/src/card-command.ts +2 -2
- package/extensions/line/src/channel.logout.test.ts +4 -4
- package/extensions/line/src/channel.sendPayload.test.ts +8 -8
- package/extensions/line/src/channel.ts +3 -3
- package/extensions/llm-task/README.md +3 -3
- package/extensions/llm-task/index.ts +2 -2
- package/extensions/llm-task/package.json +1 -1
- package/extensions/llm-task/src/llm-task-tool.ts +4 -4
- package/extensions/lobster/README.md +6 -6
- package/extensions/lobster/index.ts +2 -2
- package/extensions/lobster/src/lobster-tool.test.ts +4 -4
- package/extensions/lobster/src/lobster-tool.ts +2 -2
- package/extensions/matrix/index.ts +2 -2
- package/extensions/matrix/package.json +1 -1
- package/extensions/matrix/src/matrix/client/config.ts +1 -1
- package/extensions/matrix/src/matrix/monitor/handler.ts +1 -1
- package/extensions/matrix/src/onboarding.ts +1 -1
- package/extensions/mattermost/index.ts +2 -2
- package/extensions/mattermost/package.json +1 -1
- package/extensions/mattermost/src/mattermost/accounts.ts +8 -8
- package/extensions/mattermost/src/mattermost/monitor-helpers.ts +5 -5
- package/extensions/mattermost/src/mattermost/monitor.ts +2 -2
- package/extensions/mattermost/src/onboarding-helpers.ts +3 -3
- package/extensions/mattermost/src/onboarding.ts +2 -2
- package/extensions/memory-core/index.ts +2 -2
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/index.ts +3 -3
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/msteams/index.ts +2 -2
- package/extensions/msteams/package.json +1 -1
- package/extensions/msteams/src/channel.directory.test.ts +2 -2
- package/extensions/msteams/src/channel.ts +2 -2
- package/extensions/msteams/src/graph-upload.ts +4 -4
- package/extensions/msteams/src/monitor-handler.ts +2 -2
- package/extensions/msteams/src/monitor.ts +2 -2
- package/extensions/msteams/src/onboarding.ts +9 -9
- package/extensions/msteams/src/reply-dispatcher.ts +2 -2
- package/extensions/msteams/src/send-context.ts +2 -2
- package/extensions/msteams/src/send.ts +4 -4
- package/extensions/nextcloud-talk/index.ts +2 -2
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nextcloud-talk/src/channel.ts +7 -7
- package/extensions/nextcloud-talk/src/inbound.ts +7 -7
- package/extensions/nextcloud-talk/src/onboarding.ts +1 -1
- package/extensions/nostr/README.md +2 -2
- package/extensions/nostr/index.ts +5 -5
- package/extensions/nostr/package.json +1 -1
- package/extensions/nostr/src/types.ts +4 -4
- package/extensions/open-prose/index.ts +2 -2
- package/extensions/qwen-portal-auth/README.md +1 -1
- package/extensions/signal/index.ts +2 -2
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/index.ts +2 -2
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/index.ts +2 -2
- package/extensions/telegram/package.json +1 -1
- package/extensions/telegram/src/channel.ts +2 -2
- package/extensions/tlon/README.md +2 -2
- package/extensions/tlon/index.ts +2 -2
- package/extensions/tlon/package.json +1 -1
- package/extensions/tlon/src/channel.ts +13 -13
- package/extensions/tlon/src/monitor/index.ts +3 -3
- package/extensions/tlon/src/onboarding.ts +3 -3
- package/extensions/tlon/src/types.ts +3 -3
- package/extensions/twitch/README.md +1 -1
- package/extensions/twitch/index.ts +2 -2
- package/extensions/twitch/package.json +1 -1
- package/extensions/twitch/src/config.ts +3 -3
- package/extensions/twitch/src/monitor.ts +3 -3
- package/extensions/twitch/src/onboarding.ts +9 -9
- package/extensions/twitch/src/outbound.test.ts +2 -2
- package/extensions/twitch/src/plugin.test.ts +2 -2
- package/extensions/twitch/src/plugin.ts +8 -8
- package/extensions/twitch/src/send.test.ts +2 -2
- package/extensions/twitch/src/send.ts +4 -4
- package/extensions/twitch/src/token.test.ts +8 -8
- package/extensions/twitch/src/token.ts +3 -3
- package/extensions/twitch/src/twitch-client.ts +3 -3
- package/extensions/twitch/src/types.ts +3 -3
- package/extensions/twitch/src/utils/markdown.ts +1 -1
- package/extensions/voice-call/README.md +3 -3
- package/extensions/voice-call/package.json +1 -1
- package/extensions/voice-call/src/core-bridge.ts +2 -2
- package/extensions/voice-call/src/response-generator.ts +1 -1
- package/extensions/whatsapp/index.ts +2 -2
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/README.md +1 -1
- package/extensions/zalo/index.ts +2 -2
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalo/src/accounts.ts +8 -8
- package/extensions/zalo/src/actions.ts +4 -4
- package/extensions/zalo/src/channel.directory.test.ts +2 -2
- package/extensions/zalo/src/channel.ts +18 -18
- package/extensions/zalo/src/monitor.ts +9 -9
- package/extensions/zalo/src/monitor.webhook.test.ts +2 -2
- package/extensions/zalo/src/onboarding.ts +24 -24
- package/extensions/zalo/src/send.ts +2 -2
- package/extensions/zalouser/README.md +2 -2
- package/extensions/zalouser/index.ts +2 -2
- package/extensions/zalouser/package.json +1 -1
- package/extensions/zalouser/src/accounts.ts +9 -9
- package/extensions/zalouser/src/channel.ts +24 -24
- package/extensions/zalouser/src/monitor.ts +4 -4
- package/extensions/zalouser/src/onboarding.ts +28 -28
- package/package.json +13 -251
- package/skills/nano-banana-pro/scripts/generate_image.py +1 -1
- package/skills/tmux/scripts/find-sessions.sh +1 -1
- package/CHANGELOG.md +0 -102
- package/README-header.png +0 -0
- package/git-hooks/pre-commit +0 -4
- package/scripts/format-staged.js +0 -148
- package/scripts/postinstall.js +0 -300
- package/scripts/setup-git-hooks.js +0 -96
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
|
|
3
|
+
import { parseDurationMs } from "../cli/parse-duration.js";
|
|
4
|
+
import { resolveUserPath } from "../utils.js";
|
|
5
|
+
import { splitShellArgs } from "../utils/shell-argv.js";
|
|
6
|
+
const DEFAULT_BACKEND = "builtin";
|
|
7
|
+
const DEFAULT_CITATIONS = "auto";
|
|
8
|
+
const DEFAULT_QMD_INTERVAL = "5m";
|
|
9
|
+
const DEFAULT_QMD_DEBOUNCE_MS = 15_000;
|
|
10
|
+
const DEFAULT_QMD_TIMEOUT_MS = 4_000;
|
|
11
|
+
const DEFAULT_QMD_EMBED_INTERVAL = "60m";
|
|
12
|
+
const DEFAULT_QMD_COMMAND_TIMEOUT_MS = 30_000;
|
|
13
|
+
const DEFAULT_QMD_UPDATE_TIMEOUT_MS = 120_000;
|
|
14
|
+
const DEFAULT_QMD_EMBED_TIMEOUT_MS = 120_000;
|
|
15
|
+
const DEFAULT_QMD_LIMITS = {
|
|
16
|
+
maxResults: 6,
|
|
17
|
+
maxSnippetChars: 700,
|
|
18
|
+
maxInjectedChars: 4_000,
|
|
19
|
+
timeoutMs: DEFAULT_QMD_TIMEOUT_MS,
|
|
20
|
+
};
|
|
21
|
+
const DEFAULT_QMD_SCOPE = {
|
|
22
|
+
default: "deny",
|
|
23
|
+
rules: [
|
|
24
|
+
{
|
|
25
|
+
action: "allow",
|
|
26
|
+
match: { chatType: "direct" },
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
function sanitizeName(input) {
|
|
31
|
+
const lower = input.toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
32
|
+
const trimmed = lower.replace(/^-+|-+$/g, "");
|
|
33
|
+
return trimmed || "collection";
|
|
34
|
+
}
|
|
35
|
+
function ensureUniqueName(base, existing) {
|
|
36
|
+
let name = sanitizeName(base);
|
|
37
|
+
if (!existing.has(name)) {
|
|
38
|
+
existing.add(name);
|
|
39
|
+
return name;
|
|
40
|
+
}
|
|
41
|
+
let suffix = 2;
|
|
42
|
+
while (existing.has(`${name}-${suffix}`)) {
|
|
43
|
+
suffix += 1;
|
|
44
|
+
}
|
|
45
|
+
const unique = `${name}-${suffix}`;
|
|
46
|
+
existing.add(unique);
|
|
47
|
+
return unique;
|
|
48
|
+
}
|
|
49
|
+
function resolvePath(raw, workspaceDir) {
|
|
50
|
+
const trimmed = raw.trim();
|
|
51
|
+
if (!trimmed) {
|
|
52
|
+
throw new Error("path required");
|
|
53
|
+
}
|
|
54
|
+
if (trimmed.startsWith("~") || path.isAbsolute(trimmed)) {
|
|
55
|
+
return path.normalize(resolveUserPath(trimmed));
|
|
56
|
+
}
|
|
57
|
+
return path.normalize(path.resolve(workspaceDir, trimmed));
|
|
58
|
+
}
|
|
59
|
+
function resolveIntervalMs(raw) {
|
|
60
|
+
const value = raw?.trim();
|
|
61
|
+
if (!value) {
|
|
62
|
+
return parseDurationMs(DEFAULT_QMD_INTERVAL, { defaultUnit: "m" });
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
return parseDurationMs(value, { defaultUnit: "m" });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return parseDurationMs(DEFAULT_QMD_INTERVAL, { defaultUnit: "m" });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function resolveEmbedIntervalMs(raw) {
|
|
72
|
+
const value = raw?.trim();
|
|
73
|
+
if (!value) {
|
|
74
|
+
return parseDurationMs(DEFAULT_QMD_EMBED_INTERVAL, { defaultUnit: "m" });
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
return parseDurationMs(value, { defaultUnit: "m" });
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return parseDurationMs(DEFAULT_QMD_EMBED_INTERVAL, { defaultUnit: "m" });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function resolveDebounceMs(raw) {
|
|
84
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw >= 0) {
|
|
85
|
+
return Math.floor(raw);
|
|
86
|
+
}
|
|
87
|
+
return DEFAULT_QMD_DEBOUNCE_MS;
|
|
88
|
+
}
|
|
89
|
+
function resolveTimeoutMs(raw, fallback) {
|
|
90
|
+
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) {
|
|
91
|
+
return Math.floor(raw);
|
|
92
|
+
}
|
|
93
|
+
return fallback;
|
|
94
|
+
}
|
|
95
|
+
function resolveLimits(raw) {
|
|
96
|
+
const parsed = { ...DEFAULT_QMD_LIMITS };
|
|
97
|
+
if (raw?.maxResults && raw.maxResults > 0) {
|
|
98
|
+
parsed.maxResults = Math.floor(raw.maxResults);
|
|
99
|
+
}
|
|
100
|
+
if (raw?.maxSnippetChars && raw.maxSnippetChars > 0) {
|
|
101
|
+
parsed.maxSnippetChars = Math.floor(raw.maxSnippetChars);
|
|
102
|
+
}
|
|
103
|
+
if (raw?.maxInjectedChars && raw.maxInjectedChars > 0) {
|
|
104
|
+
parsed.maxInjectedChars = Math.floor(raw.maxInjectedChars);
|
|
105
|
+
}
|
|
106
|
+
if (raw?.timeoutMs && raw.timeoutMs > 0) {
|
|
107
|
+
parsed.timeoutMs = Math.floor(raw.timeoutMs);
|
|
108
|
+
}
|
|
109
|
+
return parsed;
|
|
110
|
+
}
|
|
111
|
+
function resolveSessionConfig(cfg, workspaceDir) {
|
|
112
|
+
const enabled = Boolean(cfg?.enabled);
|
|
113
|
+
const exportDirRaw = cfg?.exportDir?.trim();
|
|
114
|
+
const exportDir = exportDirRaw ? resolvePath(exportDirRaw, workspaceDir) : undefined;
|
|
115
|
+
const retentionDays = cfg?.retentionDays && cfg.retentionDays > 0 ? Math.floor(cfg.retentionDays) : undefined;
|
|
116
|
+
return {
|
|
117
|
+
enabled,
|
|
118
|
+
exportDir,
|
|
119
|
+
retentionDays,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function resolveCustomPaths(rawPaths, workspaceDir, existing) {
|
|
123
|
+
if (!rawPaths?.length) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const collections = [];
|
|
127
|
+
rawPaths.forEach((entry, index) => {
|
|
128
|
+
const trimmedPath = entry?.path?.trim();
|
|
129
|
+
if (!trimmedPath) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let resolved;
|
|
133
|
+
try {
|
|
134
|
+
resolved = resolvePath(trimmedPath, workspaceDir);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const pattern = entry.pattern?.trim() || "**/*.md";
|
|
140
|
+
const baseName = entry.name?.trim() || `custom-${index + 1}`;
|
|
141
|
+
const name = ensureUniqueName(baseName, existing);
|
|
142
|
+
collections.push({
|
|
143
|
+
name,
|
|
144
|
+
path: resolved,
|
|
145
|
+
pattern,
|
|
146
|
+
kind: "custom",
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
return collections;
|
|
150
|
+
}
|
|
151
|
+
function resolveDefaultCollections(include, workspaceDir, existing) {
|
|
152
|
+
if (!include) {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
const entries = [
|
|
156
|
+
{ path: workspaceDir, pattern: "MEMORY.md", base: "memory-root" },
|
|
157
|
+
{ path: workspaceDir, pattern: "memory.md", base: "memory-alt" },
|
|
158
|
+
{ path: path.join(workspaceDir, "memory"), pattern: "**/*.md", base: "memory-dir" },
|
|
159
|
+
];
|
|
160
|
+
return entries.map((entry) => ({
|
|
161
|
+
name: ensureUniqueName(entry.base, existing),
|
|
162
|
+
path: entry.path,
|
|
163
|
+
pattern: entry.pattern,
|
|
164
|
+
kind: "memory",
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
export function resolveMemoryBackendConfig(params) {
|
|
168
|
+
const backend = params.cfg.memory?.backend ?? DEFAULT_BACKEND;
|
|
169
|
+
const citations = params.cfg.memory?.citations ?? DEFAULT_CITATIONS;
|
|
170
|
+
if (backend !== "qmd") {
|
|
171
|
+
return { backend: "builtin", citations };
|
|
172
|
+
}
|
|
173
|
+
const workspaceDir = resolveAgentWorkspaceDir(params.cfg, params.agentId);
|
|
174
|
+
const qmdCfg = params.cfg.memory?.qmd;
|
|
175
|
+
const includeDefaultMemory = qmdCfg?.includeDefaultMemory !== false;
|
|
176
|
+
const nameSet = new Set();
|
|
177
|
+
const collections = [
|
|
178
|
+
...resolveDefaultCollections(includeDefaultMemory, workspaceDir, nameSet),
|
|
179
|
+
...resolveCustomPaths(qmdCfg?.paths, workspaceDir, nameSet),
|
|
180
|
+
];
|
|
181
|
+
const rawCommand = qmdCfg?.command?.trim() || "qmd";
|
|
182
|
+
const parsedCommand = splitShellArgs(rawCommand);
|
|
183
|
+
const command = parsedCommand?.[0] || rawCommand.split(/\s+/)[0] || "qmd";
|
|
184
|
+
const resolved = {
|
|
185
|
+
command,
|
|
186
|
+
collections,
|
|
187
|
+
includeDefaultMemory,
|
|
188
|
+
sessions: resolveSessionConfig(qmdCfg?.sessions, workspaceDir),
|
|
189
|
+
update: {
|
|
190
|
+
intervalMs: resolveIntervalMs(qmdCfg?.update?.interval),
|
|
191
|
+
debounceMs: resolveDebounceMs(qmdCfg?.update?.debounceMs),
|
|
192
|
+
onBoot: qmdCfg?.update?.onBoot !== false,
|
|
193
|
+
waitForBootSync: qmdCfg?.update?.waitForBootSync === true,
|
|
194
|
+
embedIntervalMs: resolveEmbedIntervalMs(qmdCfg?.update?.embedInterval),
|
|
195
|
+
commandTimeoutMs: resolveTimeoutMs(qmdCfg?.update?.commandTimeoutMs, DEFAULT_QMD_COMMAND_TIMEOUT_MS),
|
|
196
|
+
updateTimeoutMs: resolveTimeoutMs(qmdCfg?.update?.updateTimeoutMs, DEFAULT_QMD_UPDATE_TIMEOUT_MS),
|
|
197
|
+
embedTimeoutMs: resolveTimeoutMs(qmdCfg?.update?.embedTimeoutMs, DEFAULT_QMD_EMBED_TIMEOUT_MS),
|
|
198
|
+
},
|
|
199
|
+
limits: resolveLimits(qmdCfg?.limits),
|
|
200
|
+
scope: qmdCfg?.scope ?? DEFAULT_QMD_SCOPE,
|
|
201
|
+
};
|
|
202
|
+
return {
|
|
203
|
+
backend: "qmd",
|
|
204
|
+
citations,
|
|
205
|
+
qmd: resolved,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import { retryAsync } from "../infra/retry.js";
|
|
4
|
+
import { hashText, runWithConcurrency } from "./internal.js";
|
|
5
|
+
export const VOYAGE_BATCH_ENDPOINT = "/v1/embeddings";
|
|
6
|
+
const VOYAGE_BATCH_COMPLETION_WINDOW = "12h";
|
|
7
|
+
const VOYAGE_BATCH_MAX_REQUESTS = 50000;
|
|
8
|
+
function getVoyageBaseUrl(client) {
|
|
9
|
+
return client.baseUrl?.replace(/\/$/, "") ?? "";
|
|
10
|
+
}
|
|
11
|
+
function getVoyageHeaders(client, params) {
|
|
12
|
+
const headers = client.headers ? { ...client.headers } : {};
|
|
13
|
+
if (params.json) {
|
|
14
|
+
if (!headers["Content-Type"] && !headers["content-type"]) {
|
|
15
|
+
headers["Content-Type"] = "application/json";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
delete headers["Content-Type"];
|
|
20
|
+
delete headers["content-type"];
|
|
21
|
+
}
|
|
22
|
+
return headers;
|
|
23
|
+
}
|
|
24
|
+
function splitVoyageBatchRequests(requests) {
|
|
25
|
+
if (requests.length <= VOYAGE_BATCH_MAX_REQUESTS) {
|
|
26
|
+
return [requests];
|
|
27
|
+
}
|
|
28
|
+
const groups = [];
|
|
29
|
+
for (let i = 0; i < requests.length; i += VOYAGE_BATCH_MAX_REQUESTS) {
|
|
30
|
+
groups.push(requests.slice(i, i + VOYAGE_BATCH_MAX_REQUESTS));
|
|
31
|
+
}
|
|
32
|
+
return groups;
|
|
33
|
+
}
|
|
34
|
+
async function submitVoyageBatch(params) {
|
|
35
|
+
const baseUrl = getVoyageBaseUrl(params.client);
|
|
36
|
+
const jsonl = params.requests.map((request) => JSON.stringify(request)).join("\n");
|
|
37
|
+
const form = new FormData();
|
|
38
|
+
form.append("purpose", "batch");
|
|
39
|
+
form.append("file", new Blob([jsonl], { type: "application/jsonl" }), `memory-embeddings.${hashText(String(Date.now()))}.jsonl`);
|
|
40
|
+
// 1. Upload file using Voyage Files API
|
|
41
|
+
const fileRes = await fetch(`${baseUrl}/files`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: getVoyageHeaders(params.client, { json: false }),
|
|
44
|
+
body: form,
|
|
45
|
+
});
|
|
46
|
+
if (!fileRes.ok) {
|
|
47
|
+
const text = await fileRes.text();
|
|
48
|
+
throw new Error(`voyage batch file upload failed: ${fileRes.status} ${text}`);
|
|
49
|
+
}
|
|
50
|
+
const filePayload = (await fileRes.json());
|
|
51
|
+
if (!filePayload.id) {
|
|
52
|
+
throw new Error("voyage batch file upload failed: missing file id");
|
|
53
|
+
}
|
|
54
|
+
// 2. Create batch job using Voyage Batches API
|
|
55
|
+
const batchRes = await retryAsync(async () => {
|
|
56
|
+
const res = await fetch(`${baseUrl}/batches`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: getVoyageHeaders(params.client, { json: true }),
|
|
59
|
+
body: JSON.stringify({
|
|
60
|
+
input_file_id: filePayload.id,
|
|
61
|
+
endpoint: VOYAGE_BATCH_ENDPOINT,
|
|
62
|
+
completion_window: VOYAGE_BATCH_COMPLETION_WINDOW,
|
|
63
|
+
request_params: {
|
|
64
|
+
model: params.client.model,
|
|
65
|
+
input_type: "document",
|
|
66
|
+
},
|
|
67
|
+
metadata: {
|
|
68
|
+
source: "clawdbot-memory",
|
|
69
|
+
agent: params.agentId,
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const text = await res.text();
|
|
75
|
+
const err = new Error(`voyage batch create failed: ${res.status} ${text}`);
|
|
76
|
+
err.status = res.status;
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
return res;
|
|
80
|
+
}, {
|
|
81
|
+
attempts: 3,
|
|
82
|
+
minDelayMs: 300,
|
|
83
|
+
maxDelayMs: 2000,
|
|
84
|
+
jitter: 0.2,
|
|
85
|
+
shouldRetry: (err) => {
|
|
86
|
+
const status = err.status;
|
|
87
|
+
return status === 429 || (typeof status === "number" && status >= 500);
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
return (await batchRes.json());
|
|
91
|
+
}
|
|
92
|
+
async function fetchVoyageBatchStatus(params) {
|
|
93
|
+
const baseUrl = getVoyageBaseUrl(params.client);
|
|
94
|
+
const res = await fetch(`${baseUrl}/batches/${params.batchId}`, {
|
|
95
|
+
headers: getVoyageHeaders(params.client, { json: true }),
|
|
96
|
+
});
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
const text = await res.text();
|
|
99
|
+
throw new Error(`voyage batch status failed: ${res.status} ${text}`);
|
|
100
|
+
}
|
|
101
|
+
return (await res.json());
|
|
102
|
+
}
|
|
103
|
+
async function readVoyageBatchError(params) {
|
|
104
|
+
try {
|
|
105
|
+
const baseUrl = getVoyageBaseUrl(params.client);
|
|
106
|
+
const res = await fetch(`${baseUrl}/files/${params.errorFileId}/content`, {
|
|
107
|
+
headers: getVoyageHeaders(params.client, { json: true }),
|
|
108
|
+
});
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
const text = await res.text();
|
|
111
|
+
throw new Error(`voyage batch error file content failed: ${res.status} ${text}`);
|
|
112
|
+
}
|
|
113
|
+
const text = await res.text();
|
|
114
|
+
if (!text.trim()) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const lines = text
|
|
118
|
+
.split("\n")
|
|
119
|
+
.map((line) => line.trim())
|
|
120
|
+
.filter(Boolean)
|
|
121
|
+
.map((line) => JSON.parse(line));
|
|
122
|
+
const first = lines.find((line) => line.error?.message || line.response?.body?.error);
|
|
123
|
+
const message = first?.error?.message ??
|
|
124
|
+
(typeof first?.response?.body?.error?.message === "string"
|
|
125
|
+
? first?.response?.body?.error?.message
|
|
126
|
+
: undefined);
|
|
127
|
+
return message;
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
131
|
+
return message ? `error file unavailable: ${message}` : undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function waitForVoyageBatch(params) {
|
|
135
|
+
const start = Date.now();
|
|
136
|
+
let current = params.initial;
|
|
137
|
+
while (true) {
|
|
138
|
+
const status = current ??
|
|
139
|
+
(await fetchVoyageBatchStatus({
|
|
140
|
+
client: params.client,
|
|
141
|
+
batchId: params.batchId,
|
|
142
|
+
}));
|
|
143
|
+
const state = status.status ?? "unknown";
|
|
144
|
+
if (state === "completed") {
|
|
145
|
+
if (!status.output_file_id) {
|
|
146
|
+
throw new Error(`voyage batch ${params.batchId} completed without output file`);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
outputFileId: status.output_file_id,
|
|
150
|
+
errorFileId: status.error_file_id ?? undefined,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (["failed", "expired", "cancelled", "canceled"].includes(state)) {
|
|
154
|
+
const detail = status.error_file_id
|
|
155
|
+
? await readVoyageBatchError({ client: params.client, errorFileId: status.error_file_id })
|
|
156
|
+
: undefined;
|
|
157
|
+
const suffix = detail ? `: ${detail}` : "";
|
|
158
|
+
throw new Error(`voyage batch ${params.batchId} ${state}${suffix}`);
|
|
159
|
+
}
|
|
160
|
+
if (!params.wait) {
|
|
161
|
+
throw new Error(`voyage batch ${params.batchId} still ${state}; wait disabled`);
|
|
162
|
+
}
|
|
163
|
+
if (Date.now() - start > params.timeoutMs) {
|
|
164
|
+
throw new Error(`voyage batch ${params.batchId} timed out after ${params.timeoutMs}ms`);
|
|
165
|
+
}
|
|
166
|
+
params.debug?.(`voyage batch ${params.batchId} ${state}; waiting ${params.pollIntervalMs}ms`);
|
|
167
|
+
await new Promise((resolve) => setTimeout(resolve, params.pollIntervalMs));
|
|
168
|
+
current = undefined;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function runVoyageEmbeddingBatches(params) {
|
|
172
|
+
if (params.requests.length === 0) {
|
|
173
|
+
return new Map();
|
|
174
|
+
}
|
|
175
|
+
const groups = splitVoyageBatchRequests(params.requests);
|
|
176
|
+
const byCustomId = new Map();
|
|
177
|
+
const tasks = groups.map((group, groupIndex) => async () => {
|
|
178
|
+
const batchInfo = await submitVoyageBatch({
|
|
179
|
+
client: params.client,
|
|
180
|
+
requests: group,
|
|
181
|
+
agentId: params.agentId,
|
|
182
|
+
});
|
|
183
|
+
if (!batchInfo.id) {
|
|
184
|
+
throw new Error("voyage batch create failed: missing batch id");
|
|
185
|
+
}
|
|
186
|
+
params.debug?.("memory embeddings: voyage batch created", {
|
|
187
|
+
batchId: batchInfo.id,
|
|
188
|
+
status: batchInfo.status,
|
|
189
|
+
group: groupIndex + 1,
|
|
190
|
+
groups: groups.length,
|
|
191
|
+
requests: group.length,
|
|
192
|
+
});
|
|
193
|
+
if (!params.wait && batchInfo.status !== "completed") {
|
|
194
|
+
throw new Error(`voyage batch ${batchInfo.id} submitted; enable remote.batch.wait to await completion`);
|
|
195
|
+
}
|
|
196
|
+
const completed = batchInfo.status === "completed"
|
|
197
|
+
? {
|
|
198
|
+
outputFileId: batchInfo.output_file_id ?? "",
|
|
199
|
+
errorFileId: batchInfo.error_file_id ?? undefined,
|
|
200
|
+
}
|
|
201
|
+
: await waitForVoyageBatch({
|
|
202
|
+
client: params.client,
|
|
203
|
+
batchId: batchInfo.id,
|
|
204
|
+
wait: params.wait,
|
|
205
|
+
pollIntervalMs: params.pollIntervalMs,
|
|
206
|
+
timeoutMs: params.timeoutMs,
|
|
207
|
+
debug: params.debug,
|
|
208
|
+
initial: batchInfo,
|
|
209
|
+
});
|
|
210
|
+
if (!completed.outputFileId) {
|
|
211
|
+
throw new Error(`voyage batch ${batchInfo.id} completed without output file`);
|
|
212
|
+
}
|
|
213
|
+
const baseUrl = getVoyageBaseUrl(params.client);
|
|
214
|
+
const contentRes = await fetch(`${baseUrl}/files/${completed.outputFileId}/content`, {
|
|
215
|
+
headers: getVoyageHeaders(params.client, { json: true }),
|
|
216
|
+
});
|
|
217
|
+
if (!contentRes.ok) {
|
|
218
|
+
const text = await contentRes.text();
|
|
219
|
+
throw new Error(`voyage batch file content failed: ${contentRes.status} ${text}`);
|
|
220
|
+
}
|
|
221
|
+
const errors = [];
|
|
222
|
+
const remaining = new Set(group.map((request) => request.custom_id));
|
|
223
|
+
if (contentRes.body) {
|
|
224
|
+
const reader = createInterface({
|
|
225
|
+
input: Readable.fromWeb(contentRes.body),
|
|
226
|
+
terminal: false,
|
|
227
|
+
});
|
|
228
|
+
for await (const rawLine of reader) {
|
|
229
|
+
if (!rawLine.trim()) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const line = JSON.parse(rawLine);
|
|
233
|
+
const customId = line.custom_id;
|
|
234
|
+
if (!customId) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
remaining.delete(customId);
|
|
238
|
+
if (line.error?.message) {
|
|
239
|
+
errors.push(`${customId}: ${line.error.message}`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const response = line.response;
|
|
243
|
+
const statusCode = response?.status_code ?? 0;
|
|
244
|
+
if (statusCode >= 400) {
|
|
245
|
+
const message = response?.body?.error?.message ??
|
|
246
|
+
(typeof response?.body === "string" ? response.body : undefined) ??
|
|
247
|
+
"unknown error";
|
|
248
|
+
errors.push(`${customId}: ${message}`);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const data = response?.body?.data ?? [];
|
|
252
|
+
const embedding = data[0]?.embedding ?? [];
|
|
253
|
+
if (embedding.length === 0) {
|
|
254
|
+
errors.push(`${customId}: empty embedding`);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
byCustomId.set(customId, embedding);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (errors.length > 0) {
|
|
261
|
+
throw new Error(`voyage batch ${batchInfo.id} failed: ${errors.join("; ")}`);
|
|
262
|
+
}
|
|
263
|
+
if (remaining.size > 0) {
|
|
264
|
+
throw new Error(`voyage batch ${batchInfo.id} missing ${remaining.size} embedding responses`);
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
params.debug?.("memory embeddings: voyage batch submit", {
|
|
268
|
+
requests: params.requests.length,
|
|
269
|
+
groups: groups.length,
|
|
270
|
+
wait: params.wait,
|
|
271
|
+
concurrency: params.concurrency,
|
|
272
|
+
pollIntervalMs: params.pollIntervalMs,
|
|
273
|
+
timeoutMs: params.timeoutMs,
|
|
274
|
+
});
|
|
275
|
+
await runWithConcurrency(tasks, params.concurrency);
|
|
276
|
+
return byCustomId;
|
|
277
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
|
2
|
+
export const DEFAULT_VOYAGE_EMBEDDING_MODEL = "voyage-4-large";
|
|
3
|
+
const DEFAULT_VOYAGE_BASE_URL = "https://api.voyageai.com/v1";
|
|
4
|
+
export function normalizeVoyageModel(model) {
|
|
5
|
+
const trimmed = model.trim();
|
|
6
|
+
if (!trimmed) {
|
|
7
|
+
return DEFAULT_VOYAGE_EMBEDDING_MODEL;
|
|
8
|
+
}
|
|
9
|
+
if (trimmed.startsWith("voyage/")) {
|
|
10
|
+
return trimmed.slice("voyage/".length);
|
|
11
|
+
}
|
|
12
|
+
return trimmed;
|
|
13
|
+
}
|
|
14
|
+
export async function createVoyageEmbeddingProvider(options) {
|
|
15
|
+
const client = await resolveVoyageEmbeddingClient(options);
|
|
16
|
+
const url = `${client.baseUrl.replace(/\/$/, "")}/embeddings`;
|
|
17
|
+
const embed = async (input, input_type) => {
|
|
18
|
+
if (input.length === 0) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
const body = {
|
|
22
|
+
model: client.model,
|
|
23
|
+
input,
|
|
24
|
+
};
|
|
25
|
+
if (input_type) {
|
|
26
|
+
body.input_type = input_type;
|
|
27
|
+
}
|
|
28
|
+
const res = await fetch(url, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: client.headers,
|
|
31
|
+
body: JSON.stringify(body),
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
const text = await res.text();
|
|
35
|
+
throw new Error(`voyage embeddings failed: ${res.status} ${text}`);
|
|
36
|
+
}
|
|
37
|
+
const payload = (await res.json());
|
|
38
|
+
const data = payload.data ?? [];
|
|
39
|
+
return data.map((entry) => entry.embedding ?? []);
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
provider: {
|
|
43
|
+
id: "voyage",
|
|
44
|
+
model: client.model,
|
|
45
|
+
embedQuery: async (text) => {
|
|
46
|
+
const [vec] = await embed([text], "query");
|
|
47
|
+
return vec ?? [];
|
|
48
|
+
},
|
|
49
|
+
embedBatch: async (texts) => embed(texts, "document"),
|
|
50
|
+
},
|
|
51
|
+
client,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export async function resolveVoyageEmbeddingClient(options) {
|
|
55
|
+
const remote = options.remote;
|
|
56
|
+
const remoteApiKey = remote?.apiKey?.trim();
|
|
57
|
+
const remoteBaseUrl = remote?.baseUrl?.trim();
|
|
58
|
+
const apiKey = remoteApiKey
|
|
59
|
+
? remoteApiKey
|
|
60
|
+
: requireApiKey(await resolveApiKeyForProvider({
|
|
61
|
+
provider: "voyage",
|
|
62
|
+
cfg: options.config,
|
|
63
|
+
agentDir: options.agentDir,
|
|
64
|
+
}), "voyage");
|
|
65
|
+
const providerConfig = options.config.models?.providers?.voyage;
|
|
66
|
+
const baseUrl = remoteBaseUrl || providerConfig?.baseUrl?.trim() || DEFAULT_VOYAGE_BASE_URL;
|
|
67
|
+
const headerOverrides = Object.assign({}, providerConfig?.headers, remote?.headers);
|
|
68
|
+
const headers = {
|
|
69
|
+
"Content-Type": "application/json",
|
|
70
|
+
Authorization: `Bearer ${apiKey}`,
|
|
71
|
+
...headerOverrides,
|
|
72
|
+
};
|
|
73
|
+
const model = normalizeVoyageModel(options.model);
|
|
74
|
+
return { baseUrl, headers, model };
|
|
75
|
+
}
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import fsSync from "node:fs";
|
|
2
|
+
import { formatErrorMessage } from "../infra/errors.js";
|
|
2
3
|
import { resolveUserPath } from "../utils.js";
|
|
3
4
|
import { createGeminiEmbeddingProvider } from "./embeddings-gemini.js";
|
|
4
5
|
import { createOpenAiEmbeddingProvider } from "./embeddings-openai.js";
|
|
6
|
+
import { createVoyageEmbeddingProvider } from "./embeddings-voyage.js";
|
|
5
7
|
import { importNodeLlamaCpp } from "./node-llama.js";
|
|
8
|
+
function sanitizeAndNormalizeEmbedding(vec) {
|
|
9
|
+
const sanitized = vec.map((value) => (Number.isFinite(value) ? value : 0));
|
|
10
|
+
const magnitude = Math.sqrt(sanitized.reduce((sum, value) => sum + value * value, 0));
|
|
11
|
+
if (magnitude < 1e-10) {
|
|
12
|
+
return sanitized;
|
|
13
|
+
}
|
|
14
|
+
return sanitized.map((value) => value / magnitude);
|
|
15
|
+
}
|
|
6
16
|
const DEFAULT_LOCAL_MODEL = "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf";
|
|
7
17
|
function canAutoSelectLocal(options) {
|
|
8
18
|
const modelPath = options.local?.modelPath?.trim();
|
|
9
|
-
if (!modelPath)
|
|
19
|
+
if (!modelPath) {
|
|
10
20
|
return false;
|
|
11
|
-
|
|
21
|
+
}
|
|
22
|
+
if (/^(hf:|https?:)/i.test(modelPath)) {
|
|
12
23
|
return false;
|
|
24
|
+
}
|
|
13
25
|
const resolved = resolveUserPath(modelPath);
|
|
14
26
|
try {
|
|
15
27
|
return fsSync.statSync(resolved).isFile();
|
|
@@ -19,7 +31,7 @@ function canAutoSelectLocal(options) {
|
|
|
19
31
|
}
|
|
20
32
|
}
|
|
21
33
|
function isMissingApiKeyError(err) {
|
|
22
|
-
const message =
|
|
34
|
+
const message = formatErrorMessage(err);
|
|
23
35
|
return message.includes("No API key found for provider");
|
|
24
36
|
}
|
|
25
37
|
async function createLocalEmbeddingProvider(options) {
|
|
@@ -49,13 +61,13 @@ async function createLocalEmbeddingProvider(options) {
|
|
|
49
61
|
embedQuery: async (text) => {
|
|
50
62
|
const ctx = await ensureContext();
|
|
51
63
|
const embedding = await ctx.getEmbeddingFor(text);
|
|
52
|
-
return Array.from(embedding.vector);
|
|
64
|
+
return sanitizeAndNormalizeEmbedding(Array.from(embedding.vector));
|
|
53
65
|
},
|
|
54
66
|
embedBatch: async (texts) => {
|
|
55
67
|
const ctx = await ensureContext();
|
|
56
68
|
const embeddings = await Promise.all(texts.map(async (text) => {
|
|
57
69
|
const embedding = await ctx.getEmbeddingFor(text);
|
|
58
|
-
return Array.from(embedding.vector);
|
|
70
|
+
return sanitizeAndNormalizeEmbedding(Array.from(embedding.vector));
|
|
59
71
|
}));
|
|
60
72
|
return embeddings;
|
|
61
73
|
},
|
|
@@ -73,10 +85,14 @@ export async function createEmbeddingProvider(options) {
|
|
|
73
85
|
const { provider, client } = await createGeminiEmbeddingProvider(options);
|
|
74
86
|
return { provider, gemini: client };
|
|
75
87
|
}
|
|
88
|
+
if (id === "voyage") {
|
|
89
|
+
const { provider, client } = await createVoyageEmbeddingProvider(options);
|
|
90
|
+
return { provider, voyage: client };
|
|
91
|
+
}
|
|
76
92
|
const { provider, client } = await createOpenAiEmbeddingProvider(options);
|
|
77
93
|
return { provider, openAi: client };
|
|
78
94
|
};
|
|
79
|
-
const formatPrimaryError = (err, provider) => provider === "local" ? formatLocalSetupError(err) :
|
|
95
|
+
const formatPrimaryError = (err, provider) => provider === "local" ? formatLocalSetupError(err) : formatErrorMessage(err);
|
|
80
96
|
if (requestedProvider === "auto") {
|
|
81
97
|
const missingKeyErrors = [];
|
|
82
98
|
let localError = null;
|
|
@@ -89,7 +105,7 @@ export async function createEmbeddingProvider(options) {
|
|
|
89
105
|
localError = formatLocalSetupError(err);
|
|
90
106
|
}
|
|
91
107
|
}
|
|
92
|
-
for (const provider of ["openai", "gemini"]) {
|
|
108
|
+
for (const provider of ["openai", "gemini", "voyage"]) {
|
|
93
109
|
try {
|
|
94
110
|
const result = await createProvider(provider);
|
|
95
111
|
return { ...result, requestedProvider };
|
|
@@ -100,7 +116,7 @@ export async function createEmbeddingProvider(options) {
|
|
|
100
116
|
missingKeyErrors.push(message);
|
|
101
117
|
continue;
|
|
102
118
|
}
|
|
103
|
-
throw new Error(message);
|
|
119
|
+
throw new Error(message, { cause: err });
|
|
104
120
|
}
|
|
105
121
|
}
|
|
106
122
|
const details = [...missingKeyErrors, localError].filter(Boolean);
|
|
@@ -126,17 +142,12 @@ export async function createEmbeddingProvider(options) {
|
|
|
126
142
|
};
|
|
127
143
|
}
|
|
128
144
|
catch (fallbackErr) {
|
|
129
|
-
throw new Error(`${reason}\n\nFallback to ${fallback} failed: ${
|
|
145
|
+
throw new Error(`${reason}\n\nFallback to ${fallback} failed: ${formatErrorMessage(fallbackErr)}`, { cause: fallbackErr });
|
|
130
146
|
}
|
|
131
147
|
}
|
|
132
|
-
throw new Error(reason);
|
|
148
|
+
throw new Error(reason, { cause: primaryErr });
|
|
133
149
|
}
|
|
134
150
|
}
|
|
135
|
-
function formatError(err) {
|
|
136
|
-
if (err instanceof Error)
|
|
137
|
-
return err.message;
|
|
138
|
-
return String(err);
|
|
139
|
-
}
|
|
140
151
|
function isNodeLlamaCppMissing(err) {
|
|
141
152
|
if (!(err instanceof Error))
|
|
142
153
|
return false;
|
|
@@ -147,7 +158,7 @@ function isNodeLlamaCppMissing(err) {
|
|
|
147
158
|
return false;
|
|
148
159
|
}
|
|
149
160
|
function formatLocalSetupError(err) {
|
|
150
|
-
const detail =
|
|
161
|
+
const detail = formatErrorMessage(err);
|
|
151
162
|
const missing = isNodeLlamaCppMissing(err);
|
|
152
163
|
return [
|
|
153
164
|
"Local embeddings unavailable.",
|
|
@@ -160,10 +171,11 @@ function formatLocalSetupError(err) {
|
|
|
160
171
|
"To enable local embeddings:",
|
|
161
172
|
"1) Use Node 22 LTS (recommended for installs/updates)",
|
|
162
173
|
missing
|
|
163
|
-
? "2) Reinstall
|
|
174
|
+
? "2) Reinstall Poolbot (this should install node-llama-cpp): npm i -g poolbot@latest"
|
|
164
175
|
: null,
|
|
165
176
|
"3) If you use pnpm: pnpm approve-builds (select node-llama-cpp), then pnpm rebuild node-llama-cpp",
|
|
166
177
|
'Or set agents.defaults.memorySearch.provider = "openai" (remote).',
|
|
178
|
+
'Or set agents.defaults.memorySearch.provider = "voyage" (remote).',
|
|
167
179
|
]
|
|
168
180
|
.filter(Boolean)
|
|
169
181
|
.join("\n");
|