@xopcai/xopc 0.0.140 → 0.0.142
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/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DtONoxBN.js → agent-avatar-dicebear-BawPxiu5.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CyvCIHnB.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BRBxLECY.js → app-management-settings-panel-81xd1p9R.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-ChvyuSEt.js → appearance-settings-DYeQsYU8.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DgHWTnjs.js → apps-page-DK_Vx6nl.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-CdIoagem.js → archive-plugin-D_oa7oti.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Ch411Kht.js → attachment-load-Cd-bwI2N.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-SVq27yw2.js → automation-suggestion-card-B1LV3YYv.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-fzrovqhv.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-D8cV-emn.js → binary-plugins-O8svLKWw.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CXDkby6y.js → block-editor-Dhj5f4Bx.js} +47 -47
- package/dist/gateway/static/root/assets/browser-settings-page-BDn-n-UB.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-DLxI--Ge.js → capability-presets-api-dJy1Eqgx.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-DKyRbnlH.js → capability-presets-settings-panel-Co5ipo_Q.js} +1 -1
- package/dist/gateway/static/root/assets/{channel-recipient-api-DllrPmp-.js → channel-recipient-api-Bfuhp2ty.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BWlpaxg9.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-D_jkIZLV.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BcekbW4q.js +2 -0
- package/dist/gateway/static/root/assets/{desktop-pet-Bz9ommjr.js → desktop-pet-DFMfIb5F.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BnLgxgoR.js → desktop-pet-settings-BJCUuL8Y.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DLsCwFaf.js → directory-picker-path-field-BrYt1gAr.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-BzkF1-XT.js → dreaming-settings-BN1Z2mIo.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-CdERvf3L.js → extension-debug-page-Bh630pLD.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D1fz474Z.js → extension-page-B-1KxvVy.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DoQMkNOK.js → extension-settings-page-BF9NACI3.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-BID89uCH.js → fetch-B1WtuprY.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Rygo8UAs.js → gateway-config-api-De2N821l.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-kb8KIeQL.js → gateway-settings-DN9sNREz.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BkrLLlpE.js → gateway-startup-retry-nEujFSDj.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BpoQW8cD.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-CBRSPd0b.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-BuY6-l0a.js → goals-config-api-DUy3eEse.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BCcBi407.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DoH5fZWo.js → goals-settings-pkTXzXkh.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BqDs48B-.js → heartbeat-settings-ezsufgLQ.js} +1 -1
- package/dist/gateway/static/root/assets/{index-CrPRlGMg.js → index-DcUaXYeb.js} +65 -65
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CVIwwM15.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-DQtTRXtj.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-CSt32FWE.js → markdown-split-B_6us9j7.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-ByItHxBj.js → media-plugins-D_fryIyj.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BXNELNBa.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BP2M9n6Q.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CspveYaO.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-BHwzJ0OC.js +2 -0
- package/dist/gateway/static/root/assets/{page-tabs-DOfMaq_L.js → page-tabs-D_8jGlqx.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BArxASu7.js → preview-open-alternatives-BBLMK8Mp.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-Dy3rsobs.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-CWKpPE0L.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CqNRyXEo.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BRxlkhG8.js → save-bar-controls-DVS3FR5r.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-BzM1iyOc.js → schedule-field-D6vKd6-T.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-ChVcm0DX.js → schema-form-BPy4lbIh.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-MEME7ivF.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-JVd0qaSF.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BcD9xrvY.js → settings-collapsible-section-WzdikxPt.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Cu30CXVl.js → settings-form-section-CvfzhBV-.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-Cfd37IYb.js → settings-loading-skeleton-BxR-Ulhi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-EINHyzLo.js → settings-page-DYEbB1EV.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-C15zixct.js → settings-page-layout-CKefvbYi.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Bu7SdpD4.js → setup-status-panel-dWN8BJ3z.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CjjAFV-v.js → share-preview-page-D8foINzP.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Tgbv1s7G.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-D_YK0b_Z.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DGytfoZK.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DlQMtzPf.js → system-settings-panel-BokgAgf7.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BS1BwExE.js → typed-models-lib-BwHlNL3L.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-EA4hfbsP.js → use-channel-catalog-DR11ap3A.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-B7RCdmSp.js → user-profile-settings-panel-8YtygcJp.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-BrhEgVaa.js → utils-BKUWB-TT.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-BVH71EFf.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-JeTE7XNM.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-CL_rnAUB.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-start-dialog-BZCY7N42.js → workflow-start-dialog-_u8Uc1ze.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-ixgk_y1l.js +18 -0
- package/dist/gateway/static/root/index.html +4 -4
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +13 -21
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/run-background-review.js +1 -0
- package/dist/src/agent/background-review/run-background-review.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.js +5 -5
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/xopc-auth-storage.d.ts +4 -3
- package/dist/src/agent/embedded/xopc-auth-storage.js +6 -6
- package/dist/src/agent/embedded/xopc-auth-storage.js.map +1 -1
- package/dist/src/agent/embedded/xopc-stream-bridge.js +1 -0
- package/dist/src/agent/embedded/xopc-stream-bridge.js.map +1 -1
- package/dist/src/agent/goals/checklist-judge.js +3 -3
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/judge.js +2 -2
- package/dist/src/agent/goals/judge.js.map +1 -1
- package/dist/src/agent/image/understanding/pi-ai-provider.js +2 -2
- package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
- package/dist/src/agent/memory/access-policy.d.ts +12 -0
- package/dist/src/agent/memory/access-policy.js +44 -0
- package/dist/src/agent/memory/access-policy.js.map +1 -0
- package/dist/src/agent/memory/builtin-provider.d.ts +4 -1
- package/dist/src/agent/memory/builtin-provider.js +51 -16
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/compaction.js +2 -2
- package/dist/src/agent/memory/compaction.js.map +1 -1
- package/dist/src/agent/memory/context/planner.d.ts +1 -0
- package/dist/src/agent/memory/context/planner.js +9 -5
- package/dist/src/agent/memory/context/planner.js.map +1 -1
- package/dist/src/agent/memory/create-memory-manager.d.ts +1 -1
- package/dist/src/agent/memory/create-memory-manager.js +8 -5
- package/dist/src/agent/memory/create-memory-manager.js.map +1 -1
- package/dist/src/agent/memory/dreaming/config.d.ts +2 -0
- package/dist/src/agent/memory/dreaming/config.js +13 -1
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +2 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +24 -3
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/light-sweep.js +184 -16
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.d.ts +30 -0
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.js +85 -0
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.js.map +1 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +4 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.js +76 -53
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +10 -0
- package/dist/src/agent/memory/dreaming/short-term-store.js +157 -79
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
- package/dist/src/agent/memory/manager.d.ts +7 -0
- package/dist/src/agent/memory/manager.js +31 -6
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.d.ts +1 -1
- package/dist/src/agent/memory/memory-config.js +3 -3
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/sensitivity.d.ts +3 -0
- package/dist/src/agent/memory/sensitivity.js +13 -0
- package/dist/src/agent/memory/sensitivity.js.map +1 -0
- package/dist/src/agent/memory/understanding/service.js +10 -14
- package/dist/src/agent/memory/understanding/service.js.map +1 -1
- package/dist/src/agent/memory/user-context-coordinator.d.ts +1 -0
- package/dist/src/agent/memory/user-context-coordinator.js +2 -0
- package/dist/src/agent/memory/user-context-coordinator.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +8 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/service/btw-query.d.ts +4 -0
- package/dist/src/agent/service/btw-query.js +94 -13
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +9 -1
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +3 -12
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.js +14 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +3 -0
- package/dist/src/agent/tools/memory-tool.js +6 -3
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/session-search-tool.js +2 -2
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/web-extract.js +2 -2
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent/workspace-runtime/registry.d.ts +6 -6
- package/dist/src/agent/workspace-runtime/registry.js +19 -12
- package/dist/src/agent/workspace-runtime/registry.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +4 -0
- package/dist/src/agent-manifest/schema.js +2 -1
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/agent-runtime/index.js +1 -1
- package/dist/src/agent-runtime/runtime-profile.js +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +2 -1
- package/dist/src/ai-assist/text-assist.js +10 -23
- package/dist/src/ai-assist/text-assist.js.map +1 -1
- package/dist/src/auth/credentials.js +5 -2
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/auth/oauth/github-copilot.d.ts +3 -4
- package/dist/src/auth/oauth/github-copilot.js +66 -2
- package/dist/src/auth/oauth/github-copilot.js.map +1 -0
- package/dist/src/auth/oauth/index.js +2 -2
- package/dist/src/automations/draft/automation-draft-service.js +3 -3
- package/dist/src/automations/draft/automation-draft-service.js.map +1 -1
- package/dist/src/chat-commands/builtins/review.js +22 -5
- package/dist/src/chat-commands/builtins/review.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +4 -0
- package/dist/src/config/schema.d.ts +4 -0
- package/dist/src/gateway/hono/lib/config-payload.d.ts +2 -0
- package/dist/src/gateway/hono/routes/dreaming.js +28 -21
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +16 -4
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -0
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/voice.js +2 -2
- package/dist/src/gateway/hono/routes/voice.js.map +1 -1
- package/dist/src/goals/goal-contract-draft.js +2 -2
- package/dist/src/goals/goal-contract-draft.js.map +1 -1
- package/dist/src/goals/goal-evidence-review.js +2 -2
- package/dist/src/goals/goal-evidence-review.js.map +1 -1
- package/dist/src/notes/service.js +2 -2
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/constants.d.ts +2 -0
- package/dist/src/providers/constants.js +11 -0
- package/dist/src/providers/constants.js.map +1 -0
- package/dist/src/providers/extension-stream-bridge.js +1 -0
- package/dist/src/providers/extension-stream-bridge.js.map +1 -1
- package/dist/src/providers/index.d.ts +3 -3
- package/dist/src/providers/index.js +5 -4
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-call.d.ts +17 -0
- package/dist/src/providers/model-call.js +60 -0
- package/dist/src/providers/model-call.js.map +1 -0
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/storage/sqlite/fts.d.ts +6 -0
- package/dist/src/storage/sqlite/fts.js +70 -1
- package/dist/src/storage/sqlite/fts.js.map +1 -1
- package/dist/src/storage/sqlite/memory-index-repository.js +16 -7
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +18 -0
- package/dist/src/storage/sqlite/memory-records-repository.js +55 -8
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/voice/tts/summarize.js +2 -2
- package/dist/src/voice/tts/summarize.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-service.js +2 -2
- package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -1
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/agents-Dl9EWnUh.js +0 -2
- package/dist/gateway/static/root/assets/automations-page-CFt5Ik4q.js +0 -4
- package/dist/gateway/static/root/assets/browser-settings-page-ColJPwer.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-BDLHV3Jx.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-EUwWYx8l.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CA752gY8.js +0 -2
- package/dist/gateway/static/root/assets/goal-create-dialog-DVAHnifk.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BuOEQZn_.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-WV4cHvD-.js +0 -2
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-D51yogNZ.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CL22jleU.js +0 -7
- package/dist/gateway/static/root/assets/messages-DbNQuFdA.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BkV9hDc-.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-BK9yydrL.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-Dd0v-hK2.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-DSPhB3do.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-C-fZk1f7.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BGaVc3t7.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DbnzgQOP.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CuDBoz5k.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-06IYvwDt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-0ODH0DXl.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-3W2-wDyO.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-BPn1ZEga.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-BQGTTsz1.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-na-N4jZ6.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-CjeVDs4h.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 AgentTool,\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 { resolveAgentHomeDir, 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, resolveUserProfilePath } from '../config/paths.js';\nimport { extractTextContent } from './context/workspace.js';\nimport { buildActiveProjectContextForPrompt } from './context/project-context.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 type {\n SkillInstallToolOptions,\n SkillInstallToolResult,\n} from './tools/skill-install-tool.js';\nimport {\n createAgentCapabilitySessionState,\n resolveAgentCapabilityCatalog,\n type AgentCapabilityCatalogEntry,\n type AgentCapabilitySessionState,\n} from './capabilities/index.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 { AutomationService } from '../automations/index.js';\nimport type { SessionStore } from '../session/store.js';\nimport type { NotesService } from '../notes/index.js';\nimport type { ProjectService } from '../projects/index.js';\nimport type { WorkItemService } from '../work-items/index.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, type SkillsLockFile } from './skills/hub-lock.js';\nimport { basename, join, 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 { UserContextCoordinator } from './memory/user-context-coordinator.js';\nimport type { UserContextPlan } from './memory/context/types.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 { resolveWorkspaceSkillsDir, resolveWorkspaceSkillsLockPath } from './skills/workspace-skills-dir.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 AutomationService for the `automation` tool. */\n getAutomationService?: () => AutomationService | undefined;\n /** Gateway: exposes first-class xopc product objects for the `xopc_use` tool. */\n getNotesService?: () => NotesService | undefined;\n getProjectService?: () => ProjectService | undefined;\n getWorkItemService?: () => WorkItemService | 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 /** Install a managed skill from an explicit source and refresh runtime state. */\n installSkillFromSource?: (opts: SkillInstallToolOptions) => Promise<SkillInstallToolResult>;\n /** Dynamic workspace verification context injected into the system prompt when edits are pending. */\n getSelfVerifyPromptContext?: (sessionKey: string, agentId?: string) => string;\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 /** Capability packs activated by explicit skills or UI entry points in this session. */\n activeCapabilities: Map<string, AgentCapabilitySessionState>;\n activeProjectContext?: string;\n activeSelfVerifyContext?: string;\n /** Declared env var names from skill_view; exec_command reads values from process.env at spawn time. */\n skillEnvPassthroughKeys: Set<string>;\n}\n\nexport interface PreparedSkillTurn {\n text: string;\n activatedCapabilityNames: 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\n private activeCapabilityNames(inst: AgentInstance | undefined): string[] {\n return inst ? [...inst.activeCapabilities.keys()] : [];\n }\n\n private buildActiveCapabilityContext(\n instance: AgentInstance,\n capabilityNames: readonly string[],\n registeredToolNames: readonly string[],\n ): string | undefined {\n const availableCatalog = this.resolveCapabilityCatalogForInstance(instance, registeredToolNames)\n .filter((definition) => definition.availableTools.length > 0);\n const definitionsById = new Map(availableCatalog.map((definition) => [definition.id, definition]));\n const definitions = [...new Set(capabilityNames)]\n .map((name) => definitionsById.get(name))\n .filter((definition): definition is AgentCapabilityCatalogEntry => Boolean(definition));\n if (definitions.length === 0) return undefined;\n const rows = definitions.map((definition) => {\n const tools = definition.availableTools.join(', ');\n const hint = definition.promptHint?.trim() ? `\\n Guidance: ${definition.promptHint.trim()}` : '';\n return `- ${definition.id} (${definition.label}): ${definition.description}\\n Tools: ${tools}${hint}`;\n });\n return [\n '# Active Capability Packs',\n '',\n 'These capability packs are active for the current task. Use their tools only when they directly help satisfy the user request.',\n '',\n ...rows,\n ].join('\\n');\n }\n\n private resolveCapabilityCatalogForInstance(\n instance: AgentInstance | undefined,\n registeredToolNames: readonly string[] = instance?.registeredToolNames ?? [],\n ): AgentCapabilityCatalogEntry[] {\n return resolveAgentCapabilityCatalog({\n registeredToolNames,\n lazyToolNames: this.toolsFactory.getLazyCapabilityToolNames(),\n deniedToolNames: instance ? [...instance.effectiveProfile.tools.denied] : [],\n });\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 userContext: UserContextCoordinator;\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.userContext = new UserContextCoordinator({\n getConfig: () => this.config.config,\n isEnabledForSession: (sk) => this.agents.get(sk)?.effectiveProfile.manifest.memory.mode !== 'off',\n getMemoryManagerForSession: (sk) => this.getMemoryManagerForSession(sk),\n getLastAssistantContent: (sk) => this.getLastAssistantContent(sk),\n });\n this.backgroundReview = new BackgroundReviewCoordinator({\n getConfig: () => this.mergedConfig(),\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 getMemoryManager: () => this.getCurrentWorkspaceRuntime().memoryManager,\n getSessionStore: this.config.getSessionStore,\n gatewayClarify: this.config.gatewayClarify,\n getAutomationService: this.config.getAutomationService,\n getNotesService: this.config.getNotesService,\n getProjectService: this.config.getProjectService,\n getWorkItemService: this.config.getWorkItemService,\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 installSkillFromSource: this.config.installSkillFromSource,\n getCodeIntelligenceRuntime: (workspace) =>\n this.workspaceRuntimes.getOrCreate(workspace).codeIntelligence,\n };\n }\n\n getMemoryManager(): MemoryManager {\n return this.getCurrentWorkspaceRuntime().memoryManager;\n }\n\n getMemoryManagerForSession(sessionKey: string): MemoryManager {\n return this.getWorkspaceRuntimeForSession(sessionKey).memoryManager;\n }\n\n markCodeIntelligenceDirty(sessionKey: string, paths: readonly string[]): void {\n if (paths.length === 0) return;\n const instance = this.agents.get(sessionKey);\n const config = this.config.config?.codeIntelligence;\n if (\n !instance ||\n !config?.enabled ||\n !config.agentIds.includes(instance.effectiveProfile.agentId)\n ) return;\n this.getWorkspaceRuntimeForSession(sessionKey).codeIntelligence.markDirty(paths);\n }\n\n /** Build the bounded, policy-filtered context used for this model turn. */\n prepareUserTurnContext(\n userMessage: AgentMessage,\n sessionKey: string,\n ): Promise<UserContextPlan> {\n return this.userContext.prepare(userMessage, sessionKey);\n }\n\n /**\n * After a completed turn: sync external providers and queue next-turn prefetch.\n * Delegates to {@link UserContextCoordinator}.\n */\n afterAgentTurn(sessionKey: string, userPlainText: string): Promise<void> {\n return this.userContext.afterTurn(sessionKey, userPlainText);\n }\n\n /**\n * Call once per user turn before the main embedded agent turn.\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);\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 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 prepareSkillTurn(sessionKey: string, text: string): PreparedSkillTurn {\n this.getOrCreateAgent(sessionKey);\n const inst = this.agents.get(sessionKey);\n if (!text.includes('/skill:')) {\n return {\n text,\n activatedCapabilityNames: this.activeCapabilityNames(inst),\n };\n }\n const rt = this.getWorkspaceRuntimeForSession(sessionKey);\n const options = {\n skillAllowlist: inst?.effectiveProfile.skillsAllowlist,\n registeredToolNames: inst?.registeredToolNames,\n };\n const expanded = text.trimStart().startsWith('/skill:')\n ? rt.skillManager.expandCommand(text, options)\n : text;\n const selectedCapabilities = rt.skillManager.getActivatedCapabilitiesForText(text, options);\n const turnOnlyCapabilities: string[] = [];\n const now = Date.now();\n for (const capabilityName of selectedCapabilities) {\n const state = createAgentCapabilitySessionState(capabilityName, 'skill', now);\n if (!state) continue;\n if (state.ttl === 'turn') {\n turnOnlyCapabilities.push(state.id);\n continue;\n }\n inst?.activeCapabilities.set(state.id, state);\n }\n return {\n text: expanded,\n activatedCapabilityNames: [\n ...new Set([\n ...this.activeCapabilityNames(inst),\n ...turnOnlyCapabilities,\n ]),\n ],\n };\n }\n\n async withSkillCapabilities<T>(\n sessionKey: string,\n capabilityNames: readonly string[],\n run: () => Promise<T>,\n ): Promise<T> {\n const requested = [...new Set(capabilityNames.map((name) => name.trim()).filter(Boolean))];\n if (requested.length === 0) return run();\n\n this.getOrCreateAgent(sessionKey);\n const inst = this.agents.get(sessionKey);\n if (!inst) return run();\n\n const activatedTools = this.toolsFactory.createCapabilityTools(requested, {\n disabledTools: inst.effectiveProfile.tools.denied,\n });\n const existingNames = new Set(inst.registeredToolNames);\n const newTools = activatedTools.filter((tool) => !existingNames.has(tool.name));\n\n const originalTools = inst.agent.state.tools as AgentTool<any, any>[];\n const originalRegisteredToolNames = inst.registeredToolNames;\n const originalSystemPrompt = inst.agent.state.systemPrompt;\n const nextRegisteredToolNames = [...originalRegisteredToolNames, ...newTools.map((tool) => tool.name)];\n\n inst.agent.state.tools = newTools.length > 0 ? [...originalTools, ...newTools] : originalTools;\n inst.registeredToolNames = nextRegisteredToolNames;\n inst.agent.state.systemPrompt = this.buildSystemPromptForInstance(\n inst,\n nextRegisteredToolNames,\n requested,\n );\n try {\n return await run();\n } finally {\n inst.agent.state.tools = originalTools;\n inst.registeredToolNames = originalRegisteredToolNames;\n inst.agent.state.systemPrompt = originalSystemPrompt;\n }\n }\n\n private buildSystemPromptForInstance(\n instance: AgentInstance,\n registeredToolNames: string[] = instance.registeredToolNames,\n activeCapabilityNames: readonly string[] = this.activeCapabilityNames(instance),\n ): string {\n const cfg = this.config.config!;\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(resolvedWorkspacePath);\n const contextFiles = this.resolveContextFilesForSession(instance.sessionKey, instance.effectiveProfile);\n const modelRef = instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel;\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 return 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,\n sessionKey: instance.sessionKey,\n modelRef,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n activeProjectContext: this.composeDynamicProjectContext(\n instance.activeProjectContext,\n instance.activeSelfVerifyContext,\n this.buildActiveCapabilityContext(instance, activeCapabilityNames, registeredToolNames),\n ),\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 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 = 'always';\n const { contextFiles } = resolveBootstrapContextSync({\n profileDir,\n userProfilePath: resolveUserProfilePath(),\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(\n s: Skill,\n skillsConfig = createSkillConfigManager(resolveStateDir()).load(),\n lock = loadSkillsLock(),\n workspaceLock?: SkillsLockFile,\n workspaceDir?: string,\n ): SkillCatalogEntry {\n const base = resolve(s.baseDir);\n const workspaceRoot = workspaceDir ? resolveWorkspaceSkillsDir(workspaceDir) : '';\n const workspaceManaged = workspaceRoot ? s.source === 'workspace' && base.startsWith(resolve(workspaceRoot) + sep) : false;\n const globalManaged = isUnderManagedSkillsDir(s.baseDir);\n const managed = globalManaged || workspaceManaged;\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 sourceLock = workspaceManaged ? workspaceLock : lock;\n const hub = managed && hubKey ? sourceLock?.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 sessionKey = this.config.getCurrentContext?.()?.sessionKey;\n const workspaceDir = sessionKey ? this.getResolvedWorkspaceForSession(sessionKey) : this.baseWorkspacePath;\n const workspaceLock = loadSkillsLock(resolveWorkspaceSkillsLockPath(workspaceDir));\n const rt = this.getCurrentWorkspaceRuntime();\n return {\n catalog: rt.skillManager\n .getSkills()\n .map((s) => this.skillCatalogEntryFromSkill(s, skillsConfig, lock, workspaceLock, workspaceDir)),\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 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 workspaceLock = loadSkillsLock(resolveWorkspaceSkillsLockPath(profile.resolvedWorkspacePath));\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(\n s,\n skillsConfig,\n lock,\n workspaceLock,\n profile.resolvedWorkspacePath,\n ),\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 ...(entry?.skills.mode === 'allowlist' ? { agentAllowlist: [...(entry.skills.allow ?? [])] } : {}),\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 instance.activeProjectContext = buildActiveProjectContextForPrompt(instance.sessionKey);\n instance.activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n instance.sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n instance.activeProjectContext,\n instance.activeSelfVerifyContext,\n ),\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 instance.activeProjectContext = buildActiveProjectContextForPrompt(instance.sessionKey);\n instance.activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n instance.sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n instance.activeProjectContext,\n instance.activeSelfVerifyContext,\n ),\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 this.refreshActiveProjectContextIfChanged(existing);\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, agentId: profile.agentId })\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 activeProjectContext = buildActiveProjectContextForPrompt(sessionKey);\n const activeSelfVerifyContext = this.getSelfVerifyPromptContext(sessionKey, profile.agentId);\n const { agent, registeredToolNames } = this.createAgentForProfile(\n sessionKey,\n profile,\n resolvedPath,\n rt,\n activeProjectContext,\n activeSelfVerifyContext,\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 activeCapabilities: new Map<string, AgentCapabilitySessionState>(),\n activeProjectContext,\n activeSelfVerifyContext,\n skillEnvPassthroughKeys: new Set<string>(),\n });\n\n const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;\n this.config.getModelManager?.().setSessionProfileDefault(sessionKey, modelRef, profile.fallbacks);\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.userContext.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 const activeProjectContext = buildActiveProjectContextForPrompt(sessionKey);\n const activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n activeProjectContext,\n activeSelfVerifyContext,\n ),\n });\n instance.activeProjectContext = activeProjectContext;\n instance.activeSelfVerifyContext = activeSelfVerifyContext;\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.userContext.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 getSelfVerifyPromptContext(sessionKey: string, agentId?: string): string {\n return this.config.getSelfVerifyPromptContext?.(sessionKey, agentId).trim() ?? '';\n }\n\n private composeDynamicProjectContext(...sections: Array<string | undefined>): string | undefined {\n return sections.map((section) => section?.trim())\n .filter((section): section is string => Boolean(section))\n .join('\\n\\n') || undefined;\n }\n\n getCapabilityCatalogForSession(sessionKey?: string): AgentCapabilityCatalogEntry[] {\n const inst = sessionKey?.trim() ? this.agents.get(sessionKey.trim()) : undefined;\n return this.resolveCapabilityCatalogForInstance(inst);\n }\n\n private createAgentForProfile(\n sessionKey: string,\n profile: EffectiveAgentProfile,\n resolvedWorkspacePath: string,\n rt: WorkspaceRuntime,\n activeProjectContext?: string,\n activeSelfVerifyContext?: string,\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 dreamingRoot = join(resolveAgentHomeDir(this.config.config!, profile.agentId), 'memories');\n const tools = this.toolsFactory.createAllTools({\n workspace: resolvedWorkspacePath,\n profileMarkdownRoot: resolveAgentProfileDir(this.config.config!, profile.agentId),\n agentId: profile.agentId,\n dreamingRoot,\n disabledTools: profile.tools.denied,\n getPrimaryModel: () => this.resolveModelStringToModel(modelRef),\n getMemoryManager: () => rt.memoryManager,\n getSkillManager: () => rt.skillManager,\n });\n if (\n this.config.config?.codeIntelligence?.enabled &&\n this.config.config.codeIntelligence.agentIds.includes(profile.agentId)\n ) {\n void rt.codeIntelligence.prime().catch(() => {});\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 activeProjectContext: this.composeDynamicProjectContext(\n activeProjectContext,\n activeSelfVerifyContext,\n ),\n }),\n model,\n thinkingLevel,\n tools,\n messages: [],\n },\n toolExecution: 'parallel',\n streamFn: createExtensionAwareStreamFn(),\n getApiKey: (provider: string) => this.resolveApiKeyWithCache(provider),\n beforeToolCall: async ({ toolCall, args }) => {\n const toolName = toolCall.name;\n\n if (toolName === 'exec_command') {\n const ctx = this.config.getCurrentContext();\n const cfg = this.mergedConfig();\n if (ctx && cfg) {\n const command =\n typeof (args as { cmd?: unknown })?.cmd === 'string'\n ? (args as { cmd: string }).cmd\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 private refreshActiveProjectContextIfChanged(instance: AgentInstance): void {\n const nextProjectContext = buildActiveProjectContextForPrompt(instance.sessionKey);\n const nextSelfVerifyContext = this.getSelfVerifyPromptContext(\n instance.sessionKey,\n instance.effectiveProfile.agentId,\n );\n if (\n nextProjectContext === instance.activeProjectContext &&\n nextSelfVerifyContext === (instance.activeSelfVerifyContext ?? '')\n ) {\n return;\n }\n const cfg = this.config.config!;\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(resolvedWorkspacePath);\n const contextFiles = this.resolveContextFilesForSession(instance.sessionKey, instance.effectiveProfile);\n const modelRef = instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel;\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 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: instance.sessionKey,\n modelRef,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n activeProjectContext: this.composeDynamicProjectContext(\n nextProjectContext,\n nextSelfVerifyContext,\n ),\n });\n instance.activeProjectContext = nextProjectContext;\n instance.activeSelfVerifyContext = nextSelfVerifyContext;\n log.debug({ sessionKey: instance.sessionKey }, 'Dynamic agent context changed; system prompt refreshed');\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 const activeProjectContext = buildActiveProjectContextForPrompt(sessionKey);\n const activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n activeProjectContext,\n activeSelfVerifyContext,\n ),\n });\n instance.activeProjectContext = activeProjectContext;\n instance.activeSelfVerifyContext = activeSelfVerifyContext;\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 AgentTool,\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 { resolveAgentHomeDir, 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, resolveUserProfilePath } from '../config/paths.js';\nimport { extractTextContent } from './context/workspace.js';\nimport { buildActiveProjectContextForPrompt } from './context/project-context.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 type {\n SkillInstallToolOptions,\n SkillInstallToolResult,\n} from './tools/skill-install-tool.js';\nimport {\n createAgentCapabilitySessionState,\n resolveAgentCapabilityCatalog,\n type AgentCapabilityCatalogEntry,\n type AgentCapabilitySessionState,\n} from './capabilities/index.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 { AutomationService } from '../automations/index.js';\nimport type { SessionStore } from '../session/store.js';\nimport type { NotesService } from '../notes/index.js';\nimport type { ProjectService } from '../projects/index.js';\nimport type { WorkItemService } from '../work-items/index.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, type SkillsLockFile } from './skills/hub-lock.js';\nimport { basename, join, 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 { UserContextCoordinator } from './memory/user-context-coordinator.js';\nimport type { UserContextPlan } from './memory/context/types.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 { resolveWorkspaceSkillsDir, resolveWorkspaceSkillsLockPath } from './skills/workspace-skills-dir.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 AutomationService for the `automation` tool. */\n getAutomationService?: () => AutomationService | undefined;\n /** Gateway: exposes first-class xopc product objects for the `xopc_use` tool. */\n getNotesService?: () => NotesService | undefined;\n getProjectService?: () => ProjectService | undefined;\n getWorkItemService?: () => WorkItemService | 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 /** Install a managed skill from an explicit source and refresh runtime state. */\n installSkillFromSource?: (opts: SkillInstallToolOptions) => Promise<SkillInstallToolResult>;\n /** Dynamic workspace verification context injected into the system prompt when edits are pending. */\n getSelfVerifyPromptContext?: (sessionKey: string, agentId?: string) => string;\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 /** Capability packs activated by explicit skills or UI entry points in this session. */\n activeCapabilities: Map<string, AgentCapabilitySessionState>;\n activeProjectContext?: string;\n activeSelfVerifyContext?: string;\n /** Declared env var names from skill_view; exec_command reads values from process.env at spawn time. */\n skillEnvPassthroughKeys: Set<string>;\n}\n\nexport interface PreparedSkillTurn {\n text: string;\n activatedCapabilityNames: 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\n private activeCapabilityNames(inst: AgentInstance | undefined): string[] {\n return inst ? [...inst.activeCapabilities.keys()] : [];\n }\n\n private buildActiveCapabilityContext(\n instance: AgentInstance,\n capabilityNames: readonly string[],\n registeredToolNames: readonly string[],\n ): string | undefined {\n const availableCatalog = this.resolveCapabilityCatalogForInstance(instance, registeredToolNames)\n .filter((definition) => definition.availableTools.length > 0);\n const definitionsById = new Map(availableCatalog.map((definition) => [definition.id, definition]));\n const definitions = [...new Set(capabilityNames)]\n .map((name) => definitionsById.get(name))\n .filter((definition): definition is AgentCapabilityCatalogEntry => Boolean(definition));\n if (definitions.length === 0) return undefined;\n const rows = definitions.map((definition) => {\n const tools = definition.availableTools.join(', ');\n const hint = definition.promptHint?.trim() ? `\\n Guidance: ${definition.promptHint.trim()}` : '';\n return `- ${definition.id} (${definition.label}): ${definition.description}\\n Tools: ${tools}${hint}`;\n });\n return [\n '# Active Capability Packs',\n '',\n 'These capability packs are active for the current task. Use their tools only when they directly help satisfy the user request.',\n '',\n ...rows,\n ].join('\\n');\n }\n\n private resolveCapabilityCatalogForInstance(\n instance: AgentInstance | undefined,\n registeredToolNames: readonly string[] = instance?.registeredToolNames ?? [],\n ): AgentCapabilityCatalogEntry[] {\n return resolveAgentCapabilityCatalog({\n registeredToolNames,\n lazyToolNames: this.toolsFactory.getLazyCapabilityToolNames(),\n deniedToolNames: instance ? [...instance.effectiveProfile.tools.denied] : [],\n });\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 userContext: UserContextCoordinator;\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.userContext = new UserContextCoordinator({\n getConfig: () => this.config.config,\n isEnabledForSession: (sk) => this.agents.get(sk)?.effectiveProfile.manifest.memory.mode !== 'off',\n getAgentIdForSession: (sk) => this.agents.get(sk)?.effectiveProfile.agentId ?? 'main',\n getMemoryManagerForSession: (sk) => this.getMemoryManagerForSession(sk),\n getLastAssistantContent: (sk) => this.getLastAssistantContent(sk),\n });\n this.backgroundReview = new BackgroundReviewCoordinator({\n getConfig: () => this.mergedConfig(),\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 profile = resolveEffectiveAgentProfileForSession(this.config.config!, sessionKey);\n const resolvedPath = sessionKey\n ? this.getResolvedWorkspaceForSession(sessionKey)\n : this.baseWorkspacePath;\n return this.workspaceRuntimes.getOrCreate(resolvedPath, profile.agentId);\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 getMemoryManager: () => this.getCurrentWorkspaceRuntime().memoryManager,\n getSessionStore: this.config.getSessionStore,\n gatewayClarify: this.config.gatewayClarify,\n getAutomationService: this.config.getAutomationService,\n getNotesService: this.config.getNotesService,\n getProjectService: this.config.getProjectService,\n getWorkItemService: this.config.getWorkItemService,\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 installSkillFromSource: this.config.installSkillFromSource,\n getCodeIntelligenceRuntime: (workspace) =>\n this.workspaceRuntimes.getOrCreate(\n workspace,\n resolveEffectiveAgentProfileForSession(\n this.config.config!,\n this.config.getCurrentContext?.()?.sessionKey,\n ).agentId,\n ).codeIntelligence,\n };\n }\n\n getMemoryManager(): MemoryManager {\n return this.getCurrentWorkspaceRuntime().memoryManager;\n }\n\n getMemoryManagerForSession(sessionKey: string): MemoryManager {\n return this.getWorkspaceRuntimeForSession(sessionKey).memoryManager;\n }\n\n markCodeIntelligenceDirty(sessionKey: string, paths: readonly string[]): void {\n if (paths.length === 0) return;\n const instance = this.agents.get(sessionKey);\n const config = this.config.config?.codeIntelligence;\n if (\n !instance ||\n !config?.enabled ||\n !config.agentIds.includes(instance.effectiveProfile.agentId)\n ) return;\n this.getWorkspaceRuntimeForSession(sessionKey).codeIntelligence.markDirty(paths);\n }\n\n /** Build the bounded, policy-filtered context used for this model turn. */\n prepareUserTurnContext(\n userMessage: AgentMessage,\n sessionKey: string,\n ): Promise<UserContextPlan> {\n return this.userContext.prepare(userMessage, sessionKey);\n }\n\n /**\n * After a completed turn: sync external providers and queue next-turn prefetch.\n * Delegates to {@link UserContextCoordinator}.\n */\n afterAgentTurn(sessionKey: string, userPlainText: string): Promise<void> {\n return this.userContext.afterTurn(sessionKey, userPlainText);\n }\n\n /**\n * Call once per user turn before the main embedded agent turn.\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);\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 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 prepareSkillTurn(sessionKey: string, text: string): PreparedSkillTurn {\n this.getOrCreateAgent(sessionKey);\n const inst = this.agents.get(sessionKey);\n if (!text.includes('/skill:')) {\n return {\n text,\n activatedCapabilityNames: this.activeCapabilityNames(inst),\n };\n }\n const rt = this.getWorkspaceRuntimeForSession(sessionKey);\n const options = {\n skillAllowlist: inst?.effectiveProfile.skillsAllowlist,\n registeredToolNames: inst?.registeredToolNames,\n };\n const expanded = text.trimStart().startsWith('/skill:')\n ? rt.skillManager.expandCommand(text, options)\n : text;\n const selectedCapabilities = rt.skillManager.getActivatedCapabilitiesForText(text, options);\n const turnOnlyCapabilities: string[] = [];\n const now = Date.now();\n for (const capabilityName of selectedCapabilities) {\n const state = createAgentCapabilitySessionState(capabilityName, 'skill', now);\n if (!state) continue;\n if (state.ttl === 'turn') {\n turnOnlyCapabilities.push(state.id);\n continue;\n }\n inst?.activeCapabilities.set(state.id, state);\n }\n return {\n text: expanded,\n activatedCapabilityNames: [\n ...new Set([\n ...this.activeCapabilityNames(inst),\n ...turnOnlyCapabilities,\n ]),\n ],\n };\n }\n\n async withSkillCapabilities<T>(\n sessionKey: string,\n capabilityNames: readonly string[],\n run: () => Promise<T>,\n ): Promise<T> {\n const requested = [...new Set(capabilityNames.map((name) => name.trim()).filter(Boolean))];\n if (requested.length === 0) return run();\n\n this.getOrCreateAgent(sessionKey);\n const inst = this.agents.get(sessionKey);\n if (!inst) return run();\n\n const activatedTools = this.toolsFactory.createCapabilityTools(requested, {\n disabledTools: inst.effectiveProfile.tools.denied,\n });\n const existingNames = new Set(inst.registeredToolNames);\n const newTools = activatedTools.filter((tool) => !existingNames.has(tool.name));\n\n const originalTools = inst.agent.state.tools as AgentTool<any, any>[];\n const originalRegisteredToolNames = inst.registeredToolNames;\n const originalSystemPrompt = inst.agent.state.systemPrompt;\n const nextRegisteredToolNames = [...originalRegisteredToolNames, ...newTools.map((tool) => tool.name)];\n\n inst.agent.state.tools = newTools.length > 0 ? [...originalTools, ...newTools] : originalTools;\n inst.registeredToolNames = nextRegisteredToolNames;\n inst.agent.state.systemPrompt = this.buildSystemPromptForInstance(\n inst,\n nextRegisteredToolNames,\n requested,\n );\n try {\n return await run();\n } finally {\n inst.agent.state.tools = originalTools;\n inst.registeredToolNames = originalRegisteredToolNames;\n inst.agent.state.systemPrompt = originalSystemPrompt;\n }\n }\n\n private buildSystemPromptForInstance(\n instance: AgentInstance,\n registeredToolNames: string[] = instance.registeredToolNames,\n activeCapabilityNames: readonly string[] = this.activeCapabilityNames(instance),\n ): string {\n const cfg = this.config.config!;\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(\n resolvedWorkspacePath,\n instance.effectiveProfile.agentId,\n );\n const contextFiles = this.resolveContextFilesForSession(instance.sessionKey, instance.effectiveProfile);\n const modelRef = instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel;\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 return 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,\n sessionKey: instance.sessionKey,\n modelRef,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n activeProjectContext: this.composeDynamicProjectContext(\n instance.activeProjectContext,\n instance.activeSelfVerifyContext,\n this.buildActiveCapabilityContext(instance, activeCapabilityNames, registeredToolNames),\n ),\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 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 = 'always';\n const { contextFiles } = resolveBootstrapContextSync({\n profileDir,\n userProfilePath: resolveUserProfilePath(),\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(\n s: Skill,\n skillsConfig = createSkillConfigManager(resolveStateDir()).load(),\n lock = loadSkillsLock(),\n workspaceLock?: SkillsLockFile,\n workspaceDir?: string,\n ): SkillCatalogEntry {\n const base = resolve(s.baseDir);\n const workspaceRoot = workspaceDir ? resolveWorkspaceSkillsDir(workspaceDir) : '';\n const workspaceManaged = workspaceRoot ? s.source === 'workspace' && base.startsWith(resolve(workspaceRoot) + sep) : false;\n const globalManaged = isUnderManagedSkillsDir(s.baseDir);\n const managed = globalManaged || workspaceManaged;\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 sourceLock = workspaceManaged ? workspaceLock : lock;\n const hub = managed && hubKey ? sourceLock?.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 sessionKey = this.config.getCurrentContext?.()?.sessionKey;\n const workspaceDir = sessionKey ? this.getResolvedWorkspaceForSession(sessionKey) : this.baseWorkspacePath;\n const workspaceLock = loadSkillsLock(resolveWorkspaceSkillsLockPath(workspaceDir));\n const rt = this.getCurrentWorkspaceRuntime();\n return {\n catalog: rt.skillManager\n .getSkills()\n .map((s) => this.skillCatalogEntryFromSkill(s, skillsConfig, lock, workspaceLock, workspaceDir)),\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 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, profile.agentId);\n const skillsConfig = createSkillConfigManager(resolveStateDir()).load();\n const lock = loadSkillsLock();\n const workspaceLock = loadSkillsLock(resolveWorkspaceSkillsLockPath(profile.resolvedWorkspacePath));\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(\n s,\n skillsConfig,\n lock,\n workspaceLock,\n profile.resolvedWorkspacePath,\n ),\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 ...(entry?.skills.mode === 'allowlist' ? { agentAllowlist: [...(entry.skills.allow ?? [])] } : {}),\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 for (const rt of this.workspaceRuntimes.values()) {\n rt.skillManager.refreshPromptFromConfig();\n }\n for (const instance of this.agents.values()) {\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(\n resolvedWorkspacePath,\n instance.effectiveProfile.agentId,\n );\n const contextFiles = this.resolveContextFilesForSession(\n instance.sessionKey,\n instance.effectiveProfile,\n );\n instance.activeProjectContext = buildActiveProjectContextForPrompt(instance.sessionKey);\n instance.activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n instance.sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n instance.activeProjectContext,\n instance.activeSelfVerifyContext,\n ),\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 for (const instance of this.agents.values()) {\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(\n resolvedWorkspacePath,\n instance.effectiveProfile.agentId,\n );\n const contextFiles = this.resolveContextFilesForSession(\n instance.sessionKey,\n instance.effectiveProfile,\n );\n instance.activeProjectContext = buildActiveProjectContextForPrompt(instance.sessionKey);\n instance.activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n instance.sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n instance.activeProjectContext,\n instance.activeSelfVerifyContext,\n ),\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 this.refreshActiveProjectContextIfChanged(existing);\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, profile.agentId);\n\n if (isMemorySubsystemEnabled(cfg)) {\n void rt.memoryManager\n .initializeAll(sessionKey, { workspace: resolvedPath, agentId: profile.agentId })\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 activeProjectContext = buildActiveProjectContextForPrompt(sessionKey);\n const activeSelfVerifyContext = this.getSelfVerifyPromptContext(sessionKey, profile.agentId);\n const { agent, registeredToolNames } = this.createAgentForProfile(\n sessionKey,\n profile,\n resolvedPath,\n rt,\n activeProjectContext,\n activeSelfVerifyContext,\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 activeCapabilities: new Map<string, AgentCapabilitySessionState>(),\n activeProjectContext,\n activeSelfVerifyContext,\n skillEnvPassthroughKeys: new Set<string>(),\n });\n\n const modelRef = profile.primaryModelRef?.trim() || this.defaultModel;\n this.config.getModelManager?.().setSessionProfileDefault(sessionKey, modelRef, profile.fallbacks);\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.userContext.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(\n resolvedWorkspacePath,\n instance.effectiveProfile.agentId,\n );\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 const activeProjectContext = buildActiveProjectContextForPrompt(sessionKey);\n const activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n activeProjectContext,\n activeSelfVerifyContext,\n ),\n });\n instance.activeProjectContext = activeProjectContext;\n instance.activeSelfVerifyContext = activeSelfVerifyContext;\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.userContext.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 getSelfVerifyPromptContext(sessionKey: string, agentId?: string): string {\n return this.config.getSelfVerifyPromptContext?.(sessionKey, agentId).trim() ?? '';\n }\n\n private composeDynamicProjectContext(...sections: Array<string | undefined>): string | undefined {\n return sections.map((section) => section?.trim())\n .filter((section): section is string => Boolean(section))\n .join('\\n\\n') || undefined;\n }\n\n getCapabilityCatalogForSession(sessionKey?: string): AgentCapabilityCatalogEntry[] {\n const inst = sessionKey?.trim() ? this.agents.get(sessionKey.trim()) : undefined;\n return this.resolveCapabilityCatalogForInstance(inst);\n }\n\n private createAgentForProfile(\n sessionKey: string,\n profile: EffectiveAgentProfile,\n resolvedWorkspacePath: string,\n rt: WorkspaceRuntime,\n activeProjectContext?: string,\n activeSelfVerifyContext?: string,\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 dreamingRoot = join(resolveAgentHomeDir(this.config.config!, profile.agentId), 'memories');\n const tools = this.toolsFactory.createAllTools({\n workspace: resolvedWorkspacePath,\n profileMarkdownRoot: resolveAgentProfileDir(this.config.config!, profile.agentId),\n agentId: profile.agentId,\n dreamingRoot,\n disabledTools: profile.tools.denied,\n getPrimaryModel: () => this.resolveModelStringToModel(modelRef),\n getMemoryManager: () => rt.memoryManager,\n getSkillManager: () => rt.skillManager,\n });\n if (\n this.config.config?.codeIntelligence?.enabled &&\n this.config.config.codeIntelligence.agentIds.includes(profile.agentId)\n ) {\n void rt.codeIntelligence.prime().catch(() => {});\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 activeProjectContext: this.composeDynamicProjectContext(\n activeProjectContext,\n activeSelfVerifyContext,\n ),\n }),\n model,\n thinkingLevel,\n tools,\n messages: [],\n },\n toolExecution: 'parallel',\n streamFn: createExtensionAwareStreamFn(),\n getApiKey: (provider: string) => this.resolveApiKeyWithCache(provider),\n beforeToolCall: async ({ toolCall, args }) => {\n const toolName = toolCall.name;\n\n if (toolName === 'exec_command') {\n const ctx = this.config.getCurrentContext();\n const cfg = this.mergedConfig();\n if (ctx && cfg) {\n const command =\n typeof (args as { cmd?: unknown })?.cmd === 'string'\n ? (args as { cmd: string }).cmd\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 private refreshActiveProjectContextIfChanged(instance: AgentInstance): void {\n const nextProjectContext = buildActiveProjectContextForPrompt(instance.sessionKey);\n const nextSelfVerifyContext = this.getSelfVerifyPromptContext(\n instance.sessionKey,\n instance.effectiveProfile.agentId,\n );\n if (\n nextProjectContext === instance.activeProjectContext &&\n nextSelfVerifyContext === (instance.activeSelfVerifyContext ?? '')\n ) {\n return;\n }\n const cfg = this.config.config!;\n const resolvedWorkspacePath = this.getResolvedWorkspaceForSession(instance.sessionKey);\n const rt = this.workspaceRuntimes.getOrCreate(\n resolvedWorkspacePath,\n instance.effectiveProfile.agentId,\n );\n const contextFiles = this.resolveContextFilesForSession(instance.sessionKey, instance.effectiveProfile);\n const modelRef = instance.effectiveProfile.primaryModelRef?.trim() || this.defaultModel;\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 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: instance.sessionKey,\n modelRef,\n agentId: instance.effectiveProfile.agentId,\n thinkingLevel,\n activeProjectContext: this.composeDynamicProjectContext(\n nextProjectContext,\n nextSelfVerifyContext,\n ),\n });\n instance.activeProjectContext = nextProjectContext;\n instance.activeSelfVerifyContext = nextSelfVerifyContext;\n log.debug({ sessionKey: instance.sessionKey }, 'Dynamic agent context changed; system prompt refreshed');\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(\n resolvedWorkspacePath,\n instance.effectiveProfile.agentId,\n );\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 const activeProjectContext = buildActiveProjectContextForPrompt(sessionKey);\n const activeSelfVerifyContext = this.getSelfVerifyPromptContext(\n sessionKey,\n instance.effectiveProfile.agentId,\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 activeProjectContext: this.composeDynamicProjectContext(\n activeProjectContext,\n activeSelfVerifyContext,\n ),\n });\n instance.activeProjectContext = activeProjectContext;\n instance.activeSelfVerifyContext = activeSelfVerifyContext;\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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"}
|
|
@@ -119,6 +119,7 @@ async function runUnderstandingReview(params) {
|
|
|
119
119
|
if (isAssistantTurnAborted(reviewAgent) || isAssistantTurnFailed(reviewAgent)) return;
|
|
120
120
|
const candidates = parseUnderstandingCandidates(lastAssistantText(reviewAgent));
|
|
121
121
|
await memoryManager.applyUnderstandingCandidates(candidates, {
|
|
122
|
+
agentId: settings.agentId,
|
|
122
123
|
sessionKey,
|
|
123
124
|
sourceText: "Background review of the current session transcript",
|
|
124
125
|
reviewSource: "background"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-background-review.js","names":[],"sources":["../../../../src/agent/background-review/run-background-review.ts"],"sourcesContent":["import { Agent, type AgentMessage, type ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { resolveProviderApiKeySync } from '../../auth/sync-provider-auth.js';\nimport { getApiKeySync } from '../../providers/index.js';\nimport { createExtensionAwareStreamFn } from '../../providers/extension-stream-bridge.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport { extractTextContent } from '../context/workspace.js';\nimport type { MemoryManager } from '../memory/manager.js';\nimport type { UnderstandingCandidate } from '../memory/understanding/types.js';\nimport {\n runAgentTurnWithTimeout,\n resolveAgentTurnTimeoutMs,\n} from '../orchestration/run-agent-turn-with-timeout.js';\nimport {\n isAssistantTurnAborted,\n isAssistantTurnFailed,\n} from '../orchestration/llm-turn-retry.js';\n\nimport type { BackgroundReviewSettings } from './settings.js';\nimport {\n MEMORY_REVIEW_USER_PROMPT,\n UNDERSTANDING_REVIEW_SYSTEM_PROMPT,\n} from './prompts.js';\n\nconst log = createLogger('BackgroundReview');\n\nfunction cloneMessageTail(messages: AgentMessage[], max: number): AgentMessage[] {\n const tail = messages.length <= max ? messages : messages.slice(-max);\n return JSON.parse(JSON.stringify(tail)) as AgentMessage[];\n}\n\nexport interface RunBackgroundReviewParams {\n sessionKey: string;\n mainAgent: Agent;\n settings: BackgroundReviewSettings;\n memoryManager: MemoryManager;\n getConfig: () => Config | undefined;\n}\n\nconst ALLOWED_UNDERSTANDING_KINDS = new Set<UnderstandingCandidate['kind']>([\n 'preference', 'boundary', 'relationship', 'project_context', 'commitment', 'routine',\n 'personal_logistics', 'open_question', 'milestone', 'current_state', 'task_lesson',\n 'tool_preference', 'long_term_goal', 'derived_insight',\n]);\nconst ALLOWED_SENSITIVITIES = new Set<UnderstandingCandidate['sensitivity']>([\n 'normal', 'personal', 'secret', 'regulated',\n]);\n\nfunction lastAssistantText(agent: Agent): string {\n for (let i = agent.state.messages.length - 1; i >= 0; i--) {\n const message = agent.state.messages[i];\n if (message.role !== 'assistant') continue;\n return Array.isArray(message.content)\n ? extractTextContent(message.content as Array<{ type: string; text?: string }>)\n : String(message.content);\n }\n return '';\n}\n\nfunction parseUnderstandingCandidates(raw: string): UnderstandingCandidate[] {\n const fenced = /```(?:json)?\\s*([\\s\\S]*?)```/i.exec(raw)?.[1];\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n const candidateJson = fenced ?? (start >= 0 && end > start ? raw.slice(start, end + 1) : raw);\n try {\n const parsed = JSON.parse(candidateJson) as { candidates?: unknown };\n if (!Array.isArray(parsed.candidates)) return [];\n const output: UnderstandingCandidate[] = [];\n for (const value of parsed.candidates.slice(0, 8)) {\n if (!value || typeof value !== 'object') continue;\n const item = value as Record<string, unknown>;\n if (!ALLOWED_UNDERSTANDING_KINDS.has(item.kind as UnderstandingCandidate['kind'])) continue;\n if (typeof item.content !== 'string' || item.content.trim().length < 4) continue;\n const confidence = typeof item.confidence === 'number' ? item.confidence : 0.65;\n const importance = typeof item.importance === 'number' ? item.importance : 0.5;\n const durability = item.durability === 'ephemeral' || item.durability === 'recurring'\n ? item.durability\n : 'durable';\n const sensitivity = ALLOWED_SENSITIVITIES.has(item.sensitivity as UnderstandingCandidate['sensitivity'])\n ? item.sensitivity as UnderstandingCandidate['sensitivity']\n : 'personal';\n const disclosurePolicy = item.disclosurePolicy === 'silent' || item.disclosurePolicy === 'ask_before_reference'\n ? item.disclosurePolicy\n : 'referenceable';\n output.push({\n kind: item.kind as UnderstandingCandidate['kind'],\n content: item.content.trim(),\n confidence: Math.max(0, Math.min(1, confidence)),\n importance: Math.max(0, Math.min(1, importance)),\n explicitness: 'inferred',\n durability,\n sensitivity,\n disclosurePolicy,\n tags: Array.isArray(item.tags)\n ? item.tags.filter((tag): tag is string => typeof tag === 'string').slice(0, 8)\n : ['background-review'],\n });\n }\n return output;\n } catch {\n return [];\n }\n}\n\nasync function runUnderstandingReview(params: RunBackgroundReviewParams): Promise<void> {\n const { sessionKey, mainAgent, settings, memoryManager, getConfig } = params;\n const reviewAgent = new Agent({\n initialState: {\n systemPrompt: UNDERSTANDING_REVIEW_SYSTEM_PROMPT,\n model: mainAgent.state.model as Model<Api>,\n thinkingLevel: 'off' as ThinkingLevel,\n tools: [],\n messages: [],\n },\n streamFn: createExtensionAwareStreamFn(),\n getApiKey: (provider: string) => resolveProviderApiKeySync(provider) ?? getApiKeySync(provider) ?? '',\n });\n reviewAgent.state.messages = cloneMessageTail(mainAgent.state.messages, settings.maxHistoryMessages);\n const timeoutMs = Math.min(settings.maxDurationMs, resolveAgentTurnTimeoutMs(getConfig()));\n try {\n await runAgentTurnWithTimeout(reviewAgent, async () => {\n await reviewAgent.prompt({ role: 'user', content: MEMORY_REVIEW_USER_PROMPT, timestamp: Date.now() });\n await reviewAgent.waitForIdle();\n }, timeoutMs);\n } catch (err) {\n log.warn({ err, sessionKey }, 'User-understanding review failed or timed out');\n reviewAgent.abort();\n await reviewAgent.waitForIdle().catch(() => {});\n return;\n }\n if (isAssistantTurnAborted(reviewAgent) || isAssistantTurnFailed(reviewAgent)) return;\n const candidates = parseUnderstandingCandidates(lastAssistantText(reviewAgent));\n await memoryManager.applyUnderstandingCandidates(candidates, {\n sessionKey,\n sourceText: 'Background review of the current session transcript',\n reviewSource: 'background',\n });\n log.debug({ sessionKey, candidateCount: candidates.length }, 'User-understanding review completed');\n}\n\nexport async function runBackgroundReviewTurn(params: RunBackgroundReviewParams): Promise<void> {\n await runUnderstandingReview(params);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-background-review.js","names":[],"sources":["../../../../src/agent/background-review/run-background-review.ts"],"sourcesContent":["import { Agent, type AgentMessage, type ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { resolveProviderApiKeySync } from '../../auth/sync-provider-auth.js';\nimport { getApiKeySync } from '../../providers/index.js';\nimport { createExtensionAwareStreamFn } from '../../providers/extension-stream-bridge.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport { extractTextContent } from '../context/workspace.js';\nimport type { MemoryManager } from '../memory/manager.js';\nimport type { UnderstandingCandidate } from '../memory/understanding/types.js';\nimport {\n runAgentTurnWithTimeout,\n resolveAgentTurnTimeoutMs,\n} from '../orchestration/run-agent-turn-with-timeout.js';\nimport {\n isAssistantTurnAborted,\n isAssistantTurnFailed,\n} from '../orchestration/llm-turn-retry.js';\n\nimport type { BackgroundReviewSettings } from './settings.js';\nimport {\n MEMORY_REVIEW_USER_PROMPT,\n UNDERSTANDING_REVIEW_SYSTEM_PROMPT,\n} from './prompts.js';\n\nconst log = createLogger('BackgroundReview');\n\nfunction cloneMessageTail(messages: AgentMessage[], max: number): AgentMessage[] {\n const tail = messages.length <= max ? messages : messages.slice(-max);\n return JSON.parse(JSON.stringify(tail)) as AgentMessage[];\n}\n\nexport interface RunBackgroundReviewParams {\n sessionKey: string;\n mainAgent: Agent;\n settings: BackgroundReviewSettings;\n memoryManager: MemoryManager;\n getConfig: () => Config | undefined;\n}\n\nconst ALLOWED_UNDERSTANDING_KINDS = new Set<UnderstandingCandidate['kind']>([\n 'preference', 'boundary', 'relationship', 'project_context', 'commitment', 'routine',\n 'personal_logistics', 'open_question', 'milestone', 'current_state', 'task_lesson',\n 'tool_preference', 'long_term_goal', 'derived_insight',\n]);\nconst ALLOWED_SENSITIVITIES = new Set<UnderstandingCandidate['sensitivity']>([\n 'normal', 'personal', 'secret', 'regulated',\n]);\n\nfunction lastAssistantText(agent: Agent): string {\n for (let i = agent.state.messages.length - 1; i >= 0; i--) {\n const message = agent.state.messages[i];\n if (message.role !== 'assistant') continue;\n return Array.isArray(message.content)\n ? extractTextContent(message.content as Array<{ type: string; text?: string }>)\n : String(message.content);\n }\n return '';\n}\n\nfunction parseUnderstandingCandidates(raw: string): UnderstandingCandidate[] {\n const fenced = /```(?:json)?\\s*([\\s\\S]*?)```/i.exec(raw)?.[1];\n const start = raw.indexOf('{');\n const end = raw.lastIndexOf('}');\n const candidateJson = fenced ?? (start >= 0 && end > start ? raw.slice(start, end + 1) : raw);\n try {\n const parsed = JSON.parse(candidateJson) as { candidates?: unknown };\n if (!Array.isArray(parsed.candidates)) return [];\n const output: UnderstandingCandidate[] = [];\n for (const value of parsed.candidates.slice(0, 8)) {\n if (!value || typeof value !== 'object') continue;\n const item = value as Record<string, unknown>;\n if (!ALLOWED_UNDERSTANDING_KINDS.has(item.kind as UnderstandingCandidate['kind'])) continue;\n if (typeof item.content !== 'string' || item.content.trim().length < 4) continue;\n const confidence = typeof item.confidence === 'number' ? item.confidence : 0.65;\n const importance = typeof item.importance === 'number' ? item.importance : 0.5;\n const durability = item.durability === 'ephemeral' || item.durability === 'recurring'\n ? item.durability\n : 'durable';\n const sensitivity = ALLOWED_SENSITIVITIES.has(item.sensitivity as UnderstandingCandidate['sensitivity'])\n ? item.sensitivity as UnderstandingCandidate['sensitivity']\n : 'personal';\n const disclosurePolicy = item.disclosurePolicy === 'silent' || item.disclosurePolicy === 'ask_before_reference'\n ? item.disclosurePolicy\n : 'referenceable';\n output.push({\n kind: item.kind as UnderstandingCandidate['kind'],\n content: item.content.trim(),\n confidence: Math.max(0, Math.min(1, confidence)),\n importance: Math.max(0, Math.min(1, importance)),\n explicitness: 'inferred',\n durability,\n sensitivity,\n disclosurePolicy,\n tags: Array.isArray(item.tags)\n ? item.tags.filter((tag): tag is string => typeof tag === 'string').slice(0, 8)\n : ['background-review'],\n });\n }\n return output;\n } catch {\n return [];\n }\n}\n\nasync function runUnderstandingReview(params: RunBackgroundReviewParams): Promise<void> {\n const { sessionKey, mainAgent, settings, memoryManager, getConfig } = params;\n const reviewAgent = new Agent({\n initialState: {\n systemPrompt: UNDERSTANDING_REVIEW_SYSTEM_PROMPT,\n model: mainAgent.state.model as Model<Api>,\n thinkingLevel: 'off' as ThinkingLevel,\n tools: [],\n messages: [],\n },\n streamFn: createExtensionAwareStreamFn(),\n getApiKey: (provider: string) => resolveProviderApiKeySync(provider) ?? getApiKeySync(provider) ?? '',\n });\n reviewAgent.state.messages = cloneMessageTail(mainAgent.state.messages, settings.maxHistoryMessages);\n const timeoutMs = Math.min(settings.maxDurationMs, resolveAgentTurnTimeoutMs(getConfig()));\n try {\n await runAgentTurnWithTimeout(reviewAgent, async () => {\n await reviewAgent.prompt({ role: 'user', content: MEMORY_REVIEW_USER_PROMPT, timestamp: Date.now() });\n await reviewAgent.waitForIdle();\n }, timeoutMs);\n } catch (err) {\n log.warn({ err, sessionKey }, 'User-understanding review failed or timed out');\n reviewAgent.abort();\n await reviewAgent.waitForIdle().catch(() => {});\n return;\n }\n if (isAssistantTurnAborted(reviewAgent) || isAssistantTurnFailed(reviewAgent)) return;\n const candidates = parseUnderstandingCandidates(lastAssistantText(reviewAgent));\n await memoryManager.applyUnderstandingCandidates(candidates, {\n agentId: settings.agentId,\n sessionKey,\n sourceText: 'Background review of the current session transcript',\n reviewSource: 'background',\n });\n log.debug({ sessionKey, candidateCount: candidates.length }, 'User-understanding review completed');\n}\n\nexport async function runBackgroundReviewTurn(params: RunBackgroundReviewParams): Promise<void> {\n await runUnderstandingReview(params);\n}\n"],"mappings":"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"}
|
|
@@ -3,11 +3,11 @@ import { init_logger } from "../../utils/logger.js";
|
|
|
3
3
|
import { guardSessionManager } from "./session-tool-result-guard.js";
|
|
4
4
|
import { transformUserMessageForPersistence } from "../inbound/attachment-pipeline.js";
|
|
5
5
|
import { openSqliteHydratingSessionManager } from "./sqlite-hydrating-session-manager.js";
|
|
6
|
-
import { applyXopcProviderApiKey,
|
|
6
|
+
import { applyXopcProviderApiKey, createEmbeddedCredentialStore } from "./xopc-auth-storage.js";
|
|
7
7
|
import { wrapStreamFnForXopcExtensions } from "./xopc-stream-bridge.js";
|
|
8
8
|
import { xopcToolsToDefinitions } from "./xopc-tools-bridge.js";
|
|
9
9
|
import { applySystemPromptOverrideToSession } from "./system-prompt-override.js";
|
|
10
|
-
import { DefaultResourceLoader, SettingsManager, createAgentSession, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
10
|
+
import { DefaultResourceLoader, ModelRuntime, SettingsManager, createAgentSession, getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
//#region src/agent/embedded/session-runner.ts
|
|
12
12
|
init_logger();
|
|
13
13
|
const log = createLogger("EmbeddedSessionRunner");
|
|
@@ -167,8 +167,8 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
167
167
|
});
|
|
168
168
|
const toolDefs = xopcToolsToDefinitions(tools);
|
|
169
169
|
const toolNames = tools.map((t) => t.name);
|
|
170
|
-
const
|
|
171
|
-
applyXopcProviderApiKey(
|
|
170
|
+
const modelRuntime = await ModelRuntime.create({ credentials: createEmbeddedCredentialStore() });
|
|
171
|
+
await applyXopcProviderApiKey(modelRuntime, model.provider);
|
|
172
172
|
const resourceLoader = new DefaultResourceLoader({
|
|
173
173
|
cwd: workspaceDir,
|
|
174
174
|
agentDir: getAgentDir(),
|
|
@@ -182,7 +182,7 @@ var EmbeddedSessionRunnerPool = class {
|
|
|
182
182
|
thinkingLevel: thinkingLevel ?? "medium",
|
|
183
183
|
sessionManager: piSm,
|
|
184
184
|
settingsManager,
|
|
185
|
-
|
|
185
|
+
modelRuntime,
|
|
186
186
|
resourceLoader,
|
|
187
187
|
noTools: "builtin",
|
|
188
188
|
customTools: toolDefs,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-runner.js","names":[],"sources":["../../../../src/agent/embedded/session-runner.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport {\n createAgentSession,\n DefaultResourceLoader,\n getAgentDir,\n SettingsManager,\n type AgentSession,\n} from '@earendil-works/pi-coding-agent';\nimport type { Model, Api } from '@earendil-works/pi-ai';\n\nimport { createLogger } from '../../utils/logger.js';\nimport { guardSessionManager, type GuardedPiTranscriptManager } from './session-tool-result-guard.js';\nimport { transformUserMessageForPersistence } from '../inbound/attachment-pipeline.js';\nimport { openSqliteHydratingSessionManager } from './sqlite-hydrating-session-manager.js';\nimport { applyXopcProviderApiKey, createEmbeddedAuthStorage } from './xopc-auth-storage.js';\nimport { wrapStreamFnForXopcExtensions } from './xopc-stream-bridge.js';\nimport { xopcToolsToDefinitions } from './xopc-tools-bridge.js';\nimport { applySystemPromptOverrideToSession } from './system-prompt-override.js';\n\nconst log = createLogger('EmbeddedSessionRunner');\n\nconst DEFAULT_IDLE_TTL_MS = 5 * 60_000;\n\nexport type EmbeddedRunnerFingerprintInput = {\n sessionId: string;\n workspaceDir: string;\n modelRef: string;\n toolNames: readonly string[];\n systemPrompt: string;\n thinkingLevel: string;\n};\n\nexport function buildEmbeddedRunnerFingerprint(input: EmbeddedRunnerFingerprintInput): string {\n const tools = [...input.toolNames].sort().join('\\0');\n const promptMarker = `${input.systemPrompt.length}:${input.systemPrompt.slice(0, 128)}`;\n return [\n input.sessionId,\n input.workspaceDir,\n input.modelRef,\n tools,\n promptMarker,\n input.thinkingLevel,\n ].join('\u001f');\n}\n\ntype PooledRunner = {\n sessionKey: string;\n fingerprint: string;\n session: AgentSession;\n piSm: GuardedPiTranscriptManager;\n settingsManager: SettingsManager;\n baseStreamFn: AgentSession['agent']['streamFn'];\n lastUsedAt: number;\n idleTimer: ReturnType<typeof setTimeout> | null;\n};\n\nexport type AcquireEmbeddedSessionRunnerParams = {\n sessionKey: string;\n sessionId: string;\n workspaceDir: string;\n model: Model<Api>;\n modelRef: string;\n tools: AgentTool[];\n systemPrompt: string;\n thinkingLevel: ThinkingLevel;\n};\n\nexport type AcquiredEmbeddedSessionRunner = {\n session: AgentSession;\n piSm: GuardedPiTranscriptManager;\n reused: boolean;\n release: () => void;\n};\n\nexport interface EmbeddedSessionRunnerPoolStats {\n acquires: number;\n reuses: number;\n creates: number;\n evictions: number;\n pooled: number;\n}\n\nexport function isEmbeddedSessionRunnerEnabled(): boolean {\n const raw = process.env.XOPC_SESSION_RUNNER?.trim().toLowerCase();\n if (raw === '0' || raw === 'false' || raw === 'off') {\n return false;\n }\n return true;\n}\n\nexport function getEmbeddedSessionRunnerIdleTtlMs(): number {\n const raw = process.env.XOPC_SESSION_RUNNER_TTL_MS?.trim();\n if (!raw) {\n return DEFAULT_IDLE_TTL_MS;\n }\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_IDLE_TTL_MS;\n}\n\nfunction createEmbeddedSettingsManager(cwd: string): SettingsManager {\n const sm = SettingsManager.inMemory({ compaction: { enabled: false } });\n sm.setCompactionEnabled(false);\n void cwd;\n return sm;\n}\n\nexport interface EmbeddedSessionRunnerPoolOptions {\n /** Override for the env-driven enable flag (testing). */\n isEnabled?: () => boolean;\n /** Override for the env-driven idle TTL (testing). */\n getIdleTtlMs?: () => number;\n}\n\n/**\n * Owns the per-session pool of pi `AgentSession` runners. The class is the supported,\n * injectable owner; {@link defaultEmbeddedSessionRunnerPool} keeps the historic\n * module-level free functions working until every caller is migrated to DI.\n */\nexport class EmbeddedSessionRunnerPool {\n private readonly pool = new Map<string, PooledRunner>();\n private readonly isEnabledFn: () => boolean;\n private readonly getIdleTtlMsFn: () => number;\n\n private stats: Omit<EmbeddedSessionRunnerPoolStats, 'pooled'> = {\n acquires: 0,\n reuses: 0,\n creates: 0,\n evictions: 0,\n };\n\n constructor(opts: EmbeddedSessionRunnerPoolOptions = {}) {\n this.isEnabledFn = opts.isEnabled ?? isEmbeddedSessionRunnerEnabled;\n this.getIdleTtlMsFn = opts.getIdleTtlMs ?? getEmbeddedSessionRunnerIdleTtlMs;\n }\n\n getStats(): Readonly<EmbeddedSessionRunnerPoolStats> {\n return { ...this.stats, pooled: this.pool.size };\n }\n\n resetForTest(): void {\n for (const entry of this.pool.values()) {\n this.clearIdleTimer(entry);\n }\n this.pool.clear();\n this.stats = { acquires: 0, reuses: 0, creates: 0, evictions: 0 };\n }\n\n evict(sessionKey: string, reason = 'explicit'): void {\n const entry = this.pool.get(sessionKey);\n if (!entry) {\n return;\n }\n this.disposePooledRunner(sessionKey, entry, reason);\n }\n\n evictAll(reason = 'dispose_all'): void {\n for (const sessionKey of [...this.pool.keys()]) {\n this.evict(sessionKey, reason);\n }\n }\n\n async acquire(params: AcquireEmbeddedSessionRunnerParams): Promise<AcquiredEmbeddedSessionRunner> {\n this.stats.acquires += 1;\n\n const fingerprint = buildEmbeddedRunnerFingerprint({\n sessionId: params.sessionId,\n workspaceDir: params.workspaceDir,\n modelRef: params.modelRef,\n toolNames: params.tools.map((t) => t.name),\n systemPrompt: params.systemPrompt,\n thinkingLevel: params.thinkingLevel ?? 'medium',\n });\n\n const reuseEnabled = this.isEnabledFn();\n const existing = this.pool.get(params.sessionKey);\n\n let entry: PooledRunner;\n let reused = false;\n\n if (reuseEnabled && existing && existing.fingerprint === fingerprint) {\n this.clearIdleTimer(existing);\n entry = existing;\n entry.lastUsedAt = Date.now();\n reused = true;\n this.stats.reuses += 1;\n applySystemPromptOverrideToSession(entry.session, params.systemPrompt);\n entry.session.agent.streamFn = entry.baseStreamFn;\n log.debug({ sessionKey: params.sessionKey }, 'Reusing pooled embedded session runner');\n } else {\n if (existing) {\n this.disposePooledRunner(params.sessionKey, existing, 'fingerprint_mismatch');\n }\n entry = await this.createPooledRunner(params);\n this.pool.set(params.sessionKey, entry);\n this.stats.creates += 1;\n log.debug({ sessionKey: params.sessionKey }, 'Created embedded session runner');\n }\n\n return {\n session: entry.session,\n piSm: entry.piSm,\n reused,\n release: () => {\n if (!this.isEnabledFn()) {\n this.disposePooledRunner(params.sessionKey, entry, 'runner_disabled');\n return;\n }\n entry.lastUsedAt = Date.now();\n this.scheduleIdleEviction(params.sessionKey, entry);\n },\n };\n }\n\n private clearIdleTimer(entry: PooledRunner): void {\n if (entry.idleTimer) {\n clearTimeout(entry.idleTimer);\n entry.idleTimer = null;\n }\n }\n\n private scheduleIdleEviction(sessionKey: string, entry: PooledRunner): void {\n this.clearIdleTimer(entry);\n const ttlMs = this.getIdleTtlMsFn();\n entry.idleTimer = setTimeout(() => {\n const current = this.pool.get(sessionKey);\n if (current === entry) {\n this.disposePooledRunner(sessionKey, entry, 'idle_ttl');\n }\n }, ttlMs);\n entry.idleTimer.unref?.();\n }\n\n private disposePooledRunner(sessionKey: string, entry: PooledRunner, reason: string): void {\n this.clearIdleTimer(entry);\n this.pool.delete(sessionKey);\n this.stats.evictions += 1;\n try {\n entry.piSm.flushPendingToolResults?.();\n } catch {\n /* ignore */\n }\n log.debug({ sessionKey, reason }, 'Embedded session runner evicted');\n }\n\n private async createPooledRunner(params: AcquireEmbeddedSessionRunnerParams): Promise<PooledRunner> {\n const { sessionKey, sessionId, workspaceDir, model, thinkingLevel, tools, systemPrompt } = params;\n\n const settingsManager = createEmbeddedSettingsManager(workspaceDir);\n\n const piSm = guardSessionManager(\n openSqliteHydratingSessionManager({\n sessionKey,\n sessionId,\n cwd: workspaceDir,\n }),\n {\n sessionKey,\n contextWindowTokens: model.contextWindow ?? 128_000,\n transformMessageForPersistence: (message) =>\n transformUserMessageForPersistence(sessionKey, message),\n },\n );\n\n const toolDefs = xopcToolsToDefinitions(tools);\n const toolNames = tools.map((t) => t.name);\n\n const authStorage = createEmbeddedAuthStorage();\n applyXopcProviderApiKey(authStorage, model.provider);\n\n const resourceLoader = new DefaultResourceLoader({\n cwd: workspaceDir,\n agentDir: getAgentDir(),\n settingsManager,\n noContextFiles: true,\n });\n await resourceLoader.reload();\n\n const { session } = await createAgentSession({\n cwd: workspaceDir,\n model,\n thinkingLevel: thinkingLevel ?? 'medium',\n sessionManager: piSm,\n settingsManager,\n authStorage,\n resourceLoader,\n noTools: 'builtin',\n customTools: toolDefs,\n tools: toolNames,\n });\n\n applySystemPromptOverrideToSession(session, systemPrompt);\n const baseStreamFn = wrapStreamFnForXopcExtensions(session.agent.streamFn);\n session.agent.streamFn = baseStreamFn;\n\n const fingerprint = buildEmbeddedRunnerFingerprint({\n sessionId,\n workspaceDir,\n modelRef: params.modelRef,\n toolNames,\n systemPrompt,\n thinkingLevel: thinkingLevel ?? 'medium',\n });\n\n return {\n sessionKey,\n fingerprint,\n session,\n piSm,\n settingsManager,\n baseStreamFn,\n lastUsedAt: Date.now(),\n idleTimer: null,\n };\n }\n}\n\nexport const defaultEmbeddedSessionRunnerPool = new EmbeddedSessionRunnerPool();\n\nexport function getEmbeddedSessionRunnerStats(): Readonly<EmbeddedSessionRunnerPoolStats> {\n return defaultEmbeddedSessionRunnerPool.getStats();\n}\n\nexport function resetEmbeddedSessionRunnerForTest(): void {\n defaultEmbeddedSessionRunnerPool.resetForTest();\n}\n\nexport function evictEmbeddedSessionRunner(sessionKey: string, reason = 'explicit'): void {\n defaultEmbeddedSessionRunnerPool.evict(sessionKey, reason);\n}\n\nexport function evictAllEmbeddedSessionRunners(reason = 'dispose_all'): void {\n defaultEmbeddedSessionRunnerPool.evictAll(reason);\n}\n\nexport function acquireEmbeddedSessionRunner(\n params: AcquireEmbeddedSessionRunnerParams,\n): Promise<AcquiredEmbeddedSessionRunner> {\n return defaultEmbeddedSessionRunnerPool.acquire(params);\n}\n\n/** Resolve session identity used by embedded runner acquire and turn execution. */\nexport async function resolveEmbeddedTranscriptInputs(\n sessionStore: import('../../session/store.js').SessionStore,\n sessionKey: string,\n): Promise<{\n sessionId: string;\n sessionKey: string;\n}> {\n return sessionStore.resolveTranscriptPath(sessionKey);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-runner.js","names":[],"sources":["../../../../src/agent/embedded/session-runner.ts"],"sourcesContent":["import type { AgentTool } from '@earendil-works/pi-agent-core';\nimport type { ThinkingLevel } from '@earendil-works/pi-agent-core';\nimport {\n createAgentSession,\n DefaultResourceLoader,\n getAgentDir,\n ModelRuntime,\n SettingsManager,\n type AgentSession,\n} from '@earendil-works/pi-coding-agent';\nimport type { Model, Api } from '@earendil-works/pi-ai';\n\nimport { createLogger } from '../../utils/logger.js';\nimport { guardSessionManager, type GuardedPiTranscriptManager } from './session-tool-result-guard.js';\nimport { transformUserMessageForPersistence } from '../inbound/attachment-pipeline.js';\nimport { openSqliteHydratingSessionManager } from './sqlite-hydrating-session-manager.js';\nimport { applyXopcProviderApiKey, createEmbeddedCredentialStore } from './xopc-auth-storage.js';\nimport { wrapStreamFnForXopcExtensions } from './xopc-stream-bridge.js';\nimport { xopcToolsToDefinitions } from './xopc-tools-bridge.js';\nimport { applySystemPromptOverrideToSession } from './system-prompt-override.js';\n\nconst log = createLogger('EmbeddedSessionRunner');\n\nconst DEFAULT_IDLE_TTL_MS = 5 * 60_000;\n\nexport type EmbeddedRunnerFingerprintInput = {\n sessionId: string;\n workspaceDir: string;\n modelRef: string;\n toolNames: readonly string[];\n systemPrompt: string;\n thinkingLevel: string;\n};\n\nexport function buildEmbeddedRunnerFingerprint(input: EmbeddedRunnerFingerprintInput): string {\n const tools = [...input.toolNames].sort().join('\\0');\n const promptMarker = `${input.systemPrompt.length}:${input.systemPrompt.slice(0, 128)}`;\n return [\n input.sessionId,\n input.workspaceDir,\n input.modelRef,\n tools,\n promptMarker,\n input.thinkingLevel,\n ].join('\u001f');\n}\n\ntype PooledRunner = {\n sessionKey: string;\n fingerprint: string;\n session: AgentSession;\n piSm: GuardedPiTranscriptManager;\n settingsManager: SettingsManager;\n baseStreamFn: AgentSession['agent']['streamFn'];\n lastUsedAt: number;\n idleTimer: ReturnType<typeof setTimeout> | null;\n};\n\nexport type AcquireEmbeddedSessionRunnerParams = {\n sessionKey: string;\n sessionId: string;\n workspaceDir: string;\n model: Model<Api>;\n modelRef: string;\n tools: AgentTool[];\n systemPrompt: string;\n thinkingLevel: ThinkingLevel;\n};\n\nexport type AcquiredEmbeddedSessionRunner = {\n session: AgentSession;\n piSm: GuardedPiTranscriptManager;\n reused: boolean;\n release: () => void;\n};\n\nexport interface EmbeddedSessionRunnerPoolStats {\n acquires: number;\n reuses: number;\n creates: number;\n evictions: number;\n pooled: number;\n}\n\nexport function isEmbeddedSessionRunnerEnabled(): boolean {\n const raw = process.env.XOPC_SESSION_RUNNER?.trim().toLowerCase();\n if (raw === '0' || raw === 'false' || raw === 'off') {\n return false;\n }\n return true;\n}\n\nexport function getEmbeddedSessionRunnerIdleTtlMs(): number {\n const raw = process.env.XOPC_SESSION_RUNNER_TTL_MS?.trim();\n if (!raw) {\n return DEFAULT_IDLE_TTL_MS;\n }\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_IDLE_TTL_MS;\n}\n\nfunction createEmbeddedSettingsManager(cwd: string): SettingsManager {\n const sm = SettingsManager.inMemory({ compaction: { enabled: false } });\n sm.setCompactionEnabled(false);\n void cwd;\n return sm;\n}\n\nexport interface EmbeddedSessionRunnerPoolOptions {\n /** Override for the env-driven enable flag (testing). */\n isEnabled?: () => boolean;\n /** Override for the env-driven idle TTL (testing). */\n getIdleTtlMs?: () => number;\n}\n\n/**\n * Owns the per-session pool of pi `AgentSession` runners. The class is the supported,\n * injectable owner; {@link defaultEmbeddedSessionRunnerPool} keeps the historic\n * module-level free functions working until every caller is migrated to DI.\n */\nexport class EmbeddedSessionRunnerPool {\n private readonly pool = new Map<string, PooledRunner>();\n private readonly isEnabledFn: () => boolean;\n private readonly getIdleTtlMsFn: () => number;\n\n private stats: Omit<EmbeddedSessionRunnerPoolStats, 'pooled'> = {\n acquires: 0,\n reuses: 0,\n creates: 0,\n evictions: 0,\n };\n\n constructor(opts: EmbeddedSessionRunnerPoolOptions = {}) {\n this.isEnabledFn = opts.isEnabled ?? isEmbeddedSessionRunnerEnabled;\n this.getIdleTtlMsFn = opts.getIdleTtlMs ?? getEmbeddedSessionRunnerIdleTtlMs;\n }\n\n getStats(): Readonly<EmbeddedSessionRunnerPoolStats> {\n return { ...this.stats, pooled: this.pool.size };\n }\n\n resetForTest(): void {\n for (const entry of this.pool.values()) {\n this.clearIdleTimer(entry);\n }\n this.pool.clear();\n this.stats = { acquires: 0, reuses: 0, creates: 0, evictions: 0 };\n }\n\n evict(sessionKey: string, reason = 'explicit'): void {\n const entry = this.pool.get(sessionKey);\n if (!entry) {\n return;\n }\n this.disposePooledRunner(sessionKey, entry, reason);\n }\n\n evictAll(reason = 'dispose_all'): void {\n for (const sessionKey of [...this.pool.keys()]) {\n this.evict(sessionKey, reason);\n }\n }\n\n async acquire(params: AcquireEmbeddedSessionRunnerParams): Promise<AcquiredEmbeddedSessionRunner> {\n this.stats.acquires += 1;\n\n const fingerprint = buildEmbeddedRunnerFingerprint({\n sessionId: params.sessionId,\n workspaceDir: params.workspaceDir,\n modelRef: params.modelRef,\n toolNames: params.tools.map((t) => t.name),\n systemPrompt: params.systemPrompt,\n thinkingLevel: params.thinkingLevel ?? 'medium',\n });\n\n const reuseEnabled = this.isEnabledFn();\n const existing = this.pool.get(params.sessionKey);\n\n let entry: PooledRunner;\n let reused = false;\n\n if (reuseEnabled && existing && existing.fingerprint === fingerprint) {\n this.clearIdleTimer(existing);\n entry = existing;\n entry.lastUsedAt = Date.now();\n reused = true;\n this.stats.reuses += 1;\n applySystemPromptOverrideToSession(entry.session, params.systemPrompt);\n entry.session.agent.streamFn = entry.baseStreamFn;\n log.debug({ sessionKey: params.sessionKey }, 'Reusing pooled embedded session runner');\n } else {\n if (existing) {\n this.disposePooledRunner(params.sessionKey, existing, 'fingerprint_mismatch');\n }\n entry = await this.createPooledRunner(params);\n this.pool.set(params.sessionKey, entry);\n this.stats.creates += 1;\n log.debug({ sessionKey: params.sessionKey }, 'Created embedded session runner');\n }\n\n return {\n session: entry.session,\n piSm: entry.piSm,\n reused,\n release: () => {\n if (!this.isEnabledFn()) {\n this.disposePooledRunner(params.sessionKey, entry, 'runner_disabled');\n return;\n }\n entry.lastUsedAt = Date.now();\n this.scheduleIdleEviction(params.sessionKey, entry);\n },\n };\n }\n\n private clearIdleTimer(entry: PooledRunner): void {\n if (entry.idleTimer) {\n clearTimeout(entry.idleTimer);\n entry.idleTimer = null;\n }\n }\n\n private scheduleIdleEviction(sessionKey: string, entry: PooledRunner): void {\n this.clearIdleTimer(entry);\n const ttlMs = this.getIdleTtlMsFn();\n entry.idleTimer = setTimeout(() => {\n const current = this.pool.get(sessionKey);\n if (current === entry) {\n this.disposePooledRunner(sessionKey, entry, 'idle_ttl');\n }\n }, ttlMs);\n entry.idleTimer.unref?.();\n }\n\n private disposePooledRunner(sessionKey: string, entry: PooledRunner, reason: string): void {\n this.clearIdleTimer(entry);\n this.pool.delete(sessionKey);\n this.stats.evictions += 1;\n try {\n entry.piSm.flushPendingToolResults?.();\n } catch {\n /* ignore */\n }\n log.debug({ sessionKey, reason }, 'Embedded session runner evicted');\n }\n\n private async createPooledRunner(params: AcquireEmbeddedSessionRunnerParams): Promise<PooledRunner> {\n const { sessionKey, sessionId, workspaceDir, model, thinkingLevel, tools, systemPrompt } = params;\n\n const settingsManager = createEmbeddedSettingsManager(workspaceDir);\n\n const piSm = guardSessionManager(\n openSqliteHydratingSessionManager({\n sessionKey,\n sessionId,\n cwd: workspaceDir,\n }),\n {\n sessionKey,\n contextWindowTokens: model.contextWindow ?? 128_000,\n transformMessageForPersistence: (message) =>\n transformUserMessageForPersistence(sessionKey, message),\n },\n );\n\n const toolDefs = xopcToolsToDefinitions(tools);\n const toolNames = tools.map((t) => t.name);\n\n const modelRuntime = await ModelRuntime.create({\n credentials: createEmbeddedCredentialStore(),\n });\n await applyXopcProviderApiKey(modelRuntime, model.provider);\n\n const resourceLoader = new DefaultResourceLoader({\n cwd: workspaceDir,\n agentDir: getAgentDir(),\n settingsManager,\n noContextFiles: true,\n });\n await resourceLoader.reload();\n\n const { session } = await createAgentSession({\n cwd: workspaceDir,\n model,\n thinkingLevel: thinkingLevel ?? 'medium',\n sessionManager: piSm,\n settingsManager,\n modelRuntime,\n resourceLoader,\n noTools: 'builtin',\n customTools: toolDefs,\n tools: toolNames,\n });\n\n applySystemPromptOverrideToSession(session, systemPrompt);\n const baseStreamFn = wrapStreamFnForXopcExtensions(session.agent.streamFn);\n session.agent.streamFn = baseStreamFn;\n\n const fingerprint = buildEmbeddedRunnerFingerprint({\n sessionId,\n workspaceDir,\n modelRef: params.modelRef,\n toolNames,\n systemPrompt,\n thinkingLevel: thinkingLevel ?? 'medium',\n });\n\n return {\n sessionKey,\n fingerprint,\n session,\n piSm,\n settingsManager,\n baseStreamFn,\n lastUsedAt: Date.now(),\n idleTimer: null,\n };\n }\n}\n\nexport const defaultEmbeddedSessionRunnerPool = new EmbeddedSessionRunnerPool();\n\nexport function getEmbeddedSessionRunnerStats(): Readonly<EmbeddedSessionRunnerPoolStats> {\n return defaultEmbeddedSessionRunnerPool.getStats();\n}\n\nexport function resetEmbeddedSessionRunnerForTest(): void {\n defaultEmbeddedSessionRunnerPool.resetForTest();\n}\n\nexport function evictEmbeddedSessionRunner(sessionKey: string, reason = 'explicit'): void {\n defaultEmbeddedSessionRunnerPool.evict(sessionKey, reason);\n}\n\nexport function evictAllEmbeddedSessionRunners(reason = 'dispose_all'): void {\n defaultEmbeddedSessionRunnerPool.evictAll(reason);\n}\n\nexport function acquireEmbeddedSessionRunner(\n params: AcquireEmbeddedSessionRunnerParams,\n): Promise<AcquiredEmbeddedSessionRunner> {\n return defaultEmbeddedSessionRunnerPool.acquire(params);\n}\n\n/** Resolve session identity used by embedded runner acquire and turn execution. */\nexport async function resolveEmbeddedTranscriptInputs(\n sessionStore: import('../../session/store.js').SessionStore,\n sessionKey: string,\n): Promise<{\n sessionId: string;\n sessionKey: string;\n}> {\n return sessionStore.resolveTranscriptPath(sessionKey);\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InMemoryCredentialStore } from '@earendil-works/pi-ai';
|
|
2
|
+
import type { ModelRuntime } from '@earendil-works/pi-coding-agent';
|
|
2
3
|
/**
|
|
3
4
|
* Resolve API keys the same way as {@link AgentManager} / gateway settings:
|
|
4
5
|
* auth-profiles (agent + global), OAuth files, models.json, then env.
|
|
@@ -8,9 +9,9 @@ export declare function resolveXopcProviderApiKey(providerId: string): string |
|
|
|
8
9
|
* pi-coding-agent {@link createAgentSession} defaults to `~/.pi/agent/auth.json` and env.
|
|
9
10
|
* Gateway / webchat turns inject xopc credentials through {@link applyXopcProviderApiKey}.
|
|
10
11
|
*/
|
|
11
|
-
export declare function
|
|
12
|
+
export declare function createEmbeddedCredentialStore(): InMemoryCredentialStore;
|
|
12
13
|
/**
|
|
13
14
|
* Inject the resolved key as a runtime override (highest-priority, in-memory only) before
|
|
14
15
|
* the session starts so request-time auth resolution finds it.
|
|
15
16
|
*/
|
|
16
|
-
export declare function applyXopcProviderApiKey(
|
|
17
|
+
export declare function applyXopcProviderApiKey(modelRuntime: Pick<ModelRuntime, 'setRuntimeApiKey'>, providerId: string): Promise<void>;
|