@poolzin/pool-bot 2026.2.0 → 2026.2.2
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 +118 -0
- package/README-header.png +0 -0
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +9 -11
- package/dist/agents/context.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/model-catalog.js +1 -1
- package/dist/agents/model-selection.js +21 -0
- 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.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +8 -10
- package/dist/agents/pi-embedded-runner/model.js +62 -3
- package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
- package/dist/agents/pi-embedded-runner/run.js +199 -46
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-tools.js +10 -5
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- 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-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +24 -0
- 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 +1 -1
- 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/envelope.js +74 -82
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +1 -0
- 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/get-reply-run.js +2 -1
- package/dist/auto-reply/reply/inbound-context.js +5 -1
- package/dist/auto-reply/reply/mentions.js +1 -1
- package/dist/auto-reply/reply/model-selection.js +3 -3
- 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 +50 -7
- package/dist/browser/config.js +1 -10
- package/dist/browser/extension-relay.js +101 -40
- 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.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/index.html +28 -28
- package/dist/channels/reply-prefix.js +8 -1
- 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/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +5 -5
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/update-cli.js +173 -52
- package/dist/commands/agent.js +1 -0
- package/dist/commands/auth-choice.apply.oauth.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-state-migrations.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.registry.js +1 -1
- package/dist/commands/models/list.status-command.js +43 -23
- package/dist/commands/models/shared.js +15 -0
- 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 +6 -3
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/defaults.js +3 -2
- 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 +2 -2
- package/dist/config/sessions/store.js +291 -23
- 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/control-ui/assets/{index-CIRDm-Lu.css → index-CSfXd2LO.css} +1 -1
- package/dist/control-ui/assets/{index-CmNMuoem.js → index-HRr1grwl.js} +446 -413
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -0
- package/dist/control-ui/index.html +4 -4
- 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 +172 -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/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/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- 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-http.js +109 -11
- 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 +5 -1
- 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.mocks.js +11 -7
- package/dist/gateway/test-helpers.server.js +35 -2
- 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/infra/bonjour-discovery.js +131 -70
- 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/poolbot-root.js +43 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- 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/media/fetch.js +81 -58
- package/dist/media/store.js +2 -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 +3 -3
- 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/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +28 -16
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +154 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/node-host/runner.js +34 -24
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/source-display.js +51 -0
- 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/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/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +1 -2
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +37 -10
- package/dist/telegram/bot-message-dispatch.js +54 -17
- 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/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/transcript-tools.js +58 -0
- package/dist/utils.js +45 -14
- package/dist/version.js +42 -5
- package/dist/wizard/clack-prompter.js +9 -6
- package/extensions/googlechat/node_modules/.bin/poolbot +21 -0
- package/extensions/googlechat/package.json +2 -2
- package/extensions/line/node_modules/.bin/poolbot +21 -0
- package/extensions/line/package.json +1 -1
- package/extensions/matrix/node_modules/.bin/poolbot +21 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/memory-core/node_modules/.bin/poolbot +21 -0
- package/extensions/memory-core/package.json +4 -1
- package/extensions/twitch/node_modules/.bin/poolbot +21 -0
- package/extensions/twitch/package.json +1 -1
- package/package.json +183 -24
- package/dist/control-ui/assets/index-CmNMuoem.js.map +0 -1
|
@@ -2,27 +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 { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
|
5
6
|
import { findModelInCatalog, loadModelCatalog, modelSupportsVision, } from "../agents/model-catalog.js";
|
|
6
7
|
import { applyTemplate } from "../auto-reply/templating.js";
|
|
7
|
-
import { requireApiKey, resolveApiKeyForProvider } from "../agents/model-auth.js";
|
|
8
8
|
import { logVerbose, shouldLogVerbose } from "../globals.js";
|
|
9
9
|
import { runExec } from "../process/exec.js";
|
|
10
10
|
import { MediaAttachmentCache, normalizeAttachments, selectAttachments } from "./attachments.js";
|
|
11
|
-
import { CLI_OUTPUT_MAX_BUFFER, DEFAULT_AUDIO_MODELS, DEFAULT_TIMEOUT_SECONDS, } from "./defaults.js";
|
|
11
|
+
import { AUTO_AUDIO_KEY_PROVIDERS, AUTO_IMAGE_KEY_PROVIDERS, AUTO_VIDEO_KEY_PROVIDERS, CLI_OUTPUT_MAX_BUFFER, DEFAULT_AUDIO_MODELS, DEFAULT_IMAGE_MODELS, DEFAULT_TIMEOUT_SECONDS, } from "./defaults.js";
|
|
12
12
|
import { isMediaUnderstandingSkipError, MediaUnderstandingSkipError } from "./errors.js";
|
|
13
|
-
import { resolveMaxBytes, resolveMaxChars, resolveModelEntries, resolvePrompt, resolveScopeDecision, resolveTimeoutMs, } from "./resolve.js";
|
|
14
|
-
import { buildMediaUnderstandingRegistry, getMediaUnderstandingProvider, normalizeMediaProviderId, } from "./providers/index.js";
|
|
15
13
|
import { describeImageWithModel } from "./providers/image.js";
|
|
14
|
+
import { buildMediaUnderstandingRegistry, getMediaUnderstandingProvider, normalizeMediaProviderId, } from "./providers/index.js";
|
|
15
|
+
import { resolveMaxBytes, resolveMaxChars, resolveModelEntries, resolvePrompt, resolveScopeDecision, resolveTimeoutMs, } from "./resolve.js";
|
|
16
16
|
import { estimateBase64Size, resolveVideoMaxBase64Bytes } from "./video.js";
|
|
17
|
-
const AUTO_AUDIO_KEY_PROVIDERS = ["openai", "groq", "deepgram", "google"];
|
|
18
|
-
const AUTO_IMAGE_KEY_PROVIDERS = ["openai", "anthropic", "google", "minimax"];
|
|
19
|
-
const AUTO_VIDEO_KEY_PROVIDERS = ["google"];
|
|
20
|
-
const DEFAULT_IMAGE_MODELS = {
|
|
21
|
-
openai: "gpt-5-mini",
|
|
22
|
-
anthropic: "claude-opus-4-5",
|
|
23
|
-
google: "gemini-3-flash-preview",
|
|
24
|
-
minimax: "MiniMax-VL-01",
|
|
25
|
-
};
|
|
26
17
|
export function buildProviderRegistry(overrides) {
|
|
27
18
|
return buildMediaUnderstandingRegistry(overrides);
|
|
28
19
|
}
|
|
@@ -35,24 +26,29 @@ export function createMediaAttachmentCache(attachments) {
|
|
|
35
26
|
const binaryCache = new Map();
|
|
36
27
|
const geminiProbeCache = new Map();
|
|
37
28
|
function expandHomeDir(value) {
|
|
38
|
-
if (!value.startsWith("~"))
|
|
29
|
+
if (!value.startsWith("~")) {
|
|
39
30
|
return value;
|
|
31
|
+
}
|
|
40
32
|
const home = os.homedir();
|
|
41
|
-
if (value === "~")
|
|
33
|
+
if (value === "~") {
|
|
42
34
|
return home;
|
|
43
|
-
|
|
35
|
+
}
|
|
36
|
+
if (value.startsWith("~/")) {
|
|
44
37
|
return path.join(home, value.slice(2));
|
|
38
|
+
}
|
|
45
39
|
return value;
|
|
46
40
|
}
|
|
47
41
|
function hasPathSeparator(value) {
|
|
48
42
|
return value.includes("/") || value.includes("\\");
|
|
49
43
|
}
|
|
50
44
|
function candidateBinaryNames(name) {
|
|
51
|
-
if (process.platform !== "win32")
|
|
45
|
+
if (process.platform !== "win32") {
|
|
52
46
|
return [name];
|
|
47
|
+
}
|
|
53
48
|
const ext = path.extname(name);
|
|
54
|
-
if (ext)
|
|
49
|
+
if (ext) {
|
|
55
50
|
return [name];
|
|
51
|
+
}
|
|
56
52
|
const pathext = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM")
|
|
57
53
|
.split(";")
|
|
58
54
|
.map((item) => item.trim())
|
|
@@ -64,10 +60,12 @@ function candidateBinaryNames(name) {
|
|
|
64
60
|
async function isExecutable(filePath) {
|
|
65
61
|
try {
|
|
66
62
|
const stat = await fs.stat(filePath);
|
|
67
|
-
if (!stat.isFile())
|
|
63
|
+
if (!stat.isFile()) {
|
|
68
64
|
return false;
|
|
69
|
-
|
|
65
|
+
}
|
|
66
|
+
if (process.platform === "win32") {
|
|
70
67
|
return true;
|
|
68
|
+
}
|
|
71
69
|
await fs.access(filePath, fsConstants.X_OK);
|
|
72
70
|
return true;
|
|
73
71
|
}
|
|
@@ -77,29 +75,34 @@ async function isExecutable(filePath) {
|
|
|
77
75
|
}
|
|
78
76
|
async function findBinary(name) {
|
|
79
77
|
const cached = binaryCache.get(name);
|
|
80
|
-
if (cached)
|
|
78
|
+
if (cached) {
|
|
81
79
|
return cached;
|
|
80
|
+
}
|
|
82
81
|
const resolved = (async () => {
|
|
83
82
|
const direct = expandHomeDir(name.trim());
|
|
84
83
|
if (direct && hasPathSeparator(direct)) {
|
|
85
84
|
for (const candidate of candidateBinaryNames(direct)) {
|
|
86
|
-
if (await isExecutable(candidate))
|
|
85
|
+
if (await isExecutable(candidate)) {
|
|
87
86
|
return candidate;
|
|
87
|
+
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
const searchName = name.trim();
|
|
91
|
-
if (!searchName)
|
|
91
|
+
if (!searchName) {
|
|
92
92
|
return null;
|
|
93
|
+
}
|
|
93
94
|
const pathEntries = (process.env.PATH ?? "").split(path.delimiter);
|
|
94
95
|
const candidates = candidateBinaryNames(searchName);
|
|
95
96
|
for (const entryRaw of pathEntries) {
|
|
96
97
|
const entry = expandHomeDir(entryRaw.trim().replace(/^"(.*)"$/, "$1"));
|
|
97
|
-
if (!entry)
|
|
98
|
+
if (!entry) {
|
|
98
99
|
continue;
|
|
100
|
+
}
|
|
99
101
|
for (const candidate of candidates) {
|
|
100
102
|
const fullPath = path.join(entry, candidate);
|
|
101
|
-
if (await isExecutable(fullPath))
|
|
103
|
+
if (await isExecutable(fullPath)) {
|
|
102
104
|
return fullPath;
|
|
105
|
+
}
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
return null;
|
|
@@ -111,8 +114,9 @@ async function hasBinary(name) {
|
|
|
111
114
|
return Boolean(await findBinary(name));
|
|
112
115
|
}
|
|
113
116
|
async function fileExists(filePath) {
|
|
114
|
-
if (!filePath)
|
|
117
|
+
if (!filePath) {
|
|
115
118
|
return false;
|
|
119
|
+
}
|
|
116
120
|
try {
|
|
117
121
|
await fs.stat(filePath);
|
|
118
122
|
return true;
|
|
@@ -124,8 +128,9 @@ async function fileExists(filePath) {
|
|
|
124
128
|
function extractLastJsonObject(raw) {
|
|
125
129
|
const trimmed = raw.trim();
|
|
126
130
|
const start = trimmed.lastIndexOf("{");
|
|
127
|
-
if (start === -1)
|
|
131
|
+
if (start === -1) {
|
|
128
132
|
return null;
|
|
133
|
+
}
|
|
129
134
|
const slice = trimmed.slice(start);
|
|
130
135
|
try {
|
|
131
136
|
return JSON.parse(slice);
|
|
@@ -136,22 +141,26 @@ function extractLastJsonObject(raw) {
|
|
|
136
141
|
}
|
|
137
142
|
function extractGeminiResponse(raw) {
|
|
138
143
|
const payload = extractLastJsonObject(raw);
|
|
139
|
-
if (!payload || typeof payload !== "object")
|
|
144
|
+
if (!payload || typeof payload !== "object") {
|
|
140
145
|
return null;
|
|
146
|
+
}
|
|
141
147
|
const response = payload.response;
|
|
142
|
-
if (typeof response !== "string")
|
|
148
|
+
if (typeof response !== "string") {
|
|
143
149
|
return null;
|
|
150
|
+
}
|
|
144
151
|
const trimmed = response.trim();
|
|
145
152
|
return trimmed || null;
|
|
146
153
|
}
|
|
147
154
|
function extractSherpaOnnxText(raw) {
|
|
148
155
|
const tryParse = (value) => {
|
|
149
156
|
const trimmed = value.trim();
|
|
150
|
-
if (!trimmed)
|
|
157
|
+
if (!trimmed) {
|
|
151
158
|
return null;
|
|
159
|
+
}
|
|
152
160
|
const head = trimmed[0];
|
|
153
|
-
if (head !== "{" && head !== '"')
|
|
161
|
+
if (head !== "{" && head !== '"') {
|
|
154
162
|
return null;
|
|
163
|
+
}
|
|
155
164
|
try {
|
|
156
165
|
const parsed = JSON.parse(trimmed);
|
|
157
166
|
if (typeof parsed === "string") {
|
|
@@ -168,26 +177,30 @@ function extractSherpaOnnxText(raw) {
|
|
|
168
177
|
return null;
|
|
169
178
|
};
|
|
170
179
|
const direct = tryParse(raw);
|
|
171
|
-
if (direct)
|
|
180
|
+
if (direct) {
|
|
172
181
|
return direct;
|
|
182
|
+
}
|
|
173
183
|
const lines = raw
|
|
174
184
|
.split("\n")
|
|
175
185
|
.map((line) => line.trim())
|
|
176
186
|
.filter(Boolean);
|
|
177
187
|
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
178
188
|
const parsed = tryParse(lines[i] ?? "");
|
|
179
|
-
if (parsed)
|
|
189
|
+
if (parsed) {
|
|
180
190
|
return parsed;
|
|
191
|
+
}
|
|
181
192
|
}
|
|
182
193
|
return null;
|
|
183
194
|
}
|
|
184
195
|
async function probeGeminiCli() {
|
|
185
196
|
const cached = geminiProbeCache.get("gemini");
|
|
186
|
-
if (cached)
|
|
197
|
+
if (cached) {
|
|
187
198
|
return cached;
|
|
199
|
+
}
|
|
188
200
|
const resolved = (async () => {
|
|
189
|
-
if (!(await hasBinary("gemini")))
|
|
201
|
+
if (!(await hasBinary("gemini"))) {
|
|
190
202
|
return false;
|
|
203
|
+
}
|
|
191
204
|
try {
|
|
192
205
|
const { stdout } = await runExec("gemini", ["--output-format", "json", "ok"], {
|
|
193
206
|
timeoutMs: 8000,
|
|
@@ -202,13 +215,15 @@ async function probeGeminiCli() {
|
|
|
202
215
|
return resolved;
|
|
203
216
|
}
|
|
204
217
|
async function resolveLocalWhisperCppEntry() {
|
|
205
|
-
if (!(await hasBinary("whisper-cli")))
|
|
218
|
+
if (!(await hasBinary("whisper-cli"))) {
|
|
206
219
|
return null;
|
|
220
|
+
}
|
|
207
221
|
const envModel = process.env.WHISPER_CPP_MODEL?.trim();
|
|
208
222
|
const defaultModel = "/opt/homebrew/share/whisper-cpp/for-tests-ggml-tiny.bin";
|
|
209
223
|
const modelPath = envModel && (await fileExists(envModel)) ? envModel : defaultModel;
|
|
210
|
-
if (!(await fileExists(modelPath)))
|
|
224
|
+
if (!(await fileExists(modelPath))) {
|
|
211
225
|
return null;
|
|
226
|
+
}
|
|
212
227
|
return {
|
|
213
228
|
type: "cli",
|
|
214
229
|
command: "whisper-cli",
|
|
@@ -216,8 +231,9 @@ async function resolveLocalWhisperCppEntry() {
|
|
|
216
231
|
};
|
|
217
232
|
}
|
|
218
233
|
async function resolveLocalWhisperEntry() {
|
|
219
|
-
if (!(await hasBinary("whisper")))
|
|
234
|
+
if (!(await hasBinary("whisper"))) {
|
|
220
235
|
return null;
|
|
236
|
+
}
|
|
221
237
|
return {
|
|
222
238
|
type: "cli",
|
|
223
239
|
command: "whisper",
|
|
@@ -235,23 +251,29 @@ async function resolveLocalWhisperEntry() {
|
|
|
235
251
|
};
|
|
236
252
|
}
|
|
237
253
|
async function resolveSherpaOnnxEntry() {
|
|
238
|
-
if (!(await hasBinary("sherpa-onnx-offline")))
|
|
254
|
+
if (!(await hasBinary("sherpa-onnx-offline"))) {
|
|
239
255
|
return null;
|
|
256
|
+
}
|
|
240
257
|
const modelDir = process.env.SHERPA_ONNX_MODEL_DIR?.trim();
|
|
241
|
-
if (!modelDir)
|
|
258
|
+
if (!modelDir) {
|
|
242
259
|
return null;
|
|
260
|
+
}
|
|
243
261
|
const tokens = path.join(modelDir, "tokens.txt");
|
|
244
262
|
const encoder = path.join(modelDir, "encoder.onnx");
|
|
245
263
|
const decoder = path.join(modelDir, "decoder.onnx");
|
|
246
264
|
const joiner = path.join(modelDir, "joiner.onnx");
|
|
247
|
-
if (!(await fileExists(tokens)))
|
|
265
|
+
if (!(await fileExists(tokens))) {
|
|
248
266
|
return null;
|
|
249
|
-
|
|
267
|
+
}
|
|
268
|
+
if (!(await fileExists(encoder))) {
|
|
250
269
|
return null;
|
|
251
|
-
|
|
270
|
+
}
|
|
271
|
+
if (!(await fileExists(decoder))) {
|
|
252
272
|
return null;
|
|
253
|
-
|
|
273
|
+
}
|
|
274
|
+
if (!(await fileExists(joiner))) {
|
|
254
275
|
return null;
|
|
276
|
+
}
|
|
255
277
|
return {
|
|
256
278
|
type: "cli",
|
|
257
279
|
command: "sherpa-onnx-offline",
|
|
@@ -266,16 +288,19 @@ async function resolveSherpaOnnxEntry() {
|
|
|
266
288
|
}
|
|
267
289
|
async function resolveLocalAudioEntry() {
|
|
268
290
|
const sherpa = await resolveSherpaOnnxEntry();
|
|
269
|
-
if (sherpa)
|
|
291
|
+
if (sherpa) {
|
|
270
292
|
return sherpa;
|
|
293
|
+
}
|
|
271
294
|
const whisperCpp = await resolveLocalWhisperCppEntry();
|
|
272
|
-
if (whisperCpp)
|
|
295
|
+
if (whisperCpp) {
|
|
273
296
|
return whisperCpp;
|
|
297
|
+
}
|
|
274
298
|
return await resolveLocalWhisperEntry();
|
|
275
299
|
}
|
|
276
300
|
async function resolveGeminiCliEntry(_capability) {
|
|
277
|
-
if (!(await probeGeminiCli()))
|
|
301
|
+
if (!(await probeGeminiCli())) {
|
|
278
302
|
return null;
|
|
303
|
+
}
|
|
279
304
|
return {
|
|
280
305
|
type: "cli",
|
|
281
306
|
command: "gemini",
|
|
@@ -295,14 +320,18 @@ async function resolveKeyEntry(params) {
|
|
|
295
320
|
const { cfg, agentDir, providerRegistry, capability } = params;
|
|
296
321
|
const checkProvider = async (providerId, model) => {
|
|
297
322
|
const provider = getMediaUnderstandingProvider(providerId, providerRegistry);
|
|
298
|
-
if (!provider)
|
|
323
|
+
if (!provider) {
|
|
299
324
|
return null;
|
|
300
|
-
|
|
325
|
+
}
|
|
326
|
+
if (capability === "audio" && !provider.transcribeAudio) {
|
|
301
327
|
return null;
|
|
302
|
-
|
|
328
|
+
}
|
|
329
|
+
if (capability === "image" && !provider.describeImage) {
|
|
303
330
|
return null;
|
|
304
|
-
|
|
331
|
+
}
|
|
332
|
+
if (capability === "video" && !provider.describeVideo) {
|
|
305
333
|
return null;
|
|
334
|
+
}
|
|
306
335
|
try {
|
|
307
336
|
await resolveApiKeyForProvider({ provider: providerId, cfg, agentDir });
|
|
308
337
|
return { type: "provider", provider: providerId, model };
|
|
@@ -315,14 +344,16 @@ async function resolveKeyEntry(params) {
|
|
|
315
344
|
const activeProvider = params.activeModel?.provider?.trim();
|
|
316
345
|
if (activeProvider) {
|
|
317
346
|
const activeEntry = await checkProvider(activeProvider, params.activeModel?.model);
|
|
318
|
-
if (activeEntry)
|
|
347
|
+
if (activeEntry) {
|
|
319
348
|
return activeEntry;
|
|
349
|
+
}
|
|
320
350
|
}
|
|
321
351
|
for (const providerId of AUTO_IMAGE_KEY_PROVIDERS) {
|
|
322
352
|
const model = DEFAULT_IMAGE_MODELS[providerId];
|
|
323
353
|
const entry = await checkProvider(providerId, model);
|
|
324
|
-
if (entry)
|
|
354
|
+
if (entry) {
|
|
325
355
|
return entry;
|
|
356
|
+
}
|
|
326
357
|
}
|
|
327
358
|
return null;
|
|
328
359
|
}
|
|
@@ -330,57 +361,68 @@ async function resolveKeyEntry(params) {
|
|
|
330
361
|
const activeProvider = params.activeModel?.provider?.trim();
|
|
331
362
|
if (activeProvider) {
|
|
332
363
|
const activeEntry = await checkProvider(activeProvider, params.activeModel?.model);
|
|
333
|
-
if (activeEntry)
|
|
364
|
+
if (activeEntry) {
|
|
334
365
|
return activeEntry;
|
|
366
|
+
}
|
|
335
367
|
}
|
|
336
368
|
for (const providerId of AUTO_VIDEO_KEY_PROVIDERS) {
|
|
337
369
|
const entry = await checkProvider(providerId, undefined);
|
|
338
|
-
if (entry)
|
|
370
|
+
if (entry) {
|
|
339
371
|
return entry;
|
|
372
|
+
}
|
|
340
373
|
}
|
|
341
374
|
return null;
|
|
342
375
|
}
|
|
343
376
|
const activeProvider = params.activeModel?.provider?.trim();
|
|
344
377
|
if (activeProvider) {
|
|
345
378
|
const activeEntry = await checkProvider(activeProvider, params.activeModel?.model);
|
|
346
|
-
if (activeEntry)
|
|
379
|
+
if (activeEntry) {
|
|
347
380
|
return activeEntry;
|
|
381
|
+
}
|
|
348
382
|
}
|
|
349
383
|
for (const providerId of AUTO_AUDIO_KEY_PROVIDERS) {
|
|
350
384
|
const entry = await checkProvider(providerId, undefined);
|
|
351
|
-
if (entry)
|
|
385
|
+
if (entry) {
|
|
352
386
|
return entry;
|
|
387
|
+
}
|
|
353
388
|
}
|
|
354
389
|
return null;
|
|
355
390
|
}
|
|
356
391
|
async function resolveAutoEntries(params) {
|
|
357
392
|
const activeEntry = await resolveActiveModelEntry(params);
|
|
358
|
-
if (activeEntry)
|
|
393
|
+
if (activeEntry) {
|
|
359
394
|
return [activeEntry];
|
|
395
|
+
}
|
|
360
396
|
if (params.capability === "audio") {
|
|
361
397
|
const localAudio = await resolveLocalAudioEntry();
|
|
362
|
-
if (localAudio)
|
|
398
|
+
if (localAudio) {
|
|
363
399
|
return [localAudio];
|
|
400
|
+
}
|
|
364
401
|
}
|
|
365
402
|
const gemini = await resolveGeminiCliEntry(params.capability);
|
|
366
|
-
if (gemini)
|
|
403
|
+
if (gemini) {
|
|
367
404
|
return [gemini];
|
|
405
|
+
}
|
|
368
406
|
const keys = await resolveKeyEntry(params);
|
|
369
|
-
if (keys)
|
|
407
|
+
if (keys) {
|
|
370
408
|
return [keys];
|
|
409
|
+
}
|
|
371
410
|
return [];
|
|
372
411
|
}
|
|
373
412
|
export async function resolveAutoImageModel(params) {
|
|
374
413
|
const providerRegistry = buildProviderRegistry();
|
|
375
414
|
const toActive = (entry) => {
|
|
376
|
-
if (!entry || entry.type === "cli")
|
|
415
|
+
if (!entry || entry.type === "cli") {
|
|
377
416
|
return null;
|
|
417
|
+
}
|
|
378
418
|
const provider = entry.provider;
|
|
379
|
-
if (!provider)
|
|
419
|
+
if (!provider) {
|
|
380
420
|
return null;
|
|
421
|
+
}
|
|
381
422
|
const model = entry.model ?? DEFAULT_IMAGE_MODELS[provider];
|
|
382
|
-
if (!model)
|
|
423
|
+
if (!model) {
|
|
383
424
|
return null;
|
|
425
|
+
}
|
|
384
426
|
return { provider, model };
|
|
385
427
|
};
|
|
386
428
|
const activeEntry = await resolveActiveModelEntry({
|
|
@@ -391,8 +433,9 @@ export async function resolveAutoImageModel(params) {
|
|
|
391
433
|
activeModel: params.activeModel,
|
|
392
434
|
});
|
|
393
435
|
const resolvedActive = toActive(activeEntry);
|
|
394
|
-
if (resolvedActive)
|
|
436
|
+
if (resolvedActive) {
|
|
395
437
|
return resolvedActive;
|
|
438
|
+
}
|
|
396
439
|
const keyEntry = await resolveKeyEntry({
|
|
397
440
|
cfg: params.cfg,
|
|
398
441
|
agentDir: params.agentDir,
|
|
@@ -404,20 +447,26 @@ export async function resolveAutoImageModel(params) {
|
|
|
404
447
|
}
|
|
405
448
|
async function resolveActiveModelEntry(params) {
|
|
406
449
|
const activeProviderRaw = params.activeModel?.provider?.trim();
|
|
407
|
-
if (!activeProviderRaw)
|
|
450
|
+
if (!activeProviderRaw) {
|
|
408
451
|
return null;
|
|
452
|
+
}
|
|
409
453
|
const providerId = normalizeMediaProviderId(activeProviderRaw);
|
|
410
|
-
if (!providerId)
|
|
454
|
+
if (!providerId) {
|
|
411
455
|
return null;
|
|
456
|
+
}
|
|
412
457
|
const provider = getMediaUnderstandingProvider(providerId, params.providerRegistry);
|
|
413
|
-
if (!provider)
|
|
458
|
+
if (!provider) {
|
|
414
459
|
return null;
|
|
415
|
-
|
|
460
|
+
}
|
|
461
|
+
if (params.capability === "audio" && !provider.transcribeAudio) {
|
|
416
462
|
return null;
|
|
417
|
-
|
|
463
|
+
}
|
|
464
|
+
if (params.capability === "image" && !provider.describeImage) {
|
|
418
465
|
return null;
|
|
419
|
-
|
|
466
|
+
}
|
|
467
|
+
if (params.capability === "video" && !provider.describeVideo) {
|
|
420
468
|
return null;
|
|
469
|
+
}
|
|
421
470
|
try {
|
|
422
471
|
await resolveApiKeyForProvider({
|
|
423
472
|
provider: providerId,
|
|
@@ -436,8 +485,9 @@ async function resolveActiveModelEntry(params) {
|
|
|
436
485
|
}
|
|
437
486
|
function trimOutput(text, maxChars) {
|
|
438
487
|
const trimmed = text.trim();
|
|
439
|
-
if (!maxChars || trimmed.length <= maxChars)
|
|
488
|
+
if (!maxChars || trimmed.length <= maxChars) {
|
|
440
489
|
return trimmed;
|
|
490
|
+
}
|
|
441
491
|
return trimmed.slice(0, maxChars).trim();
|
|
442
492
|
}
|
|
443
493
|
function commandBase(command) {
|
|
@@ -447,8 +497,9 @@ function findArgValue(args, keys) {
|
|
|
447
497
|
for (let i = 0; i < args.length; i += 1) {
|
|
448
498
|
if (keys.includes(args[i] ?? "")) {
|
|
449
499
|
const value = args[i + 1];
|
|
450
|
-
if (value)
|
|
500
|
+
if (value) {
|
|
451
501
|
return value;
|
|
502
|
+
}
|
|
452
503
|
}
|
|
453
504
|
}
|
|
454
505
|
return undefined;
|
|
@@ -459,20 +510,24 @@ function hasArg(args, keys) {
|
|
|
459
510
|
function resolveWhisperOutputPath(args, mediaPath) {
|
|
460
511
|
const outputDir = findArgValue(args, ["--output_dir", "-o"]);
|
|
461
512
|
const outputFormat = findArgValue(args, ["--output_format"]);
|
|
462
|
-
if (!outputDir || !outputFormat)
|
|
513
|
+
if (!outputDir || !outputFormat) {
|
|
463
514
|
return null;
|
|
515
|
+
}
|
|
464
516
|
const formats = outputFormat.split(",").map((value) => value.trim());
|
|
465
|
-
if (!formats.includes("txt"))
|
|
517
|
+
if (!formats.includes("txt")) {
|
|
466
518
|
return null;
|
|
519
|
+
}
|
|
467
520
|
const base = path.parse(mediaPath).name;
|
|
468
521
|
return path.join(outputDir, `${base}.txt`);
|
|
469
522
|
}
|
|
470
523
|
function resolveWhisperCppOutputPath(args) {
|
|
471
|
-
if (!hasArg(args, ["-otxt", "--output-txt"]))
|
|
524
|
+
if (!hasArg(args, ["-otxt", "--output-txt"])) {
|
|
472
525
|
return null;
|
|
526
|
+
}
|
|
473
527
|
const outputBase = findArgValue(args, ["-of", "--output-file"]);
|
|
474
|
-
if (!outputBase)
|
|
528
|
+
if (!outputBase) {
|
|
475
529
|
return null;
|
|
530
|
+
}
|
|
476
531
|
return `${outputBase}.txt`;
|
|
477
532
|
}
|
|
478
533
|
async function resolveCliOutput(params) {
|
|
@@ -485,44 +540,53 @@ async function resolveCliOutput(params) {
|
|
|
485
540
|
if (fileOutput && (await fileExists(fileOutput))) {
|
|
486
541
|
try {
|
|
487
542
|
const content = await fs.readFile(fileOutput, "utf8");
|
|
488
|
-
if (content.trim())
|
|
543
|
+
if (content.trim()) {
|
|
489
544
|
return content.trim();
|
|
545
|
+
}
|
|
490
546
|
}
|
|
491
547
|
catch { }
|
|
492
548
|
}
|
|
493
549
|
if (commandId === "gemini") {
|
|
494
550
|
const response = extractGeminiResponse(params.stdout);
|
|
495
|
-
if (response)
|
|
551
|
+
if (response) {
|
|
496
552
|
return response;
|
|
553
|
+
}
|
|
497
554
|
}
|
|
498
555
|
if (commandId === "sherpa-onnx-offline") {
|
|
499
556
|
const response = extractSherpaOnnxText(params.stdout);
|
|
500
|
-
if (response)
|
|
557
|
+
if (response) {
|
|
501
558
|
return response;
|
|
559
|
+
}
|
|
502
560
|
}
|
|
503
561
|
return params.stdout.trim();
|
|
504
562
|
}
|
|
505
563
|
function normalizeProviderQuery(options) {
|
|
506
|
-
if (!options)
|
|
564
|
+
if (!options) {
|
|
507
565
|
return undefined;
|
|
566
|
+
}
|
|
508
567
|
const query = {};
|
|
509
568
|
for (const [key, value] of Object.entries(options)) {
|
|
510
|
-
if (value === undefined)
|
|
569
|
+
if (value === undefined) {
|
|
511
570
|
continue;
|
|
571
|
+
}
|
|
512
572
|
query[key] = value;
|
|
513
573
|
}
|
|
514
574
|
return Object.keys(query).length > 0 ? query : undefined;
|
|
515
575
|
}
|
|
516
576
|
function buildDeepgramCompatQuery(options) {
|
|
517
|
-
if (!options)
|
|
577
|
+
if (!options) {
|
|
518
578
|
return undefined;
|
|
579
|
+
}
|
|
519
580
|
const query = {};
|
|
520
|
-
if (typeof options.detectLanguage === "boolean")
|
|
581
|
+
if (typeof options.detectLanguage === "boolean") {
|
|
521
582
|
query.detect_language = options.detectLanguage;
|
|
522
|
-
|
|
583
|
+
}
|
|
584
|
+
if (typeof options.punctuate === "boolean") {
|
|
523
585
|
query.punctuate = options.punctuate;
|
|
524
|
-
|
|
586
|
+
}
|
|
587
|
+
if (typeof options.smartFormat === "boolean") {
|
|
525
588
|
query.smart_format = options.smartFormat;
|
|
589
|
+
}
|
|
526
590
|
return Object.keys(query).length > 0 ? query : undefined;
|
|
527
591
|
}
|
|
528
592
|
function normalizeDeepgramQueryKeys(query) {
|
|
@@ -797,8 +861,9 @@ async function runCliEntry(params) {
|
|
|
797
861
|
mediaPath,
|
|
798
862
|
});
|
|
799
863
|
const text = trimOutput(resolved, maxChars);
|
|
800
|
-
if (!text)
|
|
864
|
+
if (!text) {
|
|
801
865
|
return null;
|
|
866
|
+
}
|
|
802
867
|
return {
|
|
803
868
|
kind: capability === "audio" ? "audio.transcription" : `${capability}.description`,
|
|
804
869
|
attachmentIndex: params.attachmentIndex,
|
|
@@ -840,10 +905,12 @@ async function runAttachmentEntries(params) {
|
|
|
840
905
|
});
|
|
841
906
|
if (result) {
|
|
842
907
|
const decision = buildModelDecision({ entry, entryType, outcome: "success" });
|
|
843
|
-
if (result.provider)
|
|
908
|
+
if (result.provider) {
|
|
844
909
|
decision.provider = result.provider;
|
|
845
|
-
|
|
910
|
+
}
|
|
911
|
+
if (result.model) {
|
|
846
912
|
decision.model = result.model;
|
|
913
|
+
}
|
|
847
914
|
attempts.push(decision);
|
|
848
915
|
return { output: result, attempts };
|
|
849
916
|
}
|
|
@@ -985,8 +1052,9 @@ export async function runCapability(params) {
|
|
|
985
1052
|
entries: resolvedEntries,
|
|
986
1053
|
config,
|
|
987
1054
|
});
|
|
988
|
-
if (output)
|
|
1055
|
+
if (output) {
|
|
989
1056
|
outputs.push(output);
|
|
1057
|
+
}
|
|
990
1058
|
attachmentDecisions.push({
|
|
991
1059
|
attachmentIndex: attachment.index,
|
|
992
1060
|
attempts,
|