@poolzin/pool-bot 2026.2.21 → 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 +17 -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-catalog.js +40 -9
- 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 -95
- 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/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/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
1
|
import { Type } from "@sinclair/typebox";
|
|
3
|
-
import { formatThinkingLevels, normalizeThinkLevel } from "../../auto-reply/thinking.js";
|
|
4
|
-
import { loadConfig } from "../../config/config.js";
|
|
5
|
-
import { callGateway } from "../../gateway/call.js";
|
|
6
|
-
import { isSubagentSessionKey, normalizeAgentId, parseAgentSessionKey, } from "../../routing/session-key.js";
|
|
7
|
-
import { normalizeDeliveryContext } from "../../utils/delivery-context.js";
|
|
8
|
-
import { resolveAgentConfig } from "../agent-scope.js";
|
|
9
|
-
import { AGENT_LANE_SUBAGENT } from "../lanes.js";
|
|
10
2
|
import { optionalStringEnum } from "../schema/typebox.js";
|
|
11
|
-
import {
|
|
12
|
-
import { registerSubagentRun } from "../subagent-registry.js";
|
|
3
|
+
import { spawnSubagentDirect } from "../subagent-spawn.js";
|
|
13
4
|
import { jsonResult, readStringParam } from "./common.js";
|
|
14
|
-
import { resolveDisplaySessionKey, resolveInternalSessionKey, resolveMainSessionAlias, } from "./sessions-helpers.js";
|
|
15
5
|
const SessionsSpawnToolSchema = Type.Object({
|
|
16
6
|
task: Type.String(),
|
|
17
7
|
label: Type.Optional(Type.String()),
|
|
@@ -19,33 +9,10 @@ const SessionsSpawnToolSchema = Type.Object({
|
|
|
19
9
|
model: Type.Optional(Type.String()),
|
|
20
10
|
thinking: Type.Optional(Type.String()),
|
|
21
11
|
runTimeoutSeconds: Type.Optional(Type.Number({ minimum: 0 })),
|
|
22
|
-
// Back-compat
|
|
12
|
+
// Back-compat: older callers used timeoutSeconds for this tool.
|
|
23
13
|
timeoutSeconds: Type.Optional(Type.Number({ minimum: 0 })),
|
|
24
14
|
cleanup: optionalStringEnum(["delete", "keep"]),
|
|
25
15
|
});
|
|
26
|
-
function splitModelRef(ref) {
|
|
27
|
-
if (!ref)
|
|
28
|
-
return { provider: undefined, model: undefined };
|
|
29
|
-
const trimmed = ref.trim();
|
|
30
|
-
if (!trimmed)
|
|
31
|
-
return { provider: undefined, model: undefined };
|
|
32
|
-
const [provider, model] = trimmed.split("/", 2);
|
|
33
|
-
if (model)
|
|
34
|
-
return { provider, model };
|
|
35
|
-
return { provider: undefined, model: trimmed };
|
|
36
|
-
}
|
|
37
|
-
function normalizeModelSelection(value) {
|
|
38
|
-
if (typeof value === "string") {
|
|
39
|
-
const trimmed = value.trim();
|
|
40
|
-
return trimmed || undefined;
|
|
41
|
-
}
|
|
42
|
-
if (!value || typeof value !== "object")
|
|
43
|
-
return undefined;
|
|
44
|
-
const primary = value.primary;
|
|
45
|
-
if (typeof primary === "string" && primary.trim())
|
|
46
|
-
return primary.trim();
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
16
|
export function createSessionsSpawnTool(opts) {
|
|
50
17
|
return {
|
|
51
18
|
label: "Sessions",
|
|
@@ -59,174 +26,37 @@ export function createSessionsSpawnTool(opts) {
|
|
|
59
26
|
const requestedAgentId = readStringParam(params, "agentId");
|
|
60
27
|
const modelOverride = readStringParam(params, "model");
|
|
61
28
|
const thinkingOverrideRaw = readStringParam(params, "thinking");
|
|
62
|
-
const cleanup = params.cleanup === "keep" || params.cleanup === "delete"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
to: opts?.agentTo,
|
|
69
|
-
threadId: opts?.agentThreadId,
|
|
70
|
-
});
|
|
71
|
-
const runTimeoutSeconds = (() => {
|
|
72
|
-
const explicit = typeof params.runTimeoutSeconds === "number" && Number.isFinite(params.runTimeoutSeconds)
|
|
73
|
-
? Math.max(0, Math.floor(params.runTimeoutSeconds))
|
|
29
|
+
const cleanup = params.cleanup === "keep" || params.cleanup === "delete" ? params.cleanup : "keep";
|
|
30
|
+
// Back-compat: older callers used timeoutSeconds for this tool.
|
|
31
|
+
const timeoutSecondsCandidate = typeof params.runTimeoutSeconds === "number"
|
|
32
|
+
? params.runTimeoutSeconds
|
|
33
|
+
: typeof params.timeoutSeconds === "number"
|
|
34
|
+
? params.timeoutSeconds
|
|
74
35
|
: undefined;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
: undefined;
|
|
80
|
-
return legacy ?? 0;
|
|
81
|
-
})();
|
|
82
|
-
let modelWarning;
|
|
83
|
-
let modelApplied = false;
|
|
84
|
-
const cfg = loadConfig();
|
|
85
|
-
const { mainKey, alias } = resolveMainSessionAlias(cfg);
|
|
86
|
-
const requesterSessionKey = opts?.agentSessionKey;
|
|
87
|
-
if (typeof requesterSessionKey === "string" && isSubagentSessionKey(requesterSessionKey)) {
|
|
88
|
-
return jsonResult({
|
|
89
|
-
status: "forbidden",
|
|
90
|
-
error: "sessions_spawn is not allowed from sub-agent sessions",
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
const requesterInternalKey = requesterSessionKey
|
|
94
|
-
? resolveInternalSessionKey({
|
|
95
|
-
key: requesterSessionKey,
|
|
96
|
-
alias,
|
|
97
|
-
mainKey,
|
|
98
|
-
})
|
|
99
|
-
: alias;
|
|
100
|
-
const requesterDisplayKey = resolveDisplaySessionKey({
|
|
101
|
-
key: requesterInternalKey,
|
|
102
|
-
alias,
|
|
103
|
-
mainKey,
|
|
104
|
-
});
|
|
105
|
-
const requesterAgentId = normalizeAgentId(opts?.requesterAgentIdOverride ?? parseAgentSessionKey(requesterInternalKey)?.agentId);
|
|
106
|
-
const targetAgentId = requestedAgentId
|
|
107
|
-
? normalizeAgentId(requestedAgentId)
|
|
108
|
-
: requesterAgentId;
|
|
109
|
-
if (targetAgentId !== requesterAgentId) {
|
|
110
|
-
const allowAgents = resolveAgentConfig(cfg, requesterAgentId)?.subagents?.allowAgents ?? [];
|
|
111
|
-
const allowAny = allowAgents.some((value) => value.trim() === "*");
|
|
112
|
-
const normalizedTargetId = targetAgentId.toLowerCase();
|
|
113
|
-
const allowSet = new Set(allowAgents
|
|
114
|
-
.filter((value) => value.trim() && value.trim() !== "*")
|
|
115
|
-
.map((value) => normalizeAgentId(value).toLowerCase()));
|
|
116
|
-
if (!allowAny && !allowSet.has(normalizedTargetId)) {
|
|
117
|
-
const allowedText = allowAny
|
|
118
|
-
? "*"
|
|
119
|
-
: allowSet.size > 0
|
|
120
|
-
? Array.from(allowSet).join(", ")
|
|
121
|
-
: "none";
|
|
122
|
-
return jsonResult({
|
|
123
|
-
status: "forbidden",
|
|
124
|
-
error: `agentId is not allowed for sessions_spawn (allowed: ${allowedText})`,
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
const childSessionKey = `agent:${targetAgentId}:subagent:${crypto.randomUUID()}`;
|
|
129
|
-
const spawnedByKey = requesterInternalKey;
|
|
130
|
-
const targetAgentConfig = resolveAgentConfig(cfg, targetAgentId);
|
|
131
|
-
const resolvedModel = normalizeModelSelection(modelOverride) ??
|
|
132
|
-
normalizeModelSelection(targetAgentConfig?.subagents?.model) ??
|
|
133
|
-
normalizeModelSelection(cfg.agents?.defaults?.subagents?.model);
|
|
134
|
-
let thinkingOverride;
|
|
135
|
-
if (thinkingOverrideRaw) {
|
|
136
|
-
const normalized = normalizeThinkLevel(thinkingOverrideRaw);
|
|
137
|
-
if (!normalized) {
|
|
138
|
-
const { provider, model } = splitModelRef(resolvedModel);
|
|
139
|
-
const hint = formatThinkingLevels(provider, model);
|
|
140
|
-
return jsonResult({
|
|
141
|
-
status: "error",
|
|
142
|
-
error: `Invalid thinking level "${thinkingOverrideRaw}". Use one of: ${hint}.`,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
thinkingOverride = normalized;
|
|
146
|
-
}
|
|
147
|
-
if (resolvedModel) {
|
|
148
|
-
try {
|
|
149
|
-
await callGateway({
|
|
150
|
-
method: "sessions.patch",
|
|
151
|
-
params: { key: childSessionKey, model: resolvedModel },
|
|
152
|
-
timeoutMs: 10_000,
|
|
153
|
-
});
|
|
154
|
-
modelApplied = true;
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
const messageText = err instanceof Error ? err.message : typeof err === "string" ? err : "error";
|
|
158
|
-
const recoverable = messageText.includes("invalid model") || messageText.includes("model not allowed");
|
|
159
|
-
if (!recoverable) {
|
|
160
|
-
return jsonResult({
|
|
161
|
-
status: "error",
|
|
162
|
-
error: messageText,
|
|
163
|
-
childSessionKey,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
modelWarning = messageText;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const childSystemPrompt = buildSubagentSystemPrompt({
|
|
170
|
-
requesterSessionKey,
|
|
171
|
-
requesterOrigin,
|
|
172
|
-
childSessionKey,
|
|
173
|
-
label: label || undefined,
|
|
36
|
+
const runTimeoutSeconds = typeof timeoutSecondsCandidate === "number" && Number.isFinite(timeoutSecondsCandidate)
|
|
37
|
+
? Math.max(0, Math.floor(timeoutSecondsCandidate))
|
|
38
|
+
: undefined;
|
|
39
|
+
const result = await spawnSubagentDirect({
|
|
174
40
|
task,
|
|
175
|
-
});
|
|
176
|
-
const childIdem = crypto.randomUUID();
|
|
177
|
-
let childRunId = childIdem;
|
|
178
|
-
try {
|
|
179
|
-
const response = (await callGateway({
|
|
180
|
-
method: "agent",
|
|
181
|
-
params: {
|
|
182
|
-
message: task,
|
|
183
|
-
sessionKey: childSessionKey,
|
|
184
|
-
channel: requesterOrigin?.channel,
|
|
185
|
-
idempotencyKey: childIdem,
|
|
186
|
-
deliver: false,
|
|
187
|
-
lane: AGENT_LANE_SUBAGENT,
|
|
188
|
-
extraSystemPrompt: childSystemPrompt,
|
|
189
|
-
thinking: thinkingOverride,
|
|
190
|
-
timeout: runTimeoutSeconds > 0 ? runTimeoutSeconds : undefined,
|
|
191
|
-
label: label || undefined,
|
|
192
|
-
spawnedBy: spawnedByKey,
|
|
193
|
-
groupId: opts?.agentGroupId ?? undefined,
|
|
194
|
-
groupChannel: opts?.agentGroupChannel ?? undefined,
|
|
195
|
-
groupSpace: opts?.agentGroupSpace ?? undefined,
|
|
196
|
-
},
|
|
197
|
-
timeoutMs: 10_000,
|
|
198
|
-
}));
|
|
199
|
-
if (typeof response?.runId === "string" && response.runId) {
|
|
200
|
-
childRunId = response.runId;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
catch (err) {
|
|
204
|
-
const messageText = err instanceof Error ? err.message : typeof err === "string" ? err : "error";
|
|
205
|
-
return jsonResult({
|
|
206
|
-
status: "error",
|
|
207
|
-
error: messageText,
|
|
208
|
-
childSessionKey,
|
|
209
|
-
runId: childRunId,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
registerSubagentRun({
|
|
213
|
-
runId: childRunId,
|
|
214
|
-
childSessionKey,
|
|
215
|
-
requesterSessionKey: requesterInternalKey,
|
|
216
|
-
requesterOrigin,
|
|
217
|
-
requesterDisplayKey,
|
|
218
|
-
task,
|
|
219
|
-
cleanup,
|
|
220
41
|
label: label || undefined,
|
|
42
|
+
agentId: requestedAgentId,
|
|
43
|
+
model: modelOverride,
|
|
44
|
+
thinking: thinkingOverrideRaw,
|
|
221
45
|
runTimeoutSeconds,
|
|
46
|
+
cleanup,
|
|
47
|
+
expectsCompletionMessage: true,
|
|
48
|
+
}, {
|
|
49
|
+
agentSessionKey: opts?.agentSessionKey,
|
|
50
|
+
agentChannel: opts?.agentChannel,
|
|
51
|
+
agentAccountId: opts?.agentAccountId,
|
|
52
|
+
agentTo: opts?.agentTo,
|
|
53
|
+
agentThreadId: opts?.agentThreadId,
|
|
54
|
+
agentGroupId: opts?.agentGroupId,
|
|
55
|
+
agentGroupChannel: opts?.agentGroupChannel,
|
|
56
|
+
agentGroupSpace: opts?.agentGroupSpace,
|
|
57
|
+
requesterAgentIdOverride: opts?.requesterAgentIdOverride,
|
|
222
58
|
});
|
|
223
|
-
return jsonResult(
|
|
224
|
-
status: "accepted",
|
|
225
|
-
childSessionKey,
|
|
226
|
-
runId: childRunId,
|
|
227
|
-
modelApplied: resolvedModel ? modelApplied : undefined,
|
|
228
|
-
warning: modelWarning,
|
|
229
|
-
});
|
|
59
|
+
return jsonResult(result);
|
|
230
60
|
},
|
|
231
61
|
};
|
|
232
62
|
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { createTelegramActionGate } from "../../telegram/accounts.js";
|
|
2
|
+
import { resolveTelegramInlineButtonsScope, resolveTelegramTargetChatType, } from "../../telegram/inline-buttons.js";
|
|
1
3
|
import { resolveTelegramReactionLevel } from "../../telegram/reaction-level.js";
|
|
2
|
-
import { deleteMessageTelegram, editMessageTelegram, reactMessageTelegram, sendMessageTelegram, sendStickerTelegram, } from "../../telegram/send.js";
|
|
4
|
+
import { createForumTopicTelegram, deleteMessageTelegram, editMessageTelegram, reactMessageTelegram, sendMessageTelegram, sendStickerTelegram, } from "../../telegram/send.js";
|
|
3
5
|
import { getCacheStats, searchStickers } from "../../telegram/sticker-cache.js";
|
|
4
6
|
import { resolveTelegramToken } from "../../telegram/token.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
+
import { jsonResult, readNumberParam, readReactionParams, readStringOrNumberParam, readStringParam, } from "./common.js";
|
|
8
|
+
const TELEGRAM_BUTTON_STYLES = ["danger", "success", "primary"];
|
|
7
9
|
export function readTelegramButtons(params) {
|
|
8
10
|
const raw = params.buttons;
|
|
9
|
-
if (raw == null)
|
|
11
|
+
if (raw == null) {
|
|
10
12
|
return undefined;
|
|
13
|
+
}
|
|
11
14
|
if (!Array.isArray(raw)) {
|
|
12
15
|
throw new Error("buttons must be an array of button rows");
|
|
13
16
|
}
|
|
@@ -31,7 +34,19 @@ export function readTelegramButtons(params) {
|
|
|
31
34
|
if (callbackData.length > 64) {
|
|
32
35
|
throw new Error(`buttons[${rowIndex}][${buttonIndex}] callback_data too long (max 64 chars)`);
|
|
33
36
|
}
|
|
34
|
-
|
|
37
|
+
const styleRaw = button.style;
|
|
38
|
+
const style = typeof styleRaw === "string" ? styleRaw.trim().toLowerCase() : undefined;
|
|
39
|
+
if (styleRaw !== undefined && !style) {
|
|
40
|
+
throw new Error(`buttons[${rowIndex}][${buttonIndex}] style must be string`);
|
|
41
|
+
}
|
|
42
|
+
if (style && !TELEGRAM_BUTTON_STYLES.includes(style)) {
|
|
43
|
+
throw new Error(`buttons[${rowIndex}][${buttonIndex}] style must be one of ${TELEGRAM_BUTTON_STYLES.join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
text,
|
|
47
|
+
callback_data: callbackData,
|
|
48
|
+
...(style ? { style: style } : {}),
|
|
49
|
+
};
|
|
35
50
|
});
|
|
36
51
|
});
|
|
37
52
|
const filtered = rows.filter((row) => row.length > 0);
|
|
@@ -40,7 +55,7 @@ export function readTelegramButtons(params) {
|
|
|
40
55
|
export async function handleTelegramAction(params, cfg) {
|
|
41
56
|
const action = readStringParam(params, "action", { required: true });
|
|
42
57
|
const accountId = readStringParam(params, "accountId");
|
|
43
|
-
const isActionEnabled =
|
|
58
|
+
const isActionEnabled = createTelegramActionGate({ cfg, accountId });
|
|
44
59
|
if (action === "react") {
|
|
45
60
|
// Check reaction level first
|
|
46
61
|
const reactionLevelInfo = resolveTelegramReactionLevel({
|
|
@@ -69,11 +84,18 @@ export async function handleTelegramAction(params, cfg) {
|
|
|
69
84
|
if (!token) {
|
|
70
85
|
throw new Error("Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.");
|
|
71
86
|
}
|
|
72
|
-
await reactMessageTelegram(chatId ?? "", messageId ?? 0, emoji ?? "", {
|
|
87
|
+
const reactionResult = await reactMessageTelegram(chatId ?? "", messageId ?? 0, emoji ?? "", {
|
|
73
88
|
token,
|
|
74
89
|
remove,
|
|
75
90
|
accountId: accountId ?? undefined,
|
|
76
91
|
});
|
|
92
|
+
if (!reactionResult.ok) {
|
|
93
|
+
return jsonResult({
|
|
94
|
+
ok: false,
|
|
95
|
+
warning: reactionResult.warning,
|
|
96
|
+
...(remove || isEmpty ? { removed: true } : { added: emoji }),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
77
99
|
if (!remove && !isEmpty) {
|
|
78
100
|
return jsonResult({ ok: true, added: emoji });
|
|
79
101
|
}
|
|
@@ -119,6 +141,7 @@ export async function handleTelegramAction(params, cfg) {
|
|
|
119
141
|
const messageThreadId = readNumberParam(params, "messageThreadId", {
|
|
120
142
|
integer: true,
|
|
121
143
|
});
|
|
144
|
+
const quoteText = readStringParam(params, "quoteText");
|
|
122
145
|
const token = resolveTelegramToken(cfg, { accountId }).token;
|
|
123
146
|
if (!token) {
|
|
124
147
|
throw new Error("Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.");
|
|
@@ -130,6 +153,7 @@ export async function handleTelegramAction(params, cfg) {
|
|
|
130
153
|
buttons,
|
|
131
154
|
replyToMessageId: replyToMessageId ?? undefined,
|
|
132
155
|
messageThreadId: messageThreadId ?? undefined,
|
|
156
|
+
quoteText: quoteText ?? undefined,
|
|
133
157
|
asVoice: typeof params.asVoice === "boolean" ? params.asVoice : undefined,
|
|
134
158
|
silent: typeof params.silent === "boolean" ? params.silent : undefined,
|
|
135
159
|
});
|
|
@@ -250,5 +274,32 @@ export async function handleTelegramAction(params, cfg) {
|
|
|
250
274
|
const stats = getCacheStats();
|
|
251
275
|
return jsonResult({ ok: true, ...stats });
|
|
252
276
|
}
|
|
277
|
+
if (action === "createForumTopic") {
|
|
278
|
+
if (!isActionEnabled("createForumTopic")) {
|
|
279
|
+
throw new Error("Telegram createForumTopic is disabled.");
|
|
280
|
+
}
|
|
281
|
+
const chatId = readStringOrNumberParam(params, "chatId", {
|
|
282
|
+
required: true,
|
|
283
|
+
});
|
|
284
|
+
const name = readStringParam(params, "name", { required: true });
|
|
285
|
+
const iconColor = readNumberParam(params, "iconColor", { integer: true });
|
|
286
|
+
const iconCustomEmojiId = readStringParam(params, "iconCustomEmojiId");
|
|
287
|
+
const token = resolveTelegramToken(cfg, { accountId }).token;
|
|
288
|
+
if (!token) {
|
|
289
|
+
throw new Error("Telegram bot token missing. Set TELEGRAM_BOT_TOKEN or channels.telegram.botToken.");
|
|
290
|
+
}
|
|
291
|
+
const result = await createForumTopicTelegram(chatId ?? "", name, {
|
|
292
|
+
token,
|
|
293
|
+
accountId: accountId ?? undefined,
|
|
294
|
+
iconColor: iconColor ?? undefined,
|
|
295
|
+
iconCustomEmojiId: iconCustomEmojiId ?? undefined,
|
|
296
|
+
});
|
|
297
|
+
return jsonResult({
|
|
298
|
+
ok: true,
|
|
299
|
+
topicId: result.topicId,
|
|
300
|
+
name: result.name,
|
|
301
|
+
chatId: result.chatId,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
253
304
|
throw new Error(`Unsupported Telegram action: ${action}`);
|
|
254
305
|
}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
const READABILITY_MAX_HTML_CHARS = 1_000_000;
|
|
2
|
+
const READABILITY_MAX_ESTIMATED_NESTING_DEPTH = 3_000;
|
|
3
|
+
let readabilityDepsPromise;
|
|
4
|
+
async function loadReadabilityDeps() {
|
|
5
|
+
if (!readabilityDepsPromise) {
|
|
6
|
+
readabilityDepsPromise = Promise.all([import("@mozilla/readability"), import("linkedom")]).then(([readability, linkedom]) => ({
|
|
7
|
+
Readability: readability.Readability,
|
|
8
|
+
parseHTML: linkedom.parseHTML,
|
|
9
|
+
}));
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
return await readabilityDepsPromise;
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
readabilityDepsPromise = undefined;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
1
19
|
function decodeEntities(value) {
|
|
2
20
|
return value
|
|
3
21
|
.replace(/ /gi, " ")
|
|
@@ -29,8 +47,9 @@ export function htmlToMarkdown(html) {
|
|
|
29
47
|
.replace(/<noscript[\s\S]*?<\/noscript>/gi, "");
|
|
30
48
|
text = text.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (_, href, body) => {
|
|
31
49
|
const label = normalizeWhitespace(stripTags(body));
|
|
32
|
-
if (!label)
|
|
50
|
+
if (!label) {
|
|
33
51
|
return href;
|
|
52
|
+
}
|
|
34
53
|
return `[${label}](${href})`;
|
|
35
54
|
});
|
|
36
55
|
text = text.replace(/<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi, (_, level, body) => {
|
|
@@ -61,10 +80,94 @@ export function markdownToText(markdown) {
|
|
|
61
80
|
return normalizeWhitespace(text);
|
|
62
81
|
}
|
|
63
82
|
export function truncateText(value, maxChars) {
|
|
64
|
-
if (value.length <= maxChars)
|
|
83
|
+
if (value.length <= maxChars) {
|
|
65
84
|
return { text: value, truncated: false };
|
|
85
|
+
}
|
|
66
86
|
return { text: value.slice(0, maxChars), truncated: true };
|
|
67
87
|
}
|
|
88
|
+
function exceedsEstimatedHtmlNestingDepth(html, maxDepth) {
|
|
89
|
+
// Cheap heuristic to skip Readability+DOM parsing on pathological HTML (deep nesting => stack/memory blowups).
|
|
90
|
+
// Not an HTML parser; tuned to catch attacker-controlled "<div><div>..." cases.
|
|
91
|
+
const voidTags = new Set([
|
|
92
|
+
"area",
|
|
93
|
+
"base",
|
|
94
|
+
"br",
|
|
95
|
+
"col",
|
|
96
|
+
"embed",
|
|
97
|
+
"hr",
|
|
98
|
+
"img",
|
|
99
|
+
"input",
|
|
100
|
+
"link",
|
|
101
|
+
"meta",
|
|
102
|
+
"param",
|
|
103
|
+
"source",
|
|
104
|
+
"track",
|
|
105
|
+
"wbr",
|
|
106
|
+
]);
|
|
107
|
+
let depth = 0;
|
|
108
|
+
const len = html.length;
|
|
109
|
+
for (let i = 0; i < len; i++) {
|
|
110
|
+
if (html.charCodeAt(i) !== 60) {
|
|
111
|
+
continue; // '<'
|
|
112
|
+
}
|
|
113
|
+
const next = html.charCodeAt(i + 1);
|
|
114
|
+
if (next === 33 || next === 63) {
|
|
115
|
+
continue; // <! ...> or <? ...>
|
|
116
|
+
}
|
|
117
|
+
let j = i + 1;
|
|
118
|
+
let closing = false;
|
|
119
|
+
if (html.charCodeAt(j) === 47) {
|
|
120
|
+
closing = true;
|
|
121
|
+
j += 1;
|
|
122
|
+
}
|
|
123
|
+
while (j < len && html.charCodeAt(j) <= 32) {
|
|
124
|
+
j += 1;
|
|
125
|
+
}
|
|
126
|
+
const nameStart = j;
|
|
127
|
+
while (j < len) {
|
|
128
|
+
const c = html.charCodeAt(j);
|
|
129
|
+
const isNameChar = (c >= 65 && c <= 90) || // A-Z
|
|
130
|
+
(c >= 97 && c <= 122) || // a-z
|
|
131
|
+
(c >= 48 && c <= 57) || // 0-9
|
|
132
|
+
c === 58 || // :
|
|
133
|
+
c === 45; // -
|
|
134
|
+
if (!isNameChar) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
j += 1;
|
|
138
|
+
}
|
|
139
|
+
const tagName = html.slice(nameStart, j).toLowerCase();
|
|
140
|
+
if (!tagName) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (closing) {
|
|
144
|
+
depth = Math.max(0, depth - 1);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (voidTags.has(tagName)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// Best-effort self-closing detection: scan a short window for "/>".
|
|
151
|
+
let selfClosing = false;
|
|
152
|
+
for (let k = j; k < len && k < j + 200; k++) {
|
|
153
|
+
const c = html.charCodeAt(k);
|
|
154
|
+
if (c === 62) {
|
|
155
|
+
if (html.charCodeAt(k - 1) === 47) {
|
|
156
|
+
selfClosing = true;
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (selfClosing) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
depth += 1;
|
|
165
|
+
if (depth > maxDepth) {
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
68
171
|
export async function extractReadableContent(params) {
|
|
69
172
|
const fallback = () => {
|
|
70
173
|
const rendered = htmlToMarkdown(params.html);
|
|
@@ -74,11 +177,12 @@ export async function extractReadableContent(params) {
|
|
|
74
177
|
}
|
|
75
178
|
return rendered;
|
|
76
179
|
};
|
|
180
|
+
if (params.html.length > READABILITY_MAX_HTML_CHARS ||
|
|
181
|
+
exceedsEstimatedHtmlNestingDepth(params.html, READABILITY_MAX_ESTIMATED_NESTING_DEPTH)) {
|
|
182
|
+
return fallback();
|
|
183
|
+
}
|
|
77
184
|
try {
|
|
78
|
-
const
|
|
79
|
-
import("@mozilla/readability"),
|
|
80
|
-
import("linkedom"),
|
|
81
|
-
]);
|
|
185
|
+
const { Readability, parseHTML } = await loadReadabilityDeps();
|
|
82
186
|
const { document } = parseHTML(params.html);
|
|
83
187
|
try {
|
|
84
188
|
document.baseURI = params.url;
|
|
@@ -88,8 +192,9 @@ export async function extractReadableContent(params) {
|
|
|
88
192
|
}
|
|
89
193
|
const reader = new Readability(document, { charThreshold: 0 });
|
|
90
194
|
const parsed = reader.parse();
|
|
91
|
-
if (!parsed?.content)
|
|
195
|
+
if (!parsed?.content) {
|
|
92
196
|
return fallback();
|
|
197
|
+
}
|
|
93
198
|
const title = parsed.title || undefined;
|
|
94
199
|
if (params.extractMode === "text") {
|
|
95
200
|
const text = normalizeWhitespace(parsed.textContent ?? "");
|