@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
package/dist/memory/internal.js
CHANGED
|
@@ -13,6 +13,16 @@ export function normalizeRelPath(value) {
|
|
|
13
13
|
const trimmed = value.trim().replace(/^[./]+/, "");
|
|
14
14
|
return trimmed.replace(/\\/g, "/");
|
|
15
15
|
}
|
|
16
|
+
export function normalizeExtraMemoryPaths(workspaceDir, extraPaths) {
|
|
17
|
+
if (!extraPaths?.length) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
const resolved = extraPaths
|
|
21
|
+
.map((value) => value.trim())
|
|
22
|
+
.filter(Boolean)
|
|
23
|
+
.map((value) => path.isAbsolute(value) ? path.resolve(value) : path.resolve(workspaceDir, value));
|
|
24
|
+
return Array.from(new Set(resolved));
|
|
25
|
+
}
|
|
16
26
|
export function isMemoryPath(relPath) {
|
|
17
27
|
const normalized = normalizeRelPath(relPath);
|
|
18
28
|
if (!normalized)
|
|
@@ -21,15 +31,6 @@ export function isMemoryPath(relPath) {
|
|
|
21
31
|
return true;
|
|
22
32
|
return normalized.startsWith("memory/");
|
|
23
33
|
}
|
|
24
|
-
async function exists(filePath) {
|
|
25
|
-
try {
|
|
26
|
-
await fs.access(filePath);
|
|
27
|
-
return true;
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
34
|
async function walkDir(dir, files) {
|
|
34
35
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
35
36
|
for (const entry of entries) {
|
|
@@ -45,20 +46,55 @@ async function walkDir(dir, files) {
|
|
|
45
46
|
files.push(full);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
|
-
export async function listMemoryFiles(workspaceDir) {
|
|
49
|
+
export async function listMemoryFiles(workspaceDir, extraPaths) {
|
|
49
50
|
const result = [];
|
|
50
51
|
const memoryFile = path.join(workspaceDir, "MEMORY.md");
|
|
51
52
|
const altMemoryFile = path.join(workspaceDir, "memory.md");
|
|
52
|
-
if (await exists(memoryFile))
|
|
53
|
-
result.push(memoryFile);
|
|
54
|
-
if (await exists(altMemoryFile))
|
|
55
|
-
result.push(altMemoryFile);
|
|
56
53
|
const memoryDir = path.join(workspaceDir, "memory");
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
const addMarkdownFile = async (absPath) => {
|
|
55
|
+
try {
|
|
56
|
+
const stat = await fs.lstat(absPath);
|
|
57
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!absPath.endsWith(".md")) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
result.push(absPath);
|
|
64
|
+
}
|
|
65
|
+
catch { }
|
|
66
|
+
};
|
|
67
|
+
await addMarkdownFile(memoryFile);
|
|
68
|
+
await addMarkdownFile(altMemoryFile);
|
|
69
|
+
try {
|
|
70
|
+
const dirStat = await fs.lstat(memoryDir);
|
|
71
|
+
if (!dirStat.isSymbolicLink() && dirStat.isDirectory()) {
|
|
72
|
+
await walkDir(memoryDir, result);
|
|
73
|
+
}
|
|
59
74
|
}
|
|
60
|
-
|
|
75
|
+
catch { }
|
|
76
|
+
const normalizedExtraPaths = normalizeExtraMemoryPaths(workspaceDir, extraPaths);
|
|
77
|
+
if (normalizedExtraPaths.length > 0) {
|
|
78
|
+
for (const inputPath of normalizedExtraPaths) {
|
|
79
|
+
try {
|
|
80
|
+
const stat = await fs.lstat(inputPath);
|
|
81
|
+
if (stat.isSymbolicLink()) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (stat.isDirectory()) {
|
|
85
|
+
await walkDir(inputPath, result);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (stat.isFile() && inputPath.endsWith(".md")) {
|
|
89
|
+
result.push(inputPath);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (result.length <= 1) {
|
|
61
96
|
return result;
|
|
97
|
+
}
|
|
62
98
|
const seen = new Set();
|
|
63
99
|
const deduped = [];
|
|
64
100
|
for (const entry of result) {
|
|
@@ -67,8 +103,9 @@ export async function listMemoryFiles(workspaceDir) {
|
|
|
67
103
|
key = await fs.realpath(entry);
|
|
68
104
|
}
|
|
69
105
|
catch { }
|
|
70
|
-
if (seen.has(key))
|
|
106
|
+
if (seen.has(key)) {
|
|
71
107
|
continue;
|
|
108
|
+
}
|
|
72
109
|
seen.add(key);
|
|
73
110
|
deduped.push(entry);
|
|
74
111
|
}
|
|
@@ -187,3 +224,49 @@ export function cosineSimilarity(a, b) {
|
|
|
187
224
|
return 0;
|
|
188
225
|
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
189
226
|
}
|
|
227
|
+
export async function runWithConcurrency(tasks, limit) {
|
|
228
|
+
if (tasks.length === 0) {
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));
|
|
232
|
+
const results = Array.from({ length: tasks.length });
|
|
233
|
+
let next = 0;
|
|
234
|
+
let firstError = null;
|
|
235
|
+
const workers = Array.from({ length: resolvedLimit }, async () => {
|
|
236
|
+
while (true) {
|
|
237
|
+
if (firstError) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const index = next;
|
|
241
|
+
next += 1;
|
|
242
|
+
if (index >= tasks.length) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
results[index] = await tasks[index]();
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
firstError = err;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
await Promise.allSettled(workers);
|
|
255
|
+
if (firstError) {
|
|
256
|
+
throw firstError;
|
|
257
|
+
}
|
|
258
|
+
return results;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Remap chunk startLine/endLine using a lineMap from session file building.
|
|
262
|
+
*/
|
|
263
|
+
export function remapChunkLines(chunks, lineMap) {
|
|
264
|
+
if (!lineMap || lineMap.length === 0) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
for (const chunk of chunks) {
|
|
268
|
+
// startLine/endLine are 1-indexed; lineMap is 0-indexed by content line
|
|
269
|
+
chunk.startLine = lineMap[chunk.startLine - 1] ?? chunk.startLine;
|
|
270
|
+
chunk.endLine = lineMap[chunk.endLine - 1] ?? chunk.endLine;
|
|
271
|
+
}
|
|
272
|
+
}
|
package/dist/memory/manager.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
|
+
import fsSync from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import chokidar from "chokidar";
|
|
5
6
|
import { resolveAgentDir, resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
|
|
@@ -11,9 +12,11 @@ import { resolveUserPath } from "../utils.js";
|
|
|
11
12
|
import { createEmbeddingProvider, } from "./embeddings.js";
|
|
12
13
|
import { DEFAULT_GEMINI_EMBEDDING_MODEL } from "./embeddings-gemini.js";
|
|
13
14
|
import { DEFAULT_OPENAI_EMBEDDING_MODEL } from "./embeddings-openai.js";
|
|
15
|
+
import { DEFAULT_VOYAGE_EMBEDDING_MODEL } from "./embeddings-voyage.js";
|
|
14
16
|
import { OPENAI_BATCH_ENDPOINT, runOpenAiEmbeddingBatches, } from "./batch-openai.js";
|
|
15
17
|
import { runGeminiEmbeddingBatches } from "./batch-gemini.js";
|
|
16
|
-
import {
|
|
18
|
+
import { runVoyageEmbeddingBatches } from "./batch-voyage.js";
|
|
19
|
+
import { buildFileEntry, chunkMarkdown, ensureDir, hashText, isMemoryPath, listMemoryFiles, normalizeExtraMemoryPaths, parseEmbedding, remapChunkLines, runWithConcurrency, } from "./internal.js";
|
|
17
20
|
import { bm25RankToScore, buildFtsQuery, mergeHybridResults } from "./hybrid.js";
|
|
18
21
|
import { searchKeyword, searchVector } from "./manager-search.js";
|
|
19
22
|
import { ensureMemoryIndexSchema } from "./memory-schema.js";
|
|
@@ -53,6 +56,7 @@ export class MemoryIndexManager {
|
|
|
53
56
|
fallbackReason;
|
|
54
57
|
openAi;
|
|
55
58
|
gemini;
|
|
59
|
+
voyage;
|
|
56
60
|
batch;
|
|
57
61
|
batchFailureCount = 0;
|
|
58
62
|
batchFailureLastError;
|
|
@@ -120,6 +124,7 @@ export class MemoryIndexManager {
|
|
|
120
124
|
this.fallbackReason = params.providerResult.fallbackReason;
|
|
121
125
|
this.openAi = params.providerResult.openAi;
|
|
122
126
|
this.gemini = params.providerResult.gemini;
|
|
127
|
+
this.voyage = params.providerResult.voyage;
|
|
123
128
|
this.sources = new Set(params.settings.sources);
|
|
124
129
|
this.db = this.openDatabase();
|
|
125
130
|
this.providerKey = this.computeProviderKey();
|
|
@@ -257,13 +262,51 @@ export class MemoryIndexManager {
|
|
|
257
262
|
return this.syncing;
|
|
258
263
|
}
|
|
259
264
|
async readFile(params) {
|
|
260
|
-
const
|
|
261
|
-
if (!
|
|
265
|
+
const rawPath = params.relPath.trim();
|
|
266
|
+
if (!rawPath) {
|
|
262
267
|
throw new Error("path required");
|
|
263
268
|
}
|
|
264
|
-
const absPath = path.
|
|
265
|
-
|
|
266
|
-
|
|
269
|
+
const absPath = path.isAbsolute(rawPath)
|
|
270
|
+
? path.resolve(rawPath)
|
|
271
|
+
: path.resolve(this.workspaceDir, rawPath);
|
|
272
|
+
const relPath = path.relative(this.workspaceDir, absPath).replace(/\\/g, "/");
|
|
273
|
+
const inWorkspace = relPath.length > 0 && !relPath.startsWith("..") && !path.isAbsolute(relPath);
|
|
274
|
+
const allowedWorkspace = inWorkspace && isMemoryPath(relPath);
|
|
275
|
+
let allowedAdditional = false;
|
|
276
|
+
if (!allowedWorkspace && this.settings.extraPaths.length > 0) {
|
|
277
|
+
const additionalPaths = normalizeExtraMemoryPaths(this.workspaceDir, this.settings.extraPaths);
|
|
278
|
+
for (const additionalPath of additionalPaths) {
|
|
279
|
+
try {
|
|
280
|
+
const stat = await fs.lstat(additionalPath);
|
|
281
|
+
if (stat.isSymbolicLink()) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (stat.isDirectory()) {
|
|
285
|
+
if (absPath === additionalPath || absPath.startsWith(`${additionalPath}${path.sep}`)) {
|
|
286
|
+
allowedAdditional = true;
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (stat.isFile()) {
|
|
292
|
+
if (absPath === additionalPath && absPath.endsWith(".md")) {
|
|
293
|
+
allowedAdditional = true;
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch { }
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (!allowedWorkspace && !allowedAdditional) {
|
|
302
|
+
throw new Error("path required");
|
|
303
|
+
}
|
|
304
|
+
if (!absPath.endsWith(".md")) {
|
|
305
|
+
throw new Error("path required");
|
|
306
|
+
}
|
|
307
|
+
const stat = await fs.lstat(absPath);
|
|
308
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
309
|
+
throw new Error("path required");
|
|
267
310
|
}
|
|
268
311
|
const content = await fs.readFile(absPath, "utf-8");
|
|
269
312
|
if (!params.from && !params.lines) {
|
|
@@ -307,18 +350,20 @@ export class MemoryIndexManager {
|
|
|
307
350
|
entry.chunks = row.c ?? 0;
|
|
308
351
|
bySource.set(row.source, entry);
|
|
309
352
|
}
|
|
310
|
-
return sources.map((source) => ({ source,
|
|
353
|
+
return sources.map((source) => Object.assign({ source }, bySource.get(source)));
|
|
311
354
|
})();
|
|
312
355
|
return {
|
|
356
|
+
backend: "builtin",
|
|
313
357
|
files: files?.c ?? 0,
|
|
314
358
|
chunks: chunks?.c ?? 0,
|
|
315
|
-
dirty: this.dirty,
|
|
359
|
+
dirty: this.dirty || this.sessionsDirty,
|
|
316
360
|
workspaceDir: this.workspaceDir,
|
|
317
361
|
dbPath: this.settings.store.path,
|
|
318
362
|
provider: this.provider.id,
|
|
319
363
|
model: this.provider.model,
|
|
320
364
|
requestedProvider: this.requestedProvider,
|
|
321
365
|
sources: Array.from(this.sources),
|
|
366
|
+
extraPaths: this.settings.extraPaths,
|
|
322
367
|
sourceCounts,
|
|
323
368
|
cache: this.cache.enabled
|
|
324
369
|
? {
|
|
@@ -559,13 +604,27 @@ export class MemoryIndexManager {
|
|
|
559
604
|
}
|
|
560
605
|
}
|
|
561
606
|
ensureWatcher() {
|
|
562
|
-
if (!this.sources.has("memory") || !this.settings.sync.watch || this.watcher)
|
|
607
|
+
if (!this.sources.has("memory") || !this.settings.sync.watch || this.watcher) {
|
|
563
608
|
return;
|
|
564
|
-
|
|
609
|
+
}
|
|
610
|
+
const additionalPaths = normalizeExtraMemoryPaths(this.workspaceDir, this.settings.extraPaths)
|
|
611
|
+
.map((entry) => {
|
|
612
|
+
try {
|
|
613
|
+
const stat = fsSync.lstatSync(entry);
|
|
614
|
+
return stat.isSymbolicLink() ? null : entry;
|
|
615
|
+
}
|
|
616
|
+
catch {
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
})
|
|
620
|
+
.filter((entry) => Boolean(entry));
|
|
621
|
+
const watchPaths = new Set([
|
|
565
622
|
path.join(this.workspaceDir, "MEMORY.md"),
|
|
623
|
+
path.join(this.workspaceDir, "memory.md"),
|
|
566
624
|
path.join(this.workspaceDir, "memory"),
|
|
567
|
-
|
|
568
|
-
|
|
625
|
+
...additionalPaths,
|
|
626
|
+
]);
|
|
627
|
+
this.watcher = chokidar.watch(Array.from(watchPaths), {
|
|
569
628
|
ignoreInitial: true,
|
|
570
629
|
awaitWriteFinish: {
|
|
571
630
|
stabilityThreshold: this.settings.sync.watchDebounceMs,
|
|
@@ -764,7 +823,7 @@ export class MemoryIndexManager {
|
|
|
764
823
|
return this.sessionsDirty && this.sessionsDirtyFiles.size > 0;
|
|
765
824
|
}
|
|
766
825
|
async syncMemoryFiles(params) {
|
|
767
|
-
const files = await listMemoryFiles(this.workspaceDir);
|
|
826
|
+
const files = await listMemoryFiles(this.workspaceDir, this.settings.extraPaths);
|
|
768
827
|
const fileEntries = await Promise.all(files.map(async (file) => buildFileEntry(file, this.workspaceDir)));
|
|
769
828
|
log.debug("memory sync: indexing memory files", {
|
|
770
829
|
files: fileEntries.length,
|
|
@@ -804,7 +863,7 @@ export class MemoryIndexManager {
|
|
|
804
863
|
});
|
|
805
864
|
}
|
|
806
865
|
});
|
|
807
|
-
await
|
|
866
|
+
await runWithConcurrency(tasks, this.getIndexConcurrency());
|
|
808
867
|
const staleRows = this.db
|
|
809
868
|
.prepare(`SELECT path FROM files WHERE source = ?`)
|
|
810
869
|
.all("memory");
|
|
@@ -894,7 +953,7 @@ export class MemoryIndexManager {
|
|
|
894
953
|
});
|
|
895
954
|
}
|
|
896
955
|
});
|
|
897
|
-
await
|
|
956
|
+
await runWithConcurrency(tasks, this.getIndexConcurrency());
|
|
898
957
|
const staleRows = this.db
|
|
899
958
|
.prepare(`SELECT path FROM files WHERE source = ?`)
|
|
900
959
|
.all("sessions");
|
|
@@ -1010,7 +1069,8 @@ export class MemoryIndexManager {
|
|
|
1010
1069
|
const batch = this.settings.remote?.batch;
|
|
1011
1070
|
const enabled = Boolean(batch?.enabled &&
|
|
1012
1071
|
((this.openAi && this.provider.id === "openai") ||
|
|
1013
|
-
(this.gemini && this.provider.id === "gemini")
|
|
1072
|
+
(this.gemini && this.provider.id === "gemini") ||
|
|
1073
|
+
(this.voyage && this.provider.id === "voyage")));
|
|
1014
1074
|
return {
|
|
1015
1075
|
enabled,
|
|
1016
1076
|
wait: batch?.wait ?? true,
|
|
@@ -1030,7 +1090,9 @@ export class MemoryIndexManager {
|
|
|
1030
1090
|
? DEFAULT_GEMINI_EMBEDDING_MODEL
|
|
1031
1091
|
: fallback === "openai"
|
|
1032
1092
|
? DEFAULT_OPENAI_EMBEDDING_MODEL
|
|
1033
|
-
:
|
|
1093
|
+
: fallback === "voyage"
|
|
1094
|
+
? DEFAULT_VOYAGE_EMBEDDING_MODEL
|
|
1095
|
+
: this.settings.model;
|
|
1034
1096
|
const fallbackResult = await createEmbeddingProvider({
|
|
1035
1097
|
config: this.cfg,
|
|
1036
1098
|
agentDir: resolveAgentDir(this.cfg, this.agentId),
|
|
@@ -1045,6 +1107,7 @@ export class MemoryIndexManager {
|
|
|
1045
1107
|
this.provider = fallbackResult.provider;
|
|
1046
1108
|
this.openAi = fallbackResult.openAi;
|
|
1047
1109
|
this.gemini = fallbackResult.gemini;
|
|
1110
|
+
this.voyage = fallbackResult.voyage;
|
|
1048
1111
|
this.providerKey = this.computeProviderKey();
|
|
1049
1112
|
this.batch = this.resolveBatchConfig();
|
|
1050
1113
|
log.warn(`memory embeddings: switched to fallback provider (${fallback})`, { reason });
|
|
@@ -1401,7 +1464,7 @@ export class MemoryIndexManager {
|
|
|
1401
1464
|
if (this.provider.id === "openai" && this.openAi) {
|
|
1402
1465
|
const entries = Object.entries(this.openAi.headers)
|
|
1403
1466
|
.filter(([key]) => key.toLowerCase() !== "authorization")
|
|
1404
|
-
.
|
|
1467
|
+
.toSorted(([a], [b]) => a.localeCompare(b))
|
|
1405
1468
|
.map(([key, value]) => [key, value]);
|
|
1406
1469
|
return hashText(JSON.stringify({
|
|
1407
1470
|
provider: "openai",
|
|
@@ -1416,7 +1479,7 @@ export class MemoryIndexManager {
|
|
|
1416
1479
|
const lower = key.toLowerCase();
|
|
1417
1480
|
return lower !== "authorization" && lower !== "x-goog-api-key";
|
|
1418
1481
|
})
|
|
1419
|
-
.
|
|
1482
|
+
.toSorted(([a], [b]) => a.localeCompare(b))
|
|
1420
1483
|
.map(([key, value]) => [key, value]);
|
|
1421
1484
|
return hashText(JSON.stringify({
|
|
1422
1485
|
provider: "gemini",
|
|
@@ -1434,8 +1497,78 @@ export class MemoryIndexManager {
|
|
|
1434
1497
|
if (this.provider.id === "gemini" && this.gemini) {
|
|
1435
1498
|
return this.embedChunksWithGeminiBatch(chunks, entry, source);
|
|
1436
1499
|
}
|
|
1500
|
+
if (this.provider.id === "voyage" && this.voyage) {
|
|
1501
|
+
return this.embedChunksWithVoyageBatch(chunks, entry, source);
|
|
1502
|
+
}
|
|
1437
1503
|
return this.embedChunksInBatches(chunks);
|
|
1438
1504
|
}
|
|
1505
|
+
async embedChunksWithVoyageBatch(chunks, entry, source) {
|
|
1506
|
+
const voyage = this.voyage;
|
|
1507
|
+
if (!voyage) {
|
|
1508
|
+
return this.embedChunksInBatches(chunks);
|
|
1509
|
+
}
|
|
1510
|
+
if (chunks.length === 0) {
|
|
1511
|
+
return [];
|
|
1512
|
+
}
|
|
1513
|
+
const cached = this.loadEmbeddingCache(chunks.map((chunk) => chunk.hash));
|
|
1514
|
+
const embeddings = Array.from({ length: chunks.length }, () => []);
|
|
1515
|
+
const missing = [];
|
|
1516
|
+
for (let i = 0; i < chunks.length; i += 1) {
|
|
1517
|
+
const chunk = chunks[i];
|
|
1518
|
+
const hit = chunk?.hash ? cached.get(chunk.hash) : undefined;
|
|
1519
|
+
if (hit && hit.length > 0) {
|
|
1520
|
+
embeddings[i] = hit;
|
|
1521
|
+
}
|
|
1522
|
+
else if (chunk) {
|
|
1523
|
+
missing.push({ index: i, chunk });
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
if (missing.length === 0) {
|
|
1527
|
+
return embeddings;
|
|
1528
|
+
}
|
|
1529
|
+
const requests = [];
|
|
1530
|
+
const mapping = new Map();
|
|
1531
|
+
for (const item of missing) {
|
|
1532
|
+
const chunk = item.chunk;
|
|
1533
|
+
const customId = hashText(`${source}:${entry.path}:${chunk.startLine}:${chunk.endLine}:${chunk.hash}:${item.index}`);
|
|
1534
|
+
mapping.set(customId, { index: item.index, hash: chunk.hash });
|
|
1535
|
+
requests.push({
|
|
1536
|
+
custom_id: customId,
|
|
1537
|
+
body: {
|
|
1538
|
+
input: chunk.text,
|
|
1539
|
+
},
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
const batchResult = await this.runBatchWithFallback({
|
|
1543
|
+
provider: "voyage",
|
|
1544
|
+
run: async () => await runVoyageEmbeddingBatches({
|
|
1545
|
+
client: voyage,
|
|
1546
|
+
agentId: this.agentId,
|
|
1547
|
+
requests,
|
|
1548
|
+
wait: this.batch.wait,
|
|
1549
|
+
concurrency: this.batch.concurrency,
|
|
1550
|
+
pollIntervalMs: this.batch.pollIntervalMs,
|
|
1551
|
+
timeoutMs: this.batch.timeoutMs,
|
|
1552
|
+
debug: (message, data) => log.debug(message, { ...data, source, chunks: chunks.length }),
|
|
1553
|
+
}),
|
|
1554
|
+
fallback: async () => await this.embedChunksInBatches(chunks),
|
|
1555
|
+
});
|
|
1556
|
+
if (Array.isArray(batchResult)) {
|
|
1557
|
+
return batchResult;
|
|
1558
|
+
}
|
|
1559
|
+
const byCustomId = batchResult;
|
|
1560
|
+
const toCache = [];
|
|
1561
|
+
for (const [customId, embedding] of byCustomId.entries()) {
|
|
1562
|
+
const mapped = mapping.get(customId);
|
|
1563
|
+
if (!mapped) {
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1566
|
+
embeddings[mapped.index] = embedding;
|
|
1567
|
+
toCache.push({ hash: mapped.hash, embedding });
|
|
1568
|
+
}
|
|
1569
|
+
this.upsertEmbeddingCache(toCache);
|
|
1570
|
+
return embeddings;
|
|
1571
|
+
}
|
|
1439
1572
|
async embedChunksWithOpenAiBatch(chunks, entry, source) {
|
|
1440
1573
|
const openAi = this.openAi;
|
|
1441
1574
|
if (!openAi) {
|
|
@@ -1622,35 +1755,6 @@ export class MemoryIndexManager {
|
|
|
1622
1755
|
clearTimeout(timer);
|
|
1623
1756
|
}
|
|
1624
1757
|
}
|
|
1625
|
-
async runWithConcurrency(tasks, limit) {
|
|
1626
|
-
if (tasks.length === 0)
|
|
1627
|
-
return [];
|
|
1628
|
-
const resolvedLimit = Math.max(1, Math.min(limit, tasks.length));
|
|
1629
|
-
const results = Array.from({ length: tasks.length });
|
|
1630
|
-
let next = 0;
|
|
1631
|
-
let firstError = null;
|
|
1632
|
-
const workers = Array.from({ length: resolvedLimit }, async () => {
|
|
1633
|
-
while (true) {
|
|
1634
|
-
if (firstError)
|
|
1635
|
-
return;
|
|
1636
|
-
const index = next;
|
|
1637
|
-
next += 1;
|
|
1638
|
-
if (index >= tasks.length)
|
|
1639
|
-
return;
|
|
1640
|
-
try {
|
|
1641
|
-
results[index] = await tasks[index]();
|
|
1642
|
-
}
|
|
1643
|
-
catch (err) {
|
|
1644
|
-
firstError = err;
|
|
1645
|
-
return;
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
});
|
|
1649
|
-
await Promise.allSettled(workers);
|
|
1650
|
-
if (firstError)
|
|
1651
|
-
throw firstError;
|
|
1652
|
-
return results;
|
|
1653
|
-
}
|
|
1654
1758
|
async withBatchFailureLock(fn) {
|
|
1655
1759
|
let release;
|
|
1656
1760
|
const wait = this.batchFailureLock;
|
|
@@ -1748,6 +1852,9 @@ export class MemoryIndexManager {
|
|
|
1748
1852
|
async indexFile(entry, options) {
|
|
1749
1853
|
const content = options.content ?? (await fs.readFile(entry.absPath, "utf-8"));
|
|
1750
1854
|
const chunks = chunkMarkdown(content, this.settings.chunking).filter((chunk) => chunk.text.trim().length > 0);
|
|
1855
|
+
if (options.source === "sessions" && "lineMap" in entry) {
|
|
1856
|
+
remapChunkLines(chunks, entry.lineMap);
|
|
1857
|
+
}
|
|
1751
1858
|
const embeddings = this.batch.enabled
|
|
1752
1859
|
? await this.embedChunksWithBatch(chunks, entry, options.source)
|
|
1753
1860
|
: await this.embedChunksInBatches(chunks);
|
|
@@ -1,4 +1,40 @@
|
|
|
1
|
+
import { createSubsystemLogger } from "../logging/subsystem.js";
|
|
2
|
+
import { resolveMemoryBackendConfig } from "./backend-config.js";
|
|
3
|
+
const log = createSubsystemLogger("memory");
|
|
4
|
+
const QMD_MANAGER_CACHE = new Map();
|
|
1
5
|
export async function getMemorySearchManager(params) {
|
|
6
|
+
const resolved = resolveMemoryBackendConfig(params);
|
|
7
|
+
if (resolved.backend === "qmd" && resolved.qmd) {
|
|
8
|
+
const cacheKey = buildQmdCacheKey(params.agentId, resolved.qmd);
|
|
9
|
+
const cached = QMD_MANAGER_CACHE.get(cacheKey);
|
|
10
|
+
if (cached) {
|
|
11
|
+
return { manager: cached };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
// @ts-expect-error qmd-manager is an optional module that may not exist at build time
|
|
15
|
+
const { QmdMemoryManager } = await import("./qmd-manager.js");
|
|
16
|
+
const primary = await QmdMemoryManager.create({
|
|
17
|
+
cfg: params.cfg,
|
|
18
|
+
agentId: params.agentId,
|
|
19
|
+
resolved,
|
|
20
|
+
});
|
|
21
|
+
if (primary) {
|
|
22
|
+
const wrapper = new FallbackMemoryManager({
|
|
23
|
+
primary,
|
|
24
|
+
fallbackFactory: async () => {
|
|
25
|
+
const { MemoryIndexManager } = await import("./manager.js");
|
|
26
|
+
return await MemoryIndexManager.get(params);
|
|
27
|
+
},
|
|
28
|
+
}, () => QMD_MANAGER_CACHE.delete(cacheKey));
|
|
29
|
+
QMD_MANAGER_CACHE.set(cacheKey, wrapper);
|
|
30
|
+
return { manager: wrapper };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
35
|
+
log.warn(`qmd memory unavailable; falling back to builtin: ${message}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
2
38
|
try {
|
|
3
39
|
const { MemoryIndexManager } = await import("./manager.js");
|
|
4
40
|
const manager = await MemoryIndexManager.get(params);
|
|
@@ -9,3 +45,140 @@ export async function getMemorySearchManager(params) {
|
|
|
9
45
|
return { manager: null, error: message };
|
|
10
46
|
}
|
|
11
47
|
}
|
|
48
|
+
class FallbackMemoryManager {
|
|
49
|
+
deps;
|
|
50
|
+
onClose;
|
|
51
|
+
fallback = null;
|
|
52
|
+
primaryFailed = false;
|
|
53
|
+
lastError;
|
|
54
|
+
cacheEvicted = false;
|
|
55
|
+
constructor(deps, onClose) {
|
|
56
|
+
this.deps = deps;
|
|
57
|
+
this.onClose = onClose;
|
|
58
|
+
}
|
|
59
|
+
async search(query, opts) {
|
|
60
|
+
if (!this.primaryFailed) {
|
|
61
|
+
try {
|
|
62
|
+
return await this.deps.primary.search(query, opts);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
this.primaryFailed = true;
|
|
66
|
+
this.lastError = err instanceof Error ? err.message : String(err);
|
|
67
|
+
log.warn(`qmd memory failed; switching to builtin index: ${this.lastError}`);
|
|
68
|
+
await this.deps.primary.close?.().catch(() => { });
|
|
69
|
+
// Evict the failed wrapper so the next request can retry QMD with a fresh manager.
|
|
70
|
+
this.evictCacheEntry();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const fallback = await this.ensureFallback();
|
|
74
|
+
if (fallback) {
|
|
75
|
+
return await fallback.search(query, opts);
|
|
76
|
+
}
|
|
77
|
+
throw new Error(this.lastError ?? "memory search unavailable");
|
|
78
|
+
}
|
|
79
|
+
async readFile(params) {
|
|
80
|
+
if (!this.primaryFailed) {
|
|
81
|
+
return await this.deps.primary.readFile(params);
|
|
82
|
+
}
|
|
83
|
+
const fallback = await this.ensureFallback();
|
|
84
|
+
if (fallback) {
|
|
85
|
+
return await fallback.readFile(params);
|
|
86
|
+
}
|
|
87
|
+
throw new Error(this.lastError ?? "memory read unavailable");
|
|
88
|
+
}
|
|
89
|
+
status() {
|
|
90
|
+
if (!this.primaryFailed) {
|
|
91
|
+
return this.deps.primary.status();
|
|
92
|
+
}
|
|
93
|
+
const fallbackStatus = this.fallback?.status();
|
|
94
|
+
const fallbackInfo = { from: "qmd", reason: this.lastError ?? "unknown" };
|
|
95
|
+
if (fallbackStatus) {
|
|
96
|
+
const custom = fallbackStatus.custom ?? {};
|
|
97
|
+
return {
|
|
98
|
+
...fallbackStatus,
|
|
99
|
+
fallback: fallbackInfo,
|
|
100
|
+
custom: {
|
|
101
|
+
...custom,
|
|
102
|
+
fallback: { disabled: true, reason: this.lastError ?? "unknown" },
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
const primaryStatus = this.deps.primary.status();
|
|
107
|
+
const custom = primaryStatus.custom ?? {};
|
|
108
|
+
return {
|
|
109
|
+
...primaryStatus,
|
|
110
|
+
fallback: fallbackInfo,
|
|
111
|
+
custom: {
|
|
112
|
+
...custom,
|
|
113
|
+
fallback: { disabled: true, reason: this.lastError ?? "unknown" },
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
async sync(params) {
|
|
118
|
+
if (!this.primaryFailed) {
|
|
119
|
+
await this.deps.primary.sync?.(params);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const fallback = await this.ensureFallback();
|
|
123
|
+
await fallback?.sync?.(params);
|
|
124
|
+
}
|
|
125
|
+
async probeEmbeddingAvailability() {
|
|
126
|
+
if (!this.primaryFailed) {
|
|
127
|
+
return await this.deps.primary.probeEmbeddingAvailability();
|
|
128
|
+
}
|
|
129
|
+
const fallback = await this.ensureFallback();
|
|
130
|
+
if (fallback) {
|
|
131
|
+
return await fallback.probeEmbeddingAvailability();
|
|
132
|
+
}
|
|
133
|
+
return { ok: false, error: this.lastError ?? "memory embeddings unavailable" };
|
|
134
|
+
}
|
|
135
|
+
async probeVectorAvailability() {
|
|
136
|
+
if (!this.primaryFailed) {
|
|
137
|
+
return await this.deps.primary.probeVectorAvailability();
|
|
138
|
+
}
|
|
139
|
+
const fallback = await this.ensureFallback();
|
|
140
|
+
return (await fallback?.probeVectorAvailability()) ?? false;
|
|
141
|
+
}
|
|
142
|
+
async close() {
|
|
143
|
+
await this.deps.primary.close?.();
|
|
144
|
+
await this.fallback?.close?.();
|
|
145
|
+
this.evictCacheEntry();
|
|
146
|
+
}
|
|
147
|
+
async ensureFallback() {
|
|
148
|
+
if (this.fallback) {
|
|
149
|
+
return this.fallback;
|
|
150
|
+
}
|
|
151
|
+
const fallback = await this.deps.fallbackFactory();
|
|
152
|
+
if (!fallback) {
|
|
153
|
+
log.warn("memory fallback requested but builtin index is unavailable");
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
this.fallback = fallback;
|
|
157
|
+
return this.fallback;
|
|
158
|
+
}
|
|
159
|
+
evictCacheEntry() {
|
|
160
|
+
if (this.cacheEvicted) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
this.cacheEvicted = true;
|
|
164
|
+
this.onClose?.();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function buildQmdCacheKey(agentId, config) {
|
|
168
|
+
return `${agentId}:${stableSerialize(config)}`;
|
|
169
|
+
}
|
|
170
|
+
function stableSerialize(value) {
|
|
171
|
+
return JSON.stringify(sortValue(value));
|
|
172
|
+
}
|
|
173
|
+
function sortValue(value) {
|
|
174
|
+
if (Array.isArray(value)) {
|
|
175
|
+
return value.map((entry) => sortValue(entry));
|
|
176
|
+
}
|
|
177
|
+
if (value && typeof value === "object") {
|
|
178
|
+
const sortedEntries = Object.keys(value)
|
|
179
|
+
.toSorted((a, b) => a.localeCompare(b))
|
|
180
|
+
.map((key) => [key, sortValue(value[key])]);
|
|
181
|
+
return Object.fromEntries(sortedEntries);
|
|
182
|
+
}
|
|
183
|
+
return value;
|
|
184
|
+
}
|