@poolzin/pool-bot 2026.2.21 → 2026.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/agents/api-key-rotation.js +47 -0
- package/dist/agents/apply-patch-update.js +19 -9
- package/dist/agents/apply-patch.js +72 -47
- package/dist/agents/bash-tools.exec.js +141 -559
- package/dist/agents/cli-backends.js +49 -6
- package/dist/agents/cli-runner/helpers.js +69 -152
- package/dist/agents/cli-runner.js +70 -19
- package/dist/agents/identity.js +20 -1
- package/dist/agents/image-sanitization.js +9 -0
- package/dist/agents/live-auth-keys.js +123 -26
- package/dist/agents/live-model-filter.js +13 -4
- package/dist/agents/model-catalog.js +40 -9
- package/dist/agents/model-forward-compat.js +60 -23
- package/dist/agents/model-selection.js +134 -41
- package/dist/agents/pi-auth-json.js +2 -2
- package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
- package/dist/agents/pi-embedded-helpers/errors.js +140 -15
- package/dist/agents/pi-embedded-helpers/images.js +22 -12
- package/dist/agents/pi-embedded-helpers.js +2 -2
- package/dist/agents/pi-embedded-runner/abort.js +10 -3
- package/dist/agents/pi-embedded-runner/compact.js +230 -32
- package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
- package/dist/agents/pi-embedded-runner/google.js +109 -19
- package/dist/agents/pi-embedded-runner/history.js +35 -17
- package/dist/agents/pi-embedded-runner/run/attempt.js +386 -95
- package/dist/agents/pi-embedded-runner/run/images.js +81 -55
- package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
- package/dist/agents/pi-embedded-runner/run.js +193 -25
- package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
- package/dist/agents/pi-embedded-runner/runs.js +17 -8
- package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
- package/dist/agents/pi-embedded-runner.js +1 -1
- package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
- package/dist/agents/pi-embedded-subscribe.js +37 -0
- package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
- package/dist/agents/pi-model-discovery.js +9 -2
- package/dist/agents/pi-tool-definition-adapter.js +60 -8
- package/dist/agents/pi-tools.before-tool-call.js +1 -1
- package/dist/agents/pi-tools.js +113 -94
- package/dist/agents/pi-tools.read.js +337 -38
- package/dist/agents/poolbot-tools.js +14 -5
- package/dist/agents/sandbox/docker.js +10 -5
- package/dist/agents/sandbox/registry.js +96 -46
- package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
- package/dist/agents/sandbox-paths.js +43 -10
- package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
- package/dist/agents/session-tool-result-guard.js +39 -39
- package/dist/agents/session-transcript-repair.js +36 -33
- package/dist/agents/session-write-lock.js +62 -44
- package/dist/agents/skills/frontmatter.js +49 -88
- package/dist/agents/skills/workspace.js +335 -28
- package/dist/agents/subagent-announce.js +508 -174
- package/dist/agents/subagent-registry.js +45 -4
- package/dist/agents/subagent-spawn.js +16 -33
- package/dist/agents/system-prompt-report.js +27 -10
- package/dist/agents/system-prompt.js +26 -32
- package/dist/agents/tool-call-id.js +69 -17
- package/dist/agents/tool-display-common.js +1 -1
- package/dist/agents/tool-images.js +64 -31
- package/dist/agents/tools/canvas-tool.js +17 -11
- package/dist/agents/tools/common.js +37 -19
- package/dist/agents/tools/cron-tool.js +40 -38
- package/dist/agents/tools/gateway.js +70 -2
- package/dist/agents/tools/message-tool.js +181 -40
- package/dist/agents/tools/nodes-tool.js +128 -36
- package/dist/agents/tools/nodes-utils.js +12 -38
- package/dist/agents/tools/session-status-tool.js +24 -71
- package/dist/agents/tools/sessions-helpers.js +38 -210
- package/dist/agents/tools/sessions-spawn-tool.js +28 -198
- package/dist/agents/tools/telegram-actions.js +58 -7
- package/dist/agents/tools/web-fetch-utils.js +112 -7
- package/dist/agents/tools/web-fetch.js +279 -175
- package/dist/agents/tools/web-shared.js +71 -8
- package/dist/agents/usage.js +25 -16
- package/dist/auto-reply/commands-registry.data.js +85 -11
- package/dist/auto-reply/dispatch.js +40 -21
- package/dist/auto-reply/reply/abort.js +102 -33
- package/dist/auto-reply/reply/commands-core.js +82 -33
- package/dist/auto-reply/reply/commands-export-session.js +1 -1
- package/dist/auto-reply/reply/commands-info.js +41 -12
- package/dist/auto-reply/reply/commands-subagents.js +352 -100
- package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
- package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
- package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
- package/dist/auto-reply/reply/inbound-meta.js +12 -1
- package/dist/auto-reply/reply/mentions.js +18 -11
- package/dist/auto-reply/reply/normalize-reply.js +17 -8
- package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
- package/dist/auto-reply/reply/session.js +102 -21
- package/dist/auto-reply/reply/streaming-directives.js +16 -5
- package/dist/auto-reply/status.js +73 -50
- package/dist/browser/extension-relay.js +3 -3
- package/dist/browser/http-auth.js +1 -1
- package/dist/browser/paths.js +2 -2
- package/dist/build-info.json +3 -3
- package/dist/channels/allowlist-match.js +20 -0
- package/dist/channels/allowlists/resolve-utils.js +65 -2
- package/dist/channels/chat-type.js +8 -4
- package/dist/channels/dock.js +127 -35
- package/dist/channels/draft-stream-loop.js +6 -2
- package/dist/channels/plugins/actions/telegram.js +42 -18
- package/dist/channels/plugins/allowlist-match.js +1 -1
- package/dist/channels/plugins/group-mentions.js +51 -41
- package/dist/channels/plugins/message-action-names.js +2 -0
- package/dist/channels/plugins/message-actions.js +24 -5
- package/dist/channels/plugins/normalize/discord.js +26 -4
- package/dist/channels/plugins/normalize/signal.js +35 -22
- package/dist/channels/plugins/onboarding/helpers.js +8 -26
- package/dist/channels/plugins/outbound/imessage.js +15 -14
- package/dist/channels/registry.js +20 -7
- package/dist/cli/acp-cli.js +7 -5
- package/dist/cli/browser-cli-extension.js +25 -12
- package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
- package/dist/cli/browser-cli-state.js +101 -145
- package/dist/cli/command-options.js +28 -0
- package/dist/cli/completion-cli.js +6 -6
- package/dist/cli/cron-cli/register.cron-add.js +25 -1
- package/dist/cli/cron-cli/register.cron-edit.js +44 -0
- package/dist/cli/cron-cli/shared.js +7 -1
- package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
- package/dist/cli/daemon-cli/lifecycle.js +23 -247
- package/dist/cli/daemon-cli/register-service-commands.js +25 -4
- package/dist/cli/daemon-cli.js +1 -0
- package/dist/cli/devices-cli.js +33 -20
- package/dist/cli/gateway-cli/register.js +37 -105
- package/dist/cli/gateway-cli/run.js +49 -11
- package/dist/cli/nodes-camera.js +59 -4
- package/dist/cli/nodes-cli/register.camera.js +27 -24
- package/dist/cli/nodes-cli/rpc.js +21 -38
- package/dist/cli/qr-cli.js +2 -2
- package/dist/cli/skills-cli.format.js +2 -2
- package/dist/cli/update-cli/progress.js +2 -2
- package/dist/cli/update-cli/restart-helper.js +28 -7
- package/dist/cli/update-cli/shared.js +7 -7
- package/dist/cli/update-cli/status.js +1 -1
- package/dist/cli/update-cli/update-command.js +14 -8
- package/dist/cli/update-cli/wizard.js +2 -2
- package/dist/cli/update-cli.js +21 -1027
- package/dist/commands/auth-choice.apply.anthropic.js +10 -2
- package/dist/commands/channels/add-mutators.js +3 -35
- package/dist/commands/channels/add.js +39 -51
- package/dist/commands/config-validation.js +1 -1
- package/dist/commands/configure.gateway-auth.js +52 -15
- package/dist/commands/configure.gateway.js +84 -40
- package/dist/commands/doctor-completion.js +3 -3
- package/dist/commands/doctor-config-flow.js +536 -16
- package/dist/commands/doctor-gateway-services.js +103 -79
- package/dist/commands/doctor-memory-search.js +9 -9
- package/dist/commands/doctor-platform-notes.js +57 -30
- package/dist/commands/doctor-prompter.js +26 -15
- package/dist/commands/doctor-session-locks.js +1 -1
- package/dist/commands/doctor.js +21 -9
- package/dist/commands/model-picker.js +120 -95
- package/dist/commands/models/set.js +2 -21
- package/dist/commands/models/shared.js +65 -37
- package/dist/commands/onboard-helpers.js +81 -39
- package/dist/commands/openai-codex-oauth.js +1 -1
- package/dist/commands/sessions.js +52 -53
- package/dist/commands/status.summary.js +52 -34
- package/dist/commands/test-wizard-helpers.js +2 -2
- package/dist/config/defaults.js +79 -42
- package/dist/config/group-policy.js +50 -18
- package/dist/config/includes.js +37 -10
- package/dist/config/schema.help.js +5 -4
- package/dist/config/schema.hints.js +2 -2
- package/dist/config/schema.labels.js +1 -0
- package/dist/config/sessions/group.js +12 -11
- package/dist/config/sessions/paths.js +137 -11
- package/dist/config/sessions/store.js +185 -65
- package/dist/config/sessions/types.js +15 -1
- package/dist/config/sessions.js +1 -0
- package/dist/config/telegram-custom-commands.js +3 -2
- package/dist/config/types.js +2 -0
- package/dist/config/zod-schema.agent-defaults.js +6 -27
- package/dist/config/zod-schema.agent-runtime.js +171 -79
- package/dist/config/zod-schema.providers-core.js +138 -65
- package/dist/config/zod-schema.session.js +49 -22
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
- package/dist/cron/isolated-agent/run.js +224 -57
- package/dist/cron/normalize.js +48 -45
- package/dist/cron/run-log.js +14 -0
- package/dist/cron/service/jobs.js +190 -28
- package/dist/cron/service/normalize.js +29 -11
- package/dist/cron/service/store.js +30 -44
- package/dist/cron/service/timer.js +182 -96
- package/dist/cron/service.js +3 -0
- package/dist/cron/stagger.js +37 -0
- package/dist/daemon/inspect.js +132 -92
- package/dist/daemon/runtime-paths.js +25 -4
- package/dist/daemon/service-audit.js +47 -16
- package/dist/discord/accounts.js +23 -20
- package/dist/discord/monitor/agent-components.js +1115 -219
- package/dist/discord/monitor/allow-list.js +114 -34
- package/dist/discord/monitor/listeners.js +204 -97
- package/dist/discord/monitor/message-handler.js +21 -10
- package/dist/discord/monitor/message-handler.preflight.js +195 -101
- package/dist/discord/monitor/message-handler.process.js +384 -123
- package/dist/discord/monitor/message-utils.js +86 -23
- package/dist/discord/monitor/native-command.js +77 -57
- package/dist/discord/monitor/provider.js +122 -117
- package/dist/discord/monitor/reply-context.js +20 -16
- package/dist/discord/monitor/reply-delivery.js +40 -8
- package/dist/discord/monitor/rest-fetch.js +22 -0
- package/dist/discord/monitor/threading.js +117 -24
- package/dist/discord/send.js +2 -1
- package/dist/discord/send.outbound.js +124 -11
- package/dist/discord/send.shared.js +112 -72
- package/dist/discord/voice-message.js +3 -3
- package/dist/gateway/auth.js +119 -44
- package/dist/gateway/call.js +76 -34
- package/dist/gateway/channel-health-monitor.js +57 -50
- package/dist/gateway/client.js +63 -29
- package/dist/gateway/control-ui-contract.js +1 -1
- package/dist/gateway/gateway-config-prompts.shared.js +2 -2
- package/dist/gateway/net.js +109 -1
- package/dist/gateway/protocol/index.js +5 -8
- package/dist/gateway/protocol/schema/agent.js +19 -1
- package/dist/gateway/protocol/schema/channels.js +21 -0
- package/dist/gateway/protocol/schema/cron.js +43 -30
- package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
- package/dist/gateway/protocol/schema/sessions.js +5 -1
- package/dist/gateway/protocol/schema.js +0 -1
- package/dist/gateway/server/presence-events.js +12 -0
- package/dist/gateway/server/ws-connection/message-handler.js +203 -212
- package/dist/gateway/server/ws-connection.js +58 -21
- package/dist/gateway/server-broadcast.js +18 -13
- package/dist/gateway/server-cron.js +177 -10
- package/dist/gateway/server-methods/agent-job.js +131 -38
- package/dist/gateway/server-methods/send.js +60 -14
- package/dist/gateway/server-methods/sessions.js +160 -96
- package/dist/gateway/server-methods/system.js +5 -7
- package/dist/gateway/server-methods-list.js +8 -0
- package/dist/gateway/server-methods.js +24 -8
- package/dist/gateway/server-node-events.js +278 -68
- package/dist/gateway/session-utils.fs.js +316 -75
- package/dist/gateway/session-utils.js +224 -70
- package/dist/gateway/sessions-patch.js +63 -20
- package/dist/gateway/test-temp-config.js +1 -1
- package/dist/gateway/tools-invoke-http.js +118 -70
- package/dist/gateway/ws-log.js +135 -107
- package/dist/hooks/frontmatter.js +36 -82
- package/dist/hooks/install.js +149 -139
- package/dist/hooks/internal-hooks.js +29 -4
- package/dist/hooks/plugin-hooks.js +2 -1
- package/dist/imessage/monitor/deliver.js +10 -4
- package/dist/imessage/monitor/monitor-provider.js +138 -375
- package/dist/imessage/monitor/runtime.js +4 -8
- package/dist/imessage/send.js +65 -19
- package/dist/infra/exec-approvals-allowlist.js +7 -0
- package/dist/infra/exec-approvals.js +35 -920
- package/dist/infra/exec-safe-bin-trust.js +64 -0
- package/dist/infra/heartbeat-runner.js +207 -134
- package/dist/infra/heartbeat-wake.js +183 -22
- package/dist/infra/install-source-utils.js +47 -0
- package/dist/infra/net/ssrf.js +170 -36
- package/dist/infra/outbound/deliver.js +224 -58
- package/dist/infra/outbound/message-action-spec.js +12 -5
- package/dist/infra/outbound/outbound-session.js +27 -25
- package/dist/infra/poolbot-root.js +32 -22
- package/dist/infra/ports.js +14 -11
- package/dist/infra/skills-remote.js +48 -37
- package/dist/infra/system-events.js +25 -11
- package/dist/infra/system-presence.js +26 -33
- package/dist/infra/tmp-poolbot-dir.js +81 -2
- package/dist/infra/wsl.js +37 -1
- package/dist/line/bot-message-context.js +163 -191
- package/dist/logging/subsystem.js +59 -22
- package/dist/markdown/ir.js +124 -50
- package/dist/media/store.js +1 -1
- package/dist/media-understanding/runner.entries.js +42 -25
- package/dist/media-understanding/runner.js +53 -488
- package/dist/memory/embeddings-gemini.js +53 -38
- package/dist/memory/manager-embedding-ops.js +48 -69
- package/dist/pairing/pairing-store.js +178 -119
- package/dist/plugin-sdk/index.js +34 -6
- package/dist/plugins/hooks.js +135 -14
- package/dist/plugins/install.js +190 -152
- package/dist/polls.js +11 -0
- package/dist/routing/resolve-route.js +190 -56
- package/dist/routing/session-key.js +38 -22
- package/dist/runtime.js +35 -9
- package/dist/security/audit-channel.js +1 -1
- package/dist/sessions/session-key-utils.js +29 -11
- package/dist/shared/frontmatter.js +5 -5
- package/dist/shared/node-list-types.js +1 -0
- package/dist/shared/string-normalization.js +15 -0
- package/dist/signal/monitor/event-handler.js +68 -36
- package/dist/signal/send.js +29 -37
- package/dist/slack/monitor/allow-list.js +10 -11
- package/dist/slack/monitor/commands.js +14 -3
- package/dist/slack/monitor/events/interactions.js +4 -4
- package/dist/slack/monitor/media.js +224 -16
- package/dist/slack/monitor/message-handler/dispatch.js +247 -13
- package/dist/slack/monitor/message-handler/prepare.js +128 -45
- package/dist/slack/monitor/slash.js +357 -144
- package/dist/slack/streaming.js +77 -0
- package/dist/telegram/accounts.js +40 -13
- package/dist/telegram/allowed-updates.js +3 -0
- package/dist/telegram/bot/delivery.js +129 -66
- package/dist/telegram/bot/helpers.js +136 -122
- package/dist/telegram/bot-handlers.js +600 -339
- package/dist/telegram/bot-message-context.js +115 -73
- package/dist/telegram/bot-message-dispatch.js +235 -104
- package/dist/telegram/bot-native-command-menu.js +3 -1
- package/dist/telegram/bot-native-commands.js +213 -193
- package/dist/telegram/bot.js +24 -132
- package/dist/telegram/draft-stream.js +84 -75
- package/dist/telegram/format.js +150 -6
- package/dist/telegram/send.js +415 -255
- package/dist/telegram/targets.js +21 -2
- package/dist/telegram/update-offset-store.js +19 -3
- package/dist/terminal/restore.js +5 -2
- package/dist/test-utils/fetch-mock.js +5 -0
- package/dist/version.js +18 -5
- package/dist/web/auto-reply/monitor/broadcast.js +7 -3
- package/dist/web/auto-reply/monitor/on-message.js +6 -3
- package/dist/web/inbound/media.js +34 -8
- package/dist/web/inbound/monitor.js +34 -17
- package/dist/web/inbound/send-api.js +18 -17
- package/dist/web/outbound.js +12 -5
- package/dist/wizard/clack-prompter.js +40 -7
- package/extensions/bluebubbles/package.json +1 -1
- package/extensions/copilot-proxy/package.json +1 -1
- package/extensions/diagnostics-otel/package.json +1 -1
- package/extensions/discord/package.json +1 -1
- package/extensions/feishu/package.json +1 -1
- package/extensions/google-antigravity-auth/package.json +1 -1
- package/extensions/google-gemini-cli-auth/package.json +1 -1
- package/extensions/googlechat/package.json +1 -1
- package/extensions/imessage/package.json +1 -1
- package/extensions/irc/package.json +1 -1
- package/extensions/line/package.json +1 -1
- package/extensions/llm-task/package.json +1 -1
- package/extensions/lobster/package.json +1 -1
- package/extensions/matrix/CHANGELOG.md +5 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/mattermost/package.json +1 -1
- package/extensions/memory-core/package.json +1 -1
- package/extensions/memory-lancedb/package.json +1 -1
- package/extensions/minimax-portal-auth/package.json +1 -1
- package/extensions/msteams/CHANGELOG.md +5 -0
- package/extensions/msteams/package.json +1 -1
- package/extensions/nextcloud-talk/package.json +1 -1
- package/extensions/nostr/CHANGELOG.md +5 -0
- package/extensions/nostr/package.json +1 -1
- package/extensions/open-prose/package.json +1 -1
- package/extensions/openai-codex-auth/package.json +1 -1
- package/extensions/signal/package.json +1 -1
- package/extensions/slack/package.json +1 -1
- package/extensions/telegram/package.json +1 -1
- package/extensions/tlon/package.json +1 -1
- package/extensions/twitch/CHANGELOG.md +5 -0
- package/extensions/twitch/package.json +1 -1
- package/extensions/voice-call/CHANGELOG.md +5 -0
- package/extensions/voice-call/package.json +1 -1
- package/extensions/whatsapp/package.json +1 -1
- package/extensions/zalo/CHANGELOG.md +5 -0
- package/extensions/zalo/package.json +1 -1
- package/extensions/zalouser/CHANGELOG.md +5 -0
- package/extensions/zalouser/package.json +1 -1
- package/package.json +1 -1
- package/skills/apple-reminders/SKILL.md +100 -49
- package/skills/coding-agent/SKILL.md +34 -28
- package/skills/github/SKILL.md +131 -16
- package/skills/imsg/SKILL.md +112 -15
- package/skills/openhue/SKILL.md +101 -19
- package/skills/tmux/SKILL.md +111 -79
- package/skills/weather/SKILL.md +88 -25
|
@@ -1,20 +1,60 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { resolveSessionTranscriptPath } from "../config/sessions.js";
|
|
4
|
+
import { resolveSessionFilePath, resolveSessionTranscriptPath, resolveSessionTranscriptPathInDir, } from "../config/sessions.js";
|
|
5
5
|
import { resolveRequiredHomeDir } from "../infra/home-dir.js";
|
|
6
|
+
import { hasInterSessionUserProvenance } from "../sessions/input-provenance.js";
|
|
6
7
|
import { extractToolCallNames, hasToolCall } from "../utils/transcript-tools.js";
|
|
7
8
|
import { stripEnvelope } from "./chat-sanitize.js";
|
|
9
|
+
const sessionTitleFieldsCache = new Map();
|
|
10
|
+
const MAX_SESSION_TITLE_FIELDS_CACHE_ENTRIES = 5000;
|
|
11
|
+
function readSessionTitleFieldsCacheKey(filePath, opts) {
|
|
12
|
+
const includeInterSession = opts?.includeInterSession === true ? "1" : "0";
|
|
13
|
+
return `${filePath}\t${includeInterSession}`;
|
|
14
|
+
}
|
|
15
|
+
function getCachedSessionTitleFields(cacheKey, stat) {
|
|
16
|
+
const cached = sessionTitleFieldsCache.get(cacheKey);
|
|
17
|
+
if (!cached) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (cached.mtimeMs !== stat.mtimeMs || cached.size !== stat.size) {
|
|
21
|
+
sessionTitleFieldsCache.delete(cacheKey);
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
// LRU bump
|
|
25
|
+
sessionTitleFieldsCache.delete(cacheKey);
|
|
26
|
+
sessionTitleFieldsCache.set(cacheKey, cached);
|
|
27
|
+
return {
|
|
28
|
+
firstUserMessage: cached.firstUserMessage,
|
|
29
|
+
lastMessagePreview: cached.lastMessagePreview,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function setCachedSessionTitleFields(cacheKey, stat, value) {
|
|
33
|
+
sessionTitleFieldsCache.set(cacheKey, {
|
|
34
|
+
...value,
|
|
35
|
+
mtimeMs: stat.mtimeMs,
|
|
36
|
+
size: stat.size,
|
|
37
|
+
});
|
|
38
|
+
while (sessionTitleFieldsCache.size > MAX_SESSION_TITLE_FIELDS_CACHE_ENTRIES) {
|
|
39
|
+
const oldestKey = sessionTitleFieldsCache.keys().next().value;
|
|
40
|
+
if (typeof oldestKey !== "string" || !oldestKey) {
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
sessionTitleFieldsCache.delete(oldestKey);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
8
46
|
export function readSessionMessages(sessionId, storePath, sessionFile) {
|
|
9
47
|
const candidates = resolveSessionTranscriptCandidates(sessionId, storePath, sessionFile);
|
|
10
48
|
const filePath = candidates.find((p) => fs.existsSync(p));
|
|
11
|
-
if (!filePath)
|
|
49
|
+
if (!filePath) {
|
|
12
50
|
return [];
|
|
51
|
+
}
|
|
13
52
|
const lines = fs.readFileSync(filePath, "utf-8").split(/\r?\n/);
|
|
14
53
|
const messages = [];
|
|
15
54
|
for (const line of lines) {
|
|
16
|
-
if (!line.trim())
|
|
55
|
+
if (!line.trim()) {
|
|
17
56
|
continue;
|
|
57
|
+
}
|
|
18
58
|
try {
|
|
19
59
|
const parsed = JSON.parse(line);
|
|
20
60
|
if (parsed?.message) {
|
|
@@ -45,18 +85,39 @@ export function readSessionMessages(sessionId, storePath, sessionFile) {
|
|
|
45
85
|
}
|
|
46
86
|
export function resolveSessionTranscriptCandidates(sessionId, storePath, sessionFile, agentId) {
|
|
47
87
|
const candidates = [];
|
|
48
|
-
|
|
49
|
-
|
|
88
|
+
const pushCandidate = (resolve) => {
|
|
89
|
+
try {
|
|
90
|
+
candidates.push(resolve());
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Ignore invalid paths/IDs and keep scanning other safe candidates.
|
|
94
|
+
}
|
|
95
|
+
};
|
|
50
96
|
if (storePath) {
|
|
51
|
-
const
|
|
52
|
-
|
|
97
|
+
const sessionsDir = path.dirname(storePath);
|
|
98
|
+
if (sessionFile) {
|
|
99
|
+
pushCandidate(() => resolveSessionFilePath(sessionId, { sessionFile }, { sessionsDir, agentId }));
|
|
100
|
+
}
|
|
101
|
+
pushCandidate(() => resolveSessionTranscriptPathInDir(sessionId, sessionsDir));
|
|
102
|
+
}
|
|
103
|
+
else if (sessionFile) {
|
|
104
|
+
if (agentId) {
|
|
105
|
+
pushCandidate(() => resolveSessionFilePath(sessionId, { sessionFile }, { agentId }));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const trimmed = sessionFile.trim();
|
|
109
|
+
if (trimmed) {
|
|
110
|
+
candidates.push(path.resolve(trimmed));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
53
113
|
}
|
|
54
114
|
if (agentId) {
|
|
55
|
-
|
|
115
|
+
pushCandidate(() => resolveSessionTranscriptPath(sessionId, agentId));
|
|
56
116
|
}
|
|
57
117
|
const home = resolveRequiredHomeDir(process.env, os.homedir);
|
|
58
|
-
|
|
59
|
-
|
|
118
|
+
const legacyDir = path.join(home, ".poolbot", "sessions");
|
|
119
|
+
pushCandidate(() => resolveSessionTranscriptPathInDir(sessionId, legacyDir));
|
|
120
|
+
return Array.from(new Set(candidates));
|
|
60
121
|
}
|
|
61
122
|
export function archiveFileOnDisk(filePath, reason) {
|
|
62
123
|
const ts = new Date().toISOString().replaceAll(":", "-");
|
|
@@ -64,6 +125,76 @@ export function archiveFileOnDisk(filePath, reason) {
|
|
|
64
125
|
fs.renameSync(filePath, archived);
|
|
65
126
|
return archived;
|
|
66
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Archives all transcript files for a given session.
|
|
130
|
+
* Best-effort: silently skips files that don't exist or fail to rename.
|
|
131
|
+
*/
|
|
132
|
+
export function archiveSessionTranscripts(opts) {
|
|
133
|
+
const archived = [];
|
|
134
|
+
for (const candidate of resolveSessionTranscriptCandidates(opts.sessionId, opts.storePath, opts.sessionFile, opts.agentId)) {
|
|
135
|
+
if (!fs.existsSync(candidate)) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
archived.push(archiveFileOnDisk(candidate, opts.reason));
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Best-effort.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return archived;
|
|
146
|
+
}
|
|
147
|
+
function restoreArchiveTimestamp(raw) {
|
|
148
|
+
const [datePart, timePart] = raw.split("T");
|
|
149
|
+
if (!datePart || !timePart) {
|
|
150
|
+
return raw;
|
|
151
|
+
}
|
|
152
|
+
return `${datePart}T${timePart.replace(/-/g, ":")}`;
|
|
153
|
+
}
|
|
154
|
+
function parseArchivedTimestamp(fileName, reason) {
|
|
155
|
+
const marker = `.${reason}.`;
|
|
156
|
+
const index = fileName.lastIndexOf(marker);
|
|
157
|
+
if (index < 0) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const raw = fileName.slice(index + marker.length);
|
|
161
|
+
if (!raw) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
const timestamp = Date.parse(restoreArchiveTimestamp(raw));
|
|
165
|
+
return Number.isNaN(timestamp) ? null : timestamp;
|
|
166
|
+
}
|
|
167
|
+
export async function cleanupArchivedSessionTranscripts(opts) {
|
|
168
|
+
if (!Number.isFinite(opts.olderThanMs) || opts.olderThanMs < 0) {
|
|
169
|
+
return { removed: 0, scanned: 0 };
|
|
170
|
+
}
|
|
171
|
+
const now = opts.nowMs ?? Date.now();
|
|
172
|
+
const reason = opts.reason ?? "deleted";
|
|
173
|
+
const directories = Array.from(new Set(opts.directories.map((dir) => path.resolve(dir))));
|
|
174
|
+
let removed = 0;
|
|
175
|
+
let scanned = 0;
|
|
176
|
+
for (const dir of directories) {
|
|
177
|
+
const entries = await fs.promises.readdir(dir).catch(() => []);
|
|
178
|
+
for (const entry of entries) {
|
|
179
|
+
const timestamp = parseArchivedTimestamp(entry, reason);
|
|
180
|
+
if (timestamp == null) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
scanned += 1;
|
|
184
|
+
if (now - timestamp <= opts.olderThanMs) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const fullPath = path.join(dir, entry);
|
|
188
|
+
const stat = await fs.promises.stat(fullPath).catch(() => null);
|
|
189
|
+
if (!stat?.isFile()) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
await fs.promises.rm(fullPath).catch(() => undefined);
|
|
193
|
+
removed += 1;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { removed, scanned };
|
|
197
|
+
}
|
|
67
198
|
function jsonUtf8Bytes(value) {
|
|
68
199
|
try {
|
|
69
200
|
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
@@ -73,8 +204,9 @@ function jsonUtf8Bytes(value) {
|
|
|
73
204
|
}
|
|
74
205
|
}
|
|
75
206
|
export function capArrayByJsonBytes(items, maxBytes) {
|
|
76
|
-
if (items.length === 0)
|
|
207
|
+
if (items.length === 0) {
|
|
77
208
|
return { items, bytes: 2 };
|
|
209
|
+
}
|
|
78
210
|
const parts = items.map((item) => jsonUtf8Bytes(item));
|
|
79
211
|
let bytes = 2 + parts.reduce((a, b) => a + b, 0) + (items.length - 1);
|
|
80
212
|
let start = 0;
|
|
@@ -86,113 +218,210 @@ export function capArrayByJsonBytes(items, maxBytes) {
|
|
|
86
218
|
return { items: next, bytes };
|
|
87
219
|
}
|
|
88
220
|
const MAX_LINES_TO_SCAN = 10;
|
|
221
|
+
export function readSessionTitleFieldsFromTranscript(sessionId, storePath, sessionFile, agentId, opts) {
|
|
222
|
+
const candidates = resolveSessionTranscriptCandidates(sessionId, storePath, sessionFile, agentId);
|
|
223
|
+
const filePath = candidates.find((p) => fs.existsSync(p));
|
|
224
|
+
if (!filePath) {
|
|
225
|
+
return { firstUserMessage: null, lastMessagePreview: null };
|
|
226
|
+
}
|
|
227
|
+
let stat;
|
|
228
|
+
try {
|
|
229
|
+
stat = fs.statSync(filePath);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return { firstUserMessage: null, lastMessagePreview: null };
|
|
233
|
+
}
|
|
234
|
+
const cacheKey = readSessionTitleFieldsCacheKey(filePath, opts);
|
|
235
|
+
const cached = getCachedSessionTitleFields(cacheKey, stat);
|
|
236
|
+
if (cached) {
|
|
237
|
+
return cached;
|
|
238
|
+
}
|
|
239
|
+
if (stat.size === 0) {
|
|
240
|
+
const empty = { firstUserMessage: null, lastMessagePreview: null };
|
|
241
|
+
setCachedSessionTitleFields(cacheKey, stat, empty);
|
|
242
|
+
return empty;
|
|
243
|
+
}
|
|
244
|
+
let fd = null;
|
|
245
|
+
try {
|
|
246
|
+
fd = fs.openSync(filePath, "r");
|
|
247
|
+
const size = stat.size;
|
|
248
|
+
// Head (first user message)
|
|
249
|
+
let firstUserMessage = null;
|
|
250
|
+
try {
|
|
251
|
+
const chunk = readTranscriptHeadChunk(fd);
|
|
252
|
+
if (chunk) {
|
|
253
|
+
firstUserMessage = extractFirstUserMessageFromTranscriptChunk(chunk, opts);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// ignore head read errors
|
|
258
|
+
}
|
|
259
|
+
// Tail (last message preview)
|
|
260
|
+
let lastMessagePreview = null;
|
|
261
|
+
try {
|
|
262
|
+
lastMessagePreview = readLastMessagePreviewFromOpenTranscript({ fd, size });
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// ignore tail read errors
|
|
266
|
+
}
|
|
267
|
+
const result = { firstUserMessage, lastMessagePreview };
|
|
268
|
+
setCachedSessionTitleFields(cacheKey, stat, result);
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return { firstUserMessage: null, lastMessagePreview: null };
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
if (fd !== null) {
|
|
276
|
+
try {
|
|
277
|
+
fs.closeSync(fd);
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
/* ignore */
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
89
285
|
function extractTextFromContent(content) {
|
|
90
|
-
if (typeof content === "string")
|
|
286
|
+
if (typeof content === "string") {
|
|
91
287
|
return content.trim() || null;
|
|
92
|
-
|
|
288
|
+
}
|
|
289
|
+
if (!Array.isArray(content)) {
|
|
93
290
|
return null;
|
|
291
|
+
}
|
|
94
292
|
for (const part of content) {
|
|
95
|
-
if (!part || typeof part.text !== "string")
|
|
293
|
+
if (!part || typeof part.text !== "string") {
|
|
96
294
|
continue;
|
|
295
|
+
}
|
|
97
296
|
if (part.type === "text" || part.type === "output_text" || part.type === "input_text") {
|
|
98
297
|
const trimmed = part.text.trim();
|
|
99
|
-
if (trimmed)
|
|
298
|
+
if (trimmed) {
|
|
100
299
|
return trimmed;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
function readTranscriptHeadChunk(fd, maxBytes = 8192) {
|
|
306
|
+
const buf = Buffer.alloc(maxBytes);
|
|
307
|
+
const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
|
|
308
|
+
if (bytesRead <= 0) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
return buf.toString("utf-8", 0, bytesRead);
|
|
312
|
+
}
|
|
313
|
+
function extractFirstUserMessageFromTranscriptChunk(chunk, opts) {
|
|
314
|
+
const lines = chunk.split(/\r?\n/).slice(0, MAX_LINES_TO_SCAN);
|
|
315
|
+
for (const line of lines) {
|
|
316
|
+
if (!line.trim()) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
const parsed = JSON.parse(line);
|
|
321
|
+
const msg = parsed?.message;
|
|
322
|
+
if (msg?.role !== "user") {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
if (opts?.includeInterSession !== true && hasInterSessionUserProvenance(msg)) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const text = extractTextFromContent(msg.content);
|
|
329
|
+
if (text) {
|
|
330
|
+
return text;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// skip malformed lines
|
|
101
335
|
}
|
|
102
336
|
}
|
|
103
337
|
return null;
|
|
104
338
|
}
|
|
105
|
-
export function readFirstUserMessageFromTranscript(sessionId, storePath, sessionFile, agentId) {
|
|
339
|
+
export function readFirstUserMessageFromTranscript(sessionId, storePath, sessionFile, agentId, opts) {
|
|
106
340
|
const candidates = resolveSessionTranscriptCandidates(sessionId, storePath, sessionFile, agentId);
|
|
107
341
|
const filePath = candidates.find((p) => fs.existsSync(p));
|
|
108
|
-
if (!filePath)
|
|
342
|
+
if (!filePath) {
|
|
109
343
|
return null;
|
|
344
|
+
}
|
|
110
345
|
let fd = null;
|
|
111
346
|
try {
|
|
112
347
|
fd = fs.openSync(filePath, "r");
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
if (bytesRead === 0)
|
|
348
|
+
const chunk = readTranscriptHeadChunk(fd);
|
|
349
|
+
if (!chunk) {
|
|
116
350
|
return null;
|
|
117
|
-
const chunk = buf.toString("utf-8", 0, bytesRead);
|
|
118
|
-
const lines = chunk.split(/\r?\n/).slice(0, MAX_LINES_TO_SCAN);
|
|
119
|
-
for (const line of lines) {
|
|
120
|
-
if (!line.trim())
|
|
121
|
-
continue;
|
|
122
|
-
try {
|
|
123
|
-
const parsed = JSON.parse(line);
|
|
124
|
-
const msg = parsed?.message;
|
|
125
|
-
if (msg?.role === "user") {
|
|
126
|
-
const text = extractTextFromContent(msg.content);
|
|
127
|
-
if (text)
|
|
128
|
-
return text;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch {
|
|
132
|
-
// skip malformed lines
|
|
133
|
-
}
|
|
134
351
|
}
|
|
352
|
+
return extractFirstUserMessageFromTranscriptChunk(chunk, opts);
|
|
135
353
|
}
|
|
136
354
|
catch {
|
|
137
355
|
// file read error
|
|
138
356
|
}
|
|
139
357
|
finally {
|
|
140
|
-
if (fd !== null)
|
|
358
|
+
if (fd !== null) {
|
|
141
359
|
fs.closeSync(fd);
|
|
360
|
+
}
|
|
142
361
|
}
|
|
143
362
|
return null;
|
|
144
363
|
}
|
|
145
364
|
const LAST_MSG_MAX_BYTES = 16384;
|
|
146
365
|
const LAST_MSG_MAX_LINES = 20;
|
|
366
|
+
function readLastMessagePreviewFromOpenTranscript(params) {
|
|
367
|
+
const readStart = Math.max(0, params.size - LAST_MSG_MAX_BYTES);
|
|
368
|
+
const readLen = Math.min(params.size, LAST_MSG_MAX_BYTES);
|
|
369
|
+
const buf = Buffer.alloc(readLen);
|
|
370
|
+
fs.readSync(params.fd, buf, 0, readLen, readStart);
|
|
371
|
+
const chunk = buf.toString("utf-8");
|
|
372
|
+
const lines = chunk.split(/\r?\n/).filter((l) => l.trim());
|
|
373
|
+
const tailLines = lines.slice(-LAST_MSG_MAX_LINES);
|
|
374
|
+
for (let i = tailLines.length - 1; i >= 0; i--) {
|
|
375
|
+
const line = tailLines[i];
|
|
376
|
+
try {
|
|
377
|
+
const parsed = JSON.parse(line);
|
|
378
|
+
const msg = parsed?.message;
|
|
379
|
+
if (msg?.role !== "user" && msg?.role !== "assistant") {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const text = extractTextFromContent(msg.content);
|
|
383
|
+
if (text) {
|
|
384
|
+
return text;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
// skip malformed
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
147
393
|
export function readLastMessagePreviewFromTranscript(sessionId, storePath, sessionFile, agentId) {
|
|
148
394
|
const candidates = resolveSessionTranscriptCandidates(sessionId, storePath, sessionFile, agentId);
|
|
149
395
|
const filePath = candidates.find((p) => fs.existsSync(p));
|
|
150
|
-
if (!filePath)
|
|
396
|
+
if (!filePath) {
|
|
151
397
|
return null;
|
|
398
|
+
}
|
|
152
399
|
let fd = null;
|
|
153
400
|
try {
|
|
154
401
|
fd = fs.openSync(filePath, "r");
|
|
155
402
|
const stat = fs.fstatSync(fd);
|
|
156
403
|
const size = stat.size;
|
|
157
|
-
if (size === 0)
|
|
404
|
+
if (size === 0) {
|
|
158
405
|
return null;
|
|
159
|
-
const readStart = Math.max(0, size - LAST_MSG_MAX_BYTES);
|
|
160
|
-
const readLen = Math.min(size, LAST_MSG_MAX_BYTES);
|
|
161
|
-
const buf = Buffer.alloc(readLen);
|
|
162
|
-
fs.readSync(fd, buf, 0, readLen, readStart);
|
|
163
|
-
const chunk = buf.toString("utf-8");
|
|
164
|
-
const lines = chunk.split(/\r?\n/).filter((l) => l.trim());
|
|
165
|
-
const tailLines = lines.slice(-LAST_MSG_MAX_LINES);
|
|
166
|
-
for (let i = tailLines.length - 1; i >= 0; i--) {
|
|
167
|
-
const line = tailLines[i];
|
|
168
|
-
try {
|
|
169
|
-
const parsed = JSON.parse(line);
|
|
170
|
-
const msg = parsed?.message;
|
|
171
|
-
if (msg?.role === "user" || msg?.role === "assistant") {
|
|
172
|
-
const text = extractTextFromContent(msg.content);
|
|
173
|
-
if (text)
|
|
174
|
-
return text;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
catch {
|
|
178
|
-
// skip malformed
|
|
179
|
-
}
|
|
180
406
|
}
|
|
407
|
+
return readLastMessagePreviewFromOpenTranscript({ fd, size });
|
|
181
408
|
}
|
|
182
409
|
catch {
|
|
183
410
|
// file error
|
|
184
411
|
}
|
|
185
412
|
finally {
|
|
186
|
-
if (fd !== null)
|
|
413
|
+
if (fd !== null) {
|
|
187
414
|
fs.closeSync(fd);
|
|
415
|
+
}
|
|
188
416
|
}
|
|
189
417
|
return null;
|
|
190
418
|
}
|
|
191
419
|
const PREVIEW_READ_SIZES = [64 * 1024, 256 * 1024, 1024 * 1024];
|
|
192
420
|
const PREVIEW_MAX_LINES = 200;
|
|
193
421
|
function normalizeRole(role, isTool) {
|
|
194
|
-
if (isTool)
|
|
422
|
+
if (isTool) {
|
|
195
423
|
return "tool";
|
|
424
|
+
}
|
|
196
425
|
switch ((role ?? "").toLowerCase()) {
|
|
197
426
|
case "user":
|
|
198
427
|
return "user";
|
|
@@ -207,10 +436,12 @@ function normalizeRole(role, isTool) {
|
|
|
207
436
|
}
|
|
208
437
|
}
|
|
209
438
|
function truncatePreviewText(text, maxChars) {
|
|
210
|
-
if (maxChars <= 0 || text.length <= maxChars)
|
|
439
|
+
if (maxChars <= 0 || text.length <= maxChars) {
|
|
211
440
|
return text;
|
|
212
|
-
|
|
441
|
+
}
|
|
442
|
+
if (maxChars <= 3) {
|
|
213
443
|
return text.slice(0, maxChars);
|
|
444
|
+
}
|
|
214
445
|
return `${text.slice(0, maxChars - 3)}...`;
|
|
215
446
|
}
|
|
216
447
|
function extractPreviewText(message) {
|
|
@@ -239,12 +470,14 @@ function extractToolNames(message) {
|
|
|
239
470
|
return extractToolCallNames(message);
|
|
240
471
|
}
|
|
241
472
|
function extractMediaSummary(message) {
|
|
242
|
-
if (!Array.isArray(message.content))
|
|
473
|
+
if (!Array.isArray(message.content)) {
|
|
243
474
|
return null;
|
|
475
|
+
}
|
|
244
476
|
for (const entry of message.content) {
|
|
245
477
|
const raw = typeof entry?.type === "string" ? entry.type.trim().toLowerCase() : "";
|
|
246
|
-
if (!raw || raw === "text" || raw === "toolcall" || raw === "tool_call")
|
|
478
|
+
if (!raw || raw === "text" || raw === "toolcall" || raw === "tool_call") {
|
|
247
479
|
continue;
|
|
480
|
+
}
|
|
248
481
|
return `[${raw}]`;
|
|
249
482
|
}
|
|
250
483
|
return null;
|
|
@@ -261,26 +494,30 @@ function buildPreviewItems(messages, maxItems, maxChars) {
|
|
|
261
494
|
const shown = toolNames.slice(0, 2);
|
|
262
495
|
const overflow = toolNames.length - shown.length;
|
|
263
496
|
text = `call ${shown.join(", ")}`;
|
|
264
|
-
if (overflow > 0)
|
|
497
|
+
if (overflow > 0) {
|
|
265
498
|
text += ` +${overflow}`;
|
|
499
|
+
}
|
|
266
500
|
}
|
|
267
501
|
}
|
|
268
502
|
if (!text) {
|
|
269
503
|
text = extractMediaSummary(message);
|
|
270
504
|
}
|
|
271
|
-
if (!text)
|
|
505
|
+
if (!text) {
|
|
272
506
|
continue;
|
|
507
|
+
}
|
|
273
508
|
let trimmed = text.trim();
|
|
274
|
-
if (!trimmed)
|
|
509
|
+
if (!trimmed) {
|
|
275
510
|
continue;
|
|
511
|
+
}
|
|
276
512
|
if (role === "user") {
|
|
277
513
|
trimmed = stripEnvelope(trimmed);
|
|
278
514
|
}
|
|
279
515
|
trimmed = truncatePreviewText(trimmed, maxChars);
|
|
280
516
|
items.push({ role, text: trimmed });
|
|
281
517
|
}
|
|
282
|
-
if (items.length <= maxItems)
|
|
518
|
+
if (items.length <= maxItems) {
|
|
283
519
|
return items;
|
|
520
|
+
}
|
|
284
521
|
return items.slice(-maxItems);
|
|
285
522
|
}
|
|
286
523
|
function readRecentMessagesFromTranscript(filePath, maxMessages, readBytes) {
|
|
@@ -289,8 +526,9 @@ function readRecentMessagesFromTranscript(filePath, maxMessages, readBytes) {
|
|
|
289
526
|
fd = fs.openSync(filePath, "r");
|
|
290
527
|
const stat = fs.fstatSync(fd);
|
|
291
528
|
const size = stat.size;
|
|
292
|
-
if (size === 0)
|
|
529
|
+
if (size === 0) {
|
|
293
530
|
return [];
|
|
531
|
+
}
|
|
294
532
|
const readStart = Math.max(0, size - readBytes);
|
|
295
533
|
const readLen = Math.min(size, readBytes);
|
|
296
534
|
const buf = Buffer.alloc(readLen);
|
|
@@ -306,8 +544,9 @@ function readRecentMessagesFromTranscript(filePath, maxMessages, readBytes) {
|
|
|
306
544
|
const msg = parsed?.message;
|
|
307
545
|
if (msg && typeof msg === "object") {
|
|
308
546
|
collected.push(msg);
|
|
309
|
-
if (collected.length >= maxMessages)
|
|
547
|
+
if (collected.length >= maxMessages) {
|
|
310
548
|
break;
|
|
549
|
+
}
|
|
311
550
|
}
|
|
312
551
|
}
|
|
313
552
|
catch {
|
|
@@ -320,15 +559,17 @@ function readRecentMessagesFromTranscript(filePath, maxMessages, readBytes) {
|
|
|
320
559
|
return [];
|
|
321
560
|
}
|
|
322
561
|
finally {
|
|
323
|
-
if (fd !== null)
|
|
562
|
+
if (fd !== null) {
|
|
324
563
|
fs.closeSync(fd);
|
|
564
|
+
}
|
|
325
565
|
}
|
|
326
566
|
}
|
|
327
567
|
export function readSessionPreviewItemsFromTranscript(sessionId, storePath, sessionFile, agentId, maxItems, maxChars) {
|
|
328
568
|
const candidates = resolveSessionTranscriptCandidates(sessionId, storePath, sessionFile, agentId);
|
|
329
569
|
const filePath = candidates.find((p) => fs.existsSync(p));
|
|
330
|
-
if (!filePath)
|
|
570
|
+
if (!filePath) {
|
|
331
571
|
return [];
|
|
572
|
+
}
|
|
332
573
|
const boundedItems = Math.max(1, Math.min(maxItems, 50));
|
|
333
574
|
const boundedChars = Math.max(20, Math.min(maxChars, 2000));
|
|
334
575
|
for (const readSize of PREVIEW_READ_SIZES) {
|