@xopcai/xopc 0.0.113 → 0.0.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CBlklyNr.js → agent-avatar-dicebear-DVnBfANm.js} +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-DPXc4hz8.js +6 -0
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CTJ0YnRQ.js +1 -0
- package/dist/gateway/static/root/assets/agents-zJXQfJ_W.js +71 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-28E_WfMe.js → app-management-settings-panel-DzGbdr04.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-Do1z0XgJ.js → appearance-settings-BQpPSTHD.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CPjfyzSD.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BAFlsov_.js → archive-plugin-CXu-Csep.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-V3qGPC3x.js → attachment-load-BAjgOoGY.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-DT8NvA6W.js → binary-plugins-BSBgB2hO.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CdLMEcHd.js → block-editor-BpXw9TTR.js} +3 -3
- package/dist/gateway/static/root/assets/channels-settings-BbPUpzWB.js +1 -0
- package/dist/gateway/static/root/assets/{config-api-Bf5mjpu7.js → config-api-NOoPiIYz.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-settings-CAXYMOdp.js +2 -0
- package/dist/gateway/static/root/assets/{cron-api--pAB_rps.js → cron-api-C9BOqAXd.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-DuUbBeKI.js +3 -0
- package/dist/gateway/static/root/assets/{dreaming-settings-6UZE1FSK.js → dreaming-settings-DQ4DtiK1.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BGhE7msg.js → extension-debug-page-D9kgUHCc.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CvpI45WG.js → extension-page-CGyhXqzR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DAmR5FUe.js → extension-settings-page-DL8Xquqd.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-NZmjSXLl.js → fetch-D0VXA932.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-qhth3BMV.js → format-interval-label-Be8SmgUw.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CaXBt-9R.js → gateway-config-api-C-xjn__h.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DphpbLBc.js → gateway-settings-BMPwIjKI.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Be1omjh3.js → gateway-startup-retry-DERUH61L.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BJsyjJnF.js +1 -0
- package/dist/gateway/static/root/assets/goals-config-api-BPmqWk90.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-BerDgIhw.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-ByTjeAto.js +1 -0
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BzO6G4fD.js → heartbeat-config-api-Bfdzr8oV.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DCST9-du.js → heartbeat-settings-TbHgcjTn.js} +1 -1
- package/dist/gateway/static/root/assets/index-AkTrf6Pb.js +122 -0
- package/dist/gateway/static/root/assets/index-fh5sXTj9.css +1 -0
- package/dist/gateway/static/root/assets/{interval-presets-DJmshV8n.js → interval-presets-utKbuCRY.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-9AUUlQ5Q.js → keyboard-shortcuts-settings-CjqS6c6V.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DGXuPf5B.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-CYYELqAr.js → markdown-split-DW8C47iB.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BEcMR2M8.js → media-plugins-D6HwDhDT.js} +1 -1
- package/dist/gateway/static/root/assets/messages-upgxw6Ub.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-Bot16nn7.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-Brlyou8M.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-DNAoPcmm.js → note-image-lightbox-pJM35Pz5.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DvZ4pwc-.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BPLz0AIv.js → preview-open-alternatives-CVwHuyN6.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BZEDmxbZ.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-CrWwWRVK.js → save-bar-controls-Ba-UEk7x.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CF2sadvN.js → schedule-field-CNN9595U.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Di5cKjYE.js → schema-form-DnNMmtD5.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DdGGlsfn.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DlkEkPf9.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-Chh282jW.js → settings-collapsible-section-CmOz80i5.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Dq-83cQd.js → settings-form-section-BmK7JJOV.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DFPTrsPF.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-CYCCfgh4.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-0FXYnSUA.js → share-preview-page-Dp2qGrHC.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Bff1pGd0.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CJGKpBur.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-C6ocduTD.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-W1pTcojB.js → system-settings-panel-5jrIEr5b.js} +1 -1
- package/dist/gateway/static/root/assets/{use-agent-defaults-form-BVRvkK7m.js → use-agent-defaults-form-BuiXLIs5.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CgJibfMM.js → use-channel-catalog-CHlO8J9G.js} +1 -1
- package/dist/gateway/static/root/assets/{use-settings-tab-guard-Bw_qkRQE.js → use-settings-tab-guard-CW5JORnl.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DDoQyghO.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-C7lziaAx.js → voice-player-store-DDDWYHvg.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-CKjeEGqx.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-B604ehHG.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/gateway/static/root/logo.svg +4 -3
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +8 -0
- package/dist/src/agent/agent-manager.js +63 -28
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
- package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
- package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/context/workspace.js +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +8 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/goals/checklist-judge.d.ts +1 -0
- package/dist/src/agent/goals/checklist-judge.js +3 -2
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/evaluate-turn.d.ts +1 -1
- package/dist/src/agent/goals/evaluate-turn.js +1 -0
- package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.js +2 -2
- package/dist/src/agent/goals/persistent-goal-service.js +2 -4
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.d.ts +6 -1
- package/dist/src/agent/goals/post-turn.js +15 -6
- package/dist/src/agent/goals/post-turn.js.map +1 -1
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/inbound/inbound-loop.js +5 -1
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/ipc/inbox.js +3 -3
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +50 -2
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +79 -4
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/memory/index.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/btw-query.js +11 -3
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
- package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
- package/dist/src/agent/service/process-direct-one-shot.js +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +1 -1
- package/dist/src/agent/service.js +13 -9
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +5 -0
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +2 -2
- package/dist/src/agent/skills/filesystem-watcher.js +5 -4
- package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +4 -3
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/installer.js +2 -2
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +3 -2
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/skills/skill-view-path.js +1 -1
- package/dist/src/agent/skills/test-framework.js +1 -1
- package/dist/src/agent/skills/types.d.ts +1 -1
- package/dist/src/agent/skills/watcher.js +2 -5
- package/dist/src/agent/skills/watcher.js.map +1 -1
- package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
- package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
- package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
- package/dist/src/agent/starter-agents.js +1 -1
- package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
- package/dist/src/agent/tool-manuals/browser.js +62 -3
- package/dist/src/agent/tool-manuals/browser.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
- package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
- package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -10
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +1 -1
- package/dist/src/agent/tools/grep.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +2 -2
- package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/snapshot.d.ts +10 -0
- package/dist/src/agent/workflow/snapshot.js +136 -1
- package/dist/src/agent/workflow/snapshot.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +18 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/profiles/store.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
- package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
- package/dist/src/browser/actions/registry.js +383 -7
- package/dist/src/browser/actions/registry.js.map +1 -1
- package/dist/src/browser/actions/types.d.ts +11 -3
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/index.js +2 -2
- package/dist/src/browser/pipeline/output.d.ts +18 -16
- package/dist/src/browser/pipeline/output.js +28 -20
- package/dist/src/browser/pipeline/output.js.map +1 -1
- package/dist/src/browser/pipeline/runner.d.ts +7 -14
- package/dist/src/browser/pipeline/runner.js +349 -102
- package/dist/src/browser/pipeline/runner.js.map +1 -1
- package/dist/src/browser/pipeline/schema.d.ts +1 -0
- package/dist/src/browser/pipeline/schema.js +35 -58
- package/dist/src/browser/pipeline/schema.js.map +1 -1
- package/dist/src/browser/pipeline/source.d.ts +2 -0
- package/dist/src/browser/pipeline/source.js +10 -1
- package/dist/src/browser/pipeline/source.js.map +1 -1
- package/dist/src/browser/pipeline/template.d.ts +10 -2
- package/dist/src/browser/pipeline/template.js +50 -8
- package/dist/src/browser/pipeline/template.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/cloakbrowser.js +5 -5
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/catalog/channel-catalog-service.d.ts +2 -1
- package/dist/src/channels/catalog/channel-catalog-service.js +133 -16
- package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
- package/dist/src/channels/catalog/channel-catalog-types.d.ts +13 -0
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +5 -7
- package/dist/src/chat-commands/builtins/config.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +5 -0
- package/dist/src/chat-commands/context.js +18 -9
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +1 -1
- package/dist/src/chat-commands/index.js +2 -2
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/processor.js +22 -21
- package/dist/src/chat-commands/processor.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +3 -15
- package/dist/src/chat-commands/session-key.js +3 -49
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +4 -0
- package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.js +14 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-create.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +2 -2
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension-pack.js +2 -2
- package/dist/src/cli/commands/extension.js +3 -3
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +2 -2
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/skills-test.js +1 -1
- package/dist/src/cli/templates.js +1 -1
- package/dist/src/cli/utils/gateway-client.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/agent-typed-models.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +7 -7
- package/dist/src/config/loader.js +4 -4
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/paths.js +1 -1
- package/dist/src/config/profile.js +1 -1
- package/dist/src/config/reload.js +1 -1
- package/dist/src/config/rules.js +5 -0
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +8 -0
- package/dist/src/config/schema.js +7 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +1 -0
- package/dist/src/config/web-patch.js +1 -0
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/connectors/builtin-catalog.js +180 -1
- package/dist/src/connectors/builtin-catalog.js.map +1 -1
- package/dist/src/connectors/health.js +18 -9
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/types.d.ts +19 -0
- package/dist/src/connectors/usage.js +12 -4
- package/dist/src/connectors/usage.js.map +1 -1
- package/dist/src/cron/executor.js +1 -1
- package/dist/src/cron/service.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +2 -2
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/install.js +2 -2
- package/dist/src/extensions/loader.js +2 -2
- package/dist/src/extensions/lockfile.js +3 -3
- package/dist/src/extensions/security.js +1 -1
- package/dist/src/extensions/types/tui.d.ts +2 -0
- package/dist/src/extensions/update.js +2 -2
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +13 -1
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +18 -5
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
- package/dist/src/gateway/hono/lib/config-payload.js +7 -4
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +19 -5
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -1
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
- package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/channels.js +18 -14
- package/dist/src/gateway/hono/routes/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/goals.js +16 -3
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/logs.js +1 -0
- package/dist/src/gateway/hono/routes/logs.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +27 -8
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/notes.js +14 -2
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +62 -4
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +5 -68
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.d.ts +2 -2
- package/dist/src/gateway/hono/sse.js +7 -15
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +12 -0
- package/dist/src/gateway/rate-limit/buckets.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
- package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +2 -3
- package/dist/src/gateway/service/agent-runner.js +9 -22
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service/run-gateway-agent.js +9 -7
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +9 -0
- package/dist/src/gateway/service/sessions-api.js +11 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +23 -9
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-file-search.d.ts +9 -0
- package/dist/src/gateway/workspace-file-search.js +76 -0
- package/dist/src/gateway/workspace-file-search.js.map +1 -0
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/goals/goal-notifications.d.ts +2 -0
- package/dist/src/goals/goal-notifications.js +16 -11
- package/dist/src/goals/goal-notifications.js.map +1 -1
- package/dist/src/goals/goal-service.js +1 -6
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/goals/goal-workflow-judge.js +2 -2
- package/dist/src/i18n/goals-bundle.js +1 -1
- package/dist/src/i18n/index.js +1 -1
- package/dist/src/i18n/share-tool-bundle.js +2 -2
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +1 -1
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +2 -2
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +1 -1
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/agent-context.js +1 -1
- package/dist/src/notes/service.js +1 -1
- package/dist/src/notes/store.js +2 -2
- package/dist/src/project-trust/trust-store.js +4 -2
- package/dist/src/project-trust/trust-store.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +1 -1
- package/dist/src/providers/model-registry.js +4 -4
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +2 -2
- package/dist/src/session/init-session-turn.js +7 -10
- package/dist/src/session/init-session-turn.js.map +1 -1
- package/dist/src/session/manager.d.ts +5 -1
- package/dist/src/session/manager.js +5 -2
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/reset-type.d.ts +0 -2
- package/dist/src/session/reset-type.js +3 -9
- package/dist/src/session/reset-type.js.map +1 -1
- package/dist/src/session/resolve-session.js +10 -21
- package/dist/src/session/resolve-session.js.map +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.d.ts +11 -3
- package/dist/src/session/store.js +30 -14
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +2 -4
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +1 -1
- package/dist/src/storage/sqlite/index.d.ts +2 -2
- package/dist/src/storage/sqlite/index.js +3 -3
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
- package/dist/src/storage/sqlite/migrations/runner.js +5 -5
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
- package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
- package/dist/src/storage/sqlite/row-mappers.js +11 -14
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +4 -4
- package/dist/src/storage/sqlite/schema.js.map +1 -1
- package/dist/src/storage/sqlite/schema.sql +37 -10
- package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
- package/dist/src/storage/sqlite/session-metadata.js +18 -72
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
- package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
- package/dist/src/storage/sqlite/session-repository.js +34 -40
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
- package/dist/src/storage/sqlite/transcript-repository.js +52 -52
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +18 -4
- package/dist/src/tui/backends/embedded-backend.js +100 -1
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +5 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +45 -2
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/components/chat-log.d.ts +2 -0
- package/dist/src/tui/components/chat-log.js +19 -0
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/extension-host/autocomplete.d.ts +3 -2
- package/dist/src/tui/extension-host/autocomplete.js +29 -12
- package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/extension-host/runtime.d.ts +12 -0
- package/dist/src/tui/extension-host/runtime.js +6 -4
- package/dist/src/tui/extension-host/runtime.js.map +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-backend.d.ts +23 -0
- package/dist/src/tui/tui-command-formatters.js +4 -4
- package/dist/src/tui/tui-commands.d.ts +16 -3
- package/dist/src/tui/tui-commands.js +134 -27
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
- package/dist/src/tui/tui-file-autocomplete.js +26 -0
- package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-picker-overlay.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui-startup-text.js +1 -1
- package/dist/src/tui/tui-startup-text.js.map +1 -1
- package/dist/src/tui/tui.js +106 -17
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/tunnel/frpc-binary.js +4 -4
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/context.d.ts +2 -2
- package/dist/src/utils/logger/context.js +2 -1
- package/dist/src/utils/logger/context.js.map +1 -1
- package/dist/src/utils/logger/log-store.js +2 -1
- package/dist/src/utils/logger/log-store.js.map +1 -1
- package/dist/src/utils/logger/pino-record.js +3 -0
- package/dist/src/utils/logger/pino-record.js.map +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/logger/streams.js +1 -1
- package/dist/src/utils/logger/types.d.ts +5 -0
- package/dist/src/utils/logger/types.js.map +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +0 -6
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CtwVbjOA.js +0 -1
- package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +0 -71
- package/dist/gateway/static/root/assets/apps-page-xwCsJS15.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-C044DcYk.js +0 -1
- package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +0 -3
- package/dist/gateway/static/root/assets/goal-detail-page-bv0VRDaf.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-ceEBjnfc.js +0 -1
- package/dist/gateway/static/root/assets/index-Cxm6xsps.js +0 -122
- package/dist/gateway/static/root/assets/index-b_R4tKqt.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-B_wrxhee.js +0 -2
- package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-CdkjTch8.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DSYVAi96.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CenkcVjF.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DL35U0x0.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DIM3JNsr.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-vYAO71Gn.js +0 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-sgHjOXOm.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-DYyOTmFx.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-manager.js","names":[],"sources":["../../../src/agent/agent-manager.ts"],"sourcesContent":["/**\n * Agent Manager - Manages Agent instances per session\n *\n * Each session gets its own Agent instance for true isolation\n * and concurrent processing across sessions.\n */\n\nimport {\n Agent,\n type AgentMessage,\n type AgentEvent,\n type ThinkingLevel,\n} from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\nimport type { AgentInstanceGateway } from './agent-instance-gateway.js';\nimport { type Config, getAgentDefaultModelRef } from '../config/schema.js';\nimport { applyConfigOverrides } from '../config/runtime-overrides.js';\nimport { resolveAgentProfileDir } from './agent-scope.js';\nimport {\n type EffectiveAgentProfile,\n resolveEffectiveAgentProfile,\n resolveEffectiveAgentProfileForSession,\n} from '../config/agent-profile.js';\nimport { expandWorkspacePathString } from '../config/workspace-path.js';\nimport type { ModelManager } from './models/manager.js';\nimport { createLogger } from '../utils/logger.js';\nimport { resolveProviderApiKeySync } from '../auth/sync-provider-auth.js';\nimport { resolveModel, getDefaultModelSync, getApiKeySync } from '../providers/index.js';\nimport { createExtensionAwareStreamFn } from '../providers/extension-stream-bridge.js';\nimport { CredentialResolver } from '../auth/credentials.js';\nimport { resolveBundledSkillsDir, resolveStateDir } from '../config/paths.js';\nimport { loadProfileMarkdownFiles, extractTextContent } from './context/workspace.js';\nimport { clearBootstrapSnapshot, resolveBootstrapContextSync } from './bootstrap/bootstrap-files.js';\nimport type { EmbeddedContextFile } from './bootstrap/types.js';\nimport { AgentToolsFactory } from './tools/factory.js';\nimport { parseMcpToolName } from './mcp/bundle-mcp-policy.js';\nimport {\n disposeAllSessionMcpRuntimes,\n retireSessionMcpRuntimeForSessionKey,\n} from './mcp/bundle-mcp-tools.js';\nimport { evictAllEmbeddedSessionRunners, evictEmbeddedSessionRunner } from './embedded/session-runner.js';\nimport type { GatewayClarifyRequestFn } from './tools/clarify-tool.js';\nimport type { ExtensionRegistryImpl as ExtensionRegistry } from '../extensions/index.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { CronService } from '../cron/index.js';\nimport type { SessionStore } from '../session/store.js';\nimport { isValidSkillEnvVarName } from './skills/required-env-vars.js';\nimport type { SessionContext } from './session/session-context.js';\nimport type {\n Skill,\n SkillDiagnostic,\n SkillMarkdownPreviewPayload,\n SkillRuntimeStatus,\n} from './skills/types.js';\nimport { createSkillConfigManager, isSkillEnabled, resolveSkillConfig } from './skills/config.js';\nimport { isUnderManagedSkillsDir } from './skills/managed-store.js';\nimport { loadSkillsLock, type SkillHubLockEntry } from './skills/hub-lock.js';\nimport { basename, resolve, sep } from 'node:path';\n\nimport {\n isMemorySubsystemEnabled,\n shouldRegisterCuratedMemoryTool,\n} from './memory/memory-config.js';\nimport type { MemoryManager } from './memory/manager.js';\nimport { MemoryPrefetchCoordinator } from './memory/prefetch-coordinator.js';\nimport { WorkspaceRuntimeRegistry, type WorkspaceRuntime } from './workspace-runtime/registry.js';\nimport { BackgroundReviewCoordinator } from './background-review/coordinator.js';\nimport { maybeRequestChannelExecApproval } from '../channels/exec-approval-runtime.js';\nimport { SkillFilesystemWatcher } from './skills/filesystem-watcher.js';\n\nconst log = createLogger('AgentManager');\n\nexport interface SkillCatalogEntry {\n directoryId: string;\n name: string;\n description: string;\n category?: string;\n source: Skill['source'];\n path: string;\n managed: boolean;\n /** User toggle in ~/.xopc/skills.json (`entries[name].enabled`). Default true. */\n enabled: boolean;\n /** When true, skill is never injected into `<available_skills>` (SKILL.md frontmatter). */\n disableModelInvocation: boolean;\n /** Hub install provenance when under ~/.xopc/skills and listed in skills-lock.json. */\n hub?: SkillHubLockEntry;\n}\n\nexport interface SkillCatalogRuntimeMeta {\n version: string;\n loadedAt: number;\n diagnostics: SkillDiagnostic[];\n status: SkillRuntimeStatus;\n}\n\nexport interface SkillCatalogSnapshot extends SkillCatalogRuntimeMeta {\n catalog: SkillCatalogEntry[];\n}\n\nexport type AgentSkillUnavailableReason = 'agent-denied' | 'disabled' | 'requirements-unmet' | 'model-invocation-disabled';\n\nexport interface AgentSkillAvailabilityEntry extends SkillCatalogEntry {\n availableForCurrentAgent: boolean;\n unavailableReason: AgentSkillUnavailableReason | null;\n}\n\nexport interface AgentSkillAvailabilityPayload {\n agentId: string;\n version: string;\n loadedAt: number;\n diagnostics: SkillDiagnostic[];\n status: SkillRuntimeStatus;\n defaultsAllowlist?: string[];\n agentAllowlist?: string[];\n effectiveAllowlist?: string[];\n skills: AgentSkillAvailabilityEntry[];\n}\n\nexport interface AgentManagerConfig {\n workspace: string;\n model?: string;\n config?: Config;\n extensionRegistry?: ExtensionRegistry;\n hookRunner?: import('../extensions/index.js').ExtensionHookRunner;\n bus: MessageBus;\n getCurrentContext: () => SessionContext | null;\n /** Session persistence (enables `session_search` when set). */\n getSessionStore?: () => SessionStore;\n /** Clears per-session profile default on teardown. */\n getModelManager?: () => ModelManager;\n // Thinking configuration\n thinkingLevel?: ThinkingLevel;\n reasoningLevel?: 'off' | 'on' | 'stream';\n verboseLevel?: 'off' | 'on' | 'full';\n gatewayClarify?: { requestClarification: GatewayClarifyRequestFn };\n /** Gateway: exposes CronService for the `cronjob` tool. */\n getCronService?: () => CronService | undefined;\n /** Gateway: starts persisted workflow runs (dedicated chat session per run). */\n getWorkflowRunService?: () => import('../workflows/service/workflow-run-service.types.js').WorkflowRunServiceLike | undefined;\n /** Runtime notification for UI/CLI shells that cache skill catalogs. */\n onSkillsUpdated?: (payload: { reason: 'disk' | 'config' }) => void;\n}\n\nexport interface AgentInstance {\n agent: Agent;\n sessionKey: string;\n createdAt: number;\n lastUsedAt: number;\n effectiveProfile: EffectiveAgentProfile;\n resolvedWorkspacePath: string;\n /** Tool names registered on this agent (for skill indexing / tool gating). */\n registeredToolNames: string[];\n /** Declared env var names from skill_view; shell reads values from process.env at spawn time. */\n skillEnvPassthroughKeys: Set<string>;\n}\n\n\nexport class AgentManager implements AgentInstanceGateway {\n private agents = new Map<string, AgentInstance>();\n private config: AgentManagerConfig;\n private toolsFactory: AgentToolsFactory;\n\n private mergedConfig(): Config | undefined {\n const base = this.config.config;\n return base ? applyConfigOverrides(base) : undefined;\n }\n /** Default agent workspace (effective profile for `getDefaultAgentId`). */\n private baseWorkspacePath: string;\n /** Per-session absolute markdown workspace when `SessionAgentConfig.workingDirectoryOverride` is set. */\n private sessionWorkspaceOverrides = new Map<string, string>();\n private defaultModel: string;\n private credentialCache = new Map<string, string>();\n private credentialResolver: CredentialResolver;\n private workspaceRuntimes: WorkspaceRuntimeRegistry;\n private memoryPrefetch: MemoryPrefetchCoordinator;\n private backgroundReview: BackgroundReviewCoordinator;\n private skillFilesystemWatcher: SkillFilesystemWatcher;\n private skillDiskRefreshInProgress = false;\n private skillDiskRefreshPending = false;\n private lastExplicitSkillDiskRefreshAt = 0;\n private skillsUpdatedTimer: NodeJS.Timeout | undefined;\n private pendingSkillsUpdatedReason: 'disk' | 'config' | undefined;\n\n constructor(config: AgentManagerConfig) {\n this.config = config;\n this.baseWorkspacePath = this.computeBaseWorkspacePath();\n this.skillFilesystemWatcher = new SkillFilesystemWatcher({\n onChange: (event) => {\n log.info({ changedPath: event.changedPath }, 'Skill filesystem changed; refreshing skills');\n this.refreshSkillsAfterDiskChange('watch');\n },\n });\n this.skillFilesystemWatcher.refreshPrimaryWorkspace(this.baseWorkspacePath);\n this.workspaceRuntimes = new WorkspaceRuntimeRegistry({\n getConfig: () => this.config.config!,\n bundledSkillsDir: resolveBundledSkillsDir(),\n onRuntimeCreated: (resolvedPath) => {\n this.skillFilesystemWatcher.watchWorkspace(resolvedPath);\n },\n });\n this.memoryPrefetch = new MemoryPrefetchCoordinator({\n getConfig: () => this.config.config,\n getMemoryManagerForSession: (sk) => this.getMemoryManagerForSession(sk),\n getLastAssistantContent: (sk) => this.getLastAssistantContent(sk),\n });\n this.backgroundReview = new BackgroundReviewCoordinator({\n getConfig: () => this.mergedConfig(),\n onSkillsFilesystemMutate: () => this.refreshSkillsAfterDiskChange('explicit'),\n });\n this.toolsFactory = new AgentToolsFactory(this.buildToolsFactoryDeps());\n\n this.defaultModel = config.model || getDefaultModelSync(config.config);\n\n this.credentialResolver = new CredentialResolver();\n this.warmCredentialCache().catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn({ err, errorMessage: em }, `Credential cache pre-warm failed: ${em}`);\n });\n }\n\n private computeBaseWorkspacePath(): string {\n const cfg = this.config.config;\n if (!cfg) {\n return expandWorkspacePathString(this.config.workspace);\n }\n return resolveEffectiveAgentProfileForSession(cfg, null).resolvedWorkspacePath;\n }\n\n /**\n * Workspace root for inbound attachments / side effects for this session's agent id.\n * Uses in-memory session workspace overrides when the session has a persisted `workingDirectoryOverride`.\n */\n getResolvedWorkspaceForSession(sessionKey: string): string {\n const cfg = this.config.config!;\n const fromMap = this.sessionWorkspaceOverrides.get(sessionKey);\n if (fromMap !== undefined) {\n return fromMap;\n }\n return resolveEffectiveAgentProfileForSession(cfg, sessionKey).resolvedWorkspacePath;\n }\n\n /**\n * Sync in-memory workspace override from session config (after load or PATCH).\n * Pass `null` to clear when the session has no `workingDirectoryOverride` on disk.\n */\n setSessionWorkspaceOverride(sessionKey: string, absolutePath: string | null): void {\n if (absolutePath === null || absolutePath === '') {\n this.sessionWorkspaceOverrides.delete(sessionKey);\n } else {\n this.sessionWorkspaceOverrides.set(sessionKey, absolutePath);\n }\n }\n\n /** Merged `thinkingDefault` for this session's agent id (defaults + `agents.list`). */\n getThinkingDefaultForSession(\n sessionKey: string,\n ): import('./transcript/thinking-types.js').ThinkLevel | undefined {\n const cfg = this.mergedConfig();\n if (!cfg) {\n return undefined;\n }\n return resolveEffectiveAgentProfileForSession(cfg, sessionKey).thinkingDefault;\n }\n\n private pickDefaultModelRef(): string {\n const cfg = this.mergedConfig();\n const ref = getAgentDefaultModelRef(cfg);\n return ref?.trim() || getDefaultModelSync(cfg);\n }\n\n private resolveModelStringToModel(modelRef: string): Model<Api> {\n try {\n return resolveModel(modelRef);\n } catch {\n const fallback = getDefaultModelSync(this.mergedConfig());\n log.warn({ modelRef, fallback }, 'Model not found, using default');\n return resolveModel(fallback);\n }\n }\n\n /**\n * Keep defaults in sync when config is hot-reloaded or saved from the UI.\n *\n * The previous implementation rebuilt the entire `AgentToolsFactory` (80+ lines\n * of dependency wiring) on every reload. The factory's deps are now built from\n * a single helper ({@link buildToolsFactoryDeps}) and read `this.*` through\n * closures, so existing instances automatically see the new config without\n * reconstruction. The browser is still shut down because its cached settings\n * (headless mode, backend choice) come from the config snapshot at connect time.\n */\n updateAgentDefaults(config: Config): void {\n this.config.config = config;\n const ref = getAgentDefaultModelRef(config);\n this.config.model = ref;\n this.defaultModel = ref || getDefaultModelSync(config);\n this.baseWorkspacePath = this.computeBaseWorkspacePath();\n this.skillFilesystemWatcher.refreshPrimaryWorkspace(this.baseWorkspacePath);\n void this.toolsFactory.shutdownBrowser();\n void this.workspaceRuntimes.clearAll();\n }\n\n /**\n * Construct the dep bag passed to `AgentToolsFactory`. Closures reference\n * `this.*` so they remain valid across hot reloads (no rebuild needed).\n */\n private buildToolsFactoryDeps(): ConstructorParameters<typeof AgentToolsFactory>[0] {\n return {\n workspace: this.baseWorkspacePath,\n extensionRegistry: this.config.extensionRegistry,\n getCurrentContext: this.config.getCurrentContext,\n hookRunner: this.config.hookRunner,\n bus: this.config.bus,\n getConfig: () => this.mergedConfig(),\n getPrimaryModel: () => this.resolveModelStringToModel(this.pickDefaultModelRef()),\n getBuiltinMemoryStore: () =>\n this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).builtinMemoryStore,\n getMemoryManager: () =>\n this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).memoryManager,\n getSessionStore: this.config.getSessionStore,\n gatewayClarify: this.config.gatewayClarify,\n getCronService: this.config.getCronService,\n getWorkflowRunService: this.config.getWorkflowRunService,\n getSkillIndexingContext: () => {\n const ctx = this.config.getCurrentContext?.();\n if (!ctx?.sessionKey) return undefined;\n const inst = this.agents.get(ctx.sessionKey);\n if (!inst) return undefined;\n return {\n registeredToolNames: inst.registeredToolNames,\n skillAllowlist: inst.effectiveProfile.skillsAllowlist,\n };\n },\n onSkillsFilesystemMutate: () => {\n this.refreshSkillsAfterDiskChange('explicit');\n },\n getSkillPassthroughEnvVarNames: () => {\n const ctx = this.config.getCurrentContext?.();\n if (!ctx?.sessionKey) return [];\n return [...(this.agents.get(ctx.sessionKey)?.skillEnvPassthroughKeys ?? [])];\n },\n registerSkillEnvPassthrough: (names: string[]) => {\n const ctx = this.config.getCurrentContext?.();\n if (!ctx?.sessionKey) return;\n const inst = this.agents.get(ctx.sessionKey);\n if (!inst) return;\n for (const n of names) {\n if (isValidSkillEnvVarName(n)) {\n inst.skillEnvPassthroughKeys.add(n.trim());\n }\n }\n },\n };\n }\n\n getMemoryManager(): MemoryManager {\n return this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).memoryManager;\n }\n\n private getMemoryManagerForSession(sessionKey: string): MemoryManager {\n const path = this.getResolvedWorkspaceForSession(sessionKey);\n return this.workspaceRuntimes.getOrCreate(path).memoryManager;\n }\n\n /**\n * Prefix the user turn with fenced prefetched memory (external providers).\n * Delegates to {@link MemoryPrefetchCoordinator}.\n */\n applyMemoryPrefetchToUserMessage(\n userMessage: AgentMessage,\n sessionKey: string,\n ): Promise<AgentMessage> {\n return this.memoryPrefetch.applyToUserMessage(userMessage, sessionKey);\n }\n\n /**\n * After a completed turn: sync external providers and queue next-turn prefetch.\n * Delegates to {@link MemoryPrefetchCoordinator}.\n */\n afterAgentTurn(sessionKey: string, userPlainText: string): void {\n this.memoryPrefetch.afterTurn(sessionKey, userPlainText);\n }\n\n /**\n * Call once per user turn before the main `agent.prompt` (via {@link runAgentTurnWithModelFallbacks} `beforeUserPrompt`).\n * Delegates to {@link BackgroundReviewCoordinator}.\n */\n beginBackgroundReviewUserTurn(sessionKey: string): void {\n const inst = this.agents.get(sessionKey);\n if (!inst) return;\n this.backgroundReview.beginUserTurn(sessionKey, inst.registeredToolNames);\n }\n\n /**\n * After a successful main turn (after memory sync via `afterAgentTurn`), may run a quiet follow-up for memory/skills.\n * Delegates to {@link BackgroundReviewCoordinator}.\n */\n scheduleBackgroundReviewAfterUserTurn(sessionKey: string): void {\n const inst = this.agents.get(sessionKey);\n if (!inst) return;\n this.backgroundReview.scheduleAfterUserTurn({\n sessionKey,\n agent: inst.agent,\n registeredToolNames: inst.registeredToolNames,\n skillAllowlist: inst.effectiveProfile.skillsAllowlist,\n workspacePath: inst.resolvedWorkspacePath,\n lastAssistantText: this.getLastAssistantContent(sessionKey),\n workspaceRuntime: this.workspaceRuntimes.getOrCreate(inst.resolvedWorkspacePath),\n });\n }\n\n /**\n * Expand `/skill:name` user text into the full skill block for the current turn (WebChat, channels).\n */\n expandSkillUserText(text: string): string {\n const ctx = this.config.getCurrentContext?.();\n const sessionKey = ctx?.sessionKey;\n const path = sessionKey\n ? this.getResolvedWorkspaceForSession(sessionKey)\n : this.baseWorkspacePath;\n const inst = sessionKey ? this.agents.get(sessionKey) : undefined;\n return this.workspaceRuntimes.getOrCreate(path).skillManager.expandCommand(text, {\n skillAllowlist: inst?.effectiveProfile.skillsAllowlist,\n registeredToolNames: inst?.registeredToolNames,\n });\n }\n\n /** Structured SKILL.md preview for the gateway console. */\n getSkillMarkdownSource(skillName: string): SkillMarkdownPreviewPayload | null {\n const skill = this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath).skillManager.findSkill(skillName);\n if (!skill) return null;\n\n return {\n name: skill.name,\n description: skill.description,\n bodyMarkdown: skill.content,\n disableModelInvocation: skill.disableModelInvocation,\n metadata: skill.metadata,\n toolConditions: skill.toolConditions,\n requiredEnvVarNames: skill.requiredEnvVarNames,\n };\n }\n\n private loadProfileMarkdownForProfile(profile: EffectiveAgentProfile): ReturnType<typeof loadProfileMarkdownFiles> {\n const cfg = this.config.config!;\n const profileDir = resolveAgentProfileDir(cfg, profile.agentId);\n return loadProfileMarkdownFiles(profileDir);\n }\n\n private resolveContextFilesForSession(\n sessionKey: string,\n profile: EffectiveAgentProfile,\n excludeHeartbeat?: boolean,\n ): EmbeddedContextFile[] {\n const cfg = this.config.config!;\n const profileDir = resolveAgentProfileDir(cfg, profile.agentId);\n const heartbeatEnabled = cfg.gateway?.heartbeat?.includeSystemPromptSection ?? false;\n const contextInjection = cfg.agents?.defaults?.contextInjection ?? 'always';\n const { contextFiles } = resolveBootstrapContextSync({\n profileDir,\n config: cfg,\n sessionKey,\n excludeHeartbeat: excludeHeartbeat ?? !heartbeatEnabled,\n contextInjection,\n });\n return contextFiles;\n }\n\n private skillCatalogEntryFromSkill(s: Skill, skillsConfig = createSkillConfigManager(resolveStateDir()).load(), lock = loadSkillsLock()): SkillCatalogEntry {\n const base = resolve(s.baseDir);\n const managed = isUnderManagedSkillsDir(s.baseDir);\n const directoryId = base.split(sep).filter(Boolean).pop() || s.name;\n const enabled = !(skillsConfig.entries?.[s.name]?.enabled === false);\n const hubKey = managed ? basename(base) : '';\n const hub = managed && hubKey ? lock.entries[hubKey] : undefined;\n\n return {\n directoryId,\n name: s.name,\n description: s.description,\n category: s.category,\n source: s.source,\n path: s.baseDir,\n managed,\n enabled,\n disableModelInvocation: s.disableModelInvocation,\n ...(hub ? { hub } : {}),\n };\n }\n\n getSkillCatalog(): SkillCatalogEntry[] {\n return this.getSkillCatalogSnapshot().catalog;\n }\n\n getSkillCatalogSnapshot(): SkillCatalogSnapshot {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const lock = loadSkillsLock();\n const rt = this.workspaceRuntimes.getOrCreate(this.baseWorkspacePath);\n return {\n catalog: rt.skillManager\n .getSkills()\n .map((s) => this.skillCatalogEntryFromSkill(s, skillsConfig, lock)),\n version: rt.skillManager.getVersion(),\n loadedAt: rt.skillManager.getLoadedAt(),\n diagnostics: rt.skillManager.getDiagnostics(),\n status: rt.skillManager.getStatus(),\n };\n }\n\n getAgentSkillAvailability(agentId: string): AgentSkillAvailabilityPayload {\n const cfg = this.config.config!;\n const defaultsAllowlist = cfg.agents?.defaults?.skills;\n const entry = Array.isArray(cfg.agents?.list)\n ? cfg.agents.list.find((a) => a && a.enabled !== false && a.id.toLowerCase() === agentId.toLowerCase())\n : undefined;\n const profile = resolveEffectiveAgentProfile(cfg, agentId);\n const rt = this.workspaceRuntimes.getOrCreate(profile.resolvedWorkspacePath);\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const lock = loadSkillsLock();\n const allow = profile.skillsAllowlist === undefined ? undefined : new Set(profile.skillsAllowlist.map((s) => s.toLowerCase()));\n\n const skills = rt.skillManager.getSkills().map((s) => {\n let unavailableReason: AgentSkillUnavailableReason | null = null;\n const skillConfig = resolveSkillConfig(s, skillsConfig);\n if (skillConfig.enabled === false) {\n unavailableReason = 'disabled';\n } else if (s.disableModelInvocation) {\n unavailableReason = 'model-invocation-disabled';\n } else if (!isSkillEnabled(s, skillsConfig)) {\n unavailableReason = 'requirements-unmet';\n } else if (allow !== undefined && !allow.has(s.name.toLowerCase())) {\n unavailableReason = 'agent-denied';\n }\n\n return {\n ...this.skillCatalogEntryFromSkill(s, skillsConfig, lock),\n availableForCurrentAgent: unavailableReason === null,\n unavailableReason,\n };\n });\n\n return {\n agentId: profile.agentId,\n version: rt.skillManager.getVersion(),\n loadedAt: rt.skillManager.getLoadedAt(),\n diagnostics: rt.skillManager.getDiagnostics(),\n status: rt.skillManager.getStatus(),\n ...(defaultsAllowlist !== undefined ? { defaultsAllowlist: [...defaultsAllowlist] } : {}),\n ...(entry?.skills !== undefined ? { agentAllowlist: [...entry.skills] } : {}),\n ...(profile.skillsAllowlist !== undefined ? { effectiveAllowlist: [...profile.skillsAllowlist] } : {}),\n skills,\n };\n }\n\n /**\n * After ~/.xopc/skills.json changes (enable/disable), refresh `<available_skills>` on active agents.\n */\n refreshSkillsAfterSkillConfigChange(): void {\n const cfg = this.config.config!;\n const touched = new Set<string>();\n for (const [resolvedPath, rt] of this.workspaceRuntimes.entries()) {\n rt.skillManager.refreshPromptFromConfig();\n touched.add(resolvedPath);\n }\n for (const instance of this.agents.values()) {\n const rt = this.workspaceRuntimes.getOrCreate(instance.resolvedWorkspacePath);\n if (!touched.has(instance.resolvedWorkspacePath)) {\n rt.skillManager.refreshPromptFromConfig();\n touched.add(instance.resolvedWorkspacePath);\n }\n const contextFiles = this.resolveContextFilesForSession(\n instance.sessionKey,\n instance.effectiveProfile,\n );\n const newPrompt = rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: instance.resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey: instance.sessionKey,\n modelRef: instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel:\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium',\n });\n instance.agent.state.systemPrompt = newPrompt;\n }\n log.info({ agents: this.agents.size }, 'Skill toggles applied; system prompt updated');\n this.scheduleSkillsUpdated('config');\n }\n\n /**\n * Reload skills from disk and refresh system prompt on all active Agent instances.\n */\n refreshSkillsAfterDiskChange(source: 'explicit' | 'watch' = 'explicit'): void {\n const now = Date.now();\n if (source === 'watch' && now - this.lastExplicitSkillDiskRefreshAt < 2500) {\n log.debug({ changedWithinMs: now - this.lastExplicitSkillDiskRefreshAt }, 'Ignoring skill watcher echo after explicit refresh');\n return;\n }\n if (source === 'explicit') {\n this.lastExplicitSkillDiskRefreshAt = now;\n }\n\n if (this.skillDiskRefreshInProgress) {\n this.skillDiskRefreshPending = true;\n return;\n }\n\n this.skillDiskRefreshInProgress = true;\n let refreshed = false;\n try {\n do {\n this.skillDiskRefreshPending = false;\n this.applySkillsAfterDiskChange();\n refreshed = true;\n } while (this.skillDiskRefreshPending);\n } finally {\n this.skillDiskRefreshInProgress = false;\n }\n\n if (refreshed) {\n this.scheduleSkillsUpdated('disk');\n }\n }\n\n private scheduleSkillsUpdated(reason: 'disk' | 'config'): void {\n this.pendingSkillsUpdatedReason = reason === 'disk' ? 'disk' : this.pendingSkillsUpdatedReason ?? 'config';\n if (this.skillsUpdatedTimer) clearTimeout(this.skillsUpdatedTimer);\n this.skillsUpdatedTimer = setTimeout(() => {\n const nextReason = this.pendingSkillsUpdatedReason ?? reason;\n this.pendingSkillsUpdatedReason = undefined;\n this.skillsUpdatedTimer = undefined;\n this.config.onSkillsUpdated?.({ reason: nextReason });\n }, 250);\n }\n\n private applySkillsAfterDiskChange(): void {\n const cfg = this.config.config!;\n // Reload every workspace SkillManager first. When there are no active agent sessions\n // (e.g. gateway UI only), the loop below runs zero times — without this, `getSkillCatalog()`\n // and delete flows still see stale in-memory skills after ~/.xopc/skills changes.\n for (const rt of this.workspaceRuntimes.values()) {\n rt.skillManager.reload();\n }\n\n const touched = new Set<string>();\n for (const instance of this.agents.values()) {\n const rt = this.workspaceRuntimes.getOrCreate(instance.resolvedWorkspacePath);\n if (!touched.has(instance.resolvedWorkspacePath)) {\n touched.add(instance.resolvedWorkspacePath);\n }\n const contextFiles = this.resolveContextFilesForSession(\n instance.sessionKey,\n instance.effectiveProfile,\n );\n const newPrompt = rt.systemPromptBuilder.rebuild(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: instance.resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey: instance.sessionKey,\n modelRef: instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel:\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium',\n });\n instance.agent.state.systemPrompt = newPrompt;\n }\n log.info({ agents: this.agents.size }, 'Skills refreshed; system prompt updated');\n }\n\n /**\n * Get or create an Agent instance for a session\n */\n getOrCreateAgent(sessionKey: string): Agent {\n const cfg = this.config.config!;\n const targetPath = this.getResolvedWorkspaceForSession(sessionKey);\n const existing = this.agents.get(sessionKey);\n if (existing) {\n if (existing.resolvedWorkspacePath !== targetPath) {\n this.removeAgent(sessionKey);\n } else {\n existing.lastUsedAt = Date.now();\n log.debug({ sessionKey }, 'Reusing existing agent instance');\n return existing.agent;\n }\n }\n\n const profile = resolveEffectiveAgentProfileForSession(cfg, sessionKey);\n const resolvedPath = targetPath;\n const rt = this.workspaceRuntimes.getOrCreate(resolvedPath);\n\n if (isMemorySubsystemEnabled(cfg)) {\n void rt.memoryManager\n .initializeAll(sessionKey, { workspace: resolvedPath })\n .catch((err) => log.warn({ err, sessionKey }, 'memory initializeAll failed'));\n }\n\n if (isMemorySubsystemEnabled(cfg) && shouldRegisterCuratedMemoryTool(cfg)) {\n rt.builtinMemoryStore.loadFromDiskSync();\n }\n\n const { agent, registeredToolNames } = this.createAgentForProfile(\n sessionKey,\n profile,\n resolvedPath,\n rt,\n );\n\n this.agents.set(sessionKey, {\n agent,\n sessionKey,\n createdAt: Date.now(),\n lastUsedAt: Date.now(),\n effectiveProfile: profile,\n resolvedWorkspacePath: resolvedPath,\n registeredToolNames,\n skillEnvPassthroughKeys: new Set<string>(),\n });\n\n this.backgroundReview.attachToAgent(sessionKey, agent, registeredToolNames);\n\n const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;\n this.config.getModelManager?.().setSessionProfileDefault(sessionKey, modelRef);\n\n log.debug({ sessionKey, totalAgents: this.agents.size, agentId: profile.agentId }, 'Created new agent instance');\n return agent;\n }\n\n /**\n * Get existing agent for a session (if any)\n */\n getAgent(sessionKey: string): Agent | undefined {\n return this.agents.get(sessionKey)?.agent;\n }\n\n /**\n * Check if an agent exists for a session\n */\n hasAgent(sessionKey: string): boolean {\n return this.agents.has(sessionKey);\n }\n\n /**\n * Remove an agent instance\n */\n removeAgent(sessionKey: string): boolean {\n const instance = this.agents.get(sessionKey);\n if (instance) {\n this.backgroundReview.forgetSession(sessionKey);\n void this.toolsFactory.closeBrowserPageForSession(sessionKey);\n void retireSessionMcpRuntimeForSessionKey({ sessionKey, reason: 'agent-evict' });\n instance.agent.abort();\n evictEmbeddedSessionRunner(sessionKey, 'agent_removed');\n this.agents.delete(sessionKey);\n this.memoryPrefetch.forgetSession(sessionKey);\n clearBootstrapSnapshot(sessionKey);\n this.config.getModelManager?.().clearSessionProfileDefault(sessionKey);\n log.info({ sessionKey, totalAgents: this.agents.size }, 'Removed agent instance');\n return true;\n }\n return false;\n }\n\n /**\n * Get all active session keys\n */\n getActiveSessions(): string[] {\n return Array.from(this.agents.keys());\n }\n\n /**\n * Get agent count\n */\n getAgentCount(): number {\n return this.agents.size;\n }\n\n /**\n * Merge per-turn channel system prompt (e.g. Telegram group/topic override) into the agent.\n */\n applyTurnChannelSystemPrompt(sessionKey: string, channelSystemPrompt: string): void {\n const trimmed = channelSystemPrompt.trim();\n if (!trimmed) return;\n\n const instance = this.agents.get(sessionKey);\n if (!instance) return;\n\n const cfg = this.config.config!;\n const rt = this.workspaceRuntimes.getOrCreate(instance.resolvedWorkspacePath);\n const contextFiles = this.resolveContextFilesForSession(sessionKey, instance.effectiveProfile);\n const modelRef = instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel;\n const thinkingLevel =\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium';\n\n instance.agent.state.systemPrompt = rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: instance.resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey,\n modelRef,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n extraSystemPrompt: trimmed,\n });\n }\n\n /**\n * Set thinking level for a session's agent\n */\n setThinkingLevel(sessionKey: string, level: ThinkingLevel): void {\n const instance = this.agents.get(sessionKey);\n if (instance) {\n instance.agent.state.thinkingLevel = level;\n log.debug({ sessionKey, thinkingLevel: level }, 'Set thinking level for agent');\n }\n }\n\n /**\n * Dispose all agents\n */\n dispose(): void {\n if (this.skillsUpdatedTimer) clearTimeout(this.skillsUpdatedTimer);\n this.skillFilesystemWatcher.dispose();\n void this.toolsFactory.shutdownBrowser();\n void disposeAllSessionMcpRuntimes().catch(() => {});\n evictAllEmbeddedSessionRunners('agent_manager_dispose');\n this.backgroundReview.clear();\n for (const instance of this.agents.values()) {\n instance.agent.abort();\n }\n this.agents.clear();\n this.memoryPrefetch.clear();\n this.sessionWorkspaceOverrides.clear();\n void this.workspaceRuntimes.clearAll();\n log.debug('All agent instances disposed');\n }\n\n async warmCredentialCache(): Promise<void> {\n const profiles = await this.credentialResolver.listProfiles();\n for (const profile of profiles) {\n const secret = profile.key?.trim()\n ? profile.key.trim()\n : profile.envVar\n ? process.env[profile.envVar]?.trim()\n : undefined;\n if (secret) {\n this.credentialCache.set(profile.provider.toLowerCase(), secret);\n }\n }\n log.debug({ count: this.credentialCache.size }, 'Credential cache warmed');\n }\n\n async refreshCredentials(): Promise<void> {\n this.credentialCache.clear();\n await this.warmCredentialCache();\n }\n\n private resolveApiKeyWithCache(provider: string): string | undefined {\n const key = provider.toLowerCase();\n const cached = this.credentialCache.get(key);\n if (cached) return cached;\n\n const fromDisk = resolveProviderApiKeySync(provider);\n if (fromDisk) {\n this.credentialCache.set(key, fromDisk);\n return fromDisk;\n }\n\n const fromRegistryOrEnv = getApiKeySync(provider);\n if (fromRegistryOrEnv) {\n this.credentialCache.set(key, fromRegistryOrEnv);\n return fromRegistryOrEnv;\n }\n return undefined;\n }\n\n private createAgentForProfile(\n sessionKey: string,\n profile: EffectiveAgentProfile,\n resolvedWorkspacePath: string,\n rt: WorkspaceRuntime,\n ): { agent: Agent; registeredToolNames: string[] } {\n const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;\n const model = this.resolveModelStringToModel(modelRef);\n\n const contextFiles = this.resolveContextFilesForSession(sessionKey, profile);\n const tools = this.toolsFactory.createAllTools({\n workspace: resolvedWorkspacePath,\n profileMarkdownRoot: resolveAgentProfileDir(this.config.config!, profile.agentId),\n disabledTools: profile.tools.disable,\n getPrimaryModel: () => this.resolveModelStringToModel(modelRef),\n getBuiltinMemoryStore: () => rt.builtinMemoryStore,\n getMemoryManager: () => rt.memoryManager,\n getSkillManager: () => rt.skillManager,\n });\n const registeredToolNames = tools.map((t) => t.name);\n\n const thinkingLevel =\n (profile.thinkingDefault as ThinkingLevel | undefined) ?? this.config.thinkingLevel ?? 'medium';\n\n const agent = new Agent({\n initialState: {\n systemPrompt: rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(this.config.config!, profile.agentId),\n systemPromptOverride: profile.systemPromptOverride,\n skillAllowlist: profile.skillsAllowlist,\n registeredToolNames,\n sessionKey,\n modelRef,\n agentId: profile.agentId,\n thinkingLevel,\n }),\n model,\n thinkingLevel,\n tools,\n messages: [],\n },\n streamFn: createExtensionAwareStreamFn(),\n getApiKey: (provider: string) => this.resolveApiKeyWithCache(provider),\n beforeToolCall: async ({ toolCall, args }) => {\n const toolName = toolCall.name;\n\n if (toolName === 'shell') {\n const ctx = this.config.getCurrentContext();\n const cfg = this.mergedConfig();\n if (ctx && cfg) {\n const command =\n typeof (args as { command?: unknown })?.command === 'string'\n ? (args as { command: string }).command\n : JSON.stringify(args ?? {});\n const accountId =\n typeof ctx.metadata?.accountId === 'string' ? ctx.metadata.accountId : undefined;\n const approval = await maybeRequestChannelExecApproval({\n cfg,\n payload: {\n sessionKey: ctx.sessionKey,\n channel: ctx.channel,\n chatId: ctx.chatId,\n accountId,\n toolName,\n summary: command.slice(0, 500),\n details: { command: command.slice(0, 2000) },\n },\n });\n if (approval.required && !approval.approved) {\n return {\n block: true,\n reason: approval.reason ?? 'Exec approval denied or timed out.',\n };\n }\n }\n }\n\n if (!this.config.hookRunner) {\n return undefined;\n }\n const parsed = parseMcpToolName(toolName);\n const hookResult = await this.config.hookRunner.runBeforeToolCall(\n toolName,\n (args ?? {}) as Record<string, unknown>,\n {\n sessionKey,\n isMcpTool: parsed !== null,\n mcpServerId: parsed?.serverId,\n },\n );\n if (!hookResult.allowed) {\n return { block: true, reason: hookResult.reason ?? 'Tool call blocked by policy hook.' };\n }\n return undefined;\n },\n });\n return { agent, registeredToolNames };\n }\n\n /**\n * Set model for a specific session\n */\n setModelForSession(sessionKey: string, modelId: string): boolean {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n log.warn(\n { sessionKey, modelId, activeSessionCount: this.agents.size },\n `setModelForSession: no agent instance for session (create session / run turn first); modelId=${modelId}`,\n );\n return false;\n }\n\n try {\n const model = resolveModel(modelId);\n instance.agent.state.model = model;\n\n const cfg = this.config.config!;\n const rt = this.workspaceRuntimes.getOrCreate(instance.resolvedWorkspacePath);\n const contextFiles = this.resolveContextFilesForSession(\n sessionKey,\n instance.effectiveProfile,\n );\n const thinkingLevel =\n (instance.agent.state.thinkingLevel as ThinkingLevel | undefined) ??\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium';\n\n instance.agent.state.systemPrompt = rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: instance.resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey,\n modelRef: modelId,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n });\n\n log.info({ sessionKey, modelId }, 'Model set for session');\n return true;\n } catch (err) {\n log.error({ err, sessionKey, modelId }, 'Failed to set model for session');\n return false;\n }\n }\n\n /**\n * Get last assistant content from a session's agent\n */\n getLastAssistantContent(sessionKey: string): string | null {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return null;\n }\n\n const messages = instance.agent.state.messages;\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.role === 'assistant') {\n const content = msg.content;\n if (Array.isArray(content)) {\n return extractTextContent(content as Array<{ type: string; text?: string }>);\n }\n return String(content);\n }\n }\n return null;\n }\n\n /**\n * Replace messages for a session's agent\n */\n replaceMessages(sessionKey: string, messages: AgentMessage[]): boolean {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return false;\n }\n\n instance.agent.state.messages = messages;\n return true;\n }\n\n /**\n * Get messages for a session's agent\n */\n getMessages(sessionKey: string): AgentMessage[] | null {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return null;\n }\n\n return instance.agent.state.messages;\n }\n\n /**\n * Subscribe to agent events for a session\n */\n subscribeToSession(sessionKey: string, callback: (event: AgentEvent) => void): (() => void) | null {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return null;\n }\n\n return instance.agent.subscribe(callback);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-manager.js","names":[],"sources":["../../../src/agent/agent-manager.ts"],"sourcesContent":["/**\n * Agent Manager - Manages Agent instances per session\n *\n * Each session gets its own Agent instance for true isolation\n * and concurrent processing across sessions.\n */\n\nimport {\n Agent,\n type AgentMessage,\n type AgentEvent,\n type ThinkingLevel,\n} from '@earendil-works/pi-agent-core';\nimport type { Model, Api } from '@earendil-works/pi-ai';\nimport type { AgentInstanceGateway } from './agent-instance-gateway.js';\nimport { type Config, getAgentDefaultModelRef } from '../config/schema.js';\nimport { applyConfigOverrides } from '../config/runtime-overrides.js';\nimport { resolveAgentProfileDir } from './agent-scope.js';\nimport {\n type EffectiveAgentProfile,\n resolveEffectiveAgentProfile,\n resolveEffectiveAgentProfileForSession,\n} from '../config/agent-profile.js';\nimport { expandWorkspacePathString } from '../config/workspace-path.js';\nimport type { ModelManager } from './models/manager.js';\nimport { createLogger } from '../utils/logger.js';\nimport { resolveProviderApiKeySync } from '../auth/sync-provider-auth.js';\nimport { resolveModel, getDefaultModelSync, getApiKeySync } from '../providers/index.js';\nimport { createExtensionAwareStreamFn } from '../providers/extension-stream-bridge.js';\nimport { CredentialResolver } from '../auth/credentials.js';\nimport { resolveBundledSkillsDir, resolveStateDir } from '../config/paths.js';\nimport { loadProfileMarkdownFiles, extractTextContent } from './context/workspace.js';\nimport { clearBootstrapSnapshot, resolveBootstrapContextSync } from './bootstrap/bootstrap-files.js';\nimport { loadProjectAgentsContextFile } from './bootstrap/project-agents-context.js';\nimport type { EmbeddedContextFile } from './bootstrap/types.js';\nimport { AgentToolsFactory } from './tools/factory.js';\nimport { parseMcpToolName } from './mcp/bundle-mcp-policy.js';\nimport {\n disposeAllSessionMcpRuntimes,\n retireSessionMcpRuntimeForSessionKey,\n} from './mcp/bundle-mcp-tools.js';\nimport { evictAllEmbeddedSessionRunners, evictEmbeddedSessionRunner } from './embedded/session-runner.js';\nimport type { GatewayClarifyRequestFn } from './tools/clarify-tool.js';\nimport type { ExtensionRegistryImpl as ExtensionRegistry } from '../extensions/index.js';\nimport type { MessageBus } from '../infra/bus/index.js';\nimport type { CronService } from '../cron/index.js';\nimport type { SessionStore } from '../session/store.js';\nimport { isValidSkillEnvVarName } from './skills/required-env-vars.js';\nimport type { SessionContext } from './session/session-context.js';\nimport type {\n Skill,\n SkillDiagnostic,\n SkillMarkdownPreviewPayload,\n SkillRuntimeStatus,\n} from './skills/types.js';\nimport { createSkillConfigManager, isSkillEnabled, resolveSkillConfig } from './skills/config.js';\nimport { isUnderManagedSkillsDir } from './skills/managed-store.js';\nimport { loadSkillsLock, type SkillHubLockEntry } from './skills/hub-lock.js';\nimport { basename, resolve, sep } from 'node:path';\n\nimport {\n isMemorySubsystemEnabled,\n shouldRegisterCuratedMemoryTool,\n} from './memory/memory-config.js';\nimport type { MemoryManager } from './memory/manager.js';\nimport { MemoryPrefetchCoordinator } from './memory/prefetch-coordinator.js';\nimport { WorkspaceRuntimeRegistry, type WorkspaceRuntime } from './workspace-runtime/registry.js';\nimport { BackgroundReviewCoordinator } from './background-review/coordinator.js';\nimport { maybeRequestChannelExecApproval } from '../channels/exec-approval-runtime.js';\nimport { SkillFilesystemWatcher } from './skills/filesystem-watcher.js';\nimport { ProjectTrustStore, hasTrustRequiringProjectResources } from '../project-trust/trust-store.js';\n\nconst log = createLogger('AgentManager');\n\nexport interface SkillCatalogEntry {\n directoryId: string;\n name: string;\n description: string;\n category?: string;\n source: Skill['source'];\n path: string;\n managed: boolean;\n /** User toggle in ~/.xopc/skills.json (`entries[name].enabled`). Default true. */\n enabled: boolean;\n /** When true, skill is never injected into `<available_skills>` (SKILL.md frontmatter). */\n disableModelInvocation: boolean;\n /** Hub install provenance when under ~/.xopc/skills and listed in skills-lock.json. */\n hub?: SkillHubLockEntry;\n}\n\nexport interface SkillCatalogRuntimeMeta {\n version: string;\n loadedAt: number;\n diagnostics: SkillDiagnostic[];\n status: SkillRuntimeStatus;\n}\n\nexport interface SkillCatalogSnapshot extends SkillCatalogRuntimeMeta {\n catalog: SkillCatalogEntry[];\n}\n\nexport type AgentSkillUnavailableReason = 'agent-denied' | 'disabled' | 'requirements-unmet' | 'model-invocation-disabled';\n\nexport interface AgentSkillAvailabilityEntry extends SkillCatalogEntry {\n availableForCurrentAgent: boolean;\n unavailableReason: AgentSkillUnavailableReason | null;\n}\n\nexport interface AgentSkillAvailabilityPayload {\n agentId: string;\n version: string;\n loadedAt: number;\n diagnostics: SkillDiagnostic[];\n status: SkillRuntimeStatus;\n defaultsAllowlist?: string[];\n agentAllowlist?: string[];\n effectiveAllowlist?: string[];\n skills: AgentSkillAvailabilityEntry[];\n}\n\nexport interface AgentManagerConfig {\n workspace: string;\n model?: string;\n config?: Config;\n extensionRegistry?: ExtensionRegistry;\n hookRunner?: import('../extensions/index.js').ExtensionHookRunner;\n bus: MessageBus;\n getCurrentContext: () => SessionContext | null;\n /** Session persistence (enables `session_search` when set). */\n getSessionStore?: () => SessionStore;\n /** Clears per-session profile default on teardown. */\n getModelManager?: () => ModelManager;\n // Thinking configuration\n thinkingLevel?: ThinkingLevel;\n reasoningLevel?: 'off' | 'on' | 'stream';\n verboseLevel?: 'off' | 'on' | 'full';\n gatewayClarify?: { requestClarification: GatewayClarifyRequestFn };\n /** Gateway: exposes CronService for the `cronjob` tool. */\n getCronService?: () => CronService | undefined;\n /** Gateway: starts persisted workflow runs (dedicated chat session per run). */\n getWorkflowRunService?: () => import('../workflows/service/workflow-run-service.types.js').WorkflowRunServiceLike | undefined;\n /** Runtime notification for UI/CLI shells that cache skill catalogs. */\n onSkillsUpdated?: (payload: { reason: 'disk' | 'config' }) => void;\n /**\n * Runtime trust override. Persistent \"do not trust\" entries still take precedence.\n */\n isWorkspaceTrusted?: (workspaceDir: string) => boolean | null | undefined;\n}\n\nexport interface AgentInstance {\n agent: Agent;\n sessionKey: string;\n createdAt: number;\n lastUsedAt: number;\n effectiveProfile: EffectiveAgentProfile;\n resolvedWorkspacePath: string;\n /** Tool names registered on this agent (for skill indexing / tool gating). */\n registeredToolNames: string[];\n /** Declared env var names from skill_view; shell reads values from process.env at spawn time. */\n skillEnvPassthroughKeys: Set<string>;\n}\n\n\nexport class AgentManager implements AgentInstanceGateway {\n private agents = new Map<string, AgentInstance>();\n private config: AgentManagerConfig;\n private toolsFactory: AgentToolsFactory;\n\n private mergedConfig(): Config | undefined {\n const base = this.config.config;\n return base ? applyConfigOverrides(base) : undefined;\n }\n /** Default agent workspace (effective profile for `getDefaultAgentId`). */\n private baseWorkspacePath: string;\n /** Per-session absolute markdown workspace when `SessionAgentConfig.workingDirectoryOverride` is set. */\n private sessionWorkspaceOverrides = new Map<string, string>();\n private defaultModel: string;\n private credentialCache = new Map<string, string>();\n private credentialResolver: CredentialResolver;\n private workspaceRuntimes: WorkspaceRuntimeRegistry;\n private memoryPrefetch: MemoryPrefetchCoordinator;\n private backgroundReview: BackgroundReviewCoordinator;\n private skillFilesystemWatcher: SkillFilesystemWatcher;\n private skillDiskRefreshInProgress = false;\n private skillDiskRefreshPending = false;\n private lastExplicitSkillDiskRefreshAt = 0;\n private skillsUpdatedTimer: NodeJS.Timeout | undefined;\n private pendingSkillsUpdatedReason: 'disk' | 'config' | undefined;\n private projectTrustStore = new ProjectTrustStore();\n\n constructor(config: AgentManagerConfig) {\n this.config = config;\n this.baseWorkspacePath = this.computeBaseWorkspacePath();\n this.skillFilesystemWatcher = new SkillFilesystemWatcher({\n onChange: (event) => {\n log.info({ changedPath: event.changedPath }, 'Skill filesystem changed; refreshing skills');\n this.refreshSkillsAfterDiskChange('watch');\n },\n });\n this.skillFilesystemWatcher.refreshPrimaryWorkspace(this.baseWorkspacePath);\n this.workspaceRuntimes = new WorkspaceRuntimeRegistry({\n getConfig: () => this.config.config!,\n bundledSkillsDir: resolveBundledSkillsDir(),\n onRuntimeCreated: (resolvedPath) => {\n this.skillFilesystemWatcher.watchWorkspace(resolvedPath);\n },\n });\n this.memoryPrefetch = new MemoryPrefetchCoordinator({\n getConfig: () => this.config.config,\n getMemoryManagerForSession: (sk) => this.getMemoryManagerForSession(sk),\n getLastAssistantContent: (sk) => this.getLastAssistantContent(sk),\n });\n this.backgroundReview = new BackgroundReviewCoordinator({\n getConfig: () => this.mergedConfig(),\n onSkillsFilesystemMutate: () => this.refreshSkillsAfterDiskChange('explicit'),\n });\n this.toolsFactory = new AgentToolsFactory(this.buildToolsFactoryDeps());\n\n this.defaultModel = config.model || getDefaultModelSync(config.config);\n\n this.credentialResolver = new CredentialResolver();\n this.warmCredentialCache().catch((err) => {\n const em = err instanceof Error ? err.message : String(err);\n log.warn({ err, errorMessage: em }, `Credential cache pre-warm failed: ${em}`);\n });\n }\n\n private computeBaseWorkspacePath(): string {\n const cfg = this.config.config;\n if (!cfg) {\n return expandWorkspacePathString(this.config.workspace);\n }\n return resolveEffectiveAgentProfileForSession(cfg, null).resolvedWorkspacePath;\n }\n\n /**\n * Workspace root for inbound attachments / side effects for this session's agent id.\n * Uses in-memory session workspace overrides when the session has a persisted `workingDirectoryOverride`.\n */\n getResolvedWorkspaceForSession(sessionKey: string): string {\n const cfg = this.config.config!;\n const fromMap = this.sessionWorkspaceOverrides.get(sessionKey);\n if (fromMap !== undefined) {\n return fromMap;\n }\n return resolveEffectiveAgentProfileForSession(cfg, sessionKey).resolvedWorkspacePath;\n }\n\n private getWorkspaceRuntimeForSession(sessionKey: string | undefined): WorkspaceRuntime {\n const resolvedPath = sessionKey\n ? this.getResolvedWorkspaceForSession(sessionKey)\n : this.baseWorkspacePath;\n return this.workspaceRuntimes.getOrCreate(resolvedPath);\n }\n\n private getCurrentWorkspaceRuntime(): WorkspaceRuntime {\n return this.getWorkspaceRuntimeForSession(this.config.getCurrentContext?.()?.sessionKey);\n }\n\n /**\n * Sync in-memory workspace override from session config (after load or PATCH).\n * Pass `null` to clear when the session has no `workingDirectoryOverride` on disk.\n */\n setSessionWorkspaceOverride(sessionKey: string, absolutePath: string | null): void {\n if (absolutePath === null || absolutePath === '') {\n this.sessionWorkspaceOverrides.delete(sessionKey);\n } else {\n this.sessionWorkspaceOverrides.set(sessionKey, absolutePath);\n }\n }\n\n /** Merged `thinkingDefault` for this session's agent id (defaults + `agents.list`). */\n getThinkingDefaultForSession(\n sessionKey: string,\n ): import('./transcript/thinking-types.js').ThinkLevel | undefined {\n const cfg = this.mergedConfig();\n if (!cfg) {\n return undefined;\n }\n return resolveEffectiveAgentProfileForSession(cfg, sessionKey).thinkingDefault;\n }\n\n private pickDefaultModelRef(): string {\n const cfg = this.mergedConfig();\n const ref = getAgentDefaultModelRef(cfg);\n return ref?.trim() || getDefaultModelSync(cfg);\n }\n\n private resolveModelStringToModel(modelRef: string): Model<Api> {\n try {\n return resolveModel(modelRef);\n } catch {\n const fallback = getDefaultModelSync(this.mergedConfig());\n log.warn({ modelRef, fallback }, 'Model not found, using default');\n return resolveModel(fallback);\n }\n }\n\n /**\n * Keep defaults in sync when config is hot-reloaded or saved from the UI.\n *\n * The previous implementation rebuilt the entire `AgentToolsFactory` (80+ lines\n * of dependency wiring) on every reload. The factory's deps are now built from\n * a single helper ({@link buildToolsFactoryDeps}) and read `this.*` through\n * closures, so existing instances automatically see the new config without\n * reconstruction. The browser is still shut down because its cached settings\n * (headless mode, backend choice) come from the config snapshot at connect time.\n */\n updateAgentDefaults(config: Config): void {\n this.config.config = config;\n const ref = getAgentDefaultModelRef(config);\n this.config.model = ref;\n this.defaultModel = ref || getDefaultModelSync(config);\n this.baseWorkspacePath = this.computeBaseWorkspacePath();\n this.skillFilesystemWatcher.refreshPrimaryWorkspace(this.baseWorkspacePath);\n void this.toolsFactory.shutdownBrowser();\n void this.workspaceRuntimes.clearAll();\n }\n\n /**\n * Construct the dep bag passed to `AgentToolsFactory`. Closures reference\n * `this.*` so they remain valid across hot reloads (no rebuild needed).\n */\n private buildToolsFactoryDeps(): ConstructorParameters<typeof AgentToolsFactory>[0] {\n return {\n workspace: this.baseWorkspacePath,\n extensionRegistry: this.config.extensionRegistry,\n getCurrentContext: this.config.getCurrentContext,\n hookRunner: this.config.hookRunner,\n bus: this.config.bus,\n getConfig: () => this.mergedConfig(),\n getPrimaryModel: () => this.resolveModelStringToModel(this.pickDefaultModelRef()),\n getBuiltinMemoryStore: () => this.getCurrentWorkspaceRuntime().builtinMemoryStore,\n getMemoryManager: () => this.getCurrentWorkspaceRuntime().memoryManager,\n getSessionStore: this.config.getSessionStore,\n gatewayClarify: this.config.gatewayClarify,\n getCronService: this.config.getCronService,\n getWorkflowRunService: this.config.getWorkflowRunService,\n getSkillIndexingContext: () => {\n const ctx = this.config.getCurrentContext?.();\n if (!ctx?.sessionKey) return undefined;\n const inst = this.agents.get(ctx.sessionKey);\n if (!inst) return undefined;\n return {\n registeredToolNames: inst.registeredToolNames,\n skillAllowlist: inst.effectiveProfile.skillsAllowlist,\n };\n },\n onSkillsFilesystemMutate: () => {\n this.refreshSkillsAfterDiskChange('explicit');\n },\n getSkillPassthroughEnvVarNames: () => {\n const ctx = this.config.getCurrentContext?.();\n if (!ctx?.sessionKey) return [];\n return [...(this.agents.get(ctx.sessionKey)?.skillEnvPassthroughKeys ?? [])];\n },\n registerSkillEnvPassthrough: (names: string[]) => {\n const ctx = this.config.getCurrentContext?.();\n if (!ctx?.sessionKey) return;\n const inst = this.agents.get(ctx.sessionKey);\n if (!inst) return;\n for (const n of names) {\n if (isValidSkillEnvVarName(n)) {\n inst.skillEnvPassthroughKeys.add(n.trim());\n }\n }\n },\n };\n }\n\n getMemoryManager(): MemoryManager {\n return this.getCurrentWorkspaceRuntime().memoryManager;\n }\n\n private getMemoryManagerForSession(sessionKey: string): MemoryManager {\n return this.getWorkspaceRuntimeForSession(sessionKey).memoryManager;\n }\n\n /**\n * Prefix the user turn with fenced prefetched memory (external providers).\n * Delegates to {@link MemoryPrefetchCoordinator}.\n */\n applyMemoryPrefetchToUserMessage(\n userMessage: AgentMessage,\n sessionKey: string,\n ): Promise<AgentMessage> {\n return this.memoryPrefetch.applyToUserMessage(userMessage, sessionKey);\n }\n\n /**\n * After a completed turn: sync external providers and queue next-turn prefetch.\n * Delegates to {@link MemoryPrefetchCoordinator}.\n */\n afterAgentTurn(sessionKey: string, userPlainText: string): void {\n this.memoryPrefetch.afterTurn(sessionKey, userPlainText);\n }\n\n /**\n * Call once per user turn before the main `agent.prompt` (via {@link runAgentTurnWithModelFallbacks} `beforeUserPrompt`).\n * Delegates to {@link BackgroundReviewCoordinator}.\n */\n beginBackgroundReviewUserTurn(sessionKey: string): void {\n const inst = this.agents.get(sessionKey);\n if (!inst) return;\n this.backgroundReview.beginUserTurn(sessionKey, inst.registeredToolNames);\n }\n\n /**\n * After a successful main turn (after memory sync via `afterAgentTurn`), may run a quiet follow-up for memory/skills.\n * Delegates to {@link BackgroundReviewCoordinator}.\n */\n scheduleBackgroundReviewAfterUserTurn(sessionKey: string): void {\n const inst = this.agents.get(sessionKey);\n if (!inst) return;\n this.backgroundReview.scheduleAfterUserTurn({\n sessionKey,\n agent: inst.agent,\n registeredToolNames: inst.registeredToolNames,\n skillAllowlist: inst.effectiveProfile.skillsAllowlist,\n workspacePath: this.getResolvedWorkspaceForSession(sessionKey),\n lastAssistantText: this.getLastAssistantContent(sessionKey),\n workspaceRuntime: this.getWorkspaceRuntimeForSession(sessionKey),\n });\n }\n\n /**\n * Expand `/skill:name` user text into the full skill block for the current turn (WebChat, channels).\n */\n expandSkillUserText(text: string): string {\n const ctx = this.config.getCurrentContext?.();\n const sessionKey = ctx?.sessionKey;\n const inst = sessionKey ? this.agents.get(sessionKey) : undefined;\n return this.getWorkspaceRuntimeForSession(sessionKey).skillManager.expandCommand(text, {\n skillAllowlist: inst?.effectiveProfile.skillsAllowlist,\n registeredToolNames: inst?.registeredToolNames,\n });\n }\n\n /** Structured SKILL.md preview for the gateway console. */\n getSkillMarkdownSource(skillName: string): SkillMarkdownPreviewPayload | null {\n const skill = this.getCurrentWorkspaceRuntime().skillManager.findSkill(skillName);\n if (!skill) return null;\n\n return {\n name: skill.name,\n description: skill.description,\n bodyMarkdown: skill.content,\n disableModelInvocation: skill.disableModelInvocation,\n metadata: skill.metadata,\n toolConditions: skill.toolConditions,\n requiredEnvVarNames: skill.requiredEnvVarNames,\n };\n }\n\n private loadProfileMarkdownForProfile(profile: EffectiveAgentProfile): ReturnType<typeof loadProfileMarkdownFiles> {\n const cfg = this.config.config!;\n const profileDir = resolveAgentProfileDir(cfg, profile.agentId);\n return loadProfileMarkdownFiles(profileDir);\n }\n\n private isProjectWorkspaceTrusted(workspaceDir: string): boolean {\n if (!hasTrustRequiringProjectResources(workspaceDir)) {\n return false;\n }\n\n const persisted = this.projectTrustStore.get(workspaceDir);\n if (persisted === false) {\n return false;\n }\n if (persisted === true) {\n return true;\n }\n\n try {\n return this.config.isWorkspaceTrusted?.(workspaceDir) === true;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n log.warn({ err, workspaceDir, errorMessage }, `Workspace trust override failed: ${errorMessage}`);\n return false;\n }\n }\n\n private resolveContextFilesForSession(\n sessionKey: string,\n profile: EffectiveAgentProfile,\n excludeHeartbeat?: boolean,\n ): EmbeddedContextFile[] {\n const cfg = this.config.config!;\n const profileDir = resolveAgentProfileDir(cfg, profile.agentId);\n const heartbeatEnabled = cfg.gateway?.heartbeat?.includeSystemPromptSection ?? false;\n const contextInjection = cfg.agents?.defaults?.contextInjection ?? 'always';\n const { contextFiles } = resolveBootstrapContextSync({\n profileDir,\n config: cfg,\n sessionKey,\n excludeHeartbeat: excludeHeartbeat ?? !heartbeatEnabled,\n contextInjection,\n });\n const shouldAppendProjectContext =\n contextInjection === 'always' ||\n (contextInjection === 'continuation-skip' && contextFiles.length > 0);\n const workspaceDir = this.getResolvedWorkspaceForSession(sessionKey);\n if (\n shouldAppendProjectContext &&\n this.isProjectWorkspaceTrusted(workspaceDir)\n ) {\n const projectAgentsFile = loadProjectAgentsContextFile(workspaceDir);\n if (projectAgentsFile) {\n contextFiles.push(projectAgentsFile);\n }\n }\n return contextFiles;\n }\n\n private skillCatalogEntryFromSkill(s: Skill, skillsConfig = createSkillConfigManager(resolveStateDir()).load(), lock = loadSkillsLock()): SkillCatalogEntry {\n const base = resolve(s.baseDir);\n const managed = isUnderManagedSkillsDir(s.baseDir);\n const directoryId = base.split(sep).filter(Boolean).pop() || s.name;\n const enabled = !(skillsConfig.entries?.[s.name]?.enabled === false);\n const hubKey = managed ? basename(base) : '';\n const hub = managed && hubKey ? lock.entries[hubKey] : undefined;\n\n return {\n directoryId,\n name: s.name,\n description: s.description,\n category: s.category,\n source: s.source,\n path: s.baseDir,\n managed,\n enabled,\n disableModelInvocation: s.disableModelInvocation,\n ...(hub ? { hub } : {}),\n };\n }\n\n getSkillCatalog(): SkillCatalogEntry[] {\n return this.getSkillCatalogSnapshot().catalog;\n }\n\n getSkillCatalogSnapshot(): SkillCatalogSnapshot {\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const lock = loadSkillsLock();\n const rt = this.getCurrentWorkspaceRuntime();\n return {\n catalog: rt.skillManager\n .getSkills()\n .map((s) => this.skillCatalogEntryFromSkill(s, skillsConfig, lock)),\n version: rt.skillManager.getVersion(),\n loadedAt: rt.skillManager.getLoadedAt(),\n diagnostics: rt.skillManager.getDiagnostics(),\n status: rt.skillManager.getStatus(),\n };\n }\n\n getAgentSkillAvailability(agentId: string): AgentSkillAvailabilityPayload {\n const cfg = this.config.config!;\n const defaultsAllowlist = cfg.agents?.defaults?.skills;\n const entry = Array.isArray(cfg.agents?.list)\n ? cfg.agents.list.find((a) => a && a.enabled !== false && a.id.toLowerCase() === agentId.toLowerCase())\n : undefined;\n const profile = resolveEffectiveAgentProfile(cfg, agentId);\n const rt = this.workspaceRuntimes.getOrCreate(profile.resolvedWorkspacePath);\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const lock = loadSkillsLock();\n const allow = profile.skillsAllowlist === undefined ? undefined : new Set(profile.skillsAllowlist.map((s) => s.toLowerCase()));\n\n const skills = rt.skillManager.getSkills().map((s) => {\n let unavailableReason: AgentSkillUnavailableReason | null = null;\n const skillConfig = resolveSkillConfig(s, skillsConfig);\n if (skillConfig.enabled === false) {\n unavailableReason = 'disabled';\n } else if (s.disableModelInvocation) {\n unavailableReason = 'model-invocation-disabled';\n } else if (!isSkillEnabled(s, skillsConfig)) {\n unavailableReason = 'requirements-unmet';\n } else if (allow !== undefined && !allow.has(s.name.toLowerCase())) {\n unavailableReason = 'agent-denied';\n }\n\n return {\n ...this.skillCatalogEntryFromSkill(s, skillsConfig, lock),\n availableForCurrentAgent: unavailableReason === null,\n unavailableReason,\n };\n });\n\n return {\n agentId: profile.agentId,\n version: rt.skillManager.getVersion(),\n loadedAt: rt.skillManager.getLoadedAt(),\n diagnostics: rt.skillManager.getDiagnostics(),\n status: rt.skillManager.getStatus(),\n ...(defaultsAllowlist !== undefined ? { defaultsAllowlist: [...defaultsAllowlist] } : {}),\n ...(entry?.skills !== undefined ? { agentAllowlist: [...entry.skills] } : {}),\n ...(profile.skillsAllowlist !== undefined ? { effectiveAllowlist: [...profile.skillsAllowlist] } : {}),\n skills,\n };\n }\n\n /**\n * After ~/.xopc/skills.json changes (enable/disable), refresh `<available_skills>` on active agents.\n */\n refreshSkillsAfterSkillConfigChange(): void {\n const cfg = this.config.config!;\n const touched = new Set<string>();\n for (const [resolvedPath, rt] of this.workspaceRuntimes.entries()) {\n rt.skillManager.refreshPromptFromConfig();\n touched.add(resolvedPath);\n }\n for (const instance of this.agents.values()) {\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(resolvedWorkspacePath);\n if (!touched.has(resolvedWorkspacePath)) {\n rt.skillManager.refreshPromptFromConfig();\n touched.add(resolvedWorkspacePath);\n }\n const contextFiles = this.resolveContextFilesForSession(\n instance.sessionKey,\n instance.effectiveProfile,\n );\n const newPrompt = rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey: instance.sessionKey,\n modelRef: instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel:\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium',\n });\n instance.agent.state.systemPrompt = newPrompt;\n }\n log.info({ agents: this.agents.size }, 'Skill toggles applied; system prompt updated');\n this.scheduleSkillsUpdated('config');\n }\n\n /**\n * Reload skills from disk and refresh system prompt on all active Agent instances.\n */\n refreshSkillsAfterDiskChange(source: 'explicit' | 'watch' = 'explicit'): void {\n const now = Date.now();\n if (source === 'watch' && now - this.lastExplicitSkillDiskRefreshAt < 2500) {\n log.debug({ changedWithinMs: now - this.lastExplicitSkillDiskRefreshAt }, 'Ignoring skill watcher echo after explicit refresh');\n return;\n }\n if (source === 'explicit') {\n this.lastExplicitSkillDiskRefreshAt = now;\n }\n\n if (this.skillDiskRefreshInProgress) {\n this.skillDiskRefreshPending = true;\n return;\n }\n\n this.skillDiskRefreshInProgress = true;\n let refreshed = false;\n try {\n do {\n this.skillDiskRefreshPending = false;\n this.applySkillsAfterDiskChange();\n refreshed = true;\n } while (this.skillDiskRefreshPending);\n } finally {\n this.skillDiskRefreshInProgress = false;\n }\n\n if (refreshed) {\n this.scheduleSkillsUpdated('disk');\n }\n }\n\n private scheduleSkillsUpdated(reason: 'disk' | 'config'): void {\n this.pendingSkillsUpdatedReason = reason === 'disk' ? 'disk' : this.pendingSkillsUpdatedReason ?? 'config';\n if (this.skillsUpdatedTimer) clearTimeout(this.skillsUpdatedTimer);\n this.skillsUpdatedTimer = setTimeout(() => {\n const nextReason = this.pendingSkillsUpdatedReason ?? reason;\n this.pendingSkillsUpdatedReason = undefined;\n this.skillsUpdatedTimer = undefined;\n this.config.onSkillsUpdated?.({ reason: nextReason });\n }, 250);\n }\n\n private applySkillsAfterDiskChange(): void {\n const cfg = this.config.config!;\n // Reload every workspace SkillManager first. When there are no active agent sessions\n // (e.g. gateway UI only), the loop below runs zero times — without this, `getSkillCatalog()`\n // and delete flows still see stale in-memory skills after ~/.xopc/skills changes.\n for (const rt of this.workspaceRuntimes.values()) {\n rt.skillManager.reload();\n }\n\n const touched = new Set<string>();\n for (const instance of this.agents.values()) {\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(resolvedWorkspacePath);\n if (!touched.has(resolvedWorkspacePath)) {\n touched.add(resolvedWorkspacePath);\n }\n const contextFiles = this.resolveContextFilesForSession(\n instance.sessionKey,\n instance.effectiveProfile,\n );\n const newPrompt = rt.systemPromptBuilder.rebuild(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey: instance.sessionKey,\n modelRef: instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel:\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium',\n });\n instance.agent.state.systemPrompt = newPrompt;\n }\n log.info({ agents: this.agents.size }, 'Skills refreshed; system prompt updated');\n }\n\n /**\n * Get or create an Agent instance for a session\n */\n getOrCreateAgent(sessionKey: string): Agent {\n const cfg = this.config.config!;\n const targetPath = this.getResolvedWorkspaceForSession(sessionKey);\n const existing = this.agents.get(sessionKey);\n if (existing) {\n if (existing.resolvedWorkspacePath !== targetPath) {\n this.removeAgent(sessionKey);\n } else {\n existing.lastUsedAt = Date.now();\n log.debug({ sessionKey }, 'Reusing existing agent instance');\n return existing.agent;\n }\n }\n\n const profile = resolveEffectiveAgentProfileForSession(cfg, sessionKey);\n const resolvedPath = targetPath;\n const rt = this.workspaceRuntimes.getOrCreate(resolvedPath);\n\n if (isMemorySubsystemEnabled(cfg)) {\n void rt.memoryManager\n .initializeAll(sessionKey, { workspace: resolvedPath })\n .catch((err) => log.warn({ err, sessionKey }, 'memory initializeAll failed'));\n }\n\n if (isMemorySubsystemEnabled(cfg) && shouldRegisterCuratedMemoryTool(cfg)) {\n rt.builtinMemoryStore.loadFromDiskSync();\n }\n\n const { agent, registeredToolNames } = this.createAgentForProfile(\n sessionKey,\n profile,\n resolvedPath,\n rt,\n );\n\n this.agents.set(sessionKey, {\n agent,\n sessionKey,\n createdAt: Date.now(),\n lastUsedAt: Date.now(),\n effectiveProfile: profile,\n resolvedWorkspacePath: resolvedPath,\n registeredToolNames,\n skillEnvPassthroughKeys: new Set<string>(),\n });\n\n this.backgroundReview.attachToAgent(sessionKey, agent, registeredToolNames);\n\n const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;\n this.config.getModelManager?.().setSessionProfileDefault(sessionKey, modelRef);\n\n log.debug({ sessionKey, totalAgents: this.agents.size, agentId: profile.agentId }, 'Created new agent instance');\n return agent;\n }\n\n /**\n * Get existing agent for a session (if any)\n */\n getAgent(sessionKey: string): Agent | undefined {\n return this.agents.get(sessionKey)?.agent;\n }\n\n /**\n * Check if an agent exists for a session\n */\n hasAgent(sessionKey: string): boolean {\n return this.agents.has(sessionKey);\n }\n\n /**\n * Remove an agent instance\n */\n removeAgent(sessionKey: string): boolean {\n const instance = this.agents.get(sessionKey);\n if (instance) {\n this.backgroundReview.forgetSession(sessionKey);\n void this.toolsFactory.closeBrowserPageForSession(sessionKey);\n void retireSessionMcpRuntimeForSessionKey({ sessionKey, reason: 'agent-evict' });\n instance.agent.abort();\n evictEmbeddedSessionRunner(sessionKey, 'agent_removed');\n this.agents.delete(sessionKey);\n this.memoryPrefetch.forgetSession(sessionKey);\n clearBootstrapSnapshot(sessionKey);\n this.config.getModelManager?.().clearSessionProfileDefault(sessionKey);\n log.info({ sessionKey, totalAgents: this.agents.size }, 'Removed agent instance');\n return true;\n }\n return false;\n }\n\n /**\n * Get all active session keys\n */\n getActiveSessions(): string[] {\n return Array.from(this.agents.keys());\n }\n\n /**\n * Get agent count\n */\n getAgentCount(): number {\n return this.agents.size;\n }\n\n /**\n * Merge per-turn channel system prompt (e.g. Telegram group/topic override) into the agent.\n */\n applyTurnChannelSystemPrompt(sessionKey: string, channelSystemPrompt: string): void {\n const trimmed = channelSystemPrompt.trim();\n if (!trimmed) return;\n\n const instance = this.agents.get(sessionKey);\n if (!instance) return;\n\n const cfg = this.config.config!;\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(resolvedWorkspacePath);\n const contextFiles = this.resolveContextFilesForSession(sessionKey, instance.effectiveProfile);\n const modelRef = instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel;\n const thinkingLevel =\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium';\n\n instance.agent.state.systemPrompt = rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey,\n modelRef,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n extraSystemPrompt: trimmed,\n });\n }\n\n /**\n * Set thinking level for a session's agent\n */\n setThinkingLevel(sessionKey: string, level: ThinkingLevel): void {\n const instance = this.agents.get(sessionKey);\n if (instance) {\n instance.agent.state.thinkingLevel = level;\n log.debug({ sessionKey, thinkingLevel: level }, 'Set thinking level for agent');\n }\n }\n\n /**\n * Dispose all agents\n */\n dispose(): void {\n if (this.skillsUpdatedTimer) clearTimeout(this.skillsUpdatedTimer);\n this.skillFilesystemWatcher.dispose();\n void this.toolsFactory.shutdownBrowser();\n void disposeAllSessionMcpRuntimes().catch(() => {});\n evictAllEmbeddedSessionRunners('agent_manager_dispose');\n this.backgroundReview.clear();\n for (const instance of this.agents.values()) {\n instance.agent.abort();\n }\n this.agents.clear();\n this.memoryPrefetch.clear();\n this.sessionWorkspaceOverrides.clear();\n void this.workspaceRuntimes.clearAll();\n log.debug('All agent instances disposed');\n }\n\n async warmCredentialCache(): Promise<void> {\n const profiles = await this.credentialResolver.listProfiles();\n for (const profile of profiles) {\n const secret = profile.key?.trim()\n ? profile.key.trim()\n : profile.envVar\n ? process.env[profile.envVar]?.trim()\n : undefined;\n if (secret) {\n this.credentialCache.set(profile.provider.toLowerCase(), secret);\n }\n }\n log.debug({ count: this.credentialCache.size }, 'Credential cache warmed');\n }\n\n async refreshCredentials(): Promise<void> {\n this.credentialCache.clear();\n await this.warmCredentialCache();\n }\n\n private resolveApiKeyWithCache(provider: string): string | undefined {\n const key = provider.toLowerCase();\n const cached = this.credentialCache.get(key);\n if (cached) return cached;\n\n const fromDisk = resolveProviderApiKeySync(provider);\n if (fromDisk) {\n this.credentialCache.set(key, fromDisk);\n return fromDisk;\n }\n\n const fromRegistryOrEnv = getApiKeySync(provider);\n if (fromRegistryOrEnv) {\n this.credentialCache.set(key, fromRegistryOrEnv);\n return fromRegistryOrEnv;\n }\n return undefined;\n }\n\n private createAgentForProfile(\n sessionKey: string,\n profile: EffectiveAgentProfile,\n resolvedWorkspacePath: string,\n rt: WorkspaceRuntime,\n ): { agent: Agent; registeredToolNames: string[] } {\n const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;\n const model = this.resolveModelStringToModel(modelRef);\n\n const contextFiles = this.resolveContextFilesForSession(sessionKey, profile);\n const tools = this.toolsFactory.createAllTools({\n workspace: resolvedWorkspacePath,\n profileMarkdownRoot: resolveAgentProfileDir(this.config.config!, profile.agentId),\n disabledTools: profile.tools.disable,\n getPrimaryModel: () => this.resolveModelStringToModel(modelRef),\n getBuiltinMemoryStore: () => rt.builtinMemoryStore,\n getMemoryManager: () => rt.memoryManager,\n getSkillManager: () => rt.skillManager,\n });\n const registeredToolNames = tools.map((t) => t.name);\n\n const thinkingLevel =\n (profile.thinkingDefault as ThinkingLevel | undefined) ?? this.config.thinkingLevel ?? 'medium';\n\n const agent = new Agent({\n initialState: {\n systemPrompt: rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(this.config.config!, profile.agentId),\n systemPromptOverride: profile.systemPromptOverride,\n skillAllowlist: profile.skillsAllowlist,\n registeredToolNames,\n sessionKey,\n modelRef,\n agentId: profile.agentId,\n thinkingLevel,\n }),\n model,\n thinkingLevel,\n tools,\n messages: [],\n },\n streamFn: createExtensionAwareStreamFn(),\n getApiKey: (provider: string) => this.resolveApiKeyWithCache(provider),\n beforeToolCall: async ({ toolCall, args }) => {\n const toolName = toolCall.name;\n\n if (toolName === 'shell') {\n const ctx = this.config.getCurrentContext();\n const cfg = this.mergedConfig();\n if (ctx && cfg) {\n const command =\n typeof (args as { command?: unknown })?.command === 'string'\n ? (args as { command: string }).command\n : JSON.stringify(args ?? {});\n const accountId =\n typeof ctx.metadata?.accountId === 'string' ? ctx.metadata.accountId : undefined;\n const approval = await maybeRequestChannelExecApproval({\n cfg,\n payload: {\n sessionKey: ctx.sessionKey,\n channel: ctx.channel,\n chatId: ctx.chatId,\n accountId,\n toolName,\n summary: command.slice(0, 500),\n details: { command: command.slice(0, 2000) },\n },\n });\n if (approval.required && !approval.approved) {\n return {\n block: true,\n reason: approval.reason ?? 'Exec approval denied or timed out.',\n };\n }\n }\n }\n\n if (!this.config.hookRunner) {\n return undefined;\n }\n const parsed = parseMcpToolName(toolName);\n const hookResult = await this.config.hookRunner.runBeforeToolCall(\n toolName,\n (args ?? {}) as Record<string, unknown>,\n {\n sessionKey,\n isMcpTool: parsed !== null,\n mcpServerId: parsed?.serverId,\n },\n );\n if (!hookResult.allowed) {\n return { block: true, reason: hookResult.reason ?? 'Tool call blocked by policy hook.' };\n }\n return undefined;\n },\n });\n return { agent, registeredToolNames };\n }\n\n /**\n * Set model for a specific session\n */\n setModelForSession(sessionKey: string, modelId: string): boolean {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n log.warn(\n { sessionKey, modelId, activeSessionCount: this.agents.size },\n `setModelForSession: no agent instance for session (create session / run turn first); modelId=${modelId}`,\n );\n return false;\n }\n\n try {\n const model = resolveModel(modelId);\n instance.agent.state.model = model;\n\n const cfg = this.config.config!;\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(resolvedWorkspacePath);\n const contextFiles = this.resolveContextFilesForSession(\n sessionKey,\n instance.effectiveProfile,\n );\n const thinkingLevel =\n (instance.agent.state.thinkingLevel as ThinkingLevel | undefined) ??\n (instance.effectiveProfile.thinkingDefault as ThinkingLevel | undefined) ??\n this.config.thinkingLevel ??\n 'medium';\n\n instance.agent.state.systemPrompt = rt.systemPromptBuilder.build(contextFiles, {\n externalMemoryInstructions: rt.memoryManager.buildExternalSystemPrompt(),\n workspaceOverride: resolvedWorkspacePath,\n profileMarkdownPathRoot: resolveAgentProfileDir(cfg, instance.effectiveProfile.agentId),\n systemPromptOverride: instance.effectiveProfile.systemPromptOverride,\n skillAllowlist: instance.effectiveProfile.skillsAllowlist,\n registeredToolNames: instance.registeredToolNames,\n sessionKey,\n modelRef: modelId,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n });\n\n log.info({ sessionKey, modelId }, 'Model set for session');\n return true;\n } catch (err) {\n log.error({ err, sessionKey, modelId }, 'Failed to set model for session');\n return false;\n }\n }\n\n /**\n * Get last assistant content from a session's agent\n */\n getLastAssistantContent(sessionKey: string): string | null {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return null;\n }\n\n const messages = instance.agent.state.messages;\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.role === 'assistant') {\n const content = msg.content;\n if (Array.isArray(content)) {\n return extractTextContent(content as Array<{ type: string; text?: string }>);\n }\n return String(content);\n }\n }\n return null;\n }\n\n /**\n * Replace messages for a session's agent\n */\n replaceMessages(sessionKey: string, messages: AgentMessage[]): boolean {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return false;\n }\n\n instance.agent.state.messages = messages;\n return true;\n }\n\n /**\n * Get messages for a session's agent\n */\n getMessages(sessionKey: string): AgentMessage[] | null {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return null;\n }\n\n return instance.agent.state.messages;\n }\n\n /**\n * Subscribe to agent events for a session\n */\n subscribeToSession(sessionKey: string, callback: (event: AgentEvent) => void): (() => void) | null {\n const instance = this.agents.get(sessionKey);\n if (!instance) {\n return null;\n }\n\n return instance.agent.subscribe(callback);\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
|
|
|
2
2
|
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
3
3
|
import { expandWorkspacePathString, init_workspace_path } from "../config/workspace-path.js";
|
|
4
4
|
import { init_workspace_defaults, resolveDefaultAgentWorkspaceDir } from "../config/workspace-defaults.js";
|
|
5
|
-
import fs from "node:fs";
|
|
6
5
|
import { basename, isAbsolute, join, relative, resolve } from "node:path";
|
|
6
|
+
import fs from "node:fs";
|
|
7
7
|
//#region src/agent/agent-scope.ts
|
|
8
8
|
/**
|
|
9
9
|
* Agent path and list resolution (config is the single source of truth).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_AGENTS_FILENAME, DEFAULT_HEARTBEAT_FILENAME, DEFAULT_IDENTITY_FILENAME, DEFAULT_MEMORY_FILENAME, DEFAULT_SOUL_FILENAME, DEFAULT_TOOLS_FILENAME, DEFAULT_USER_FILENAME, stripFrontMatter } from "../context/workspace.js";
|
|
2
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
3
2
|
import { join, resolve } from "node:path";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
//#region src/agent/bootstrap/load-bootstrap-files.ts
|
|
5
5
|
const PROFILE_LOAD_ORDER = [
|
|
6
6
|
DEFAULT_AGENTS_FILENAME,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DEFAULT_AGENTS_FILENAME, stripFrontMatter } from "../context/workspace.js";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
//#region src/agent/bootstrap/project-agents-context.ts
|
|
5
|
+
const PROJECT_AGENTS_MAX_CHARS = 2e4;
|
|
6
|
+
function truncateProjectAgentsContent(content) {
|
|
7
|
+
if (content.length <= PROJECT_AGENTS_MAX_CHARS) return content;
|
|
8
|
+
const suffix = `\n\n[Project AGENTS.md truncated to ${PROJECT_AGENTS_MAX_CHARS} characters]`;
|
|
9
|
+
return `${content.slice(0, Math.max(0, PROJECT_AGENTS_MAX_CHARS - suffix.length)).trimEnd()}${suffix}`;
|
|
10
|
+
}
|
|
11
|
+
function loadProjectAgentsContextFile(workspaceDir) {
|
|
12
|
+
const agentsPath = resolve(join(workspaceDir, DEFAULT_AGENTS_FILENAME));
|
|
13
|
+
if (!existsSync(agentsPath)) return null;
|
|
14
|
+
try {
|
|
15
|
+
const content = truncateProjectAgentsContent(stripFrontMatter(readFileSync(agentsPath, "utf-8")).trim());
|
|
16
|
+
if (!content) return null;
|
|
17
|
+
return {
|
|
18
|
+
path: agentsPath,
|
|
19
|
+
content: [
|
|
20
|
+
"Workspace AGENTS.md contains project-local instructions. Follow it for this workspace's coding conventions, commands, tests, and repository-specific workflows. If it conflicts with higher-priority system instructions, tool safety, or the user's explicit request, follow the higher-priority instruction.",
|
|
21
|
+
"",
|
|
22
|
+
content
|
|
23
|
+
].join("\n")
|
|
24
|
+
};
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { loadProjectAgentsContextFile };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=project-agents-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-agents-context.js","names":[],"sources":["../../../../src/agent/bootstrap/project-agents-context.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\n\nimport { stripFrontMatter, DEFAULT_AGENTS_FILENAME } from '../context/workspace.js';\nimport type { EmbeddedContextFile } from './types.js';\n\nconst PROJECT_AGENTS_MAX_CHARS = 20_000;\n\nfunction truncateProjectAgentsContent(content: string): string {\n if (content.length <= PROJECT_AGENTS_MAX_CHARS) {\n return content;\n }\n const suffix = `\\n\\n[Project AGENTS.md truncated to ${PROJECT_AGENTS_MAX_CHARS} characters]`;\n return `${content.slice(0, Math.max(0, PROJECT_AGENTS_MAX_CHARS - suffix.length)).trimEnd()}${suffix}`;\n}\n\nexport function loadProjectAgentsContextFile(workspaceDir: string): EmbeddedContextFile | null {\n const agentsPath = resolve(join(workspaceDir, DEFAULT_AGENTS_FILENAME));\n if (!existsSync(agentsPath)) {\n return null;\n }\n\n try {\n const content = truncateProjectAgentsContent(stripFrontMatter(readFileSync(agentsPath, 'utf-8')).trim());\n if (!content) {\n return null;\n }\n return {\n path: agentsPath,\n content: [\n 'Workspace AGENTS.md contains project-local instructions. Follow it for this workspace\\'s coding conventions, commands, tests, and repository-specific workflows. If it conflicts with higher-priority system instructions, tool safety, or the user\\'s explicit request, follow the higher-priority instruction.',\n '',\n content,\n ].join('\\n'),\n };\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;AAMA,MAAM,2BAA2B;AAEjC,SAAS,6BAA6B,SAAyB;AAC7D,KAAI,QAAQ,UAAU,yBACpB,QAAO;CAET,MAAM,SAAS,uCAAuC,yBAAyB;AAC/E,QAAO,GAAG,QAAQ,MAAM,GAAG,KAAK,IAAI,GAAG,2BAA2B,OAAO,OAAO,CAAC,CAAC,SAAS,GAAG;;AAGhG,SAAgB,6BAA6B,cAAkD;CAC7F,MAAM,aAAa,QAAQ,KAAK,cAAc,wBAAwB,CAAC;AACvE,KAAI,CAAC,WAAW,WAAW,CACzB,QAAO;AAGT,KAAI;EACF,MAAM,UAAU,6BAA6B,iBAAiB,aAAa,YAAY,QAAQ,CAAC,CAAC,MAAM,CAAC;AACxG,MAAI,CAAC,QACH,QAAO;AAET,SAAO;GACL,MAAM;GACN,SAAS;IACP;IACA;IACA;IACD,CAAC,KAAK,KAAK;GACb;SACK;AACN,SAAO"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { init_agent_scope, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agent-scope.js";
|
|
2
|
-
import { WORKSPACE_FILES, init_paths } from "../../config/paths.js";
|
|
3
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
4
3
|
import { init_logger } from "../../utils/logger.js";
|
|
4
|
+
import { WORKSPACE_FILES, init_paths } from "../../config/paths.js";
|
|
5
5
|
import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES } from "./workspace.js";
|
|
6
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
6
|
import { dirname, join } from "node:path";
|
|
7
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
10
|
//#region src/agent/context/workspace-seed.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FILENAMES, init_paths, resolveWorkspaceStatePath } from "../../config/paths.js";
|
|
2
|
-
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
//#region src/agent/context/workspace-state.ts
|
|
5
5
|
/**
|
|
6
6
|
* Workspace setup metadata in `<markdownWorkspace>/.xopc/workspace.json`
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { parseFrontmatter } from "../../markdown/frontmatter.js";
|
|
4
|
-
import { existsSync, readFileSync } from "fs";
|
|
5
4
|
import { join, resolve } from "path";
|
|
5
|
+
import { existsSync, readFileSync } from "fs";
|
|
6
6
|
//#region src/agent/context/workspace.ts
|
|
7
7
|
/**
|
|
8
8
|
* Agent profile Markdown (filenames, load order, system prompt assembly) and
|
|
@@ -337,7 +337,14 @@ var ToolResultGuard = class {
|
|
|
337
337
|
isSynthetic: false
|
|
338
338
|
}));
|
|
339
339
|
if (!persisted) return;
|
|
340
|
-
|
|
340
|
+
const finalToolResult = capToolResultForPersistence(persisted, this.maxToolResultChars);
|
|
341
|
+
const result = this.originalAppend(finalToolResult);
|
|
342
|
+
if (this.opts.sessionKey) emitSessionTranscriptUpdate({
|
|
343
|
+
sessionKey: this.opts.sessionKey,
|
|
344
|
+
message: finalToolResult,
|
|
345
|
+
messageId: typeof result === "string" ? result : void 0
|
|
346
|
+
});
|
|
347
|
+
return result;
|
|
341
348
|
}
|
|
342
349
|
const stopReason = nextMessage.stopReason;
|
|
343
350
|
const toolCalls = nextRole === "assistant" && stopReason !== "aborted" && stopReason !== "error" ? extractToolCallsFromAssistant(nextMessage) : [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-tool-result-guard.js","names":[],"sources":["../../../../src/agent/embedded/session-tool-result-guard.ts"],"sourcesContent":["/**\n * Session tool-result guard — wraps a pi `SessionManager.appendMessage` to:\n * 1. cap oversized tool-result text + details so they cannot blow up the next\n * LLM request (size + persistence limits).\n * 2. track pending tool-call IDs so missing tool results can be synthesised\n * (some providers refuse a turn that has an orphan tool_use block).\n * 3. drop assistant `toolCall` blocks whose tool name is not in the allowlist\n * (these would also trigger provider 400s).\n * 4. broadcast `xopc:transcript-row` updates so the gateway UI can stream them.\n *\n * Previously this module shipped with three sibling files\n * (`session-tool-result-state.ts`, `session-raw-append-message.ts`,\n * `session-tool-result-guard-wrapper.ts`). They are now consolidated here as\n * private constructs around the `ToolResultGuard` class. Pi-coding-agent owns\n * the `SessionManager` instance and calls `appendMessage` from inside the\n * runtime, so we still need to monkey-patch that method — but the patched\n * implementation is just `guard.guardedAppend.bind(guard)` and all state lives\n * on the class.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { SessionManager } from '@earendil-works/pi-coding-agent';\n\nimport type { Config } from '../../config/schema.js';\nimport {\n boundedJsonUtf8Bytes,\n firstEnumerableOwnKeys,\n jsonUtf8BytesOrInfinity,\n type BoundedJsonUtf8Bytes,\n} from '../../infra/json-utf8-bytes.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { normalizeOptionalString } from '../../utils/string-coerce.js';\nimport { formatContextLimitTruncationNotice } from './tool-result-context-guard.js';\nimport {\n DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS,\n resolveLiveToolResultMaxChars,\n truncateToolResultMessage,\n} from './tool-result-truncation.js';\nimport {\n makeMissingToolResult,\n sanitizeToolCallInputs,\n} from '../transcript/session-transcript-repair.js';\nimport {\n extractToolCallsFromAssistant,\n extractToolResultId,\n} from '../transcript/tool-call-id.js';\n\n// ── Public surface ──────────────────────────────────────────────────────────\n\nexport type BeforeMessageWriteHookEvent = { message: AgentMessage };\nexport type BeforeMessageWriteHookResult =\n | { block?: boolean; message?: AgentMessage }\n | undefined;\n\nexport interface ToolResultGuardOptions {\n /** Optional session key for transcript update broadcasts. */\n sessionKey?: string;\n /** Optional transform applied to any message before persistence. */\n transformMessageForPersistence?: (message: AgentMessage) => AgentMessage;\n /**\n * Optional, synchronous transform applied to toolResult messages *before* they are\n * persisted to the session transcript.\n */\n transformToolResultForPersistence?: (\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ) => AgentMessage;\n /**\n * Whether to synthesize missing tool results to satisfy strict providers.\n * Defaults to true.\n */\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n /**\n * Optional set/list of tool names accepted for assistant toolCall/toolUse blocks.\n * When set, tool calls with unknown names are dropped before persistence.\n */\n allowedToolNames?: Iterable<string>;\n /**\n * Synchronous hook invoked before any message is written to the session JSONL.\n * If the hook returns { block: true }, the message is silently dropped.\n * If it returns { message }, the modified message is written instead.\n */\n beforeMessageWriteHook?: (event: BeforeMessageWriteHookEvent) => BeforeMessageWriteHookResult;\n maxToolResultChars?: number;\n}\n\nexport interface InstallSessionToolResultGuardResult {\n flushPendingToolResults: () => void;\n clearPendingToolResults: () => void;\n getPendingIds: () => string[];\n}\n\n/** Idempotent wrapper that also adds the helper methods consumers expect. */\nexport type GuardedPiTranscriptManager = SessionManager & {\n flushPendingToolResults?: () => void;\n clearPendingToolResults?: () => void;\n};\n\n/**\n * Install the guard on a SessionManager and return its control API.\n * Subsequent assistant/toolResult writes by pi-coding-agent flow through the\n * guard transparently.\n */\nexport function installSessionToolResultGuard(\n sessionManager: SessionManager,\n opts: ToolResultGuardOptions = {},\n): InstallSessionToolResultGuardResult {\n const guard = new ToolResultGuard(sessionManager, opts);\n guard.attach();\n return {\n flushPendingToolResults: () => guard.flushPending(),\n clearPendingToolResults: () => guard.clearPending(),\n getPendingIds: () => guard.getPendingIds(),\n };\n}\n\n/**\n * Convenience wrapper used by the embedded runner pool: install the guard\n * (idempotent), pin the size cap from the model context window, and expose\n * `flushPendingToolResults` / `clearPendingToolResults` directly on the\n * SessionManager instance so callers do not need to keep the install result.\n */\nexport function guardSessionManager(\n sessionManager: SessionManager,\n opts?: {\n agentId?: string;\n sessionKey?: string;\n config?: Config;\n contextWindowTokens?: number;\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n allowedToolNames?: Iterable<string>;\n transformMessageForPersistence?: (message: AgentMessage) => AgentMessage;\n },\n): GuardedPiTranscriptManager {\n if (typeof (sessionManager as GuardedPiTranscriptManager).flushPendingToolResults === 'function') {\n return sessionManager as GuardedPiTranscriptManager;\n }\n\n const result = installSessionToolResultGuard(sessionManager, {\n sessionKey: opts?.sessionKey,\n transformMessageForPersistence: opts?.transformMessageForPersistence,\n allowSyntheticToolResults: opts?.allowSyntheticToolResults,\n missingToolResultText: opts?.missingToolResultText,\n allowedToolNames: opts?.allowedToolNames,\n maxToolResultChars:\n typeof opts?.contextWindowTokens === 'number'\n ? resolveLiveToolResultMaxChars({\n contextWindowTokens: opts.contextWindowTokens,\n cfg: opts?.config,\n agentId: opts?.agentId,\n })\n : undefined,\n });\n const tagged = sessionManager as GuardedPiTranscriptManager;\n tagged.flushPendingToolResults = result.flushPendingToolResults;\n tagged.clearPendingToolResults = result.clearPendingToolResults;\n return tagged;\n}\n\n/**\n * Recover the original (un-guarded) appendMessage for a session manager.\n * Useful for callers that need a low-level \"bypass the guard\" write path.\n */\nexport function getRawSessionAppendMessage(\n sessionManager: SessionManager,\n): SessionManager['appendMessage'] {\n const stored = (sessionManager as SessionManagerWithRawAppend)[RAW_APPEND_MESSAGE];\n return stored ?? sessionManager.appendMessage.bind(sessionManager);\n}\n\n// ── Internal: persistence + truncation helpers ──────────────────────────────\n\nfunction resolveMaxToolResultChars(opts: { maxToolResultChars?: number }): number {\n return Math.max(1, opts.maxToolResultChars ?? DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS);\n}\n\nfunction capToolResultSize(msg: AgentMessage, maxChars: number): AgentMessage {\n if ((msg as { role?: string }).role !== 'toolResult') {\n return msg;\n }\n return truncateToolResultMessage(msg, maxChars, {\n suffix: (truncatedChars) => formatContextLimitTruncationNotice(truncatedChars),\n minKeepChars: 2_000,\n });\n}\n\n// `details` is runtime/UI metadata, not model-visible tool output. Keep the\n// session JSONL useful for debugging without letting metadata blobs dominate\n// disk, replay repair, transcript broadcasts, or future tooling that reads raw\n// sessions. Model-visible text belongs in tool result `content`.\nconst MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES = 8_192;\nconst MAX_PERSISTED_DETAIL_STRING_CHARS = 2_000;\nconst MAX_PERSISTED_DETAIL_SESSION_COUNT = 10;\nconst MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS = 200;\n\nfunction originalDetailsSizeFields(size: BoundedJsonUtf8Bytes): Record<string, number> {\n return size.complete\n ? { originalDetailsBytes: size.bytes }\n : { originalDetailsBytesAtLeast: size.bytes };\n}\n\nfunction truncatePersistedDetailString(\n value: string,\n maxChars = MAX_PERSISTED_DETAIL_STRING_CHARS,\n): string {\n if (value.length <= maxChars) {\n return value;\n }\n return `${value.slice(0, maxChars)}\\n\\n[xopc persisted detail truncated: ${\n value.length - maxChars\n } chars omitted]`;\n}\n\nfunction sanitizePersistedSessionDetail(value: unknown): unknown {\n if (!value || typeof value !== 'object') {\n return value;\n }\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of [\n 'sessionId',\n 'status',\n 'pid',\n 'startedAt',\n 'endedAt',\n 'runtimeMs',\n 'cwd',\n 'name',\n 'truncated',\n 'exitCode',\n 'exitSignal',\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === 'string' ? truncatePersistedDetailString(field, 500) : field;\n }\n }\n if (typeof src.command === 'string') {\n out.command = truncatePersistedDetailString(src.command, 500);\n }\n return out;\n}\n\nfunction buildPersistedDetailsFallback(\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n sanitizedBytes?: number,\n): Record<string, unknown> {\n const fallback: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n };\n if (sanitizedBytes !== undefined) {\n fallback.sanitizedDetailsBytes = sanitizedBytes;\n }\n if (src) {\n fallback.originalDetailKeys = firstEnumerableOwnKeys(src, 40);\n for (const key of ['status', 'sessionId', 'pid', 'exitCode', 'exitSignal', 'truncated']) {\n const field = src[key];\n if (field !== undefined) {\n fallback[key] =\n typeof field === 'string'\n ? truncatePersistedDetailString(field, MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS)\n : field;\n }\n }\n }\n return fallback;\n}\n\nfunction enforcePersistedDetailsByteCap(\n value: Record<string, unknown>,\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n): Record<string, unknown> {\n const sanitizedBytes = jsonUtf8BytesOrInfinity(value);\n if (sanitizedBytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return value;\n }\n const fallback = buildPersistedDetailsFallback(src, originalSize, sanitizedBytes);\n if (jsonUtf8BytesOrInfinity(fallback) <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return fallback;\n }\n return {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n sanitizedDetailsBytes: sanitizedBytes,\n };\n}\n\nfunction sanitizeToolResultDetailsForPersistence(details: unknown): unknown {\n if (details === undefined || details === null) {\n return details;\n }\n const originalSize = boundedJsonUtf8Bytes(details, MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES);\n if (originalSize.complete && originalSize.bytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return details;\n }\n if (typeof details !== 'object') {\n return enforcePersistedDetailsByteCap(\n {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n valueType: typeof details,\n },\n undefined,\n originalSize,\n );\n }\n const src = details as Record<string, unknown>;\n const out: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n originalDetailKeys: firstEnumerableOwnKeys(src, 40),\n };\n for (const key of [\n 'status',\n 'sessionId',\n 'pid',\n 'startedAt',\n 'endedAt',\n 'cwd',\n 'name',\n 'exitCode',\n 'exitSignal',\n 'retryInMs',\n 'total',\n 'totalLines',\n 'totalChars',\n 'truncated',\n 'fullOutputPath',\n 'truncation',\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === 'string' ? truncatePersistedDetailString(field) : field;\n }\n }\n if (typeof src.tail === 'string') {\n out.tail = truncatePersistedDetailString(src.tail);\n }\n if (Array.isArray(src.sessions)) {\n out.sessions = src.sessions\n .slice(0, MAX_PERSISTED_DETAIL_SESSION_COUNT)\n .map(sanitizePersistedSessionDetail);\n if (src.sessions.length > MAX_PERSISTED_DETAIL_SESSION_COUNT) {\n out.sessionsTruncated = src.sessions.length - MAX_PERSISTED_DETAIL_SESSION_COUNT;\n }\n }\n return enforcePersistedDetailsByteCap(out, src, originalSize);\n}\n\nfunction capToolResultDetails(msg: AgentMessage): AgentMessage {\n if ((msg as { role?: string }).role !== 'toolResult') {\n return msg;\n }\n const details = (msg as { details?: unknown }).details;\n const sanitizedDetails = sanitizeToolResultDetailsForPersistence(details);\n if (sanitizedDetails === details) {\n return msg;\n }\n const next = { ...msg } as AgentMessage & { details?: unknown };\n next.details = sanitizedDetails;\n return next;\n}\n\nfunction capToolResultForPersistence(msg: AgentMessage, maxChars: number): AgentMessage {\n return capToolResultDetails(capToolResultSize(msg, maxChars));\n}\n\nfunction normalizePersistedToolResultName(\n message: AgentMessage,\n fallbackName?: string,\n): AgentMessage {\n if ((message as { role?: unknown }).role !== 'toolResult') {\n return message;\n }\n const toolResult = message as Extract<AgentMessage, { role: 'toolResult' }>;\n const rawToolName = (toolResult as { toolName?: unknown }).toolName;\n const normalizedToolName = normalizeOptionalString(rawToolName);\n if (normalizedToolName) {\n if (rawToolName === normalizedToolName) {\n return toolResult;\n }\n return { ...toolResult, toolName: normalizedToolName };\n }\n\n const normalizedFallback = normalizeOptionalString(fallbackName);\n if (normalizedFallback) {\n return { ...toolResult, toolName: normalizedFallback };\n }\n\n if (typeof rawToolName === 'string') {\n return { ...toolResult, toolName: 'unknown' };\n }\n return toolResult;\n}\n\n// ── Internal: raw-append symbol storage ─────────────────────────────────────\n\nconst RAW_APPEND_MESSAGE = Symbol('xopc.session.rawAppendMessage');\n\ntype SessionManagerWithRawAppend = SessionManager & {\n [RAW_APPEND_MESSAGE]?: SessionManager['appendMessage'];\n};\n\nfunction rememberOriginalAppend(\n sessionManager: SessionManager,\n): SessionManager['appendMessage'] {\n const tagged = sessionManager as SessionManagerWithRawAppend;\n const stored = tagged[RAW_APPEND_MESSAGE];\n if (stored) {\n return stored;\n }\n const original = sessionManager.appendMessage.bind(sessionManager);\n tagged[RAW_APPEND_MESSAGE] = original;\n return original;\n}\n\n// ── Internal: pending tool-call state ──────────────────────────────────────\n\ntype PendingToolCall = { id: string; name?: string };\n\nclass PendingToolCallTracker {\n private readonly pending = new Map<string, string | undefined>();\n\n size(): number {\n return this.pending.size;\n }\n\n getToolName(id: string): string | undefined {\n return this.pending.get(id);\n }\n\n delete(id: string): void {\n this.pending.delete(id);\n }\n\n clear(): void {\n this.pending.clear();\n }\n\n trackToolCalls(calls: readonly PendingToolCall[]): void {\n for (const call of calls) {\n this.pending.set(call.id, call.name);\n }\n }\n\n entries(): IterableIterator<[string, string | undefined]> {\n return this.pending.entries();\n }\n\n getPendingIds(): string[] {\n return Array.from(this.pending.keys());\n }\n\n shouldFlushForSanitizedDrop(): boolean {\n return this.pending.size > 0;\n }\n\n shouldFlushBeforeNonToolResult(nextRole: unknown, toolCallCount: number): boolean {\n return this.pending.size > 0 && (toolCallCount === 0 || nextRole !== 'assistant');\n }\n\n shouldFlushBeforeNewToolCalls(toolCallCount: number): boolean {\n return this.pending.size > 0 && toolCallCount > 0;\n }\n}\n\n// ── ToolResultGuard class ──────────────────────────────────────────────────\n\nclass ToolResultGuard {\n private readonly sessionManager: SessionManager;\n private readonly opts: ToolResultGuardOptions;\n private readonly pending = new PendingToolCallTracker();\n private readonly originalAppend: SessionManager['appendMessage'];\n private readonly allowSyntheticToolResults: boolean;\n private readonly maxToolResultChars: number;\n\n constructor(sessionManager: SessionManager, opts: ToolResultGuardOptions) {\n this.sessionManager = sessionManager;\n this.opts = opts;\n this.originalAppend = rememberOriginalAppend(sessionManager);\n this.allowSyntheticToolResults = opts.allowSyntheticToolResults ?? true;\n this.maxToolResultChars = resolveMaxToolResultChars(opts);\n }\n\n /** Monkey-patch the session manager so pi-coding-agent's internal appendMessage flows through us. */\n attach(): void {\n const bound = this.guardedAppend.bind(this);\n this.sessionManager.appendMessage = bound as SessionManager['appendMessage'];\n }\n\n flushPending(): void {\n if (this.pending.size() === 0) {\n return;\n }\n if (this.allowSyntheticToolResults) {\n for (const [id, name] of this.pending.entries()) {\n const synthetic = makeMissingToolResult({\n toolCallId: id,\n toolName: name,\n text: this.opts.missingToolResultText,\n });\n const flushed = this.applyBeforeWriteHook(\n this.persistToolResult(this.persistMessage(synthetic), {\n toolCallId: id,\n toolName: name,\n isSynthetic: true,\n }),\n );\n if (flushed) {\n this.originalAppend(capToolResultForPersistence(flushed, this.maxToolResultChars) as never);\n }\n }\n }\n this.pending.clear();\n }\n\n clearPending(): void {\n this.pending.clear();\n }\n\n getPendingIds(): string[] {\n return this.pending.getPendingIds();\n }\n\n private persistMessage(message: AgentMessage): AgentMessage {\n const transformer = this.opts.transformMessageForPersistence;\n return transformer ? transformer(message) : message;\n }\n\n private persistToolResult(\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ): AgentMessage {\n const transformer = this.opts.transformToolResultForPersistence;\n return transformer ? transformer(message, meta) : message;\n }\n\n /**\n * Run the before_message_write hook. Returns the (possibly modified) message,\n * or null if the message should be blocked.\n */\n private applyBeforeWriteHook(msg: AgentMessage): AgentMessage | null {\n const beforeWrite = this.opts.beforeMessageWriteHook;\n if (!beforeWrite) {\n return msg;\n }\n const result = beforeWrite({ message: msg });\n if (result?.block) {\n return null;\n }\n if (result?.message) {\n return result.message;\n }\n return msg;\n }\n\n private guardedAppend(message: AgentMessage): unknown {\n let nextMessage = message;\n const role = (message as { role?: unknown }).role;\n if (role === 'assistant') {\n const sanitized = sanitizeToolCallInputs([message], {\n allowedToolNames: this.opts.allowedToolNames,\n });\n if (sanitized.length === 0) {\n if (this.pending.shouldFlushForSanitizedDrop()) {\n this.flushPending();\n }\n return undefined;\n }\n nextMessage = sanitized[0];\n }\n const nextRole = (nextMessage as { role?: unknown }).role;\n\n if (nextRole === 'toolResult') {\n const id = extractToolResultId(nextMessage as Extract<AgentMessage, { role: 'toolResult' }>);\n const toolName = id ? this.pending.getToolName(id) : undefined;\n if (id) {\n this.pending.delete(id);\n }\n const normalizedToolResult = normalizePersistedToolResultName(nextMessage, toolName);\n // Apply hard size cap before persistence to prevent oversized tool results\n // from consuming the entire context window on subsequent LLM calls.\n const capped = capToolResultForPersistence(\n this.persistMessage(normalizedToolResult),\n this.maxToolResultChars,\n );\n const persisted = this.applyBeforeWriteHook(\n this.persistToolResult(capped, {\n toolCallId: id ?? undefined,\n toolName,\n isSynthetic: false,\n }),\n );\n if (!persisted) {\n return undefined;\n }\n return this.originalAppend(capToolResultForPersistence(persisted, this.maxToolResultChars) as never);\n }\n\n // Skip tool call extraction for aborted/errored assistant messages.\n // When stopReason is \"error\" or \"aborted\", the tool_use blocks may be incomplete\n // and should not have synthetic tool_results created. Creating synthetic results\n // for incomplete tool calls causes API 400 errors:\n // \"unexpected tool_use_id found in tool_result blocks\"\n // This matches the behavior in repairToolUseResultPairing (session-transcript-repair.ts)\n const stopReason = (nextMessage as { stopReason?: string }).stopReason;\n const toolCalls =\n nextRole === 'assistant' && stopReason !== 'aborted' && stopReason !== 'error'\n ? extractToolCallsFromAssistant(nextMessage as Extract<AgentMessage, { role: 'assistant' }>)\n : [];\n\n // Always clear pending tool call state before appending non-tool-result messages.\n // flushPendingToolResults() only inserts synthetic results when allowSyntheticToolResults\n // is true; it always clears the pending map. Without this, providers that disable\n // synthetic results (e.g. OpenAI) accumulate stale pending state when a user message\n // interrupts in-flight tool calls, leaving orphaned tool_use blocks in the transcript\n // that cause API 400 errors on subsequent requests.\n if (this.pending.shouldFlushBeforeNonToolResult(nextRole, toolCalls.length)) {\n this.flushPending();\n }\n // If new tool calls arrive while older ones are pending, flush the old ones first.\n if (this.pending.shouldFlushBeforeNewToolCalls(toolCalls.length)) {\n this.flushPending();\n }\n\n const finalMessage = this.applyBeforeWriteHook(this.persistMessage(nextMessage));\n if (!finalMessage) {\n return undefined;\n }\n const result = this.originalAppend(finalMessage as never);\n\n if (this.opts.sessionKey) {\n emitSessionTranscriptUpdate({\n sessionKey: this.opts.sessionKey,\n message: finalMessage,\n messageId: typeof result === 'string' ? result : undefined,\n });\n }\n\n if (toolCalls.length > 0) {\n this.pending.trackToolCalls(toolCalls);\n }\n\n return result;\n }\n}\n"],"mappings":";;;;;;;;oBA+BuE;;;;;;AAyEvE,SAAgB,8BACd,gBACA,OAA+B,EAAE,EACI;CACrC,MAAM,QAAQ,IAAI,gBAAgB,gBAAgB,KAAK;AACvD,OAAM,QAAQ;AACd,QAAO;EACL,+BAA+B,MAAM,cAAc;EACnD,+BAA+B,MAAM,cAAc;EACnD,qBAAqB,MAAM,eAAe;EAC3C;;;;;;;;AASH,SAAgB,oBACd,gBACA,MAU4B;AAC5B,KAAI,OAAQ,eAA8C,4BAA4B,WACpF,QAAO;CAGT,MAAM,SAAS,8BAA8B,gBAAgB;EAC3D,YAAY,MAAM;EAClB,gCAAgC,MAAM;EACtC,2BAA2B,MAAM;EACjC,uBAAuB,MAAM;EAC7B,kBAAkB,MAAM;EACxB,oBACE,OAAO,MAAM,wBAAwB,WACjC,8BAA8B;GAC5B,qBAAqB,KAAK;GAC1B,KAAK,MAAM;GACX,SAAS,MAAM;GAChB,CAAC,GACF,KAAA;EACP,CAAC;CACF,MAAM,SAAS;AACf,QAAO,0BAA0B,OAAO;AACxC,QAAO,0BAA0B,OAAO;AACxC,QAAO;;;;;;AAOT,SAAgB,2BACd,gBACiC;AAEjC,QADgB,eAA+C,uBAC9C,eAAe,cAAc,KAAK,eAAe;;AAKpE,SAAS,0BAA0B,MAA+C;AAChF,QAAO,KAAK,IAAI,GAAG,KAAK,sBAAA,KAAyD;;AAGnF,SAAS,kBAAkB,KAAmB,UAAgC;AAC5E,KAAK,IAA0B,SAAS,aACtC,QAAO;AAET,QAAO,0BAA0B,KAAK,UAAU;EAC9C,SAAS,mBAAmB,mCAAmC,eAAe;EAC9E,cAAc;EACf,CAAC;;AAOJ,MAAM,0CAA0C;AAChD,MAAM,oCAAoC;AAC1C,MAAM,qCAAqC;AAC3C,MAAM,6CAA6C;AAEnD,SAAS,0BAA0B,MAAoD;AACrF,QAAO,KAAK,WACR,EAAE,sBAAsB,KAAK,OAAO,GACpC,EAAE,6BAA6B,KAAK,OAAO;;AAGjD,SAAS,8BACP,OACA,WAAW,mCACH;AACR,KAAI,MAAM,UAAU,SAClB,QAAO;AAET,QAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC,wCACjC,MAAM,SAAS,SAChB;;AAGH,SAAS,+BAA+B,OAAyB;AAC/D,KAAI,CAAC,SAAS,OAAO,UAAU,SAC7B,QAAO;CAET,MAAM,MAAM;CACZ,MAAM,MAA+B,EAAE;AACvC,MAAK,MAAM,OAAO;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,EAAE;EACD,MAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,KAAA,EACZ,KAAI,OAAO,OAAO,UAAU,WAAW,8BAA8B,OAAO,IAAI,GAAG;;AAGvF,KAAI,OAAO,IAAI,YAAY,SACzB,KAAI,UAAU,8BAA8B,IAAI,SAAS,IAAI;AAE/D,QAAO;;AAGT,SAAS,8BACP,KACA,cACA,gBACyB;CACzB,MAAM,WAAoC;EACxC,2BAA2B;EAC3B,uBAAuB;EACvB,GAAG,0BAA0B,aAAa;EAC3C;AACD,KAAI,mBAAmB,KAAA,EACrB,UAAS,wBAAwB;AAEnC,KAAI,KAAK;AACP,WAAS,qBAAqB,uBAAuB,KAAK,GAAG;AAC7D,OAAK,MAAM,OAAO;GAAC;GAAU;GAAa;GAAO;GAAY;GAAc;GAAY,EAAE;GACvF,MAAM,QAAQ,IAAI;AAClB,OAAI,UAAU,KAAA,EACZ,UAAS,OACP,OAAO,UAAU,WACb,8BAA8B,OAAO,2CAA2C,GAChF;;;AAIZ,QAAO;;AAGT,SAAS,+BACP,OACA,KACA,cACyB;CACzB,MAAM,iBAAiB,wBAAwB,MAAM;AACrD,KAAI,kBAAkB,wCACpB,QAAO;CAET,MAAM,WAAW,8BAA8B,KAAK,cAAc,eAAe;AACjF,KAAI,wBAAwB,SAAS,IAAI,wCACvC,QAAO;AAET,QAAO;EACL,2BAA2B;EAC3B,uBAAuB;EACvB,GAAG,0BAA0B,aAAa;EAC1C,uBAAuB;EACxB;;AAGH,SAAS,wCAAwC,SAA2B;AAC1E,KAAI,YAAY,KAAA,KAAa,YAAY,KACvC,QAAO;CAET,MAAM,eAAe,qBAAqB,SAAS,wCAAwC;AAC3F,KAAI,aAAa,YAAY,aAAa,SAAS,wCACjD,QAAO;AAET,KAAI,OAAO,YAAY,SACrB,QAAO,+BACL;EACE,2BAA2B;EAC3B,GAAG,0BAA0B,aAAa;EAC1C,WAAW,OAAO;EACnB,EACD,KAAA,GACA,aACD;CAEH,MAAM,MAAM;CACZ,MAAM,MAA+B;EACnC,2BAA2B;EAC3B,GAAG,0BAA0B,aAAa;EAC1C,oBAAoB,uBAAuB,KAAK,GAAG;EACpD;AACD,MAAK,MAAM,OAAO;EAChB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,EAAE;EACD,MAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,KAAA,EACZ,KAAI,OAAO,OAAO,UAAU,WAAW,8BAA8B,MAAM,GAAG;;AAGlF,KAAI,OAAO,IAAI,SAAS,SACtB,KAAI,OAAO,8BAA8B,IAAI,KAAK;AAEpD,KAAI,MAAM,QAAQ,IAAI,SAAS,EAAE;AAC/B,MAAI,WAAW,IAAI,SAChB,MAAM,GAAG,mCAAmC,CAC5C,IAAI,+BAA+B;AACtC,MAAI,IAAI,SAAS,SAAS,mCACxB,KAAI,oBAAoB,IAAI,SAAS,SAAS;;AAGlD,QAAO,+BAA+B,KAAK,KAAK,aAAa;;AAG/D,SAAS,qBAAqB,KAAiC;AAC7D,KAAK,IAA0B,SAAS,aACtC,QAAO;CAET,MAAM,UAAW,IAA8B;CAC/C,MAAM,mBAAmB,wCAAwC,QAAQ;AACzE,KAAI,qBAAqB,QACvB,QAAO;CAET,MAAM,OAAO,EAAE,GAAG,KAAK;AACvB,MAAK,UAAU;AACf,QAAO;;AAGT,SAAS,4BAA4B,KAAmB,UAAgC;AACtF,QAAO,qBAAqB,kBAAkB,KAAK,SAAS,CAAC;;AAG/D,SAAS,iCACP,SACA,cACc;AACd,KAAK,QAA+B,SAAS,aAC3C,QAAO;CAET,MAAM,aAAa;CACnB,MAAM,cAAe,WAAsC;CAC3D,MAAM,qBAAqB,wBAAwB,YAAY;AAC/D,KAAI,oBAAoB;AACtB,MAAI,gBAAgB,mBAClB,QAAO;AAET,SAAO;GAAE,GAAG;GAAY,UAAU;GAAoB;;CAGxD,MAAM,qBAAqB,wBAAwB,aAAa;AAChE,KAAI,mBACF,QAAO;EAAE,GAAG;EAAY,UAAU;EAAoB;AAGxD,KAAI,OAAO,gBAAgB,SACzB,QAAO;EAAE,GAAG;EAAY,UAAU;EAAW;AAE/C,QAAO;;AAKT,MAAM,qBAAqB,OAAO,gCAAgC;AAMlE,SAAS,uBACP,gBACiC;CACjC,MAAM,SAAS;CACf,MAAM,SAAS,OAAO;AACtB,KAAI,OACF,QAAO;CAET,MAAM,WAAW,eAAe,cAAc,KAAK,eAAe;AAClE,QAAO,sBAAsB;AAC7B,QAAO;;AAOT,IAAM,yBAAN,MAA6B;CAC3B,0BAA2B,IAAI,KAAiC;CAEhE,OAAe;AACb,SAAO,KAAK,QAAQ;;CAGtB,YAAY,IAAgC;AAC1C,SAAO,KAAK,QAAQ,IAAI,GAAG;;CAG7B,OAAO,IAAkB;AACvB,OAAK,QAAQ,OAAO,GAAG;;CAGzB,QAAc;AACZ,OAAK,QAAQ,OAAO;;CAGtB,eAAe,OAAyC;AACtD,OAAK,MAAM,QAAQ,MACjB,MAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,KAAK;;CAIxC,UAA0D;AACxD,SAAO,KAAK,QAAQ,SAAS;;CAG/B,gBAA0B;AACxB,SAAO,MAAM,KAAK,KAAK,QAAQ,MAAM,CAAC;;CAGxC,8BAAuC;AACrC,SAAO,KAAK,QAAQ,OAAO;;CAG7B,+BAA+B,UAAmB,eAAgC;AAChF,SAAO,KAAK,QAAQ,OAAO,MAAM,kBAAkB,KAAK,aAAa;;CAGvE,8BAA8B,eAAgC;AAC5D,SAAO,KAAK,QAAQ,OAAO,KAAK,gBAAgB;;;AAMpD,IAAM,kBAAN,MAAsB;CACpB;CACA;CACA,UAA2B,IAAI,wBAAwB;CACvD;CACA;CACA;CAEA,YAAY,gBAAgC,MAA8B;AACxE,OAAK,iBAAiB;AACtB,OAAK,OAAO;AACZ,OAAK,iBAAiB,uBAAuB,eAAe;AAC5D,OAAK,4BAA4B,KAAK,6BAA6B;AACnE,OAAK,qBAAqB,0BAA0B,KAAK;;;CAI3D,SAAe;EACb,MAAM,QAAQ,KAAK,cAAc,KAAK,KAAK;AAC3C,OAAK,eAAe,gBAAgB;;CAGtC,eAAqB;AACnB,MAAI,KAAK,QAAQ,MAAM,KAAK,EAC1B;AAEF,MAAI,KAAK,0BACP,MAAK,MAAM,CAAC,IAAI,SAAS,KAAK,QAAQ,SAAS,EAAE;GAC/C,MAAM,YAAY,sBAAsB;IACtC,YAAY;IACZ,UAAU;IACV,MAAM,KAAK,KAAK;IACjB,CAAC;GACF,MAAM,UAAU,KAAK,qBACnB,KAAK,kBAAkB,KAAK,eAAe,UAAU,EAAE;IACrD,YAAY;IACZ,UAAU;IACV,aAAa;IACd,CAAC,CACH;AACD,OAAI,QACF,MAAK,eAAe,4BAA4B,SAAS,KAAK,mBAAmB,CAAU;;AAIjG,OAAK,QAAQ,OAAO;;CAGtB,eAAqB;AACnB,OAAK,QAAQ,OAAO;;CAGtB,gBAA0B;AACxB,SAAO,KAAK,QAAQ,eAAe;;CAGrC,eAAuB,SAAqC;EAC1D,MAAM,cAAc,KAAK,KAAK;AAC9B,SAAO,cAAc,YAAY,QAAQ,GAAG;;CAG9C,kBACE,SACA,MACc;EACd,MAAM,cAAc,KAAK,KAAK;AAC9B,SAAO,cAAc,YAAY,SAAS,KAAK,GAAG;;;;;;CAOpD,qBAA6B,KAAwC;EACnE,MAAM,cAAc,KAAK,KAAK;AAC9B,MAAI,CAAC,YACH,QAAO;EAET,MAAM,SAAS,YAAY,EAAE,SAAS,KAAK,CAAC;AAC5C,MAAI,QAAQ,MACV,QAAO;AAET,MAAI,QAAQ,QACV,QAAO,OAAO;AAEhB,SAAO;;CAGT,cAAsB,SAAgC;EACpD,IAAI,cAAc;AAElB,MADc,QAA+B,SAChC,aAAa;GACxB,MAAM,YAAY,uBAAuB,CAAC,QAAQ,EAAE,EAClD,kBAAkB,KAAK,KAAK,kBAC7B,CAAC;AACF,OAAI,UAAU,WAAW,GAAG;AAC1B,QAAI,KAAK,QAAQ,6BAA6B,CAC5C,MAAK,cAAc;AAErB;;AAEF,iBAAc,UAAU;;EAE1B,MAAM,WAAY,YAAmC;AAErD,MAAI,aAAa,cAAc;GAC7B,MAAM,KAAK,oBAAoB,YAA6D;GAC5F,MAAM,WAAW,KAAK,KAAK,QAAQ,YAAY,GAAG,GAAG,KAAA;AACrD,OAAI,GACF,MAAK,QAAQ,OAAO,GAAG;GAEzB,MAAM,uBAAuB,iCAAiC,aAAa,SAAS;GAGpF,MAAM,SAAS,4BACb,KAAK,eAAe,qBAAqB,EACzC,KAAK,mBACN;GACD,MAAM,YAAY,KAAK,qBACrB,KAAK,kBAAkB,QAAQ;IAC7B,YAAY,MAAM,KAAA;IAClB;IACA,aAAa;IACd,CAAC,CACH;AACD,OAAI,CAAC,UACH;AAEF,UAAO,KAAK,eAAe,4BAA4B,WAAW,KAAK,mBAAmB,CAAU;;EAStG,MAAM,aAAc,YAAwC;EAC5D,MAAM,YACJ,aAAa,eAAe,eAAe,aAAa,eAAe,UACnE,8BAA8B,YAA4D,GAC1F,EAAE;AAQR,MAAI,KAAK,QAAQ,+BAA+B,UAAU,UAAU,OAAO,CACzE,MAAK,cAAc;AAGrB,MAAI,KAAK,QAAQ,8BAA8B,UAAU,OAAO,CAC9D,MAAK,cAAc;EAGrB,MAAM,eAAe,KAAK,qBAAqB,KAAK,eAAe,YAAY,CAAC;AAChF,MAAI,CAAC,aACH;EAEF,MAAM,SAAS,KAAK,eAAe,aAAsB;AAEzD,MAAI,KAAK,KAAK,WACZ,6BAA4B;GAC1B,YAAY,KAAK,KAAK;GACtB,SAAS;GACT,WAAW,OAAO,WAAW,WAAW,SAAS,KAAA;GAClD,CAAC;AAGJ,MAAI,UAAU,SAAS,EACrB,MAAK,QAAQ,eAAe,UAAU;AAGxC,SAAO"}
|
|
1
|
+
{"version":3,"file":"session-tool-result-guard.js","names":[],"sources":["../../../../src/agent/embedded/session-tool-result-guard.ts"],"sourcesContent":["/**\n * Session tool-result guard — wraps a pi `SessionManager.appendMessage` to:\n * 1. cap oversized tool-result text + details so they cannot blow up the next\n * LLM request (size + persistence limits).\n * 2. track pending tool-call IDs so missing tool results can be synthesised\n * (some providers refuse a turn that has an orphan tool_use block).\n * 3. drop assistant `toolCall` blocks whose tool name is not in the allowlist\n * (these would also trigger provider 400s).\n * 4. broadcast `xopc:transcript-row` updates so the gateway UI can stream them.\n *\n * Previously this module shipped with three sibling files\n * (`session-tool-result-state.ts`, `session-raw-append-message.ts`,\n * `session-tool-result-guard-wrapper.ts`). They are now consolidated here as\n * private constructs around the `ToolResultGuard` class. Pi-coding-agent owns\n * the `SessionManager` instance and calls `appendMessage` from inside the\n * runtime, so we still need to monkey-patch that method — but the patched\n * implementation is just `guard.guardedAppend.bind(guard)` and all state lives\n * on the class.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { SessionManager } from '@earendil-works/pi-coding-agent';\n\nimport type { Config } from '../../config/schema.js';\nimport {\n boundedJsonUtf8Bytes,\n firstEnumerableOwnKeys,\n jsonUtf8BytesOrInfinity,\n type BoundedJsonUtf8Bytes,\n} from '../../infra/json-utf8-bytes.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { normalizeOptionalString } from '../../utils/string-coerce.js';\nimport { formatContextLimitTruncationNotice } from './tool-result-context-guard.js';\nimport {\n DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS,\n resolveLiveToolResultMaxChars,\n truncateToolResultMessage,\n} from './tool-result-truncation.js';\nimport {\n makeMissingToolResult,\n sanitizeToolCallInputs,\n} from '../transcript/session-transcript-repair.js';\nimport {\n extractToolCallsFromAssistant,\n extractToolResultId,\n} from '../transcript/tool-call-id.js';\n\n// ── Public surface ──────────────────────────────────────────────────────────\n\nexport type BeforeMessageWriteHookEvent = { message: AgentMessage };\nexport type BeforeMessageWriteHookResult =\n | { block?: boolean; message?: AgentMessage }\n | undefined;\n\nexport interface ToolResultGuardOptions {\n /** Optional session key for transcript update broadcasts. */\n sessionKey?: string;\n /** Optional transform applied to any message before persistence. */\n transformMessageForPersistence?: (message: AgentMessage) => AgentMessage;\n /**\n * Optional, synchronous transform applied to toolResult messages *before* they are\n * persisted to the session transcript.\n */\n transformToolResultForPersistence?: (\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ) => AgentMessage;\n /**\n * Whether to synthesize missing tool results to satisfy strict providers.\n * Defaults to true.\n */\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n /**\n * Optional set/list of tool names accepted for assistant toolCall/toolUse blocks.\n * When set, tool calls with unknown names are dropped before persistence.\n */\n allowedToolNames?: Iterable<string>;\n /**\n * Synchronous hook invoked before any message is written to the session JSONL.\n * If the hook returns { block: true }, the message is silently dropped.\n * If it returns { message }, the modified message is written instead.\n */\n beforeMessageWriteHook?: (event: BeforeMessageWriteHookEvent) => BeforeMessageWriteHookResult;\n maxToolResultChars?: number;\n}\n\nexport interface InstallSessionToolResultGuardResult {\n flushPendingToolResults: () => void;\n clearPendingToolResults: () => void;\n getPendingIds: () => string[];\n}\n\n/** Idempotent wrapper that also adds the helper methods consumers expect. */\nexport type GuardedPiTranscriptManager = SessionManager & {\n flushPendingToolResults?: () => void;\n clearPendingToolResults?: () => void;\n};\n\n/**\n * Install the guard on a SessionManager and return its control API.\n * Subsequent assistant/toolResult writes by pi-coding-agent flow through the\n * guard transparently.\n */\nexport function installSessionToolResultGuard(\n sessionManager: SessionManager,\n opts: ToolResultGuardOptions = {},\n): InstallSessionToolResultGuardResult {\n const guard = new ToolResultGuard(sessionManager, opts);\n guard.attach();\n return {\n flushPendingToolResults: () => guard.flushPending(),\n clearPendingToolResults: () => guard.clearPending(),\n getPendingIds: () => guard.getPendingIds(),\n };\n}\n\n/**\n * Convenience wrapper used by the embedded runner pool: install the guard\n * (idempotent), pin the size cap from the model context window, and expose\n * `flushPendingToolResults` / `clearPendingToolResults` directly on the\n * SessionManager instance so callers do not need to keep the install result.\n */\nexport function guardSessionManager(\n sessionManager: SessionManager,\n opts?: {\n agentId?: string;\n sessionKey?: string;\n config?: Config;\n contextWindowTokens?: number;\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n allowedToolNames?: Iterable<string>;\n transformMessageForPersistence?: (message: AgentMessage) => AgentMessage;\n },\n): GuardedPiTranscriptManager {\n if (typeof (sessionManager as GuardedPiTranscriptManager).flushPendingToolResults === 'function') {\n return sessionManager as GuardedPiTranscriptManager;\n }\n\n const result = installSessionToolResultGuard(sessionManager, {\n sessionKey: opts?.sessionKey,\n transformMessageForPersistence: opts?.transformMessageForPersistence,\n allowSyntheticToolResults: opts?.allowSyntheticToolResults,\n missingToolResultText: opts?.missingToolResultText,\n allowedToolNames: opts?.allowedToolNames,\n maxToolResultChars:\n typeof opts?.contextWindowTokens === 'number'\n ? resolveLiveToolResultMaxChars({\n contextWindowTokens: opts.contextWindowTokens,\n cfg: opts?.config,\n agentId: opts?.agentId,\n })\n : undefined,\n });\n const tagged = sessionManager as GuardedPiTranscriptManager;\n tagged.flushPendingToolResults = result.flushPendingToolResults;\n tagged.clearPendingToolResults = result.clearPendingToolResults;\n return tagged;\n}\n\n/**\n * Recover the original (un-guarded) appendMessage for a session manager.\n * Useful for callers that need a low-level \"bypass the guard\" write path.\n */\nexport function getRawSessionAppendMessage(\n sessionManager: SessionManager,\n): SessionManager['appendMessage'] {\n const stored = (sessionManager as SessionManagerWithRawAppend)[RAW_APPEND_MESSAGE];\n return stored ?? sessionManager.appendMessage.bind(sessionManager);\n}\n\n// ── Internal: persistence + truncation helpers ──────────────────────────────\n\nfunction resolveMaxToolResultChars(opts: { maxToolResultChars?: number }): number {\n return Math.max(1, opts.maxToolResultChars ?? DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS);\n}\n\nfunction capToolResultSize(msg: AgentMessage, maxChars: number): AgentMessage {\n if ((msg as { role?: string }).role !== 'toolResult') {\n return msg;\n }\n return truncateToolResultMessage(msg, maxChars, {\n suffix: (truncatedChars) => formatContextLimitTruncationNotice(truncatedChars),\n minKeepChars: 2_000,\n });\n}\n\n// `details` is runtime/UI metadata, not model-visible tool output. Keep the\n// session JSONL useful for debugging without letting metadata blobs dominate\n// disk, replay repair, transcript broadcasts, or future tooling that reads raw\n// sessions. Model-visible text belongs in tool result `content`.\nconst MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES = 8_192;\nconst MAX_PERSISTED_DETAIL_STRING_CHARS = 2_000;\nconst MAX_PERSISTED_DETAIL_SESSION_COUNT = 10;\nconst MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS = 200;\n\nfunction originalDetailsSizeFields(size: BoundedJsonUtf8Bytes): Record<string, number> {\n return size.complete\n ? { originalDetailsBytes: size.bytes }\n : { originalDetailsBytesAtLeast: size.bytes };\n}\n\nfunction truncatePersistedDetailString(\n value: string,\n maxChars = MAX_PERSISTED_DETAIL_STRING_CHARS,\n): string {\n if (value.length <= maxChars) {\n return value;\n }\n return `${value.slice(0, maxChars)}\\n\\n[xopc persisted detail truncated: ${\n value.length - maxChars\n } chars omitted]`;\n}\n\nfunction sanitizePersistedSessionDetail(value: unknown): unknown {\n if (!value || typeof value !== 'object') {\n return value;\n }\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of [\n 'sessionId',\n 'status',\n 'pid',\n 'startedAt',\n 'endedAt',\n 'runtimeMs',\n 'cwd',\n 'name',\n 'truncated',\n 'exitCode',\n 'exitSignal',\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === 'string' ? truncatePersistedDetailString(field, 500) : field;\n }\n }\n if (typeof src.command === 'string') {\n out.command = truncatePersistedDetailString(src.command, 500);\n }\n return out;\n}\n\nfunction buildPersistedDetailsFallback(\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n sanitizedBytes?: number,\n): Record<string, unknown> {\n const fallback: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n };\n if (sanitizedBytes !== undefined) {\n fallback.sanitizedDetailsBytes = sanitizedBytes;\n }\n if (src) {\n fallback.originalDetailKeys = firstEnumerableOwnKeys(src, 40);\n for (const key of ['status', 'sessionId', 'pid', 'exitCode', 'exitSignal', 'truncated']) {\n const field = src[key];\n if (field !== undefined) {\n fallback[key] =\n typeof field === 'string'\n ? truncatePersistedDetailString(field, MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS)\n : field;\n }\n }\n }\n return fallback;\n}\n\nfunction enforcePersistedDetailsByteCap(\n value: Record<string, unknown>,\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n): Record<string, unknown> {\n const sanitizedBytes = jsonUtf8BytesOrInfinity(value);\n if (sanitizedBytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return value;\n }\n const fallback = buildPersistedDetailsFallback(src, originalSize, sanitizedBytes);\n if (jsonUtf8BytesOrInfinity(fallback) <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return fallback;\n }\n return {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n sanitizedDetailsBytes: sanitizedBytes,\n };\n}\n\nfunction sanitizeToolResultDetailsForPersistence(details: unknown): unknown {\n if (details === undefined || details === null) {\n return details;\n }\n const originalSize = boundedJsonUtf8Bytes(details, MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES);\n if (originalSize.complete && originalSize.bytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return details;\n }\n if (typeof details !== 'object') {\n return enforcePersistedDetailsByteCap(\n {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n valueType: typeof details,\n },\n undefined,\n originalSize,\n );\n }\n const src = details as Record<string, unknown>;\n const out: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n originalDetailKeys: firstEnumerableOwnKeys(src, 40),\n };\n for (const key of [\n 'status',\n 'sessionId',\n 'pid',\n 'startedAt',\n 'endedAt',\n 'cwd',\n 'name',\n 'exitCode',\n 'exitSignal',\n 'retryInMs',\n 'total',\n 'totalLines',\n 'totalChars',\n 'truncated',\n 'fullOutputPath',\n 'truncation',\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === 'string' ? truncatePersistedDetailString(field) : field;\n }\n }\n if (typeof src.tail === 'string') {\n out.tail = truncatePersistedDetailString(src.tail);\n }\n if (Array.isArray(src.sessions)) {\n out.sessions = src.sessions\n .slice(0, MAX_PERSISTED_DETAIL_SESSION_COUNT)\n .map(sanitizePersistedSessionDetail);\n if (src.sessions.length > MAX_PERSISTED_DETAIL_SESSION_COUNT) {\n out.sessionsTruncated = src.sessions.length - MAX_PERSISTED_DETAIL_SESSION_COUNT;\n }\n }\n return enforcePersistedDetailsByteCap(out, src, originalSize);\n}\n\nfunction capToolResultDetails(msg: AgentMessage): AgentMessage {\n if ((msg as { role?: string }).role !== 'toolResult') {\n return msg;\n }\n const details = (msg as { details?: unknown }).details;\n const sanitizedDetails = sanitizeToolResultDetailsForPersistence(details);\n if (sanitizedDetails === details) {\n return msg;\n }\n const next = { ...msg } as AgentMessage & { details?: unknown };\n next.details = sanitizedDetails;\n return next;\n}\n\nfunction capToolResultForPersistence(msg: AgentMessage, maxChars: number): AgentMessage {\n return capToolResultDetails(capToolResultSize(msg, maxChars));\n}\n\nfunction normalizePersistedToolResultName(\n message: AgentMessage,\n fallbackName?: string,\n): AgentMessage {\n if ((message as { role?: unknown }).role !== 'toolResult') {\n return message;\n }\n const toolResult = message as Extract<AgentMessage, { role: 'toolResult' }>;\n const rawToolName = (toolResult as { toolName?: unknown }).toolName;\n const normalizedToolName = normalizeOptionalString(rawToolName);\n if (normalizedToolName) {\n if (rawToolName === normalizedToolName) {\n return toolResult;\n }\n return { ...toolResult, toolName: normalizedToolName };\n }\n\n const normalizedFallback = normalizeOptionalString(fallbackName);\n if (normalizedFallback) {\n return { ...toolResult, toolName: normalizedFallback };\n }\n\n if (typeof rawToolName === 'string') {\n return { ...toolResult, toolName: 'unknown' };\n }\n return toolResult;\n}\n\n// ── Internal: raw-append symbol storage ─────────────────────────────────────\n\nconst RAW_APPEND_MESSAGE = Symbol('xopc.session.rawAppendMessage');\n\ntype SessionManagerWithRawAppend = SessionManager & {\n [RAW_APPEND_MESSAGE]?: SessionManager['appendMessage'];\n};\n\nfunction rememberOriginalAppend(\n sessionManager: SessionManager,\n): SessionManager['appendMessage'] {\n const tagged = sessionManager as SessionManagerWithRawAppend;\n const stored = tagged[RAW_APPEND_MESSAGE];\n if (stored) {\n return stored;\n }\n const original = sessionManager.appendMessage.bind(sessionManager);\n tagged[RAW_APPEND_MESSAGE] = original;\n return original;\n}\n\n// ── Internal: pending tool-call state ──────────────────────────────────────\n\ntype PendingToolCall = { id: string; name?: string };\n\nclass PendingToolCallTracker {\n private readonly pending = new Map<string, string | undefined>();\n\n size(): number {\n return this.pending.size;\n }\n\n getToolName(id: string): string | undefined {\n return this.pending.get(id);\n }\n\n delete(id: string): void {\n this.pending.delete(id);\n }\n\n clear(): void {\n this.pending.clear();\n }\n\n trackToolCalls(calls: readonly PendingToolCall[]): void {\n for (const call of calls) {\n this.pending.set(call.id, call.name);\n }\n }\n\n entries(): IterableIterator<[string, string | undefined]> {\n return this.pending.entries();\n }\n\n getPendingIds(): string[] {\n return Array.from(this.pending.keys());\n }\n\n shouldFlushForSanitizedDrop(): boolean {\n return this.pending.size > 0;\n }\n\n shouldFlushBeforeNonToolResult(nextRole: unknown, toolCallCount: number): boolean {\n return this.pending.size > 0 && (toolCallCount === 0 || nextRole !== 'assistant');\n }\n\n shouldFlushBeforeNewToolCalls(toolCallCount: number): boolean {\n return this.pending.size > 0 && toolCallCount > 0;\n }\n}\n\n// ── ToolResultGuard class ──────────────────────────────────────────────────\n\nclass ToolResultGuard {\n private readonly sessionManager: SessionManager;\n private readonly opts: ToolResultGuardOptions;\n private readonly pending = new PendingToolCallTracker();\n private readonly originalAppend: SessionManager['appendMessage'];\n private readonly allowSyntheticToolResults: boolean;\n private readonly maxToolResultChars: number;\n\n constructor(sessionManager: SessionManager, opts: ToolResultGuardOptions) {\n this.sessionManager = sessionManager;\n this.opts = opts;\n this.originalAppend = rememberOriginalAppend(sessionManager);\n this.allowSyntheticToolResults = opts.allowSyntheticToolResults ?? true;\n this.maxToolResultChars = resolveMaxToolResultChars(opts);\n }\n\n /** Monkey-patch the session manager so pi-coding-agent's internal appendMessage flows through us. */\n attach(): void {\n const bound = this.guardedAppend.bind(this);\n this.sessionManager.appendMessage = bound as SessionManager['appendMessage'];\n }\n\n flushPending(): void {\n if (this.pending.size() === 0) {\n return;\n }\n if (this.allowSyntheticToolResults) {\n for (const [id, name] of this.pending.entries()) {\n const synthetic = makeMissingToolResult({\n toolCallId: id,\n toolName: name,\n text: this.opts.missingToolResultText,\n });\n const flushed = this.applyBeforeWriteHook(\n this.persistToolResult(this.persistMessage(synthetic), {\n toolCallId: id,\n toolName: name,\n isSynthetic: true,\n }),\n );\n if (flushed) {\n this.originalAppend(capToolResultForPersistence(flushed, this.maxToolResultChars) as never);\n }\n }\n }\n this.pending.clear();\n }\n\n clearPending(): void {\n this.pending.clear();\n }\n\n getPendingIds(): string[] {\n return this.pending.getPendingIds();\n }\n\n private persistMessage(message: AgentMessage): AgentMessage {\n const transformer = this.opts.transformMessageForPersistence;\n return transformer ? transformer(message) : message;\n }\n\n private persistToolResult(\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ): AgentMessage {\n const transformer = this.opts.transformToolResultForPersistence;\n return transformer ? transformer(message, meta) : message;\n }\n\n /**\n * Run the before_message_write hook. Returns the (possibly modified) message,\n * or null if the message should be blocked.\n */\n private applyBeforeWriteHook(msg: AgentMessage): AgentMessage | null {\n const beforeWrite = this.opts.beforeMessageWriteHook;\n if (!beforeWrite) {\n return msg;\n }\n const result = beforeWrite({ message: msg });\n if (result?.block) {\n return null;\n }\n if (result?.message) {\n return result.message;\n }\n return msg;\n }\n\n private guardedAppend(message: AgentMessage): unknown {\n let nextMessage = message;\n const role = (message as { role?: unknown }).role;\n if (role === 'assistant') {\n const sanitized = sanitizeToolCallInputs([message], {\n allowedToolNames: this.opts.allowedToolNames,\n });\n if (sanitized.length === 0) {\n if (this.pending.shouldFlushForSanitizedDrop()) {\n this.flushPending();\n }\n return undefined;\n }\n nextMessage = sanitized[0];\n }\n const nextRole = (nextMessage as { role?: unknown }).role;\n\n if (nextRole === 'toolResult') {\n const id = extractToolResultId(nextMessage as Extract<AgentMessage, { role: 'toolResult' }>);\n const toolName = id ? this.pending.getToolName(id) : undefined;\n if (id) {\n this.pending.delete(id);\n }\n const normalizedToolResult = normalizePersistedToolResultName(nextMessage, toolName);\n // Apply hard size cap before persistence to prevent oversized tool results\n // from consuming the entire context window on subsequent LLM calls.\n const capped = capToolResultForPersistence(\n this.persistMessage(normalizedToolResult),\n this.maxToolResultChars,\n );\n const persisted = this.applyBeforeWriteHook(\n this.persistToolResult(capped, {\n toolCallId: id ?? undefined,\n toolName,\n isSynthetic: false,\n }),\n );\n if (!persisted) {\n return undefined;\n }\n const finalToolResult = capToolResultForPersistence(persisted, this.maxToolResultChars);\n const result = this.originalAppend(finalToolResult as never);\n\n if (this.opts.sessionKey) {\n emitSessionTranscriptUpdate({\n sessionKey: this.opts.sessionKey,\n message: finalToolResult,\n messageId: typeof result === 'string' ? result : undefined,\n });\n }\n\n return result;\n }\n\n // Skip tool call extraction for aborted/errored assistant messages.\n // When stopReason is \"error\" or \"aborted\", the tool_use blocks may be incomplete\n // and should not have synthetic tool_results created. Creating synthetic results\n // for incomplete tool calls causes API 400 errors:\n // \"unexpected tool_use_id found in tool_result blocks\"\n // This matches the behavior in repairToolUseResultPairing (session-transcript-repair.ts)\n const stopReason = (nextMessage as { stopReason?: string }).stopReason;\n const toolCalls =\n nextRole === 'assistant' && stopReason !== 'aborted' && stopReason !== 'error'\n ? extractToolCallsFromAssistant(nextMessage as Extract<AgentMessage, { role: 'assistant' }>)\n : [];\n\n // Always clear pending tool call state before appending non-tool-result messages.\n // flushPendingToolResults() only inserts synthetic results when allowSyntheticToolResults\n // is true; it always clears the pending map. Without this, providers that disable\n // synthetic results (e.g. OpenAI) accumulate stale pending state when a user message\n // interrupts in-flight tool calls, leaving orphaned tool_use blocks in the transcript\n // that cause API 400 errors on subsequent requests.\n if (this.pending.shouldFlushBeforeNonToolResult(nextRole, toolCalls.length)) {\n this.flushPending();\n }\n // If new tool calls arrive while older ones are pending, flush the old ones first.\n if (this.pending.shouldFlushBeforeNewToolCalls(toolCalls.length)) {\n this.flushPending();\n }\n\n const finalMessage = this.applyBeforeWriteHook(this.persistMessage(nextMessage));\n if (!finalMessage) {\n return undefined;\n }\n const result = this.originalAppend(finalMessage as never);\n\n if (this.opts.sessionKey) {\n emitSessionTranscriptUpdate({\n sessionKey: this.opts.sessionKey,\n message: finalMessage,\n messageId: typeof result === 'string' ? result : undefined,\n });\n }\n\n if (toolCalls.length > 0) {\n this.pending.trackToolCalls(toolCalls);\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@ init_providers();
|
|
|
8
8
|
const GOAL_TRUNC = 4e3;
|
|
9
9
|
const RESPONSE_SNIPPET = 4e3;
|
|
10
10
|
const HISTORY_TRUNC = 24e3;
|
|
11
|
-
const DECOMPOSE_SYSTEM = "You break a user goal into an EXTREMELY detailed checklist of concrete, verifiable completion criteria. Bias toward more items. Each item is one factual statement about finished work.\n\nReply ONLY with a single JSON object on one line:\n{\"items\":[{\"text\":\"...\"},...]}\nUse at least 3 items when the goal warrants it.";
|
|
11
|
+
const DECOMPOSE_SYSTEM = "You break a user goal into an EXTREMELY detailed checklist of concrete, verifiable completion criteria. Bias toward more items. Each item is one factual statement about finished work.\n\nIf existing acceptance criteria are provided, return only missing supplemental criteria. Do not repeat, rewrite, or replace existing criteria.\n\nReply ONLY with a single JSON object on one line:\n{\"items\":[{\"text\":\"...\"},...]}\nUse at least 3 items when the goal warrants it.";
|
|
12
12
|
const DECOMPOSE_USER = "Goal:\n{goal}\n\nReturn JSON only.";
|
|
13
13
|
const EVALUATE_CHECKLIST_SYSTEM = "You evaluate an autonomous agent's progress on a goal with a numbered checklist.\nFor each pending item, decide if evidence in the agent snippet and/or history excerpt shows it is satisfied.\nFlip pending→completed only with clear evidence; pending→impossible only if truly unachievable here.\nDo not regress completed/impossible items — omit them from updates.\n\nReply ONLY with one JSON object on one line:\n{\"verdict\":\"continue|done|blocked|needs_input\",\"confidence\":0.0,\"reason\":\"...\",\"nextAction\":\"...\",\"missingEvidence\":[\"...\"],\"userQuestion\":\"...\",\"updates\":[{\"index\":1,\"status\":\"completed|impossible\",\"evidence\":\"short citation\"}],\"new_items\":[{\"text\":\"...\"}]}\nUse verdict=done only when all checklist criteria are complete/impossible. Use needs_input when the next step requires user input. Use blocked when external progress is impossible.";
|
|
14
14
|
function extractJsonObject(raw) {
|
|
@@ -52,9 +52,10 @@ async function decomposeGoalChecklist(opts) {
|
|
|
52
52
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
53
53
|
const merged = opts.signal ? AbortSignal.any([opts.signal, controller.signal]) : controller.signal;
|
|
54
54
|
try {
|
|
55
|
+
const existingChecklist = opts.existingChecklist?.trim();
|
|
55
56
|
const user = {
|
|
56
57
|
role: "user",
|
|
57
|
-
content: `${DECOMPOSE_SYSTEM}\n\n${DECOMPOSE_USER.replace("{goal}", truncateGoalText(goal, GOAL_TRUNC))}` + judgeResponseLanguageNote(locale),
|
|
58
|
+
content: `${DECOMPOSE_SYSTEM}\n\n${DECOMPOSE_USER.replace("{goal}", truncateGoalText(goal, GOAL_TRUNC)) + (existingChecklist ? `\n\nExisting acceptance criteria:\n${truncateGoalText(existingChecklist, GOAL_TRUNC)}\n\nReturn only missing supplemental criteria as JSON.` : "")}` + judgeResponseLanguageNote(locale),
|
|
58
59
|
timestamp: Date.now()
|
|
59
60
|
};
|
|
60
61
|
const apiKey = await resolveGoalJudgeApiKey(model);
|