@xopcai/xopc 0.0.145 → 0.0.147
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/README.md +2 -2
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/demo-memory/src/index.js +6 -4
- package/dist/extensions/demo-memory/src/index.js.map +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +41 -0
- package/dist/gateway/static/root/assets/activity-store-DXeSSlw1.js +1 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BEUxdhZx.js → agent-avatar-dicebear-CFdJKSjY.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DKjbRpbA.js +2 -0
- package/dist/gateway/static/root/assets/api-Bs69B5zA.js +1 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CRHSZJWi.js → app-management-settings-panel-ag1ViXT_.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-BunADYJb.js → appearance-settings-C6iMpwOM.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CpX3lBFF.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-B6vTkH2A.js → archive-plugin-Dwi3mIBy.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-BjZXzaNv.js → attachment-load-BaCDoq40.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-ZDA-Stg1.js → automation-suggestion-card-CwqtFgnw.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-DlupOxFQ.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DYZfLvPz.js → binary-plugins-DoAYhsxa.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C3MUlYC9.js → block-editor-Bw72pO7S.js} +31 -31
- package/dist/gateway/static/root/assets/browser-settings-page-BwLoUBcZ.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-vdbAR65Q.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BAsKbJgm.js +2 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-fTlTnWB4.js → channel-recipient-api-rTG26jpV.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-CxFWy0cE.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-OKlqTtKJ.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-BVFNT2zW.js → connector-logo-DIMP4NWY.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-BjQQwX62.js +2 -0
- package/dist/gateway/static/root/assets/{desktop-pet-_jUmoXd3.js → desktop-pet-kQq2e0BN.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DwGOy4AQ.js → desktop-pet-settings-B6vtozMY.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-akvF0F-u.js → directory-picker-path-field-Dn5-e3v4.js} +1 -1
- package/dist/gateway/static/root/assets/dist-C230izr8.js +1 -0
- package/dist/gateway/static/root/assets/dist-CxGUk8J-.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-settings-BzwIujPG.js +3 -0
- package/dist/gateway/static/root/assets/extension-debug-page-D_e_hsEy.js +1 -0
- package/dist/gateway/static/root/assets/{extension-page-CwWktRNz.js → extension-page-D15CWHBd.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CuggWOIl.js → extension-settings-page-D4P0n1om.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-B7sxIbza.js → gateway-config-api-B4qZctjG.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DIv0eKMf.js → gateway-settings-BvndV7TP.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DtoLihQE.js → gateway-startup-retry-BpgMunEb.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-C4Kw0mfS.js → goal-create-dialog-DrVHKXHq.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-PHlCwv68.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-B0jm5JaA.js → goals-config-api-B6YJB_ct.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-Hg9uyO6e.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-N5_iL7es.js → goals-settings-BROWCIcL.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-XzH3lbRR.js → heartbeat-settings-CoCwIOIg.js} +1 -1
- package/dist/gateway/static/root/assets/index-CxkNzw3e.js +259 -0
- package/dist/gateway/static/root/assets/index-DjCSOyaN.css +1 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-Bm_AIYQ7.js +1 -0
- package/dist/gateway/static/root/assets/local-app-workbench-page-BJWFcxwG.js +2 -0
- package/dist/gateway/static/root/assets/local-apps-page-BsiZMrEf.js +1 -0
- package/dist/gateway/static/root/assets/{locale-store-CiM-D9jA.js → locale-store-Bp8joZck.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DOmK61ey.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-5rJx5flj.js → markdown-split-Dy7QpaAz.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-DYXccwAd.js → media-plugins-3Lxliy9D.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CQGpD-dC.js +5 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DGCZom4o.js +2 -0
- package/dist/gateway/static/root/assets/{notes-page-BgLyndCO.js → notes-page-BJtT4vSf.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-B_bN7cOR.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-6Al9_sGz.js → page-tabs-DKB6RDre.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Cm3G72Hv.js → preview-open-alternatives-Br_YhYHp.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-Dq8JouJj.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-DvfL7fSe.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-DqwMXSXP.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BYtfzu_F.js → save-bar-controls-BgIE9BBh.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CvIRc6yK.js → schedule-field-BXDP-oMz.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CQuKx0n7.js → schema-form-Dhv-SmjG.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-B_mOZkQk.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BHGmH6YS.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-CF3HHM-t.js → settings-collapsible-section-CUTExnlK.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-CwWjoRN6.js → settings-form-section-CmnDhsf0.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-aUFmJa13.js → settings-loading-skeleton-B79dq-XY.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-B2UUU9TF.js → settings-page-Db8uAv3X.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-DqpbTWqI.js → settings-page-layout-DaFwstQw.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-BUSEj0KK.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-BOhlPsS1.js → share-preview-page-Bi00uXzV.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DzsTYfuX.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DSsdU081.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DeB1tQZL.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-CWxSvuwD.js → system-settings-panel-Cxaph7hW.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-C9Dxcppm.js → theme-store-eCTN1RpG.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-qROAvqTw.js → typed-models-lib-CcZ_tyFY.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-DE9cpn4G.js → use-channel-catalog-C4PWbNoi.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-QTVMx_hG.js +1 -0
- package/dist/gateway/static/root/assets/{user-profile-fields-editor-CWxc0ghP.js → user-profile-fields-editor-CPOO9Jz5.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-DW-Up6vt.js → user-profile-settings-panel-C8cgtSF7.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-D53uRXVr.js → utils-CiZK2KwH.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-b-YZtvUu.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-4zVDOl2G.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-CHe2tfkc.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-D_x9ELJp.js → workflow-run-setup-panel-8SLCYeXE.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DEOFqiWn.js +11 -0
- package/dist/gateway/static/root/index.html +10 -9
- package/dist/package.js +1 -1
- package/dist/src/activity/types.d.ts +1 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +1 -1
- package/dist/src/agent/agent-manager.d.ts +1 -1
- package/dist/src/agent/agent-manager.js +5 -4
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/coordinator.js +0 -1
- package/dist/src/agent/background-review/coordinator.js.map +1 -1
- package/dist/src/agent/background-review/settings.d.ts +1 -1
- package/dist/src/agent/background-review/settings.js +10 -17
- package/dist/src/agent/background-review/settings.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.d.ts +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +2 -3
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/code-intelligence/binary.js +1 -1
- package/dist/src/agent/context/project-context.d.ts +14 -0
- package/dist/src/agent/context/project-context.js +23 -1
- package/dist/src/agent/context/project-context.js.map +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/context/workspace.d.ts +1 -2
- package/dist/src/agent/context/workspace.js +2 -4
- package/dist/src/agent/context/workspace.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.js +1 -2
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/embedded/run-turn.js +6 -1
- package/dist/src/agent/embedded/run-turn.js.map +1 -1
- package/dist/src/agent/embedded/types.d.ts +17 -0
- package/dist/src/agent/memory/builtin-memory-store.d.ts +2 -2
- package/dist/src/agent/memory/builtin-memory-store.js +2 -2
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.d.ts +1 -3
- package/dist/src/agent/memory/builtin-provider.js +21 -48
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/context/planner.js +48 -9
- package/dist/src/agent/memory/context/planner.js.map +1 -1
- package/dist/src/agent/memory/context/types.d.ts +7 -1
- package/dist/src/agent/memory/context-fence.js +1 -1
- package/dist/src/agent/memory/context-fence.js.map +1 -1
- package/dist/src/agent/memory/create-memory-manager.js +2 -9
- package/dist/src/agent/memory/create-memory-manager.js.map +1 -1
- package/dist/src/agent/memory/dreaming/config.js +5 -10
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.js +2 -2
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.js.map +1 -1
- package/dist/src/agent/memory/dreaming/scope.d.ts +2 -3
- package/dist/src/agent/memory/dreaming/scope.js +8 -8
- package/dist/src/agent/memory/dreaming/scope.js.map +1 -1
- package/dist/src/agent/memory/manager.d.ts +1 -5
- package/dist/src/agent/memory/manager.js +2 -23
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.d.ts +3 -3
- package/dist/src/agent/memory/memory-config.js +9 -14
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/types.d.ts +9 -5
- package/dist/src/agent/memory/understanding/service.js +21 -8
- package/dist/src/agent/memory/understanding/service.js.map +1 -1
- package/dist/src/agent/memory/understanding/types.d.ts +5 -0
- package/dist/src/agent/memory/user-context-coordinator.d.ts +1 -1
- package/dist/src/agent/memory/user-context-coordinator.js +6 -2
- package/dist/src/agent/memory/user-context-coordinator.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +2 -2
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/memory/index.d.ts +1 -2
- package/dist/src/agent/prompt/memory/index.js +6 -7
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +1 -1
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +13 -2
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/tools/curated-memory-tool.js +4 -4
- package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +1 -1
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.js +1 -1
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/workflow/workflow-child-tools.js +2 -3
- package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
- package/dist/src/agent/workspace-runtime/registry.d.ts +5 -5
- package/dist/src/agent/workspace-runtime/registry.js +6 -11
- package/dist/src/agent/workspace-runtime/registry.js.map +1 -1
- package/dist/src/agent-manifest/index.js +2 -2
- package/dist/src/agent-manifest/prompt.js +1 -7
- package/dist/src/agent-manifest/prompt.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +0 -598
- package/dist/src/agent-manifest/schema.js +2 -143
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/agent-manifest/validator.js +0 -12
- package/dist/src/agent-manifest/validator.js.map +1 -1
- package/dist/src/agent-runtime/index.js +1 -1
- package/dist/src/agent-runtime/memory-runtime.d.ts +2 -2
- package/dist/src/agent-runtime/memory-runtime.js +8 -7
- package/dist/src/agent-runtime/memory-runtime.js.map +1 -1
- package/dist/src/agent-runtime/runtime-profile.d.ts +2 -0
- package/dist/src/agent-runtime/runtime-profile.js +2 -2
- package/dist/src/agent-runtime/runtime-profile.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -2
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/init.js +0 -22
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/templates.d.ts +1 -1
- package/dist/src/cli/templates.js +1 -16
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/commands/agents.config.js +0 -10
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/paths.d.ts +0 -1
- package/dist/src/config/paths.js +1 -2
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/schema.d.ts +118 -532
- package/dist/src/config/schema.js +32 -26
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/extensions/loader.js +2 -1
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +0 -2
- package/dist/src/gateway/agents-admin.js +1 -7
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/capability-presets-admin.d.ts +0 -2
- package/dist/src/gateway/capability-presets-admin.js.map +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +26 -0
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +16 -1
- package/dist/src/gateway/dreaming-automation-reconciler.d.ts +0 -1
- package/dist/src/gateway/dreaming-automation-reconciler.js +41 -63
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/app.js +3 -1
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +0 -130
- package/dist/src/gateway/hono/lib/config-payload.js +0 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +6 -12
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +6 -0
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js.map +1 -1
- package/dist/src/gateway/hono/routes/capability-presets.js +2 -2
- package/dist/src/gateway/hono/routes/capability-presets.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +9 -20
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/index.js +4 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/local-apps.d.ts +5 -0
- package/dist/src/gateway/hono/routes/local-apps.js +99 -0
- package/dist/src/gateway/hono/routes/local-apps.js.map +1 -0
- package/dist/src/gateway/hono/routes/memory.js +48 -65
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/projects.js +2 -2
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/work-discovery.d.ts +3 -0
- package/dist/src/gateway/hono/routes/work-discovery.js +150 -0
- package/dist/src/gateway/hono/routes/work-discovery.js.map +1 -0
- package/dist/src/gateway/hono/routes/you.d.ts +3 -0
- package/dist/src/gateway/hono/routes/you.js +358 -91
- package/dist/src/gateway/hono/routes/you.js.map +1 -1
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +12 -0
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/knowledge/connected-knowledge-pipeline.js +9 -5
- package/dist/src/knowledge/connected-knowledge-pipeline.js.map +1 -1
- package/dist/src/local-apps/acceptance.d.ts +30 -0
- package/dist/src/local-apps/acceptance.js +93 -0
- package/dist/src/local-apps/acceptance.js.map +1 -0
- package/dist/src/local-apps/index.d.ts +5 -0
- package/dist/src/local-apps/index.js +4 -0
- package/dist/src/local-apps/preview-runtime-bridge.d.ts +4 -0
- package/dist/src/local-apps/preview-runtime-bridge.js +171 -0
- package/dist/src/local-apps/preview-runtime-bridge.js.map +1 -0
- package/dist/src/local-apps/runtime-entry.d.ts +8 -0
- package/dist/src/local-apps/runtime-entry.js +25 -0
- package/dist/src/local-apps/runtime-entry.js.map +1 -0
- package/dist/src/local-apps/scaffold.d.ts +8 -0
- package/dist/src/local-apps/scaffold.js +122 -0
- package/dist/src/local-apps/scaffold.js.map +1 -0
- package/dist/src/local-apps/service.d.ts +37 -0
- package/dist/src/local-apps/service.js +553 -0
- package/dist/src/local-apps/service.js.map +1 -0
- package/dist/src/local-apps/store.d.ts +44 -0
- package/dist/src/local-apps/store.js +195 -0
- package/dist/src/local-apps/store.js.map +1 -0
- package/dist/src/local-apps/types.d.ts +105 -0
- package/dist/src/local-apps/types.js +1 -0
- package/dist/src/storage/sqlite/index.d.ts +3 -2
- package/dist/src/storage/sqlite/index.js +4 -3
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +2 -3
- package/dist/src/storage/sqlite/memory-index-repository.js +16 -20
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +18 -10
- package/dist/src/storage/sqlite/memory-records-repository.js +79 -34
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-reference-consent-repository.d.ts +27 -0
- package/dist/src/storage/sqlite/memory-reference-consent-repository.js +109 -0
- package/dist/src/storage/sqlite/memory-reference-consent-repository.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/038_user_owned_memory.sql +68 -0
- package/dist/src/storage/sqlite/migrations/039_memory_reference_consents.sql +19 -0
- package/dist/src/storage/sqlite/migrations/040_local_apps.sql +32 -0
- package/dist/src/storage/sqlite/migrations/041_local_app_release_lifecycle.sql +17 -0
- package/dist/src/storage/sqlite/migrations/042_work_discovery.sql +41 -0
- package/dist/src/storage/sqlite/migrations/043_local_app_acceptance_runs.sql +16 -0
- package/dist/src/storage/sqlite/migrations/044_repair_work_discovery_foreign_keys.sql +75 -0
- package/dist/src/storage/sqlite/migrations/045_extension_ui_grants.sql +13 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +20 -0
- package/dist/src/user-context/config.d.ts +227 -0
- package/dist/src/user-context/config.js +158 -0
- package/dist/src/user-context/config.js.map +1 -0
- package/dist/src/user-context/import.d.ts +1 -1
- package/dist/src/user-context/import.js +6 -1
- package/dist/src/user-context/import.js.map +1 -1
- package/dist/src/user-context/owner.d.ts +5 -0
- package/dist/src/user-context/owner.js +9 -0
- package/dist/src/user-context/owner.js.map +1 -0
- package/dist/src/user-context/projection.d.ts +11 -9
- package/dist/src/user-context/projection.js +74 -47
- package/dist/src/user-context/projection.js.map +1 -1
- package/dist/src/user-context/runtime.d.ts +13 -0
- package/dist/src/user-context/runtime.js +36 -0
- package/dist/src/user-context/runtime.js.map +1 -0
- package/dist/src/work-discovery/analyzer.d.ts +11 -0
- package/dist/src/work-discovery/analyzer.js +171 -0
- package/dist/src/work-discovery/analyzer.js.map +1 -0
- package/dist/src/work-discovery/index.d.ts +5 -0
- package/dist/src/work-discovery/index.js +5 -0
- package/dist/src/work-discovery/probe.d.ts +12 -0
- package/dist/src/work-discovery/probe.js +335 -0
- package/dist/src/work-discovery/probe.js.map +1 -0
- package/dist/src/work-discovery/repository.d.ts +11 -0
- package/dist/src/work-discovery/repository.js +100 -0
- package/dist/src/work-discovery/repository.js.map +1 -0
- package/dist/src/work-discovery/service.d.ts +30 -0
- package/dist/src/work-discovery/service.js +387 -0
- package/dist/src/work-discovery/service.js.map +1 -0
- package/dist/src/work-discovery/types.d.ts +114 -0
- package/dist/src/work-discovery/types.js +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +5 -3
- package/skills/engineering/build-xopc-local-app/SKILL.md +45 -0
- package/skills/engineering/build-xopc-local-app/references/app-contract.md +33 -0
- package/skills/engineering/build-xopc-local-app/scripts/validate-local-app.mjs +72 -0
- package/dist/gateway/static/root/assets/Combination-DolwnuKi.js +0 -41
- package/dist/gateway/static/root/assets/activity-center-store-3l9ahUqb.js +0 -1
- package/dist/gateway/static/root/assets/agents-1bpT0xRO.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-Cc4JgVUQ.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-mb0fdVpq.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-Bb0xhaMN.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-BV76yN9a.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CUcGKZqC.js +0 -2
- package/dist/gateway/static/root/assets/channels-settings-BlSDMGdy.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-CJauF1CW.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CMgAFGvb.js +0 -2
- package/dist/gateway/static/root/assets/dist-C99RGfAH.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-BLetQiYY.js +0 -3
- package/dist/gateway/static/root/assets/extension-debug-page-Cof2ncxE.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BMmzYpZL.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-CGeT77PC.js +0 -2
- package/dist/gateway/static/root/assets/index-CSLF84-Q.css +0 -1
- package/dist/gateway/static/root/assets/index-I-ZCenVw.js +0 -259
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-x_v0nrIi.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-BSh1t8cD.js +0 -7
- package/dist/gateway/static/root/assets/messages-Cb1VMeqP.js +0 -5
- package/dist/gateway/static/root/assets/models-hub-panel-BNpTenAI.js +0 -2
- package/dist/gateway/static/root/assets/notes-workbench-teklkhcE.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-CCB_dKoh.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-VOAFAHYj.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-USYu64Ru.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-oGC8O5h_.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4rP66R1.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Ck9keROI.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-BYLsCuqj.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BNHUyVML.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CpXbQH4n.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-DbNEK4Yp.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-Cs7MOrg0.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-D1ziG1Pp.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-DHGV_n6i.js +0 -11
- package/dist/src/agent/context/workspace-templates/MEMORY.md +0 -33
- package/dist/src/agent/memory/access-policy.d.ts +0 -12
- package/dist/src/agent/memory/access-policy.js +0 -44
- package/dist/src/agent/memory/access-policy.js.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { resolveEffectiveAgentManifestForSession } from "../../config/agent-profile.js";
|
|
2
1
|
//#region src/agent/background-review/settings.ts
|
|
3
2
|
const DEFAULT_SETTINGS = {
|
|
4
3
|
enabled: false,
|
|
@@ -7,23 +6,17 @@ const DEFAULT_SETTINGS = {
|
|
|
7
6
|
maxHistoryMessages: 80,
|
|
8
7
|
maxDurationMs: 12e4
|
|
9
8
|
};
|
|
10
|
-
function resolveBackgroundReviewSettings(config,
|
|
9
|
+
function resolveBackgroundReviewSettings(config, _sessionKey) {
|
|
11
10
|
if (!config) return DEFAULT_SETTINGS;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
maxHistoryMessages: understanding?.maxHistoryMessages ?? DEFAULT_SETTINGS.maxHistoryMessages,
|
|
22
|
-
maxDurationMs: understanding?.maxDurationMs ?? DEFAULT_SETTINGS.maxDurationMs
|
|
23
|
-
};
|
|
24
|
-
} catch {
|
|
25
|
-
return DEFAULT_SETTINGS;
|
|
26
|
-
}
|
|
11
|
+
const { memory, understanding } = config.userContext;
|
|
12
|
+
const writeCapable = memory.mode === "confirmWrite" || memory.mode === "auto";
|
|
13
|
+
return {
|
|
14
|
+
enabled: config.userContext.enabled && writeCapable && understanding.enabled,
|
|
15
|
+
adaptiveCadence: understanding.adaptiveCadence,
|
|
16
|
+
reviewIntervalTurns: understanding.reviewIntervalTurns,
|
|
17
|
+
maxHistoryMessages: understanding.maxHistoryMessages,
|
|
18
|
+
maxDurationMs: understanding.maxDurationMs
|
|
19
|
+
};
|
|
27
20
|
}
|
|
28
21
|
//#endregion
|
|
29
22
|
export { resolveBackgroundReviewSettings };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","names":[],"sources":["../../../../src/agent/background-review/settings.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\
|
|
1
|
+
{"version":3,"file":"settings.js","names":[],"sources":["../../../../src/agent/background-review/settings.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\n\nexport interface BackgroundReviewSettings {\n enabled: boolean;\n agentId?: string;\n adaptiveCadence: boolean;\n reviewIntervalTurns: number;\n maxHistoryMessages: number;\n maxDurationMs: number;\n}\n\nconst DEFAULT_SETTINGS: BackgroundReviewSettings = {\n enabled: false,\n adaptiveCadence: true,\n reviewIntervalTurns: 10,\n maxHistoryMessages: 80,\n maxDurationMs: 120_000,\n};\n\nexport function resolveBackgroundReviewSettings(\n config: Config | undefined,\n _sessionKey?: string,\n): BackgroundReviewSettings {\n if (!config) return DEFAULT_SETTINGS;\n\n const { memory, understanding } = config.userContext;\n const writeCapable = memory.mode === 'confirmWrite' || memory.mode === 'auto';\n return {\n enabled: config.userContext.enabled && writeCapable && understanding.enabled,\n adaptiveCadence: understanding.adaptiveCadence,\n reviewIntervalTurns: understanding.reviewIntervalTurns,\n maxHistoryMessages: understanding.maxHistoryMessages,\n maxDurationMs: understanding.maxDurationMs,\n };\n}\n"],"mappings":";AAWA,MAAM,mBAA6C;CACjD,SAAS;CACT,iBAAiB;CACjB,qBAAqB;CACrB,oBAAoB;CACpB,eAAe;CAChB;AAED,SAAgB,gCACd,QACA,aAC0B;AAC1B,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,EAAE,QAAQ,kBAAkB,OAAO;CACzC,MAAM,eAAe,OAAO,SAAS,kBAAkB,OAAO,SAAS;AACvE,QAAO;EACL,SAAS,OAAO,YAAY,WAAW,gBAAgB,cAAc;EACrE,iBAAiB,cAAc;EAC/B,qBAAqB,cAAc;EACnC,oBAAoB,cAAc;EAClC,eAAe,cAAc;EAC9B"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { WorkspaceBootstrapFile } from './types.js';
|
|
2
|
-
/** Subagent and cron sessions
|
|
2
|
+
/** Subagent and cron sessions load only the minimal identity and instruction profile. */
|
|
3
3
|
export declare function filterBootstrapFilesForSession(files: WorkspaceBootstrapFile[], sessionKey?: string): WorkspaceBootstrapFile[];
|
|
@@ -12,7 +12,7 @@ const MINIMAL_BOOTSTRAP_ALLOWLIST = new Set([
|
|
|
12
12
|
DEFAULT_IDENTITY_FILENAME,
|
|
13
13
|
USER_PROFILE_FILENAME
|
|
14
14
|
]);
|
|
15
|
-
/** Subagent and cron sessions
|
|
15
|
+
/** Subagent and cron sessions load only the minimal identity and instruction profile. */
|
|
16
16
|
function filterBootstrapFilesForSession(files, sessionKey) {
|
|
17
17
|
if (!sessionKey || !isSubagentSessionKey(sessionKey) && !isCronSessionKey(sessionKey)) return files;
|
|
18
18
|
return files.filter((file) => MINIMAL_BOOTSTRAP_ALLOWLIST.has(file.name));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter-bootstrap-files.js","names":[],"sources":["../../../../src/agent/bootstrap/filter-bootstrap-files.ts"],"sourcesContent":["import { USER_PROFILE_FILENAME } from '../../config/paths.js';\nimport { isCronSessionKey, isSubagentSessionKey } from '../../routing/session-key.js';\nimport {\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n DEFAULT_SOUL_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n} from '../context/workspace.js';\nimport type { WorkspaceBootstrapFile } from './types.js';\n\nconst MINIMAL_BOOTSTRAP_ALLOWLIST = new Set<string>([\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n DEFAULT_SOUL_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n USER_PROFILE_FILENAME,\n]);\n\n/** Subagent and cron sessions
|
|
1
|
+
{"version":3,"file":"filter-bootstrap-files.js","names":[],"sources":["../../../../src/agent/bootstrap/filter-bootstrap-files.ts"],"sourcesContent":["import { USER_PROFILE_FILENAME } from '../../config/paths.js';\nimport { isCronSessionKey, isSubagentSessionKey } from '../../routing/session-key.js';\nimport {\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n DEFAULT_SOUL_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n} from '../context/workspace.js';\nimport type { WorkspaceBootstrapFile } from './types.js';\n\nconst MINIMAL_BOOTSTRAP_ALLOWLIST = new Set<string>([\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n DEFAULT_SOUL_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n USER_PROFILE_FILENAME,\n]);\n\n/** Subagent and cron sessions load only the minimal identity and instruction profile. */\nexport function filterBootstrapFilesForSession(\n files: WorkspaceBootstrapFile[],\n sessionKey?: string,\n): WorkspaceBootstrapFile[] {\n if (!sessionKey || (!isSubagentSessionKey(sessionKey) && !isCronSessionKey(sessionKey))) {\n return files;\n }\n return files.filter((file) => MINIMAL_BOOTSTRAP_ALLOWLIST.has(file.name));\n}\n"],"mappings":";;;;;YAA8D;kBACwB;AAStF,MAAM,8BAA8B,IAAI,IAAY;CAClD;CACA;CACA;CACA;CACA;CACD,CAAC;;AAGF,SAAgB,+BACd,OACA,YAC0B;AAC1B,KAAI,CAAC,cAAe,CAAC,qBAAqB,WAAW,IAAI,CAAC,iBAAiB,WAAW,CACpF,QAAO;AAET,QAAO,MAAM,QAAQ,SAAS,4BAA4B,IAAI,KAAK,KAAK,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { USER_PROFILE_FILENAME, init_paths } from "../../config/paths.js";
|
|
2
|
-
import { DEFAULT_AGENTS_FILENAME, DEFAULT_HEARTBEAT_FILENAME, DEFAULT_IDENTITY_FILENAME,
|
|
2
|
+
import { DEFAULT_AGENTS_FILENAME, DEFAULT_HEARTBEAT_FILENAME, DEFAULT_IDENTITY_FILENAME, DEFAULT_SOUL_FILENAME, DEFAULT_TOOLS_FILENAME, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET, stripFrontMatter } from "../context/workspace.js";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
//#region src/agent/bootstrap/load-bootstrap-files.ts
|
|
@@ -9,8 +9,7 @@ const PROFILE_LOAD_ORDER = [
|
|
|
9
9
|
DEFAULT_SOUL_FILENAME,
|
|
10
10
|
DEFAULT_TOOLS_FILENAME,
|
|
11
11
|
DEFAULT_IDENTITY_FILENAME,
|
|
12
|
-
DEFAULT_HEARTBEAT_FILENAME
|
|
13
|
-
DEFAULT_MEMORY_FILENAME
|
|
12
|
+
DEFAULT_HEARTBEAT_FILENAME
|
|
14
13
|
];
|
|
15
14
|
function readProfileFile(filePath) {
|
|
16
15
|
if (!existsSync(filePath)) return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-bootstrap-files.js","names":[],"sources":["../../../../src/agent/bootstrap/load-bootstrap-files.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\nimport { USER_PROFILE_FILENAME } from '../../config/paths.js';\nimport { stripFrontMatter } from '../context/workspace.js';\nimport {\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_HEARTBEAT_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n
|
|
1
|
+
{"version":3,"file":"load-bootstrap-files.js","names":[],"sources":["../../../../src/agent/bootstrap/load-bootstrap-files.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\nimport { USER_PROFILE_FILENAME } from '../../config/paths.js';\nimport { stripFrontMatter } from '../context/workspace.js';\nimport {\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_HEARTBEAT_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n DEFAULT_SOUL_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET,\n} from '../context/workspace.js';\nimport type { BootstrapFileName, WorkspaceBootstrapFile } from './types.js';\n\nconst PROFILE_LOAD_ORDER: BootstrapFileName[] = [\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_SOUL_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n DEFAULT_HEARTBEAT_FILENAME,\n];\n\nfunction readProfileFile(filePath: string): string | null {\n if (!existsSync(filePath)) {\n return null;\n }\n try {\n return stripFrontMatter(readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n}\n\nexport function loadUserProfileBootstrapFile(userProfilePath: string | undefined): WorkspaceBootstrapFile[] {\n if (!userProfilePath) {\n return [];\n }\n const filePath = resolve(userProfilePath);\n const content = readProfileFile(filePath);\n return content !== null\n ? [{ name: USER_PROFILE_FILENAME, path: filePath, content, missing: false }]\n : [];\n}\n\n/**\n * Load bootstrap profile Markdown from `agents/<id>/profile/`.\n * Required files emit missing markers; optional files are omitted when absent.\n */\nexport function loadProfileBootstrapFiles(profileDir: string): WorkspaceBootstrapFile[] {\n const resolvedDir = resolve(profileDir);\n const result: WorkspaceBootstrapFile[] = [];\n\n for (const name of PROFILE_LOAD_ORDER) {\n const filePath = join(resolvedDir, name);\n\n const content = readProfileFile(filePath);\n if (content !== null) {\n result.push({ name, path: filePath, content, missing: false });\n } else if (REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET.has(name)) {\n result.push({ name, path: filePath, missing: true });\n }\n }\n\n return result;\n}\n"],"mappings":";;;;;YAG8D;AAY9D,MAAM,qBAA0C;CAC9C;CACA;CACA;CACA;CACA;CACD;AAED,SAAS,gBAAgB,UAAiC;AACxD,KAAI,CAAC,WAAW,SAAS,CACvB,QAAO;AAET,KAAI;AACF,SAAO,iBAAiB,aAAa,UAAU,QAAQ,CAAC;SAClD;AACN,SAAO;;;AAIX,SAAgB,6BAA6B,iBAA+D;AAC1G,KAAI,CAAC,gBACH,QAAO,EAAE;CAEX,MAAM,WAAW,QAAQ,gBAAgB;CACzC,MAAM,UAAU,gBAAgB,SAAS;AACzC,QAAO,YAAY,OACf,CAAC;EAAE,MAAM;EAAuB,MAAM;EAAU;EAAS,SAAS;EAAO,CAAC,GAC1E,EAAE;;;;;;AAOR,SAAgB,0BAA0B,YAA8C;CACtF,MAAM,cAAc,QAAQ,WAAW;CACvC,MAAM,SAAmC,EAAE;AAE3C,MAAK,MAAM,QAAQ,oBAAoB;EACrC,MAAM,WAAW,KAAK,aAAa,KAAK;EAExC,MAAM,UAAU,gBAAgB,SAAS;AACzC,MAAI,YAAY,KACd,QAAO,KAAK;GAAE;GAAM,MAAM;GAAU;GAAS,SAAS;GAAO,CAAC;WACrD,yCAAyC,IAAI,KAAK,CAC3D,QAAO,KAAK;GAAE;GAAM,MAAM;GAAU,SAAS;GAAM,CAAC;;AAIxD,QAAO"}
|
|
@@ -10,8 +10,8 @@ import { execFile } from "node:child_process";
|
|
|
10
10
|
import { createHash, randomBytes } from "node:crypto";
|
|
11
11
|
import { promisify } from "node:util";
|
|
12
12
|
import { Readable } from "node:stream";
|
|
13
|
-
import lockfile from "proper-lockfile";
|
|
14
13
|
import { pipeline } from "node:stream/promises";
|
|
14
|
+
import lockfile from "proper-lockfile";
|
|
15
15
|
//#region src/agent/code-intelligence/binary.ts
|
|
16
16
|
init_paths();
|
|
17
17
|
init_logger();
|
|
@@ -16,4 +16,18 @@ export declare function formatActiveProjectContextForPrompt(input: {
|
|
|
16
16
|
content: string;
|
|
17
17
|
updatedAt: string;
|
|
18
18
|
}>;
|
|
19
|
+
localApp?: {
|
|
20
|
+
extensionId: string;
|
|
21
|
+
draftVersion: number;
|
|
22
|
+
activeVersion?: number;
|
|
23
|
+
installationState: 'not_installed' | 'installed';
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
retainedVersions: number[];
|
|
26
|
+
latestAcceptance?: {
|
|
27
|
+
status: 'passed' | 'failed';
|
|
28
|
+
sourceHash: string;
|
|
29
|
+
failures: string[];
|
|
30
|
+
createdAt: number;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
19
33
|
}): string;
|
|
@@ -2,6 +2,7 @@ import { listMemoryRecords } from "../../storage/sqlite/memory-records-repositor
|
|
|
2
2
|
import "../../storage/sqlite/index.js";
|
|
3
3
|
import { GoalService } from "../../goals/goal-service.js";
|
|
4
4
|
import "../../goals/index.js";
|
|
5
|
+
import { LocalAppStore } from "../../local-apps/store.js";
|
|
5
6
|
import { ProjectStore } from "../../projects/project-store.js";
|
|
6
7
|
import { getProjectForSession, getProjectWorkspacePathForSession } from "../../projects/workspace.js";
|
|
7
8
|
import { sanitizeForPromptLiteral } from "../prompt/sanitize-for-prompt.js";
|
|
@@ -29,6 +30,9 @@ function formatGoal(goal) {
|
|
|
29
30
|
function buildActiveProjectContextForPrompt(sessionKey) {
|
|
30
31
|
const project = getProjectForSession(sessionKey);
|
|
31
32
|
if (!project) return void 0;
|
|
33
|
+
const localAppStore = new LocalAppStore();
|
|
34
|
+
const localApp = localAppStore.findByProjectId(project.id);
|
|
35
|
+
const latestAcceptance = localApp ? localAppStore.listAcceptanceRuns(localApp.id, 1)[0] : void 0;
|
|
32
36
|
return formatActiveProjectContextForPrompt({
|
|
33
37
|
project,
|
|
34
38
|
workspacePath: getProjectWorkspacePathForSession(sessionKey) ?? project.workspaceRoot,
|
|
@@ -47,7 +51,21 @@ function buildActiveProjectContextForPrompt(sessionKey) {
|
|
|
47
51
|
projectId: project.id,
|
|
48
52
|
status: "active",
|
|
49
53
|
limit: MAX_MEMORY
|
|
50
|
-
})
|
|
54
|
+
}),
|
|
55
|
+
localApp: localApp ? {
|
|
56
|
+
extensionId: localApp.extensionId,
|
|
57
|
+
draftVersion: localApp.draftVersion,
|
|
58
|
+
activeVersion: localApp.activeVersion,
|
|
59
|
+
installationState: localApp.installationState,
|
|
60
|
+
enabled: localApp.enabled,
|
|
61
|
+
retainedVersions: localAppStore.listReleases(localApp.id).map((release) => release.version),
|
|
62
|
+
latestAcceptance: latestAcceptance ? {
|
|
63
|
+
status: latestAcceptance.status,
|
|
64
|
+
sourceHash: latestAcceptance.sourceHash,
|
|
65
|
+
failures: latestAcceptance.checks.filter((check) => check.status === "failed").map((check) => check.message),
|
|
66
|
+
createdAt: latestAcceptance.createdAt
|
|
67
|
+
} : void 0
|
|
68
|
+
} : void 0
|
|
51
69
|
});
|
|
52
70
|
}
|
|
53
71
|
function formatActiveProjectContextForPrompt(input) {
|
|
@@ -66,6 +84,10 @@ function formatActiveProjectContextForPrompt(input) {
|
|
|
66
84
|
if (brief) lines.push("", "## Brief", brief);
|
|
67
85
|
const instructions = truncateText(input.project.instructions);
|
|
68
86
|
if (instructions) lines.push("", "## Project Instructions", "Follow these project-level instructions unless they conflict with higher-priority system, developer, safety, or direct user instructions.", instructions);
|
|
87
|
+
if (input.localApp) {
|
|
88
|
+
const retained = input.localApp.retainedVersions.length ? input.localApp.retainedVersions.map((version) => `v${version}`).join(", ") : "none";
|
|
89
|
+
lines.push("", "## Local App Runtime", `Extension id: ${sanitizeForPromptLiteral(input.localApp.extensionId)}`, `Draft version: v${input.localApp.draftVersion}`, `Installed version: ${input.localApp.activeVersion ? `v${input.localApp.activeVersion}` : "none"}`, `Installation: ${input.localApp.installationState} | enabled=${String(input.localApp.enabled)}`, `Retained releases: ${retained}`, input.localApp.latestAcceptance ? `Latest acceptance: ${input.localApp.latestAcceptance.status} | source=${sanitizeForPromptLiteral(input.localApp.latestAcceptance.sourceHash.slice(0, 12))} | checked=${new Date(input.localApp.latestAcceptance.createdAt).toISOString()}` : "Latest acceptance: none", ...input.localApp.latestAcceptance?.failures.map((failure) => `Acceptance failure: ${sanitizeForPromptLiteral(truncateText(failure, 240) ?? "")}`) ?? [], "Edit only the Project draft. Do not modify installed release artifacts directly; installation and rollback are host-managed.");
|
|
90
|
+
}
|
|
69
91
|
lines.push("", "## Active Goals");
|
|
70
92
|
if (input.activeGoals.length === 0) lines.push("- None recorded.");
|
|
71
93
|
else lines.push(...input.activeGoals.map(formatGoal));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-context.js","names":[],"sources":["../../../../src/agent/context/project-context.ts"],"sourcesContent":["import { GoalService, type GoalWithDetails } from '../../goals/index.js';\nimport {\n getProjectForSession,\n getProjectWorkspacePathForSession,\n} from '../../projects/workspace.js';\nimport type { Project } from '../../projects/types.js';\nimport { ProjectStore } from '../../projects/project-store.js';\nimport { listMemoryRecords } from '../../storage/sqlite/index.js';\nimport { sanitizeForPromptLiteral } from '../prompt/sanitize-for-prompt.js';\n\nconst MAX_TEXT = 1200;\nconst MAX_GOALS = 5;\nconst MAX_SESSIONS = 5;\nconst MAX_MEMORY = 5;\n\nfunction truncateText(value: string | undefined, max = MAX_TEXT): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n if (trimmed.length <= max) return trimmed;\n return `${trimmed.slice(0, max - 1).trimEnd()}...`;\n}\n\nfunction formatGoal(goal: GoalWithDetails): string {\n const parts = [`- ${sanitizeForPromptLiteral(goal.title)}`, `status=${goal.status}`, `priority=${goal.priority}`];\n if (goal.nextAction?.trim()) {\n parts.push(`next=${sanitizeForPromptLiteral(truncateText(goal.nextAction, 200) ?? '')}`);\n }\n if (goal.blockedReason?.trim()) {\n parts.push(`blocked=${sanitizeForPromptLiteral(truncateText(goal.blockedReason, 200) ?? '')}`);\n }\n return parts.join(' | ');\n}\n\nexport function buildActiveProjectContextForPrompt(sessionKey: string): string | undefined {\n const project = getProjectForSession(sessionKey);\n if (!project) return undefined;\n return formatActiveProjectContextForPrompt({\n project,\n workspacePath: getProjectWorkspacePathForSession(sessionKey) ?? project.workspaceRoot,\n activeGoals: new GoalService().list({\n projectId: project.id,\n status: ['active', 'paused', 'blocked', 'needs_input'],\n limit: MAX_GOALS,\n }),\n recentSessions: new ProjectStore().getRecentSessions(project.id, MAX_SESSIONS),\n memoryRecords: listMemoryRecords({\n projectId: project.id,\n status: 'active',\n limit: MAX_MEMORY,\n }),\n });\n}\n\nexport function formatActiveProjectContextForPrompt(input: {\n project: Project;\n workspacePath?: string;\n activeGoals: GoalWithDetails[];\n recentSessions: Array<{ key: string; name?: string; updatedAt: string; agentId: string }>;\n memoryRecords?: Array<{ kind: string; content: string; updatedAt: string }>;\n}): string {\n const lines: string[] = [\n '# Active Project',\n '',\n `Project: ${sanitizeForPromptLiteral(input.project.name)}`,\n `Status: ${input.project.status}`,\n ];\n\n const workspace = input.workspacePath?.trim();\n if (workspace) {\n lines.push(`Workspace root: ${sanitizeForPromptLiteral(workspace)}`);\n lines.push('This project session uses the project workspace. Do not switch working directories unless the user moves the session to another project.');\n }\n\n const brief = truncateText(input.project.brief ?? input.project.description);\n if (brief) {\n lines.push('', '## Brief', brief);\n }\n\n const instructions = truncateText(input.project.instructions);\n if (instructions) {\n lines.push(\n '',\n '## Project Instructions',\n 'Follow these project-level instructions unless they conflict with higher-priority system, developer, safety, or direct user instructions.',\n instructions,\n );\n }\n\n lines.push('', '## Active Goals');\n if (input.activeGoals.length === 0) {\n lines.push('- None recorded.');\n } else {\n lines.push(...input.activeGoals.map(formatGoal));\n }\n\n lines.push('', '## Recent Project Sessions');\n if (input.recentSessions.length === 0) {\n lines.push('- None recorded.');\n } else {\n for (const session of input.recentSessions) {\n const label = sanitizeForPromptLiteral(session.name?.trim() || session.key);\n lines.push(`- ${label} | agent=${sanitizeForPromptLiteral(session.agentId)} | updated=${sanitizeForPromptLiteral(session.updatedAt)}`);\n }\n }\n\n lines.push('', '## Project Memory');\n const memoryRecords = input.memoryRecords ?? [];\n if (memoryRecords.length === 0) {\n lines.push('- None recorded.');\n } else {\n for (const record of memoryRecords) {\n const content = sanitizeForPromptLiteral(truncateText(record.content, 240) ?? '');\n lines.push(`- ${sanitizeForPromptLiteral(record.kind)} | updated=${sanitizeForPromptLiteral(record.updatedAt)} | ${content}`);\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,WAAW;AACjB,MAAM,YAAY;AAClB,MAAM,eAAe;AACrB,MAAM,aAAa;AAEnB,SAAS,aAAa,OAA2B,MAAM,UAA8B;CACnF,MAAM,UAAU,OAAO,MAAM;AAC7B,KAAI,CAAC,QAAS,QAAO,KAAA;AACrB,KAAI,QAAQ,UAAU,IAAK,QAAO;AAClC,QAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC;;AAGhD,SAAS,WAAW,MAA+B;CACjD,MAAM,QAAQ;EAAC,KAAK,yBAAyB,KAAK,MAAM;EAAI,UAAU,KAAK;EAAU,YAAY,KAAK;EAAW;AACjH,KAAI,KAAK,YAAY,MAAM,CACzB,OAAM,KAAK,QAAQ,yBAAyB,aAAa,KAAK,YAAY,IAAI,IAAI,GAAG,GAAG;AAE1F,KAAI,KAAK,eAAe,MAAM,CAC5B,OAAM,KAAK,WAAW,yBAAyB,aAAa,KAAK,eAAe,IAAI,IAAI,GAAG,GAAG;AAEhG,QAAO,MAAM,KAAK,MAAM;;AAG1B,SAAgB,mCAAmC,YAAwC;CACzF,MAAM,UAAU,qBAAqB,WAAW;AAChD,KAAI,CAAC,QAAS,QAAO,KAAA;AACrB,QAAO,oCAAoC;EACzC;EACA,eAAe,kCAAkC,WAAW,IAAI,QAAQ;EACxE,aAAa,IAAI,aAAa,CAAC,KAAK;GAClC,WAAW,QAAQ;GACnB,QAAQ;IAAC;IAAU;IAAU;IAAW;IAAc;GACtD,OAAO;GACR,CAAC;EACF,gBAAgB,IAAI,cAAc,CAAC,kBAAkB,QAAQ,IAAI,aAAa;EAC9E,eAAe,kBAAkB;GAC/B,WAAW,QAAQ;GACnB,QAAQ;GACR,OAAO;GACR,CAAC;EACH,CAAC;;AAGJ,SAAgB,oCAAoC,OAMzC;CACT,MAAM,QAAkB;EACtB;EACA;EACA,YAAY,yBAAyB,MAAM,QAAQ,KAAK;EACxD,WAAW,MAAM,QAAQ;EAC1B;CAED,MAAM,YAAY,MAAM,eAAe,MAAM;AAC7C,KAAI,WAAW;AACb,QAAM,KAAK,mBAAmB,yBAAyB,UAAU,GAAG;AACpE,QAAM,KAAK,2IAA2I;;CAGxJ,MAAM,QAAQ,aAAa,MAAM,QAAQ,SAAS,MAAM,QAAQ,YAAY;AAC5E,KAAI,MACF,OAAM,KAAK,IAAI,YAAY,MAAM;CAGnC,MAAM,eAAe,aAAa,MAAM,QAAQ,aAAa;AAC7D,KAAI,aACF,OAAM,KACJ,IACA,2BACA,6IACA,aACD;AAGH,OAAM,KAAK,IAAI,kBAAkB;AACjC,KAAI,MAAM,YAAY,WAAW,EAC/B,OAAM,KAAK,mBAAmB;KAE9B,OAAM,KAAK,GAAG,MAAM,YAAY,IAAI,WAAW,CAAC;AAGlD,OAAM,KAAK,IAAI,6BAA6B;AAC5C,KAAI,MAAM,eAAe,WAAW,EAClC,OAAM,KAAK,mBAAmB;KAE9B,MAAK,MAAM,WAAW,MAAM,gBAAgB;EAC1C,MAAM,QAAQ,yBAAyB,QAAQ,MAAM,MAAM,IAAI,QAAQ,IAAI;AAC3E,QAAM,KAAK,KAAK,MAAM,WAAW,yBAAyB,QAAQ,QAAQ,CAAC,aAAa,yBAAyB,QAAQ,UAAU,GAAG;;AAI1I,OAAM,KAAK,IAAI,oBAAoB;CACnC,MAAM,gBAAgB,MAAM,iBAAiB,EAAE;AAC/C,KAAI,cAAc,WAAW,EAC3B,OAAM,KAAK,mBAAmB;KAE9B,MAAK,MAAM,UAAU,eAAe;EAClC,MAAM,UAAU,yBAAyB,aAAa,OAAO,SAAS,IAAI,IAAI,GAAG;AACjF,QAAM,KAAK,KAAK,yBAAyB,OAAO,KAAK,CAAC,aAAa,yBAAyB,OAAO,UAAU,CAAC,KAAK,UAAU;;AAIjI,QAAO,MAAM,KAAK,KAAK"}
|
|
1
|
+
{"version":3,"file":"project-context.js","names":[],"sources":["../../../../src/agent/context/project-context.ts"],"sourcesContent":["import { GoalService, type GoalWithDetails } from '../../goals/index.js';\nimport { LocalAppStore } from '../../local-apps/store.js';\nimport {\n getProjectForSession,\n getProjectWorkspacePathForSession,\n} from '../../projects/workspace.js';\nimport type { Project } from '../../projects/types.js';\nimport { ProjectStore } from '../../projects/project-store.js';\nimport { listMemoryRecords } from '../../storage/sqlite/index.js';\nimport { sanitizeForPromptLiteral } from '../prompt/sanitize-for-prompt.js';\n\nconst MAX_TEXT = 1200;\nconst MAX_GOALS = 5;\nconst MAX_SESSIONS = 5;\nconst MAX_MEMORY = 5;\n\nfunction truncateText(value: string | undefined, max = MAX_TEXT): string | undefined {\n const trimmed = value?.trim();\n if (!trimmed) return undefined;\n if (trimmed.length <= max) return trimmed;\n return `${trimmed.slice(0, max - 1).trimEnd()}...`;\n}\n\nfunction formatGoal(goal: GoalWithDetails): string {\n const parts = [`- ${sanitizeForPromptLiteral(goal.title)}`, `status=${goal.status}`, `priority=${goal.priority}`];\n if (goal.nextAction?.trim()) {\n parts.push(`next=${sanitizeForPromptLiteral(truncateText(goal.nextAction, 200) ?? '')}`);\n }\n if (goal.blockedReason?.trim()) {\n parts.push(`blocked=${sanitizeForPromptLiteral(truncateText(goal.blockedReason, 200) ?? '')}`);\n }\n return parts.join(' | ');\n}\n\nexport function buildActiveProjectContextForPrompt(sessionKey: string): string | undefined {\n const project = getProjectForSession(sessionKey);\n if (!project) return undefined;\n const localAppStore = new LocalAppStore();\n const localApp = localAppStore.findByProjectId(project.id);\n const latestAcceptance = localApp ? localAppStore.listAcceptanceRuns(localApp.id, 1)[0] : undefined;\n return formatActiveProjectContextForPrompt({\n project,\n workspacePath: getProjectWorkspacePathForSession(sessionKey) ?? project.workspaceRoot,\n activeGoals: new GoalService().list({\n projectId: project.id,\n status: ['active', 'paused', 'blocked', 'needs_input'],\n limit: MAX_GOALS,\n }),\n recentSessions: new ProjectStore().getRecentSessions(project.id, MAX_SESSIONS),\n memoryRecords: listMemoryRecords({\n projectId: project.id,\n status: 'active',\n limit: MAX_MEMORY,\n }),\n localApp: localApp ? {\n extensionId: localApp.extensionId,\n draftVersion: localApp.draftVersion,\n activeVersion: localApp.activeVersion,\n installationState: localApp.installationState,\n enabled: localApp.enabled,\n retainedVersions: localAppStore.listReleases(localApp.id).map((release) => release.version),\n latestAcceptance: latestAcceptance ? {\n status: latestAcceptance.status,\n sourceHash: latestAcceptance.sourceHash,\n failures: latestAcceptance.checks\n .filter((check) => check.status === 'failed')\n .map((check) => check.message),\n createdAt: latestAcceptance.createdAt,\n } : undefined,\n } : undefined,\n });\n}\n\nexport function formatActiveProjectContextForPrompt(input: {\n project: Project;\n workspacePath?: string;\n activeGoals: GoalWithDetails[];\n recentSessions: Array<{ key: string; name?: string; updatedAt: string; agentId: string }>;\n memoryRecords?: Array<{ kind: string; content: string; updatedAt: string }>;\n localApp?: {\n extensionId: string;\n draftVersion: number;\n activeVersion?: number;\n installationState: 'not_installed' | 'installed';\n enabled: boolean;\n retainedVersions: number[];\n latestAcceptance?: {\n status: 'passed' | 'failed';\n sourceHash: string;\n failures: string[];\n createdAt: number;\n };\n };\n}): string {\n const lines: string[] = [\n '# Active Project',\n '',\n `Project: ${sanitizeForPromptLiteral(input.project.name)}`,\n `Status: ${input.project.status}`,\n ];\n\n const workspace = input.workspacePath?.trim();\n if (workspace) {\n lines.push(`Workspace root: ${sanitizeForPromptLiteral(workspace)}`);\n lines.push('This project session uses the project workspace. Do not switch working directories unless the user moves the session to another project.');\n }\n\n const brief = truncateText(input.project.brief ?? input.project.description);\n if (brief) {\n lines.push('', '## Brief', brief);\n }\n\n const instructions = truncateText(input.project.instructions);\n if (instructions) {\n lines.push(\n '',\n '## Project Instructions',\n 'Follow these project-level instructions unless they conflict with higher-priority system, developer, safety, or direct user instructions.',\n instructions,\n );\n }\n\n if (input.localApp) {\n const retained = input.localApp.retainedVersions.length\n ? input.localApp.retainedVersions.map((version) => `v${version}`).join(', ')\n : 'none';\n lines.push(\n '',\n '## Local App Runtime',\n `Extension id: ${sanitizeForPromptLiteral(input.localApp.extensionId)}`,\n `Draft version: v${input.localApp.draftVersion}`,\n `Installed version: ${input.localApp.activeVersion ? `v${input.localApp.activeVersion}` : 'none'}`,\n `Installation: ${input.localApp.installationState} | enabled=${String(input.localApp.enabled)}`,\n `Retained releases: ${retained}`,\n input.localApp.latestAcceptance\n ? `Latest acceptance: ${input.localApp.latestAcceptance.status} | source=${sanitizeForPromptLiteral(input.localApp.latestAcceptance.sourceHash.slice(0, 12))} | checked=${new Date(input.localApp.latestAcceptance.createdAt).toISOString()}`\n : 'Latest acceptance: none',\n ...(input.localApp.latestAcceptance?.failures.map((failure) => (\n `Acceptance failure: ${sanitizeForPromptLiteral(truncateText(failure, 240) ?? '')}`\n )) ?? []),\n 'Edit only the Project draft. Do not modify installed release artifacts directly; installation and rollback are host-managed.',\n );\n }\n\n lines.push('', '## Active Goals');\n if (input.activeGoals.length === 0) {\n lines.push('- None recorded.');\n } else {\n lines.push(...input.activeGoals.map(formatGoal));\n }\n\n lines.push('', '## Recent Project Sessions');\n if (input.recentSessions.length === 0) {\n lines.push('- None recorded.');\n } else {\n for (const session of input.recentSessions) {\n const label = sanitizeForPromptLiteral(session.name?.trim() || session.key);\n lines.push(`- ${label} | agent=${sanitizeForPromptLiteral(session.agentId)} | updated=${sanitizeForPromptLiteral(session.updatedAt)}`);\n }\n }\n\n lines.push('', '## Project Memory');\n const memoryRecords = input.memoryRecords ?? [];\n if (memoryRecords.length === 0) {\n lines.push('- None recorded.');\n } else {\n for (const record of memoryRecords) {\n const content = sanitizeForPromptLiteral(truncateText(record.content, 240) ?? '');\n lines.push(`- ${sanitizeForPromptLiteral(record.kind)} | updated=${sanitizeForPromptLiteral(record.updatedAt)} | ${content}`);\n }\n }\n\n return lines.join('\\n');\n}\n"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ This workspace is the agent's working area. Treat it as user-owned state.
|
|
|
11
11
|
|
|
12
12
|
## Startup Context
|
|
13
13
|
|
|
14
|
-
Use runtime-provided startup context first. It may already include the
|
|
14
|
+
Use runtime-provided startup context first. It may already include the shared user context and profile files such as `SOUL.md`, `IDENTITY.md`, `TOOLS.md`, `AGENTS.md`, and `HEARTBEAT.md`.
|
|
15
15
|
|
|
16
16
|
Do not manually reread startup files unless:
|
|
17
17
|
|
|
@@ -9,8 +9,7 @@ export declare const DEFAULT_SOUL_FILENAME = "SOUL.md";
|
|
|
9
9
|
export declare const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
|
10
10
|
export declare const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
|
|
11
11
|
export declare const DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
|
|
12
|
-
export
|
|
13
|
-
export type AgentProfileMarkdownFilename = typeof DEFAULT_AGENTS_FILENAME | typeof DEFAULT_SOUL_FILENAME | typeof DEFAULT_TOOLS_FILENAME | typeof DEFAULT_IDENTITY_FILENAME | typeof DEFAULT_HEARTBEAT_FILENAME | typeof DEFAULT_MEMORY_FILENAME;
|
|
12
|
+
export type AgentProfileMarkdownFilename = typeof DEFAULT_AGENTS_FILENAME | typeof DEFAULT_SOUL_FILENAME | typeof DEFAULT_TOOLS_FILENAME | typeof DEFAULT_IDENTITY_FILENAME | typeof DEFAULT_HEARTBEAT_FILENAME;
|
|
14
13
|
/**
|
|
15
14
|
* Order for loading profile Markdown files into the system prompt (persona / user before repo guide, etc.).
|
|
16
15
|
*/
|
|
@@ -17,7 +17,6 @@ const DEFAULT_SOUL_FILENAME = "SOUL.md";
|
|
|
17
17
|
const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
|
18
18
|
const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
|
|
19
19
|
const DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
|
|
20
|
-
const DEFAULT_MEMORY_FILENAME = "MEMORY.md";
|
|
21
20
|
/**
|
|
22
21
|
* Order for loading profile Markdown files into the system prompt (persona / user before repo guide, etc.).
|
|
23
22
|
*/
|
|
@@ -26,8 +25,7 @@ const AGENT_PROFILE_MARKDOWN_SYSTEM_FILES = [
|
|
|
26
25
|
DEFAULT_IDENTITY_FILENAME,
|
|
27
26
|
DEFAULT_TOOLS_FILENAME,
|
|
28
27
|
DEFAULT_AGENTS_FILENAME,
|
|
29
|
-
DEFAULT_HEARTBEAT_FILENAME
|
|
30
|
-
DEFAULT_MEMORY_FILENAME
|
|
28
|
+
DEFAULT_HEARTBEAT_FILENAME
|
|
31
29
|
];
|
|
32
30
|
/** Files that should be surfaced when missing. Other profile files are optional overlays. */
|
|
33
31
|
const REQUIRED_AGENT_PROFILE_MARKDOWN_FILES = [DEFAULT_SOUL_FILENAME, DEFAULT_IDENTITY_FILENAME];
|
|
@@ -166,6 +164,6 @@ function extractThinkingFromAssistantMessage(message) {
|
|
|
166
164
|
return typeof t === "string" ? t : "";
|
|
167
165
|
}
|
|
168
166
|
//#endregion
|
|
169
|
-
export { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, DEFAULT_AGENTS_FILENAME, DEFAULT_HEARTBEAT_FILENAME, DEFAULT_IDENTITY_FILENAME,
|
|
167
|
+
export { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, DEFAULT_AGENTS_FILENAME, DEFAULT_HEARTBEAT_FILENAME, DEFAULT_IDENTITY_FILENAME, DEFAULT_SOUL_FILENAME, DEFAULT_TOOLS_FILENAME, PROFILE_MARKDOWN_MAX_CHARS, REQUIRED_AGENT_PROFILE_MARKDOWN_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET, extractTextContent, extractThinkingContent, extractThinkingFromAssistantMessage, loadProfileMarkdownFiles, stripFrontMatter, toWorkspaceProfileMarkdownFile, truncateProfileMarkdownContent };
|
|
170
168
|
|
|
171
169
|
//# sourceMappingURL=workspace.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","names":[],"sources":["../../../../src/agent/context/workspace.ts"],"sourcesContent":["/**\n * Agent profile Markdown (filenames, load order, system prompt assembly) and\n * small helpers for message content extraction.\n *\n * Canonical on-disk root: `agents/<agentId>/profile/`.\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, resolve } from 'path';\nimport { createLogger } from '../../utils/logger.js';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\n\nconst log = createLogger('Workspace');\n\n// =============================================================================\n// Profile Markdown filenames & types (SOUL.md, IDENTITY.md, … under `profile/`)\n// =============================================================================\n\nexport const DEFAULT_AGENTS_FILENAME = 'AGENTS.md';\nexport const DEFAULT_SOUL_FILENAME = 'SOUL.md';\nexport const DEFAULT_TOOLS_FILENAME = 'TOOLS.md';\nexport const DEFAULT_IDENTITY_FILENAME = 'IDENTITY.md';\nexport const DEFAULT_HEARTBEAT_FILENAME = 'HEARTBEAT.md';\nexport const DEFAULT_MEMORY_FILENAME = 'MEMORY.md';\n\nexport type AgentProfileMarkdownFilename =\n | typeof DEFAULT_AGENTS_FILENAME\n | typeof DEFAULT_SOUL_FILENAME\n | typeof DEFAULT_TOOLS_FILENAME\n | typeof DEFAULT_IDENTITY_FILENAME\n | typeof DEFAULT_HEARTBEAT_FILENAME\n | typeof DEFAULT_MEMORY_FILENAME;\n\n/**\n * Order for loading profile Markdown files into the system prompt (persona / user before repo guide, etc.).\n */\nexport const AGENT_PROFILE_MARKDOWN_SYSTEM_FILES: readonly AgentProfileMarkdownFilename[] = [\n DEFAULT_SOUL_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_HEARTBEAT_FILENAME,\n DEFAULT_MEMORY_FILENAME,\n];\n\n/** Files that should be surfaced when missing. Other profile files are optional overlays. */\nexport const REQUIRED_AGENT_PROFILE_MARKDOWN_FILES: readonly AgentProfileMarkdownFilename[] = [\n DEFAULT_SOUL_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n];\n\nexport const REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET: ReadonlySet<string> = new Set(\n REQUIRED_AGENT_PROFILE_MARKDOWN_FILES,\n);\n\nexport interface WorkspaceProfileMarkdownFile {\n name: AgentProfileMarkdownFilename;\n path: string;\n content?: string;\n missing: boolean;\n}\n\n/**\n * Strip YAML front matter from markdown content.\n */\nexport function stripFrontMatter(content: string): string {\n return parseFrontmatter(content).content;\n}\n\n// =============================================================================\n// Load & truncate profile Markdown for system prompt\n// =============================================================================\n\n/** Maximum characters to inject from workspace files into system prompt */\nexport const PROFILE_MARKDOWN_MAX_CHARS = 20_000;\n\n/** Profile Markdown truncation: fraction of `maxChars` kept from the start of the file */\nconst HEAD_TRUNCATION_RATIO = 0.7;\n/** Profile Markdown truncation: fraction of `maxChars` kept from the end of the file */\nconst TAIL_TRUNCATION_RATIO = 0.2;\n\nexport interface TruncateResult {\n content: string;\n truncated: boolean;\n originalLength: number;\n}\n\n/**\n * Truncate workspace file content to prevent token overflow.\n * Keeps head (HEAD_TRUNCATION_RATIO, 70%) and tail (TAIL_TRUNCATION_RATIO, 20%) with a\n * truncation marker in between; the remainder is reserved for the marker.\n */\nexport function truncateProfileMarkdownContent(content: string, maxChars: number): TruncateResult {\n const trimmed = content.trimEnd();\n if (trimmed.length <= maxChars) {\n return {\n content: trimmed,\n truncated: false,\n originalLength: trimmed.length,\n };\n }\n\n const headChars = Math.floor(maxChars * HEAD_TRUNCATION_RATIO);\n const tailChars = Math.floor(maxChars * TAIL_TRUNCATION_RATIO);\n const head = trimmed.slice(0, headChars);\n const tail = trimmed.slice(-tailChars);\n\n const marker = [\n '',\n '[...content truncated, read the full file for complete content...]',\n `...(truncated: kept ${headChars}+${tailChars} chars of ${trimmed.length})...`,\n '',\n ].join('\\n');\n\n return {\n content: head + marker + tail,\n truncated: true,\n originalLength: trimmed.length,\n };\n}\n\nexport interface ProfileMarkdownFile {\n name: AgentProfileMarkdownFilename;\n path?: string;\n content: string;\n missing?: boolean;\n}\n\n/**\n * Convert {@link ProfileMarkdownFile} to {@link WorkspaceProfileMarkdownFile} (adds required path field).\n * @param pathFallbackDir — used when `file.path` is absent (e.g. canonical `profile/` root).\n */\nexport function toWorkspaceProfileMarkdownFile(file: ProfileMarkdownFile, pathFallbackDir: string): {\n name: AgentProfileMarkdownFilename;\n path: string;\n content?: string;\n missing: boolean;\n} {\n return {\n name: file.name,\n path: file.path || join(pathFallbackDir, file.name),\n content: file.missing ? undefined : file.content,\n missing: file.missing ?? false,\n };\n}\n\n/**\n * Load profile Markdown from `profileDir` (`agents/<agentId>/profile/`).\n */\nexport function loadProfileMarkdownFiles(profileDir: string): ProfileMarkdownFile[] {\n const files: ProfileMarkdownFile[] = [];\n let loadedCount = 0;\n let missingCount = 0;\n\n for (const filename of AGENT_PROFILE_MARKDOWN_SYSTEM_FILES) {\n const filePath = join(profileDir, filename);\n\n if (existsSync(filePath)) {\n try {\n let content = readFileSync(filePath, 'utf-8');\n\n content = stripFrontMatter(content);\n\n const result = truncateProfileMarkdownContent(content, PROFILE_MARKDOWN_MAX_CHARS);\n\n if (result.content) {\n files.push({\n name: filename,\n content: result.content,\n path: resolve(filePath),\n });\n loadedCount++;\n\n if (result.truncated) {\n log.warn(\n {\n file: filename,\n originalLength: result.originalLength,\n keptLength: result.content.length,\n },\n 'Profile Markdown truncated in system prompt (too long)',\n );\n } else {\n log.debug({ file: filename, path: filePath }, 'Profile Markdown file loaded');\n }\n }\n } catch (err) {\n log.warn({ file: filename, err }, 'Failed to load profile Markdown file');\n }\n } else if (REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET.has(filename)) {\n const hint = join(profileDir, filename);\n files.push({\n name: filename,\n content: `[MISSING] Create this file at: ${hint}`,\n missing: true,\n path: resolve(hint),\n });\n missingCount++;\n log.debug({ file: filename }, 'Profile Markdown file missing');\n }\n }\n\n log.debug({ loaded: loadedCount, missing: missingCount, profileDir }, 'Profile Markdown scan done');\n\n return files;\n}\n\n// =============================================================================\n// Message content helpers\n// =============================================================================\n\n/**\n * Extract text content from agent message content array\n */\nexport function extractTextContent(\n content: Array<{ type: string; text?: string }>\n): string {\n return content\n .filter((c) => c.type === 'text')\n .map((c) => c.text || '')\n .join('');\n}\n\nconst THINKING_BLOCK_TYPES = new Set(['thinking', 'thinking_delta', 'redacted_thinking']);\n\n/**\n * Concatenate thinking / reasoning content blocks from assistant message.content.\n * pi-ai may use `thinking` or `text` on `type: \"thinking\"` blocks.\n */\nexport function extractThinkingContent(\n content: Array<{ type: string; thinking?: string; text?: string }> | undefined\n): string {\n if (!Array.isArray(content)) return '';\n return content\n .filter((c) => THINKING_BLOCK_TYPES.has(c.type))\n .map((c) => (typeof c.thinking === 'string' ? c.thinking : c.text) || '')\n .join('');\n}\n\n/**\n * Extended thinking on the assistant message (e.g. Anthropic reasoning / pi-ai reasoning_details).\n */\nexport function extractThinkingFromAssistantMessage(\n message: { role?: string; reasoning_details?: { thinking?: string } } | undefined\n): string {\n if (!message || message.role !== 'assistant') return '';\n const t = message.reasoning_details?.thinking;\n return typeof t === 'string' ? t : '';\n}\n"],"mappings":";;;;;;;;;;;;aASqD;AAGrD,MAAM,MAAM,aAAa,YAAY;AAMrC,MAAa,0BAA0B;AACvC,MAAa,wBAAwB;AACrC,MAAa,yBAAyB;AACtC,MAAa,4BAA4B;AACzC,MAAa,6BAA6B;AAC1C,MAAa,0BAA0B;;;;AAavC,MAAa,sCAA+E;CAC1F;CACA;CACA;CACA;CACA;CACA;CACD;;AAGD,MAAa,wCAAiF,CAC5F,uBACA,0BACD;AAED,MAAa,2CAAgE,IAAI,IAC/E,sCACD;;;;AAYD,SAAgB,iBAAiB,SAAyB;AACxD,QAAO,iBAAiB,QAAQ,CAAC;;;AAQnC,MAAa,6BAA6B;;AAG1C,MAAM,wBAAwB;;AAE9B,MAAM,wBAAwB;;;;;;AAa9B,SAAgB,+BAA+B,SAAiB,UAAkC;CAChG,MAAM,UAAU,QAAQ,SAAS;AACjC,KAAI,QAAQ,UAAU,SACpB,QAAO;EACL,SAAS;EACT,WAAW;EACX,gBAAgB,QAAQ;EACzB;CAGH,MAAM,YAAY,KAAK,MAAM,WAAW,sBAAsB;CAC9D,MAAM,YAAY,KAAK,MAAM,WAAW,sBAAsB;CAC9D,MAAM,OAAO,QAAQ,MAAM,GAAG,UAAU;CACxC,MAAM,OAAO,QAAQ,MAAM,CAAC,UAAU;AAStC,QAAO;EACL,SAAS,OARI;GACb;GACA;GACA,uBAAuB,UAAU,GAAG,UAAU,YAAY,QAAQ,OAAO;GACzE;GACD,CAAC,KAAK,KAGiB,GAAG;EACzB,WAAW;EACX,gBAAgB,QAAQ;EACzB;;;;;;AAcH,SAAgB,+BAA+B,MAA2B,iBAKxE;AACA,QAAO;EACL,MAAM,KAAK;EACX,MAAM,KAAK,QAAQ,KAAK,iBAAiB,KAAK,KAAK;EACnD,SAAS,KAAK,UAAU,KAAA,IAAY,KAAK;EACzC,SAAS,KAAK,WAAW;EAC1B;;;;;AAMH,SAAgB,yBAAyB,YAA2C;CAClF,MAAM,QAA+B,EAAE;CACvC,IAAI,cAAc;CAClB,IAAI,eAAe;AAEnB,MAAK,MAAM,YAAY,qCAAqC;EAC1D,MAAM,WAAW,KAAK,YAAY,SAAS;AAE3C,MAAI,WAAW,SAAS,CACtB,KAAI;GACF,IAAI,UAAU,aAAa,UAAU,QAAQ;AAE7C,aAAU,iBAAiB,QAAQ;GAEnC,MAAM,SAAS,+BAA+B,SAAS,2BAA2B;AAElF,OAAI,OAAO,SAAS;AAClB,UAAM,KAAK;KACT,MAAM;KACN,SAAS,OAAO;KAChB,MAAM,QAAQ,SAAS;KACxB,CAAC;AACF;AAEA,QAAI,OAAO,UACT,KAAI,KACF;KACE,MAAM;KACN,gBAAgB,OAAO;KACvB,YAAY,OAAO,QAAQ;KAC5B,EACD,yDACD;QAED,KAAI,MAAM;KAAE,MAAM;KAAU,MAAM;KAAU,EAAE,+BAA+B;;WAG1E,KAAK;AACZ,OAAI,KAAK;IAAE,MAAM;IAAU;IAAK,EAAE,uCAAuC;;WAElE,yCAAyC,IAAI,SAAS,EAAE;GACjE,MAAM,OAAO,KAAK,YAAY,SAAS;AACvC,SAAM,KAAK;IACT,MAAM;IACN,SAAS,kCAAkC;IAC3C,SAAS;IACT,MAAM,QAAQ,KAAK;IACpB,CAAC;AACF;AACA,OAAI,MAAM,EAAE,MAAM,UAAU,EAAE,gCAAgC;;;AAIlE,KAAI,MAAM;EAAE,QAAQ;EAAa,SAAS;EAAc;EAAY,EAAE,6BAA6B;AAEnG,QAAO;;;;;AAUT,SAAgB,mBACd,SACQ;AACR,QAAO,QACJ,QAAQ,MAAM,EAAE,SAAS,OAAO,CAChC,KAAK,MAAM,EAAE,QAAQ,GAAG,CACxB,KAAK,GAAG;;AAGb,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAY;CAAkB;CAAoB,CAAC;;;;;AAMzF,SAAgB,uBACd,SACQ;AACR,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO;AACpC,QAAO,QACJ,QAAQ,MAAM,qBAAqB,IAAI,EAAE,KAAK,CAAC,CAC/C,KAAK,OAAO,OAAO,EAAE,aAAa,WAAW,EAAE,WAAW,EAAE,SAAS,GAAG,CACxE,KAAK,GAAG;;;;;AAMb,SAAgB,oCACd,SACQ;AACR,KAAI,CAAC,WAAW,QAAQ,SAAS,YAAa,QAAO;CACrD,MAAM,IAAI,QAAQ,mBAAmB;AACrC,QAAO,OAAO,MAAM,WAAW,IAAI"}
|
|
1
|
+
{"version":3,"file":"workspace.js","names":[],"sources":["../../../../src/agent/context/workspace.ts"],"sourcesContent":["/**\n * Agent profile Markdown (filenames, load order, system prompt assembly) and\n * small helpers for message content extraction.\n *\n * Canonical on-disk root: `agents/<agentId>/profile/`.\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { join, resolve } from 'path';\nimport { createLogger } from '../../utils/logger.js';\nimport { parseFrontmatter } from '../../markdown/frontmatter.js';\n\nconst log = createLogger('Workspace');\n\n// =============================================================================\n// Profile Markdown filenames & types (SOUL.md, IDENTITY.md, … under `profile/`)\n// =============================================================================\n\nexport const DEFAULT_AGENTS_FILENAME = 'AGENTS.md';\nexport const DEFAULT_SOUL_FILENAME = 'SOUL.md';\nexport const DEFAULT_TOOLS_FILENAME = 'TOOLS.md';\nexport const DEFAULT_IDENTITY_FILENAME = 'IDENTITY.md';\nexport const DEFAULT_HEARTBEAT_FILENAME = 'HEARTBEAT.md';\n\nexport type AgentProfileMarkdownFilename =\n | typeof DEFAULT_AGENTS_FILENAME\n | typeof DEFAULT_SOUL_FILENAME\n | typeof DEFAULT_TOOLS_FILENAME\n | typeof DEFAULT_IDENTITY_FILENAME\n | typeof DEFAULT_HEARTBEAT_FILENAME;\n\n/**\n * Order for loading profile Markdown files into the system prompt (persona / user before repo guide, etc.).\n */\nexport const AGENT_PROFILE_MARKDOWN_SYSTEM_FILES: readonly AgentProfileMarkdownFilename[] = [\n DEFAULT_SOUL_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n DEFAULT_TOOLS_FILENAME,\n DEFAULT_AGENTS_FILENAME,\n DEFAULT_HEARTBEAT_FILENAME,\n];\n\n/** Files that should be surfaced when missing. Other profile files are optional overlays. */\nexport const REQUIRED_AGENT_PROFILE_MARKDOWN_FILES: readonly AgentProfileMarkdownFilename[] = [\n DEFAULT_SOUL_FILENAME,\n DEFAULT_IDENTITY_FILENAME,\n];\n\nexport const REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET: ReadonlySet<string> = new Set(\n REQUIRED_AGENT_PROFILE_MARKDOWN_FILES,\n);\n\nexport interface WorkspaceProfileMarkdownFile {\n name: AgentProfileMarkdownFilename;\n path: string;\n content?: string;\n missing: boolean;\n}\n\n/**\n * Strip YAML front matter from markdown content.\n */\nexport function stripFrontMatter(content: string): string {\n return parseFrontmatter(content).content;\n}\n\n// =============================================================================\n// Load & truncate profile Markdown for system prompt\n// =============================================================================\n\n/** Maximum characters to inject from workspace files into system prompt */\nexport const PROFILE_MARKDOWN_MAX_CHARS = 20_000;\n\n/** Profile Markdown truncation: fraction of `maxChars` kept from the start of the file */\nconst HEAD_TRUNCATION_RATIO = 0.7;\n/** Profile Markdown truncation: fraction of `maxChars` kept from the end of the file */\nconst TAIL_TRUNCATION_RATIO = 0.2;\n\nexport interface TruncateResult {\n content: string;\n truncated: boolean;\n originalLength: number;\n}\n\n/**\n * Truncate workspace file content to prevent token overflow.\n * Keeps head (HEAD_TRUNCATION_RATIO, 70%) and tail (TAIL_TRUNCATION_RATIO, 20%) with a\n * truncation marker in between; the remainder is reserved for the marker.\n */\nexport function truncateProfileMarkdownContent(content: string, maxChars: number): TruncateResult {\n const trimmed = content.trimEnd();\n if (trimmed.length <= maxChars) {\n return {\n content: trimmed,\n truncated: false,\n originalLength: trimmed.length,\n };\n }\n\n const headChars = Math.floor(maxChars * HEAD_TRUNCATION_RATIO);\n const tailChars = Math.floor(maxChars * TAIL_TRUNCATION_RATIO);\n const head = trimmed.slice(0, headChars);\n const tail = trimmed.slice(-tailChars);\n\n const marker = [\n '',\n '[...content truncated, read the full file for complete content...]',\n `...(truncated: kept ${headChars}+${tailChars} chars of ${trimmed.length})...`,\n '',\n ].join('\\n');\n\n return {\n content: head + marker + tail,\n truncated: true,\n originalLength: trimmed.length,\n };\n}\n\nexport interface ProfileMarkdownFile {\n name: AgentProfileMarkdownFilename;\n path?: string;\n content: string;\n missing?: boolean;\n}\n\n/**\n * Convert {@link ProfileMarkdownFile} to {@link WorkspaceProfileMarkdownFile} (adds required path field).\n * @param pathFallbackDir — used when `file.path` is absent (e.g. canonical `profile/` root).\n */\nexport function toWorkspaceProfileMarkdownFile(file: ProfileMarkdownFile, pathFallbackDir: string): {\n name: AgentProfileMarkdownFilename;\n path: string;\n content?: string;\n missing: boolean;\n} {\n return {\n name: file.name,\n path: file.path || join(pathFallbackDir, file.name),\n content: file.missing ? undefined : file.content,\n missing: file.missing ?? false,\n };\n}\n\n/**\n * Load profile Markdown from `profileDir` (`agents/<agentId>/profile/`).\n */\nexport function loadProfileMarkdownFiles(profileDir: string): ProfileMarkdownFile[] {\n const files: ProfileMarkdownFile[] = [];\n let loadedCount = 0;\n let missingCount = 0;\n\n for (const filename of AGENT_PROFILE_MARKDOWN_SYSTEM_FILES) {\n const filePath = join(profileDir, filename);\n\n if (existsSync(filePath)) {\n try {\n let content = readFileSync(filePath, 'utf-8');\n\n content = stripFrontMatter(content);\n\n const result = truncateProfileMarkdownContent(content, PROFILE_MARKDOWN_MAX_CHARS);\n\n if (result.content) {\n files.push({\n name: filename,\n content: result.content,\n path: resolve(filePath),\n });\n loadedCount++;\n\n if (result.truncated) {\n log.warn(\n {\n file: filename,\n originalLength: result.originalLength,\n keptLength: result.content.length,\n },\n 'Profile Markdown truncated in system prompt (too long)',\n );\n } else {\n log.debug({ file: filename, path: filePath }, 'Profile Markdown file loaded');\n }\n }\n } catch (err) {\n log.warn({ file: filename, err }, 'Failed to load profile Markdown file');\n }\n } else if (REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET.has(filename)) {\n const hint = join(profileDir, filename);\n files.push({\n name: filename,\n content: `[MISSING] Create this file at: ${hint}`,\n missing: true,\n path: resolve(hint),\n });\n missingCount++;\n log.debug({ file: filename }, 'Profile Markdown file missing');\n }\n }\n\n log.debug({ loaded: loadedCount, missing: missingCount, profileDir }, 'Profile Markdown scan done');\n\n return files;\n}\n\n// =============================================================================\n// Message content helpers\n// =============================================================================\n\n/**\n * Extract text content from agent message content array\n */\nexport function extractTextContent(\n content: Array<{ type: string; text?: string }>\n): string {\n return content\n .filter((c) => c.type === 'text')\n .map((c) => c.text || '')\n .join('');\n}\n\nconst THINKING_BLOCK_TYPES = new Set(['thinking', 'thinking_delta', 'redacted_thinking']);\n\n/**\n * Concatenate thinking / reasoning content blocks from assistant message.content.\n * pi-ai may use `thinking` or `text` on `type: \"thinking\"` blocks.\n */\nexport function extractThinkingContent(\n content: Array<{ type: string; thinking?: string; text?: string }> | undefined\n): string {\n if (!Array.isArray(content)) return '';\n return content\n .filter((c) => THINKING_BLOCK_TYPES.has(c.type))\n .map((c) => (typeof c.thinking === 'string' ? c.thinking : c.text) || '')\n .join('');\n}\n\n/**\n * Extended thinking on the assistant message (e.g. Anthropic reasoning / pi-ai reasoning_details).\n */\nexport function extractThinkingFromAssistantMessage(\n message: { role?: string; reasoning_details?: { thinking?: string } } | undefined\n): string {\n if (!message || message.role !== 'assistant') return '';\n const t = message.reasoning_details?.thinking;\n return typeof t === 'string' ? t : '';\n}\n"],"mappings":";;;;;;;;;;;;aASqD;AAGrD,MAAM,MAAM,aAAa,YAAY;AAMrC,MAAa,0BAA0B;AACvC,MAAa,wBAAwB;AACrC,MAAa,yBAAyB;AACtC,MAAa,4BAA4B;AACzC,MAAa,6BAA6B;;;;AAY1C,MAAa,sCAA+E;CAC1F;CACA;CACA;CACA;CACA;CACD;;AAGD,MAAa,wCAAiF,CAC5F,uBACA,0BACD;AAED,MAAa,2CAAgE,IAAI,IAC/E,sCACD;;;;AAYD,SAAgB,iBAAiB,SAAyB;AACxD,QAAO,iBAAiB,QAAQ,CAAC;;;AAQnC,MAAa,6BAA6B;;AAG1C,MAAM,wBAAwB;;AAE9B,MAAM,wBAAwB;;;;;;AAa9B,SAAgB,+BAA+B,SAAiB,UAAkC;CAChG,MAAM,UAAU,QAAQ,SAAS;AACjC,KAAI,QAAQ,UAAU,SACpB,QAAO;EACL,SAAS;EACT,WAAW;EACX,gBAAgB,QAAQ;EACzB;CAGH,MAAM,YAAY,KAAK,MAAM,WAAW,sBAAsB;CAC9D,MAAM,YAAY,KAAK,MAAM,WAAW,sBAAsB;CAC9D,MAAM,OAAO,QAAQ,MAAM,GAAG,UAAU;CACxC,MAAM,OAAO,QAAQ,MAAM,CAAC,UAAU;AAStC,QAAO;EACL,SAAS,OARI;GACb;GACA;GACA,uBAAuB,UAAU,GAAG,UAAU,YAAY,QAAQ,OAAO;GACzE;GACD,CAAC,KAAK,KAGiB,GAAG;EACzB,WAAW;EACX,gBAAgB,QAAQ;EACzB;;;;;;AAcH,SAAgB,+BAA+B,MAA2B,iBAKxE;AACA,QAAO;EACL,MAAM,KAAK;EACX,MAAM,KAAK,QAAQ,KAAK,iBAAiB,KAAK,KAAK;EACnD,SAAS,KAAK,UAAU,KAAA,IAAY,KAAK;EACzC,SAAS,KAAK,WAAW;EAC1B;;;;;AAMH,SAAgB,yBAAyB,YAA2C;CAClF,MAAM,QAA+B,EAAE;CACvC,IAAI,cAAc;CAClB,IAAI,eAAe;AAEnB,MAAK,MAAM,YAAY,qCAAqC;EAC1D,MAAM,WAAW,KAAK,YAAY,SAAS;AAE3C,MAAI,WAAW,SAAS,CACtB,KAAI;GACF,IAAI,UAAU,aAAa,UAAU,QAAQ;AAE7C,aAAU,iBAAiB,QAAQ;GAEnC,MAAM,SAAS,+BAA+B,SAAS,2BAA2B;AAElF,OAAI,OAAO,SAAS;AAClB,UAAM,KAAK;KACT,MAAM;KACN,SAAS,OAAO;KAChB,MAAM,QAAQ,SAAS;KACxB,CAAC;AACF;AAEA,QAAI,OAAO,UACT,KAAI,KACF;KACE,MAAM;KACN,gBAAgB,OAAO;KACvB,YAAY,OAAO,QAAQ;KAC5B,EACD,yDACD;QAED,KAAI,MAAM;KAAE,MAAM;KAAU,MAAM;KAAU,EAAE,+BAA+B;;WAG1E,KAAK;AACZ,OAAI,KAAK;IAAE,MAAM;IAAU;IAAK,EAAE,uCAAuC;;WAElE,yCAAyC,IAAI,SAAS,EAAE;GACjE,MAAM,OAAO,KAAK,YAAY,SAAS;AACvC,SAAM,KAAK;IACT,MAAM;IACN,SAAS,kCAAkC;IAC3C,SAAS;IACT,MAAM,QAAQ,KAAK;IACpB,CAAC;AACF;AACA,OAAI,MAAM,EAAE,MAAM,UAAU,EAAE,gCAAgC;;;AAIlE,KAAI,MAAM;EAAE,QAAQ;EAAa,SAAS;EAAc;EAAY,EAAE,6BAA6B;AAEnG,QAAO;;;;;AAUT,SAAgB,mBACd,SACQ;AACR,QAAO,QACJ,QAAQ,MAAM,EAAE,SAAS,OAAO,CAChC,KAAK,MAAM,EAAE,QAAQ,GAAG,CACxB,KAAK,GAAG;;AAGb,MAAM,uBAAuB,IAAI,IAAI;CAAC;CAAY;CAAkB;CAAoB,CAAC;;;;;AAMzF,SAAgB,uBACd,SACQ;AACR,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO;AACpC,QAAO,QACJ,QAAQ,MAAM,qBAAqB,IAAI,EAAE,KAAK,CAAC,CAC/C,KAAK,OAAO,OAAO,EAAE,aAAa,WAAW,EAAE,WAAW,EAAE,SAAS,GAAG,CACxE,KAAK,GAAG;;;;;AAMb,SAAgB,oCACd,SACQ;AACR,KAAI,CAAC,WAAW,QAAQ,SAAS,YAAa,QAAO;CACrD,MAAM,IAAI,QAAQ,mBAAmB;AACrC,QAAO,OAAO,MAAM,WAAW,IAAI"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { resolveEffectiveAgentManifestForSession } from "../../config/agent-profile.js";
|
|
4
3
|
import { init_providers, resolveModel } from "../../providers/index.js";
|
|
5
4
|
import { resolveAgentTurnTimeoutMs } from "../orchestration/run-agent-turn-with-timeout.js";
|
|
6
5
|
import { runXopcEmbeddedTurn } from "./run-turn.js";
|
|
@@ -164,7 +163,7 @@ async function runEmbeddedTurnForSession(params) {
|
|
|
164
163
|
async function maybeAutoCompactBeforeTurn(opts) {
|
|
165
164
|
const { sessionKey, sessionStore, agentManager, model, config, onEvent } = opts;
|
|
166
165
|
if (config) try {
|
|
167
|
-
if (
|
|
166
|
+
if (config.userContext.memory.retention?.compaction === false) return;
|
|
168
167
|
} catch {}
|
|
169
168
|
const contextWindow = model.contextWindow ?? 128e3;
|
|
170
169
|
const messages = await sessionStore.load(sessionKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-for-session.js","names":[],"sources":["../../../../src/agent/embedded/run-for-session.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport type { AgentMessage, ThinkingLevel } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport type { AgentInstanceGateway } from '../agent-instance-gateway.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { resolveAgentTurnTimeoutMs } from '../orchestration/run-agent-turn-with-timeout.js';\nimport { runXopcEmbeddedTurn } from './run-turn.js';\nimport type { EmbeddedStreamEvent, RunXopcEmbeddedTurnParams, RunXopcEmbeddedTurnResult } from './types.js';\nimport { applyStartupContextToUserMessage } from '../reply/apply-turn-user-enrichment.js';\nimport { resolveEffectiveAgentManifestForSession } from '../../config/agent-profile.js';\nimport {\n mergeTurnTools,\n resolveEmbeddedMcpToolsForTurn,\n} from '../mcp/resolve-embedded-mcp-tools.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveModel } from '../../providers/index.js';\n\nconst log = createLogger('EmbeddedTurnForSession');\n\nexport type RunEmbeddedForSessionParams = {\n sessionKey: string;\n runId?: string;\n userMessage: AgentMessage;\n llmImages?: import('@earendil-works/pi-ai').ImageContent[];\n sessionStore: SessionStore;\n agentManager: AgentInstanceGateway;\n modelManager: ModelManager;\n thinkingOverride?: string | null;\n abortSignal?: AbortSignal;\n onEvent?: (event: EmbeddedStreamEvent) => void;\n getConfig?: () => Config | undefined;\n beforeTurn?: () => void | Promise<void>;\n afterTurn?: (userPlain: string) => void | Promise<void>;\n startupAction?: 'new' | 'reset';\n forceStartupContext?: boolean;\n applyStartupContext?: boolean;\n /** When true, dispose session MCP runtime after this turn completes. */\n cleanupBundleMcpOnRunEnd?: boolean;\n};\n\nexport async function runEmbeddedTurnForSession(\n params: RunEmbeddedForSessionParams,\n): Promise<RunXopcEmbeddedTurnResult> {\n const { sessionKey, agentManager, modelManager, sessionStore, userMessage } = params;\n const runId = params.runId ?? crypto.randomUUID();\n\n await params.beforeTurn?.();\n\n const agent = (agentManager as any).getOrCreateAgent(sessionKey) as {\n state: {\n tools: RunXopcEmbeddedTurnParams['tools'];\n systemPrompt?: string;\n thinkingLevel?: ThinkingLevel;\n };\n };\n const mm = modelManager as any;\n await mm.applyModelForSession(agent, sessionKey);\n\n const modelRef = String(mm.getModelForSession(sessionKey));\n agentManager.setModelForSession(sessionKey, modelRef);\n const model = mm.getResolvedModelForSession(sessionKey) as RunXopcEmbeddedTurnParams['model'];\n const tools = agent.state.tools;\n const systemPrompt = agent.state.systemPrompt ?? '';\n const thinkingLevel = (params.thinkingOverride as ThinkingLevel | undefined) ?? agent.state.thinkingLevel;\n const workspaceDir = agentManager.getResolvedWorkspaceForSession(sessionKey);\n const config = params.getConfig?.();\n\n // --- Pre-turn automatic compaction ---\n await maybeAutoCompactBeforeTurn({\n sessionKey,\n sessionStore,\n agentManager,\n model,\n config,\n onEvent: params.onEvent,\n });\n\n let userMessageForTurn = userMessage;\n if (params.applyStartupContext !== false) {\n userMessageForTurn = await applyStartupContextToUserMessage({\n userMessage,\n sessionKey,\n workspaceDir,\n cfg: config,\n sessionStore,\n startupAction: params.startupAction,\n force: params.forceStartupContext,\n });\n }\n\n const result = await (async () => {\n const mcpResolved = await resolveEmbeddedMcpToolsForTurn({\n sessionKey,\n workspaceDir,\n cfg: config,\n baseTools: tools,\n cleanupOnTurnEnd: params.cleanupBundleMcpOnRunEnd === true,\n });\n const turnTools = mergeTurnTools(tools, mcpResolved.tools);\n try {\n const candidates = typeof mm.getFallbackCandidatesForSession === 'function'\n ? mm.getFallbackCandidatesForSession(sessionKey)\n : [];\n const candidateModelRefs = candidates.length > 0\n ? candidates.map((candidate: { provider: string; model: string }) => `${candidate.provider}/${candidate.model}`)\n : [modelRef];\n log.info(\n { sessionKey, runId, primaryModelRef: candidateModelRefs[0], candidateModelRefs },\n 'Agent model fallback candidates resolved',\n );\n\n let lastResult: RunXopcEmbeddedTurnResult | undefined;\n let lastError: unknown;\n const primaryModelRef = candidateModelRefs[0] ?? modelRef;\n const beforeLen = Array.isArray((agent as any).state?.messages)\n ? (agent as any).state.messages.length\n : undefined;\n\n for (let i = 0; i < candidateModelRefs.length; i++) {\n const candidateModelRef = candidateModelRefs[i] ?? modelRef;\n const isFallbackAttempt = i > 0;\n let candidateModel = model;\n if (candidateModelRef !== modelRef) {\n try {\n candidateModel = resolveModel(candidateModelRef) as RunXopcEmbeddedTurnParams['model'];\n } catch (err) {\n lastError = err;\n log.warn(\n { err, sessionKey, runId, modelRef: candidateModelRef, attempt: i + 1, total: candidateModelRefs.length },\n 'Skipping model fallback candidate (resolve failed)',\n );\n continue;\n }\n }\n\n if (typeof mm.applyResolvedModel === 'function') {\n mm.applyResolvedModel(agent, candidateModel, candidateModelRef);\n }\n agentManager.setModelForSession(sessionKey, candidateModelRef);\n\n if (isFallbackAttempt) {\n log.info(\n {\n sessionKey,\n runId,\n primaryModelRef,\n fallbackModelRef: candidateModelRef,\n attempt: i + 1,\n total: candidateModelRefs.length,\n },\n 'Agent model fallback started',\n );\n }\n\n try {\n const turnResult = await runXopcEmbeddedTurn({\n sessionKey,\n runId,\n userMessage: userMessageForTurn,\n images: params.llmImages,\n model: candidateModel,\n modelRef: candidateModelRef,\n tools: turnTools,\n systemPrompt,\n thinkingLevel,\n workspaceDir,\n sessionStore,\n timeoutMs: resolveAgentTurnTimeoutMs(config),\n abortSignal: params.abortSignal,\n onEvent: params.onEvent,\n });\n\n if (turnResult.ok) {\n if (isFallbackAttempt) {\n log.info(\n {\n sessionKey,\n runId,\n primaryModelRef,\n fallbackModelRef: candidateModelRef,\n attempt: i + 1,\n total: candidateModelRefs.length,\n },\n 'Agent model fallback succeeded',\n );\n }\n return turnResult;\n }\n\n lastResult = turnResult;\n const hasNextCandidate = i + 1 < candidateModelRefs.length;\n log.warn(\n {\n sessionKey,\n runId,\n modelRef: candidateModelRef,\n attempt: i + 1,\n total: candidateModelRefs.length,\n hasNextCandidate,\n errorMessage: turnResult.errorMessage,\n },\n hasNextCandidate\n ? 'Agent model turn failed, trying fallback'\n : 'Agent model turn failed, no fallback remains',\n );\n } catch (err) {\n lastError = err;\n if (err instanceof DOMException && err.name === 'AbortError') {\n throw err;\n }\n const hasNextCandidate = i + 1 < candidateModelRefs.length;\n log.warn(\n { err, sessionKey, runId, modelRef: candidateModelRef, attempt: i + 1, total: candidateModelRefs.length, hasNextCandidate },\n hasNextCandidate\n ? 'Agent model call threw, trying fallback'\n : 'Agent model call threw, no fallback remains',\n );\n }\n\n if (beforeLen !== undefined && Array.isArray((agent as any).state?.messages)) {\n (agent as any).state.messages = (agent as any).state.messages.slice(0, beforeLen);\n }\n }\n\n if (lastResult) return lastResult;\n if (lastError instanceof Error) throw lastError;\n if (lastError != null) throw new Error(String(lastError));\n return { ok: false, errorMessage: 'No model candidates available' };\n } finally {\n await mcpResolved.dispose().catch(() => {});\n }\n })();\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Pre-turn automatic compaction\n// ---------------------------------------------------------------------------\n\nasync function maybeAutoCompactBeforeTurn(opts: {\n sessionKey: string;\n sessionStore: SessionStore;\n agentManager: AgentInstanceGateway;\n model: RunXopcEmbeddedTurnParams['model'];\n config: Config | undefined;\n onEvent?: (event: EmbeddedStreamEvent) => void;\n}): Promise<void> {\n const { sessionKey, sessionStore, agentManager, model, config, onEvent } = opts;\n if (config) {\n try {\n const manifest = resolveEffectiveAgentManifestForSession(config, sessionKey);\n if (manifest.memory.retention?.compaction === false) {\n return;\n }\n } catch {\n // Keep compaction enabled when manifest resolution is unavailable.\n }\n }\n\n const contextWindow = (model as { contextWindow?: number }).contextWindow ?? 128_000;\n const messages = await sessionStore.load(sessionKey);\n const prep = sessionStore.prepareCompaction(sessionKey, messages, contextWindow);\n\n if (!prep.needsCompaction) {\n return;\n }\n\n log.info(\n { sessionKey, reason: prep.stats?.reason, usagePercent: prep.stats?.usagePercent, contextWindow },\n 'Pre-turn auto-compaction triggered',\n );\n\n onEvent?.({\n type: 'compaction',\n status: 'started',\n tokensBefore: prep.stats?.usagePercent != null\n ? Math.round((prep.stats.usagePercent as number) * contextWindow)\n : undefined,\n });\n\n try {\n const result = await sessionStore.compact(sessionKey, messages, contextWindow);\n\n if (result.compacted) {\n // Evict the cached agent so the next turn reloads from the compacted transcript\n agentManager.removeAgent(sessionKey);\n\n log.info(\n { sessionKey, tokensBefore: result.tokensBefore, tokensAfter: result.tokensAfter },\n 'Pre-turn auto-compaction completed',\n );\n\n onEvent?.({\n type: 'compaction',\n status: 'completed',\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n summary: result.summary.length > 200 ? `${result.summary.slice(0, 200)}…` : result.summary,\n });\n } else {\n onEvent?.({ type: 'compaction', status: 'skipped' });\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.warn({ err, sessionKey }, `Pre-turn auto-compaction failed: ${errorMessage}`);\n // Non-fatal: let the turn proceed even if compaction fails\n onEvent?.({ type: 'compaction', status: 'skipped' });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-for-session.js","names":[],"sources":["../../../../src/agent/embedded/run-for-session.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport type { AgentMessage, ThinkingLevel } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../../config/schema.js';\nimport type { AgentInstanceGateway } from '../agent-instance-gateway.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { resolveAgentTurnTimeoutMs } from '../orchestration/run-agent-turn-with-timeout.js';\nimport { runXopcEmbeddedTurn } from './run-turn.js';\nimport type { EmbeddedStreamEvent, RunXopcEmbeddedTurnParams, RunXopcEmbeddedTurnResult } from './types.js';\nimport { applyStartupContextToUserMessage } from '../reply/apply-turn-user-enrichment.js';\nimport {\n mergeTurnTools,\n resolveEmbeddedMcpToolsForTurn,\n} from '../mcp/resolve-embedded-mcp-tools.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveModel } from '../../providers/index.js';\n\nconst log = createLogger('EmbeddedTurnForSession');\n\nexport type RunEmbeddedForSessionParams = {\n sessionKey: string;\n runId?: string;\n userMessage: AgentMessage;\n llmImages?: import('@earendil-works/pi-ai').ImageContent[];\n sessionStore: SessionStore;\n agentManager: AgentInstanceGateway;\n modelManager: ModelManager;\n thinkingOverride?: string | null;\n abortSignal?: AbortSignal;\n onEvent?: (event: EmbeddedStreamEvent) => void;\n getConfig?: () => Config | undefined;\n beforeTurn?: () => void | Promise<void>;\n afterTurn?: (userPlain: string) => void | Promise<void>;\n startupAction?: 'new' | 'reset';\n forceStartupContext?: boolean;\n applyStartupContext?: boolean;\n /** When true, dispose session MCP runtime after this turn completes. */\n cleanupBundleMcpOnRunEnd?: boolean;\n};\n\nexport async function runEmbeddedTurnForSession(\n params: RunEmbeddedForSessionParams,\n): Promise<RunXopcEmbeddedTurnResult> {\n const { sessionKey, agentManager, modelManager, sessionStore, userMessage } = params;\n const runId = params.runId ?? crypto.randomUUID();\n\n await params.beforeTurn?.();\n\n const agent = (agentManager as any).getOrCreateAgent(sessionKey) as {\n state: {\n tools: RunXopcEmbeddedTurnParams['tools'];\n systemPrompt?: string;\n thinkingLevel?: ThinkingLevel;\n };\n };\n const mm = modelManager as any;\n await mm.applyModelForSession(agent, sessionKey);\n\n const modelRef = String(mm.getModelForSession(sessionKey));\n agentManager.setModelForSession(sessionKey, modelRef);\n const model = mm.getResolvedModelForSession(sessionKey) as RunXopcEmbeddedTurnParams['model'];\n const tools = agent.state.tools;\n const systemPrompt = agent.state.systemPrompt ?? '';\n const thinkingLevel = (params.thinkingOverride as ThinkingLevel | undefined) ?? agent.state.thinkingLevel;\n const workspaceDir = agentManager.getResolvedWorkspaceForSession(sessionKey);\n const config = params.getConfig?.();\n\n // --- Pre-turn automatic compaction ---\n await maybeAutoCompactBeforeTurn({\n sessionKey,\n sessionStore,\n agentManager,\n model,\n config,\n onEvent: params.onEvent,\n });\n\n let userMessageForTurn = userMessage;\n if (params.applyStartupContext !== false) {\n userMessageForTurn = await applyStartupContextToUserMessage({\n userMessage,\n sessionKey,\n workspaceDir,\n cfg: config,\n sessionStore,\n startupAction: params.startupAction,\n force: params.forceStartupContext,\n });\n }\n\n const result = await (async () => {\n const mcpResolved = await resolveEmbeddedMcpToolsForTurn({\n sessionKey,\n workspaceDir,\n cfg: config,\n baseTools: tools,\n cleanupOnTurnEnd: params.cleanupBundleMcpOnRunEnd === true,\n });\n const turnTools = mergeTurnTools(tools, mcpResolved.tools);\n try {\n const candidates = typeof mm.getFallbackCandidatesForSession === 'function'\n ? mm.getFallbackCandidatesForSession(sessionKey)\n : [];\n const candidateModelRefs = candidates.length > 0\n ? candidates.map((candidate: { provider: string; model: string }) => `${candidate.provider}/${candidate.model}`)\n : [modelRef];\n log.info(\n { sessionKey, runId, primaryModelRef: candidateModelRefs[0], candidateModelRefs },\n 'Agent model fallback candidates resolved',\n );\n\n let lastResult: RunXopcEmbeddedTurnResult | undefined;\n let lastError: unknown;\n const primaryModelRef = candidateModelRefs[0] ?? modelRef;\n const beforeLen = Array.isArray((agent as any).state?.messages)\n ? (agent as any).state.messages.length\n : undefined;\n\n for (let i = 0; i < candidateModelRefs.length; i++) {\n const candidateModelRef = candidateModelRefs[i] ?? modelRef;\n const isFallbackAttempt = i > 0;\n let candidateModel = model;\n if (candidateModelRef !== modelRef) {\n try {\n candidateModel = resolveModel(candidateModelRef) as RunXopcEmbeddedTurnParams['model'];\n } catch (err) {\n lastError = err;\n log.warn(\n { err, sessionKey, runId, modelRef: candidateModelRef, attempt: i + 1, total: candidateModelRefs.length },\n 'Skipping model fallback candidate (resolve failed)',\n );\n continue;\n }\n }\n\n if (typeof mm.applyResolvedModel === 'function') {\n mm.applyResolvedModel(agent, candidateModel, candidateModelRef);\n }\n agentManager.setModelForSession(sessionKey, candidateModelRef);\n\n if (isFallbackAttempt) {\n log.info(\n {\n sessionKey,\n runId,\n primaryModelRef,\n fallbackModelRef: candidateModelRef,\n attempt: i + 1,\n total: candidateModelRefs.length,\n },\n 'Agent model fallback started',\n );\n }\n\n try {\n const turnResult = await runXopcEmbeddedTurn({\n sessionKey,\n runId,\n userMessage: userMessageForTurn,\n images: params.llmImages,\n model: candidateModel,\n modelRef: candidateModelRef,\n tools: turnTools,\n systemPrompt,\n thinkingLevel,\n workspaceDir,\n sessionStore,\n timeoutMs: resolveAgentTurnTimeoutMs(config),\n abortSignal: params.abortSignal,\n onEvent: params.onEvent,\n });\n\n if (turnResult.ok) {\n if (isFallbackAttempt) {\n log.info(\n {\n sessionKey,\n runId,\n primaryModelRef,\n fallbackModelRef: candidateModelRef,\n attempt: i + 1,\n total: candidateModelRefs.length,\n },\n 'Agent model fallback succeeded',\n );\n }\n return turnResult;\n }\n\n lastResult = turnResult;\n const hasNextCandidate = i + 1 < candidateModelRefs.length;\n log.warn(\n {\n sessionKey,\n runId,\n modelRef: candidateModelRef,\n attempt: i + 1,\n total: candidateModelRefs.length,\n hasNextCandidate,\n errorMessage: turnResult.errorMessage,\n },\n hasNextCandidate\n ? 'Agent model turn failed, trying fallback'\n : 'Agent model turn failed, no fallback remains',\n );\n } catch (err) {\n lastError = err;\n if (err instanceof DOMException && err.name === 'AbortError') {\n throw err;\n }\n const hasNextCandidate = i + 1 < candidateModelRefs.length;\n log.warn(\n { err, sessionKey, runId, modelRef: candidateModelRef, attempt: i + 1, total: candidateModelRefs.length, hasNextCandidate },\n hasNextCandidate\n ? 'Agent model call threw, trying fallback'\n : 'Agent model call threw, no fallback remains',\n );\n }\n\n if (beforeLen !== undefined && Array.isArray((agent as any).state?.messages)) {\n (agent as any).state.messages = (agent as any).state.messages.slice(0, beforeLen);\n }\n }\n\n if (lastResult) return lastResult;\n if (lastError instanceof Error) throw lastError;\n if (lastError != null) throw new Error(String(lastError));\n return { ok: false, errorMessage: 'No model candidates available' };\n } finally {\n await mcpResolved.dispose().catch(() => {});\n }\n })();\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Pre-turn automatic compaction\n// ---------------------------------------------------------------------------\n\nasync function maybeAutoCompactBeforeTurn(opts: {\n sessionKey: string;\n sessionStore: SessionStore;\n agentManager: AgentInstanceGateway;\n model: RunXopcEmbeddedTurnParams['model'];\n config: Config | undefined;\n onEvent?: (event: EmbeddedStreamEvent) => void;\n}): Promise<void> {\n const { sessionKey, sessionStore, agentManager, model, config, onEvent } = opts;\n if (config) {\n try {\n if (config.userContext.memory.retention?.compaction === false) {\n return;\n }\n } catch {\n // Keep compaction enabled when manifest resolution is unavailable.\n }\n }\n\n const contextWindow = (model as { contextWindow?: number }).contextWindow ?? 128_000;\n const messages = await sessionStore.load(sessionKey);\n const prep = sessionStore.prepareCompaction(sessionKey, messages, contextWindow);\n\n if (!prep.needsCompaction) {\n return;\n }\n\n log.info(\n { sessionKey, reason: prep.stats?.reason, usagePercent: prep.stats?.usagePercent, contextWindow },\n 'Pre-turn auto-compaction triggered',\n );\n\n onEvent?.({\n type: 'compaction',\n status: 'started',\n tokensBefore: prep.stats?.usagePercent != null\n ? Math.round((prep.stats.usagePercent as number) * contextWindow)\n : undefined,\n });\n\n try {\n const result = await sessionStore.compact(sessionKey, messages, contextWindow);\n\n if (result.compacted) {\n // Evict the cached agent so the next turn reloads from the compacted transcript\n agentManager.removeAgent(sessionKey);\n\n log.info(\n { sessionKey, tokensBefore: result.tokensBefore, tokensAfter: result.tokensAfter },\n 'Pre-turn auto-compaction completed',\n );\n\n onEvent?.({\n type: 'compaction',\n status: 'completed',\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n summary: result.summary.length > 200 ? `${result.summary.slice(0, 200)}…` : result.summary,\n });\n } else {\n onEvent?.({ type: 'compaction', status: 'skipped' });\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.warn({ err, sessionKey }, `Pre-turn auto-compaction failed: ${errorMessage}`);\n // Non-fatal: let the turn proceed even if compaction fails\n onEvent?.({ type: 'compaction', status: 'skipped' });\n }\n}\n"],"mappings":";;;;;;;;;aAeqD;gBACG;AAExD,MAAM,MAAM,aAAa,yBAAyB;AAuBlD,eAAsB,0BACpB,QACoC;CACpC,MAAM,EAAE,YAAY,cAAc,cAAc,cAAc,gBAAgB;CAC9E,MAAM,QAAQ,OAAO,SAAS,OAAO,YAAY;AAEjD,OAAM,OAAO,cAAc;CAE3B,MAAM,QAAS,aAAqB,iBAAiB,WAAW;CAOhE,MAAM,KAAK;AACX,OAAM,GAAG,qBAAqB,OAAO,WAAW;CAEhD,MAAM,WAAW,OAAO,GAAG,mBAAmB,WAAW,CAAC;AAC1D,cAAa,mBAAmB,YAAY,SAAS;CACrD,MAAM,QAAQ,GAAG,2BAA2B,WAAW;CACvD,MAAM,QAAQ,MAAM,MAAM;CAC1B,MAAM,eAAe,MAAM,MAAM,gBAAgB;CACjD,MAAM,gBAAiB,OAAO,oBAAkD,MAAM,MAAM;CAC5F,MAAM,eAAe,aAAa,+BAA+B,WAAW;CAC5E,MAAM,SAAS,OAAO,aAAa;AAGnC,OAAM,2BAA2B;EAC/B;EACA;EACA;EACA;EACA;EACA,SAAS,OAAO;EACjB,CAAC;CAEF,IAAI,qBAAqB;AACzB,KAAI,OAAO,wBAAwB,MACjC,sBAAqB,MAAM,iCAAiC;EAC1D;EACA;EACA;EACA,KAAK;EACL;EACA,eAAe,OAAO;EACtB,OAAO,OAAO;EACf,CAAC;AAkJJ,QAAO,OA/Ie,YAAY;EAChC,MAAM,cAAc,MAAM,+BAA+B;GACvD;GACA;GACA,KAAK;GACL,WAAW;GACX,kBAAkB,OAAO,6BAA6B;GACvD,CAAC;EACF,MAAM,YAAY,eAAe,OAAO,YAAY,MAAM;AAC1D,MAAI;GACF,MAAM,aAAa,OAAO,GAAG,oCAAoC,aAC7D,GAAG,gCAAgC,WAAW,GAC9C,EAAE;GACN,MAAM,qBAAqB,WAAW,SAAS,IAC3C,WAAW,KAAK,cAAmD,GAAG,UAAU,SAAS,GAAG,UAAU,QAAQ,GAC9G,CAAC,SAAS;AACd,OAAI,KACF;IAAE;IAAY;IAAO,iBAAiB,mBAAmB;IAAI;IAAoB,EACjF,2CACD;GAED,IAAI;GACJ,IAAI;GACJ,MAAM,kBAAkB,mBAAmB,MAAM;GACjD,MAAM,YAAY,MAAM,QAAS,MAAc,OAAO,SAAS,GAC1D,MAAc,MAAM,SAAS,SAC9B,KAAA;AAEJ,QAAK,IAAI,IAAI,GAAG,IAAI,mBAAmB,QAAQ,KAAK;IAClD,MAAM,oBAAoB,mBAAmB,MAAM;IACnD,MAAM,oBAAoB,IAAI;IAC9B,IAAI,iBAAiB;AACrB,QAAI,sBAAsB,SACxB,KAAI;AACF,sBAAiB,aAAa,kBAAkB;aACzC,KAAK;AACZ,iBAAY;AACZ,SAAI,KACF;MAAE;MAAK;MAAY;MAAO,UAAU;MAAmB,SAAS,IAAI;MAAG,OAAO,mBAAmB;MAAQ,EACzG,qDACD;AACD;;AAIJ,QAAI,OAAO,GAAG,uBAAuB,WACnC,IAAG,mBAAmB,OAAO,gBAAgB,kBAAkB;AAEjE,iBAAa,mBAAmB,YAAY,kBAAkB;AAE9D,QAAI,kBACF,KAAI,KACF;KACE;KACA;KACA;KACA,kBAAkB;KAClB,SAAS,IAAI;KACb,OAAO,mBAAmB;KAC3B,EACD,+BACD;AAGH,QAAI;KACF,MAAM,aAAa,MAAM,oBAAoB;MAC3C;MACA;MACA,aAAa;MACb,QAAQ,OAAO;MACf,OAAO;MACP,UAAU;MACV,OAAO;MACP;MACA;MACA;MACA;MACA,WAAW,0BAA0B,OAAO;MAC5C,aAAa,OAAO;MACpB,SAAS,OAAO;MACjB,CAAC;AAEF,SAAI,WAAW,IAAI;AACjB,UAAI,kBACF,KAAI,KACF;OACE;OACA;OACA;OACA,kBAAkB;OAClB,SAAS,IAAI;OACb,OAAO,mBAAmB;OAC3B,EACD,iCACD;AAEH,aAAO;;AAGT,kBAAa;KACb,MAAM,mBAAmB,IAAI,IAAI,mBAAmB;AACpD,SAAI,KACF;MACE;MACA;MACA,UAAU;MACV,SAAS,IAAI;MACb,OAAO,mBAAmB;MAC1B;MACA,cAAc,WAAW;MAC1B,EACD,mBACI,6CACA,+CACL;aACM,KAAK;AACZ,iBAAY;AACZ,SAAI,eAAe,gBAAgB,IAAI,SAAS,aAC9C,OAAM;KAER,MAAM,mBAAmB,IAAI,IAAI,mBAAmB;AACpD,SAAI,KACF;MAAE;MAAK;MAAY;MAAO,UAAU;MAAmB,SAAS,IAAI;MAAG,OAAO,mBAAmB;MAAQ;MAAkB,EAC3H,mBACI,4CACA,8CACL;;AAGH,QAAI,cAAc,KAAA,KAAa,MAAM,QAAS,MAAc,OAAO,SAAS,CACzE,OAAc,MAAM,WAAY,MAAc,MAAM,SAAS,MAAM,GAAG,UAAU;;AAIrF,OAAI,WAAY,QAAO;AACvB,OAAI,qBAAqB,MAAO,OAAM;AACtC,OAAI,aAAa,KAAM,OAAM,IAAI,MAAM,OAAO,UAAU,CAAC;AACzD,UAAO;IAAE,IAAI;IAAO,cAAc;IAAiC;YAC3D;AACR,SAAM,YAAY,SAAS,CAAC,YAAY,GAAG;;KAE3C;;AASN,eAAe,2BAA2B,MAOxB;CAChB,MAAM,EAAE,YAAY,cAAc,cAAc,OAAO,QAAQ,YAAY;AAC3E,KAAI,OACF,KAAI;AACF,MAAI,OAAO,YAAY,OAAO,WAAW,eAAe,MACtD;SAEI;CAKV,MAAM,gBAAiB,MAAqC,iBAAiB;CAC7E,MAAM,WAAW,MAAM,aAAa,KAAK,WAAW;CACpD,MAAM,OAAO,aAAa,kBAAkB,YAAY,UAAU,cAAc;AAEhF,KAAI,CAAC,KAAK,gBACR;AAGF,KAAI,KACF;EAAE;EAAY,QAAQ,KAAK,OAAO;EAAQ,cAAc,KAAK,OAAO;EAAc;EAAe,EACjG,qCACD;AAED,WAAU;EACR,MAAM;EACN,QAAQ;EACR,cAAc,KAAK,OAAO,gBAAgB,OACtC,KAAK,MAAO,KAAK,MAAM,eAA0B,cAAc,GAC/D,KAAA;EACL,CAAC;AAEF,KAAI;EACF,MAAM,SAAS,MAAM,aAAa,QAAQ,YAAY,UAAU,cAAc;AAE9E,MAAI,OAAO,WAAW;AAEpB,gBAAa,YAAY,WAAW;AAEpC,OAAI,KACF;IAAE;IAAY,cAAc,OAAO;IAAc,aAAa,OAAO;IAAa,EAClF,qCACD;AAED,aAAU;IACR,MAAM;IACN,QAAQ;IACR,cAAc,OAAO;IACrB,aAAa,OAAO;IACpB,SAAS,OAAO,QAAQ,SAAS,MAAM,GAAG,OAAO,QAAQ,MAAM,GAAG,IAAI,CAAC,KAAK,OAAO;IACpF,CAAC;QAEF,WAAU;GAAE,MAAM;GAAc,QAAQ;GAAW,CAAC;UAE/C,KAAK;EACZ,MAAM,eAAe,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AACrE,MAAI,KAAK;GAAE;GAAK;GAAY,EAAE,oCAAoC,eAAe;AAEjF,YAAU;GAAE,MAAM;GAAc,QAAQ;GAAW,CAAC"}
|
|
@@ -101,7 +101,12 @@ async function runXopcEmbeddedTurn(params) {
|
|
|
101
101
|
toolCount: effectiveContext.tools?.length ?? 0,
|
|
102
102
|
lastUserMessagePreview: getLastUserMessagePreview(effectiveContext.messages),
|
|
103
103
|
loopWarningInjected: !!loopGuard.injection,
|
|
104
|
-
hiddenToolCount: loopGuard.hiddenTools.size
|
|
104
|
+
hiddenToolCount: loopGuard.hiddenTools.size,
|
|
105
|
+
...process.env.XOPC_LOG_LLM_PAYLOAD === "true" ? { effectiveContext: {
|
|
106
|
+
systemPrompt: effectiveContext.systemPrompt,
|
|
107
|
+
messages: effectiveContext.messages,
|
|
108
|
+
tools: effectiveContext.tools
|
|
109
|
+
} } : {}
|
|
105
110
|
}, "Sending messages to AI");
|
|
106
111
|
return streamFnWithXopcExtensions(streamModel, effectiveContext, options);
|
|
107
112
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-turn.js","names":[],"sources":["../../../../src/agent/embedded/run-turn.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\n\nimport { createLogger } from '../../utils/logger.js';\nimport { registerEmbeddedRun, unregisterEmbeddedRun } from './runs.js';\nimport { subscribeEmbeddedSessionEvents, lastAssistantPlainText } from './subscribe-session.js';\nimport type { RunXopcEmbeddedTurnParams, RunXopcEmbeddedTurnResult } from './types.js';\nimport {\n getAssistantTurnErrorMessage,\n isAssistantTurnAborted,\n isAssistantTurnFailed,\n maybeRetryTurnAfterTransientLlmFailure,\n} from '../orchestration/llm-turn-retry.js';\nimport { runAgentTurnWithTimeout, resolveAgentTurnTimeoutMs } from '../orchestration/run-agent-turn-with-timeout.js';\nimport { detectToolLoops, type RecentToolCall } from '../orchestration/loop-guard.js';\nimport {\n acquireEmbeddedSessionRunner,\n resolveEmbeddedTranscriptInputs,\n} from './session-runner.js';\nimport { wrapStreamFnForXopcExtensions } from './xopc-stream-bridge.js';\n\nconst log = createLogger('EmbeddedRun');\nconst LOG_PREVIEW_MAX_CHARS = 300;\n\nfunction truncateForLog(value: string, maxChars = LOG_PREVIEW_MAX_CHARS): string {\n return value.length > maxChars ? `${value.slice(0, maxChars)}…` : value;\n}\n\nfunction extractTextFromContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return '';\n }\n return content\n .filter((block): block is { type: string; text: string } => {\n return !!block && typeof block === 'object' && (block as { type?: string }).type === 'text';\n })\n .map((block) => block.text)\n .join('');\n}\n\nfunction extractRecentToolCalls(messages: readonly { role?: string; content?: unknown }[]): RecentToolCall[] {\n const calls: RecentToolCall[] = [];\n for (const message of messages) {\n if (message.role !== 'assistant' || !Array.isArray(message.content)) continue;\n for (const block of message.content) {\n if (block && typeof block === 'object' && (block as { type?: string }).type === 'toolCall') {\n const toolCall = block as { name: string; arguments: unknown };\n calls.push({ name: toolCall.name, params: toolCall.arguments });\n }\n }\n }\n return calls;\n}\n\nfunction getLastUserMessagePreview(messages: readonly { role?: string; content?: unknown }[]): string | undefined {\n for (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex--) {\n const message = messages[messageIndex];\n if (message?.role !== 'user') {\n continue;\n }\n const text = extractTextFromContent(message.content).trim();\n return text ? truncateForLog(text) : undefined;\n }\n return undefined;\n}\n\nfunction requireEmbeddedModel(model: Model<Api> | undefined, modelRef: string): Model<Api> {\n if (!model?.id || !model?.provider) {\n throw new Error(`Invalid model for embedded run: ${modelRef}`);\n }\n return model;\n}\n\nfunction userMessageToPromptText(message: AgentMessage): string {\n const content = (message as { content?: unknown }).content;\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter((block): block is { type: 'text'; text: string } => {\n return !!block && typeof block === 'object' && (block as { type?: string }).type === 'text';\n })\n .map((block) => block.text)\n .join('');\n }\n return '';\n}\n\nexport async function runXopcEmbeddedTurn(params: RunXopcEmbeddedTurnParams): Promise<RunXopcEmbeddedTurnResult> {\n const {\n sessionKey,\n runId,\n userMessage,\n model,\n tools,\n systemPrompt,\n thinkingLevel,\n workspaceDir,\n sessionStore,\n onEvent,\n } = params;\n\n const timeoutMs = params.timeoutMs || resolveAgentTurnTimeoutMs();\n const resolvedModel = requireEmbeddedModel(model, params.modelRef);\n const transcript = await resolveEmbeddedTranscriptInputs(sessionStore, sessionKey);\n\n let runner: Awaited<ReturnType<typeof acquireEmbeddedSessionRunner>> | undefined;\n let unsubscribe: (() => void) | undefined;\n\n try {\n runner = await acquireEmbeddedSessionRunner({\n sessionKey,\n sessionId: transcript.sessionId,\n workspaceDir,\n model: resolvedModel,\n modelRef: params.modelRef,\n tools,\n systemPrompt,\n thinkingLevel: thinkingLevel ?? 'medium',\n });\n\n const { session, reused } = runner;\n\n const streamFnWithXopcExtensions = wrapStreamFnForXopcExtensions(session.agent.streamFn);\n const loggingStreamFn: typeof session.agent.streamFn = (streamModel, context, options) => {\n const recentToolCalls = extractRecentToolCalls(context.messages);\n const loopGuard = detectToolLoops(recentToolCalls);\n\n let effectiveContext = context;\n if (loopGuard.injection || loopGuard.hiddenTools.size > 0) {\n const messages = loopGuard.injection\n ? [...context.messages, { role: 'user' as const, content: loopGuard.injection, timestamp: Date.now() }]\n : context.messages;\n\n const contextTools = loopGuard.hiddenTools.size > 0 && context.tools\n ? context.tools.filter((t) => !loopGuard.hiddenTools.has(t.name))\n : context.tools;\n\n effectiveContext = { ...context, messages, tools: contextTools };\n }\n\n log.debug(\n {\n sessionKey,\n runId,\n reusedRunner: reused,\n modelRef: `${streamModel.provider}/${streamModel.id}`,\n systemPromptLength: effectiveContext.systemPrompt?.length ?? 0,\n messageCount: effectiveContext.messages.length,\n toolCount: effectiveContext.tools?.length ?? 0,\n lastUserMessagePreview: getLastUserMessagePreview(effectiveContext.messages),\n loopWarningInjected: !!loopGuard.injection,\n hiddenToolCount: loopGuard.hiddenTools.size,\n },\n 'Sending messages to AI',\n );\n return streamFnWithXopcExtensions(streamModel, effectiveContext, options);\n };\n session.agent.streamFn = loggingStreamFn;\n\n if (onEvent) {\n unsubscribe = subscribeEmbeddedSessionEvents(session, (event) => {\n onEvent({ ...event, runId });\n });\n }\n\n const handle = {\n sessionKey,\n sessionId: transcript.sessionId,\n runId,\n session,\n abort: async () => {\n await session.abort();\n },\n };\n registerEmbeddedRun(handle);\n\n const abortListener = () => {\n void session.abort();\n };\n if (params.abortSignal) {\n if (params.abortSignal.aborted) {\n await session.abort();\n return { ok: false, errorMessage: 'aborted' };\n }\n params.abortSignal.addEventListener('abort', abortListener, { once: true });\n }\n\n try {\n await runAgentTurnWithTimeout(\n session.agent,\n async () => {\n const text = userMessageToPromptText(userMessage);\n const images = params.images ?? [];\n await session.prompt(text, images.length > 0 ? { images } : undefined);\n await session.agent.waitForIdle();\n await maybeRetryTurnAfterTransientLlmFailure(session.agent, { sessionKey, log });\n },\n timeoutMs,\n );\n\n if (isAssistantTurnAborted(session.agent)) {\n return { ok: true, lastAssistantText: lastAssistantPlainText(session) };\n }\n if (isAssistantTurnFailed(session.agent)) {\n return {\n ok: false,\n errorMessage: getAssistantTurnErrorMessage(session.agent) ?? 'Assistant turn failed',\n lastAssistantText: lastAssistantPlainText(session),\n };\n }\n\n return { ok: true, lastAssistantText: lastAssistantPlainText(session) };\n } finally {\n params.abortSignal?.removeEventListener('abort', abortListener);\n unregisterEmbeddedRun(handle);\n }\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, sessionKey, runId }, `Embedded run failed: ${em}`);\n onEvent?.({ type: 'error', content: em, runId });\n return { ok: false, errorMessage: em };\n } finally {\n unsubscribe?.();\n try {\n runner?.piSm.flushPendingToolResults?.();\n } catch {\n /* ignore */\n }\n runner?.release();\n }\n}\n\nexport { abortEmbeddedRun, queueEmbeddedSteer } from './runs.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-turn.js","names":[],"sources":["../../../../src/agent/embedded/run-turn.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\n\nimport { createLogger } from '../../utils/logger.js';\nimport { registerEmbeddedRun, unregisterEmbeddedRun } from './runs.js';\nimport { subscribeEmbeddedSessionEvents, lastAssistantPlainText } from './subscribe-session.js';\nimport type { RunXopcEmbeddedTurnParams, RunXopcEmbeddedTurnResult } from './types.js';\nimport {\n getAssistantTurnErrorMessage,\n isAssistantTurnAborted,\n isAssistantTurnFailed,\n maybeRetryTurnAfterTransientLlmFailure,\n} from '../orchestration/llm-turn-retry.js';\nimport { runAgentTurnWithTimeout, resolveAgentTurnTimeoutMs } from '../orchestration/run-agent-turn-with-timeout.js';\nimport { detectToolLoops, type RecentToolCall } from '../orchestration/loop-guard.js';\nimport {\n acquireEmbeddedSessionRunner,\n resolveEmbeddedTranscriptInputs,\n} from './session-runner.js';\nimport { wrapStreamFnForXopcExtensions } from './xopc-stream-bridge.js';\n\nconst log = createLogger('EmbeddedRun');\nconst LOG_PREVIEW_MAX_CHARS = 300;\n\nfunction truncateForLog(value: string, maxChars = LOG_PREVIEW_MAX_CHARS): string {\n return value.length > maxChars ? `${value.slice(0, maxChars)}…` : value;\n}\n\nfunction extractTextFromContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (!Array.isArray(content)) {\n return '';\n }\n return content\n .filter((block): block is { type: string; text: string } => {\n return !!block && typeof block === 'object' && (block as { type?: string }).type === 'text';\n })\n .map((block) => block.text)\n .join('');\n}\n\nfunction extractRecentToolCalls(messages: readonly { role?: string; content?: unknown }[]): RecentToolCall[] {\n const calls: RecentToolCall[] = [];\n for (const message of messages) {\n if (message.role !== 'assistant' || !Array.isArray(message.content)) continue;\n for (const block of message.content) {\n if (block && typeof block === 'object' && (block as { type?: string }).type === 'toolCall') {\n const toolCall = block as { name: string; arguments: unknown };\n calls.push({ name: toolCall.name, params: toolCall.arguments });\n }\n }\n }\n return calls;\n}\n\nfunction getLastUserMessagePreview(messages: readonly { role?: string; content?: unknown }[]): string | undefined {\n for (let messageIndex = messages.length - 1; messageIndex >= 0; messageIndex--) {\n const message = messages[messageIndex];\n if (message?.role !== 'user') {\n continue;\n }\n const text = extractTextFromContent(message.content).trim();\n return text ? truncateForLog(text) : undefined;\n }\n return undefined;\n}\n\nfunction requireEmbeddedModel(model: Model<Api> | undefined, modelRef: string): Model<Api> {\n if (!model?.id || !model?.provider) {\n throw new Error(`Invalid model for embedded run: ${modelRef}`);\n }\n return model;\n}\n\nfunction userMessageToPromptText(message: AgentMessage): string {\n const content = (message as { content?: unknown }).content;\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n return content\n .filter((block): block is { type: 'text'; text: string } => {\n return !!block && typeof block === 'object' && (block as { type?: string }).type === 'text';\n })\n .map((block) => block.text)\n .join('');\n }\n return '';\n}\n\nexport async function runXopcEmbeddedTurn(params: RunXopcEmbeddedTurnParams): Promise<RunXopcEmbeddedTurnResult> {\n const {\n sessionKey,\n runId,\n userMessage,\n model,\n tools,\n systemPrompt,\n thinkingLevel,\n workspaceDir,\n sessionStore,\n onEvent,\n } = params;\n\n const timeoutMs = params.timeoutMs || resolveAgentTurnTimeoutMs();\n const resolvedModel = requireEmbeddedModel(model, params.modelRef);\n const transcript = await resolveEmbeddedTranscriptInputs(sessionStore, sessionKey);\n\n let runner: Awaited<ReturnType<typeof acquireEmbeddedSessionRunner>> | undefined;\n let unsubscribe: (() => void) | undefined;\n\n try {\n runner = await acquireEmbeddedSessionRunner({\n sessionKey,\n sessionId: transcript.sessionId,\n workspaceDir,\n model: resolvedModel,\n modelRef: params.modelRef,\n tools,\n systemPrompt,\n thinkingLevel: thinkingLevel ?? 'medium',\n });\n\n const { session, reused } = runner;\n\n const streamFnWithXopcExtensions = wrapStreamFnForXopcExtensions(session.agent.streamFn);\n const loggingStreamFn: typeof session.agent.streamFn = (streamModel, context, options) => {\n const recentToolCalls = extractRecentToolCalls(context.messages);\n const loopGuard = detectToolLoops(recentToolCalls);\n\n let effectiveContext = context;\n if (loopGuard.injection || loopGuard.hiddenTools.size > 0) {\n const messages = loopGuard.injection\n ? [...context.messages, { role: 'user' as const, content: loopGuard.injection, timestamp: Date.now() }]\n : context.messages;\n\n const contextTools = loopGuard.hiddenTools.size > 0 && context.tools\n ? context.tools.filter((t) => !loopGuard.hiddenTools.has(t.name))\n : context.tools;\n\n effectiveContext = { ...context, messages, tools: contextTools };\n }\n\n log.debug(\n {\n sessionKey,\n runId,\n reusedRunner: reused,\n modelRef: `${streamModel.provider}/${streamModel.id}`,\n systemPromptLength: effectiveContext.systemPrompt?.length ?? 0,\n messageCount: effectiveContext.messages.length,\n toolCount: effectiveContext.tools?.length ?? 0,\n lastUserMessagePreview: getLastUserMessagePreview(effectiveContext.messages),\n loopWarningInjected: !!loopGuard.injection,\n hiddenToolCount: loopGuard.hiddenTools.size,\n ...(process.env.XOPC_LOG_LLM_PAYLOAD === 'true'\n ? {\n effectiveContext: {\n systemPrompt: effectiveContext.systemPrompt,\n messages: effectiveContext.messages,\n tools: effectiveContext.tools,\n },\n }\n : {}),\n },\n 'Sending messages to AI',\n );\n return streamFnWithXopcExtensions(streamModel, effectiveContext, options);\n };\n session.agent.streamFn = loggingStreamFn;\n\n if (onEvent) {\n unsubscribe = subscribeEmbeddedSessionEvents(session, (event) => {\n onEvent({ ...event, runId });\n });\n }\n\n const handle = {\n sessionKey,\n sessionId: transcript.sessionId,\n runId,\n session,\n abort: async () => {\n await session.abort();\n },\n };\n registerEmbeddedRun(handle);\n\n const abortListener = () => {\n void session.abort();\n };\n if (params.abortSignal) {\n if (params.abortSignal.aborted) {\n await session.abort();\n return { ok: false, errorMessage: 'aborted' };\n }\n params.abortSignal.addEventListener('abort', abortListener, { once: true });\n }\n\n try {\n await runAgentTurnWithTimeout(\n session.agent,\n async () => {\n const text = userMessageToPromptText(userMessage);\n const images = params.images ?? [];\n await session.prompt(text, images.length > 0 ? { images } : undefined);\n await session.agent.waitForIdle();\n await maybeRetryTurnAfterTransientLlmFailure(session.agent, { sessionKey, log });\n },\n timeoutMs,\n );\n\n if (isAssistantTurnAborted(session.agent)) {\n return { ok: true, lastAssistantText: lastAssistantPlainText(session) };\n }\n if (isAssistantTurnFailed(session.agent)) {\n return {\n ok: false,\n errorMessage: getAssistantTurnErrorMessage(session.agent) ?? 'Assistant turn failed',\n lastAssistantText: lastAssistantPlainText(session),\n };\n }\n\n return { ok: true, lastAssistantText: lastAssistantPlainText(session) };\n } finally {\n params.abortSignal?.removeEventListener('abort', abortListener);\n unregisterEmbeddedRun(handle);\n }\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, sessionKey, runId }, `Embedded run failed: ${em}`);\n onEvent?.({ type: 'error', content: em, runId });\n return { ok: false, errorMessage: em };\n } finally {\n unsubscribe?.();\n try {\n runner?.piSm.flushPendingToolResults?.();\n } catch {\n /* ignore */\n }\n runner?.release();\n }\n}\n\nexport { abortEmbeddedRun, queueEmbeddedSteer } from './runs.js';\n"],"mappings":"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"}
|
|
@@ -45,6 +45,23 @@ export type EmbeddedStreamEvent = {
|
|
|
45
45
|
runId?: string;
|
|
46
46
|
stage: string;
|
|
47
47
|
message: string;
|
|
48
|
+
} | {
|
|
49
|
+
type: 'memory_consent_required';
|
|
50
|
+
runId?: string;
|
|
51
|
+
requests: Array<{
|
|
52
|
+
id: string;
|
|
53
|
+
recordId: string;
|
|
54
|
+
statement: string;
|
|
55
|
+
purpose: string;
|
|
56
|
+
}>;
|
|
57
|
+
} | {
|
|
58
|
+
type: 'memory_captured';
|
|
59
|
+
runId?: string;
|
|
60
|
+
records: Array<{
|
|
61
|
+
id: string;
|
|
62
|
+
content: string;
|
|
63
|
+
kind: string;
|
|
64
|
+
}>;
|
|
48
65
|
} | {
|
|
49
66
|
type: 'error';
|
|
50
67
|
runId?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bounded curated memory
|
|
2
|
+
* Bounded curated memory under the shared user context directory, §-delimited entries.
|
|
3
3
|
* Snapshot for system prompt is captured at load time and not mutated until next load.
|
|
4
4
|
*/
|
|
5
5
|
import type { MemorySnapshot, MemoryStoreConfig } from './types.js';
|
|
@@ -12,7 +12,7 @@ export declare class BuiltinMemoryStore {
|
|
|
12
12
|
constructor(config: MemoryStoreConfig);
|
|
13
13
|
/** When false, global user memory is omitted from the snapshot and should not be edited via `curated_memory`. */
|
|
14
14
|
isUserProfileEnabled(): boolean;
|
|
15
|
-
/**
|
|
15
|
+
/** Shared curated memory directory (`~/.xopc/user/memories/`). */
|
|
16
16
|
get memoriesDir(): string;
|
|
17
17
|
/** Global user memory file (`~/.xopc/user/MEMORY.md`). */
|
|
18
18
|
get userMemoryPath(): string;
|
|
@@ -4,7 +4,7 @@ import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
|
4
4
|
import lockfile from "proper-lockfile";
|
|
5
5
|
//#region src/agent/memory/builtin-memory-store.ts
|
|
6
6
|
/**
|
|
7
|
-
* Bounded curated memory
|
|
7
|
+
* Bounded curated memory under the shared user context directory, §-delimited entries.
|
|
8
8
|
* Snapshot for system prompt is captured at load time and not mutated until next load.
|
|
9
9
|
*/
|
|
10
10
|
const MEMORY_ENTRY_DELIMITER = "\n§\n";
|
|
@@ -24,7 +24,7 @@ var BuiltinMemoryStore = class {
|
|
|
24
24
|
isUserProfileEnabled() {
|
|
25
25
|
return this.config.userProfileEnabled !== false;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
27
|
+
/** Shared curated memory directory (`~/.xopc/user/memories/`). */
|
|
28
28
|
get memoriesDir() {
|
|
29
29
|
return this.config.memoriesDir;
|
|
30
30
|
}
|