@poolzin/pool-bot 2026.2.20 → 2026.2.22
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/CHANGELOG.md +25 -0
- package/dist/agents/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-auth.js +12 -0
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-fallback.js +24 -0
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -80
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/provider/config-loader.js +76 -0
- package/dist/agents/provider/index.js +15 -0
- package/dist/agents/provider/integration.js +136 -0
- package/dist/agents/provider/models-dev.js +129 -0
- package/dist/agents/provider/rate-limits.js +458 -0
- package/dist/agents/provider/request-monitor.js +449 -0
- package/dist/agents/provider/session-binding.js +376 -0
- package/dist/agents/provider/token-pool.js +541 -0
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/plcode-controller/SKILL.md +156 -0
- package/skills/plcode-controller/assets/operator-prompts.md +65 -0
- package/skills/plcode-controller/references/command-cheatsheet.md +53 -0
- package/skills/plcode-controller/references/failure-handling.md +60 -0
- package/skills/plcode-controller/references/model-selection.md +57 -0
- package/skills/plcode-controller/references/plan-vs-build.md +52 -0
- package/skills/plcode-controller/references/question-handling.md +40 -0
- package/skills/plcode-controller/references/session-management.md +63 -0
- package/skills/plcode-controller/references/workflow.md +35 -0
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
|
@@ -2,18 +2,18 @@ import { constants as fsConstants } from "node:fs";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveApiKeyForProvider } from "../agents/model-auth.js";
|
|
6
6
|
import { findModelInCatalog, loadModelCatalog, modelSupportsVision, } from "../agents/model-catalog.js";
|
|
7
|
-
import { applyTemplate } from "../auto-reply/templating.js";
|
|
8
7
|
import { logVerbose, shouldLogVerbose } from "../globals.js";
|
|
9
8
|
import { runExec } from "../process/exec.js";
|
|
10
9
|
import { MediaAttachmentCache, normalizeAttachments, selectAttachments } from "./attachments.js";
|
|
11
|
-
import { AUTO_AUDIO_KEY_PROVIDERS, AUTO_IMAGE_KEY_PROVIDERS, AUTO_VIDEO_KEY_PROVIDERS,
|
|
12
|
-
import { isMediaUnderstandingSkipError
|
|
13
|
-
import {
|
|
10
|
+
import { AUTO_AUDIO_KEY_PROVIDERS, AUTO_IMAGE_KEY_PROVIDERS, AUTO_VIDEO_KEY_PROVIDERS, DEFAULT_IMAGE_MODELS, } from "./defaults.js";
|
|
11
|
+
import { isMediaUnderstandingSkipError } from "./errors.js";
|
|
12
|
+
import { fileExists } from "./fs.js";
|
|
13
|
+
import { extractGeminiResponse } from "./output-extract.js";
|
|
14
14
|
import { buildMediaUnderstandingRegistry, getMediaUnderstandingProvider, normalizeMediaProviderId, } from "./providers/index.js";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { resolveModelEntries, resolveScopeDecision } from "./resolve.js";
|
|
16
|
+
import { buildModelDecision, formatDecisionSummary, runCliEntry, runProviderEntry, } from "./runner.entries.js";
|
|
17
17
|
export function buildProviderRegistry(overrides) {
|
|
18
18
|
return buildMediaUnderstandingRegistry(overrides);
|
|
19
19
|
}
|
|
@@ -25,6 +25,10 @@ export function createMediaAttachmentCache(attachments) {
|
|
|
25
25
|
}
|
|
26
26
|
const binaryCache = new Map();
|
|
27
27
|
const geminiProbeCache = new Map();
|
|
28
|
+
export function clearMediaUnderstandingBinaryCacheForTests() {
|
|
29
|
+
binaryCache.clear();
|
|
30
|
+
geminiProbeCache.clear();
|
|
31
|
+
}
|
|
28
32
|
function expandHomeDir(value) {
|
|
29
33
|
if (!value.startsWith("~")) {
|
|
30
34
|
return value;
|
|
@@ -113,85 +117,6 @@ async function findBinary(name) {
|
|
|
113
117
|
async function hasBinary(name) {
|
|
114
118
|
return Boolean(await findBinary(name));
|
|
115
119
|
}
|
|
116
|
-
async function fileExists(filePath) {
|
|
117
|
-
if (!filePath) {
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
try {
|
|
121
|
-
await fs.stat(filePath);
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function extractLastJsonObject(raw) {
|
|
129
|
-
const trimmed = raw.trim();
|
|
130
|
-
const start = trimmed.lastIndexOf("{");
|
|
131
|
-
if (start === -1) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
const slice = trimmed.slice(start);
|
|
135
|
-
try {
|
|
136
|
-
return JSON.parse(slice);
|
|
137
|
-
}
|
|
138
|
-
catch {
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
function extractGeminiResponse(raw) {
|
|
143
|
-
const payload = extractLastJsonObject(raw);
|
|
144
|
-
if (!payload || typeof payload !== "object") {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
const response = payload.response;
|
|
148
|
-
if (typeof response !== "string") {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
const trimmed = response.trim();
|
|
152
|
-
return trimmed || null;
|
|
153
|
-
}
|
|
154
|
-
function extractSherpaOnnxText(raw) {
|
|
155
|
-
const tryParse = (value) => {
|
|
156
|
-
const trimmed = value.trim();
|
|
157
|
-
if (!trimmed) {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
const head = trimmed[0];
|
|
161
|
-
if (head !== "{" && head !== '"') {
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
const parsed = JSON.parse(trimmed);
|
|
166
|
-
if (typeof parsed === "string") {
|
|
167
|
-
return tryParse(parsed);
|
|
168
|
-
}
|
|
169
|
-
if (parsed && typeof parsed === "object") {
|
|
170
|
-
const text = parsed.text;
|
|
171
|
-
if (typeof text === "string" && text.trim()) {
|
|
172
|
-
return text.trim();
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
catch { }
|
|
177
|
-
return null;
|
|
178
|
-
};
|
|
179
|
-
const direct = tryParse(raw);
|
|
180
|
-
if (direct) {
|
|
181
|
-
return direct;
|
|
182
|
-
}
|
|
183
|
-
const lines = raw
|
|
184
|
-
.split("\n")
|
|
185
|
-
.map((line) => line.trim())
|
|
186
|
-
.filter(Boolean);
|
|
187
|
-
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
188
|
-
const parsed = tryParse(lines[i] ?? "");
|
|
189
|
-
if (parsed) {
|
|
190
|
-
return parsed;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
120
|
async function probeGeminiCli() {
|
|
196
121
|
const cached = geminiProbeCache.get("gemini");
|
|
197
122
|
if (cached) {
|
|
@@ -388,6 +313,41 @@ async function resolveKeyEntry(params) {
|
|
|
388
313
|
}
|
|
389
314
|
return null;
|
|
390
315
|
}
|
|
316
|
+
function resolveImageModelFromAgentDefaults(cfg) {
|
|
317
|
+
const imageModel = cfg.agents?.defaults?.imageModel;
|
|
318
|
+
if (!imageModel) {
|
|
319
|
+
return [];
|
|
320
|
+
}
|
|
321
|
+
const refs = [];
|
|
322
|
+
if (typeof imageModel === "string") {
|
|
323
|
+
if (imageModel.trim()) {
|
|
324
|
+
refs.push(imageModel.trim());
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
if (imageModel.primary?.trim()) {
|
|
329
|
+
refs.push(imageModel.primary.trim());
|
|
330
|
+
}
|
|
331
|
+
for (const fb of imageModel.fallbacks ?? []) {
|
|
332
|
+
if (fb?.trim()) {
|
|
333
|
+
refs.push(fb.trim());
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const entries = [];
|
|
338
|
+
for (const ref of refs) {
|
|
339
|
+
const slashIdx = ref.indexOf("/");
|
|
340
|
+
if (slashIdx <= 0 || slashIdx >= ref.length - 1) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
entries.push({
|
|
344
|
+
type: "provider",
|
|
345
|
+
provider: ref.slice(0, slashIdx),
|
|
346
|
+
model: ref.slice(slashIdx + 1),
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return entries;
|
|
350
|
+
}
|
|
391
351
|
async function resolveAutoEntries(params) {
|
|
392
352
|
const activeEntry = await resolveActiveModelEntry(params);
|
|
393
353
|
if (activeEntry) {
|
|
@@ -399,6 +359,12 @@ async function resolveAutoEntries(params) {
|
|
|
399
359
|
return [localAudio];
|
|
400
360
|
}
|
|
401
361
|
}
|
|
362
|
+
if (params.capability === "image") {
|
|
363
|
+
const imageModelEntries = resolveImageModelFromAgentDefaults(params.cfg);
|
|
364
|
+
if (imageModelEntries.length > 0) {
|
|
365
|
+
return imageModelEntries;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
402
368
|
const gemini = await resolveGeminiCliEntry(params.capability);
|
|
403
369
|
if (gemini) {
|
|
404
370
|
return [gemini];
|
|
@@ -477,413 +443,12 @@ async function resolveActiveModelEntry(params) {
|
|
|
477
443
|
catch {
|
|
478
444
|
return null;
|
|
479
445
|
}
|
|
480
|
-
// Use the default vision/video model for the provider rather than the
|
|
481
|
-
// user's chat model — the chat model (e.g. glm-4.7) may not support
|
|
482
|
-
// vision, while the provider has a dedicated model (e.g. glm-4.6v).
|
|
483
|
-
const model = params.capability === "image"
|
|
484
|
-
? (DEFAULT_IMAGE_MODELS[providerId] ?? params.activeModel?.model)
|
|
485
|
-
: params.capability === "audio"
|
|
486
|
-
? (DEFAULT_AUDIO_MODELS[providerId] ?? params.activeModel?.model)
|
|
487
|
-
: params.activeModel?.model;
|
|
488
446
|
return {
|
|
489
447
|
type: "provider",
|
|
490
448
|
provider: providerId,
|
|
491
|
-
model,
|
|
449
|
+
model: params.activeModel?.model,
|
|
492
450
|
};
|
|
493
451
|
}
|
|
494
|
-
function trimOutput(text, maxChars) {
|
|
495
|
-
const trimmed = text.trim();
|
|
496
|
-
if (!maxChars || trimmed.length <= maxChars) {
|
|
497
|
-
return trimmed;
|
|
498
|
-
}
|
|
499
|
-
return trimmed.slice(0, maxChars).trim();
|
|
500
|
-
}
|
|
501
|
-
function commandBase(command) {
|
|
502
|
-
return path.parse(command).name;
|
|
503
|
-
}
|
|
504
|
-
function findArgValue(args, keys) {
|
|
505
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
506
|
-
if (keys.includes(args[i] ?? "")) {
|
|
507
|
-
const value = args[i + 1];
|
|
508
|
-
if (value) {
|
|
509
|
-
return value;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
return undefined;
|
|
514
|
-
}
|
|
515
|
-
function hasArg(args, keys) {
|
|
516
|
-
return args.some((arg) => keys.includes(arg));
|
|
517
|
-
}
|
|
518
|
-
function resolveWhisperOutputPath(args, mediaPath) {
|
|
519
|
-
const outputDir = findArgValue(args, ["--output_dir", "-o"]);
|
|
520
|
-
const outputFormat = findArgValue(args, ["--output_format"]);
|
|
521
|
-
if (!outputDir || !outputFormat) {
|
|
522
|
-
return null;
|
|
523
|
-
}
|
|
524
|
-
const formats = outputFormat.split(",").map((value) => value.trim());
|
|
525
|
-
if (!formats.includes("txt")) {
|
|
526
|
-
return null;
|
|
527
|
-
}
|
|
528
|
-
const base = path.parse(mediaPath).name;
|
|
529
|
-
return path.join(outputDir, `${base}.txt`);
|
|
530
|
-
}
|
|
531
|
-
function resolveWhisperCppOutputPath(args) {
|
|
532
|
-
if (!hasArg(args, ["-otxt", "--output-txt"])) {
|
|
533
|
-
return null;
|
|
534
|
-
}
|
|
535
|
-
const outputBase = findArgValue(args, ["-of", "--output-file"]);
|
|
536
|
-
if (!outputBase) {
|
|
537
|
-
return null;
|
|
538
|
-
}
|
|
539
|
-
return `${outputBase}.txt`;
|
|
540
|
-
}
|
|
541
|
-
async function resolveCliOutput(params) {
|
|
542
|
-
const commandId = commandBase(params.command);
|
|
543
|
-
const fileOutput = commandId === "whisper-cli"
|
|
544
|
-
? resolveWhisperCppOutputPath(params.args)
|
|
545
|
-
: commandId === "whisper"
|
|
546
|
-
? resolveWhisperOutputPath(params.args, params.mediaPath)
|
|
547
|
-
: null;
|
|
548
|
-
if (fileOutput && (await fileExists(fileOutput))) {
|
|
549
|
-
try {
|
|
550
|
-
const content = await fs.readFile(fileOutput, "utf8");
|
|
551
|
-
if (content.trim()) {
|
|
552
|
-
return content.trim();
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
catch { }
|
|
556
|
-
}
|
|
557
|
-
if (commandId === "gemini") {
|
|
558
|
-
const response = extractGeminiResponse(params.stdout);
|
|
559
|
-
if (response) {
|
|
560
|
-
return response;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
if (commandId === "sherpa-onnx-offline") {
|
|
564
|
-
const response = extractSherpaOnnxText(params.stdout);
|
|
565
|
-
if (response) {
|
|
566
|
-
return response;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
return params.stdout.trim();
|
|
570
|
-
}
|
|
571
|
-
function normalizeProviderQuery(options) {
|
|
572
|
-
if (!options) {
|
|
573
|
-
return undefined;
|
|
574
|
-
}
|
|
575
|
-
const query = {};
|
|
576
|
-
for (const [key, value] of Object.entries(options)) {
|
|
577
|
-
if (value === undefined) {
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
query[key] = value;
|
|
581
|
-
}
|
|
582
|
-
return Object.keys(query).length > 0 ? query : undefined;
|
|
583
|
-
}
|
|
584
|
-
function buildDeepgramCompatQuery(options) {
|
|
585
|
-
if (!options) {
|
|
586
|
-
return undefined;
|
|
587
|
-
}
|
|
588
|
-
const query = {};
|
|
589
|
-
if (typeof options.detectLanguage === "boolean") {
|
|
590
|
-
query.detect_language = options.detectLanguage;
|
|
591
|
-
}
|
|
592
|
-
if (typeof options.punctuate === "boolean") {
|
|
593
|
-
query.punctuate = options.punctuate;
|
|
594
|
-
}
|
|
595
|
-
if (typeof options.smartFormat === "boolean") {
|
|
596
|
-
query.smart_format = options.smartFormat;
|
|
597
|
-
}
|
|
598
|
-
return Object.keys(query).length > 0 ? query : undefined;
|
|
599
|
-
}
|
|
600
|
-
function normalizeDeepgramQueryKeys(query) {
|
|
601
|
-
const normalized = { ...query };
|
|
602
|
-
if ("detectLanguage" in normalized) {
|
|
603
|
-
normalized.detect_language = normalized.detectLanguage;
|
|
604
|
-
delete normalized.detectLanguage;
|
|
605
|
-
}
|
|
606
|
-
if ("smartFormat" in normalized) {
|
|
607
|
-
normalized.smart_format = normalized.smartFormat;
|
|
608
|
-
delete normalized.smartFormat;
|
|
609
|
-
}
|
|
610
|
-
return normalized;
|
|
611
|
-
}
|
|
612
|
-
function resolveProviderQuery(params) {
|
|
613
|
-
const { providerId, config, entry } = params;
|
|
614
|
-
const mergedOptions = normalizeProviderQuery({
|
|
615
|
-
...config?.providerOptions?.[providerId],
|
|
616
|
-
...entry.providerOptions?.[providerId],
|
|
617
|
-
});
|
|
618
|
-
if (providerId !== "deepgram") {
|
|
619
|
-
return mergedOptions;
|
|
620
|
-
}
|
|
621
|
-
let query = normalizeDeepgramQueryKeys(mergedOptions ?? {});
|
|
622
|
-
const compat = buildDeepgramCompatQuery({ ...config?.deepgram, ...entry.deepgram });
|
|
623
|
-
for (const [key, value] of Object.entries(compat ?? {})) {
|
|
624
|
-
if (query[key] === undefined) {
|
|
625
|
-
query[key] = value;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
return Object.keys(query).length > 0 ? query : undefined;
|
|
629
|
-
}
|
|
630
|
-
function buildModelDecision(params) {
|
|
631
|
-
if (params.entryType === "cli") {
|
|
632
|
-
const command = params.entry.command?.trim();
|
|
633
|
-
return {
|
|
634
|
-
type: "cli",
|
|
635
|
-
provider: command ?? "cli",
|
|
636
|
-
model: params.entry.model ?? command,
|
|
637
|
-
outcome: params.outcome,
|
|
638
|
-
reason: params.reason,
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
const providerIdRaw = params.entry.provider?.trim();
|
|
642
|
-
const providerId = providerIdRaw ? normalizeMediaProviderId(providerIdRaw) : undefined;
|
|
643
|
-
return {
|
|
644
|
-
type: "provider",
|
|
645
|
-
provider: providerId ?? providerIdRaw,
|
|
646
|
-
model: params.entry.model,
|
|
647
|
-
outcome: params.outcome,
|
|
648
|
-
reason: params.reason,
|
|
649
|
-
};
|
|
650
|
-
}
|
|
651
|
-
function formatDecisionSummary(decision) {
|
|
652
|
-
const total = decision.attachments.length;
|
|
653
|
-
const success = decision.attachments.filter((entry) => entry.chosen?.outcome === "success").length;
|
|
654
|
-
const chosen = decision.attachments.find((entry) => entry.chosen)?.chosen;
|
|
655
|
-
const provider = chosen?.provider?.trim();
|
|
656
|
-
const model = chosen?.model?.trim();
|
|
657
|
-
const modelLabel = provider ? (model ? `${provider}/${model}` : provider) : undefined;
|
|
658
|
-
const reason = decision.attachments
|
|
659
|
-
.flatMap((entry) => entry.attempts.map((attempt) => attempt.reason).filter(Boolean))
|
|
660
|
-
.find(Boolean);
|
|
661
|
-
const shortReason = reason ? reason.split(":")[0]?.trim() : undefined;
|
|
662
|
-
const countLabel = total > 0 ? ` (${success}/${total})` : "";
|
|
663
|
-
const viaLabel = modelLabel ? ` via ${modelLabel}` : "";
|
|
664
|
-
const reasonLabel = shortReason ? ` reason=${shortReason}` : "";
|
|
665
|
-
return `${decision.capability}: ${decision.outcome}${countLabel}${viaLabel}${reasonLabel}`;
|
|
666
|
-
}
|
|
667
|
-
async function runProviderEntry(params) {
|
|
668
|
-
const { entry, capability, cfg } = params;
|
|
669
|
-
const providerIdRaw = entry.provider?.trim();
|
|
670
|
-
if (!providerIdRaw) {
|
|
671
|
-
throw new Error(`Provider entry missing provider for ${capability}`);
|
|
672
|
-
}
|
|
673
|
-
const providerId = normalizeMediaProviderId(providerIdRaw);
|
|
674
|
-
const maxBytes = resolveMaxBytes({ capability, entry, cfg, config: params.config });
|
|
675
|
-
const maxChars = resolveMaxChars({ capability, entry, cfg, config: params.config });
|
|
676
|
-
const timeoutMs = resolveTimeoutMs(entry.timeoutSeconds ??
|
|
677
|
-
params.config?.timeoutSeconds ??
|
|
678
|
-
cfg.tools?.media?.[capability]?.timeoutSeconds, DEFAULT_TIMEOUT_SECONDS[capability]);
|
|
679
|
-
const prompt = resolvePrompt(capability, entry.prompt ?? params.config?.prompt ?? cfg.tools?.media?.[capability]?.prompt, maxChars);
|
|
680
|
-
if (capability === "image") {
|
|
681
|
-
if (!params.agentDir) {
|
|
682
|
-
throw new Error("Image understanding requires agentDir");
|
|
683
|
-
}
|
|
684
|
-
const modelId = entry.model?.trim();
|
|
685
|
-
if (!modelId) {
|
|
686
|
-
throw new Error("Image understanding requires model id");
|
|
687
|
-
}
|
|
688
|
-
const media = await params.cache.getBuffer({
|
|
689
|
-
attachmentIndex: params.attachmentIndex,
|
|
690
|
-
maxBytes,
|
|
691
|
-
timeoutMs,
|
|
692
|
-
});
|
|
693
|
-
const provider = getMediaUnderstandingProvider(providerId, params.providerRegistry);
|
|
694
|
-
const result = provider?.describeImage
|
|
695
|
-
? await provider.describeImage({
|
|
696
|
-
buffer: media.buffer,
|
|
697
|
-
fileName: media.fileName,
|
|
698
|
-
mime: media.mime,
|
|
699
|
-
model: modelId,
|
|
700
|
-
provider: providerId,
|
|
701
|
-
prompt,
|
|
702
|
-
timeoutMs,
|
|
703
|
-
profile: entry.profile,
|
|
704
|
-
preferredProfile: entry.preferredProfile,
|
|
705
|
-
agentDir: params.agentDir,
|
|
706
|
-
cfg: params.cfg,
|
|
707
|
-
})
|
|
708
|
-
: await describeImageWithModel({
|
|
709
|
-
buffer: media.buffer,
|
|
710
|
-
fileName: media.fileName,
|
|
711
|
-
mime: media.mime,
|
|
712
|
-
model: modelId,
|
|
713
|
-
provider: providerId,
|
|
714
|
-
prompt,
|
|
715
|
-
timeoutMs,
|
|
716
|
-
profile: entry.profile,
|
|
717
|
-
preferredProfile: entry.preferredProfile,
|
|
718
|
-
agentDir: params.agentDir,
|
|
719
|
-
cfg: params.cfg,
|
|
720
|
-
});
|
|
721
|
-
return {
|
|
722
|
-
kind: "image.description",
|
|
723
|
-
attachmentIndex: params.attachmentIndex,
|
|
724
|
-
text: trimOutput(result.text, maxChars),
|
|
725
|
-
provider: providerId,
|
|
726
|
-
model: result.model ?? modelId,
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
const provider = getMediaUnderstandingProvider(providerId, params.providerRegistry);
|
|
730
|
-
if (!provider) {
|
|
731
|
-
throw new Error(`Media provider not available: ${providerId}`);
|
|
732
|
-
}
|
|
733
|
-
if (capability === "audio") {
|
|
734
|
-
if (!provider.transcribeAudio) {
|
|
735
|
-
throw new Error(`Audio transcription provider "${providerId}" not available.`);
|
|
736
|
-
}
|
|
737
|
-
const media = await params.cache.getBuffer({
|
|
738
|
-
attachmentIndex: params.attachmentIndex,
|
|
739
|
-
maxBytes,
|
|
740
|
-
timeoutMs,
|
|
741
|
-
});
|
|
742
|
-
const auth = await resolveApiKeyForProvider({
|
|
743
|
-
provider: providerId,
|
|
744
|
-
cfg,
|
|
745
|
-
profileId: entry.profile,
|
|
746
|
-
preferredProfile: entry.preferredProfile,
|
|
747
|
-
agentDir: params.agentDir,
|
|
748
|
-
});
|
|
749
|
-
const apiKey = requireApiKey(auth, providerId);
|
|
750
|
-
const providerConfig = cfg.models?.providers?.[providerId];
|
|
751
|
-
const baseUrl = entry.baseUrl ?? params.config?.baseUrl ?? providerConfig?.baseUrl;
|
|
752
|
-
const mergedHeaders = {
|
|
753
|
-
...providerConfig?.headers,
|
|
754
|
-
...params.config?.headers,
|
|
755
|
-
...entry.headers,
|
|
756
|
-
};
|
|
757
|
-
const headers = Object.keys(mergedHeaders).length > 0 ? mergedHeaders : undefined;
|
|
758
|
-
const providerQuery = resolveProviderQuery({
|
|
759
|
-
providerId,
|
|
760
|
-
config: params.config,
|
|
761
|
-
entry,
|
|
762
|
-
});
|
|
763
|
-
const model = entry.model?.trim() || DEFAULT_AUDIO_MODELS[providerId] || entry.model;
|
|
764
|
-
const result = await provider.transcribeAudio({
|
|
765
|
-
buffer: media.buffer,
|
|
766
|
-
fileName: media.fileName,
|
|
767
|
-
mime: media.mime,
|
|
768
|
-
apiKey,
|
|
769
|
-
baseUrl,
|
|
770
|
-
headers,
|
|
771
|
-
model,
|
|
772
|
-
language: entry.language ?? params.config?.language ?? cfg.tools?.media?.audio?.language,
|
|
773
|
-
prompt,
|
|
774
|
-
query: providerQuery,
|
|
775
|
-
timeoutMs,
|
|
776
|
-
});
|
|
777
|
-
return {
|
|
778
|
-
kind: "audio.transcription",
|
|
779
|
-
attachmentIndex: params.attachmentIndex,
|
|
780
|
-
text: trimOutput(result.text, maxChars),
|
|
781
|
-
provider: providerId,
|
|
782
|
-
model: result.model ?? model,
|
|
783
|
-
};
|
|
784
|
-
}
|
|
785
|
-
if (!provider.describeVideo) {
|
|
786
|
-
throw new Error(`Video understanding provider "${providerId}" not available.`);
|
|
787
|
-
}
|
|
788
|
-
const media = await params.cache.getBuffer({
|
|
789
|
-
attachmentIndex: params.attachmentIndex,
|
|
790
|
-
maxBytes,
|
|
791
|
-
timeoutMs,
|
|
792
|
-
});
|
|
793
|
-
const estimatedBase64Bytes = estimateBase64Size(media.size);
|
|
794
|
-
const maxBase64Bytes = resolveVideoMaxBase64Bytes(maxBytes);
|
|
795
|
-
if (estimatedBase64Bytes > maxBase64Bytes) {
|
|
796
|
-
throw new MediaUnderstandingSkipError("maxBytes", `Video attachment ${params.attachmentIndex + 1} base64 payload ${estimatedBase64Bytes} exceeds ${maxBase64Bytes}`);
|
|
797
|
-
}
|
|
798
|
-
const auth = await resolveApiKeyForProvider({
|
|
799
|
-
provider: providerId,
|
|
800
|
-
cfg,
|
|
801
|
-
profileId: entry.profile,
|
|
802
|
-
preferredProfile: entry.preferredProfile,
|
|
803
|
-
agentDir: params.agentDir,
|
|
804
|
-
});
|
|
805
|
-
const apiKey = requireApiKey(auth, providerId);
|
|
806
|
-
const providerConfig = cfg.models?.providers?.[providerId];
|
|
807
|
-
const result = await provider.describeVideo({
|
|
808
|
-
buffer: media.buffer,
|
|
809
|
-
fileName: media.fileName,
|
|
810
|
-
mime: media.mime,
|
|
811
|
-
apiKey,
|
|
812
|
-
baseUrl: providerConfig?.baseUrl,
|
|
813
|
-
headers: providerConfig?.headers,
|
|
814
|
-
model: entry.model,
|
|
815
|
-
prompt,
|
|
816
|
-
timeoutMs,
|
|
817
|
-
});
|
|
818
|
-
return {
|
|
819
|
-
kind: "video.description",
|
|
820
|
-
attachmentIndex: params.attachmentIndex,
|
|
821
|
-
text: trimOutput(result.text, maxChars),
|
|
822
|
-
provider: providerId,
|
|
823
|
-
model: result.model ?? entry.model,
|
|
824
|
-
};
|
|
825
|
-
}
|
|
826
|
-
async function runCliEntry(params) {
|
|
827
|
-
const { entry, capability, cfg, ctx } = params;
|
|
828
|
-
const command = entry.command?.trim();
|
|
829
|
-
const args = entry.args ?? [];
|
|
830
|
-
if (!command) {
|
|
831
|
-
throw new Error(`CLI entry missing command for ${capability}`);
|
|
832
|
-
}
|
|
833
|
-
const maxBytes = resolveMaxBytes({ capability, entry, cfg, config: params.config });
|
|
834
|
-
const maxChars = resolveMaxChars({ capability, entry, cfg, config: params.config });
|
|
835
|
-
const timeoutMs = resolveTimeoutMs(entry.timeoutSeconds ??
|
|
836
|
-
params.config?.timeoutSeconds ??
|
|
837
|
-
cfg.tools?.media?.[capability]?.timeoutSeconds, DEFAULT_TIMEOUT_SECONDS[capability]);
|
|
838
|
-
const prompt = resolvePrompt(capability, entry.prompt ?? params.config?.prompt ?? cfg.tools?.media?.[capability]?.prompt, maxChars);
|
|
839
|
-
const pathResult = await params.cache.getPath({
|
|
840
|
-
attachmentIndex: params.attachmentIndex,
|
|
841
|
-
maxBytes,
|
|
842
|
-
timeoutMs,
|
|
843
|
-
});
|
|
844
|
-
const outputDir = await fs.mkdtemp(path.join(os.tmpdir(), "poolbot-media-cli-"));
|
|
845
|
-
const mediaPath = pathResult.path;
|
|
846
|
-
const outputBase = path.join(outputDir, path.parse(mediaPath).name);
|
|
847
|
-
const templCtx = {
|
|
848
|
-
...ctx,
|
|
849
|
-
MediaPath: mediaPath,
|
|
850
|
-
MediaDir: path.dirname(mediaPath),
|
|
851
|
-
OutputDir: outputDir,
|
|
852
|
-
OutputBase: outputBase,
|
|
853
|
-
Prompt: prompt,
|
|
854
|
-
MaxChars: maxChars,
|
|
855
|
-
};
|
|
856
|
-
const argv = [command, ...args].map((part, index) => index === 0 ? part : applyTemplate(part, templCtx));
|
|
857
|
-
try {
|
|
858
|
-
if (shouldLogVerbose()) {
|
|
859
|
-
logVerbose(`Media understanding via CLI: ${argv.join(" ")}`);
|
|
860
|
-
}
|
|
861
|
-
const { stdout } = await runExec(argv[0], argv.slice(1), {
|
|
862
|
-
timeoutMs,
|
|
863
|
-
maxBuffer: CLI_OUTPUT_MAX_BUFFER,
|
|
864
|
-
});
|
|
865
|
-
const resolved = await resolveCliOutput({
|
|
866
|
-
command,
|
|
867
|
-
args: argv.slice(1),
|
|
868
|
-
stdout,
|
|
869
|
-
mediaPath,
|
|
870
|
-
});
|
|
871
|
-
const text = trimOutput(resolved, maxChars);
|
|
872
|
-
if (!text) {
|
|
873
|
-
return null;
|
|
874
|
-
}
|
|
875
|
-
return {
|
|
876
|
-
kind: capability === "audio" ? "audio.transcription" : `${capability}.description`,
|
|
877
|
-
attachmentIndex: params.attachmentIndex,
|
|
878
|
-
text,
|
|
879
|
-
provider: "cli",
|
|
880
|
-
model: command,
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
finally {
|
|
884
|
-
await fs.rm(outputDir, { recursive: true, force: true }).catch(() => { });
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
452
|
async function runAttachmentEntries(params) {
|
|
888
453
|
const { entries, capability } = params;
|
|
889
454
|
const attempts = [];
|