@xopcai/xopc 0.0.94 → 0.0.96
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agents-OqhbJkMf.js → agents-DmIuSaOE.js} +3 -3
- package/dist/gateway/static/root/assets/{apps-page-OHXW9XP8.js → apps-page-DFcHBxLw.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-4N2R-jof.js → channels-settings-DDUf55C5.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-Bv6f9kDq.js → channels-status-swr-BxF-_nzD.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-BtaQaHJq.js → cron-api-DylQtnb_.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-Dah32HJK.js → cron-page-BO0d9Pf-.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-BJfD9Qvs.js → dist-BskF0qDS.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DnYuMzmH.js → extension-debug-page-BcZdTdjJ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CJfc-6XV.js → extension-page-D2iuDa1D.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-BxdfYQMG.js → extension-settings-page-BKpQCgLc.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B0aeeY0q.js → fetch-CtNDpjij.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-DOLHwowi.js → field-primitives-2PekrGZF.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-Bj2INAf5.js → heartbeat-config-api-D3D7SW8A.js} +1 -1
- package/dist/gateway/static/root/assets/index-BvEhL9RQ.css +1 -0
- package/dist/gateway/static/root/assets/{index-DuQ1XPoA.js → index-Db9fd_X4.js} +74 -74
- package/dist/gateway/static/root/assets/{logs-page-AsOgLNJE.js → logs-page-B3I1a26m.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-24J4mVP-.js → note-detail-page-BOizhtJ8.js} +54 -53
- package/dist/gateway/static/root/assets/{note-detail-page-B91pLkEI.css → note-detail-page-D4ZIVQbk.css} +1 -1
- package/dist/gateway/static/root/assets/{note-time-JBszYV3s.js → note-time-CjUGtqKr.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-BB8-I0Of.js +1 -0
- package/dist/gateway/static/root/assets/{sessions-page-DX9huWsA.js → sessions-page-BcH-1K9i.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DWvhsTuz.js → settings-advanced-gate-Czn8nnjN.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-form-section-CxMjaMiy.js → settings-form-section-ZZWDwgVe.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-BX8c_zrN.js +3 -0
- package/dist/gateway/static/root/assets/share-preview-page-Ch3_6Qah.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page-CGKGKfwe.js → skills-page-WO0bbJ54.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-Cg_SuBw0.js → theme-store-XxRFRZDX.js} +1 -1
- package/dist/gateway/static/root/assets/url-6zpynn1R.js +3 -0
- package/dist/gateway/static/root/assets/{utils-BmlcxR2j.js → utils-uTYKh54l.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-DaGm2N4J.js → voice-api-key-field-BIAYHRs-.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-D0vsIGHD.js → workflow-page.utils-BbWhqD36.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-BFCrD3nw.js → workflows-page-D4RIF7E1.js} +2 -2
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +15 -9
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.d.ts +0 -1
- package/dist/src/agent/agent-scope.js +2 -5
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +3 -0
- package/dist/src/agent/bootstrap/bootstrap-cache.js +13 -3
- package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-files.d.ts +6 -0
- package/dist/src/agent/bootstrap/bootstrap-files.js +35 -12
- package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +5 -2
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +12 -3
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/context/workspace-seed.js +8 -4
- package/dist/src/agent/context/workspace-seed.js.map +1 -1
- package/dist/src/agent/context/workspace-state.d.ts +52 -0
- package/dist/src/agent/context/workspace-state.js +101 -0
- package/dist/src/agent/context/workspace-state.js.map +1 -0
- package/dist/src/agent/embedded/index.d.ts +2 -2
- package/dist/src/agent/embedded/index.js +3 -3
- package/dist/src/agent/embedded/run-turn.js +0 -3
- package/dist/src/agent/embedded/run-turn.js.map +1 -1
- package/dist/src/agent/embedded/session-manager-init.d.ts +0 -17
- package/dist/src/agent/embedded/session-manager-init.js +1 -36
- package/dist/src/agent/embedded/session-manager-init.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.d.ts +3 -12
- package/dist/src/agent/embedded/session-runner.js +12 -26
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -4
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/embedded/sqlite-hydrating-session-manager.d.ts +10 -0
- package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js +34 -0
- package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js.map +1 -0
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +8 -15
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -2
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/memory/index.d.ts +1 -0
- package/dist/src/agent/prompt/memory/index.js +34 -80
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js +8 -17
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +14 -23
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.js +7 -11
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +3 -3
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +1 -2
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/session-search-tool.d.ts +0 -1
- package/dist/src/agent/tools/session-search-tool.js +11 -6
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +32 -95
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +5 -7
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +7 -8
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.d.ts +3 -0
- package/dist/src/config/paths-state.js +7 -3
- package/dist/src/config/paths-state.js.map +1 -1
- package/dist/src/config/paths.d.ts +5 -35
- package/dist/src/config/paths.js +6 -50
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +15 -0
- package/dist/src/config/schema.js +11 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/execution-types.d.ts +42 -0
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.d.ts +4 -8
- package/dist/src/cron/run-log-store.js +26 -78
- package/dist/src/cron/run-log-store.js.map +1 -1
- package/dist/src/cron/service.d.ts +3 -3
- package/dist/src/cron/service.js +2 -2
- package/dist/src/cron/service.js.map +1 -1
- package/dist/src/cron/types.d.ts +1 -42
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +8 -3
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/file-path-classifier.d.ts +0 -1
- package/dist/src/gateway/file-path-classifier.js +2 -8
- package/dist/src/gateway/file-path-classifier.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.js +5 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/session-reset-service.d.ts +1 -1
- package/dist/src/gateway/session-reset-service.js +1 -1
- package/dist/src/gateway/session-reset-service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/node-sqlite.d.ts +1 -0
- package/dist/src/infra/node-sqlite.js +17 -0
- package/dist/src/infra/node-sqlite.js.map +1 -0
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/sqlite-errors.d.ts +1 -0
- package/dist/src/infra/sqlite-errors.js +77 -0
- package/dist/src/infra/sqlite-errors.js.map +1 -0
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/unhandled-rejections.d.ts +1 -0
- package/dist/src/infra/unhandled-rejections.js +25 -0
- package/dist/src/infra/unhandled-rejections.js.map +1 -0
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/warning-filter.d.ts +7 -0
- package/dist/src/infra/warning-filter.js +59 -0
- package/dist/src/infra/warning-filter.js.map +1 -0
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/notes/store.d.ts +3 -9
- package/dist/src/notes/store.js +22 -196
- package/dist/src/notes/store.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.d.ts +6 -75
- package/dist/src/session/config-store.js +38 -144
- package/dist/src/session/config-store.js.map +1 -1
- package/dist/src/session/config-types.d.ts +15 -0
- package/dist/src/session/config-types.js +1 -0
- package/dist/src/session/index.d.ts +1 -3
- package/dist/src/session/index.js +3 -5
- package/dist/src/session/init-session-turn.d.ts +0 -6
- package/dist/src/session/init-session-turn.js +18 -18
- package/dist/src/session/init-session-turn.js.map +1 -1
- package/dist/src/session/lifecycle-timestamps.d.ts +5 -2
- package/dist/src/session/lifecycle-timestamps.js.map +1 -1
- package/dist/src/session/{parity/load-jsonl-entries.js → load-jsonl-entries.js} +1 -1
- package/dist/src/session/load-jsonl-entries.js.map +1 -0
- package/dist/src/session/manager.d.ts +5 -3
- package/dist/src/session/manager.js +1 -5
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/resolve-session.d.ts +3 -6
- package/dist/src/session/resolve-session.js +26 -31
- package/dist/src/session/resolve-session.js.map +1 -1
- package/dist/src/session/session-context-for-llm.js +5 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/session-id.js +12 -0
- package/dist/src/session/session-id.js.map +1 -0
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/session-workspace.d.ts +1 -1
- package/dist/src/session/session-workspace.js.map +1 -1
- package/dist/src/session/store.d.ts +14 -63
- package/dist/src/session/store.js +172 -847
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/stored-rows-to-file-entries.d.ts +11 -0
- package/dist/src/session/stored-rows-to-file-entries.js +95 -0
- package/dist/src/session/stored-rows-to-file-entries.js.map +1 -0
- package/dist/src/session/transcript-events.d.ts +1 -2
- package/dist/src/session/transcript-events.js +5 -12
- package/dist/src/session/transcript-events.js.map +1 -1
- package/dist/src/session/transcript-format.d.ts +1 -1
- package/dist/src/session/transcript-format.js.map +1 -1
- package/dist/src/session/transcript-stats.d.ts +1 -0
- package/dist/src/session/transcript-stats.js +10 -0
- package/dist/src/session/transcript-stats.js.map +1 -0
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/config-repository.d.ts +6 -0
- package/dist/src/storage/sqlite/config-repository.js +56 -0
- package/dist/src/storage/sqlite/config-repository.js.map +1 -0
- package/dist/src/storage/sqlite/connection.d.ts +38 -0
- package/dist/src/storage/sqlite/connection.js +258 -0
- package/dist/src/storage/sqlite/connection.js.map +1 -0
- package/dist/src/storage/sqlite/cron-run-repository.d.ts +5 -0
- package/dist/src/storage/sqlite/cron-run-repository.js +97 -0
- package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -0
- package/dist/src/storage/sqlite/fts.d.ts +2 -0
- package/dist/src/storage/sqlite/fts.js +11 -0
- package/dist/src/storage/sqlite/fts.js.map +1 -0
- package/dist/src/storage/sqlite/index.d.ts +12 -0
- package/dist/src/storage/sqlite/index.js +13 -0
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +18 -0
- package/dist/src/storage/sqlite/memory-index-repository.js +132 -0
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -0
- package/dist/src/storage/sqlite/notes-repository.d.ts +11 -0
- package/dist/src/storage/sqlite/notes-repository.js +191 -0
- package/dist/src/storage/sqlite/notes-repository.js.map +1 -0
- package/dist/src/storage/sqlite/paths.d.ts +1 -0
- package/dist/src/storage/sqlite/paths.js +7 -0
- package/dist/src/storage/sqlite/paths.js.map +1 -0
- package/dist/src/storage/sqlite/row-mappers.d.ts +82 -0
- package/dist/src/storage/sqlite/row-mappers.js +164 -0
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -0
- package/dist/src/storage/sqlite/schema.d.ts +5 -0
- package/dist/src/storage/sqlite/schema.js +43 -0
- package/dist/src/storage/sqlite/schema.js.map +1 -0
- package/dist/src/storage/sqlite/schema.sql +195 -0
- package/dist/src/storage/sqlite/session-metadata.d.ts +8 -0
- package/dist/src/storage/sqlite/session-metadata.js +83 -0
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -0
- package/dist/src/storage/sqlite/session-repository.d.ts +29 -0
- package/dist/src/storage/sqlite/session-repository.js +268 -0
- package/dist/src/storage/sqlite/session-repository.js.map +1 -0
- package/dist/src/storage/sqlite/transaction.d.ts +11 -0
- package/dist/src/storage/sqlite/transaction.js +115 -0
- package/dist/src/storage/sqlite/transaction.js.map +1 -0
- package/dist/src/storage/sqlite/transcript-repository.d.ts +34 -0
- package/dist/src/storage/sqlite/transcript-repository.js +241 -0
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -0
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +3 -3
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/service/workflow-session-bridge.js +41 -64
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/index-Bj_l8QDp.css +0 -1
- package/dist/gateway/static/root/assets/notes-page-BApAirFB.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-4VmUTzQs.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-IX0TJvRd.js +0 -2
- package/dist/gateway/static/root/assets/url-BHHmdJYc.js +0 -3
- package/dist/src/agent/embedded/session-manager-cache.d.ts +0 -19
- package/dist/src/agent/embedded/session-manager-cache.js +0 -48
- package/dist/src/agent/embedded/session-manager-cache.js.map +0 -1
- package/dist/src/session/parity/artifacts.d.ts +0 -16
- package/dist/src/session/parity/artifacts.js +0 -80
- package/dist/src/session/parity/artifacts.js.map +0 -1
- package/dist/src/session/parity/jsonl-transcript-io.d.ts +0 -54
- package/dist/src/session/parity/jsonl-transcript-io.js +0 -236
- package/dist/src/session/parity/jsonl-transcript-io.js.map +0 -1
- package/dist/src/session/parity/load-jsonl-entries.js.map +0 -1
- package/dist/src/session/parity/session-id.js +0 -18
- package/dist/src/session/parity/session-id.js.map +0 -1
- package/dist/src/session/parity/sessions-json-cache.d.ts +0 -14
- package/dist/src/session/parity/sessions-json-cache.js +0 -98
- package/dist/src/session/parity/sessions-json-cache.js.map +0 -1
- package/dist/src/session/parity/sessions-json-file-read.d.ts +0 -6
- package/dist/src/session/parity/sessions-json-file-read.js +0 -19
- package/dist/src/session/parity/sessions-json-file-read.js.map +0 -1
- package/dist/src/session/parity/sessions-json-file.d.ts +0 -11
- package/dist/src/session/parity/sessions-json-file.js +0 -52
- package/dist/src/session/parity/sessions-json-file.js.map +0 -1
- package/dist/src/session/parity/sessions-json-patch.d.ts +0 -14
- package/dist/src/session/parity/sessions-json-patch.js +0 -40
- package/dist/src/session/parity/sessions-json-patch.js.map +0 -1
- package/dist/src/session/parity/transcript-file-lock.d.ts +0 -22
- package/dist/src/session/parity/transcript-file-lock.js +0 -142
- package/dist/src/session/parity/transcript-file-lock.js.map +0 -1
- package/dist/src/session/parity/transcript-pagination.d.ts +0 -29
- package/dist/src/session/parity/transcript-pagination.js +0 -132
- package/dist/src/session/parity/transcript-pagination.js.map +0 -1
- package/dist/src/session/parity/transcript-paths.d.ts +0 -13
- package/dist/src/session/parity/transcript-paths.js +0 -64
- package/dist/src/session/parity/transcript-paths.js.map +0 -1
- package/dist/src/session/parity/xopc-session-disk-entry.d.ts +0 -22
- package/dist/src/session/search-index-cache.d.ts +0 -6
- package/dist/src/session/search-index-cache.js +0 -44
- package/dist/src/session/search-index-cache.js.map +0 -1
- package/dist/src/session/search-index.d.ts +0 -20
- package/dist/src/session/search-index.js +0 -124
- package/dist/src/session/search-index.js.map +0 -1
- /package/dist/src/{session/parity/xopc-session-disk-entry.js → cron/execution-types.js} +0 -0
- /package/dist/src/session/{parity/load-jsonl-entries.d.ts → load-jsonl-entries.d.ts} +0 -0
- /package/dist/src/session/{parity/session-id.d.ts → session-id.d.ts} +0 -0
|
@@ -1,415 +1,85 @@
|
|
|
1
|
-
import { resolveStateDir } from "../config/paths-state.js";
|
|
2
|
-
import { init_agent_scope, listAgentEntries, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
3
|
-
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
4
|
-
import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
|
|
5
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
6
2
|
import { init_logger } from "../utils/logger.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
3
|
+
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
4
|
+
import { resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
|
|
5
|
+
import { requireXopcDatabase } from "../storage/sqlite/connection.js";
|
|
6
|
+
import "./types.js";
|
|
7
|
+
import { buildSessionContextForLlm, mergeLlmMessagesPreservingContextRows } from "./session-context-for-llm.js";
|
|
8
|
+
import { estimateTokensFromMessages } from "../storage/sqlite/row-mappers.js";
|
|
9
|
+
import { deleteSessionRecord, ensureSessionRecord, getGlobalSessionStats, getSessionMetadata, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord } from "../storage/sqlite/session-repository.js";
|
|
10
|
+
import { appendTranscriptEntry, captureCompactionCheckpoint, getCompactionCheckpointDetail, listCompactionCheckpoints, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRowsForSession, replaceTranscriptRows, restoreCompactionCheckpoint } from "../storage/sqlite/transcript-repository.js";
|
|
11
|
+
import "../storage/sqlite/index.js";
|
|
15
12
|
import { readPostCompactionContext } from "../agent/reply/post-compaction-context.js";
|
|
16
13
|
import { SessionCompactor } from "../agent/memory/compaction.js";
|
|
17
14
|
import { SlidingWindow } from "../agent/memory/window.js";
|
|
18
15
|
import { normalizeCompactionCheckpointId } from "./compaction-checkpoints.js";
|
|
19
|
-
import "./
|
|
20
|
-
import { readSessionsJsonFile, withSessionsJsonLock } from "./parity/sessions-json-file.js";
|
|
21
|
-
import { buildSessionsJsonStatsPatch, incrementSessionsJsonStatsForAppend, isAppendOnlyLlmTranscriptMessage, patchSessionsJsonEntryStats } from "./parity/sessions-json-patch.js";
|
|
22
|
-
import { countTranscriptMessageRows, readDisplayMessagePageFromTranscriptFile } from "./parity/transcript-pagination.js";
|
|
23
|
-
import { join } from "path";
|
|
24
|
-
import { existsSync } from "fs";
|
|
25
|
-
import { copyFile, mkdir, readdir, stat, unlink } from "fs/promises";
|
|
26
|
-
import { randomUUID } from "node:crypto";
|
|
27
|
-
import { performance } from "node:perf_hooks";
|
|
16
|
+
import { isAppendOnlyLlmTranscriptMessage } from "./transcript-stats.js";
|
|
28
17
|
//#region src/session/store.ts
|
|
29
|
-
|
|
30
|
-
init_agent_scope();
|
|
31
|
-
init_session_key();
|
|
18
|
+
init_paths_state();
|
|
32
19
|
init_logger();
|
|
33
|
-
init_artifacts();
|
|
34
|
-
init_transcript_paths();
|
|
35
|
-
init_session_id();
|
|
36
20
|
const log = createLogger("SessionStore");
|
|
37
21
|
const INDEX_VERSION = "1.0";
|
|
38
|
-
const DELETED_MARKER = ".jsonl.deleted.";
|
|
39
|
-
const ALL_SESSIONS_MAP_CACHE_TTL_MS = 2e3;
|
|
40
22
|
var SessionStore = class {
|
|
41
|
-
sessionsDir;
|
|
42
|
-
archiveDir;
|
|
43
|
-
storePath;
|
|
44
23
|
window;
|
|
45
24
|
compactor;
|
|
46
|
-
storeMutationDepth = 0;
|
|
47
|
-
storeMutationChain = Promise.resolve();
|
|
48
|
-
allSessionsMapCache;
|
|
49
|
-
/** Cache of per-agent sessions dirs to avoid re-resolution on every call. */
|
|
50
|
-
agentSessionsDirCache = /* @__PURE__ */ new Map();
|
|
51
25
|
constructor(options, windowConfig, compactionConfig) {
|
|
52
26
|
this.options = options;
|
|
53
|
-
const agentId = options.agentId ?? resolveDefaultAgentId(options.config);
|
|
54
|
-
this.sessionsDir = options.sessionsDir ?? resolveSessionsDir(options.config, agentId);
|
|
55
|
-
this.archiveDir = join(this.sessionsDir, "archive");
|
|
56
|
-
this.storePath = join(this.sessionsDir, FILENAMES.SESSIONS_MAP);
|
|
57
27
|
this.window = new SlidingWindow(windowConfig);
|
|
58
28
|
this.compactor = new SessionCompactor(compactionConfig);
|
|
59
29
|
}
|
|
60
|
-
|
|
61
|
-
return this.
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* OpenClaw-aligned: resolve the sessions directory for a given session key.
|
|
65
|
-
* Extracts agentId from the session key and routes to `agents/<agentId>/sessions/`.
|
|
66
|
-
* Falls back to the default sessions directory when agentId cannot be parsed
|
|
67
|
-
* or when `sessionsDir` was explicitly provided in options.
|
|
68
|
-
*/
|
|
69
|
-
resolveSessionsDirForKey(sessionKey) {
|
|
70
|
-
if (this.options.sessionsDir) return this.sessionsDir;
|
|
71
|
-
const parsed = parseSessionKey(sessionKey);
|
|
72
|
-
if (!parsed) return this.sessionsDir;
|
|
73
|
-
const agentId = parsed.agentId;
|
|
74
|
-
const cached = this.agentSessionsDirCache.get(agentId);
|
|
75
|
-
if (cached) return cached;
|
|
76
|
-
const resolved = resolveSessionsDir(this.options.config, agentId);
|
|
77
|
-
this.agentSessionsDirCache.set(agentId, resolved);
|
|
78
|
-
return resolved;
|
|
79
|
-
}
|
|
80
|
-
resolveStorePathForKey(sessionKey) {
|
|
81
|
-
return join(this.resolveSessionsDirForKey(sessionKey), FILENAMES.SESSIONS_MAP);
|
|
30
|
+
resolveWorkspaceCwd(sessionKey) {
|
|
31
|
+
return resolveEffectiveAgentProfileForSession(this.options.config, sessionKey).resolvedWorkspacePath;
|
|
82
32
|
}
|
|
83
33
|
async runStoreMutation(fn) {
|
|
84
|
-
|
|
85
|
-
const run = this.storeMutationChain.then(async () => {
|
|
86
|
-
this.storeMutationDepth++;
|
|
87
|
-
try {
|
|
88
|
-
return await fn();
|
|
89
|
-
} finally {
|
|
90
|
-
this.storeMutationDepth--;
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
this.storeMutationChain = run.then(() => void 0).catch(() => void 0);
|
|
94
|
-
return run;
|
|
34
|
+
return fn();
|
|
95
35
|
}
|
|
96
36
|
async initialize() {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (!existsSync(this.storePath)) await withSessionsJsonLock(this.storePath, async () => void 0);
|
|
100
|
-
log.debug("Session store initialized (sessions.json + JSONL)");
|
|
101
|
-
}
|
|
102
|
-
transcriptPathForEntry(entry, sessionsDir) {
|
|
103
|
-
return resolveSessionFilePath(entry.sessionId, entry, { sessionsDir: sessionsDir ?? this.sessionsDir });
|
|
104
|
-
}
|
|
105
|
-
async readMapForKey(sessionKey) {
|
|
106
|
-
return readSessionsJsonFile(this.resolveStorePathForKey(sessionKey));
|
|
107
|
-
}
|
|
108
|
-
async readMap() {
|
|
109
|
-
return readSessionsJsonFile(this.storePath);
|
|
110
|
-
}
|
|
111
|
-
invalidateAllSessionsMapCache() {
|
|
112
|
-
this.allSessionsMapCache = void 0;
|
|
113
|
-
}
|
|
114
|
-
async discoverSessionMapPaths() {
|
|
115
|
-
const agents = listAgentEntries(this.options.config);
|
|
116
|
-
const defaultId = resolveDefaultAgentId(this.options.config);
|
|
117
|
-
const agentIds = new Set([defaultId, ...agents.map((agent) => agent.id)]);
|
|
118
|
-
const agentsRoot = join(resolveStateDir(process.env), "agents");
|
|
119
|
-
if (existsSync(agentsRoot)) {
|
|
120
|
-
const entries = await readdir(agentsRoot, { withFileTypes: true }).catch(() => []);
|
|
121
|
-
for (const entry of entries) if (entry.isDirectory()) agentIds.add(entry.name);
|
|
122
|
-
}
|
|
123
|
-
return [...agentIds].map((agentId) => ({
|
|
124
|
-
agentId,
|
|
125
|
-
mapPath: join(resolveSessionsDir(this.options.config, agentId), FILENAMES.SESSIONS_MAP)
|
|
126
|
-
}));
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Unified cross-agent aggregation entry for global session views.
|
|
130
|
-
* Reads configured agents plus existing per-agent session maps under the state directory.
|
|
131
|
-
*/
|
|
132
|
-
async readAllMaps() {
|
|
133
|
-
if (this.options.sessionsDir) return this.readMap();
|
|
134
|
-
const nowMs = Date.now();
|
|
135
|
-
if (this.allSessionsMapCache && this.allSessionsMapCache.expiresAtMs > nowMs) {
|
|
136
|
-
log.debug({ sessionCount: Object.keys(this.allSessionsMapCache.map).length }, "All session maps cache hit");
|
|
137
|
-
return this.allSessionsMapCache.map;
|
|
138
|
-
}
|
|
139
|
-
const startedAt = performance.now();
|
|
140
|
-
const paths = await this.discoverSessionMapPaths();
|
|
141
|
-
const merged = {};
|
|
142
|
-
let scannedMapCount = 0;
|
|
143
|
-
for (const { mapPath } of paths) {
|
|
144
|
-
if (!existsSync(mapPath)) continue;
|
|
145
|
-
const map = await readSessionsJsonFile(mapPath);
|
|
146
|
-
Object.assign(merged, map);
|
|
147
|
-
scannedMapCount++;
|
|
148
|
-
}
|
|
149
|
-
this.allSessionsMapCache = {
|
|
150
|
-
expiresAtMs: nowMs + ALL_SESSIONS_MAP_CACHE_TTL_MS,
|
|
151
|
-
map: merged
|
|
152
|
-
};
|
|
153
|
-
log.debug({
|
|
154
|
-
candidateAgentCount: paths.length,
|
|
155
|
-
scannedMapCount,
|
|
156
|
-
sessionCount: Object.keys(merged).length,
|
|
157
|
-
durationMs: Math.round(performance.now() - startedAt)
|
|
158
|
-
}, "All session maps scanned");
|
|
159
|
-
return merged;
|
|
160
|
-
}
|
|
161
|
-
async getDiskEntry(sessionKey) {
|
|
162
|
-
return (await this.readMapForKey(sessionKey))[sessionKey];
|
|
163
|
-
}
|
|
164
|
-
buildDefaultMetadata(key) {
|
|
165
|
-
const { channel, chatId } = this.parseSessionKey(key);
|
|
166
|
-
const routing = this.extractRoutingFromKey(key);
|
|
167
|
-
const isCronSession = channel === "cron";
|
|
168
|
-
const isHeartbeatSession = channel === "heartbeat";
|
|
169
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
170
|
-
return {
|
|
171
|
-
key,
|
|
172
|
-
status: "active",
|
|
173
|
-
tags: [],
|
|
174
|
-
createdAt: now,
|
|
175
|
-
updatedAt: now,
|
|
176
|
-
lastAccessedAt: now,
|
|
177
|
-
messageCount: 0,
|
|
178
|
-
estimatedTokens: 0,
|
|
179
|
-
compactedCount: 0,
|
|
180
|
-
sourceChannel: channel,
|
|
181
|
-
sourceChatId: chatId,
|
|
182
|
-
routing,
|
|
183
|
-
...isCronSession ? {
|
|
184
|
-
sessionType: "cron",
|
|
185
|
-
customData: { cronJobId: chatId }
|
|
186
|
-
} : {},
|
|
187
|
-
...isHeartbeatSession ? {
|
|
188
|
-
sessionType: "heartbeat",
|
|
189
|
-
customData: { heartbeatTarget: chatId }
|
|
190
|
-
} : {},
|
|
191
|
-
stats: {
|
|
192
|
-
messageCount: 0,
|
|
193
|
-
tokenCount: 0
|
|
194
|
-
}
|
|
195
|
-
};
|
|
37
|
+
requireXopcDatabase();
|
|
38
|
+
log.debug("Session store initialized (SQLite)");
|
|
196
39
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if (parts.length >= 2 && parts[0] === "heartbeat") return {
|
|
200
|
-
channel: "heartbeat",
|
|
201
|
-
chatId: parts.slice(1).join(":")
|
|
202
|
-
};
|
|
203
|
-
const parsed = parseSessionKey(key);
|
|
204
|
-
if (parsed) {
|
|
205
|
-
if (parsed.source === "cron") return {
|
|
206
|
-
channel: "cron",
|
|
207
|
-
chatId: parsed.peerId
|
|
208
|
-
};
|
|
209
|
-
return {
|
|
210
|
-
channel: parsed.source,
|
|
211
|
-
chatId: [
|
|
212
|
-
parsed.accountId,
|
|
213
|
-
parsed.peerKind,
|
|
214
|
-
parsed.peerId
|
|
215
|
-
].join(":")
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
return {
|
|
219
|
-
channel: "unknown",
|
|
220
|
-
chatId: key
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
extractRoutingFromKey(key) {
|
|
224
|
-
const parsed = parseSessionKey(key);
|
|
225
|
-
if (!parsed) return;
|
|
226
|
-
return {
|
|
227
|
-
agentId: parsed.agentId?.toLowerCase() || "main",
|
|
228
|
-
source: parsed.source?.toLowerCase() || "unknown",
|
|
229
|
-
accountId: parsed.accountId?.toLowerCase() || "default",
|
|
230
|
-
peerKind: parsed.peerKind?.toLowerCase() || "dm",
|
|
231
|
-
peerId: parsed.peerId?.toLowerCase() || "unknown",
|
|
232
|
-
threadId: parsed.threadId,
|
|
233
|
-
scopeId: parsed.scopeId
|
|
234
|
-
};
|
|
40
|
+
getSessionsRoot() {
|
|
41
|
+
return resolveStateDir();
|
|
235
42
|
}
|
|
236
|
-
/** Resolve on-disk transcript path; creates session row + empty JSONL when missing. */
|
|
237
43
|
async resolveTranscriptPath(sessionKey) {
|
|
238
|
-
|
|
239
|
-
const sessionsDir = this.resolveSessionsDirForKey(sessionKey);
|
|
240
|
-
const absPath = this.transcriptPathForEntry(entry, sessionsDir);
|
|
44
|
+
requireXopcDatabase();
|
|
241
45
|
return {
|
|
242
|
-
sessionId:
|
|
243
|
-
|
|
244
|
-
sessionsDir
|
|
46
|
+
sessionId: ensureSessionRecord(sessionKey, this.resolveWorkspaceCwd(sessionKey)).transcriptId,
|
|
47
|
+
sessionKey
|
|
245
48
|
};
|
|
246
49
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
let changed = false;
|
|
253
|
-
const entry = await withSessionsJsonLock(keyStorePath, async (map) => {
|
|
254
|
-
const existing = map[sessionKey];
|
|
255
|
-
if (existing?.pluginExtensions?.xopc?.metadata) return existing;
|
|
256
|
-
let nextEntry = existing;
|
|
257
|
-
if (!nextEntry) {
|
|
258
|
-
const sessionId = randomUUID();
|
|
259
|
-
validateSessionId(sessionId);
|
|
260
|
-
const sessionFile = `${sessionId}.jsonl`;
|
|
261
|
-
const now = Date.now();
|
|
262
|
-
const metadata = this.buildDefaultMetadata(sessionKey);
|
|
263
|
-
metadata.transcriptId = sessionId;
|
|
264
|
-
nextEntry = {
|
|
265
|
-
sessionId,
|
|
266
|
-
updatedAt: now,
|
|
267
|
-
sessionStartedAt: now,
|
|
268
|
-
sessionFile,
|
|
269
|
-
pluginExtensions: { xopc: { metadata } }
|
|
270
|
-
};
|
|
271
|
-
map[sessionKey] = nextEntry;
|
|
272
|
-
await writeTranscriptJsonl({
|
|
273
|
-
absPath: resolveSessionTranscriptPathInDir(sessionId, keySessionsDir),
|
|
274
|
-
sessionId,
|
|
275
|
-
cwd: process.cwd(),
|
|
276
|
-
rows: []
|
|
277
|
-
});
|
|
278
|
-
changed = true;
|
|
279
|
-
} else if (!nextEntry.pluginExtensions?.xopc?.metadata) {
|
|
280
|
-
const metadata = this.buildDefaultMetadata(sessionKey);
|
|
281
|
-
metadata.transcriptId = nextEntry.sessionId;
|
|
282
|
-
nextEntry.pluginExtensions = { xopc: { metadata } };
|
|
283
|
-
map[sessionKey] = nextEntry;
|
|
284
|
-
changed = true;
|
|
285
|
-
}
|
|
286
|
-
return nextEntry;
|
|
50
|
+
async appendTranscriptMessage(sessionKey, message) {
|
|
51
|
+
return this.runStoreMutation(async () => {
|
|
52
|
+
requireXopcDatabase();
|
|
53
|
+
ensureSessionRecord(sessionKey, this.resolveWorkspaceCwd(sessionKey));
|
|
54
|
+
appendTranscriptEntry(sessionKey, message);
|
|
287
55
|
});
|
|
288
|
-
if (changed) this.invalidateAllSessionsMapCache();
|
|
289
|
-
return entry;
|
|
290
|
-
}
|
|
291
|
-
metadataFromEntry(sessionKey, entry) {
|
|
292
|
-
const base = entry.pluginExtensions?.xopc?.metadata ?? this.buildDefaultMetadata(sessionKey);
|
|
293
|
-
const { channel: keySource, chatId: keyChatId } = this.parseSessionKey(sessionKey);
|
|
294
|
-
const diskSc = typeof base.sourceChannel === "string" ? base.sourceChannel.trim() : "";
|
|
295
|
-
const diskChat = typeof base.sourceChatId === "string" ? base.sourceChatId.trim() : "";
|
|
296
|
-
return {
|
|
297
|
-
...base,
|
|
298
|
-
key: sessionKey,
|
|
299
|
-
transcriptId: entry.sessionId,
|
|
300
|
-
sourceChannel: diskSc || keySource,
|
|
301
|
-
sourceChatId: diskChat || keyChatId
|
|
302
|
-
};
|
|
303
56
|
}
|
|
304
57
|
async getByAgent(agentId) {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
for (const [key, e] of Object.entries(map)) {
|
|
308
|
-
const m = this.metadataFromEntry(key, e);
|
|
309
|
-
if (m.routing?.agentId?.toLowerCase() === agentId.toLowerCase()) out.push(m);
|
|
310
|
-
}
|
|
311
|
-
return out;
|
|
58
|
+
requireXopcDatabase();
|
|
59
|
+
return listSessionsByAgent(agentId);
|
|
312
60
|
}
|
|
313
61
|
async getByAccount(accountId) {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
for (const [key, e] of Object.entries(map)) {
|
|
317
|
-
const m = this.metadataFromEntry(key, e);
|
|
318
|
-
if (m.routing?.accountId === accountId) out.push(m);
|
|
319
|
-
}
|
|
320
|
-
return out;
|
|
62
|
+
const { items } = await this.list({ limit: 1e5 });
|
|
63
|
+
return items.filter((m) => m.routing?.accountId === accountId);
|
|
321
64
|
}
|
|
322
65
|
async getByPeer(peerKind, peerId) {
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
for (const [key, e] of Object.entries(map)) {
|
|
326
|
-
const m = this.metadataFromEntry(key, e);
|
|
327
|
-
if (m.routing?.peerKind === peerKind && m.routing.peerId === peerId) out.push(m);
|
|
328
|
-
}
|
|
329
|
-
return out;
|
|
66
|
+
const { items } = await this.list({ limit: 1e5 });
|
|
67
|
+
return items.filter((m) => m.routing?.peerKind === peerKind && m.routing.peerId === peerId);
|
|
330
68
|
}
|
|
331
69
|
async getMainSession(channel, accountId) {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
const m = this.metadataFromEntry(key, e);
|
|
335
|
-
if (m.routing?.source === channel && m.routing.accountId === accountId && m.routing.peerKind === "dm" && m.routing.peerId === "main") return m;
|
|
336
|
-
}
|
|
337
|
-
return null;
|
|
70
|
+
const { items } = await this.list({ limit: 1e5 });
|
|
71
|
+
return items.find((m) => m.routing?.source === channel && m.routing.accountId === accountId && m.routing.peerKind === "dm" && m.routing.peerId === "main") ?? null;
|
|
338
72
|
}
|
|
339
73
|
async refreshIndex() {}
|
|
340
74
|
async list(query = {}) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
if (query.status) {
|
|
344
|
-
const statuses = Array.isArray(query.status) ? query.status : [query.status];
|
|
345
|
-
sessions = sessions.filter((s) => statuses.includes(s.status));
|
|
346
|
-
}
|
|
347
|
-
if (query.channel) {
|
|
348
|
-
const rawChannels = query.channel.split(",").map((c) => c.trim().toLowerCase()).filter(Boolean);
|
|
349
|
-
/**
|
|
350
|
-
* `ui` is a legacy console source; treat as webchat when filtering web sessions.
|
|
351
|
-
* `webui` matches slash-command normalization to `gateway` (see `chat-commands/session-key.ts`).
|
|
352
|
-
*/
|
|
353
|
-
const channels = [...new Set(rawChannels.flatMap((c) => {
|
|
354
|
-
if (c === "webchat") return ["webchat", "ui"];
|
|
355
|
-
if (c === "gateway") return ["gateway", "webui"];
|
|
356
|
-
return [c];
|
|
357
|
-
}))];
|
|
358
|
-
if (channels.length === 0) sessions = [];
|
|
359
|
-
else if (channels.length === 1) {
|
|
360
|
-
const ch = channels[0];
|
|
361
|
-
sessions = sessions.filter((s) => (s.sourceChannel ?? "").toLowerCase() === ch);
|
|
362
|
-
} else sessions = sessions.filter((s) => channels.includes((s.sourceChannel ?? "").toLowerCase()));
|
|
363
|
-
}
|
|
364
|
-
if (query.tags?.length) sessions = sessions.filter((s) => query.tags.some((t) => s.tags.includes(t)));
|
|
365
|
-
if (query.search) {
|
|
366
|
-
const q = query.search.toLowerCase();
|
|
367
|
-
const metadataMatches = sessions.filter((session) => this.sessionMetadataMatchesSearch(session, q));
|
|
368
|
-
const metadataMatchedKeys = new Set(metadataMatches.map((session) => session.key));
|
|
369
|
-
const contentMatches = [];
|
|
370
|
-
const candidates = sessions.filter((session) => !metadataMatchedKeys.has(session.key));
|
|
371
|
-
for (const candidate of candidates) if (await this.sessionContentMatchesSearch(candidate.key, q)) contentMatches.push(candidate);
|
|
372
|
-
sessions = [...metadataMatches, ...contentMatches];
|
|
373
|
-
}
|
|
374
|
-
const sortBy = query.sortBy || "updatedAt";
|
|
375
|
-
const sortOrder = query.sortOrder || "desc";
|
|
376
|
-
sessions.sort((a, b) => {
|
|
377
|
-
const av = a[sortBy];
|
|
378
|
-
const bv = b[sortBy];
|
|
379
|
-
const c = av < bv ? -1 : av > bv ? 1 : 0;
|
|
380
|
-
return sortOrder === "asc" ? c : -c;
|
|
381
|
-
});
|
|
382
|
-
const total = sessions.length;
|
|
383
|
-
const limit = query.limit || 50;
|
|
384
|
-
const offset = query.offset || 0;
|
|
385
|
-
return {
|
|
386
|
-
items: sessions.slice(offset, offset + limit),
|
|
387
|
-
total,
|
|
388
|
-
limit,
|
|
389
|
-
offset,
|
|
390
|
-
hasMore: offset + limit < total
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
sessionMetadataMatchesSearch(session, query) {
|
|
394
|
-
return Boolean(session.key.toLowerCase().includes(query) || session.name?.toLowerCase().includes(query) || session.sourceChannel.toLowerCase().includes(query) || session.sourceChatId.toLowerCase().includes(query) || session.tags.some((tag) => tag.toLowerCase().includes(query)));
|
|
395
|
-
}
|
|
396
|
-
async sessionContentMatchesSearch(sessionKey, query) {
|
|
397
|
-
return (await this.loadDisplayMessages(sessionKey)).some((message) => {
|
|
398
|
-
if (this.extractTextContent(this.messageContent(message)).toLowerCase().includes(query)) return true;
|
|
399
|
-
const attachments = message.attachments;
|
|
400
|
-
if (!Array.isArray(attachments)) return false;
|
|
401
|
-
return attachments.some((attachment) => {
|
|
402
|
-
if (!attachment || typeof attachment !== "object") return false;
|
|
403
|
-
const name = attachment.name;
|
|
404
|
-
return typeof name === "string" && name.toLowerCase().includes(query);
|
|
405
|
-
});
|
|
406
|
-
});
|
|
75
|
+
requireXopcDatabase();
|
|
76
|
+
return listSessionMetadata(query);
|
|
407
77
|
}
|
|
408
78
|
async get(key, options) {
|
|
409
79
|
const metadata = await this.getMetadata(key);
|
|
410
80
|
if (!metadata) return null;
|
|
411
81
|
const messages = await this.loadDisplayMessages(key);
|
|
412
|
-
return
|
|
82
|
+
return this.buildSessionDetail(key, metadata, messages, options);
|
|
413
83
|
}
|
|
414
84
|
async getMessagePage(key, options = {}) {
|
|
415
85
|
const metadata = await this.getMetadata(key);
|
|
@@ -418,44 +88,22 @@ var SessionStore = class {
|
|
|
418
88
|
const offset = Math.max(0, Math.trunc(options.offset ?? 0));
|
|
419
89
|
const parsedBefore = options.before ? Number.parseInt(options.before, 10) : void 0;
|
|
420
90
|
const hasBeforeCursor = parsedBefore !== void 0 && Number.isFinite(parsedBefore);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
});
|
|
430
|
-
const session = await this.buildSessionDetail(key, metadata, page.messages, options);
|
|
431
|
-
const nextBeforeCursor = page.startIndex > 0 ? String(page.startIndex) : void 0;
|
|
432
|
-
return {
|
|
433
|
-
session,
|
|
434
|
-
pagination: {
|
|
435
|
-
total: page.total,
|
|
436
|
-
limit,
|
|
437
|
-
offset,
|
|
438
|
-
hasMore: page.startIndex > 0,
|
|
439
|
-
...hasBeforeCursor ? { before: String(page.endIndex) } : {},
|
|
440
|
-
...nextBeforeCursor ? { nextBeforeCursor } : {}
|
|
441
|
-
}
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
const messages = await this.loadDisplayMessages(key);
|
|
445
|
-
const total = messages.length;
|
|
446
|
-
const endExclusive = hasBeforeCursor ? Math.min(total, Math.max(0, Math.trunc(parsedBefore))) : Math.max(0, total - offset);
|
|
447
|
-
const startInclusive = Math.max(0, endExclusive - limit);
|
|
448
|
-
const pageMessages = messages.slice(startInclusive, endExclusive);
|
|
449
|
-
const session = await this.buildSessionDetail(key, metadata, pageMessages, options);
|
|
450
|
-
const nextBeforeCursor = startInclusive > 0 ? String(startInclusive) : void 0;
|
|
91
|
+
const displayMessages = await this.loadDisplayMessages(key);
|
|
92
|
+
const page = this.paginateDisplayMessages(displayMessages, {
|
|
93
|
+
limit,
|
|
94
|
+
offset: hasBeforeCursor ? void 0 : offset,
|
|
95
|
+
beforeEndIndex: hasBeforeCursor ? parsedBefore : void 0
|
|
96
|
+
});
|
|
97
|
+
const session = await this.buildSessionDetail(key, metadata, page.messages, options);
|
|
98
|
+
const nextBeforeCursor = page.startIndex > 0 ? String(page.startIndex) : void 0;
|
|
451
99
|
return {
|
|
452
100
|
session,
|
|
453
101
|
pagination: {
|
|
454
|
-
total,
|
|
102
|
+
total: page.total,
|
|
455
103
|
limit,
|
|
456
104
|
offset,
|
|
457
|
-
hasMore:
|
|
458
|
-
...hasBeforeCursor ? { before: String(
|
|
105
|
+
hasMore: hasBeforeCursor ? page.startIndex > 0 : offset + limit < page.total,
|
|
106
|
+
...hasBeforeCursor ? { before: String(page.endIndex) } : {},
|
|
459
107
|
...nextBeforeCursor ? { nextBeforeCursor } : {}
|
|
460
108
|
}
|
|
461
109
|
};
|
|
@@ -482,114 +130,40 @@ var SessionStore = class {
|
|
|
482
130
|
};
|
|
483
131
|
}
|
|
484
132
|
async loadTranscriptRows(key) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
return readTranscriptRowsFromFile(this.transcriptPathForEntry(entry, this.resolveSessionsDirForKey(key)));
|
|
133
|
+
requireXopcDatabase();
|
|
134
|
+
return loadTranscriptRowsForSession(key);
|
|
488
135
|
}
|
|
489
136
|
async getMetadata(key) {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
return this.metadataFromEntry(key, entry);
|
|
137
|
+
requireXopcDatabase();
|
|
138
|
+
return getSessionMetadata(key);
|
|
493
139
|
}
|
|
494
140
|
async updateMetadata(key, updates) {
|
|
495
141
|
return this.runStoreMutation(async () => {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
if (!entry?.pluginExtensions?.xopc?.metadata) throw new Error(`Session not found: ${key}`);
|
|
499
|
-
const meta = {
|
|
500
|
-
...entry.pluginExtensions.xopc.metadata,
|
|
501
|
-
...updates,
|
|
502
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
503
|
-
};
|
|
504
|
-
entry.pluginExtensions.xopc.metadata = meta;
|
|
505
|
-
entry.updatedAt = Date.now();
|
|
506
|
-
map[key] = entry;
|
|
507
|
-
});
|
|
508
|
-
this.invalidateAllSessionsMapCache();
|
|
509
|
-
invalidateSessionSearchIndexCache();
|
|
142
|
+
requireXopcDatabase();
|
|
143
|
+
patchSessionMetadata(key, updates);
|
|
510
144
|
log.debug({
|
|
511
145
|
key,
|
|
512
146
|
updates
|
|
513
147
|
}, "Session metadata updated");
|
|
514
148
|
});
|
|
515
149
|
}
|
|
516
|
-
/**
|
|
517
|
-
* Reset transcript for an existing session key: archive the current JSONL as
|
|
518
|
-
* `*.reset.*`, assign a new `sessionId`, and preserve per-session overrides
|
|
519
|
-
* on the disk entry (thinking/verbose) and in `sessions/config/*.json`.
|
|
520
|
-
*/
|
|
521
150
|
async reset(key) {
|
|
522
151
|
return this.runStoreMutation(async () => {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
527
|
-
const abs = this.transcriptPathForEntry(existing, keySessionsDir);
|
|
528
|
-
if (existsSync(abs)) try {
|
|
529
|
-
archiveFileOnDisk(abs, "reset");
|
|
530
|
-
} catch (err) {
|
|
531
|
-
log.warn({
|
|
532
|
-
err,
|
|
533
|
-
key
|
|
534
|
-
}, "Transcript archive on reset failed");
|
|
535
|
-
}
|
|
536
|
-
const sessionId = randomUUID();
|
|
537
|
-
validateSessionId(sessionId);
|
|
538
|
-
const now = Date.now();
|
|
539
|
-
await writeTranscriptJsonl({
|
|
540
|
-
absPath: resolveSessionTranscriptPathInDir(sessionId, keySessionsDir),
|
|
541
|
-
sessionId,
|
|
542
|
-
cwd: process.cwd(),
|
|
543
|
-
rows: []
|
|
544
|
-
});
|
|
545
|
-
await withSessionsJsonLock(this.resolveStorePathForKey(key), async (map) => {
|
|
546
|
-
const e = map[key];
|
|
547
|
-
if (!e?.pluginExtensions?.xopc?.metadata) return;
|
|
548
|
-
e.sessionId = sessionId;
|
|
549
|
-
e.sessionFile = `${sessionId}.jsonl`;
|
|
550
|
-
e.updatedAt = now;
|
|
551
|
-
e.sessionStartedAt = now;
|
|
552
|
-
e.lastInteractionAt = void 0;
|
|
553
|
-
patchSessionsJsonEntryStats(e, buildSessionsJsonStatsPatch(0, 0));
|
|
554
|
-
const meta = e.pluginExtensions.xopc.metadata;
|
|
555
|
-
meta.transcriptId = sessionId;
|
|
556
|
-
meta.updatedAt = new Date(now).toISOString();
|
|
557
|
-
map[key] = e;
|
|
558
|
-
});
|
|
559
|
-
this.invalidateAllSessionsMapCache();
|
|
560
|
-
invalidateSessionSearchIndexCache();
|
|
561
|
-
log.info({
|
|
152
|
+
requireXopcDatabase();
|
|
153
|
+
const outcome = resetSessionRecord(key, this.resolveWorkspaceCwd(key));
|
|
154
|
+
if (outcome) log.info({
|
|
562
155
|
key,
|
|
563
|
-
|
|
564
|
-
sessionId
|
|
156
|
+
...outcome
|
|
565
157
|
}, "Session reset");
|
|
566
|
-
return
|
|
567
|
-
sessionId,
|
|
568
|
-
previousSessionId
|
|
569
|
-
};
|
|
158
|
+
return outcome;
|
|
570
159
|
});
|
|
571
160
|
}
|
|
572
161
|
async delete(key) {
|
|
573
162
|
return this.runStoreMutation(async () => {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
await withSessionsJsonLock(this.resolveStorePathForKey(key), async (map) => {
|
|
579
|
-
delete map[key];
|
|
580
|
-
});
|
|
581
|
-
try {
|
|
582
|
-
if (existsSync(abs)) archiveFileOnDisk(abs, "deleted");
|
|
583
|
-
} catch (err) {
|
|
584
|
-
log.warn({
|
|
585
|
-
err,
|
|
586
|
-
key
|
|
587
|
-
}, "Transcript archive on delete failed");
|
|
588
|
-
}
|
|
589
|
-
this.invalidateAllSessionsMapCache();
|
|
590
|
-
invalidateSessionSearchIndexCache();
|
|
591
|
-
log.info({ key }, "Session deleted");
|
|
592
|
-
return true;
|
|
163
|
+
requireXopcDatabase();
|
|
164
|
+
const ok = deleteSessionRecord(key);
|
|
165
|
+
if (ok) log.info({ key }, "Session deleted");
|
|
166
|
+
return ok;
|
|
593
167
|
});
|
|
594
168
|
}
|
|
595
169
|
async deleteMany(keys) {
|
|
@@ -608,8 +182,6 @@ var SessionStore = class {
|
|
|
608
182
|
}
|
|
609
183
|
async setStatus(key, status) {
|
|
610
184
|
await this.updateMetadata(key, { status });
|
|
611
|
-
if (status === "archived") await this.moveToArchive(key);
|
|
612
|
-
else await this.moveFromArchive(key);
|
|
613
185
|
}
|
|
614
186
|
async archive(key) {
|
|
615
187
|
await this.setStatus(key, "archived");
|
|
@@ -623,200 +195,62 @@ var SessionStore = class {
|
|
|
623
195
|
async unpin(key) {
|
|
624
196
|
await this.setStatus(key, "active");
|
|
625
197
|
}
|
|
626
|
-
async
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
630
|
-
const abs = this.transcriptPathForEntry(entry, keySessionsDir);
|
|
631
|
-
if (existsSync(abs)) try {
|
|
632
|
-
archiveFileOnDisk(abs, "deleted");
|
|
633
|
-
} catch (err) {
|
|
634
|
-
log.warn({
|
|
635
|
-
err,
|
|
636
|
-
key
|
|
637
|
-
}, "Archive transcript rename failed");
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
async findMostRecentDeletedTranscript(sessionId, sessionsDir) {
|
|
641
|
-
let names;
|
|
642
|
-
try {
|
|
643
|
-
names = await readdir(sessionsDir);
|
|
644
|
-
} catch {
|
|
645
|
-
return null;
|
|
646
|
-
}
|
|
647
|
-
const prefix = `${sessionId}${DELETED_MARKER}`;
|
|
648
|
-
const hits = names.filter((n) => n.startsWith(prefix) && n.endsWith("Z"));
|
|
649
|
-
hits.sort().reverse();
|
|
650
|
-
const first = hits[0];
|
|
651
|
-
return first ? join(sessionsDir, first) : null;
|
|
652
|
-
}
|
|
653
|
-
async moveFromArchive(key) {
|
|
654
|
-
const entry = await this.getDiskEntry(key);
|
|
655
|
-
if (!entry) return;
|
|
656
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
657
|
-
const target = resolveSessionTranscriptPathInDir(entry.sessionId, keySessionsDir);
|
|
658
|
-
if (existsSync(target)) return;
|
|
659
|
-
const src = await this.findMostRecentDeletedTranscript(entry.sessionId, keySessionsDir);
|
|
660
|
-
if (!src) return;
|
|
661
|
-
try {
|
|
662
|
-
const { rename } = await import("fs/promises");
|
|
663
|
-
await rename(src, target);
|
|
664
|
-
} catch (err) {
|
|
665
|
-
log.warn({
|
|
666
|
-
err,
|
|
667
|
-
key,
|
|
668
|
-
src,
|
|
669
|
-
target
|
|
670
|
-
}, "Unarchive transcript rename failed");
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
async loadMessages(key, options) {
|
|
674
|
-
const entry = await this.getDiskEntry(key);
|
|
675
|
-
if (!entry) return [];
|
|
676
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
677
|
-
const primary = this.transcriptPathForEntry(entry, keySessionsDir);
|
|
678
|
-
if (existsSync(primary)) return rowsToLlmMessages(await readTranscriptRowsFromFile(primary));
|
|
679
|
-
if (options?.fromArchive) {
|
|
680
|
-
const archived = await this.findMostRecentDeletedTranscript(entry.sessionId, keySessionsDir);
|
|
681
|
-
if (!archived) return [];
|
|
682
|
-
return rowsToLlmMessages(await readTranscriptRowsFromFile(archived));
|
|
683
|
-
}
|
|
684
|
-
return [];
|
|
685
|
-
}
|
|
686
|
-
async loadDisplayMessages(key) {
|
|
687
|
-
const entry = await this.getDiskEntry(key);
|
|
688
|
-
if (!entry) return [];
|
|
689
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
690
|
-
const primary = this.transcriptPathForEntry(entry, keySessionsDir);
|
|
691
|
-
const transcriptPaths = [];
|
|
692
|
-
const checkpoints = await this.listCompactionCheckpoints(key);
|
|
693
|
-
for (const checkpoint of [...checkpoints].reverse()) transcriptPaths.push(join(keySessionsDir, `${this.checkpointBasename(entry.sessionId)}${checkpoint.id}.jsonl`));
|
|
694
|
-
transcriptPaths.push(primary);
|
|
695
|
-
const messages = [];
|
|
696
|
-
const seenMessages = /* @__PURE__ */ new Set();
|
|
697
|
-
for (const transcriptPath of transcriptPaths) {
|
|
698
|
-
if (!existsSync(transcriptPath)) continue;
|
|
699
|
-
const rows = await readTranscriptRowsFromFile(transcriptPath);
|
|
700
|
-
for (const message of rowsToLlmMessages(rows)) {
|
|
701
|
-
if (this.isCompactionSummaryMessage(message)) continue;
|
|
702
|
-
const key = this.displayMessageIdentity(message);
|
|
703
|
-
if (seenMessages.has(key)) continue;
|
|
704
|
-
seenMessages.add(key);
|
|
705
|
-
messages.push(message);
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
return messages;
|
|
198
|
+
async loadMessages(_key, _options) {
|
|
199
|
+
requireXopcDatabase();
|
|
200
|
+
return loadLlmMessagesForSession(_key);
|
|
709
201
|
}
|
|
710
202
|
async loadTranscriptDocument(key) {
|
|
711
|
-
const
|
|
712
|
-
if (!
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
tokensAfter: typeof c.details === "object" && c.details && "tokensAfter" in c.details && typeof c.details.tokensAfter === "number" ? c.details.tokensAfter : 0
|
|
726
|
-
}));
|
|
203
|
+
const metadata = await this.getMetadata(key);
|
|
204
|
+
if (!metadata?.transcriptId) return null;
|
|
205
|
+
const rows = await this.loadTranscriptRows(key);
|
|
206
|
+
const compactions = [];
|
|
207
|
+
for (const row of rows) if (row.type === "compaction") {
|
|
208
|
+
const c = row;
|
|
209
|
+
compactions.push({
|
|
210
|
+
at: c.at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
211
|
+
summary: c.summary ?? "",
|
|
212
|
+
firstKeptIndex: Number(c.firstKeptIndex ?? 0),
|
|
213
|
+
tokensBefore: c.tokensBefore ?? 0,
|
|
214
|
+
tokensAfter: c.tokensAfter ?? 0
|
|
215
|
+
});
|
|
216
|
+
}
|
|
727
217
|
return {
|
|
728
218
|
type: "xopc_session_transcript",
|
|
729
219
|
version: 1,
|
|
730
|
-
id:
|
|
731
|
-
createdAt:
|
|
732
|
-
updatedAt:
|
|
220
|
+
id: metadata.transcriptId,
|
|
221
|
+
createdAt: metadata.createdAt,
|
|
222
|
+
updatedAt: metadata.updatedAt,
|
|
733
223
|
messages: rows,
|
|
734
224
|
...compactions.length > 0 ? { compactions } : {}
|
|
735
225
|
};
|
|
736
226
|
}
|
|
737
|
-
async
|
|
738
|
-
const entry = await this.ensureSession(key);
|
|
739
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
740
|
-
const abs = this.transcriptPathForEntry(entry, keySessionsDir);
|
|
741
|
-
const llm = rowsToLlmMessages(rows);
|
|
742
|
-
await persistMergedTranscriptRows({
|
|
743
|
-
absPath: abs,
|
|
744
|
-
sessionId: entry.sessionId,
|
|
745
|
-
cwd: process.cwd(),
|
|
746
|
-
rows,
|
|
747
|
-
appendCompaction: opts?.appendCompaction
|
|
748
|
-
});
|
|
749
|
-
await withSessionsJsonLock(this.resolveStorePathForKey(key), async (map) => {
|
|
750
|
-
const e = map[key];
|
|
751
|
-
if (!e?.pluginExtensions?.xopc?.metadata) return;
|
|
752
|
-
patchSessionsJsonEntryStats(e, buildSessionsJsonStatsPatch(llm.length, this.estimateTokens(llm)));
|
|
753
|
-
map[key] = e;
|
|
754
|
-
});
|
|
755
|
-
this.invalidateAllSessionsMapCache();
|
|
756
|
-
invalidateSessionSearchIndexCache();
|
|
757
|
-
}
|
|
758
|
-
/** Incremental sessions.json stats after guard append (OpenClaw transcript-events). */
|
|
759
|
-
async syncSessionsJsonFromTranscriptUpdate(update) {
|
|
227
|
+
async syncEmbeddedTranscriptUpdate(update) {
|
|
760
228
|
const sessionKey = update.sessionKey?.trim();
|
|
761
|
-
if (!sessionKey
|
|
229
|
+
if (!sessionKey) return;
|
|
762
230
|
return this.runStoreMutation(async () => {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
if (update.message && isAppendOnlyLlmTranscriptMessage(update.message)) {
|
|
767
|
-
incrementSessionsJsonStatsForAppend(e);
|
|
768
|
-
map[sessionKey] = e;
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
const messageCount = await countTranscriptMessageRows(update.sessionFile);
|
|
772
|
-
const llm = rowsToLlmMessages(await readTranscriptRowsFromFile(update.sessionFile));
|
|
773
|
-
patchSessionsJsonEntryStats(e, buildSessionsJsonStatsPatch(messageCount, this.estimateTokens(llm)));
|
|
774
|
-
map[sessionKey] = e;
|
|
775
|
-
});
|
|
776
|
-
this.invalidateAllSessionsMapCache();
|
|
777
|
-
invalidateSessionSearchIndexCache();
|
|
231
|
+
requireXopcDatabase();
|
|
232
|
+
ensureSessionRecord(sessionKey, this.resolveWorkspaceCwd(sessionKey));
|
|
233
|
+
if (update.message && isAppendOnlyLlmTranscriptMessage(update.message)) appendTranscriptEntry(sessionKey, update.message);
|
|
778
234
|
});
|
|
779
235
|
}
|
|
780
236
|
async appendTranscriptContextEntry(key, entry) {
|
|
781
237
|
return this.runStoreMutation(async () => {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
786
|
-
const absPath = this.transcriptPathForEntry(disk, keySessionsDir);
|
|
787
|
-
const row = {
|
|
238
|
+
requireXopcDatabase();
|
|
239
|
+
ensureSessionRecord(key, this.resolveWorkspaceCwd(key));
|
|
240
|
+
appendTranscriptEntry(key, {
|
|
788
241
|
kind: "context",
|
|
789
242
|
id: typeof entry.id === "string" ? entry.id : void 0,
|
|
790
243
|
text: typeof entry.text === "string" ? entry.text : void 0,
|
|
791
244
|
data: entry.data,
|
|
792
245
|
createdAt: entry.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
793
|
-
};
|
|
794
|
-
await appendPiTranscriptContextEntry({
|
|
795
|
-
absPath,
|
|
796
|
-
cwd: process.cwd(),
|
|
797
|
-
entry: row,
|
|
798
|
-
sessionKey: key
|
|
799
|
-
});
|
|
800
|
-
const llm = rowsToLlmMessages(existsSync(absPath) ? await readTranscriptRowsFromFile(absPath) : []);
|
|
801
|
-
await withSessionsJsonLock(this.resolveStorePathForKey(key), async (map) => {
|
|
802
|
-
const e = map[key];
|
|
803
|
-
if (!e?.pluginExtensions?.xopc?.metadata) return;
|
|
804
|
-
patchSessionsJsonEntryStats(e, buildSessionsJsonStatsPatch(llm.length, this.estimateTokens(llm)));
|
|
805
|
-
map[key] = e;
|
|
806
246
|
});
|
|
807
|
-
this.invalidateAllSessionsMapCache();
|
|
808
|
-
invalidateSessionSearchIndexCache();
|
|
809
247
|
});
|
|
810
248
|
}
|
|
811
|
-
/**
|
|
812
|
-
* Bulk write entry point used by compaction, tests, and admin tools.
|
|
813
|
-
* Runtime agent turns must persist via {@link guardSessionManager} + appendMessage.
|
|
814
|
-
*/
|
|
815
249
|
async saveMessages(key, messages) {
|
|
816
250
|
return this.runStoreMutation(async () => {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
await this.
|
|
251
|
+
requireXopcDatabase();
|
|
252
|
+
ensureSessionRecord(key, this.resolveWorkspaceCwd(key));
|
|
253
|
+
replaceTranscriptRows(key, mergeLlmMessagesPreservingContextRows(await this.loadTranscriptRows(key), messages));
|
|
820
254
|
});
|
|
821
255
|
}
|
|
822
256
|
getWindowStats(messages) {
|
|
@@ -833,62 +267,12 @@ var SessionStore = class {
|
|
|
833
267
|
stats: result
|
|
834
268
|
};
|
|
835
269
|
}
|
|
836
|
-
checkpointBasename(sessionId) {
|
|
837
|
-
return `${sessionId}.checkpoint.`;
|
|
838
|
-
}
|
|
839
|
-
async pruneCompactionCheckpoints(sessionId, sessionsDir) {
|
|
840
|
-
const MAX = 15;
|
|
841
|
-
const prefix = this.checkpointBasename(sessionId);
|
|
842
|
-
let names;
|
|
843
|
-
try {
|
|
844
|
-
names = await readdir(sessionsDir);
|
|
845
|
-
} catch {
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
const candidates = names.filter((n) => n.startsWith(prefix) && n.endsWith(".jsonl"));
|
|
849
|
-
if (candidates.length <= MAX) return;
|
|
850
|
-
const stats = await Promise.all(candidates.map(async (name) => {
|
|
851
|
-
const p = join(sessionsDir, name);
|
|
852
|
-
try {
|
|
853
|
-
return {
|
|
854
|
-
p,
|
|
855
|
-
mtimeMs: (await stat(p)).mtimeMs
|
|
856
|
-
};
|
|
857
|
-
} catch {
|
|
858
|
-
return {
|
|
859
|
-
p: join(sessionsDir, name),
|
|
860
|
-
mtimeMs: 0
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
}));
|
|
864
|
-
stats.sort((a, b) => a.mtimeMs - b.mtimeMs);
|
|
865
|
-
for (let i = 0; i < stats.length - MAX; i++) try {
|
|
866
|
-
await unlink(stats[i].p);
|
|
867
|
-
} catch {}
|
|
868
|
-
}
|
|
869
|
-
async captureCompactionCheckpoint(sessionId, transcriptAbs, sessionsDir) {
|
|
870
|
-
if (!existsSync(transcriptAbs)) return;
|
|
871
|
-
const dest = join(sessionsDir, `${sessionId}.checkpoint.${randomUUID()}.jsonl`);
|
|
872
|
-
try {
|
|
873
|
-
await copyFile(transcriptAbs, dest);
|
|
874
|
-
await this.pruneCompactionCheckpoints(sessionId, sessionsDir);
|
|
875
|
-
} catch (err) {
|
|
876
|
-
log.warn({
|
|
877
|
-
err,
|
|
878
|
-
sessionId
|
|
879
|
-
}, "Compaction checkpoint copy failed");
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
270
|
async applyCompaction(key, messages, result) {
|
|
883
271
|
const compacted = this.compactor.applyCompaction(messages, result);
|
|
884
272
|
return this.runStoreMutation(async () => {
|
|
885
|
-
const entry = await this.getDiskEntry(key);
|
|
886
|
-
if (!entry) return compacted;
|
|
887
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
888
|
-
const abs = this.transcriptPathForEntry(entry, keySessionsDir);
|
|
889
|
-
await this.captureCompactionCheckpoint(entry.sessionId, abs, keySessionsDir);
|
|
890
273
|
const merged = mergeLlmMessagesPreservingContextRows(await this.loadTranscriptRows(key), compacted);
|
|
891
|
-
|
|
274
|
+
captureCompactionCheckpoint(key);
|
|
275
|
+
replaceTranscriptRows(key, merged, { appendCompaction: {
|
|
892
276
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
893
277
|
summary: result.summary,
|
|
894
278
|
firstKeptIndex: result.firstKeptIndex,
|
|
@@ -923,72 +307,21 @@ var SessionStore = class {
|
|
|
923
307
|
};
|
|
924
308
|
}
|
|
925
309
|
async listCompactionCheckpoints(key) {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
929
|
-
const sessionId = entry.sessionId;
|
|
930
|
-
const prefix = this.checkpointBasename(sessionId);
|
|
931
|
-
let names;
|
|
932
|
-
try {
|
|
933
|
-
names = await readdir(keySessionsDir);
|
|
934
|
-
} catch {
|
|
935
|
-
return [];
|
|
936
|
-
}
|
|
937
|
-
const files = names.filter((n) => n.startsWith(prefix) && n.endsWith(".jsonl"));
|
|
938
|
-
const valid = (await Promise.all(files.map(async (name) => {
|
|
939
|
-
const p = join(keySessionsDir, name);
|
|
940
|
-
const id = parseCompactionCheckpointTranscriptFileName(name)?.checkpointId;
|
|
941
|
-
if (!id || !normalizeCompactionCheckpointId(id)) return null;
|
|
942
|
-
try {
|
|
943
|
-
const s = await stat(p);
|
|
944
|
-
return {
|
|
945
|
-
id: normalizeCompactionCheckpointId(id),
|
|
946
|
-
sizeBytes: s.size,
|
|
947
|
-
modifiedAt: new Date(s.mtimeMs).toISOString()
|
|
948
|
-
};
|
|
949
|
-
} catch {
|
|
950
|
-
return null;
|
|
951
|
-
}
|
|
952
|
-
}))).filter((r) => r !== null);
|
|
953
|
-
valid.sort((a, b) => b.modifiedAt.localeCompare(a.modifiedAt));
|
|
954
|
-
return valid;
|
|
310
|
+
requireXopcDatabase();
|
|
311
|
+
return listCompactionCheckpoints(key);
|
|
955
312
|
}
|
|
956
313
|
async getCompactionCheckpointDetail(key, checkpointId) {
|
|
314
|
+
requireXopcDatabase();
|
|
957
315
|
const id = normalizeCompactionCheckpointId(checkpointId);
|
|
958
316
|
if (!id) return null;
|
|
959
|
-
|
|
960
|
-
if (!entry) return null;
|
|
961
|
-
const cpPath = join(this.resolveSessionsDirForKey(key), `${this.checkpointBasename(entry.sessionId)}${id}.jsonl`);
|
|
962
|
-
if (!existsSync(cpPath)) return null;
|
|
963
|
-
try {
|
|
964
|
-
const llm = rowsToLlmMessages(await readTranscriptRowsFromFile(cpPath));
|
|
965
|
-
const s = await stat(cpPath);
|
|
966
|
-
return {
|
|
967
|
-
id,
|
|
968
|
-
sizeBytes: s.size,
|
|
969
|
-
modifiedAt: new Date(s.mtimeMs).toISOString(),
|
|
970
|
-
messageCount: llm.length
|
|
971
|
-
};
|
|
972
|
-
} catch {
|
|
973
|
-
return null;
|
|
974
|
-
}
|
|
317
|
+
return getCompactionCheckpointDetail(key, id);
|
|
975
318
|
}
|
|
976
319
|
async restoreCompactionCheckpoint(key, checkpointId) {
|
|
977
|
-
const id = normalizeCompactionCheckpointId(checkpointId);
|
|
978
|
-
if (!id) throw new Error("Invalid checkpoint id");
|
|
979
320
|
return this.runStoreMutation(async () => {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
if (!existsSync(cpPath)) throw new Error(`Checkpoint not found: ${id}`);
|
|
985
|
-
await copyFile(cpPath, this.transcriptPathForEntry(entry, keySessionsDir));
|
|
986
|
-
const messages = await this.loadMessages(key);
|
|
987
|
-
await this.saveMessages(key, messages);
|
|
988
|
-
log.info({
|
|
989
|
-
key,
|
|
990
|
-
checkpointId: id
|
|
991
|
-
}, "Session transcript restored from compaction checkpoint");
|
|
321
|
+
requireXopcDatabase();
|
|
322
|
+
const id = normalizeCompactionCheckpointId(checkpointId);
|
|
323
|
+
if (!id) throw new Error(`Invalid checkpoint id: ${checkpointId}`);
|
|
324
|
+
restoreCompactionCheckpoint(key, id);
|
|
992
325
|
});
|
|
993
326
|
}
|
|
994
327
|
async deleteSession(key) {
|
|
@@ -1002,66 +335,34 @@ var SessionStore = class {
|
|
|
1002
335
|
}
|
|
1003
336
|
async searchInSession(key, keyword) {
|
|
1004
337
|
const messages = await this.loadDisplayMessages(key);
|
|
1005
|
-
const
|
|
1006
|
-
return this.convertMessages(messages.filter((m) =>
|
|
1007
|
-
return this.extractTextContent(this.messageContent(m)).toLowerCase().includes(keywordLower);
|
|
1008
|
-
}));
|
|
338
|
+
const q = keyword.toLowerCase();
|
|
339
|
+
return this.convertMessages(messages.filter((m) => this.extractTextContent(this.messageContent(m)).toLowerCase().includes(q)));
|
|
1009
340
|
}
|
|
1010
341
|
async exportSession(key, format) {
|
|
1011
|
-
const
|
|
1012
|
-
if (!
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
}
|
|
342
|
+
const metadata = await this.getMetadata(key);
|
|
343
|
+
if (!metadata) throw new Error(`Session not found: ${key}`);
|
|
344
|
+
const rows = await this.loadTranscriptRows(key);
|
|
345
|
+
const messages = this.convertMessages(buildSessionContextForLlm(rows));
|
|
346
|
+
const payload = {
|
|
347
|
+
version: INDEX_VERSION,
|
|
348
|
+
exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
349
|
+
metadata,
|
|
350
|
+
messages,
|
|
351
|
+
transcriptRows: rows
|
|
352
|
+
};
|
|
353
|
+
if (format === "json") return JSON.stringify(payload, null, 2);
|
|
1024
354
|
const lines = [
|
|
1025
|
-
`# ${
|
|
1026
|
-
"",
|
|
1027
|
-
`- **Channel:** ${detail.sourceChannel}`,
|
|
1028
|
-
`- **Created:** ${detail.createdAt}`,
|
|
1029
|
-
`- **Messages:** ${detail.messageCount}`,
|
|
1030
|
-
`- **Tags:** ${detail.tags.join(", ") || "none"}`,
|
|
355
|
+
`# ${metadata.name ?? metadata.key}`,
|
|
1031
356
|
"",
|
|
1032
|
-
|
|
357
|
+
`Exported: ${payload.exportedAt}`,
|
|
1033
358
|
""
|
|
1034
359
|
];
|
|
1035
|
-
for (const msg of
|
|
1036
|
-
const role = msg.role === "assistant" ? "Assistant" : msg.role === "user" ? "User" : msg.role;
|
|
1037
|
-
lines.push(`## ${role}`, "");
|
|
1038
|
-
const body = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content, null, 2);
|
|
1039
|
-
lines.push(body, "", "---", "");
|
|
1040
|
-
}
|
|
360
|
+
for (const msg of messages) lines.push(`## ${msg.role}`, "", typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content), "");
|
|
1041
361
|
return lines.join("\n");
|
|
1042
362
|
}
|
|
1043
363
|
async getStats() {
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
for (const s of sessions) byChannel[s.sourceChannel] = (byChannel[s.sourceChannel] || 0) + 1;
|
|
1047
|
-
let oldestSession;
|
|
1048
|
-
let newestSession;
|
|
1049
|
-
if (sessions.length > 0) {
|
|
1050
|
-
const sorted = [...sessions].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
1051
|
-
oldestSession = sorted[0].createdAt;
|
|
1052
|
-
newestSession = sorted[sorted.length - 1].createdAt;
|
|
1053
|
-
}
|
|
1054
|
-
return {
|
|
1055
|
-
totalSessions: sessions.length,
|
|
1056
|
-
activeSessions: sessions.filter((s) => s.status === "active" || s.status === "idle").length,
|
|
1057
|
-
archivedSessions: sessions.filter((s) => s.status === "archived").length,
|
|
1058
|
-
pinnedSessions: sessions.filter((s) => s.status === "pinned").length,
|
|
1059
|
-
totalMessages: sessions.reduce((sum, s) => sum + s.messageCount, 0),
|
|
1060
|
-
totalTokens: sessions.reduce((sum, s) => sum + s.estimatedTokens, 0),
|
|
1061
|
-
oldestSession,
|
|
1062
|
-
newestSession,
|
|
1063
|
-
byChannel
|
|
1064
|
-
};
|
|
364
|
+
requireXopcDatabase();
|
|
365
|
+
return getGlobalSessionStats();
|
|
1065
366
|
}
|
|
1066
367
|
async archiveOld(olderThanDays) {
|
|
1067
368
|
const cutoff = /* @__PURE__ */ new Date();
|
|
@@ -1077,17 +378,44 @@ var SessionStore = class {
|
|
|
1077
378
|
return archived;
|
|
1078
379
|
}
|
|
1079
380
|
estimateTokens(messages) {
|
|
1080
|
-
|
|
1081
|
-
for (const msg of messages) total += Math.ceil(this.extractTextContent(this.messageContent(msg)).length / 4);
|
|
1082
|
-
return total;
|
|
381
|
+
return estimateTokensFromMessages(messages);
|
|
1083
382
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
383
|
+
async loadDisplayMessages(key) {
|
|
384
|
+
requireXopcDatabase();
|
|
385
|
+
const checkpoints = listCompactionCheckpoints(key);
|
|
386
|
+
const rowSets = [];
|
|
387
|
+
for (const checkpoint of [...checkpoints].reverse()) rowSets.push(loadCheckpointRows(key, checkpoint.id));
|
|
388
|
+
rowSets.push(await this.loadTranscriptRows(key));
|
|
389
|
+
const messages = [];
|
|
390
|
+
const seen = /* @__PURE__ */ new Set();
|
|
391
|
+
for (const rows of rowSets) for (const message of buildSessionContextForLlm(rows)) {
|
|
392
|
+
if (this.isCompactionSummaryMessage(message)) continue;
|
|
393
|
+
const identity = this.displayMessageIdentity(message);
|
|
394
|
+
if (seen.has(identity)) continue;
|
|
395
|
+
seen.add(identity);
|
|
396
|
+
messages.push(message);
|
|
397
|
+
}
|
|
398
|
+
return messages;
|
|
1086
399
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
const
|
|
1090
|
-
|
|
400
|
+
paginateDisplayMessages(messages, options = {}) {
|
|
401
|
+
const total = messages.length;
|
|
402
|
+
const limit = Math.min(200, Math.max(1, Math.trunc(options.limit ?? 50)));
|
|
403
|
+
const offset = Math.max(0, Math.trunc(options.offset ?? 0));
|
|
404
|
+
let startIndex;
|
|
405
|
+
let endIndex;
|
|
406
|
+
if (options.beforeEndIndex !== void 0 && Number.isFinite(options.beforeEndIndex)) {
|
|
407
|
+
endIndex = Math.min(total, Math.max(0, Math.trunc(options.beforeEndIndex)));
|
|
408
|
+
startIndex = Math.max(0, endIndex - limit);
|
|
409
|
+
} else {
|
|
410
|
+
endIndex = Math.max(0, total - offset);
|
|
411
|
+
startIndex = Math.max(0, endIndex - limit);
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
messages: messages.slice(startIndex, endIndex),
|
|
415
|
+
total,
|
|
416
|
+
startIndex,
|
|
417
|
+
endIndex
|
|
418
|
+
};
|
|
1091
419
|
}
|
|
1092
420
|
displayMessageIdentity(message) {
|
|
1093
421
|
const record = message;
|
|
@@ -1099,6 +427,14 @@ var SessionStore = class {
|
|
|
1099
427
|
content: this.messageContent(message)
|
|
1100
428
|
});
|
|
1101
429
|
}
|
|
430
|
+
messageContent(msg) {
|
|
431
|
+
return msg.content;
|
|
432
|
+
}
|
|
433
|
+
isCompactionSummaryMessage(msg) {
|
|
434
|
+
if (msg.role !== "user") return false;
|
|
435
|
+
const text = this.extractTextContent(this.messageContent(msg)).trim();
|
|
436
|
+
return /^\[Previous conversation summary\]/i.test(text);
|
|
437
|
+
}
|
|
1102
438
|
extractTextContent(content) {
|
|
1103
439
|
if (typeof content === "string") return content;
|
|
1104
440
|
if (Array.isArray(content)) {
|
|
@@ -1119,22 +455,11 @@ var SessionStore = class {
|
|
|
1119
455
|
sessionKey: key
|
|
1120
456
|
});
|
|
1121
457
|
if (!contextText?.trim()) return;
|
|
1122
|
-
const entry = await this.getDiskEntry(key);
|
|
1123
|
-
if (!entry) return;
|
|
1124
|
-
const keySessionsDir = this.resolveSessionsDirForKey(key);
|
|
1125
|
-
const abs = this.transcriptPathForEntry(entry, keySessionsDir);
|
|
1126
|
-
const workspaceDir = resolveEffectiveAgentProfileForSession(this.options.config, key).resolvedWorkspacePath;
|
|
1127
458
|
try {
|
|
1128
|
-
await
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
entry: {
|
|
1133
|
-
kind: "context",
|
|
1134
|
-
id: `post-compaction-${Date.now()}`,
|
|
1135
|
-
text: contextText,
|
|
1136
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1137
|
-
}
|
|
459
|
+
await this.appendTranscriptContextEntry(key, {
|
|
460
|
+
id: `post-compaction-${Date.now()}`,
|
|
461
|
+
text: contextText,
|
|
462
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1138
463
|
});
|
|
1139
464
|
} catch (err) {
|
|
1140
465
|
log.warn({
|
|
@@ -1161,7 +486,7 @@ var SessionStore = class {
|
|
|
1161
486
|
const inputTokens = typeof rawUsage.input === "number" ? rawUsage.input : void 0;
|
|
1162
487
|
const outputTokens = typeof rawUsage.output === "number" ? rawUsage.output : void 0;
|
|
1163
488
|
const totalTokens = typeof rawUsage.totalTokens === "number" ? rawUsage.totalTokens : typeof rawUsage.total === "number" ? rawUsage.total : void 0;
|
|
1164
|
-
if (inputTokens
|
|
489
|
+
if (inputTokens !== void 0 || outputTokens !== void 0 || totalTokens !== void 0) row.usage = {
|
|
1165
490
|
inputTokens,
|
|
1166
491
|
outputTokens,
|
|
1167
492
|
totalTokens
|