@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
|
@@ -3,41 +3,53 @@ import os from "node:os";
|
|
|
3
3
|
import { streamSimple } from "@mariozechner/pi-ai";
|
|
4
4
|
import { createAgentSession, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
|
|
5
5
|
import { resolveHeartbeatPrompt } from "../../../auto-reply/heartbeat.js";
|
|
6
|
-
import { listChannelSupportedActions, resolveChannelMessageToolHints, } from "../../channel-tools.js";
|
|
7
6
|
import { resolveChannelCapabilities } from "../../../config/channel-capabilities.js";
|
|
8
7
|
import { getMachineDisplayName } from "../../../infra/machine-name.js";
|
|
8
|
+
import { MAX_IMAGE_BYTES } from "../../../media/constants.js";
|
|
9
|
+
import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js";
|
|
10
|
+
import { isCronSessionKey, isSubagentSessionKey, normalizeAgentId, } from "../../../routing/session-key.js";
|
|
11
|
+
import { resolveSignalReactionLevel } from "../../../signal/reaction-level.js";
|
|
9
12
|
import { resolveTelegramInlineButtonsScope } from "../../../telegram/inline-buttons.js";
|
|
10
13
|
import { resolveTelegramReactionLevel } from "../../../telegram/reaction-level.js";
|
|
11
|
-
import {
|
|
14
|
+
import { buildTtsSystemPromptHint } from "../../../tts/tts.js";
|
|
15
|
+
import { resolveUserPath } from "../../../utils.js";
|
|
12
16
|
import { normalizeMessageChannel } from "../../../utils/message-channel.js";
|
|
13
17
|
import { isReasoningTagProvider } from "../../../utils/provider-utils.js";
|
|
14
|
-
import { isSubagentSessionKey } from "../../../routing/session-key.js";
|
|
15
|
-
import { resolveUserPath } from "../../../utils.js";
|
|
16
|
-
import { createCacheTrace } from "../../cache-trace.js";
|
|
17
|
-
import { createAnthropicPayloadLogger } from "../../anthropic-payload-log.js";
|
|
18
18
|
import { resolvePoolbotAgentDir } from "../../agent-paths.js";
|
|
19
19
|
import { resolveSessionAgentIds } from "../../agent-scope.js";
|
|
20
|
+
import { createAnthropicPayloadLogger } from "../../anthropic-payload-log.js";
|
|
20
21
|
import { makeBootstrapWarn, resolveBootstrapContextForRun } from "../../bootstrap-files.js";
|
|
22
|
+
import { createCacheTrace } from "../../cache-trace.js";
|
|
23
|
+
import { listChannelSupportedActions, resolveChannelMessageToolHints, } from "../../channel-tools.js";
|
|
24
|
+
import { DEFAULT_CONTEXT_TOKENS } from "../../defaults.js";
|
|
21
25
|
import { resolvePoolbotDocsPath } from "../../docs-path.js";
|
|
26
|
+
import { isTimeoutError } from "../../failover-error.js";
|
|
27
|
+
import { resolveImageSanitizationLimits } from "../../image-sanitization.js";
|
|
22
28
|
import { resolveModelAuthMode } from "../../model-auth.js";
|
|
23
|
-
import {
|
|
29
|
+
import { resolveDefaultModelForAgent } from "../../model-selection.js";
|
|
30
|
+
import { createOllamaStreamFn, OLLAMA_NATIVE_BASE_URL } from "../../ollama-stream.js";
|
|
31
|
+
import { isCloudCodeAssistFormatError, resolveBootstrapMaxChars, resolveBootstrapTotalMaxChars, validateAnthropicTurns, validateGeminiTurns, } from "../../pi-embedded-helpers.js";
|
|
24
32
|
import { subscribeEmbeddedPiSession } from "../../pi-embedded-subscribe.js";
|
|
25
33
|
import { ensurePiCompactionReserveTokens, resolveCompactionReserveTokensFloor, } from "../../pi-settings.js";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
34
|
+
import { toClientToolDefinitions } from "../../pi-tool-definition-adapter.js";
|
|
35
|
+
import { createPoolbotCodingTools, resolveToolLoopDetectionConfig } from "../../pi-tools.js";
|
|
28
36
|
import { resolveSandboxContext } from "../../sandbox.js";
|
|
37
|
+
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
|
38
|
+
import { repairSessionFileIfNeeded } from "../../session-file-repair.js";
|
|
29
39
|
import { guardSessionManager } from "../../session-tool-result-guard-wrapper.js";
|
|
30
|
-
import {
|
|
31
|
-
import { acquireSessionWriteLock } from "../../session-write-lock.js";
|
|
40
|
+
import { sanitizeToolUseResultPairing } from "../../session-transcript-repair.js";
|
|
41
|
+
import { acquireSessionWriteLock, resolveSessionLockMaxHoldFromTimeout, } from "../../session-write-lock.js";
|
|
42
|
+
import { detectRuntimeShell } from "../../shell-utils.js";
|
|
32
43
|
import { applySkillEnvOverrides, applySkillEnvOverridesFromSnapshot, loadWorkspaceSkillEntries, resolveSkillsPromptForRun, } from "../../skills.js";
|
|
33
|
-
import {
|
|
44
|
+
import { buildSystemPromptParams } from "../../system-prompt-params.js";
|
|
34
45
|
import { buildSystemPromptReport } from "../../system-prompt-report.js";
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
46
|
+
import { resolveTranscriptPolicy } from "../../transcript-policy.js";
|
|
47
|
+
import { DEFAULT_BOOTSTRAP_FILENAME } from "../../workspace.js";
|
|
48
|
+
import { isRunnerAbortError } from "../abort.js";
|
|
49
|
+
import { appendCacheTtlTimestamp, isCacheTtlEligibleProvider } from "../cache-ttl.js";
|
|
37
50
|
import { buildEmbeddedExtensionPaths } from "../extensions.js";
|
|
38
51
|
import { applyExtraParamsToAgent } from "../extra-params.js";
|
|
39
|
-
import {
|
|
40
|
-
import { logToolSchemasForGoogle, sanitizeSessionHistory, sanitizeToolsForGoogle, } from "../google.js";
|
|
52
|
+
import { logToolSchemasForGoogle, sanitizeAntigravityThinkingBlocks, sanitizeSessionHistory, sanitizeToolsForGoogle, } from "../google.js";
|
|
41
53
|
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "../history.js";
|
|
42
54
|
import { log } from "../logger.js";
|
|
43
55
|
import { buildModelAliasLines } from "../model.js";
|
|
@@ -46,25 +58,22 @@ import { buildEmbeddedSandboxInfo } from "../sandbox-info.js";
|
|
|
46
58
|
import { prewarmSessionFile, trackSessionManagerAccess } from "../session-manager-cache.js";
|
|
47
59
|
import { prepareSessionManagerForRun } from "../session-manager-init.js";
|
|
48
60
|
import { applySystemPromptOverrideToSession, buildEmbeddedSystemPrompt, createSystemPromptOverride, } from "../system-prompt.js";
|
|
61
|
+
import { installToolResultContextGuard } from "../tool-result-context-guard.js";
|
|
49
62
|
import { splitSdkTools } from "../tool-split.js";
|
|
50
|
-
import { toClientToolDefinitions } from "../../pi-tool-definition-adapter.js";
|
|
51
|
-
import { buildSystemPromptParams } from "../../system-prompt-params.js";
|
|
52
|
-
import { detectRuntimeShell } from "../../shell-utils.js";
|
|
53
63
|
import { describeUnknownError, mapThinkingLevel } from "../utils.js";
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import { isTimeoutError } from "../../failover-error.js";
|
|
57
|
-
import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js";
|
|
58
|
-
import { MAX_IMAGE_BYTES } from "../../../media/constants.js";
|
|
64
|
+
import { flushPendingToolResultsAfterIdle } from "../wait-for-idle-before-flush.js";
|
|
65
|
+
import { selectCompactionTimeoutSnapshot, shouldFlagCompactionTimeout, } from "./compaction-timeout.js";
|
|
59
66
|
import { detectAndLoadPromptImages } from "./images.js";
|
|
60
67
|
export function injectHistoryImagesIntoMessages(messages, historyImagesByIndex) {
|
|
61
|
-
if (historyImagesByIndex.size === 0)
|
|
68
|
+
if (historyImagesByIndex.size === 0) {
|
|
62
69
|
return false;
|
|
70
|
+
}
|
|
63
71
|
let didMutate = false;
|
|
64
72
|
for (const [msgIndex, images] of historyImagesByIndex) {
|
|
65
73
|
// Bounds check: ensure index is valid before accessing
|
|
66
|
-
if (msgIndex < 0 || msgIndex >= messages.length)
|
|
74
|
+
if (msgIndex < 0 || msgIndex >= messages.length) {
|
|
67
75
|
continue;
|
|
76
|
+
}
|
|
68
77
|
const msg = messages[msgIndex];
|
|
69
78
|
if (msg && msg.role === "user") {
|
|
70
79
|
// Convert string content to array format if needed
|
|
@@ -92,6 +101,56 @@ export function injectHistoryImagesIntoMessages(messages, historyImagesByIndex)
|
|
|
92
101
|
}
|
|
93
102
|
return didMutate;
|
|
94
103
|
}
|
|
104
|
+
function summarizeMessagePayload(msg) {
|
|
105
|
+
const content = msg.content;
|
|
106
|
+
if (typeof content === "string") {
|
|
107
|
+
return { textChars: content.length, imageBlocks: 0 };
|
|
108
|
+
}
|
|
109
|
+
if (!Array.isArray(content)) {
|
|
110
|
+
return { textChars: 0, imageBlocks: 0 };
|
|
111
|
+
}
|
|
112
|
+
let textChars = 0;
|
|
113
|
+
let imageBlocks = 0;
|
|
114
|
+
for (const block of content) {
|
|
115
|
+
if (!block || typeof block !== "object") {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const typedBlock = block;
|
|
119
|
+
if (typedBlock.type === "image") {
|
|
120
|
+
imageBlocks++;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (typeof typedBlock.text === "string") {
|
|
124
|
+
textChars += typedBlock.text.length;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { textChars, imageBlocks };
|
|
128
|
+
}
|
|
129
|
+
function summarizeSessionContext(messages) {
|
|
130
|
+
const roleCounts = new Map();
|
|
131
|
+
let totalTextChars = 0;
|
|
132
|
+
let totalImageBlocks = 0;
|
|
133
|
+
let maxMessageTextChars = 0;
|
|
134
|
+
for (const msg of messages) {
|
|
135
|
+
const role = typeof msg.role === "string" ? msg.role : "unknown";
|
|
136
|
+
roleCounts.set(role, (roleCounts.get(role) ?? 0) + 1);
|
|
137
|
+
const payload = summarizeMessagePayload(msg);
|
|
138
|
+
totalTextChars += payload.textChars;
|
|
139
|
+
totalImageBlocks += payload.imageBlocks;
|
|
140
|
+
if (payload.textChars > maxMessageTextChars) {
|
|
141
|
+
maxMessageTextChars = payload.textChars;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
roleCounts: [...roleCounts.entries()]
|
|
146
|
+
.toSorted((a, b) => a[0].localeCompare(b[0]))
|
|
147
|
+
.map(([role, count]) => `${role}:${count}`)
|
|
148
|
+
.join(",") || "none",
|
|
149
|
+
totalTextChars,
|
|
150
|
+
totalImageBlocks,
|
|
151
|
+
maxMessageTextChars,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
95
154
|
export async function runEmbeddedAttempt(params) {
|
|
96
155
|
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
|
97
156
|
const prevCwd = process.cwd();
|
|
@@ -174,6 +233,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
174
233
|
abortSignal: runAbortController.signal,
|
|
175
234
|
modelProvider: params.model.provider,
|
|
176
235
|
modelId: params.modelId,
|
|
236
|
+
modelContextWindowTokens: params.model.contextWindow,
|
|
177
237
|
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config),
|
|
178
238
|
currentChannelId: params.currentChannelId,
|
|
179
239
|
currentThreadTs: params.currentThreadTs,
|
|
@@ -200,8 +260,9 @@ export async function runEmbeddedAttempt(params) {
|
|
|
200
260
|
accountId: params.agentAccountId ?? undefined,
|
|
201
261
|
});
|
|
202
262
|
if (inlineButtonsScope !== "off") {
|
|
203
|
-
if (!runtimeCapabilities)
|
|
263
|
+
if (!runtimeCapabilities) {
|
|
204
264
|
runtimeCapabilities = [];
|
|
265
|
+
}
|
|
205
266
|
if (!runtimeCapabilities.some((cap) => String(cap).trim().toLowerCase() === "inlinebuttons")) {
|
|
206
267
|
runtimeCapabilities.push("inlineButtons");
|
|
207
268
|
}
|
|
@@ -265,14 +326,16 @@ export async function runEmbeddedAttempt(params) {
|
|
|
265
326
|
node: process.version,
|
|
266
327
|
model: `${params.provider}/${params.modelId}`,
|
|
267
328
|
defaultModel: defaultModelLabel,
|
|
329
|
+
shell: detectRuntimeShell(),
|
|
268
330
|
channel: runtimeChannel,
|
|
269
331
|
capabilities: runtimeCapabilities,
|
|
270
332
|
channelActions,
|
|
271
|
-
shell: detectRuntimeShell(),
|
|
272
333
|
},
|
|
273
334
|
});
|
|
274
335
|
const isDefaultAgent = sessionAgentId === defaultAgentId;
|
|
275
|
-
const promptMode = isSubagentSessionKey(params.sessionKey)
|
|
336
|
+
const promptMode = isSubagentSessionKey(params.sessionKey) || isCronSessionKey(params.sessionKey)
|
|
337
|
+
? "minimal"
|
|
338
|
+
: "full";
|
|
276
339
|
const docsPath = await resolvePoolbotDocsPath({
|
|
277
340
|
workspaceDir: effectiveWorkspace,
|
|
278
341
|
argv1: process.argv[1],
|
|
@@ -316,6 +379,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
316
379
|
model: params.modelId,
|
|
317
380
|
workspaceDir: effectiveWorkspace,
|
|
318
381
|
bootstrapMaxChars: resolveBootstrapMaxChars(params.config),
|
|
382
|
+
bootstrapTotalMaxChars: resolveBootstrapTotalMaxChars(params.config),
|
|
319
383
|
sandbox: (() => {
|
|
320
384
|
const runtime = resolveSandboxRuntimeStatus({
|
|
321
385
|
cfg: params.config,
|
|
@@ -333,9 +397,13 @@ export async function runEmbeddedAttempt(params) {
|
|
|
333
397
|
const systemPromptText = systemPromptOverride();
|
|
334
398
|
const sessionLock = await acquireSessionWriteLock({
|
|
335
399
|
sessionFile: params.sessionFile,
|
|
400
|
+
maxHoldMs: resolveSessionLockMaxHoldFromTimeout({
|
|
401
|
+
timeoutMs: params.timeoutMs,
|
|
402
|
+
}),
|
|
336
403
|
});
|
|
337
404
|
let sessionManager;
|
|
338
405
|
let session;
|
|
406
|
+
let removeToolResultContextGuard;
|
|
339
407
|
try {
|
|
340
408
|
await repairSessionFileIfNeeded({
|
|
341
409
|
sessionFile: params.sessionFile,
|
|
@@ -354,6 +422,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
354
422
|
sessionManager = guardSessionManager(SessionManager.open(params.sessionFile), {
|
|
355
423
|
agentId: sessionAgentId,
|
|
356
424
|
sessionKey: params.sessionKey,
|
|
425
|
+
inputProvenance: params.inputProvenance,
|
|
357
426
|
allowSyntheticToolResults: transcriptPolicy.allowSyntheticToolResults,
|
|
358
427
|
});
|
|
359
428
|
trackSessionManagerAccess(params.sessionFile);
|
|
@@ -369,6 +438,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
369
438
|
settingsManager,
|
|
370
439
|
minReserveTokens: resolveCompactionReserveTokensFloor(params.config),
|
|
371
440
|
});
|
|
441
|
+
// Call for side effects (sets compaction/pruning runtime state)
|
|
372
442
|
buildEmbeddedExtensionPaths({
|
|
373
443
|
cfg: params.config,
|
|
374
444
|
sessionManager,
|
|
@@ -376,16 +446,26 @@ export async function runEmbeddedAttempt(params) {
|
|
|
376
446
|
modelId: params.modelId,
|
|
377
447
|
model: params.model,
|
|
378
448
|
});
|
|
449
|
+
// Get hook runner early so it's available when creating tools
|
|
450
|
+
const hookRunner = getGlobalHookRunner();
|
|
379
451
|
const { builtInTools, customTools } = splitSdkTools({
|
|
380
452
|
tools,
|
|
381
453
|
sandboxEnabled: !!sandbox?.enabled,
|
|
382
454
|
});
|
|
383
455
|
// Add client tools (OpenResponses hosted tools) to customTools
|
|
384
456
|
let clientToolCallDetected = null;
|
|
457
|
+
const clientToolLoopDetection = resolveToolLoopDetectionConfig({
|
|
458
|
+
cfg: params.config,
|
|
459
|
+
agentId: sessionAgentId,
|
|
460
|
+
});
|
|
385
461
|
const clientToolDefs = params.clientTools
|
|
386
462
|
? toClientToolDefinitions(params.clientTools, (toolName, toolParams) => {
|
|
387
463
|
clientToolCallDetected = { name: toolName, params: toolParams };
|
|
388
|
-
}, {
|
|
464
|
+
}, {
|
|
465
|
+
agentId: sessionAgentId,
|
|
466
|
+
sessionKey: params.sessionKey,
|
|
467
|
+
loopDetection: clientToolLoopDetection,
|
|
468
|
+
})
|
|
389
469
|
: [];
|
|
390
470
|
const allCustomTools = [...customTools, ...clientToolDefs];
|
|
391
471
|
({ session } = await createAgentSession({
|
|
@@ -405,6 +485,10 @@ export async function runEmbeddedAttempt(params) {
|
|
|
405
485
|
throw new Error("Embedded agent session missing");
|
|
406
486
|
}
|
|
407
487
|
const activeSession = session;
|
|
488
|
+
removeToolResultContextGuard = installToolResultContextGuard({
|
|
489
|
+
agent: activeSession.agent,
|
|
490
|
+
contextWindowTokens: Math.max(1, Math.floor(params.model.contextWindow ?? params.model.maxTokens ?? DEFAULT_CONTEXT_TOKENS)),
|
|
491
|
+
});
|
|
408
492
|
const cacheTrace = createCacheTrace({
|
|
409
493
|
cfg: params.config,
|
|
410
494
|
env: process.env,
|
|
@@ -426,8 +510,20 @@ export async function runEmbeddedAttempt(params) {
|
|
|
426
510
|
modelApi: params.model.api,
|
|
427
511
|
workspaceDir: params.workspaceDir,
|
|
428
512
|
});
|
|
429
|
-
//
|
|
430
|
-
|
|
513
|
+
// Ollama native API: bypass SDK's streamSimple and use direct /api/chat calls
|
|
514
|
+
// for reliable streaming + tool calling support (#11828).
|
|
515
|
+
if (params.model.api === "ollama") {
|
|
516
|
+
// Use the resolved model baseUrl first so custom provider aliases work.
|
|
517
|
+
const providerConfig = params.config?.models?.providers?.[params.model.provider];
|
|
518
|
+
const modelBaseUrl = typeof params.model.baseUrl === "string" ? params.model.baseUrl.trim() : "";
|
|
519
|
+
const providerBaseUrl = typeof providerConfig?.baseUrl === "string" ? providerConfig.baseUrl.trim() : "";
|
|
520
|
+
const ollamaBaseUrl = modelBaseUrl || providerBaseUrl || OLLAMA_NATIVE_BASE_URL;
|
|
521
|
+
activeSession.agent.streamFn = createOllamaStreamFn(ollamaBaseUrl);
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
// Force a stable streamFn reference so vitest can reliably mock @mariozechner/pi-ai.
|
|
525
|
+
activeSession.agent.streamFn = streamSimple;
|
|
526
|
+
}
|
|
431
527
|
applyExtraParamsToAgent(activeSession.agent, params.config, params.provider, params.modelId, params.streamParams);
|
|
432
528
|
if (cacheTrace) {
|
|
433
529
|
cacheTrace.recordStage("session:loaded", {
|
|
@@ -446,6 +542,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
446
542
|
modelApi: params.model.api,
|
|
447
543
|
modelId: params.modelId,
|
|
448
544
|
provider: params.provider,
|
|
545
|
+
config: params.config,
|
|
449
546
|
sessionManager,
|
|
450
547
|
sessionId: params.sessionId,
|
|
451
548
|
policy: transcriptPolicy,
|
|
@@ -457,19 +554,29 @@ export async function runEmbeddedAttempt(params) {
|
|
|
457
554
|
const validated = transcriptPolicy.validateAnthropicTurns
|
|
458
555
|
? validateAnthropicTurns(validatedGemini)
|
|
459
556
|
: validatedGemini;
|
|
460
|
-
const
|
|
557
|
+
const truncated = limitHistoryTurns(validated, getDmHistoryLimitFromSessionKey(params.sessionKey, params.config));
|
|
558
|
+
// Re-run tool_use/tool_result pairing repair after truncation, since
|
|
559
|
+
// limitHistoryTurns can orphan tool_result blocks by removing the
|
|
560
|
+
// assistant message that contained the matching tool_use.
|
|
561
|
+
const limited = transcriptPolicy.repairToolUseResultPairing
|
|
562
|
+
? sanitizeToolUseResultPairing(truncated)
|
|
563
|
+
: truncated;
|
|
461
564
|
cacheTrace?.recordStage("session:limited", { messages: limited });
|
|
462
565
|
if (limited.length > 0) {
|
|
463
566
|
activeSession.agent.replaceMessages(limited);
|
|
464
567
|
}
|
|
465
568
|
}
|
|
466
569
|
catch (err) {
|
|
467
|
-
|
|
570
|
+
await flushPendingToolResultsAfterIdle({
|
|
571
|
+
agent: activeSession?.agent,
|
|
572
|
+
sessionManager,
|
|
573
|
+
});
|
|
468
574
|
activeSession.dispose();
|
|
469
575
|
throw err;
|
|
470
576
|
}
|
|
471
577
|
let aborted = Boolean(params.abortSignal?.aborted);
|
|
472
578
|
let timedOut = false;
|
|
579
|
+
let timedOutDuringCompaction = false;
|
|
473
580
|
const getAbortReason = (signal) => "reason" in signal ? signal.reason : undefined;
|
|
474
581
|
const makeTimeoutAbortReason = () => {
|
|
475
582
|
const err = new Error("request timed out");
|
|
@@ -484,8 +591,9 @@ export async function runEmbeddedAttempt(params) {
|
|
|
484
591
|
};
|
|
485
592
|
const abortRun = (isTimeout = false, reason) => {
|
|
486
593
|
aborted = true;
|
|
487
|
-
if (isTimeout)
|
|
594
|
+
if (isTimeout) {
|
|
488
595
|
timedOut = true;
|
|
596
|
+
}
|
|
489
597
|
if (isTimeout) {
|
|
490
598
|
runAbortController.abort(reason ?? makeTimeoutAbortReason());
|
|
491
599
|
}
|
|
@@ -517,6 +625,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
517
625
|
const subscription = subscribeEmbeddedPiSession({
|
|
518
626
|
session: activeSession,
|
|
519
627
|
runId: params.runId,
|
|
628
|
+
hookRunner: getGlobalHookRunner() ?? undefined,
|
|
520
629
|
verboseLevel: params.verboseLevel,
|
|
521
630
|
reasoningMode: params.reasoningLevel ?? "off",
|
|
522
631
|
toolResultFormat: params.toolResultFormat,
|
|
@@ -524,6 +633,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
524
633
|
shouldEmitToolOutput: params.shouldEmitToolOutput,
|
|
525
634
|
onToolResult: params.onToolResult,
|
|
526
635
|
onReasoningStream: params.onReasoningStream,
|
|
636
|
+
onReasoningEnd: params.onReasoningEnd,
|
|
527
637
|
onBlockReply: params.onBlockReply,
|
|
528
638
|
onBlockReplyFlush: params.onBlockReplyFlush,
|
|
529
639
|
blockReplyBreak: params.blockReplyBreak,
|
|
@@ -532,8 +642,10 @@ export async function runEmbeddedAttempt(params) {
|
|
|
532
642
|
onAssistantMessageStart: params.onAssistantMessageStart,
|
|
533
643
|
onAgentEvent: params.onAgentEvent,
|
|
534
644
|
enforceFinalTag: params.enforceFinalTag,
|
|
645
|
+
config: params.config,
|
|
646
|
+
sessionKey: params.sessionKey ?? params.sessionId,
|
|
535
647
|
});
|
|
536
|
-
const { assistantTexts, toolMetas, unsubscribe, waitForCompactionRetry, getMessagingToolSentTexts, getMessagingToolSentTargets, didSendViaMessagingTool, getLastToolError, } = subscription;
|
|
648
|
+
const { assistantTexts, toolMetas, unsubscribe, waitForCompactionRetry, getMessagingToolSentTexts, getMessagingToolSentMediaUrls, getMessagingToolSentTargets, getSuccessfulCronAdds, didSendViaMessagingTool, getLastToolError, getUsageTotals, getCompactionCount, } = subscription;
|
|
537
649
|
const queueHandle = {
|
|
538
650
|
queueMessage: async (text) => {
|
|
539
651
|
await activeSession.steer(text);
|
|
@@ -542,18 +654,26 @@ export async function runEmbeddedAttempt(params) {
|
|
|
542
654
|
isCompacting: () => subscription.isCompacting(),
|
|
543
655
|
abort: abortRun,
|
|
544
656
|
};
|
|
545
|
-
setActiveEmbeddedRun(params.sessionId, queueHandle);
|
|
657
|
+
setActiveEmbeddedRun(params.sessionId, queueHandle, params.sessionKey);
|
|
546
658
|
let abortWarnTimer;
|
|
547
659
|
const isProbeSession = params.sessionId?.startsWith("probe-") ?? false;
|
|
548
660
|
const abortTimer = setTimeout(() => {
|
|
549
661
|
if (!isProbeSession) {
|
|
550
662
|
log.warn(`embedded run timeout: runId=${params.runId} sessionId=${params.sessionId} timeoutMs=${params.timeoutMs}`);
|
|
551
663
|
}
|
|
664
|
+
if (shouldFlagCompactionTimeout({
|
|
665
|
+
isTimeout: true,
|
|
666
|
+
isCompactionPendingOrRetrying: subscription.isCompacting(),
|
|
667
|
+
isCompactionInFlight: activeSession.isCompacting,
|
|
668
|
+
})) {
|
|
669
|
+
timedOutDuringCompaction = true;
|
|
670
|
+
}
|
|
552
671
|
abortRun(true);
|
|
553
672
|
if (!abortWarnTimer) {
|
|
554
673
|
abortWarnTimer = setTimeout(() => {
|
|
555
|
-
if (!activeSession.isStreaming)
|
|
674
|
+
if (!activeSession.isStreaming) {
|
|
556
675
|
return;
|
|
676
|
+
}
|
|
557
677
|
if (!isProbeSession) {
|
|
558
678
|
log.warn(`embedded run abort still streaming: runId=${params.runId} sessionId=${params.sessionId}`);
|
|
559
679
|
}
|
|
@@ -565,6 +685,13 @@ export async function runEmbeddedAttempt(params) {
|
|
|
565
685
|
const onAbort = () => {
|
|
566
686
|
const reason = params.abortSignal ? getAbortReason(params.abortSignal) : undefined;
|
|
567
687
|
const timeout = reason ? isTimeoutError(reason) : false;
|
|
688
|
+
if (shouldFlagCompactionTimeout({
|
|
689
|
+
isTimeout: timeout,
|
|
690
|
+
isCompactionPendingOrRetrying: subscription.isCompacting(),
|
|
691
|
+
isCompactionInFlight: activeSession.isCompacting,
|
|
692
|
+
})) {
|
|
693
|
+
timedOutDuringCompaction = true;
|
|
694
|
+
}
|
|
568
695
|
abortRun(timeout, reason);
|
|
569
696
|
};
|
|
570
697
|
if (params.abortSignal) {
|
|
@@ -577,32 +704,59 @@ export async function runEmbeddedAttempt(params) {
|
|
|
577
704
|
});
|
|
578
705
|
}
|
|
579
706
|
}
|
|
580
|
-
//
|
|
581
|
-
const
|
|
582
|
-
|
|
707
|
+
// Hook runner was already obtained earlier before tool creation
|
|
708
|
+
const hookAgentId = typeof params.agentId === "string" && params.agentId.trim()
|
|
709
|
+
? normalizeAgentId(params.agentId)
|
|
710
|
+
: resolveSessionAgentIds({
|
|
711
|
+
sessionKey: params.sessionKey,
|
|
712
|
+
config: params.config,
|
|
713
|
+
}).sessionAgentId;
|
|
583
714
|
let promptError = null;
|
|
715
|
+
let promptErrorSource = null;
|
|
584
716
|
try {
|
|
585
717
|
const promptStartedAt = Date.now();
|
|
586
|
-
// Run
|
|
718
|
+
// Run before_prompt_build hooks to allow plugins to inject prompt context.
|
|
719
|
+
// Legacy compatibility: before_agent_start is also checked for context fields.
|
|
587
720
|
let effectivePrompt = params.prompt;
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
721
|
+
const hookCtx = {
|
|
722
|
+
agentId: hookAgentId,
|
|
723
|
+
sessionKey: params.sessionKey,
|
|
724
|
+
sessionId: params.sessionId,
|
|
725
|
+
workspaceDir: params.workspaceDir,
|
|
726
|
+
messageProvider: params.messageProvider ?? undefined,
|
|
727
|
+
};
|
|
728
|
+
const promptBuildResult = hookRunner?.hasHooks("before_prompt_build")
|
|
729
|
+
? await hookRunner
|
|
730
|
+
.runBeforePromptBuild({
|
|
731
|
+
prompt: params.prompt,
|
|
732
|
+
messages: activeSession.messages,
|
|
733
|
+
}, hookCtx)
|
|
734
|
+
.catch((hookErr) => {
|
|
735
|
+
log.warn(`before_prompt_build hook failed: ${String(hookErr)}`);
|
|
736
|
+
return undefined;
|
|
737
|
+
})
|
|
738
|
+
: undefined;
|
|
739
|
+
const legacyResult = hookRunner?.hasHooks("before_agent_start")
|
|
740
|
+
? await hookRunner
|
|
741
|
+
.runBeforeAgentStart({
|
|
742
|
+
prompt: params.prompt,
|
|
743
|
+
messages: activeSession.messages,
|
|
744
|
+
}, hookCtx)
|
|
745
|
+
.catch((hookErr) => {
|
|
746
|
+
log.warn(`before_agent_start hook (legacy prompt build path) failed: ${String(hookErr)}`);
|
|
747
|
+
return undefined;
|
|
748
|
+
})
|
|
749
|
+
: undefined;
|
|
750
|
+
const hookResult = {
|
|
751
|
+
systemPrompt: promptBuildResult?.systemPrompt ?? legacyResult?.systemPrompt,
|
|
752
|
+
prependContext: [promptBuildResult?.prependContext, legacyResult?.prependContext]
|
|
753
|
+
.filter((value) => Boolean(value))
|
|
754
|
+
.join("\n\n"),
|
|
755
|
+
};
|
|
756
|
+
{
|
|
757
|
+
if (hookResult?.prependContext) {
|
|
758
|
+
effectivePrompt = `${hookResult.prependContext}\n\n${params.prompt}`;
|
|
759
|
+
log.debug(`hooks: prepended context to prompt (${hookResult.prependContext.length} chars)`);
|
|
606
760
|
}
|
|
607
761
|
}
|
|
608
762
|
log.debug(`embedded run prompt start: runId=${params.runId} sessionId=${params.sessionId}`);
|
|
@@ -620,7 +774,10 @@ export async function runEmbeddedAttempt(params) {
|
|
|
620
774
|
sessionManager.resetLeaf();
|
|
621
775
|
}
|
|
622
776
|
const sessionContext = sessionManager.buildSessionContext();
|
|
623
|
-
|
|
777
|
+
const sanitizedOrphan = transcriptPolicy.normalizeAntigravityThinkingBlocks
|
|
778
|
+
? sanitizeAntigravityThinkingBlocks(sessionContext.messages)
|
|
779
|
+
: sessionContext.messages;
|
|
780
|
+
activeSession.agent.replaceMessages(sanitizedOrphan);
|
|
624
781
|
log.warn(`Removed orphaned user message to prevent consecutive user turns. ` +
|
|
625
782
|
`runId=${params.runId} sessionId=${params.sessionId}`);
|
|
626
783
|
}
|
|
@@ -636,8 +793,11 @@ export async function runEmbeddedAttempt(params) {
|
|
|
636
793
|
existingImages: params.images,
|
|
637
794
|
historyMessages: activeSession.messages,
|
|
638
795
|
maxBytes: MAX_IMAGE_BYTES,
|
|
796
|
+
maxDimensionPx: resolveImageSanitizationLimits(params.config).maxDimensionPx,
|
|
639
797
|
// Enforce sandbox path restrictions when sandbox is enabled
|
|
640
|
-
|
|
798
|
+
sandbox: sandbox?.enabled && sandbox?.fsBridge
|
|
799
|
+
? { root: sandbox.workspaceDir, bridge: sandbox.fsBridge }
|
|
800
|
+
: undefined,
|
|
641
801
|
});
|
|
642
802
|
// Inject history images into their original message positions.
|
|
643
803
|
// This ensures the model sees images in context (e.g., "compare to the first image").
|
|
@@ -651,13 +811,42 @@ export async function runEmbeddedAttempt(params) {
|
|
|
651
811
|
messages: activeSession.messages,
|
|
652
812
|
note: `images: prompt=${imageResult.images.length} history=${imageResult.historyImagesByIndex.size}`,
|
|
653
813
|
});
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
814
|
+
// Diagnostic: log context sizes before prompt to help debug early overflow errors.
|
|
815
|
+
if (log.isEnabled("debug")) {
|
|
816
|
+
const msgCount = activeSession.messages.length;
|
|
817
|
+
const systemLen = systemPromptText?.length ?? 0;
|
|
818
|
+
const promptLen = effectivePrompt.length;
|
|
819
|
+
const sessionSummary = summarizeSessionContext(activeSession.messages);
|
|
820
|
+
log.debug(`[context-diag] pre-prompt: sessionKey=${params.sessionKey ?? params.sessionId} ` +
|
|
821
|
+
`messages=${msgCount} roleCounts=${sessionSummary.roleCounts} ` +
|
|
822
|
+
`historyTextChars=${sessionSummary.totalTextChars} ` +
|
|
823
|
+
`maxMessageTextChars=${sessionSummary.maxMessageTextChars} ` +
|
|
824
|
+
`historyImageBlocks=${sessionSummary.totalImageBlocks} ` +
|
|
825
|
+
`systemPromptChars=${systemLen} promptChars=${promptLen} ` +
|
|
826
|
+
`promptImages=${imageResult.images.length} ` +
|
|
827
|
+
`historyImageMessages=${imageResult.historyImagesByIndex.size} ` +
|
|
828
|
+
`provider=${params.provider}/${params.modelId} sessionFile=${params.sessionFile}`);
|
|
829
|
+
}
|
|
830
|
+
if (hookRunner?.hasHooks("llm_input")) {
|
|
831
|
+
hookRunner
|
|
832
|
+
.runLlmInput({
|
|
833
|
+
runId: params.runId,
|
|
834
|
+
sessionId: params.sessionId,
|
|
659
835
|
provider: params.provider,
|
|
660
|
-
|
|
836
|
+
model: params.modelId,
|
|
837
|
+
systemPrompt: systemPromptText,
|
|
838
|
+
prompt: effectivePrompt,
|
|
839
|
+
historyMessages: activeSession.messages,
|
|
840
|
+
imagesCount: imageResult.images.length,
|
|
841
|
+
}, {
|
|
842
|
+
agentId: hookAgentId,
|
|
843
|
+
sessionKey: params.sessionKey,
|
|
844
|
+
sessionId: params.sessionId,
|
|
845
|
+
workspaceDir: params.workspaceDir,
|
|
846
|
+
messageProvider: params.messageProvider ?? undefined,
|
|
847
|
+
})
|
|
848
|
+
.catch((err) => {
|
|
849
|
+
log.warn(`llm_input hook failed: ${String(err)}`);
|
|
661
850
|
});
|
|
662
851
|
}
|
|
663
852
|
// Only pass images option if there are actually images to pass
|
|
@@ -671,31 +860,98 @@ export async function runEmbeddedAttempt(params) {
|
|
|
671
860
|
}
|
|
672
861
|
catch (err) {
|
|
673
862
|
promptError = err;
|
|
863
|
+
promptErrorSource = "prompt";
|
|
674
864
|
}
|
|
675
865
|
finally {
|
|
676
866
|
log.debug(`embedded run prompt end: runId=${params.runId} sessionId=${params.sessionId} durationMs=${Date.now() - promptStartedAt}`);
|
|
677
867
|
}
|
|
868
|
+
// Capture snapshot before compaction wait so we have complete messages if timeout occurs
|
|
869
|
+
// Check compaction state before and after to avoid race condition where compaction starts during capture
|
|
870
|
+
// Use session state (not subscription) for snapshot decisions - need instantaneous compaction status
|
|
871
|
+
const wasCompactingBefore = activeSession.isCompacting;
|
|
872
|
+
const snapshot = activeSession.messages.slice();
|
|
873
|
+
const wasCompactingAfter = activeSession.isCompacting;
|
|
874
|
+
// Only trust snapshot if compaction wasn't running before or after capture
|
|
875
|
+
const preCompactionSnapshot = wasCompactingBefore || wasCompactingAfter ? null : snapshot;
|
|
876
|
+
const preCompactionSessionId = activeSession.sessionId;
|
|
678
877
|
try {
|
|
679
|
-
await waitForCompactionRetry();
|
|
878
|
+
await abortable(waitForCompactionRetry());
|
|
680
879
|
}
|
|
681
880
|
catch (err) {
|
|
682
|
-
if (
|
|
683
|
-
if (!promptError)
|
|
881
|
+
if (isRunnerAbortError(err)) {
|
|
882
|
+
if (!promptError) {
|
|
684
883
|
promptError = err;
|
|
884
|
+
promptErrorSource = "compaction";
|
|
885
|
+
}
|
|
886
|
+
if (!isProbeSession) {
|
|
887
|
+
log.debug(`compaction wait aborted: runId=${params.runId} sessionId=${params.sessionId}`);
|
|
888
|
+
}
|
|
685
889
|
}
|
|
686
890
|
else {
|
|
687
891
|
throw err;
|
|
688
892
|
}
|
|
689
893
|
}
|
|
690
|
-
|
|
691
|
-
|
|
894
|
+
// Append cache-TTL timestamp AFTER prompt + compaction retry completes.
|
|
895
|
+
// Previously this was before the prompt, which caused a custom entry to be
|
|
896
|
+
// inserted between compaction and the next prompt — breaking the
|
|
897
|
+
// prepareCompaction() guard that checks the last entry type, leading to
|
|
898
|
+
// double-compaction. See: https://github.com/poolbot/poolbot/issues/9282
|
|
899
|
+
// Skip when timed out during compaction — session state may be inconsistent.
|
|
900
|
+
if (!timedOutDuringCompaction) {
|
|
901
|
+
const shouldTrackCacheTtl = params.config?.agents?.defaults?.contextPruning?.mode === "cache-ttl" &&
|
|
902
|
+
isCacheTtlEligibleProvider(params.provider, params.modelId);
|
|
903
|
+
if (shouldTrackCacheTtl) {
|
|
904
|
+
appendCacheTtlTimestamp(sessionManager, {
|
|
905
|
+
timestamp: Date.now(),
|
|
906
|
+
provider: params.provider,
|
|
907
|
+
modelId: params.modelId,
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
// If timeout occurred during compaction, use pre-compaction snapshot when available
|
|
912
|
+
// (compaction restructures messages but does not add user/assistant turns).
|
|
913
|
+
const snapshotSelection = selectCompactionTimeoutSnapshot({
|
|
914
|
+
timedOutDuringCompaction,
|
|
915
|
+
preCompactionSnapshot,
|
|
916
|
+
preCompactionSessionId,
|
|
917
|
+
currentSnapshot: activeSession.messages.slice(),
|
|
918
|
+
currentSessionId: activeSession.sessionId,
|
|
919
|
+
});
|
|
920
|
+
if (timedOutDuringCompaction) {
|
|
921
|
+
if (!isProbeSession) {
|
|
922
|
+
log.warn(`using ${snapshotSelection.source} snapshot: timed out during compaction runId=${params.runId} sessionId=${params.sessionId}`);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
messagesSnapshot = snapshotSelection.messagesSnapshot;
|
|
926
|
+
sessionIdUsed = snapshotSelection.sessionIdUsed;
|
|
927
|
+
if (promptError && promptErrorSource === "prompt") {
|
|
928
|
+
try {
|
|
929
|
+
sessionManager.appendCustomEntry("poolbot:prompt-error", {
|
|
930
|
+
timestamp: Date.now(),
|
|
931
|
+
runId: params.runId,
|
|
932
|
+
sessionId: params.sessionId,
|
|
933
|
+
provider: params.provider,
|
|
934
|
+
model: params.modelId,
|
|
935
|
+
api: params.model.api,
|
|
936
|
+
error: describeUnknownError(promptError),
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
catch (entryErr) {
|
|
940
|
+
log.warn(`failed to persist prompt error entry: ${String(entryErr)}`);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
692
943
|
cacheTrace?.recordStage("session:after", {
|
|
693
944
|
messages: messagesSnapshot,
|
|
694
|
-
note:
|
|
945
|
+
note: timedOutDuringCompaction
|
|
946
|
+
? "compaction timeout"
|
|
947
|
+
: promptError
|
|
948
|
+
? "prompt error"
|
|
949
|
+
: undefined,
|
|
695
950
|
});
|
|
696
951
|
anthropicPayloadLogger?.recordUsage(messagesSnapshot, promptError);
|
|
697
952
|
// Run agent_end hooks to allow plugins to analyze the conversation
|
|
698
953
|
// This is fire-and-forget, so we don't await
|
|
954
|
+
// Run even on compaction timeout so plugins can log/cleanup
|
|
699
955
|
if (hookRunner?.hasHooks("agent_end")) {
|
|
700
956
|
hookRunner
|
|
701
957
|
.runAgentEnd({
|
|
@@ -706,6 +962,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
706
962
|
}, {
|
|
707
963
|
agentId: hookAgentId,
|
|
708
964
|
sessionKey: params.sessionKey,
|
|
965
|
+
sessionId: params.sessionId,
|
|
709
966
|
workspaceDir: params.workspaceDir,
|
|
710
967
|
messageProvider: params.messageProvider ?? undefined,
|
|
711
968
|
})
|
|
@@ -716,22 +973,56 @@ export async function runEmbeddedAttempt(params) {
|
|
|
716
973
|
}
|
|
717
974
|
finally {
|
|
718
975
|
clearTimeout(abortTimer);
|
|
719
|
-
if (abortWarnTimer)
|
|
976
|
+
if (abortWarnTimer) {
|
|
720
977
|
clearTimeout(abortWarnTimer);
|
|
721
|
-
|
|
722
|
-
|
|
978
|
+
}
|
|
979
|
+
if (!isProbeSession && (aborted || timedOut) && !timedOutDuringCompaction) {
|
|
980
|
+
log.debug(`run cleanup: runId=${params.runId} sessionId=${params.sessionId} aborted=${aborted} timedOut=${timedOut}`);
|
|
981
|
+
}
|
|
982
|
+
try {
|
|
983
|
+
unsubscribe();
|
|
984
|
+
}
|
|
985
|
+
catch (err) {
|
|
986
|
+
// unsubscribe() should never throw; if it does, it indicates a serious bug.
|
|
987
|
+
// Log at error level to ensure visibility, but don't rethrow in finally block
|
|
988
|
+
// as it would mask any exception from the try block above.
|
|
989
|
+
log.error(`CRITICAL: unsubscribe failed, possible resource leak: runId=${params.runId} ${String(err)}`);
|
|
990
|
+
}
|
|
991
|
+
clearActiveEmbeddedRun(params.sessionId, queueHandle, params.sessionKey);
|
|
723
992
|
params.abortSignal?.removeEventListener?.("abort", onAbort);
|
|
724
993
|
}
|
|
725
994
|
const lastAssistant = messagesSnapshot
|
|
726
995
|
.slice()
|
|
727
|
-
.
|
|
728
|
-
.find((m) => m
|
|
996
|
+
.toReversed()
|
|
997
|
+
.find((m) => m.role === "assistant");
|
|
729
998
|
const toolMetasNormalized = toolMetas
|
|
730
999
|
.filter((entry) => typeof entry.toolName === "string" && entry.toolName.trim().length > 0)
|
|
731
1000
|
.map((entry) => ({ toolName: entry.toolName, meta: entry.meta }));
|
|
1001
|
+
if (hookRunner?.hasHooks("llm_output")) {
|
|
1002
|
+
hookRunner
|
|
1003
|
+
.runLlmOutput({
|
|
1004
|
+
runId: params.runId,
|
|
1005
|
+
sessionId: params.sessionId,
|
|
1006
|
+
provider: params.provider,
|
|
1007
|
+
model: params.modelId,
|
|
1008
|
+
assistantTexts,
|
|
1009
|
+
lastAssistant,
|
|
1010
|
+
usage: getUsageTotals(),
|
|
1011
|
+
}, {
|
|
1012
|
+
agentId: hookAgentId,
|
|
1013
|
+
sessionKey: params.sessionKey,
|
|
1014
|
+
sessionId: params.sessionId,
|
|
1015
|
+
workspaceDir: params.workspaceDir,
|
|
1016
|
+
messageProvider: params.messageProvider ?? undefined,
|
|
1017
|
+
})
|
|
1018
|
+
.catch((err) => {
|
|
1019
|
+
log.warn(`llm_output hook failed: ${String(err)}`);
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
732
1022
|
return {
|
|
733
1023
|
aborted,
|
|
734
1024
|
timedOut,
|
|
1025
|
+
timedOutDuringCompaction,
|
|
735
1026
|
promptError,
|
|
736
1027
|
sessionIdUsed,
|
|
737
1028
|
systemPromptReport,
|
|
@@ -742,15 +1033,30 @@ export async function runEmbeddedAttempt(params) {
|
|
|
742
1033
|
lastToolError: getLastToolError?.(),
|
|
743
1034
|
didSendViaMessagingTool: didSendViaMessagingTool(),
|
|
744
1035
|
messagingToolSentTexts: getMessagingToolSentTexts(),
|
|
1036
|
+
messagingToolSentMediaUrls: getMessagingToolSentMediaUrls(),
|
|
745
1037
|
messagingToolSentTargets: getMessagingToolSentTargets(),
|
|
1038
|
+
successfulCronAdds: getSuccessfulCronAdds(),
|
|
746
1039
|
cloudCodeAssistFormatError: Boolean(lastAssistant?.errorMessage && isCloudCodeAssistFormatError(lastAssistant.errorMessage)),
|
|
1040
|
+
attemptUsage: getUsageTotals(),
|
|
1041
|
+
compactionCount: getCompactionCount(),
|
|
747
1042
|
// Client tool call detected (OpenResponses hosted tools)
|
|
748
1043
|
clientToolCall: clientToolCallDetected ?? undefined,
|
|
749
1044
|
};
|
|
750
1045
|
}
|
|
751
1046
|
finally {
|
|
752
1047
|
// Always tear down the session (and release the lock) before we leave this attempt.
|
|
753
|
-
|
|
1048
|
+
//
|
|
1049
|
+
// BUGFIX: Wait for the agent to be truly idle before flushing pending tool results.
|
|
1050
|
+
// pi-agent-core's auto-retry resolves waitForRetry() on assistant message receipt,
|
|
1051
|
+
// *before* tool execution completes in the retried agent loop. Without this wait,
|
|
1052
|
+
// flushPendingToolResults() fires while tools are still executing, inserting
|
|
1053
|
+
// synthetic "missing tool result" errors and causing silent agent failures.
|
|
1054
|
+
// See: https://github.com/poolbot/poolbot/issues/8643
|
|
1055
|
+
removeToolResultContextGuard?.();
|
|
1056
|
+
await flushPendingToolResultsAfterIdle({
|
|
1057
|
+
agent: session?.agent,
|
|
1058
|
+
sessionManager,
|
|
1059
|
+
});
|
|
754
1060
|
session?.dispose();
|
|
755
1061
|
await sessionLock.release();
|
|
756
1062
|
}
|