@poolzin/pool-bot 2026.2.21 → 2026.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/agents/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
|
@@ -2,24 +2,25 @@ import { resolveAgentConfig, resolveAgentDir, resolveAgentModelFallbacksOverride
|
|
|
2
2
|
import { runCliAgent } from "../../agents/cli-runner.js";
|
|
3
3
|
import { getCliSessionId, setCliSessionId } from "../../agents/cli-session.js";
|
|
4
4
|
import { lookupContextTokens } from "../../agents/context.js";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveCronStyleNow } from "../../agents/current-time.js";
|
|
6
6
|
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../agents/defaults.js";
|
|
7
7
|
import { loadModelCatalog } from "../../agents/model-catalog.js";
|
|
8
8
|
import { runWithModelFallback } from "../../agents/model-fallback.js";
|
|
9
9
|
import { getModelRefStatus, isCliProvider, resolveAllowedModelRef, resolveConfiguredModelRef, resolveHooksGmailModel, resolveThinkingDefault, } from "../../agents/model-selection.js";
|
|
10
10
|
import { runEmbeddedPiAgent } from "../../agents/pi-embedded.js";
|
|
11
|
-
import { buildWorkspaceSkillSnapshot } from "../../agents/skills.js";
|
|
12
|
-
import { getSkillsSnapshotVersion } from "../../agents/skills/refresh.js";
|
|
13
11
|
import { runSubagentAnnounceFlow } from "../../agents/subagent-announce.js";
|
|
12
|
+
import { countActiveDescendantRuns } from "../../agents/subagent-registry.js";
|
|
14
13
|
import { resolveAgentTimeoutMs } from "../../agents/timeout.js";
|
|
15
14
|
import { deriveSessionTotalTokens, hasNonzeroUsage } from "../../agents/usage.js";
|
|
16
15
|
import { ensureAgentWorkspace } from "../../agents/workspace.js";
|
|
17
16
|
import { normalizeThinkLevel, normalizeVerboseLevel, supportsXHighThinking, } from "../../auto-reply/thinking.js";
|
|
17
|
+
import { SILENT_REPLY_TOKEN } from "../../auto-reply/tokens.js";
|
|
18
18
|
import { createOutboundSendDeps } from "../../cli/outbound-send-deps.js";
|
|
19
19
|
import { resolveAgentMainSessionKey, resolveSessionTranscriptPath, updateSessionStore, } from "../../config/sessions.js";
|
|
20
20
|
import { registerAgentRunContext } from "../../infra/agent-events.js";
|
|
21
21
|
import { deliverOutboundPayloads } from "../../infra/outbound/deliver.js";
|
|
22
|
-
import {
|
|
22
|
+
import { resolveAgentOutboundIdentity } from "../../infra/outbound/identity.js";
|
|
23
|
+
import { resolveOutboundSessionRoute } from "../../infra/outbound/outbound-session.js";
|
|
23
24
|
import { logWarn } from "../../logger.js";
|
|
24
25
|
import { buildAgentMainSessionKey, normalizeAgentId } from "../../routing/session-key.js";
|
|
25
26
|
import { buildSafeExternalPrompt, detectSuspiciousPatterns, getHookType, isExternalHookSession, } from "../../security/external-content.js";
|
|
@@ -27,6 +28,8 @@ import { resolveCronDeliveryPlan } from "../delivery.js";
|
|
|
27
28
|
import { resolveDeliveryTarget } from "./delivery-target.js";
|
|
28
29
|
import { isHeartbeatOnlyResponse, pickLastDeliverablePayload, pickLastNonEmptyTextFromPayloads, pickSummaryFromOutput, pickSummaryFromPayloads, resolveHeartbeatAckMaxChars, } from "./helpers.js";
|
|
29
30
|
import { resolveCronSession } from "./session.js";
|
|
31
|
+
import { resolveCronSkillsSnapshot } from "./skills-snapshot.js";
|
|
32
|
+
import { expectsSubagentFollowup, isLikelyInterimCronMessage, readDescendantSubagentFallbackReply, waitForDescendantSubagentSummary, } from "./subagent-followup.js";
|
|
30
33
|
function matchesMessagingToolDeliveryTarget(target, delivery) {
|
|
31
34
|
if (!delivery.to || !target.to) {
|
|
32
35
|
return false;
|
|
@@ -50,7 +53,32 @@ function resolveCronDeliveryBestEffort(job) {
|
|
|
50
53
|
}
|
|
51
54
|
return false;
|
|
52
55
|
}
|
|
56
|
+
async function resolveCronAnnounceSessionKey(params) {
|
|
57
|
+
const to = params.delivery.to?.trim();
|
|
58
|
+
if (!to) {
|
|
59
|
+
return params.fallbackSessionKey;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const route = await resolveOutboundSessionRoute({
|
|
63
|
+
cfg: params.cfg,
|
|
64
|
+
channel: params.delivery.channel,
|
|
65
|
+
agentId: params.agentId,
|
|
66
|
+
accountId: params.delivery.accountId,
|
|
67
|
+
target: to,
|
|
68
|
+
threadId: params.delivery.threadId,
|
|
69
|
+
});
|
|
70
|
+
const resolved = route?.sessionKey?.trim();
|
|
71
|
+
if (resolved) {
|
|
72
|
+
return resolved;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Fall back to main session routing if announce session resolution fails.
|
|
77
|
+
}
|
|
78
|
+
return params.fallbackSessionKey;
|
|
79
|
+
}
|
|
53
80
|
export async function runCronIsolatedAgentTurn(params) {
|
|
81
|
+
const isFastTestEnv = process.env.POOLBOT_TEST_FAST === "1";
|
|
54
82
|
const defaultAgentId = resolveDefaultAgentId(params.cfg);
|
|
55
83
|
const requestedAgentId = typeof params.agentId === "string" && params.agentId.trim()
|
|
56
84
|
? params.agentId
|
|
@@ -62,13 +90,20 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
62
90
|
? resolveAgentConfig(params.cfg, normalizedRequested)
|
|
63
91
|
: undefined;
|
|
64
92
|
const { model: overrideModel, ...agentOverrideRest } = agentConfigOverride ?? {};
|
|
65
|
-
|
|
93
|
+
// Use the requested agentId even when there is no explicit agent config entry.
|
|
94
|
+
// This ensures auth-profiles, workspace, and agentDir all resolve to the
|
|
95
|
+
// correct per-agent paths (e.g. ~/.poolbot/agents/<agentId>/agent/).
|
|
96
|
+
const agentId = normalizedRequested ?? defaultAgentId;
|
|
66
97
|
const agentCfg = Object.assign({}, params.cfg.agents?.defaults, agentOverrideRest);
|
|
98
|
+
// Merge agent model override with defaults instead of replacing, so that
|
|
99
|
+
// `fallbacks` from `agents.defaults.model` are preserved when the agent
|
|
100
|
+
// (or its per-cron model pin) only specifies `primary`.
|
|
101
|
+
const existingModel = agentCfg.model && typeof agentCfg.model === "object" ? agentCfg.model : {};
|
|
67
102
|
if (typeof overrideModel === "string") {
|
|
68
|
-
agentCfg.model = { primary: overrideModel };
|
|
103
|
+
agentCfg.model = { ...existingModel, primary: overrideModel };
|
|
69
104
|
}
|
|
70
105
|
else if (overrideModel) {
|
|
71
|
-
agentCfg.model = overrideModel;
|
|
106
|
+
agentCfg.model = { ...existingModel, ...overrideModel };
|
|
72
107
|
}
|
|
73
108
|
const cfgWithAgentDefaults = {
|
|
74
109
|
...params.cfg,
|
|
@@ -83,7 +118,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
83
118
|
const agentDir = resolveAgentDir(params.cfg, agentId);
|
|
84
119
|
const workspace = await ensureAgentWorkspace({
|
|
85
120
|
dir: workspaceDirRaw,
|
|
86
|
-
ensureBootstrapFiles: !agentCfg?.skipBootstrap,
|
|
121
|
+
ensureBootstrapFiles: !agentCfg?.skipBootstrap && !isFastTestEnv,
|
|
87
122
|
});
|
|
88
123
|
const workspaceDir = workspace.dir;
|
|
89
124
|
const resolvedDefault = resolveConfiguredModelRef({
|
|
@@ -102,6 +137,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
102
137
|
};
|
|
103
138
|
// Resolve model - prefer hooks.gmail.model for Gmail hooks.
|
|
104
139
|
const isGmailHook = baseSessionKey.startsWith("hook:gmail:");
|
|
140
|
+
let hooksGmailModelApplied = false;
|
|
105
141
|
const hooksGmailModelRef = isGmailHook
|
|
106
142
|
? resolveHooksGmailModel({
|
|
107
143
|
cfg: params.cfg,
|
|
@@ -119,6 +155,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
119
155
|
if (status.allowed) {
|
|
120
156
|
provider = hooksGmailModelRef.provider;
|
|
121
157
|
model = hooksGmailModelRef.model;
|
|
158
|
+
hooksGmailModelApplied = true;
|
|
122
159
|
}
|
|
123
160
|
}
|
|
124
161
|
const modelOverrideRaw = params.job.payload.kind === "agentTurn" ? params.job.payload.model : undefined;
|
|
@@ -149,6 +186,9 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
149
186
|
? `${agentSessionKey}:run:${runSessionId}`
|
|
150
187
|
: agentSessionKey;
|
|
151
188
|
const persistSessionEntry = async () => {
|
|
189
|
+
if (isFastTestEnv) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
152
192
|
cronSession.store[agentSessionKey] = cronSession.sessionEntry;
|
|
153
193
|
if (runSessionKey !== agentSessionKey) {
|
|
154
194
|
cronSession.store[runSessionKey] = cronSession.sessionEntry;
|
|
@@ -171,6 +211,26 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
171
211
|
: params.job.id;
|
|
172
212
|
cronSession.sessionEntry.label = `Cron: ${labelSuffix}`;
|
|
173
213
|
}
|
|
214
|
+
// Respect session model override — check session.modelOverride before falling
|
|
215
|
+
// back to the default config model. This ensures /model changes are honoured
|
|
216
|
+
// by cron and isolated agent runs.
|
|
217
|
+
if (!modelOverride && !hooksGmailModelApplied) {
|
|
218
|
+
const sessionModelOverride = cronSession.sessionEntry.modelOverride?.trim();
|
|
219
|
+
if (sessionModelOverride) {
|
|
220
|
+
const sessionProviderOverride = cronSession.sessionEntry.providerOverride?.trim() || resolvedDefault.provider;
|
|
221
|
+
const resolvedSessionOverride = resolveAllowedModelRef({
|
|
222
|
+
cfg: cfgWithAgentDefaults,
|
|
223
|
+
catalog: await loadCatalog(),
|
|
224
|
+
raw: `${sessionProviderOverride}/${sessionModelOverride}`,
|
|
225
|
+
defaultProvider: resolvedDefault.provider,
|
|
226
|
+
defaultModel: resolvedDefault.model,
|
|
227
|
+
});
|
|
228
|
+
if (!("error" in resolvedSessionOverride)) {
|
|
229
|
+
provider = resolvedSessionOverride.ref.provider;
|
|
230
|
+
model = resolvedSessionOverride.ref.model;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
174
234
|
// Resolve thinking level - job thinking > hooks.gmail.thinking > agent default
|
|
175
235
|
const hooksGmailThinking = isGmailHook
|
|
176
236
|
? normalizeThinkLevel(params.cfg.hooks?.gmail?.thinking)
|
|
@@ -202,10 +262,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
202
262
|
channel: deliveryPlan.channel ?? "last",
|
|
203
263
|
to: deliveryPlan.to,
|
|
204
264
|
});
|
|
205
|
-
const
|
|
206
|
-
const userTimeFormat = resolveUserTimeFormat(params.cfg.agents?.defaults?.timeFormat);
|
|
207
|
-
const formattedTime = formatUserTime(new Date(now), userTimezone, userTimeFormat) ?? new Date(now).toISOString();
|
|
208
|
-
const timeLine = `Current time: ${formattedTime} (${userTimezone})`;
|
|
265
|
+
const { formattedTime, timeLine } = resolveCronStyleNow(params.cfg, now);
|
|
209
266
|
const base = `[cron:${params.job.id} ${params.job.name}] ${params.message}`.trim();
|
|
210
267
|
// SECURITY: Wrap external hook content with security boundaries to prevent prompt injection
|
|
211
268
|
// unless explicitly allowed via a dangerous config override.
|
|
@@ -242,17 +299,15 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
242
299
|
commandBody =
|
|
243
300
|
`${commandBody}\n\nReturn your summary as plain text; it will be delivered automatically. If the task explicitly calls for messaging a specific external recipient, note who/where it should go instead of sending it yourself.`.trim();
|
|
244
301
|
}
|
|
245
|
-
const
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
: cronSession.sessionEntry.skillsSnapshot;
|
|
255
|
-
if (needsSkillsSnapshot && skillsSnapshot) {
|
|
302
|
+
const existingSkillsSnapshot = cronSession.sessionEntry.skillsSnapshot;
|
|
303
|
+
const skillsSnapshot = resolveCronSkillsSnapshot({
|
|
304
|
+
workspaceDir,
|
|
305
|
+
config: cfgWithAgentDefaults,
|
|
306
|
+
agentId,
|
|
307
|
+
existingSnapshot: existingSkillsSnapshot,
|
|
308
|
+
isFastTestEnv,
|
|
309
|
+
});
|
|
310
|
+
if (!isFastTestEnv && skillsSnapshot !== existingSkillsSnapshot) {
|
|
256
311
|
cronSession.sessionEntry = {
|
|
257
312
|
...cronSession.sessionEntry,
|
|
258
313
|
updatedAt: Date.now(),
|
|
@@ -290,6 +345,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
290
345
|
return runCliAgent({
|
|
291
346
|
sessionId: cronSession.sessionEntry.sessionId,
|
|
292
347
|
sessionKey: agentSessionKey,
|
|
348
|
+
agentId,
|
|
293
349
|
sessionFile,
|
|
294
350
|
workspaceDir,
|
|
295
351
|
config: cfgWithAgentDefaults,
|
|
@@ -305,6 +361,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
305
361
|
return runEmbeddedPiAgent({
|
|
306
362
|
sessionId: cronSession.sessionEntry.sessionId,
|
|
307
363
|
sessionKey: agentSessionKey,
|
|
364
|
+
agentId,
|
|
308
365
|
messageChannel,
|
|
309
366
|
agentAccountId: resolvedDelivery.accountId,
|
|
310
367
|
sessionFile,
|
|
@@ -319,6 +376,8 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
319
376
|
verboseLevel: resolvedVerboseLevel,
|
|
320
377
|
timeoutMs,
|
|
321
378
|
runId: cronSession.sessionEntry.sessionId,
|
|
379
|
+
requireExplicitMessageTarget: true,
|
|
380
|
+
disableMessageTool: deliveryRequested,
|
|
322
381
|
});
|
|
323
382
|
},
|
|
324
383
|
});
|
|
@@ -332,16 +391,19 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
332
391
|
}
|
|
333
392
|
const payloads = runResult.payloads ?? [];
|
|
334
393
|
// Update token+model fields in the session store.
|
|
394
|
+
// Also collect best-effort telemetry for the cron run log.
|
|
395
|
+
let telemetry;
|
|
335
396
|
{
|
|
336
|
-
const usage = runResult.meta
|
|
337
|
-
const
|
|
338
|
-
const
|
|
397
|
+
const usage = runResult.meta?.agentMeta?.usage;
|
|
398
|
+
const promptTokens = runResult.meta?.agentMeta?.promptTokens;
|
|
399
|
+
const modelUsed = runResult.meta?.agentMeta?.model ?? fallbackModel ?? model;
|
|
400
|
+
const providerUsed = runResult.meta?.agentMeta?.provider ?? fallbackProvider ?? provider;
|
|
339
401
|
const contextTokens = agentCfg?.contextTokens ?? lookupContextTokens(modelUsed) ?? DEFAULT_CONTEXT_TOKENS;
|
|
340
402
|
cronSession.sessionEntry.modelProvider = providerUsed;
|
|
341
403
|
cronSession.sessionEntry.model = modelUsed;
|
|
342
404
|
cronSession.sessionEntry.contextTokens = contextTokens;
|
|
343
405
|
if (isCliProvider(providerUsed, cfgWithAgentDefaults)) {
|
|
344
|
-
const cliSessionId = runResult.meta
|
|
406
|
+
const cliSessionId = runResult.meta?.agentMeta?.sessionId?.trim();
|
|
345
407
|
if (cliSessionId) {
|
|
346
408
|
setCliSessionId(cronSession.sessionEntry, providerUsed, cliSessionId);
|
|
347
409
|
}
|
|
@@ -349,22 +411,39 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
349
411
|
if (hasNonzeroUsage(usage)) {
|
|
350
412
|
const input = usage.input ?? 0;
|
|
351
413
|
const output = usage.output ?? 0;
|
|
414
|
+
const totalTokens = deriveSessionTotalTokens({
|
|
415
|
+
usage,
|
|
416
|
+
contextTokens,
|
|
417
|
+
promptTokens,
|
|
418
|
+
}) ?? input;
|
|
352
419
|
cronSession.sessionEntry.inputTokens = input;
|
|
353
420
|
cronSession.sessionEntry.outputTokens = output;
|
|
354
|
-
cronSession.sessionEntry.totalTokens =
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
421
|
+
cronSession.sessionEntry.totalTokens = totalTokens;
|
|
422
|
+
cronSession.sessionEntry.totalTokensFresh = true;
|
|
423
|
+
telemetry = {
|
|
424
|
+
model: modelUsed,
|
|
425
|
+
provider: providerUsed,
|
|
426
|
+
usage: {
|
|
427
|
+
input_tokens: input,
|
|
428
|
+
output_tokens: output,
|
|
429
|
+
total_tokens: totalTokens,
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
telemetry = {
|
|
435
|
+
model: modelUsed,
|
|
436
|
+
provider: providerUsed,
|
|
437
|
+
};
|
|
359
438
|
}
|
|
360
439
|
await persistSessionEntry();
|
|
361
440
|
}
|
|
362
441
|
const firstText = payloads[0]?.text ?? "";
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
442
|
+
let summary = pickSummaryFromPayloads(payloads) ?? pickSummaryFromOutput(firstText);
|
|
443
|
+
let outputText = pickLastNonEmptyTextFromPayloads(payloads);
|
|
444
|
+
let synthesizedText = outputText?.trim() || summary?.trim() || undefined;
|
|
366
445
|
const deliveryPayload = pickLastDeliverablePayload(payloads);
|
|
367
|
-
|
|
446
|
+
let deliveryPayloads = deliveryPayload !== undefined
|
|
368
447
|
? [deliveryPayload]
|
|
369
448
|
: synthesizedText
|
|
370
449
|
? [{ text: synthesizedText }]
|
|
@@ -383,6 +462,9 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
383
462
|
to: resolvedDelivery.to,
|
|
384
463
|
accountId: resolvedDelivery.accountId,
|
|
385
464
|
}));
|
|
465
|
+
// `true` means we confirmed at least one outbound send reached the target.
|
|
466
|
+
// Keep this strict so timer fallback can safely decide whether to wake main.
|
|
467
|
+
let delivered = skipMessagingToolDelivery;
|
|
386
468
|
if (deliveryRequested && !skipHeartbeatDelivery && !skipMessagingToolDelivery) {
|
|
387
469
|
if (resolvedDelivery.error) {
|
|
388
470
|
if (!deliveryBestEffort) {
|
|
@@ -391,10 +473,11 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
391
473
|
error: resolvedDelivery.error.message,
|
|
392
474
|
summary,
|
|
393
475
|
outputText,
|
|
476
|
+
...telemetry,
|
|
394
477
|
});
|
|
395
478
|
}
|
|
396
479
|
logWarn(`[cron:${params.job.id}] ${resolvedDelivery.error.message}`);
|
|
397
|
-
return withRunSession({ status: "ok", summary, outputText });
|
|
480
|
+
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
|
398
481
|
}
|
|
399
482
|
if (!resolvedDelivery.to) {
|
|
400
483
|
const message = "cron delivery target is missing";
|
|
@@ -404,43 +487,117 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
404
487
|
error: message,
|
|
405
488
|
summary,
|
|
406
489
|
outputText,
|
|
490
|
+
...telemetry,
|
|
407
491
|
});
|
|
408
492
|
}
|
|
409
493
|
logWarn(`[cron:${params.job.id}] ${message}`);
|
|
410
|
-
return withRunSession({ status: "ok", summary, outputText });
|
|
494
|
+
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
|
411
495
|
}
|
|
412
|
-
|
|
413
|
-
//
|
|
496
|
+
const identity = resolveAgentOutboundIdentity(cfgWithAgentDefaults, agentId);
|
|
497
|
+
// Route text-only cron announce output back through the main session so it
|
|
498
|
+
// follows the same system-message injection path as subagent completions.
|
|
499
|
+
// Keep direct outbound delivery only for structured payloads (media/channel
|
|
500
|
+
// data), which cannot be represented by the shared announce flow.
|
|
414
501
|
if (deliveryPayloadHasStructuredContent) {
|
|
415
502
|
try {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
503
|
+
const payloadsForDelivery = deliveryPayloads.length > 0
|
|
504
|
+
? deliveryPayloads
|
|
505
|
+
: synthesizedText
|
|
506
|
+
? [{ text: synthesizedText }]
|
|
507
|
+
: [];
|
|
508
|
+
if (payloadsForDelivery.length > 0) {
|
|
509
|
+
const deliveryResults = await deliverOutboundPayloads({
|
|
510
|
+
cfg: cfgWithAgentDefaults,
|
|
511
|
+
channel: resolvedDelivery.channel,
|
|
512
|
+
to: resolvedDelivery.to,
|
|
513
|
+
accountId: resolvedDelivery.accountId,
|
|
514
|
+
threadId: resolvedDelivery.threadId,
|
|
515
|
+
payloads: payloadsForDelivery,
|
|
516
|
+
agentId,
|
|
517
|
+
identity,
|
|
518
|
+
bestEffort: deliveryBestEffort,
|
|
519
|
+
deps: createOutboundSendDeps(params.deps),
|
|
520
|
+
});
|
|
521
|
+
delivered = deliveryResults.length > 0;
|
|
522
|
+
}
|
|
426
523
|
}
|
|
427
524
|
catch (err) {
|
|
428
525
|
if (!deliveryBestEffort) {
|
|
429
|
-
return withRunSession({
|
|
526
|
+
return withRunSession({
|
|
527
|
+
status: "error",
|
|
528
|
+
summary,
|
|
529
|
+
outputText,
|
|
530
|
+
error: String(err),
|
|
531
|
+
...telemetry,
|
|
532
|
+
});
|
|
430
533
|
}
|
|
431
534
|
}
|
|
432
535
|
}
|
|
433
536
|
else if (synthesizedText) {
|
|
434
|
-
const
|
|
537
|
+
const announceMainSessionKey = resolveAgentMainSessionKey({
|
|
435
538
|
cfg: params.cfg,
|
|
436
539
|
agentId,
|
|
437
540
|
});
|
|
541
|
+
const announceSessionKey = await resolveCronAnnounceSessionKey({
|
|
542
|
+
cfg: cfgWithAgentDefaults,
|
|
543
|
+
agentId,
|
|
544
|
+
fallbackSessionKey: announceMainSessionKey,
|
|
545
|
+
delivery: {
|
|
546
|
+
channel: resolvedDelivery.channel,
|
|
547
|
+
to: resolvedDelivery.to,
|
|
548
|
+
accountId: resolvedDelivery.accountId,
|
|
549
|
+
threadId: resolvedDelivery.threadId,
|
|
550
|
+
},
|
|
551
|
+
});
|
|
438
552
|
const taskLabel = typeof params.job.name === "string" && params.job.name.trim()
|
|
439
553
|
? params.job.name.trim()
|
|
440
554
|
: `cron:${params.job.id}`;
|
|
555
|
+
const initialSynthesizedText = synthesizedText.trim();
|
|
556
|
+
let activeSubagentRuns = countActiveDescendantRuns(agentSessionKey);
|
|
557
|
+
const expectedSubagentFollowup = expectsSubagentFollowup(initialSynthesizedText);
|
|
558
|
+
const hadActiveDescendants = activeSubagentRuns > 0;
|
|
559
|
+
if (activeSubagentRuns > 0 || expectedSubagentFollowup) {
|
|
560
|
+
let finalReply = await waitForDescendantSubagentSummary({
|
|
561
|
+
sessionKey: agentSessionKey,
|
|
562
|
+
initialReply: initialSynthesizedText,
|
|
563
|
+
timeoutMs,
|
|
564
|
+
observedActiveDescendants: activeSubagentRuns > 0 || expectedSubagentFollowup,
|
|
565
|
+
});
|
|
566
|
+
activeSubagentRuns = countActiveDescendantRuns(agentSessionKey);
|
|
567
|
+
if (!finalReply &&
|
|
568
|
+
activeSubagentRuns === 0 &&
|
|
569
|
+
(hadActiveDescendants || expectedSubagentFollowup)) {
|
|
570
|
+
finalReply = await readDescendantSubagentFallbackReply({
|
|
571
|
+
sessionKey: agentSessionKey,
|
|
572
|
+
runStartedAt,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
if (finalReply && activeSubagentRuns === 0) {
|
|
576
|
+
outputText = finalReply;
|
|
577
|
+
summary = pickSummaryFromOutput(finalReply) ?? summary;
|
|
578
|
+
synthesizedText = finalReply;
|
|
579
|
+
deliveryPayloads = [{ text: finalReply }];
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
if (activeSubagentRuns > 0) {
|
|
583
|
+
// Parent orchestration is still in progress; avoid announcing a partial
|
|
584
|
+
// update to the main requester.
|
|
585
|
+
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
|
586
|
+
}
|
|
587
|
+
if ((hadActiveDescendants || expectedSubagentFollowup) &&
|
|
588
|
+
synthesizedText.trim() === initialSynthesizedText &&
|
|
589
|
+
isLikelyInterimCronMessage(initialSynthesizedText) &&
|
|
590
|
+
initialSynthesizedText.toUpperCase() !== SILENT_REPLY_TOKEN.toUpperCase()) {
|
|
591
|
+
// Descendants existed but no post-orchestration synthesis arrived, so
|
|
592
|
+
// suppress stale parent text like "on it, pulling everything together".
|
|
593
|
+
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
|
594
|
+
}
|
|
595
|
+
if (synthesizedText.toUpperCase() === SILENT_REPLY_TOKEN.toUpperCase()) {
|
|
596
|
+
return withRunSession({ status: "ok", summary, outputText, ...telemetry });
|
|
597
|
+
}
|
|
441
598
|
try {
|
|
442
599
|
const didAnnounce = await runSubagentAnnounceFlow({
|
|
443
|
-
childSessionKey:
|
|
600
|
+
childSessionKey: agentSessionKey,
|
|
444
601
|
childRunId: `${params.job.id}:${runSessionId}`,
|
|
445
602
|
requesterSessionKey: announceSessionKey,
|
|
446
603
|
requesterOrigin: {
|
|
@@ -452,7 +609,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
452
609
|
requesterDisplayKey: announceSessionKey,
|
|
453
610
|
task: taskLabel,
|
|
454
611
|
timeoutMs,
|
|
455
|
-
cleanup: "keep",
|
|
612
|
+
cleanup: params.job.deleteAfterRun ? "delete" : "keep",
|
|
456
613
|
roundOneReply: synthesizedText,
|
|
457
614
|
waitForCompletion: false,
|
|
458
615
|
startedAt: runStartedAt,
|
|
@@ -460,7 +617,10 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
460
617
|
outcome: { status: "ok" },
|
|
461
618
|
announceType: "cron job",
|
|
462
619
|
});
|
|
463
|
-
if (
|
|
620
|
+
if (didAnnounce) {
|
|
621
|
+
delivered = true;
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
464
624
|
const message = "cron announce delivery failed";
|
|
465
625
|
if (!deliveryBestEffort) {
|
|
466
626
|
return withRunSession({
|
|
@@ -468,6 +628,7 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
468
628
|
summary,
|
|
469
629
|
outputText,
|
|
470
630
|
error: message,
|
|
631
|
+
...telemetry,
|
|
471
632
|
});
|
|
472
633
|
}
|
|
473
634
|
logWarn(`[cron:${params.job.id}] ${message}`);
|
|
@@ -475,11 +636,17 @@ export async function runCronIsolatedAgentTurn(params) {
|
|
|
475
636
|
}
|
|
476
637
|
catch (err) {
|
|
477
638
|
if (!deliveryBestEffort) {
|
|
478
|
-
return withRunSession({
|
|
639
|
+
return withRunSession({
|
|
640
|
+
status: "error",
|
|
641
|
+
summary,
|
|
642
|
+
outputText,
|
|
643
|
+
error: String(err),
|
|
644
|
+
...telemetry,
|
|
645
|
+
});
|
|
479
646
|
}
|
|
480
647
|
logWarn(`[cron:${params.job.id}] ${String(err)}`);
|
|
481
648
|
}
|
|
482
649
|
}
|
|
483
650
|
}
|
|
484
|
-
return withRunSession({ status: "ok", summary, outputText });
|
|
651
|
+
return withRunSession({ status: "ok", summary, outputText, delivered, ...telemetry });
|
|
485
652
|
}
|
package/dist/cron/normalize.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { sanitizeAgentId } from "../routing/session-key.js";
|
|
2
2
|
import { isRecord } from "../utils.js";
|
|
3
|
+
import { buildDeliveryFromLegacyPayload, hasLegacyDeliveryHints, stripLegacyDeliveryFields, } from "./legacy-delivery.js";
|
|
3
4
|
import { parseAbsoluteTimeMs } from "./parse.js";
|
|
4
5
|
import { migrateLegacyCronPayload } from "./payload-migration.js";
|
|
5
6
|
import { inferLegacyName } from "./service/normalize.js";
|
|
7
|
+
import { normalizeCronStaggerMs, resolveDefaultCronStaggerMs } from "./stagger.js";
|
|
6
8
|
const DEFAULT_OPTIONS = {
|
|
7
9
|
applyDefaults: false,
|
|
8
10
|
};
|
|
@@ -45,6 +47,13 @@ function coerceSchedule(schedule) {
|
|
|
45
47
|
if ("atMs" in next) {
|
|
46
48
|
delete next.atMs;
|
|
47
49
|
}
|
|
50
|
+
const staggerMs = normalizeCronStaggerMs(schedule.staggerMs);
|
|
51
|
+
if (staggerMs !== undefined) {
|
|
52
|
+
next.staggerMs = staggerMs;
|
|
53
|
+
}
|
|
54
|
+
else if ("staggerMs" in next) {
|
|
55
|
+
delete next.staggerMs;
|
|
56
|
+
}
|
|
48
57
|
return next;
|
|
49
58
|
}
|
|
50
59
|
function coercePayload(payload) {
|
|
@@ -64,12 +73,20 @@ function coercePayload(payload) {
|
|
|
64
73
|
if (!next.kind) {
|
|
65
74
|
const hasMessage = typeof next.message === "string" && next.message.trim().length > 0;
|
|
66
75
|
const hasText = typeof next.text === "string" && next.text.trim().length > 0;
|
|
76
|
+
const hasAgentTurnHint = typeof next.model === "string" ||
|
|
77
|
+
typeof next.thinking === "string" ||
|
|
78
|
+
typeof next.timeoutSeconds === "number" ||
|
|
79
|
+
typeof next.allowUnsafeExternalContent === "boolean";
|
|
67
80
|
if (hasMessage) {
|
|
68
81
|
next.kind = "agentTurn";
|
|
69
82
|
}
|
|
70
83
|
else if (hasText) {
|
|
71
84
|
next.kind = "systemEvent";
|
|
72
85
|
}
|
|
86
|
+
else if (hasAgentTurnHint) {
|
|
87
|
+
// Accept partial agentTurn payload patches that only tweak agent-turn-only fields.
|
|
88
|
+
next.kind = "agentTurn";
|
|
89
|
+
}
|
|
73
90
|
}
|
|
74
91
|
if (typeof next.message === "string") {
|
|
75
92
|
const trimmed = next.message.trim();
|
|
@@ -113,7 +130,7 @@ function coercePayload(payload) {
|
|
|
113
130
|
}
|
|
114
131
|
if ("timeoutSeconds" in next) {
|
|
115
132
|
if (typeof next.timeoutSeconds === "number" && Number.isFinite(next.timeoutSeconds)) {
|
|
116
|
-
next.timeoutSeconds = Math.max(
|
|
133
|
+
next.timeoutSeconds = Math.max(0, Math.floor(next.timeoutSeconds));
|
|
117
134
|
}
|
|
118
135
|
else {
|
|
119
136
|
delete next.timeoutSeconds;
|
|
@@ -132,7 +149,7 @@ function coerceDelivery(delivery) {
|
|
|
132
149
|
if (mode === "deliver") {
|
|
133
150
|
next.mode = "announce";
|
|
134
151
|
}
|
|
135
|
-
else if (mode === "announce" || mode === "none") {
|
|
152
|
+
else if (mode === "announce" || mode === "none" || mode === "webhook") {
|
|
136
153
|
next.mode = mode;
|
|
137
154
|
}
|
|
138
155
|
else {
|
|
@@ -162,49 +179,6 @@ function coerceDelivery(delivery) {
|
|
|
162
179
|
}
|
|
163
180
|
return next;
|
|
164
181
|
}
|
|
165
|
-
function hasLegacyDeliveryHints(payload) {
|
|
166
|
-
if (typeof payload.deliver === "boolean") {
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
169
|
-
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
170
|
-
return true;
|
|
171
|
-
}
|
|
172
|
-
if (typeof payload.to === "string" && payload.to.trim()) {
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
function buildDeliveryFromLegacyPayload(payload) {
|
|
178
|
-
const deliver = payload.deliver;
|
|
179
|
-
const mode = deliver === false ? "none" : "announce";
|
|
180
|
-
const channelRaw = typeof payload.channel === "string" ? payload.channel.trim().toLowerCase() : "";
|
|
181
|
-
const toRaw = typeof payload.to === "string" ? payload.to.trim() : "";
|
|
182
|
-
const next = { mode };
|
|
183
|
-
if (channelRaw) {
|
|
184
|
-
next.channel = channelRaw;
|
|
185
|
-
}
|
|
186
|
-
if (toRaw) {
|
|
187
|
-
next.to = toRaw;
|
|
188
|
-
}
|
|
189
|
-
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
190
|
-
next.bestEffort = payload.bestEffortDeliver;
|
|
191
|
-
}
|
|
192
|
-
return next;
|
|
193
|
-
}
|
|
194
|
-
function stripLegacyDeliveryFields(payload) {
|
|
195
|
-
if ("deliver" in payload) {
|
|
196
|
-
delete payload.deliver;
|
|
197
|
-
}
|
|
198
|
-
if ("channel" in payload) {
|
|
199
|
-
delete payload.channel;
|
|
200
|
-
}
|
|
201
|
-
if ("to" in payload) {
|
|
202
|
-
delete payload.to;
|
|
203
|
-
}
|
|
204
|
-
if ("bestEffortDeliver" in payload) {
|
|
205
|
-
delete payload.bestEffortDeliver;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
182
|
function unwrapJob(raw) {
|
|
209
183
|
if (isRecord(raw.data)) {
|
|
210
184
|
return raw.data;
|
|
@@ -310,6 +284,21 @@ export function normalizeCronJobInput(raw, options = DEFAULT_OPTIONS) {
|
|
|
310
284
|
}
|
|
311
285
|
}
|
|
312
286
|
}
|
|
287
|
+
if ("sessionKey" in base) {
|
|
288
|
+
const sessionKey = base.sessionKey;
|
|
289
|
+
if (sessionKey === null) {
|
|
290
|
+
next.sessionKey = null;
|
|
291
|
+
}
|
|
292
|
+
else if (typeof sessionKey === "string") {
|
|
293
|
+
const trimmed = sessionKey.trim();
|
|
294
|
+
if (trimmed) {
|
|
295
|
+
next.sessionKey = trimmed;
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
delete next.sessionKey;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
313
302
|
if ("enabled" in base) {
|
|
314
303
|
const enabled = base.enabled;
|
|
315
304
|
if (typeof enabled === "boolean") {
|
|
@@ -407,6 +396,20 @@ export function normalizeCronJobInput(raw, options = DEFAULT_OPTIONS) {
|
|
|
407
396
|
!("deleteAfterRun" in next)) {
|
|
408
397
|
next.deleteAfterRun = true;
|
|
409
398
|
}
|
|
399
|
+
if ("schedule" in next && isRecord(next.schedule) && next.schedule.kind === "cron") {
|
|
400
|
+
const schedule = next.schedule;
|
|
401
|
+
const explicit = normalizeCronStaggerMs(schedule.staggerMs);
|
|
402
|
+
if (explicit !== undefined) {
|
|
403
|
+
schedule.staggerMs = explicit;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
const expr = typeof schedule.expr === "string" ? schedule.expr : "";
|
|
407
|
+
const defaultStaggerMs = resolveDefaultCronStaggerMs(expr);
|
|
408
|
+
if (defaultStaggerMs !== undefined) {
|
|
409
|
+
schedule.staggerMs = defaultStaggerMs;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
410
413
|
const payload = isRecord(next.payload) ? next.payload : null;
|
|
411
414
|
const payloadKind = payload && typeof payload.kind === "string" ? payload.kind : "";
|
|
412
415
|
const sessionTarget = typeof next.sessionTarget === "string" ? next.sessionTarget : "";
|