@poolzin/pool-bot 2026.2.21 → 2026.2.23
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-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/device-pair/index.ts +2 -2
- 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/irc/src/accounts.ts +1 -1
- package/extensions/irc/src/onboarding.ts +4 -4
- 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 +10 -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 +10 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +10 -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 +10 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +10 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +10 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +10 -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
- package/dist/agents/openclaw-tools.js +0 -151
- package/dist/agents/tool-security.js +0 -96
- package/dist/gateway/url-validation.js +0 -94
- package/dist/infra/openclaw-root.js +0 -109
- package/dist/infra/tmp-openclaw-dir.js +0 -81
- package/dist/media/path-sanitization.js +0 -78
|
@@ -3,42 +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 {
|
|
24
|
-
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";
|
|
25
32
|
import { subscribeEmbeddedPiSession } from "../../pi-embedded-subscribe.js";
|
|
26
33
|
import { ensurePiCompactionReserveTokens, resolveCompactionReserveTokensFloor, } from "../../pi-settings.js";
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
34
|
+
import { toClientToolDefinitions } from "../../pi-tool-definition-adapter.js";
|
|
35
|
+
import { createPoolbotCodingTools, resolveToolLoopDetectionConfig } from "../../pi-tools.js";
|
|
29
36
|
import { resolveSandboxContext } from "../../sandbox.js";
|
|
37
|
+
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
|
38
|
+
import { repairSessionFileIfNeeded } from "../../session-file-repair.js";
|
|
30
39
|
import { guardSessionManager } from "../../session-tool-result-guard-wrapper.js";
|
|
31
|
-
import {
|
|
32
|
-
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";
|
|
33
43
|
import { applySkillEnvOverrides, applySkillEnvOverridesFromSnapshot, loadWorkspaceSkillEntries, resolveSkillsPromptForRun, } from "../../skills.js";
|
|
34
|
-
import {
|
|
44
|
+
import { buildSystemPromptParams } from "../../system-prompt-params.js";
|
|
35
45
|
import { buildSystemPromptReport } from "../../system-prompt-report.js";
|
|
36
|
-
import {
|
|
37
|
-
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";
|
|
38
50
|
import { buildEmbeddedExtensionPaths } from "../extensions.js";
|
|
39
51
|
import { applyExtraParamsToAgent } from "../extra-params.js";
|
|
40
|
-
import {
|
|
41
|
-
import { logToolSchemasForGoogle, sanitizeSessionHistory, sanitizeToolsForGoogle, } from "../google.js";
|
|
52
|
+
import { logToolSchemasForGoogle, sanitizeAntigravityThinkingBlocks, sanitizeSessionHistory, sanitizeToolsForGoogle, } from "../google.js";
|
|
42
53
|
import { getDmHistoryLimitFromSessionKey, limitHistoryTurns } from "../history.js";
|
|
43
54
|
import { log } from "../logger.js";
|
|
44
55
|
import { buildModelAliasLines } from "../model.js";
|
|
@@ -47,25 +58,22 @@ import { buildEmbeddedSandboxInfo } from "../sandbox-info.js";
|
|
|
47
58
|
import { prewarmSessionFile, trackSessionManagerAccess } from "../session-manager-cache.js";
|
|
48
59
|
import { prepareSessionManagerForRun } from "../session-manager-init.js";
|
|
49
60
|
import { applySystemPromptOverrideToSession, buildEmbeddedSystemPrompt, createSystemPromptOverride, } from "../system-prompt.js";
|
|
61
|
+
import { installToolResultContextGuard } from "../tool-result-context-guard.js";
|
|
50
62
|
import { splitSdkTools } from "../tool-split.js";
|
|
51
|
-
import { toClientToolDefinitions } from "../../pi-tool-definition-adapter.js";
|
|
52
|
-
import { buildSystemPromptParams } from "../../system-prompt-params.js";
|
|
53
|
-
import { detectRuntimeShell } from "../../shell-utils.js";
|
|
54
63
|
import { describeUnknownError, mapThinkingLevel } from "../utils.js";
|
|
55
|
-
import {
|
|
56
|
-
import {
|
|
57
|
-
import { isTimeoutError } from "../../failover-error.js";
|
|
58
|
-
import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js";
|
|
59
|
-
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";
|
|
60
66
|
import { detectAndLoadPromptImages } from "./images.js";
|
|
61
67
|
export function injectHistoryImagesIntoMessages(messages, historyImagesByIndex) {
|
|
62
|
-
if (historyImagesByIndex.size === 0)
|
|
68
|
+
if (historyImagesByIndex.size === 0) {
|
|
63
69
|
return false;
|
|
70
|
+
}
|
|
64
71
|
let didMutate = false;
|
|
65
72
|
for (const [msgIndex, images] of historyImagesByIndex) {
|
|
66
73
|
// Bounds check: ensure index is valid before accessing
|
|
67
|
-
if (msgIndex < 0 || msgIndex >= messages.length)
|
|
74
|
+
if (msgIndex < 0 || msgIndex >= messages.length) {
|
|
68
75
|
continue;
|
|
76
|
+
}
|
|
69
77
|
const msg = messages[msgIndex];
|
|
70
78
|
if (msg && msg.role === "user") {
|
|
71
79
|
// Convert string content to array format if needed
|
|
@@ -93,6 +101,56 @@ export function injectHistoryImagesIntoMessages(messages, historyImagesByIndex)
|
|
|
93
101
|
}
|
|
94
102
|
return didMutate;
|
|
95
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
|
+
}
|
|
96
154
|
export async function runEmbeddedAttempt(params) {
|
|
97
155
|
const resolvedWorkspace = resolveUserPath(params.workspaceDir);
|
|
98
156
|
const prevCwd = process.cwd();
|
|
@@ -175,6 +233,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
175
233
|
abortSignal: runAbortController.signal,
|
|
176
234
|
modelProvider: params.model.provider,
|
|
177
235
|
modelId: params.modelId,
|
|
236
|
+
modelContextWindowTokens: params.model.contextWindow,
|
|
178
237
|
modelAuthMode: resolveModelAuthMode(params.model.provider, params.config),
|
|
179
238
|
currentChannelId: params.currentChannelId,
|
|
180
239
|
currentThreadTs: params.currentThreadTs,
|
|
@@ -201,8 +260,9 @@ export async function runEmbeddedAttempt(params) {
|
|
|
201
260
|
accountId: params.agentAccountId ?? undefined,
|
|
202
261
|
});
|
|
203
262
|
if (inlineButtonsScope !== "off") {
|
|
204
|
-
if (!runtimeCapabilities)
|
|
263
|
+
if (!runtimeCapabilities) {
|
|
205
264
|
runtimeCapabilities = [];
|
|
265
|
+
}
|
|
206
266
|
if (!runtimeCapabilities.some((cap) => String(cap).trim().toLowerCase() === "inlinebuttons")) {
|
|
207
267
|
runtimeCapabilities.push("inlineButtons");
|
|
208
268
|
}
|
|
@@ -266,14 +326,16 @@ export async function runEmbeddedAttempt(params) {
|
|
|
266
326
|
node: process.version,
|
|
267
327
|
model: `${params.provider}/${params.modelId}`,
|
|
268
328
|
defaultModel: defaultModelLabel,
|
|
329
|
+
shell: detectRuntimeShell(),
|
|
269
330
|
channel: runtimeChannel,
|
|
270
331
|
capabilities: runtimeCapabilities,
|
|
271
332
|
channelActions,
|
|
272
|
-
shell: detectRuntimeShell(),
|
|
273
333
|
},
|
|
274
334
|
});
|
|
275
335
|
const isDefaultAgent = sessionAgentId === defaultAgentId;
|
|
276
|
-
const promptMode = isSubagentSessionKey(params.sessionKey)
|
|
336
|
+
const promptMode = isSubagentSessionKey(params.sessionKey) || isCronSessionKey(params.sessionKey)
|
|
337
|
+
? "minimal"
|
|
338
|
+
: "full";
|
|
277
339
|
const docsPath = await resolvePoolbotDocsPath({
|
|
278
340
|
workspaceDir: effectiveWorkspace,
|
|
279
341
|
argv1: process.argv[1],
|
|
@@ -317,6 +379,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
317
379
|
model: params.modelId,
|
|
318
380
|
workspaceDir: effectiveWorkspace,
|
|
319
381
|
bootstrapMaxChars: resolveBootstrapMaxChars(params.config),
|
|
382
|
+
bootstrapTotalMaxChars: resolveBootstrapTotalMaxChars(params.config),
|
|
320
383
|
sandbox: (() => {
|
|
321
384
|
const runtime = resolveSandboxRuntimeStatus({
|
|
322
385
|
cfg: params.config,
|
|
@@ -334,9 +397,13 @@ export async function runEmbeddedAttempt(params) {
|
|
|
334
397
|
const systemPromptText = systemPromptOverride();
|
|
335
398
|
const sessionLock = await acquireSessionWriteLock({
|
|
336
399
|
sessionFile: params.sessionFile,
|
|
400
|
+
maxHoldMs: resolveSessionLockMaxHoldFromTimeout({
|
|
401
|
+
timeoutMs: params.timeoutMs,
|
|
402
|
+
}),
|
|
337
403
|
});
|
|
338
404
|
let sessionManager;
|
|
339
405
|
let session;
|
|
406
|
+
let removeToolResultContextGuard;
|
|
340
407
|
try {
|
|
341
408
|
await repairSessionFileIfNeeded({
|
|
342
409
|
sessionFile: params.sessionFile,
|
|
@@ -355,6 +422,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
355
422
|
sessionManager = guardSessionManager(SessionManager.open(params.sessionFile), {
|
|
356
423
|
agentId: sessionAgentId,
|
|
357
424
|
sessionKey: params.sessionKey,
|
|
425
|
+
inputProvenance: params.inputProvenance,
|
|
358
426
|
allowSyntheticToolResults: transcriptPolicy.allowSyntheticToolResults,
|
|
359
427
|
});
|
|
360
428
|
trackSessionManagerAccess(params.sessionFile);
|
|
@@ -370,6 +438,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
370
438
|
settingsManager,
|
|
371
439
|
minReserveTokens: resolveCompactionReserveTokensFloor(params.config),
|
|
372
440
|
});
|
|
441
|
+
// Call for side effects (sets compaction/pruning runtime state)
|
|
373
442
|
buildEmbeddedExtensionPaths({
|
|
374
443
|
cfg: params.config,
|
|
375
444
|
sessionManager,
|
|
@@ -377,16 +446,26 @@ export async function runEmbeddedAttempt(params) {
|
|
|
377
446
|
modelId: params.modelId,
|
|
378
447
|
model: params.model,
|
|
379
448
|
});
|
|
449
|
+
// Get hook runner early so it's available when creating tools
|
|
450
|
+
const hookRunner = getGlobalHookRunner();
|
|
380
451
|
const { builtInTools, customTools } = splitSdkTools({
|
|
381
452
|
tools,
|
|
382
453
|
sandboxEnabled: !!sandbox?.enabled,
|
|
383
454
|
});
|
|
384
455
|
// Add client tools (OpenResponses hosted tools) to customTools
|
|
385
456
|
let clientToolCallDetected = null;
|
|
457
|
+
const clientToolLoopDetection = resolveToolLoopDetectionConfig({
|
|
458
|
+
cfg: params.config,
|
|
459
|
+
agentId: sessionAgentId,
|
|
460
|
+
});
|
|
386
461
|
const clientToolDefs = params.clientTools
|
|
387
462
|
? toClientToolDefinitions(params.clientTools, (toolName, toolParams) => {
|
|
388
463
|
clientToolCallDetected = { name: toolName, params: toolParams };
|
|
389
|
-
}, {
|
|
464
|
+
}, {
|
|
465
|
+
agentId: sessionAgentId,
|
|
466
|
+
sessionKey: params.sessionKey,
|
|
467
|
+
loopDetection: clientToolLoopDetection,
|
|
468
|
+
})
|
|
390
469
|
: [];
|
|
391
470
|
const allCustomTools = [...customTools, ...clientToolDefs];
|
|
392
471
|
({ session } = await createAgentSession({
|
|
@@ -406,6 +485,10 @@ export async function runEmbeddedAttempt(params) {
|
|
|
406
485
|
throw new Error("Embedded agent session missing");
|
|
407
486
|
}
|
|
408
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
|
+
});
|
|
409
492
|
const cacheTrace = createCacheTrace({
|
|
410
493
|
cfg: params.config,
|
|
411
494
|
env: process.env,
|
|
@@ -427,8 +510,20 @@ export async function runEmbeddedAttempt(params) {
|
|
|
427
510
|
modelApi: params.model.api,
|
|
428
511
|
workspaceDir: params.workspaceDir,
|
|
429
512
|
});
|
|
430
|
-
//
|
|
431
|
-
|
|
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
|
+
}
|
|
432
527
|
applyExtraParamsToAgent(activeSession.agent, params.config, params.provider, params.modelId, params.streamParams);
|
|
433
528
|
if (cacheTrace) {
|
|
434
529
|
cacheTrace.recordStage("session:loaded", {
|
|
@@ -447,6 +542,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
447
542
|
modelApi: params.model.api,
|
|
448
543
|
modelId: params.modelId,
|
|
449
544
|
provider: params.provider,
|
|
545
|
+
config: params.config,
|
|
450
546
|
sessionManager,
|
|
451
547
|
sessionId: params.sessionId,
|
|
452
548
|
policy: transcriptPolicy,
|
|
@@ -458,19 +554,29 @@ export async function runEmbeddedAttempt(params) {
|
|
|
458
554
|
const validated = transcriptPolicy.validateAnthropicTurns
|
|
459
555
|
? validateAnthropicTurns(validatedGemini)
|
|
460
556
|
: validatedGemini;
|
|
461
|
-
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;
|
|
462
564
|
cacheTrace?.recordStage("session:limited", { messages: limited });
|
|
463
565
|
if (limited.length > 0) {
|
|
464
566
|
activeSession.agent.replaceMessages(limited);
|
|
465
567
|
}
|
|
466
568
|
}
|
|
467
569
|
catch (err) {
|
|
468
|
-
|
|
570
|
+
await flushPendingToolResultsAfterIdle({
|
|
571
|
+
agent: activeSession?.agent,
|
|
572
|
+
sessionManager,
|
|
573
|
+
});
|
|
469
574
|
activeSession.dispose();
|
|
470
575
|
throw err;
|
|
471
576
|
}
|
|
472
577
|
let aborted = Boolean(params.abortSignal?.aborted);
|
|
473
578
|
let timedOut = false;
|
|
579
|
+
let timedOutDuringCompaction = false;
|
|
474
580
|
const getAbortReason = (signal) => "reason" in signal ? signal.reason : undefined;
|
|
475
581
|
const makeTimeoutAbortReason = () => {
|
|
476
582
|
const err = new Error("request timed out");
|
|
@@ -485,8 +591,9 @@ export async function runEmbeddedAttempt(params) {
|
|
|
485
591
|
};
|
|
486
592
|
const abortRun = (isTimeout = false, reason) => {
|
|
487
593
|
aborted = true;
|
|
488
|
-
if (isTimeout)
|
|
594
|
+
if (isTimeout) {
|
|
489
595
|
timedOut = true;
|
|
596
|
+
}
|
|
490
597
|
if (isTimeout) {
|
|
491
598
|
runAbortController.abort(reason ?? makeTimeoutAbortReason());
|
|
492
599
|
}
|
|
@@ -518,6 +625,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
518
625
|
const subscription = subscribeEmbeddedPiSession({
|
|
519
626
|
session: activeSession,
|
|
520
627
|
runId: params.runId,
|
|
628
|
+
hookRunner: getGlobalHookRunner() ?? undefined,
|
|
521
629
|
verboseLevel: params.verboseLevel,
|
|
522
630
|
reasoningMode: params.reasoningLevel ?? "off",
|
|
523
631
|
toolResultFormat: params.toolResultFormat,
|
|
@@ -525,6 +633,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
525
633
|
shouldEmitToolOutput: params.shouldEmitToolOutput,
|
|
526
634
|
onToolResult: params.onToolResult,
|
|
527
635
|
onReasoningStream: params.onReasoningStream,
|
|
636
|
+
onReasoningEnd: params.onReasoningEnd,
|
|
528
637
|
onBlockReply: params.onBlockReply,
|
|
529
638
|
onBlockReplyFlush: params.onBlockReplyFlush,
|
|
530
639
|
blockReplyBreak: params.blockReplyBreak,
|
|
@@ -533,8 +642,10 @@ export async function runEmbeddedAttempt(params) {
|
|
|
533
642
|
onAssistantMessageStart: params.onAssistantMessageStart,
|
|
534
643
|
onAgentEvent: params.onAgentEvent,
|
|
535
644
|
enforceFinalTag: params.enforceFinalTag,
|
|
645
|
+
config: params.config,
|
|
646
|
+
sessionKey: params.sessionKey ?? params.sessionId,
|
|
536
647
|
});
|
|
537
|
-
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;
|
|
538
649
|
const queueHandle = {
|
|
539
650
|
queueMessage: async (text) => {
|
|
540
651
|
await activeSession.steer(text);
|
|
@@ -543,18 +654,26 @@ export async function runEmbeddedAttempt(params) {
|
|
|
543
654
|
isCompacting: () => subscription.isCompacting(),
|
|
544
655
|
abort: abortRun,
|
|
545
656
|
};
|
|
546
|
-
setActiveEmbeddedRun(params.sessionId, queueHandle);
|
|
657
|
+
setActiveEmbeddedRun(params.sessionId, queueHandle, params.sessionKey);
|
|
547
658
|
let abortWarnTimer;
|
|
548
659
|
const isProbeSession = params.sessionId?.startsWith("probe-") ?? false;
|
|
549
660
|
const abortTimer = setTimeout(() => {
|
|
550
661
|
if (!isProbeSession) {
|
|
551
662
|
log.warn(`embedded run timeout: runId=${params.runId} sessionId=${params.sessionId} timeoutMs=${params.timeoutMs}`);
|
|
552
663
|
}
|
|
664
|
+
if (shouldFlagCompactionTimeout({
|
|
665
|
+
isTimeout: true,
|
|
666
|
+
isCompactionPendingOrRetrying: subscription.isCompacting(),
|
|
667
|
+
isCompactionInFlight: activeSession.isCompacting,
|
|
668
|
+
})) {
|
|
669
|
+
timedOutDuringCompaction = true;
|
|
670
|
+
}
|
|
553
671
|
abortRun(true);
|
|
554
672
|
if (!abortWarnTimer) {
|
|
555
673
|
abortWarnTimer = setTimeout(() => {
|
|
556
|
-
if (!activeSession.isStreaming)
|
|
674
|
+
if (!activeSession.isStreaming) {
|
|
557
675
|
return;
|
|
676
|
+
}
|
|
558
677
|
if (!isProbeSession) {
|
|
559
678
|
log.warn(`embedded run abort still streaming: runId=${params.runId} sessionId=${params.sessionId}`);
|
|
560
679
|
}
|
|
@@ -566,6 +685,13 @@ export async function runEmbeddedAttempt(params) {
|
|
|
566
685
|
const onAbort = () => {
|
|
567
686
|
const reason = params.abortSignal ? getAbortReason(params.abortSignal) : undefined;
|
|
568
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
|
+
}
|
|
569
695
|
abortRun(timeout, reason);
|
|
570
696
|
};
|
|
571
697
|
if (params.abortSignal) {
|
|
@@ -578,32 +704,59 @@ export async function runEmbeddedAttempt(params) {
|
|
|
578
704
|
});
|
|
579
705
|
}
|
|
580
706
|
}
|
|
581
|
-
//
|
|
582
|
-
const
|
|
583
|
-
|
|
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;
|
|
584
714
|
let promptError = null;
|
|
715
|
+
let promptErrorSource = null;
|
|
585
716
|
try {
|
|
586
717
|
const promptStartedAt = Date.now();
|
|
587
|
-
// 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.
|
|
588
720
|
let effectivePrompt = params.prompt;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
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)`);
|
|
607
760
|
}
|
|
608
761
|
}
|
|
609
762
|
log.debug(`embedded run prompt start: runId=${params.runId} sessionId=${params.sessionId}`);
|
|
@@ -621,7 +774,10 @@ export async function runEmbeddedAttempt(params) {
|
|
|
621
774
|
sessionManager.resetLeaf();
|
|
622
775
|
}
|
|
623
776
|
const sessionContext = sessionManager.buildSessionContext();
|
|
624
|
-
|
|
777
|
+
const sanitizedOrphan = transcriptPolicy.normalizeAntigravityThinkingBlocks
|
|
778
|
+
? sanitizeAntigravityThinkingBlocks(sessionContext.messages)
|
|
779
|
+
: sessionContext.messages;
|
|
780
|
+
activeSession.agent.replaceMessages(sanitizedOrphan);
|
|
625
781
|
log.warn(`Removed orphaned user message to prevent consecutive user turns. ` +
|
|
626
782
|
`runId=${params.runId} sessionId=${params.sessionId}`);
|
|
627
783
|
}
|
|
@@ -637,8 +793,11 @@ export async function runEmbeddedAttempt(params) {
|
|
|
637
793
|
existingImages: params.images,
|
|
638
794
|
historyMessages: activeSession.messages,
|
|
639
795
|
maxBytes: MAX_IMAGE_BYTES,
|
|
796
|
+
maxDimensionPx: resolveImageSanitizationLimits(params.config).maxDimensionPx,
|
|
640
797
|
// Enforce sandbox path restrictions when sandbox is enabled
|
|
641
|
-
|
|
798
|
+
sandbox: sandbox?.enabled && sandbox?.fsBridge
|
|
799
|
+
? { root: sandbox.workspaceDir, bridge: sandbox.fsBridge }
|
|
800
|
+
: undefined,
|
|
642
801
|
});
|
|
643
802
|
// Inject history images into their original message positions.
|
|
644
803
|
// This ensures the model sees images in context (e.g., "compare to the first image").
|
|
@@ -652,13 +811,42 @@ export async function runEmbeddedAttempt(params) {
|
|
|
652
811
|
messages: activeSession.messages,
|
|
653
812
|
note: `images: prompt=${imageResult.images.length} history=${imageResult.historyImagesByIndex.size}`,
|
|
654
813
|
});
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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,
|
|
660
835
|
provider: params.provider,
|
|
661
|
-
|
|
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)}`);
|
|
662
850
|
});
|
|
663
851
|
}
|
|
664
852
|
// Only pass images option if there are actually images to pass
|
|
@@ -672,45 +860,98 @@ export async function runEmbeddedAttempt(params) {
|
|
|
672
860
|
}
|
|
673
861
|
catch (err) {
|
|
674
862
|
promptError = err;
|
|
863
|
+
promptErrorSource = "prompt";
|
|
675
864
|
}
|
|
676
865
|
finally {
|
|
677
866
|
log.debug(`embedded run prompt end: runId=${params.runId} sessionId=${params.sessionId} durationMs=${Date.now() - promptStartedAt}`);
|
|
678
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;
|
|
679
877
|
try {
|
|
680
|
-
await waitForCompactionRetry();
|
|
878
|
+
await abortable(waitForCompactionRetry());
|
|
681
879
|
}
|
|
682
880
|
catch (err) {
|
|
683
|
-
if (
|
|
684
|
-
if (!promptError)
|
|
881
|
+
if (isRunnerAbortError(err)) {
|
|
882
|
+
if (!promptError) {
|
|
685
883
|
promptError = err;
|
|
884
|
+
promptErrorSource = "compaction";
|
|
885
|
+
}
|
|
886
|
+
if (!isProbeSession) {
|
|
887
|
+
log.debug(`compaction wait aborted: runId=${params.runId} sessionId=${params.sessionId}`);
|
|
888
|
+
}
|
|
686
889
|
}
|
|
687
890
|
else {
|
|
688
891
|
throw err;
|
|
689
892
|
}
|
|
690
893
|
}
|
|
691
|
-
|
|
692
|
-
|
|
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
|
+
}
|
|
693
943
|
cacheTrace?.recordStage("session:after", {
|
|
694
944
|
messages: messagesSnapshot,
|
|
695
|
-
note:
|
|
945
|
+
note: timedOutDuringCompaction
|
|
946
|
+
? "compaction timeout"
|
|
947
|
+
: promptError
|
|
948
|
+
? "prompt error"
|
|
949
|
+
: undefined,
|
|
696
950
|
});
|
|
697
951
|
anthropicPayloadLogger?.recordUsage(messagesSnapshot, promptError);
|
|
698
|
-
// Record request outcome into provider infrastructure (monitoring + rate limits).
|
|
699
|
-
// Fire-and-forget — never blocks or throws.
|
|
700
|
-
try {
|
|
701
|
-
recordRequestOutcome({
|
|
702
|
-
provider: params.provider,
|
|
703
|
-
model: params.modelId,
|
|
704
|
-
status: promptError ? 500 : 200,
|
|
705
|
-
latencyMs: Date.now() - promptStartedAt,
|
|
706
|
-
streaming: true,
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
catch {
|
|
710
|
-
// Observability must never break the run
|
|
711
|
-
}
|
|
712
952
|
// Run agent_end hooks to allow plugins to analyze the conversation
|
|
713
953
|
// This is fire-and-forget, so we don't await
|
|
954
|
+
// Run even on compaction timeout so plugins can log/cleanup
|
|
714
955
|
if (hookRunner?.hasHooks("agent_end")) {
|
|
715
956
|
hookRunner
|
|
716
957
|
.runAgentEnd({
|
|
@@ -721,6 +962,7 @@ export async function runEmbeddedAttempt(params) {
|
|
|
721
962
|
}, {
|
|
722
963
|
agentId: hookAgentId,
|
|
723
964
|
sessionKey: params.sessionKey,
|
|
965
|
+
sessionId: params.sessionId,
|
|
724
966
|
workspaceDir: params.workspaceDir,
|
|
725
967
|
messageProvider: params.messageProvider ?? undefined,
|
|
726
968
|
})
|
|
@@ -731,22 +973,56 @@ export async function runEmbeddedAttempt(params) {
|
|
|
731
973
|
}
|
|
732
974
|
finally {
|
|
733
975
|
clearTimeout(abortTimer);
|
|
734
|
-
if (abortWarnTimer)
|
|
976
|
+
if (abortWarnTimer) {
|
|
735
977
|
clearTimeout(abortWarnTimer);
|
|
736
|
-
|
|
737
|
-
|
|
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);
|
|
738
992
|
params.abortSignal?.removeEventListener?.("abort", onAbort);
|
|
739
993
|
}
|
|
740
994
|
const lastAssistant = messagesSnapshot
|
|
741
995
|
.slice()
|
|
742
|
-
.
|
|
743
|
-
.find((m) => m
|
|
996
|
+
.toReversed()
|
|
997
|
+
.find((m) => m.role === "assistant");
|
|
744
998
|
const toolMetasNormalized = toolMetas
|
|
745
999
|
.filter((entry) => typeof entry.toolName === "string" && entry.toolName.trim().length > 0)
|
|
746
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
|
+
}
|
|
747
1022
|
return {
|
|
748
1023
|
aborted,
|
|
749
1024
|
timedOut,
|
|
1025
|
+
timedOutDuringCompaction,
|
|
750
1026
|
promptError,
|
|
751
1027
|
sessionIdUsed,
|
|
752
1028
|
systemPromptReport,
|
|
@@ -757,15 +1033,30 @@ export async function runEmbeddedAttempt(params) {
|
|
|
757
1033
|
lastToolError: getLastToolError?.(),
|
|
758
1034
|
didSendViaMessagingTool: didSendViaMessagingTool(),
|
|
759
1035
|
messagingToolSentTexts: getMessagingToolSentTexts(),
|
|
1036
|
+
messagingToolSentMediaUrls: getMessagingToolSentMediaUrls(),
|
|
760
1037
|
messagingToolSentTargets: getMessagingToolSentTargets(),
|
|
1038
|
+
successfulCronAdds: getSuccessfulCronAdds(),
|
|
761
1039
|
cloudCodeAssistFormatError: Boolean(lastAssistant?.errorMessage && isCloudCodeAssistFormatError(lastAssistant.errorMessage)),
|
|
1040
|
+
attemptUsage: getUsageTotals(),
|
|
1041
|
+
compactionCount: getCompactionCount(),
|
|
762
1042
|
// Client tool call detected (OpenResponses hosted tools)
|
|
763
1043
|
clientToolCall: clientToolCallDetected ?? undefined,
|
|
764
1044
|
};
|
|
765
1045
|
}
|
|
766
1046
|
finally {
|
|
767
1047
|
// Always tear down the session (and release the lock) before we leave this attempt.
|
|
768
|
-
|
|
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
|
+
});
|
|
769
1060
|
session?.dispose();
|
|
770
1061
|
await sessionLock.release();
|
|
771
1062
|
}
|