@xopcai/xopc 0.0.8 → 0.0.11
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/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/gateway/static/root/assets/{agents-BSNzJWbQ.js → agents-BdC4Y-HX.js} +2 -2
- package/dist/gateway/static/root/assets/agents-BdC4Y-HX.js.map +1 -0
- package/dist/gateway/static/root/assets/{apps-page-BKk9SB4D.js → apps-page-C-oaSHkm.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-BKk9SB4D.js.map → apps-page-C-oaSHkm.js.map} +1 -1
- package/dist/gateway/static/root/assets/attachment-load-BDDlItdE.js +1 -0
- package/dist/gateway/static/root/assets/{channels-settings-_J6cQN6G.js → channels-settings-BqEUppPO.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-settings-_J6cQN6G.js.map → channels-settings-BqEUppPO.js.map} +1 -1
- package/dist/gateway/static/root/assets/{chat-agents-api-DPb_0O8M.js → chat-agents-api-BhqjQ7iL.js} +2 -2
- package/dist/gateway/static/root/assets/{chat-agents-api-DPb_0O8M.js.map → chat-agents-api-BhqjQ7iL.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BUJOuuKX.js → cron-page-Cli49RKR.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-BUJOuuKX.js.map → cron-page-Cli49RKR.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-Cn0YVg8x.js → cron-utils-Dkj-Ldpf.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-Cn0YVg8x.js.map → cron-utils-Dkj-Ldpf.js.map} +1 -1
- package/dist/gateway/static/root/assets/{electron-env-D9bm1FIu.js → electron-env-BDtJw9AY.js} +2 -2
- package/dist/gateway/static/root/assets/{electron-env-D9bm1FIu.js.map → electron-env-BDtJw9AY.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DTz4O5Ua.js → extension-debug-page-BMcZlaxF.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-DTz4O5Ua.js.map → extension-debug-page-BMcZlaxF.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-iframe-host-Cs1Kde9o.js → extension-iframe-host-D5HEF0KR.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-iframe-host-Cs1Kde9o.js.map → extension-iframe-host-D5HEF0KR.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-G52iX0Bo.js → extension-page-CXdCSSPl.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-G52iX0Bo.js.map → extension-page-CXdCSSPl.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-provider-CO2jxBA9.js → extension-provider-DZCZgQE2.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-provider-CO2jxBA9.js.map → extension-provider-DZCZgQE2.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D9Ul8uSt.js → extension-settings-page-CX6STpx3.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-D9Ul8uSt.js.map → extension-settings-page-CX6STpx3.js.map} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Bc8SVD15.js → gateway-config-swr-Cph02QZn.js} +2 -2
- package/dist/gateway/static/root/assets/{gateway-config-swr-Bc8SVD15.js.map → gateway-config-swr-Cph02QZn.js.map} +1 -1
- package/dist/gateway/static/root/assets/index-Bty3m0mS.css +2 -0
- package/dist/gateway/static/root/assets/{index-BXUJbteW.js → index-iTUyfzNr.js} +10 -10
- package/dist/gateway/static/root/assets/index-iTUyfzNr.js.map +1 -0
- package/dist/gateway/static/root/assets/{logs-page-5V25JkQY.js → logs-page-B9O5l3I8.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-5V25JkQY.js.map → logs-page-B9O5l3I8.js.map} +1 -1
- package/dist/gateway/static/root/assets/{model-selector-he3aQfme.js → model-selector-BLiY_O25.js} +2 -2
- package/dist/gateway/static/root/assets/{model-selector-he3aQfme.js.map → model-selector-BLiY_O25.js.map} +1 -1
- package/dist/gateway/static/root/assets/page-header-store-BFpnFTed.js +2 -0
- package/dist/gateway/static/root/assets/{page-header-store-DJHD9Ean.js.map → page-header-store-BFpnFTed.js.map} +1 -1
- package/dist/gateway/static/root/assets/{session-api-n-4O5d9U.js → session-api-DEhQXWJg.js} +2 -2
- package/dist/gateway/static/root/assets/{session-api-n-4O5d9U.js.map → session-api-DEhQXWJg.js.map} +1 -1
- package/dist/gateway/static/root/assets/{session-working-directory-control-B6dHLvbr.js → session-working-directory-control-DKOtWs3-.js} +2 -2
- package/dist/gateway/static/root/assets/{session-working-directory-control-B6dHLvbr.js.map → session-working-directory-control-DKOtWs3-.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-rBUfTdm3.js → sessions-page-BYlWP1ep.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-rBUfTdm3.js.map → sessions-page-BYlWP1ep.js.map} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-B3QrJm-E.js → settings-page-oCnIavdg.js} +2 -2
- package/dist/gateway/static/root/assets/settings-page-oCnIavdg.js.map +1 -0
- package/dist/gateway/static/root/assets/{skill-api-vxtE8kI6.js → skill-api-DWrn8Az0.js} +2 -2
- package/dist/gateway/static/root/assets/{skill-api-vxtE8kI6.js.map → skill-api-DWrn8Az0.js.map} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-D36_O2Ub.js → skills-page-C59WQpM1.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-D36_O2Ub.js.map → skills-page-C59WQpM1.js.map} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-CmiSsYBd.js → theme-store-CywXkKml.js} +2 -2
- package/dist/gateway/static/root/assets/{theme-store-CmiSsYBd.js.map → theme-store-CywXkKml.js.map} +1 -1
- package/dist/gateway/static/root/assets/url-D7yWllI8.js +2 -0
- package/dist/gateway/static/root/assets/url-D7yWllI8.js.map +1 -0
- package/dist/gateway/static/root/assets/{useTranslation-DYORQ7x6.js → useTranslation-CACj0DBJ.js} +2 -2
- package/dist/gateway/static/root/assets/{useTranslation-DYORQ7x6.js.map → useTranslation-CACj0DBJ.js.map} +1 -1
- package/dist/gateway/static/root/index.html +15 -15
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +1 -0
- package/dist/src/agent/agent-manager.js +20 -12
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/run-background-review.js +2 -0
- package/dist/src/agent/background-review/run-background-review.js.map +1 -1
- package/dist/src/agent/child-agent-factory.js +2 -0
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/context/expand-at-file-mentions.d.ts +4 -0
- package/dist/src/agent/context/expand-at-file-mentions.js +69 -0
- package/dist/src/agent/context/expand-at-file-mentions.js.map +1 -0
- package/dist/src/agent/context/workspace-seed.js +1 -1
- package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +1 -1
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/memory/compaction.d.ts +1 -1
- package/dist/src/agent/memory/compaction.js +38 -11
- package/dist/src/agent/memory/compaction.js.map +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +13 -0
- package/dist/src/agent/messaging/command-handler.js +14 -2
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +6 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
- package/dist/src/agent/service.d.ts +16 -1
- package/dist/src/agent/service.js +178 -20
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/skills/format-skills-prompt.js.map +1 -1
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/browser/tools.js.map +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-tool.js.map +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/index.d.ts +1 -1
- package/dist/src/channels/index.js +2 -2
- package/dist/src/channels/pipeline.d.ts +8 -1
- package/dist/src/channels/pipeline.js +49 -4
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.d.ts +4 -0
- package/dist/src/chat-commands/builtins/config.js +197 -0
- package/dist/src/chat-commands/builtins/config.js.map +1 -0
- package/dist/src/chat-commands/builtins/context.d.ts +4 -0
- package/dist/src/chat-commands/builtins/context.js +44 -0
- package/dist/src/chat-commands/builtins/context.js.map +1 -0
- package/dist/src/chat-commands/builtins/session.js +111 -0
- package/dist/src/chat-commands/builtins/session.js.map +1 -1
- package/dist/src/chat-commands/builtins/thinking.js +49 -21
- package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
- package/dist/src/chat-commands/config-paths.d.ts +10 -0
- package/dist/src/chat-commands/config-paths.js +45 -0
- package/dist/src/chat-commands/config-paths.js.map +1 -0
- package/dist/src/chat-commands/config-value.d.ts +12 -0
- package/dist/src/chat-commands/config-value.js +53 -0
- package/dist/src/chat-commands/config-value.js.map +1 -0
- package/dist/src/chat-commands/context.d.ts +24 -1
- package/dist/src/chat-commands/context.js +41 -0
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +2 -0
- package/dist/src/chat-commands/index.js +5 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +33 -1
- package/dist/src/cli/commands/agent/interactive.js +1 -1
- package/dist/src/cli/commands/agent/interactive.js.map +1 -1
- package/dist/src/cli/commands/agent.js +22 -10
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/auth.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/extension.js +10 -0
- package/dist/src/cli/commands/extension.js.map +1 -1
- package/dist/src/cli/commands/init.js +3 -4
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/update.d.ts +1 -0
- package/dist/src/cli/commands/update.js +171 -0
- package/dist/src/cli/commands/update.js.map +1 -0
- package/dist/src/cli/index.d.ts +1 -1
- package/dist/src/cli/index.js +3 -1
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/config/index.d.ts +1 -0
- package/dist/src/config/index.js +5 -4
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/runtime-overrides.d.ts +8 -0
- package/dist/src/config/runtime-overrides.js +40 -0
- package/dist/src/config/runtime-overrides.js.map +1 -0
- package/dist/src/config/schema.d.ts +35 -0
- package/dist/src/config/schema.js +19 -3
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.d.ts +1 -1
- package/dist/src/extensions/loader.js +6 -9
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/extensions/sdk/index.js +6 -1
- package/dist/src/extensions/sdk/index.js.map +1 -0
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/config.js +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +64 -11
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/public-gateway.js +10 -0
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/update.d.ts +3 -0
- package/dist/src/gateway/hono/routes/update.js +141 -0
- package/dist/src/gateway/hono/routes/update.js.map +1 -0
- package/dist/src/gateway/hono/routes/workspace.js +84 -4
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/service.d.ts +1 -0
- package/dist/src/gateway/service.js +16 -4
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.d.ts +5 -0
- package/dist/src/gateway/workspace-fs-file-list.js +56 -0
- package/dist/src/gateway/workspace-fs-file-list.js.map +1 -0
- package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +5 -0
- package/dist/src/gateway/workspace-ripgrep.js +88 -4
- package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
- package/dist/src/infra/update-channels.d.ts +14 -0
- package/dist/src/infra/update-channels.js +30 -0
- package/dist/src/infra/update-channels.js.map +1 -0
- package/dist/src/infra/update-check.d.ts +53 -0
- package/dist/src/infra/update-check.js +155 -0
- package/dist/src/infra/update-check.js.map +1 -0
- package/dist/src/infra/update-runner.d.ts +18 -0
- package/dist/src/infra/update-runner.js +112 -0
- package/dist/src/infra/update-runner.js.map +1 -0
- package/dist/src/infra/update-startup.d.ts +20 -0
- package/dist/src/infra/update-startup.js +246 -0
- package/dist/src/infra/update-startup.js.map +1 -0
- package/dist/src/providers/extension-stream-bridge.d.ts +3 -0
- package/dist/src/providers/extension-stream-bridge.js +239 -0
- package/dist/src/providers/extension-stream-bridge.js.map +1 -0
- package/dist/src/providers/index.d.ts +7 -2
- package/dist/src/providers/index.js +77 -14
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/plugin-registry.js +92 -87
- package/dist/src/providers/plugin-registry.js.map +1 -1
- package/dist/src/session/chat-export.d.ts +5 -0
- package/dist/src/session/chat-export.js +35 -0
- package/dist/src/session/chat-export.js.map +1 -0
- package/dist/src/session/config-store.js +1 -1
- package/dist/src/session/manager.d.ts +1 -1
- package/dist/src/session/manager.js +2 -2
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.d.ts +1 -1
- package/dist/src/session/store.js +5 -5
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/package.json +2 -1
- package/dist/gateway/static/root/assets/agents-BSNzJWbQ.js.map +0 -1
- package/dist/gateway/static/root/assets/attachment-load-DXcJLSWT.js +0 -1
- package/dist/gateway/static/root/assets/index-BXUJbteW.js.map +0 -1
- package/dist/gateway/static/root/assets/index-CQLMxWSA.css +0 -2
- package/dist/gateway/static/root/assets/page-header-store-DJHD9Ean.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-B3QrJm-E.js.map +0 -1
- package/dist/gateway/static/root/assets/url-CtSqjF9J.js +0 -2
- package/dist/gateway/static/root/assets/url-CtSqjF9J.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-orchestrator.js","names":[],"sources":["../../../../src/agent/orchestration/agent-orchestrator.ts"],"sourcesContent":["/**\n * Agent Orchestrator - Coordinates Agent execution flow\n *\n * Manages the complete agent execution pipeline from message processing\n * to response generation.\n */\n\nimport type { Agent, AgentMessage } from '@mariozechner/pi-agent-core';\nimport type { Config } from '../../config/schema.js';\nimport type { InboundMessage } from '../../infra/bus/index.js';\nimport type { SessionConfigStore, SessionStore } from '../../session/index.js';\nimport { resolveEffectiveThinkingLevel } from '../../session/thinking-resolve.js';\nimport type { ThinkLevel } from '../transcript/thinking-types.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionContext } from '../session/session-context.js';\nimport type { AgentEventHandler } from './agent-event-handler.js';\nimport type { FeedbackCoordinator } from '../feedback/feedback-coordinator.js';\nimport type { AgentManager } from '../agent-manager.js';\nimport { sanitizeMessages, cleanTrailingErrors } from '../memory/message-sanitizer.js';\nimport {\n tryApplySessionTranscriptHygiene,\n tryApplySessionTranscriptHygieneForPersistence,\n} from '../transcript/transcript-hygiene.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { extractAgentUserPlainText } from '../memory/user-message-text.js';\nimport { runAgentTurnWithModelFallbacks } from './run-agent-turn-with-fallbacks.js';\nimport {\n persistInboundAttachmentsToWorkspace,\n formatInboundFileTextBlock,\n} from '../../channels/attachments/inbound-persist.js';\nimport { resolveInboundImageContentParts } from '../image/inbound-image-handling.js';\n\nconst log = createLogger('AgentOrchestrator');\n\nexport interface AgentOrchestratorConfig {\n agentManager: AgentManager;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n eventHandler: AgentEventHandler;\n feedbackCoordinator: FeedbackCoordinator;\n sessionConfigStore: SessionConfigStore;\n /** Load per-session workspace override and mkdir before creating the agent. */\n hydrateSessionWorkspaceFromStore?: (sessionKey: string) => Promise<void>;\n getThinkingDefault: () => ThinkLevel | undefined;\n /** Per-session default from merged `agents.list` / defaults (optional). */\n getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n /** Default workspace root when no per-session resolver is set. */\n workspaceRoot: string;\n /** Per-agent workspace root for attachments (optional; defaults to `workspaceRoot`). */\n getWorkspaceRootForSession?: (sessionKey: string) => string;\n /** Agent home (`…/agents/<id>/`) for inbound/TTS files — keeps internal state out of the markdown workspace. */\n getAgentInternalStorageRootForSession?: (sessionKey: string) => string;\n /** Fire-and-forget after full session persist (e.g. LLM session title); not called from mid-turn snapshots. */\n enqueueAutoTitle?: (sessionKey: string) => void;\n /** For per-turn timeout via `agents.defaults.maxTaskDurationMs`. */\n getConfig?: () => Config | undefined;\n}\n\nexport class AgentOrchestrator {\n private agentManager: AgentManager;\n private sessionStore: SessionStore;\n private modelManager: ModelManager;\n private eventHandler: AgentEventHandler;\n private feedbackCoordinator: FeedbackCoordinator;\n private sessionConfigStore: SessionConfigStore;\n private hydrateSessionWorkspaceFromStore?: (sessionKey: string) => Promise<void>;\n private getThinkingDefault: () => ThinkLevel | undefined;\n private getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n private workspaceRoot: string;\n private getWorkspaceRootForSession?: (sessionKey: string) => string;\n private getAgentInternalStorageRootForSession: (sessionKey: string) => string;\n private enqueueAutoTitle?: (sessionKey: string) => void;\n private getConfig?: () => Config | undefined;\n\n constructor(config: AgentOrchestratorConfig) {\n this.agentManager = config.agentManager;\n this.sessionStore = config.sessionStore;\n this.modelManager = config.modelManager;\n this.eventHandler = config.eventHandler;\n this.feedbackCoordinator = config.feedbackCoordinator;\n this.sessionConfigStore = config.sessionConfigStore;\n this.hydrateSessionWorkspaceFromStore = config.hydrateSessionWorkspaceFromStore;\n this.getThinkingDefault = config.getThinkingDefault;\n this.getThinkingDefaultForSession = config.getThinkingDefaultForSession;\n this.workspaceRoot = config.workspaceRoot;\n this.getWorkspaceRootForSession = config.getWorkspaceRootForSession;\n this.getAgentInternalStorageRootForSession =\n config.getAgentInternalStorageRootForSession ??\n ((sk) => this.getWorkspaceRootForSession?.(sk) ?? this.workspaceRoot);\n this.enqueueAutoTitle = config.enqueueAutoTitle;\n this.getConfig = config.getConfig;\n }\n\n private async hydrateSessionModelFromStore(sessionKey: string): Promise<void> {\n const cfg = await this.sessionConfigStore.get(sessionKey);\n if (cfg?.modelOverride) {\n await this.modelManager.switchModelForSession(sessionKey, cfg.modelOverride);\n }\n }\n\n /**\n * Process a message through the agent orchestration pipeline\n */\n async process(msg: InboundMessage, context: SessionContext): Promise<void> {\n const { sessionKey } = context;\n\n log.debug({ sessionKey }, 'Processing message through agent orchestrator');\n\n await this.hydrateSessionWorkspaceFromStore?.(sessionKey);\n\n // Get or create agent for this session\n const agent = this.agentManager.getOrCreateAgent(sessionKey);\n\n try {\n await this.hydrateSessionModelFromStore(sessionKey);\n\n // 1. Load session history\n let messages = await this.sessionStore.load(sessionKey);\n\n // Clean any trailing errors from previous sessions (defensive)\n messages = cleanTrailingErrors(messages);\n\n try {\n const model = this.modelManager.getResolvedModelForSession(sessionKey);\n messages = tryApplySessionTranscriptHygiene(messages, model);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Transcript hygiene skipped (model resolve failed)');\n }\n\n agent.state.messages = messages;\n\n // 2. Apply model configuration for session\n await this.modelManager.applyModelForSession(agent, sessionKey);\n\n const thinkingDefault =\n this.getThinkingDefaultForSession?.(sessionKey) ?? this.getThinkingDefault();\n const thinkingLevel = await resolveEffectiveThinkingLevel(\n this.sessionConfigStore,\n sessionKey,\n null,\n thinkingDefault,\n );\n this.agentManager.setThinkingLevel(sessionKey, thinkingLevel);\n\n // 3. Persist inbound files (Telegram, etc.) under agent home, then build user message\n const storageRoot = this.getAgentInternalStorageRootForSession(sessionKey);\n const persistedAttachments = await persistInboundAttachmentsToWorkspace(\n storageRoot,\n sessionKey,\n msg.attachments,\n );\n const userMessage = await this.buildUserMessage(\n {\n ...msg,\n attachments: persistedAttachments ?? msg.attachments,\n },\n sessionKey,\n );\n const userPlainForMemory = extractAgentUserPlainText(userMessage);\n const userMessageForModel = await this.agentManager.applyMemoryPrefetchToUserMessage(\n userMessage,\n sessionKey,\n );\n\n // 4. Start task feedback\n this.feedbackCoordinator.startTask();\n\n // 5. Execute agent\n await this.executeAgent(agent, userMessageForModel, context);\n\n this.agentManager.afterAgentTurn(sessionKey, userPlainForMemory);\n this.agentManager.scheduleBackgroundReviewAfterUserTurn(sessionKey);\n\n // 6. Sanitize messages before saving (remove error messages, empty content)\n const rawMessages = agent.state.messages;\n const { messages: sanitizedMessages, removed } = sanitizeMessages(rawMessages);\n\n if (removed > 0) {\n log.info({ sessionKey, removed }, 'Removed problematic messages before saving');\n }\n\n // 7. Save session messages (transcript hygiene)\n await this.saveSessionSnapshot(sessionKey, sanitizedMessages);\n\n this.enqueueAutoTitle?.(sessionKey);\n\n // 8. End task feedback\n this.feedbackCoordinator.endTask();\n\n } catch (error) {\n log.error({ err: error, sessionKey }, 'Error in agent orchestration');\n this.feedbackCoordinator.endTask();\n throw error;\n }\n }\n\n /**\n * Transcript hygiene + persist. Expects messages already passed through {@link sanitizeMessages}.\n * Keeps thinking blocks on disk for UI; agent load path applies full hygiene including dropThinking.\n */\n private async saveSessionSnapshot(sessionKey: string, messages: AgentMessage[]): Promise<void> {\n let toPersist = messages;\n try {\n const model = this.modelManager.getResolvedModelForSession(sessionKey);\n toPersist = tryApplySessionTranscriptHygieneForPersistence(messages, model);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Transcript hygiene on save skipped');\n }\n await this.sessionStore.save(sessionKey, toPersist);\n }\n\n /**\n * Execute the agent with a user message (primary model, then `agents.defaults.model.fallbacks` on failure).\n */\n private async executeAgent(\n agent: Agent,\n userMessage: AgentMessage,\n context: SessionContext\n ): Promise<void> {\n const sessionKey = context.sessionKey;\n await runAgentTurnWithModelFallbacks({\n agent,\n sessionKey,\n modelManager: this.modelManager,\n userMessage,\n log,\n getConfig: this.getConfig,\n beforeUserPrompt: () => this.agentManager.beginBackgroundReviewUserTurn(sessionKey),\n afterUserPrompt: async () => {\n try {\n const { messages: sanitizedTurn } = sanitizeMessages(agent.state.messages);\n await this.saveSessionSnapshot(sessionKey, sanitizedTurn);\n log.debug({ sessionKey }, 'User message saved immediately after prompt');\n } catch (err) {\n log.warn({ err, sessionKey }, 'Failed to save user message immediately');\n }\n },\n });\n }\n\n /**\n * Build an agent message from an inbound message\n */\n private async buildUserMessage(msg: InboundMessage, sessionKey: string): Promise<AgentMessage> {\n const storageRootAbs = this.getAgentInternalStorageRootForSession(sessionKey);\n const textBody = msg.content.trimStart().startsWith('/skill:')\n ? this.agentManager.expandSkillUserText(msg.content)\n : msg.content;\n\n if (!msg.attachments || msg.attachments.length === 0) {\n return {\n role: 'user',\n content: textBody,\n timestamp: Date.now(),\n };\n }\n\n const modelRef = this.modelManager.getModelForSession(sessionKey);\n const cfg = this.getConfig?.();\n\n const messageContent: Array<\n { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }\n > = [];\n\n if (msg.content.trim()) {\n messageContent.push({ type: 'text', text: textBody });\n }\n\n const attachments = msg.attachments;\n let i = 0;\n while (i < attachments.length) {\n const att = attachments[i]!;\n const isImage =\n att.type === 'image' || att.type === 'photo' || Boolean(att.mimeType?.startsWith('image/'));\n\n if (isImage) {\n const group: Array<{ data: string; mimeType: string }> = [];\n while (i < attachments.length) {\n const a = attachments[i]!;\n const img =\n a.type === 'image' || a.type === 'photo' || Boolean(a.mimeType?.startsWith('image/'));\n if (!img) {\n break;\n }\n if (!a.data || a.data.length === 0) {\n log.warn({ type: a.type, name: a.name }, 'Empty image data, skipping');\n i += 1;\n continue;\n }\n group.push({ data: a.data, mimeType: a.mimeType || 'image/jpeg' });\n i += 1;\n }\n if (group.length > 0) {\n const parts = await resolveInboundImageContentParts({\n modelRef,\n cfg,\n userTextForContext: msg.content.trim() ? textBody : '',\n images: group,\n });\n messageContent.push(...parts);\n }\n } else {\n const fileBlock = formatInboundFileTextBlock(\n {\n type: att.type,\n mimeType: att.mimeType,\n name: att.name,\n size: att.size,\n workspaceRelativePath: att.workspaceRelativePath,\n },\n storageRootAbs,\n );\n messageContent.push({ type: 'text', text: fileBlock });\n i += 1;\n }\n }\n\n const hasText = messageContent.some((item) => item.type === 'text');\n const hasImage = messageContent.some((item) => item.type === 'image');\n if (hasImage && !hasText) {\n messageContent.unshift({ type: 'text', text: 'Please analyze the image(s) I sent.' });\n }\n\n if (messageContent.length === 0) {\n log.warn(\n { attachmentCount: msg.attachments.length },\n 'All attachments were skipped, falling back to text message',\n );\n return {\n role: 'user',\n content: textBody || '[Image attachment could not be processed]',\n timestamp: Date.now(),\n };\n }\n\n return {\n role: 'user',\n content: messageContent,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Get the current agent model ID\n */\n getCurrentModel(): string {\n return this.modelManager.getCurrentModel();\n }\n\n /**\n * Check if agent is currently processing for a session\n */\n isProcessing(sessionKey: string): boolean {\n const agent = this.agentManager.getAgent(sessionKey);\n if (!agent) {\n return false;\n }\n return agent.state.messages.length > 0;\n }\n\n /**\n * Abort current agent execution for a session\n */\n abort(sessionKey: string): void {\n const agent = this.agentManager.getAgent(sessionKey);\n if (agent) {\n agent.abort();\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-orchestrator.js","names":[],"sources":["../../../../src/agent/orchestration/agent-orchestrator.ts"],"sourcesContent":["/**\n * Agent Orchestrator - Coordinates Agent execution flow\n *\n * Manages the complete agent execution pipeline from message processing\n * to response generation.\n */\n\nimport type { Agent, AgentMessage } from '@mariozechner/pi-agent-core';\nimport type { Config } from '../../config/schema.js';\nimport type { InboundMessage } from '../../infra/bus/index.js';\nimport type { SessionConfigStore, SessionStore } from '../../session/index.js';\nimport { resolveEffectiveThinkingLevel } from '../../session/thinking-resolve.js';\nimport type { ThinkLevel } from '../transcript/thinking-types.js';\nimport type { ModelManager } from '../models/index.js';\nimport type { SessionContext } from '../session/session-context.js';\nimport type { AgentEventHandler } from './agent-event-handler.js';\nimport type { FeedbackCoordinator } from '../feedback/feedback-coordinator.js';\nimport type { AgentManager } from '../agent-manager.js';\nimport { sanitizeMessages, cleanTrailingErrors } from '../memory/message-sanitizer.js';\nimport {\n tryApplySessionTranscriptHygiene,\n tryApplySessionTranscriptHygieneForPersistence,\n} from '../transcript/transcript-hygiene.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { extractAgentUserPlainText } from '../memory/user-message-text.js';\nimport { runAgentTurnWithModelFallbacks } from './run-agent-turn-with-fallbacks.js';\nimport {\n persistInboundAttachmentsToWorkspace,\n formatInboundFileTextBlock,\n} from '../../channels/attachments/inbound-persist.js';\nimport { expandAtFileMentionsInPlainText } from '../context/expand-at-file-mentions.js';\nimport { resolveInboundImageContentParts } from '../image/inbound-image-handling.js';\n\nconst log = createLogger('AgentOrchestrator');\n\nexport interface AgentOrchestratorConfig {\n agentManager: AgentManager;\n sessionStore: SessionStore;\n modelManager: ModelManager;\n eventHandler: AgentEventHandler;\n feedbackCoordinator: FeedbackCoordinator;\n sessionConfigStore: SessionConfigStore;\n /** Load per-session workspace override and mkdir before creating the agent. */\n hydrateSessionWorkspaceFromStore?: (sessionKey: string) => Promise<void>;\n getThinkingDefault: () => ThinkLevel | undefined;\n /** Per-session default from merged `agents.list` / defaults (optional). */\n getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n /** Default workspace root when no per-session resolver is set. */\n workspaceRoot: string;\n /** Per-agent workspace root for attachments (optional; defaults to `workspaceRoot`). */\n getWorkspaceRootForSession?: (sessionKey: string) => string;\n /** Agent home (`…/agents/<id>/`) for inbound/TTS files — keeps internal state out of the markdown workspace. */\n getAgentInternalStorageRootForSession?: (sessionKey: string) => string;\n /** Fire-and-forget after full session persist (e.g. LLM session title); not called from mid-turn snapshots. */\n enqueueAutoTitle?: (sessionKey: string) => void;\n /** For per-turn timeout via `agents.defaults.maxTaskDurationMs`. */\n getConfig?: () => Config | undefined;\n}\n\nexport class AgentOrchestrator {\n private agentManager: AgentManager;\n private sessionStore: SessionStore;\n private modelManager: ModelManager;\n private eventHandler: AgentEventHandler;\n private feedbackCoordinator: FeedbackCoordinator;\n private sessionConfigStore: SessionConfigStore;\n private hydrateSessionWorkspaceFromStore?: (sessionKey: string) => Promise<void>;\n private getThinkingDefault: () => ThinkLevel | undefined;\n private getThinkingDefaultForSession?: (sessionKey: string) => ThinkLevel | undefined;\n private workspaceRoot: string;\n private getWorkspaceRootForSession?: (sessionKey: string) => string;\n private getAgentInternalStorageRootForSession: (sessionKey: string) => string;\n private enqueueAutoTitle?: (sessionKey: string) => void;\n private getConfig?: () => Config | undefined;\n\n constructor(config: AgentOrchestratorConfig) {\n this.agentManager = config.agentManager;\n this.sessionStore = config.sessionStore;\n this.modelManager = config.modelManager;\n this.eventHandler = config.eventHandler;\n this.feedbackCoordinator = config.feedbackCoordinator;\n this.sessionConfigStore = config.sessionConfigStore;\n this.hydrateSessionWorkspaceFromStore = config.hydrateSessionWorkspaceFromStore;\n this.getThinkingDefault = config.getThinkingDefault;\n this.getThinkingDefaultForSession = config.getThinkingDefaultForSession;\n this.workspaceRoot = config.workspaceRoot;\n this.getWorkspaceRootForSession = config.getWorkspaceRootForSession;\n this.getAgentInternalStorageRootForSession =\n config.getAgentInternalStorageRootForSession ??\n ((sk) => this.getWorkspaceRootForSession?.(sk) ?? this.workspaceRoot);\n this.enqueueAutoTitle = config.enqueueAutoTitle;\n this.getConfig = config.getConfig;\n }\n\n private async hydrateSessionModelFromStore(sessionKey: string): Promise<void> {\n const cfg = await this.sessionConfigStore.get(sessionKey);\n if (cfg?.modelOverride) {\n await this.modelManager.switchModelForSession(sessionKey, cfg.modelOverride);\n }\n }\n\n /**\n * Process a message through the agent orchestration pipeline\n */\n async process(msg: InboundMessage, context: SessionContext): Promise<void> {\n const { sessionKey } = context;\n\n log.debug({ sessionKey }, 'Processing message through agent orchestrator');\n\n await this.hydrateSessionWorkspaceFromStore?.(sessionKey);\n\n // Get or create agent for this session\n const agent = this.agentManager.getOrCreateAgent(sessionKey);\n\n try {\n await this.hydrateSessionModelFromStore(sessionKey);\n\n // 1. Load session history\n let messages = await this.sessionStore.load(sessionKey);\n\n // Clean any trailing errors from previous sessions (defensive)\n messages = cleanTrailingErrors(messages);\n\n try {\n const model = this.modelManager.getResolvedModelForSession(sessionKey);\n messages = tryApplySessionTranscriptHygiene(messages, model);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Transcript hygiene skipped (model resolve failed)');\n }\n\n agent.state.messages = messages;\n\n // 2. Apply model configuration for session\n await this.modelManager.applyModelForSession(agent, sessionKey);\n\n const thinkingDefault =\n this.getThinkingDefaultForSession?.(sessionKey) ?? this.getThinkingDefault();\n const thinkingLevel = await resolveEffectiveThinkingLevel(\n this.sessionConfigStore,\n sessionKey,\n null,\n thinkingDefault,\n );\n this.agentManager.setThinkingLevel(sessionKey, thinkingLevel);\n\n // 3. Persist inbound files (Telegram, etc.) under agent home, then build user message\n const storageRoot = this.getAgentInternalStorageRootForSession(sessionKey);\n const persistedAttachments = await persistInboundAttachmentsToWorkspace(\n storageRoot,\n sessionKey,\n msg.attachments,\n );\n const userMessage = await this.buildUserMessage(\n {\n ...msg,\n attachments: persistedAttachments ?? msg.attachments,\n },\n sessionKey,\n );\n const userPlainForMemory = extractAgentUserPlainText(userMessage);\n const userMessageForModel = await this.agentManager.applyMemoryPrefetchToUserMessage(\n userMessage,\n sessionKey,\n );\n\n // 4. Start task feedback\n this.feedbackCoordinator.startTask();\n\n // 5. Execute agent\n await this.executeAgent(agent, userMessageForModel, context);\n\n this.agentManager.afterAgentTurn(sessionKey, userPlainForMemory);\n this.agentManager.scheduleBackgroundReviewAfterUserTurn(sessionKey);\n\n // 6. Sanitize messages before saving (remove error messages, empty content)\n const rawMessages = agent.state.messages;\n const { messages: sanitizedMessages, removed } = sanitizeMessages(rawMessages);\n\n if (removed > 0) {\n log.info({ sessionKey, removed }, 'Removed problematic messages before saving');\n }\n\n // 7. Save session messages (transcript hygiene)\n await this.saveSessionSnapshot(sessionKey, sanitizedMessages);\n\n this.enqueueAutoTitle?.(sessionKey);\n\n // 8. End task feedback\n this.feedbackCoordinator.endTask();\n\n } catch (error) {\n log.error({ err: error, sessionKey }, 'Error in agent orchestration');\n this.feedbackCoordinator.endTask();\n throw error;\n }\n }\n\n /**\n * Transcript hygiene + persist. Expects messages already passed through {@link sanitizeMessages}.\n * Keeps thinking blocks on disk for UI; agent load path applies full hygiene including dropThinking.\n */\n private async saveSessionSnapshot(sessionKey: string, messages: AgentMessage[]): Promise<void> {\n let toPersist = messages;\n try {\n const model = this.modelManager.getResolvedModelForSession(sessionKey);\n toPersist = tryApplySessionTranscriptHygieneForPersistence(messages, model);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Transcript hygiene on save skipped');\n }\n await this.sessionStore.save(sessionKey, toPersist);\n }\n\n /**\n * Execute the agent with a user message (primary model, then `agents.defaults.model.fallbacks` on failure).\n */\n private async executeAgent(\n agent: Agent,\n userMessage: AgentMessage,\n context: SessionContext\n ): Promise<void> {\n const sessionKey = context.sessionKey;\n await runAgentTurnWithModelFallbacks({\n agent,\n sessionKey,\n modelManager: this.modelManager,\n userMessage,\n log,\n getConfig: this.getConfig,\n beforeUserPrompt: () => this.agentManager.beginBackgroundReviewUserTurn(sessionKey),\n afterUserPrompt: async () => {\n try {\n const { messages: sanitizedTurn } = sanitizeMessages(agent.state.messages);\n await this.saveSessionSnapshot(sessionKey, sanitizedTurn);\n log.debug({ sessionKey }, 'User message saved immediately after prompt');\n } catch (err) {\n log.warn({ err, sessionKey }, 'Failed to save user message immediately');\n }\n },\n });\n }\n\n /**\n * Build an agent message from an inbound message\n */\n private async buildUserMessage(msg: InboundMessage, sessionKey: string): Promise<AgentMessage> {\n const storageRootAbs = this.getAgentInternalStorageRootForSession(sessionKey);\n let textBody = msg.content.trimStart().startsWith('/skill:')\n ? this.agentManager.expandSkillUserText(msg.content)\n : msg.content;\n\n if (/@file:/.test(textBody)) {\n const root = this.agentManager.getResolvedWorkspaceForSession(sessionKey);\n textBody = await expandAtFileMentionsInPlainText(textBody, root);\n }\n\n if (!msg.attachments || msg.attachments.length === 0) {\n return {\n role: 'user',\n content: textBody,\n timestamp: Date.now(),\n };\n }\n\n const modelRef = this.modelManager.getModelForSession(sessionKey);\n const cfg = this.getConfig?.();\n\n const messageContent: Array<\n { type: 'text'; text: string } | { type: 'image'; data: string; mimeType: string }\n > = [];\n\n if (msg.content.trim()) {\n messageContent.push({ type: 'text', text: textBody });\n }\n\n const attachments = msg.attachments;\n let i = 0;\n while (i < attachments.length) {\n const att = attachments[i]!;\n const isImage =\n att.type === 'image' || att.type === 'photo' || Boolean(att.mimeType?.startsWith('image/'));\n\n if (isImage) {\n const group: Array<{ data: string; mimeType: string }> = [];\n while (i < attachments.length) {\n const a = attachments[i]!;\n const img =\n a.type === 'image' || a.type === 'photo' || Boolean(a.mimeType?.startsWith('image/'));\n if (!img) {\n break;\n }\n if (!a.data || a.data.length === 0) {\n log.warn({ type: a.type, name: a.name }, 'Empty image data, skipping');\n i += 1;\n continue;\n }\n group.push({ data: a.data, mimeType: a.mimeType || 'image/jpeg' });\n i += 1;\n }\n if (group.length > 0) {\n const parts = await resolveInboundImageContentParts({\n modelRef,\n cfg,\n userTextForContext: msg.content.trim() ? textBody : '',\n images: group,\n });\n messageContent.push(...parts);\n }\n } else {\n const fileBlock = formatInboundFileTextBlock(\n {\n type: att.type,\n mimeType: att.mimeType,\n name: att.name,\n size: att.size,\n workspaceRelativePath: att.workspaceRelativePath,\n },\n storageRootAbs,\n );\n messageContent.push({ type: 'text', text: fileBlock });\n i += 1;\n }\n }\n\n const hasText = messageContent.some((item) => item.type === 'text');\n const hasImage = messageContent.some((item) => item.type === 'image');\n if (hasImage && !hasText) {\n messageContent.unshift({ type: 'text', text: 'Please analyze the image(s) I sent.' });\n }\n\n if (messageContent.length === 0) {\n log.warn(\n { attachmentCount: msg.attachments.length },\n 'All attachments were skipped, falling back to text message',\n );\n return {\n role: 'user',\n content: textBody || '[Image attachment could not be processed]',\n timestamp: Date.now(),\n };\n }\n\n return {\n role: 'user',\n content: messageContent,\n timestamp: Date.now(),\n };\n }\n\n /**\n * Get the current agent model ID\n */\n getCurrentModel(): string {\n return this.modelManager.getCurrentModel();\n }\n\n /**\n * Check if agent is currently processing for a session\n */\n isProcessing(sessionKey: string): boolean {\n const agent = this.agentManager.getAgent(sessionKey);\n if (!agent) {\n return false;\n }\n return agent.state.messages.length > 0;\n }\n\n /**\n * Abort current agent execution for a session\n */\n abort(sessionKey: string): void {\n const agent = this.agentManager.getAgent(sessionKey);\n if (agent) {\n agent.abort();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { resolveStateDir } from "../../config/paths-state.js";
|
|
2
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { resolveStateDir } from "../../config/paths-state.js";
|
|
4
4
|
import { init_paths } from "../../config/paths.js";
|
|
5
5
|
import { DEFAULT_USER_FILENAME, toWorkspaceBootstrapFile } from "../context/workspace.js";
|
|
6
6
|
import { createSkillConfigManager } from "../skills/config.js";
|
|
@@ -5,6 +5,7 @@ import type { ChannelManager } from '../channels/manager.js';
|
|
|
5
5
|
import { type ReasoningLevel } from './transcript/thinking-types.js';
|
|
6
6
|
import { type SkillCatalogEntry } from './agent-manager.js';
|
|
7
7
|
import type { AgentServiceConfig, StreamHandle } from './service.types.js';
|
|
8
|
+
import type { CompactionResult } from './memory/compaction.js';
|
|
8
9
|
export type { AgentServiceConfig, AgentContext, StreamHandle } from './service.types.js';
|
|
9
10
|
export declare class AgentService {
|
|
10
11
|
private sessionStore;
|
|
@@ -42,6 +43,7 @@ export declare class AgentService {
|
|
|
42
43
|
/** Webchat SSE queue pushers for `clarify_request` and similar mid-turn UI events. */
|
|
43
44
|
private webchatSseEnqueueBySession;
|
|
44
45
|
private sessionUnsubscribers;
|
|
46
|
+
private effectiveAppConfig;
|
|
45
47
|
constructor(bus: MessageBus, config: AgentServiceConfig);
|
|
46
48
|
private attachmentRootsForSession;
|
|
47
49
|
private createSessionStore;
|
|
@@ -108,7 +110,20 @@ export declare class AgentService {
|
|
|
108
110
|
workspaceRelativePath?: string;
|
|
109
111
|
}> | undefined>;
|
|
110
112
|
private endDirectRequestContext;
|
|
111
|
-
compactSession(sessionKey: string,
|
|
113
|
+
compactSession(sessionKey: string, options?: {
|
|
114
|
+
instructions?: string;
|
|
115
|
+
force?: boolean;
|
|
116
|
+
}): Promise<CompactionResult>;
|
|
117
|
+
/**
|
|
118
|
+
* One-shot LLM answer for /btw: uses transcript as background only; does not persist to session.
|
|
119
|
+
*/
|
|
120
|
+
btwQuery(sessionKey: string, question: string): Promise<{
|
|
121
|
+
text: string;
|
|
122
|
+
error?: string;
|
|
123
|
+
}>;
|
|
124
|
+
private formatMessagesForBtw;
|
|
125
|
+
/** Markdown or JSON summary for /context (prompt assembly is approximated from config + transcript stats). */
|
|
126
|
+
getSessionContextReport(sessionKey: string, mode: 'list' | 'detail' | 'json'): Promise<string>;
|
|
112
127
|
getSessionStats(sessionKey: string, messages: AgentMessage[]): {
|
|
113
128
|
windowStats: {
|
|
114
129
|
total: number;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { init_agent_scope, resolveAgentBootstrapDir, resolveAgentHomeDir, resolveDefaultAgentId } from "./agent-scope.js";
|
|
2
|
-
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
3
|
-
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
4
|
-
import { extractProfileAgentId } from "../config/agent-profile.js";
|
|
5
1
|
import { runWithLogContext, updateAsyncLogContext } from "../utils/logger/context.js";
|
|
6
2
|
import { createLogger } from "../utils/logger/index.js";
|
|
7
3
|
import { init_logger } from "../utils/logger.js";
|
|
8
|
-
import {
|
|
4
|
+
import { init_agent_scope, resolveAgentBootstrapDir, resolveAgentHomeDir, resolveDefaultAgentId } from "./agent-scope.js";
|
|
5
|
+
import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
|
|
6
|
+
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
7
|
+
import { applyConfigOverrides } from "../config/runtime-overrides.js";
|
|
8
|
+
import { extractProfileAgentId, resolveEffectiveAgentProfileForSession } from "../config/agent-profile.js";
|
|
9
|
+
import { getDefaultModelSync, init_providers, resolveModel } from "../providers/index.js";
|
|
9
10
|
import { extractTextContent, loadBootstrapFiles } from "./context/workspace.js";
|
|
10
11
|
import { isTTSAvailable } from "../voice/tts/factory.js";
|
|
11
12
|
import { mergeTtsConfigFromAppConfig } from "../voice/tts/merge-config.js";
|
|
@@ -58,6 +59,7 @@ import { SessionLifecycleManager } from "./session/session-lifecycle.js";
|
|
|
58
59
|
import "./session/index.js";
|
|
59
60
|
import { tryApplySessionTranscriptHygiene, tryApplySessionTranscriptHygieneForPersistence } from "./transcript/transcript-hygiene.js";
|
|
60
61
|
import { runAgentTurnWithModelFallbacks } from "./orchestration/run-agent-turn-with-fallbacks.js";
|
|
62
|
+
import { expandAtFileMentionsInPlainText } from "./context/expand-at-file-mentions.js";
|
|
61
63
|
import { resolveInboundImageContentParts } from "./image/inbound-image-handling.js";
|
|
62
64
|
import { AgentOrchestrator } from "./orchestration/agent-orchestrator.js";
|
|
63
65
|
import { AgentEventHandler } from "./orchestration/agent-event-handler.js";
|
|
@@ -69,6 +71,7 @@ import { runProcessDirectStreaming } from "./service/process-direct-streaming.js
|
|
|
69
71
|
import { shouldSilence } from "../heartbeat/tokens.js";
|
|
70
72
|
import { createTypingController } from "./lifecycle/typing.js";
|
|
71
73
|
import { persistOutboundTtsAudio } from "../channels/attachments/outbound-tts-persist.js";
|
|
74
|
+
import { complete } from "@mariozechner/pi-ai";
|
|
72
75
|
import { mkdir } from "node:fs/promises";
|
|
73
76
|
//#region src/agent/service.ts
|
|
74
77
|
init_schema();
|
|
@@ -113,6 +116,10 @@ var AgentService = class {
|
|
|
113
116
|
/** Webchat SSE queue pushers for `clarify_request` and similar mid-turn UI events. */
|
|
114
117
|
webchatSseEnqueueBySession = /* @__PURE__ */ new Map();
|
|
115
118
|
sessionUnsubscribers = /* @__PURE__ */ new Map();
|
|
119
|
+
effectiveAppConfig() {
|
|
120
|
+
const base = this.config.config;
|
|
121
|
+
return base ? applyConfigOverrides(base) : void 0;
|
|
122
|
+
}
|
|
116
123
|
constructor(bus, config) {
|
|
117
124
|
this.bus = bus;
|
|
118
125
|
this.config = config;
|
|
@@ -186,8 +193,8 @@ var AgentService = class {
|
|
|
186
193
|
feedbackCoordinator: this.feedbackCoordinator,
|
|
187
194
|
sessionConfigStore: this.sessionConfigStore,
|
|
188
195
|
hydrateSessionWorkspaceFromStore: (sessionKey) => this.hydrateSessionWorkspaceFromStore(sessionKey),
|
|
189
|
-
getConfig: () => this.
|
|
190
|
-
getThinkingDefault: () => this.
|
|
196
|
+
getConfig: () => this.effectiveAppConfig(),
|
|
197
|
+
getThinkingDefault: () => this.effectiveAppConfig()?.agents?.defaults?.thinkingDefault,
|
|
191
198
|
getThinkingDefaultForSession: (sessionKey) => this.agentManager.getThinkingDefaultForSession(sessionKey),
|
|
192
199
|
workspaceRoot: this.workspaceDir,
|
|
193
200
|
getWorkspaceRootForSession: (sessionKey) => this.agentManager.getResolvedWorkspaceForSession(sessionKey),
|
|
@@ -211,7 +218,10 @@ var AgentService = class {
|
|
|
211
218
|
abortSessionTurn: async (sessionKey) => {
|
|
212
219
|
await this.streamManager.abort();
|
|
213
220
|
this.agentOrchestrator.abort(sessionKey);
|
|
214
|
-
}
|
|
221
|
+
},
|
|
222
|
+
compactSession: (sessionKey, options) => this.compactSession(sessionKey, options),
|
|
223
|
+
btwQuery: (sessionKey, question) => this.btwQuery(sessionKey, question),
|
|
224
|
+
getSessionContextReport: (sessionKey, mode) => this.getSessionContextReport(sessionKey, mode)
|
|
215
225
|
});
|
|
216
226
|
this.sessionLifecycleManager = new SessionLifecycleManager(this.sessionStore, this.sessionTracker, this.lifecycleManager);
|
|
217
227
|
if (!!!process.env.ELECTRON_RUN_AS_NODE) {
|
|
@@ -525,12 +535,20 @@ var AgentService = class {
|
|
|
525
535
|
}
|
|
526
536
|
async buildMessageContent(content, attachments, sessionKey) {
|
|
527
537
|
const messageContent = [];
|
|
528
|
-
if (content.trim()) messageContent.push({
|
|
529
|
-
type: "text",
|
|
530
|
-
text: content
|
|
531
|
-
});
|
|
532
|
-
if (!attachments?.length) return messageContent;
|
|
533
538
|
const sk = sessionKey ?? "";
|
|
539
|
+
if (content.trim()) {
|
|
540
|
+
let textPart = content;
|
|
541
|
+
if (/@file:/.test(textPart)) {
|
|
542
|
+
const wsKey = sk !== "" ? sk : "cli:direct";
|
|
543
|
+
const root = this.agentManager.getResolvedWorkspaceForSession(wsKey);
|
|
544
|
+
textPart = await expandAtFileMentionsInPlainText(textPart, root);
|
|
545
|
+
}
|
|
546
|
+
messageContent.push({
|
|
547
|
+
type: "text",
|
|
548
|
+
text: textPart
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
if (!attachments?.length) return messageContent;
|
|
534
552
|
const modelRef = sk !== "" ? this.modelManager.getModelForSession(sk) : getAgentDefaultModelRef(this.config.config) ?? getDefaultModelSync(this.config.config);
|
|
535
553
|
const cfg = this.config.config;
|
|
536
554
|
const storageRoot = sk !== "" ? resolveAgentHomeDir(this.config.config, extractProfileAgentId(sk, this.config.config)) : resolveAgentHomeDir(this.config.config, resolveDefaultAgentId(this.config.config));
|
|
@@ -585,15 +603,155 @@ var AgentService = class {
|
|
|
585
603
|
this.feedbackCoordinator.clearContext();
|
|
586
604
|
this.contextMiddleware.onResponse();
|
|
587
605
|
}
|
|
588
|
-
async compactSession(sessionKey,
|
|
606
|
+
async compactSession(sessionKey, options) {
|
|
589
607
|
const messages = await this.sessionStore.load(sessionKey);
|
|
590
608
|
const contextWindow = this.getContextWindow();
|
|
591
|
-
const result = await this.sessionStore.compact(sessionKey, messages, contextWindow, instructions);
|
|
592
|
-
if (result.compacted)
|
|
609
|
+
const result = await this.sessionStore.compact(sessionKey, messages, contextWindow, options?.instructions, options?.force ?? true);
|
|
610
|
+
if (result.compacted) {
|
|
611
|
+
await this.sessionStore.save(sessionKey, await this.sessionStore.load(sessionKey));
|
|
612
|
+
this.agentManager.removeAgent(sessionKey);
|
|
613
|
+
}
|
|
593
614
|
log.info({
|
|
594
615
|
sessionKey,
|
|
595
616
|
result
|
|
596
617
|
}, "Manual compaction complete");
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* One-shot LLM answer for /btw: uses transcript as background only; does not persist to session.
|
|
622
|
+
*/
|
|
623
|
+
async btwQuery(sessionKey, question) {
|
|
624
|
+
const q = question.trim();
|
|
625
|
+
if (!q) return {
|
|
626
|
+
text: "",
|
|
627
|
+
error: "Empty question."
|
|
628
|
+
};
|
|
629
|
+
const messages = await this.sessionStore.load(sessionKey);
|
|
630
|
+
const modelRef = this.modelManager.getModelForSession(sessionKey);
|
|
631
|
+
let model;
|
|
632
|
+
try {
|
|
633
|
+
model = resolveModel(modelRef);
|
|
634
|
+
} catch (err) {
|
|
635
|
+
const em = err instanceof Error ? err.message : String(err);
|
|
636
|
+
log.warn({
|
|
637
|
+
err,
|
|
638
|
+
modelRef,
|
|
639
|
+
errorMessage: em
|
|
640
|
+
}, "btwQuery: model resolve failed");
|
|
641
|
+
return {
|
|
642
|
+
text: "",
|
|
643
|
+
error: `Could not resolve model: ${modelRef}`
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
const background = this.formatMessagesForBtw(messages.slice(-40));
|
|
647
|
+
const userMessage = {
|
|
648
|
+
role: "user",
|
|
649
|
+
content: [
|
|
650
|
+
[
|
|
651
|
+
"You are answering an ephemeral /btw side question about the current conversation.",
|
|
652
|
+
"Use the conversation only as background context.",
|
|
653
|
+
"Answer only the side question. Do not continue or complete any unfinished task from the conversation.",
|
|
654
|
+
"Do not use tools, shell, or file writes unless the question explicitly requires a tiny code snippet.",
|
|
655
|
+
"If the question can be answered briefly, answer briefly."
|
|
656
|
+
].join("\n"),
|
|
657
|
+
"",
|
|
658
|
+
"---",
|
|
659
|
+
"Conversation background (read-only):",
|
|
660
|
+
background || "(empty)",
|
|
661
|
+
"",
|
|
662
|
+
"---",
|
|
663
|
+
"Side question:",
|
|
664
|
+
q
|
|
665
|
+
].join("\n"),
|
|
666
|
+
timestamp: Date.now()
|
|
667
|
+
};
|
|
668
|
+
const controller = new AbortController();
|
|
669
|
+
const timeoutId = setTimeout(() => controller.abort(), 9e4);
|
|
670
|
+
try {
|
|
671
|
+
const out = await complete(model, { messages: [userMessage] }, {
|
|
672
|
+
maxTokens: 2048,
|
|
673
|
+
temperature: .4,
|
|
674
|
+
signal: controller.signal
|
|
675
|
+
});
|
|
676
|
+
return { text: (Array.isArray(out.content) ? out.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text || "").join("") : "").trim() };
|
|
677
|
+
} catch (err) {
|
|
678
|
+
const em = err instanceof Error ? err.message : String(err);
|
|
679
|
+
log.warn({
|
|
680
|
+
err,
|
|
681
|
+
sessionKey,
|
|
682
|
+
errorMessage: em
|
|
683
|
+
}, "btwQuery failed");
|
|
684
|
+
return {
|
|
685
|
+
text: "",
|
|
686
|
+
error: em
|
|
687
|
+
};
|
|
688
|
+
} finally {
|
|
689
|
+
clearTimeout(timeoutId);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
formatMessagesForBtw(messages) {
|
|
693
|
+
return messages.map((m) => {
|
|
694
|
+
const role = m.role;
|
|
695
|
+
let body = "";
|
|
696
|
+
if (typeof m.content === "string") body = m.content;
|
|
697
|
+
else if (Array.isArray(m.content)) body = m.content.filter((c) => c.type === "text").map((c) => c.text || "").join("\n");
|
|
698
|
+
const line = `[${role}]: ${body}`;
|
|
699
|
+
return line.length > 4e3 ? `${line.slice(0, 4e3)}…` : line;
|
|
700
|
+
}).join("\n\n");
|
|
701
|
+
}
|
|
702
|
+
/** Markdown or JSON summary for /context (prompt assembly is approximated from config + transcript stats). */
|
|
703
|
+
async getSessionContextReport(sessionKey, mode) {
|
|
704
|
+
const messages = await this.sessionStore.load(sessionKey);
|
|
705
|
+
const cw = this.getContextWindow();
|
|
706
|
+
const stats = this.getSessionStats(sessionKey, messages);
|
|
707
|
+
const cfg = this.effectiveAppConfig() ?? this.config.config;
|
|
708
|
+
const model = this.modelManager.getModelForSession(sessionKey);
|
|
709
|
+
const workspace = effectiveWorkspacePathForSession(cfg, sessionKey, await this.sessionConfigStore.get(sessionKey));
|
|
710
|
+
const estTokens = await this.sessionStore.estimateTokenUsage(sessionKey, messages);
|
|
711
|
+
const profile = resolveEffectiveAgentProfileForSession(cfg, sessionKey);
|
|
712
|
+
const defaults = cfg.agents?.defaults;
|
|
713
|
+
const compaction = defaults?.compaction;
|
|
714
|
+
const tools = defaults?.tools;
|
|
715
|
+
const toolsSummary = tools && typeof tools === "object" ? Object.entries(tools).filter(([, v]) => v === true).map(([k]) => k).slice(0, 16).join(", ") || "(none explicitly true)" : "(see agents.defaults.tools in config)";
|
|
716
|
+
const payload = {
|
|
717
|
+
sessionKey,
|
|
718
|
+
model,
|
|
719
|
+
workspacePath: workspace,
|
|
720
|
+
agentId: profile.agentId,
|
|
721
|
+
messageCount: messages.length,
|
|
722
|
+
contextWindowNominal: cw,
|
|
723
|
+
estimatedTranscriptTokens: estTokens,
|
|
724
|
+
approxWindowUsage: cw > 0 ? estTokens / cw : null,
|
|
725
|
+
thinkingDefault: defaults?.thinkingDefault,
|
|
726
|
+
reasoningDefault: defaults?.reasoningDefault,
|
|
727
|
+
verboseDefault: defaults?.verboseDefault,
|
|
728
|
+
compaction,
|
|
729
|
+
toolsFlagsOn: toolsSummary,
|
|
730
|
+
windowStats: stats.windowStats,
|
|
731
|
+
compactionRunStats: stats.compactionStats
|
|
732
|
+
};
|
|
733
|
+
if (mode === "json") return JSON.stringify(payload, null, 2);
|
|
734
|
+
const lines = [
|
|
735
|
+
"📎 *Context overview*",
|
|
736
|
+
"",
|
|
737
|
+
`• Session: \`${sessionKey}\``,
|
|
738
|
+
`• Model: \`${model}\``,
|
|
739
|
+
`• Agent profile: \`${profile.agentId}\``,
|
|
740
|
+
`• Workspace: \`${workspace}\``,
|
|
741
|
+
`• Messages: ${messages.length}`,
|
|
742
|
+
`• Est. transcript tokens (rough): ${estTokens}`,
|
|
743
|
+
`• Nominal context budget (4× maxTokens): ${cw}`
|
|
744
|
+
];
|
|
745
|
+
if (cw > 0) lines.push(`• Approx. usage vs budget: ${(estTokens / cw * 100).toFixed(1)}%`);
|
|
746
|
+
lines.push(`• Thinking / reasoning / verbose defaults: ${defaults?.thinkingDefault ?? "—"} / ${defaults?.reasoningDefault ?? "—"} / ${defaults?.verboseDefault ?? "—"}`, `• Tools (true flags): ${toolsSummary}`, "", "_Full system prompt, skills, and memory blocks are assembled at agent runtime; use Web settings or logs for deep inspection._");
|
|
747
|
+
if (mode === "detail") {
|
|
748
|
+
lines.push("", "*Compaction config (agents.defaults.compaction):*", "```json");
|
|
749
|
+
lines.push(JSON.stringify(compaction ?? {}, null, 2));
|
|
750
|
+
lines.push("```", "", "*Window stats:*", "```json");
|
|
751
|
+
lines.push(JSON.stringify(stats.windowStats ?? {}, null, 2));
|
|
752
|
+
lines.push("```");
|
|
753
|
+
}
|
|
754
|
+
return lines.join("\n");
|
|
597
755
|
}
|
|
598
756
|
getSessionStats(sessionKey, messages) {
|
|
599
757
|
return {
|
|
@@ -603,14 +761,14 @@ var AgentService = class {
|
|
|
603
761
|
};
|
|
604
762
|
}
|
|
605
763
|
async applyResolvedThinkingLevel(sessionKey, requestOverride) {
|
|
606
|
-
const def = this.
|
|
764
|
+
const def = this.effectiveAppConfig()?.agents?.defaults?.thinkingDefault;
|
|
607
765
|
const level = await resolveEffectiveThinkingLevel(this.sessionConfigStore, sessionKey, requestOverride, def);
|
|
608
766
|
this.agentManager.setThinkingLevel(sessionKey, level);
|
|
609
767
|
}
|
|
610
768
|
/** Resolved thinking level and effective model ref for a session (Web UI). */
|
|
611
769
|
async getSessionAgentConfig(sessionKey) {
|
|
612
770
|
await this.hydrateSessionModelFromStore(sessionKey);
|
|
613
|
-
const cfg = this.
|
|
771
|
+
const cfg = this.effectiveAppConfig();
|
|
614
772
|
const sc = await this.sessionConfigStore.get(sessionKey);
|
|
615
773
|
const defThink = cfg.agents?.defaults?.thinkingDefault ?? "medium";
|
|
616
774
|
const level = await resolveEffectiveThinkingLevel(this.sessionConfigStore, sessionKey, null, defThink);
|
|
@@ -786,7 +944,7 @@ var AgentService = class {
|
|
|
786
944
|
prepareLoadedSessionMessages: (sk, msgs) => this.prepareLoadedSessionMessages(sk, msgs),
|
|
787
945
|
modelManager: this.modelManager,
|
|
788
946
|
applyResolvedThinkingLevel: (sk, t) => this.applyResolvedThinkingLevel(sk, t),
|
|
789
|
-
getConfig: () => this.
|
|
947
|
+
getConfig: () => this.effectiveAppConfig(),
|
|
790
948
|
sessionConfigStore: this.sessionConfigStore,
|
|
791
949
|
attachmentRootsForSession: (sk) => this.attachmentRootsForSession(sk),
|
|
792
950
|
agentOrchestrator: this.agentOrchestrator,
|
|
@@ -1112,7 +1270,7 @@ var AgentService = class {
|
|
|
1112
1270
|
reason: prep.stats?.reason,
|
|
1113
1271
|
usagePercent: prep.stats?.usagePercent
|
|
1114
1272
|
}, "Session needs compaction");
|
|
1115
|
-
const result = await this.sessionStore.compact(sessionKey, messages, contextWindow);
|
|
1273
|
+
const result = await this.sessionStore.compact(sessionKey, messages, contextWindow, void 0, false);
|
|
1116
1274
|
await this.hookHandler.trigger("after_compaction", {
|
|
1117
1275
|
messageCount: messages.length,
|
|
1118
1276
|
tokenCount: result.tokensBefore,
|