@xopcai/xopc 0.0.82 → 0.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/README.zh-CN.md +3 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +2 -3
- package/dist/extensions/feishu/src/outbound/media-load.js.map +1 -1
- package/dist/extensions/feishu/src/schema/config-schema.d.ts +6 -6
- package/dist/extensions/telegram/src/config-schema.d.ts +6 -6
- package/dist/extensions/telegram/src/plugin.d.ts +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +3 -3
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/gateway/static/root/assets/agents-tR-nNP04.js +222 -0
- package/dist/gateway/static/root/assets/{apps-page-pJ27dsqn.js → apps-page-BDw6SP-d.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-DEFd-jj1.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-D1KYmOmi.js → channels-status-swr-DI5FHdGe.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-Y2wfSJVI.js → cron-api-BSqY8LwW.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-B97KU_RG.js → cron-page-D7lVDjcR.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-CboA_Css.js → dist-CqNMNhJM.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DN_zNmpo.js → extension-debug-page-gf2L0kY_.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BUXtOzv5.js → extension-page-CQo2Xsmg.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-C2dX4KCW.js → extension-settings-page-CZf0WoZg.js} +1 -1
- package/dist/gateway/static/root/assets/fetch-2iRFmd3n.js +3 -0
- package/dist/gateway/static/root/assets/{field-primitives-B9rOLqdm.js → field-primitives-DTtlp-l8.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-DvfiRVrc.js → heartbeat-config-api-B0drdQEJ.js} +1 -1
- package/dist/gateway/static/root/assets/{index-DQuaMye9.js → index-0Gt3TG4j.js} +94 -85
- package/dist/gateway/static/root/assets/index-BuFldCsB.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-BQuBpHcc.js → logs-page-DMuORLfC.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-_UO8g6NN.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-2Yu-FASs.js → settings-form-section-DkmHkknc.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-Cz8FoW_A.js +3 -0
- package/dist/gateway/static/root/assets/skills-page-HrUOxF7H.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-DnwYutiX.js → theme-store-D01dJt95.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-D2Gn2qod.js → utils-BFwcR6pL.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-JF8-aqc5.js +1 -0
- package/dist/gateway/static/root/index.html +4 -4
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-instance-gateway.d.ts +50 -0
- package/dist/src/agent/agent-instance-gateway.js +1 -0
- package/dist/src/agent/agent-manager.d.ts +20 -14
- package/dist/src/agent/agent-manager.js +74 -186
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/coordinator.d.ts +61 -0
- package/dist/src/agent/background-review/coordinator.js +120 -0
- package/dist/src/agent/background-review/coordinator.js.map +1 -0
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +14 -0
- package/dist/src/agent/child-agent-factory.js +2 -8
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/context/workspace-seed.js +3 -3
- package/dist/src/agent/embedded/index.d.ts +1 -2
- package/dist/src/agent/embedded/index.js +2 -3
- package/dist/src/agent/embedded/run-for-session.d.ts +2 -2
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/embedded/runs.d.ts +32 -0
- package/dist/src/agent/embedded/runs.js +79 -19
- package/dist/src/agent/embedded/runs.js.map +1 -1
- package/dist/src/agent/embedded/session-manager-cache.d.ts +14 -0
- package/dist/src/agent/embedded/session-manager-cache.js +32 -11
- package/dist/src/agent/embedded/session-manager-cache.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.d.ts +37 -7
- package/dist/src/agent/embedded/session-runner.js +184 -153
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.d.ts +57 -9
- package/dist/src/agent/embedded/session-tool-result-guard.js +159 -67
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.d.ts +84 -0
- package/dist/src/agent/goals/persistent-goal-service.js +139 -0
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -0
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/goals/state.d.ts +1 -1
- package/dist/src/agent/goals/state.js.map +1 -1
- package/dist/src/agent/image/load-image-media.js +1 -1
- package/dist/src/agent/inbound/inbound-loop.d.ts +77 -0
- package/dist/src/agent/inbound/inbound-loop.js +226 -0
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +80 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +138 -0
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -0
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
- package/dist/src/agent/lifecycle/manager.d.ts +1 -1
- package/dist/src/agent/lifecycle/manager.js.map +1 -1
- package/dist/src/agent/lifecycle/types.d.ts +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.d.ts +12 -2
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js.map +1 -1
- package/dist/src/agent/memory/index.js +3 -3
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/memory/prefetch-coordinator.d.ts +37 -0
- package/dist/src/agent/memory/prefetch-coordinator.js +45 -0
- package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -0
- package/dist/src/agent/messaging/command-handler.d.ts +5 -1
- package/dist/src/agent/messaging/command-handler.js +24 -96
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/messaging/index.d.ts +1 -0
- package/dist/src/agent/messaging/index.js +2 -1
- package/dist/src/agent/messaging/message-router.d.ts +1 -1
- package/dist/src/agent/messaging/message-router.js.map +1 -1
- package/dist/src/agent/messaging/outbound-coordinator.d.ts +82 -0
- package/dist/src/agent/messaging/outbound-coordinator.js +123 -0
- package/dist/src/agent/messaging/outbound-coordinator.js.map +1 -0
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.d.ts +36 -33
- package/dist/src/agent/orchestration/agent-event-handler.js +212 -174
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +4 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +4 -8
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/orchestration/index.d.ts +1 -1
- package/dist/src/agent/orchestration/index.js +2 -2
- package/dist/src/agent/prompt/service-prompt-builder.js +4 -4
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +1 -1
- package/dist/src/agent/service/async-queue.d.ts +20 -0
- package/dist/src/agent/service/async-queue.js +53 -0
- package/dist/src/agent/service/async-queue.js.map +1 -0
- package/dist/src/agent/service/build-direct-message-content.d.ts +2 -2
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +70 -0
- package/dist/src/agent/service/direct-turn-helpers.js +90 -0
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -0
- package/dist/src/agent/service/process-direct-one-shot.d.ts +3 -3
- package/dist/src/agent/service/process-direct-one-shot.js +17 -34
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +122 -168
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.d.ts +2 -2
- package/dist/src/agent/service/webchat-tts.js +1 -1
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +62 -167
- package/dist/src/agent/service.js +177 -786
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/index.d.ts +4 -0
- package/dist/src/agent/session/index.js +5 -1
- package/dist/src/agent/session/session-config-service.d.ts +68 -0
- package/dist/src/agent/session/session-config-service.js +172 -0
- package/dist/src/agent/session/session-config-service.js.map +1 -0
- package/dist/src/agent/session/session-context.d.ts +27 -19
- package/dist/src/agent/session/session-context.js +39 -24
- package/dist/src/agent/session/session-context.js.map +1 -1
- package/dist/src/agent/session/session-hydrator.d.ts +42 -0
- package/dist/src/agent/session/session-hydrator.js +66 -0
- package/dist/src/agent/session/session-hydrator.js.map +1 -0
- package/dist/src/agent/session/session-inspector.d.ts +80 -0
- package/dist/src/agent/session/session-inspector.js +119 -0
- package/dist/src/agent/session/session-inspector.js.map +1 -0
- package/dist/src/agent/session/session-state-bag.d.ts +83 -0
- package/dist/src/agent/session/session-state-bag.js +192 -0
- package/dist/src/agent/session/session-state-bag.js.map +1 -0
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.d.ts +0 -2
- package/dist/src/agent/skills/index.js +3 -5
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js +11 -6
- package/dist/src/agent/skills/marketplace/adapters/clawhub/adapter.js.map +1 -1
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js +35 -7
- package/dist/src/agent/skills/marketplace/adapters/skillhub/adapter.js.map +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +2 -2
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +7 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +37 -0
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/delegate-tool.d.ts +7 -0
- package/dist/src/agent/tools/delegate-tool.js +2 -1
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/executor.d.ts +34 -15
- package/dist/src/agent/tools/executor.js +44 -79
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +6 -0
- package/dist/src/agent/tools/factory.js +63 -4
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +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/skills-tools.js +1 -1
- package/dist/src/agent/tools/tts-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workspace-runtime/registry.d.ts +48 -0
- package/dist/src/agent/workspace-runtime/registry.js +59 -0
- package/dist/src/agent/workspace-runtime/registry.js.map +1 -0
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +4 -3
- package/dist/src/browser/cdp-local-launcher.js.map +1 -1
- package/dist/src/browser/index.d.ts +1 -0
- package/dist/src/browser/index.js +2 -1
- package/dist/src/browser/manager.js +3 -2
- package/dist/src/browser/manager.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/browser-use.js +2 -1
- package/dist/src/browser/providers/browser-use.js.map +1 -1
- package/dist/src/browser/providers/browserbase.js +2 -1
- package/dist/src/browser/providers/browserbase.js.map +1 -1
- package/dist/src/browser/providers/cloakbrowser.js +7 -6
- package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
- package/dist/src/browser/providers/playwright-doctor.d.ts +2 -0
- package/dist/src/browser/providers/playwright-doctor.js +7 -3
- package/dist/src/browser/providers/playwright-doctor.js.map +1 -1
- package/dist/src/browser/readiness.d.ts +33 -0
- package/dist/src/browser/readiness.js +138 -0
- package/dist/src/browser/readiness.js.map +1 -0
- package/dist/src/browser/stealth.js +2 -2
- 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/channel-domain.d.ts +1 -1
- package/dist/src/channels/config-helpers.d.ts +1 -1
- package/dist/src/channels/config-helpers.js.map +1 -1
- package/dist/src/channels/heartbeat-scheduler.d.ts +40 -0
- package/dist/src/channels/heartbeat-scheduler.js +94 -0
- package/dist/src/channels/heartbeat-scheduler.js.map +1 -0
- package/dist/src/channels/lifecycle-supervisor.d.ts +81 -0
- package/dist/src/channels/lifecycle-supervisor.js +263 -0
- package/dist/src/channels/lifecycle-supervisor.js.map +1 -0
- package/dist/src/channels/manager.d.ts +34 -68
- package/dist/src/channels/manager.js +107 -477
- package/dist/src/channels/manager.js.map +1 -1
- package/dist/src/channels/outbound/deliver.d.ts +1 -1
- package/dist/src/channels/outbound/deliver.js.map +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/outbound-sender.d.ts +51 -0
- package/dist/src/channels/outbound-sender.js +125 -0
- package/dist/src/channels/outbound-sender.js.map +1 -0
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-service.d.ts +3 -10
- package/dist/src/channels/pairing/pairing-service.js.map +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/channels/pairing/pairing-types.d.ts +15 -0
- package/dist/src/channels/pairing/pairing-types.js +1 -0
- package/dist/src/channels/plugin-registry.d.ts +22 -0
- package/dist/src/channels/plugin-registry.js +44 -0
- package/dist/src/channels/plugin-registry.js.map +1 -0
- package/dist/src/channels/plugin-types.d.ts +1 -1
- package/dist/src/channels/plugins/types.adapters.d.ts +2 -2
- package/dist/src/channels/security-helpers.d.ts +1 -1
- package/dist/src/channels/security-helpers.js.map +1 -1
- package/dist/src/channels/setup-wizard.d.ts +1 -1
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/command-catalog.js +110 -8
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +2 -0
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +9 -1
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/agent/stream-renderer.js +1 -1
- package/dist/src/cli/commands/agent/stream-renderer.js.map +1 -1
- package/dist/src/cli/commands/agent.js +4 -4
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/browser-cli-helpers.js +2 -1
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/config.js +70 -19
- package/dist/src/cli/commands/config.js.map +1 -1
- package/dist/src/cli/commands/cron-cli.d.ts +2 -0
- package/dist/src/cli/commands/cron-cli.js +15 -0
- package/dist/src/cli/commands/cron-cli.js.map +1 -0
- package/dist/src/cli/commands/cron.d.ts +4 -1
- package/dist/src/cli/commands/cron.js +76 -41
- package/dist/src/cli/commands/cron.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +2 -2
- package/dist/src/cli/commands/doctor/checks/config-health.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/cron-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/cron-health.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/gateway-health.js +2 -2
- package/dist/src/cli/commands/doctor/checks/gateway-health.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/gateway-service.js +2 -2
- package/dist/src/cli/commands/doctor/checks/gateway-service.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +2 -2
- package/dist/src/cli/commands/doctor/checks/state-integrity.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +4 -4
- package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
- package/dist/src/cli/commands/extension-dev.js +2 -2
- package/dist/src/cli/commands/extension-dev.js.map +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension-marketplace.js.map +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/call.js +1 -1
- package/dist/src/cli/commands/gateway/call.js.map +1 -1
- package/dist/src/cli/commands/gateway/health.js +1 -1
- package/dist/src/cli/commands/gateway/health.js.map +1 -1
- package/dist/src/cli/commands/gateway/index.d.ts +1 -1
- package/dist/src/cli/commands/gateway/index.js +2 -2
- package/dist/src/cli/commands/gateway/lifecycle-core.d.ts +31 -12
- package/dist/src/cli/commands/gateway/lifecycle-core.js +167 -116
- package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.d.ts +11 -0
- package/dist/src/cli/commands/gateway/lifecycle.js +102 -0
- package/dist/src/cli/commands/gateway/lifecycle.js.map +1 -0
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js.map +1 -1
- package/dist/src/cli/commands/gateway/probe.js +1 -1
- package/dist/src/cli/commands/gateway/probe.js.map +1 -1
- package/dist/src/cli/commands/gateway/restart-health.d.ts +12 -0
- package/dist/src/cli/commands/gateway/restart-health.js +45 -1
- package/dist/src/cli/commands/gateway/restart-health.js.map +1 -1
- package/dist/src/cli/commands/gateway/restart.js +3 -3
- package/dist/src/cli/commands/gateway/restart.js.map +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.d.ts +0 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +0 -35
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/gateway/service.d.ts +4 -0
- package/dist/src/cli/commands/gateway/service.js +18 -3
- package/dist/src/cli/commands/gateway/service.js.map +1 -1
- package/dist/src/cli/commands/gateway/shared.d.ts +3 -0
- package/dist/src/cli/commands/gateway/shared.js +54 -0
- package/dist/src/cli/commands/gateway/shared.js.map +1 -0
- package/dist/src/cli/commands/gateway/status.js +1 -1
- package/dist/src/cli/commands/gateway/status.js.map +1 -1
- package/dist/src/cli/commands/gateway/stop.js +2 -2
- package/dist/src/cli/commands/gateway/stop.js.map +1 -1
- package/dist/src/cli/commands/gateway/subcommands.js +1 -4
- package/dist/src/cli/commands/gateway/subcommands.js.map +1 -1
- package/dist/src/cli/commands/gateway/token.js +1 -1
- package/dist/src/cli/commands/gateway/token.js.map +1 -1
- package/dist/src/cli/commands/gateway.js +5 -5
- package/dist/src/cli/commands/gateway.js.map +1 -1
- package/dist/src/cli/commands/image.js +2 -2
- package/dist/src/cli/commands/image.js.map +1 -1
- package/dist/src/cli/commands/init.js +31 -4
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/models.d.ts +4 -1
- package/dist/src/cli/commands/models.js +87 -75
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/gateway.d.ts +0 -8
- package/dist/src/cli/commands/onboard/gateway.js +48 -49
- package/dist/src/cli/commands/onboard/gateway.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +11 -64
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/profile.d.ts +3 -5
- package/dist/src/cli/commands/profile.js +31 -31
- package/dist/src/cli/commands/profile.js.map +1 -1
- package/dist/src/cli/commands/session/utils.js +1 -1
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/setup.js +6 -1
- package/dist/src/cli/commands/setup.js.map +1 -1
- package/dist/src/cli/commands/skills.js +1 -1
- package/dist/src/cli/commands/tailscale.js +1 -1
- package/dist/src/cli/commands/tailscale.js.map +1 -1
- package/dist/src/cli/context.d.ts +20 -0
- package/dist/src/cli/context.js +23 -0
- package/dist/src/cli/context.js.map +1 -0
- package/dist/src/cli/extension-cli-register.js +3 -3
- package/dist/src/cli/gateway-run-argv.js +16 -9
- package/dist/src/cli/gateway-run-argv.js.map +1 -1
- package/dist/src/cli/gateway-run-fast-path.js +1 -1
- package/dist/src/cli/gateway-run-fast-path.js.map +1 -1
- package/dist/src/cli/index.d.ts +1 -7
- package/dist/src/cli/index.js +4 -6
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/config/commands.flags.d.ts +3 -0
- package/dist/src/config/commands.flags.js +11 -0
- package/dist/src/config/commands.flags.js.map +1 -0
- package/dist/src/config/index.d.ts +1 -0
- package/dist/src/config/index.js +6 -5
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +11 -4
- package/dist/src/config/schema.js +13 -12
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path-helpers.d.ts +15 -0
- package/dist/src/config/workspace-path-helpers.js +14 -0
- package/dist/src/config/workspace-path-helpers.js.map +1 -0
- package/dist/src/cron/executor.js +4 -4
- package/dist/src/cron/executor.js.map +1 -1
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/daemon/index.d.ts +0 -1
- package/dist/src/daemon/index.js +1 -2
- package/dist/src/daemon/install-plan.js +3 -2
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/daemon/types.d.ts +0 -6
- package/dist/src/extensions/api.d.ts +1 -1
- package/dist/src/extensions/api.js +2 -2
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/extension-registry-impl.d.ts +51 -0
- package/dist/src/extensions/extension-registry-impl.js +117 -0
- package/dist/src/extensions/extension-registry-impl.js.map +1 -0
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/index.js +3 -2
- package/dist/src/extensions/loader.d.ts +3 -43
- package/dist/src/extensions/loader.js +3 -110
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/sdk/index.js +2 -1
- package/dist/src/extensions/sdk/index.js.map +1 -1
- package/dist/src/extensions/types/events.d.ts +7 -1
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +5 -53
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +1 -1
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/middleware/auth.d.ts +5 -14
- package/dist/src/gateway/hono/middleware/auth.js +89 -126
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/middleware/logger.js +1 -1
- package/dist/src/gateway/hono/middleware/logger.js.map +1 -1
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +14 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +62 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -0
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +4 -4
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js.map +1 -1
- package/dist/src/gateway/hono/routes/browser.d.ts +20 -0
- package/dist/src/gateway/hono/routes/browser.js +626 -0
- package/dist/src/gateway/hono/routes/browser.js.map +1 -0
- package/dist/src/gateway/hono/routes/commands-skills.js +13 -13
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.d.ts +18 -0
- package/dist/src/gateway/hono/routes/config-patch/agents.js +418 -0
- package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/channels.d.ts +12 -0
- package/dist/src/gateway/hono/routes/config-patch/channels.js +186 -0
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +18 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +264 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/index.d.ts +9 -0
- package/dist/src/gateway/hono/routes/config-patch/index.js +6 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +23 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.js +139 -0
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -0
- package/dist/src/gateway/hono/routes/config-patch/result.d.ts +18 -0
- package/dist/src/gateway/hono/routes/config-patch/result.js +13 -0
- package/dist/src/gateway/hono/routes/config-patch/result.js.map +1 -0
- package/dist/src/gateway/hono/routes/config.js +20 -1764
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +2 -3
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -5
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +1 -2
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +32 -32
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +4 -4
- package/dist/src/gateway/hono/routes/shares.js.map +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +6 -7
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.js +2 -2
- package/dist/src/gateway/index.d.ts +1 -1
- package/dist/src/gateway/index.js +4 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/rate-limit/auth-policy.d.ts +34 -0
- package/dist/src/gateway/rate-limit/auth-policy.js +49 -0
- package/dist/src/gateway/rate-limit/auth-policy.js.map +1 -0
- package/dist/src/gateway/rate-limit/buckets.d.ts +63 -0
- package/dist/src/gateway/rate-limit/buckets.js +143 -0
- package/dist/src/gateway/rate-limit/buckets.js.map +1 -0
- package/dist/src/gateway/rate-limit/env-flags.d.ts +13 -0
- package/dist/src/gateway/rate-limit/env-flags.js +16 -0
- package/dist/src/gateway/rate-limit/env-flags.js.map +1 -0
- package/dist/src/gateway/rate-limit/index.d.ts +3 -0
- package/dist/src/gateway/rate-limit/index.js +4 -0
- package/dist/src/gateway/run-loop.d.ts +1 -1
- package/dist/src/gateway/run-loop.js +24 -4
- package/dist/src/gateway/run-loop.js.map +1 -1
- package/dist/src/gateway/runtime-config.js +2 -1
- package/dist/src/gateway/runtime-config.js.map +1 -1
- package/dist/src/gateway/security/audit.js +2 -1
- package/dist/src/gateway/security/audit.js.map +1 -1
- package/dist/src/gateway/security/index.d.ts +0 -1
- package/dist/src/gateway/security/index.js +1 -2
- package/dist/src/gateway/security/loopback.d.ts +13 -0
- package/dist/src/gateway/security/loopback.js +45 -0
- package/dist/src/gateway/security/loopback.js.map +1 -0
- package/dist/src/gateway/service/agent-runner.d.ts +108 -0
- package/dist/src/gateway/service/agent-runner.js +184 -0
- package/dist/src/gateway/service/agent-runner.js.map +1 -0
- package/dist/src/gateway/service/config-coordinator.d.ts +119 -0
- package/dist/src/gateway/service/config-coordinator.js +351 -0
- package/dist/src/gateway/service/config-coordinator.js.map +1 -0
- package/dist/src/gateway/service/marketplace-service.d.ts +85 -0
- package/dist/src/gateway/service/marketplace-service.js +239 -0
- package/dist/src/gateway/service/marketplace-service.js.map +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +5 -5
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +125 -0
- package/dist/src/gateway/service/sessions-api.js +135 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -0
- package/dist/src/gateway/service.d.ts +30 -360
- package/dist/src/gateway/service.js +122 -904
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/gateway/workspace-heartbeat-path.js +1 -2
- package/dist/src/gateway/workspace-heartbeat-path.js.map +1 -1
- package/dist/src/infra/gateway-process-argv.d.ts +4 -0
- package/dist/src/infra/gateway-process-argv.js +26 -0
- package/dist/src/infra/gateway-process-argv.js.map +1 -0
- package/dist/src/infra/gateway-processes.d.ts +5 -0
- package/dist/src/infra/gateway-processes.js +65 -0
- package/dist/src/infra/gateway-processes.js.map +1 -0
- package/dist/src/infra/rate-limit/failure-limiter.d.ts +50 -0
- package/dist/src/infra/rate-limit/failure-limiter.js +100 -0
- package/dist/src/infra/rate-limit/failure-limiter.js.map +1 -0
- package/dist/src/infra/rate-limit/index.d.ts +5 -0
- package/dist/src/infra/rate-limit/index.js +3 -0
- package/dist/src/infra/rate-limit/keyed-store.d.ts +34 -0
- package/dist/src/infra/rate-limit/keyed-store.js +44 -0
- package/dist/src/infra/rate-limit/keyed-store.js.map +1 -0
- package/dist/src/infra/rate-limit/rate-limiter.d.ts +39 -0
- package/dist/src/infra/rate-limit/rate-limiter.js +65 -0
- package/dist/src/infra/rate-limit/rate-limiter.js.map +1 -0
- package/dist/src/infra/restart.d.ts +21 -0
- package/dist/src/infra/restart.js +122 -0
- package/dist/src/infra/restart.js.map +1 -0
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/mcp/channel-bridge.d.ts +0 -6
- package/dist/src/mcp/channel-bridge.js +1 -5
- package/dist/src/mcp/channel-bridge.js.map +1 -1
- package/dist/src/media-shared/http/ssrf-guard.js +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +2 -2
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file-read.d.ts +2 -1
- package/dist/src/session/parity/sessions-json-file-read.js.map +1 -1
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +1 -1
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.js +1 -1
- package/dist/src/session/store.js +5 -5
- package/dist/src/share/share-rate-limit.d.ts +10 -2
- package/dist/src/share/share-rate-limit.js +33 -42
- package/dist/src/share/share-rate-limit.js.map +1 -1
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/tui/backends/embedded-backend.js +16 -12
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +2 -2
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/format-tui-hotkeys.js +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +1 -1
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-skills-autocomplete.js +1 -1
- package/dist/src/tui/tui.js +1 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/tui/xopc-tui-keybindings.d.ts +0 -1
- package/dist/src/tui/xopc-tui-keybindings.js +1 -2
- package/dist/src/tui/xopc-tui-keybindings.js.map +1 -1
- package/dist/src/tunnel/frpc-binary.js +2 -2
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/pairing-rate-limit.d.ts +10 -2
- package/dist/src/tunnel/pairing-rate-limit.js +19 -15
- package/dist/src/tunnel/pairing-rate-limit.js.map +1 -1
- package/dist/src/tunnel/tunnel-rate-limit.d.ts +6 -3
- package/dist/src/tunnel/tunnel-rate-limit.js +11 -22
- package/dist/src/tunnel/tunnel-rate-limit.js.map +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/logger/stats.d.ts +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/factory.js +1 -1
- package/dist/src/voice/tts/index.js +2 -2
- package/dist/src/voice/tts/merge-config.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +1 -1
- package/dist/src/voice/tts/service.js +1 -1
- package/dist/src/voice/tts/service.js.map +1 -1
- package/dist/src/voice/tts/speak-core.js +1 -1
- package/package.json +10 -5
- package/dist/gateway/static/root/assets/agents-Cqh1ts38.js +0 -222
- package/dist/gateway/static/root/assets/channels-settings-wTiWStg9.js +0 -1
- package/dist/gateway/static/root/assets/fetch-BAAh_kXG.js +0 -3
- package/dist/gateway/static/root/assets/index-C8yHX-AA.css +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BeiFm0Ms.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-RPAz_Wg_.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-Wu4aNWDx.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-BxIGhhEL.js +0 -1
- package/dist/src/agent/embedded/session-raw-append-message.d.ts +0 -11
- package/dist/src/agent/embedded/session-raw-append-message.js +0 -15
- package/dist/src/agent/embedded/session-raw-append-message.js.map +0 -1
- package/dist/src/agent/embedded/session-tool-result-guard-wrapper.d.ts +0 -15
- package/dist/src/agent/embedded/session-tool-result-guard-wrapper.js +0 -24
- package/dist/src/agent/embedded/session-tool-result-guard-wrapper.js.map +0 -1
- package/dist/src/agent/embedded/session-tool-result-state.d.ts +0 -17
- package/dist/src/agent/embedded/session-tool-result-state.js +0 -26
- package/dist/src/agent/embedded/session-tool-result-state.js.map +0 -1
- package/dist/src/daemon/launchd-restart-handoff.d.ts +0 -25
- package/dist/src/daemon/launchd-restart-handoff.js +0 -132
- package/dist/src/daemon/launchd-restart-handoff.js.map +0 -1
- package/dist/src/gateway/auth-rate-limit.d.ts +0 -71
- package/dist/src/gateway/auth-rate-limit.js +0 -192
- package/dist/src/gateway/auth-rate-limit.js.map +0 -1
- package/dist/src/gateway/restart-handler.d.ts +0 -14
- package/dist/src/gateway/restart-handler.js +0 -64
- package/dist/src/gateway/restart-handler.js.map +0 -1
- package/dist/src/gateway/security/flood-guard.d.ts +0 -28
- package/dist/src/gateway/security/flood-guard.js +0 -42
- package/dist/src/gateway/security/flood-guard.js.map +0 -1
- package/dist/src/infra/rate-limit.d.ts +0 -38
- package/dist/src/infra/rate-limit.js +0 -60
- package/dist/src/infra/rate-limit.js.map +0 -1
- package/dist/src/infra/restart-intent.d.ts +0 -13
- package/dist/src/infra/restart-intent.js +0 -40
- package/dist/src/infra/restart-intent.js.map +0 -1
- package/dist/src/infra/restart-sentinel.d.ts +0 -23
- package/dist/src/infra/restart-sentinel.js +0 -75
- package/dist/src/infra/restart-sentinel.js.map +0 -1
- package/skills/creative/canvas-design/LICENSE.txt +0 -202
- package/skills/creative/canvas-design/SKILL-zh.md +0 -130
- package/skills/creative/canvas-design/SKILL.md +0 -130
- package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BigShoulders-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Boldonse-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/DMMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/EricaOne-OFL.txt +0 -94
- package/skills/creative/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/GeistMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Gloock-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Italiana-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Jura-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Lora-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/NationalPark-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/PixelifySans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/PoiretOne-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/RedHatMono-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Silkscreen-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/SmoochSans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/creative/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -93
- package/skills/creative/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
|
@@ -2,17 +2,58 @@ import { normalizeOptionalString } from "../../utils/string-coerce.js";
|
|
|
2
2
|
import { emitSessionTranscriptUpdate } from "../../session/transcript-events.js";
|
|
3
3
|
import { boundedJsonUtf8Bytes, firstEnumerableOwnKeys, jsonUtf8BytesOrInfinity } from "../../infra/json-utf8-bytes.js";
|
|
4
4
|
import { formatContextLimitTruncationNotice } from "./tool-result-context-guard.js";
|
|
5
|
-
import { truncateToolResultMessage } from "./tool-result-truncation.js";
|
|
6
|
-
import { getRawSessionAppendMessage, setRawSessionAppendMessage } from "./session-raw-append-message.js";
|
|
7
|
-
import { createPendingToolCallState } from "./session-tool-result-state.js";
|
|
5
|
+
import { resolveLiveToolResultMaxChars, truncateToolResultMessage } from "./tool-result-truncation.js";
|
|
8
6
|
import { extractToolCallsFromAssistant, extractToolResultId } from "../transcript/tool-call-id.js";
|
|
9
7
|
import { makeMissingToolResult, sanitizeToolCallInputs } from "../transcript/session-transcript-repair.js";
|
|
10
8
|
//#region src/agent/embedded/session-tool-result-guard.ts
|
|
11
9
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
10
|
+
* Install the guard on a SessionManager and return its control API.
|
|
11
|
+
* Subsequent assistant/toolResult writes by pi-coding-agent flow through the
|
|
12
|
+
* guard transparently.
|
|
15
13
|
*/
|
|
14
|
+
function installSessionToolResultGuard(sessionManager, opts = {}) {
|
|
15
|
+
const guard = new ToolResultGuard(sessionManager, opts);
|
|
16
|
+
guard.attach();
|
|
17
|
+
return {
|
|
18
|
+
flushPendingToolResults: () => guard.flushPending(),
|
|
19
|
+
clearPendingToolResults: () => guard.clearPending(),
|
|
20
|
+
getPendingIds: () => guard.getPendingIds()
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convenience wrapper used by the embedded runner pool: install the guard
|
|
25
|
+
* (idempotent), pin the size cap from the model context window, and expose
|
|
26
|
+
* `flushPendingToolResults` / `clearPendingToolResults` directly on the
|
|
27
|
+
* SessionManager instance so callers do not need to keep the install result.
|
|
28
|
+
*/
|
|
29
|
+
function guardSessionManager(sessionManager, opts) {
|
|
30
|
+
if (typeof sessionManager.flushPendingToolResults === "function") return sessionManager;
|
|
31
|
+
const result = installSessionToolResultGuard(sessionManager, {
|
|
32
|
+
sessionKey: opts?.sessionKey,
|
|
33
|
+
allowSyntheticToolResults: opts?.allowSyntheticToolResults,
|
|
34
|
+
missingToolResultText: opts?.missingToolResultText,
|
|
35
|
+
allowedToolNames: opts?.allowedToolNames,
|
|
36
|
+
maxToolResultChars: typeof opts?.contextWindowTokens === "number" ? resolveLiveToolResultMaxChars({
|
|
37
|
+
contextWindowTokens: opts.contextWindowTokens,
|
|
38
|
+
cfg: opts?.config,
|
|
39
|
+
agentId: opts?.agentId
|
|
40
|
+
}) : void 0
|
|
41
|
+
});
|
|
42
|
+
const tagged = sessionManager;
|
|
43
|
+
tagged.flushPendingToolResults = result.flushPendingToolResults;
|
|
44
|
+
tagged.clearPendingToolResults = result.clearPendingToolResults;
|
|
45
|
+
return tagged;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Recover the original (un-guarded) appendMessage for a session manager.
|
|
49
|
+
* Useful for callers that need a low-level "bypass the guard" write path.
|
|
50
|
+
*/
|
|
51
|
+
function getRawSessionAppendMessage(sessionManager) {
|
|
52
|
+
return sessionManager[RAW_APPEND_MESSAGE] ?? sessionManager.appendMessage.bind(sessionManager);
|
|
53
|
+
}
|
|
54
|
+
function resolveMaxToolResultChars(opts) {
|
|
55
|
+
return Math.max(1, opts.maxToolResultChars ?? 16e3);
|
|
56
|
+
}
|
|
16
57
|
function capToolResultSize(msg, maxChars) {
|
|
17
58
|
if (msg.role !== "toolResult") return msg;
|
|
18
59
|
return truncateToolResultMessage(msg, maxChars, {
|
|
@@ -20,9 +61,6 @@ function capToolResultSize(msg, maxChars) {
|
|
|
20
61
|
minKeepChars: 2e3
|
|
21
62
|
});
|
|
22
63
|
}
|
|
23
|
-
function resolveMaxToolResultChars(opts) {
|
|
24
|
-
return Math.max(1, opts?.maxToolResultChars ?? 16e3);
|
|
25
|
-
}
|
|
26
64
|
const MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES = 8192;
|
|
27
65
|
const MAX_PERSISTED_DETAIL_STRING_CHARS = 2e3;
|
|
28
66
|
const MAX_PERSISTED_DETAIL_SESSION_COUNT = 10;
|
|
@@ -170,58 +208,116 @@ function normalizePersistedToolResultName(message, fallbackName) {
|
|
|
170
208
|
};
|
|
171
209
|
return toolResult;
|
|
172
210
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
211
|
+
const RAW_APPEND_MESSAGE = Symbol("xopc.session.rawAppendMessage");
|
|
212
|
+
function rememberOriginalAppend(sessionManager) {
|
|
213
|
+
const tagged = sessionManager;
|
|
214
|
+
const stored = tagged[RAW_APPEND_MESSAGE];
|
|
215
|
+
if (stored) return stored;
|
|
216
|
+
const original = sessionManager.appendMessage.bind(sessionManager);
|
|
217
|
+
tagged[RAW_APPEND_MESSAGE] = original;
|
|
218
|
+
return original;
|
|
219
|
+
}
|
|
220
|
+
var PendingToolCallTracker = class {
|
|
221
|
+
pending = /* @__PURE__ */ new Map();
|
|
222
|
+
size() {
|
|
223
|
+
return this.pending.size;
|
|
224
|
+
}
|
|
225
|
+
getToolName(id) {
|
|
226
|
+
return this.pending.get(id);
|
|
227
|
+
}
|
|
228
|
+
delete(id) {
|
|
229
|
+
this.pending.delete(id);
|
|
230
|
+
}
|
|
231
|
+
clear() {
|
|
232
|
+
this.pending.clear();
|
|
233
|
+
}
|
|
234
|
+
trackToolCalls(calls) {
|
|
235
|
+
for (const call of calls) this.pending.set(call.id, call.name);
|
|
236
|
+
}
|
|
237
|
+
entries() {
|
|
238
|
+
return this.pending.entries();
|
|
239
|
+
}
|
|
240
|
+
getPendingIds() {
|
|
241
|
+
return Array.from(this.pending.keys());
|
|
242
|
+
}
|
|
243
|
+
shouldFlushForSanitizedDrop() {
|
|
244
|
+
return this.pending.size > 0;
|
|
245
|
+
}
|
|
246
|
+
shouldFlushBeforeNonToolResult(nextRole, toolCallCount) {
|
|
247
|
+
return this.pending.size > 0 && (toolCallCount === 0 || nextRole !== "assistant");
|
|
248
|
+
}
|
|
249
|
+
shouldFlushBeforeNewToolCalls(toolCallCount) {
|
|
250
|
+
return this.pending.size > 0 && toolCallCount > 0;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
var ToolResultGuard = class {
|
|
254
|
+
sessionManager;
|
|
255
|
+
opts;
|
|
256
|
+
pending = new PendingToolCallTracker();
|
|
257
|
+
originalAppend;
|
|
258
|
+
allowSyntheticToolResults;
|
|
259
|
+
maxToolResultChars;
|
|
260
|
+
constructor(sessionManager, opts) {
|
|
261
|
+
this.sessionManager = sessionManager;
|
|
262
|
+
this.opts = opts;
|
|
263
|
+
this.originalAppend = rememberOriginalAppend(sessionManager);
|
|
264
|
+
this.allowSyntheticToolResults = opts.allowSyntheticToolResults ?? true;
|
|
265
|
+
this.maxToolResultChars = resolveMaxToolResultChars(opts);
|
|
266
|
+
}
|
|
267
|
+
/** Monkey-patch the session manager so pi-coding-agent's internal appendMessage flows through us. */
|
|
268
|
+
attach() {
|
|
269
|
+
const bound = this.guardedAppend.bind(this);
|
|
270
|
+
this.sessionManager.appendMessage = bound;
|
|
271
|
+
}
|
|
272
|
+
flushPending() {
|
|
273
|
+
if (this.pending.size() === 0) return;
|
|
274
|
+
if (this.allowSyntheticToolResults) for (const [id, name] of this.pending.entries()) {
|
|
275
|
+
const synthetic = makeMissingToolResult({
|
|
276
|
+
toolCallId: id,
|
|
277
|
+
toolName: name,
|
|
278
|
+
text: this.opts.missingToolResultText
|
|
279
|
+
});
|
|
280
|
+
const flushed = this.applyBeforeWriteHook(this.persistToolResult(this.persistMessage(synthetic), {
|
|
281
|
+
toolCallId: id,
|
|
282
|
+
toolName: name,
|
|
283
|
+
isSynthetic: true
|
|
284
|
+
}));
|
|
285
|
+
if (flushed) this.originalAppend(capToolResultForPersistence(flushed, this.maxToolResultChars));
|
|
286
|
+
}
|
|
287
|
+
this.pending.clear();
|
|
288
|
+
}
|
|
289
|
+
clearPending() {
|
|
290
|
+
this.pending.clear();
|
|
291
|
+
}
|
|
292
|
+
getPendingIds() {
|
|
293
|
+
return this.pending.getPendingIds();
|
|
294
|
+
}
|
|
295
|
+
persistMessage(message) {
|
|
296
|
+
const transformer = this.opts.transformMessageForPersistence;
|
|
179
297
|
return transformer ? transformer(message) : message;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const transformer = opts
|
|
298
|
+
}
|
|
299
|
+
persistToolResult(message, meta) {
|
|
300
|
+
const transformer = this.opts.transformToolResultForPersistence;
|
|
183
301
|
return transformer ? transformer(message, meta) : message;
|
|
184
|
-
}
|
|
185
|
-
const allowSyntheticToolResults = opts?.allowSyntheticToolResults ?? true;
|
|
186
|
-
const missingToolResultText = opts?.missingToolResultText;
|
|
187
|
-
const beforeWrite = opts?.beforeMessageWriteHook;
|
|
188
|
-
const maxToolResultChars = resolveMaxToolResultChars(opts);
|
|
302
|
+
}
|
|
189
303
|
/**
|
|
190
304
|
* Run the before_message_write hook. Returns the (possibly modified) message,
|
|
191
305
|
* or null if the message should be blocked.
|
|
192
306
|
*/
|
|
193
|
-
|
|
307
|
+
applyBeforeWriteHook(msg) {
|
|
308
|
+
const beforeWrite = this.opts.beforeMessageWriteHook;
|
|
194
309
|
if (!beforeWrite) return msg;
|
|
195
310
|
const result = beforeWrite({ message: msg });
|
|
196
311
|
if (result?.block) return null;
|
|
197
312
|
if (result?.message) return result.message;
|
|
198
313
|
return msg;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
if (pendingState.size() === 0) return;
|
|
202
|
-
if (allowSyntheticToolResults) for (const [id, name] of pendingState.entries()) {
|
|
203
|
-
const flushed = applyBeforeWriteHook(persistToolResult(persistMessage(makeMissingToolResult({
|
|
204
|
-
toolCallId: id,
|
|
205
|
-
toolName: name,
|
|
206
|
-
text: missingToolResultText
|
|
207
|
-
})), {
|
|
208
|
-
toolCallId: id,
|
|
209
|
-
toolName: name,
|
|
210
|
-
isSynthetic: true
|
|
211
|
-
}));
|
|
212
|
-
if (flushed) originalAppend(capToolResultForPersistence(flushed, maxToolResultChars));
|
|
213
|
-
}
|
|
214
|
-
pendingState.clear();
|
|
215
|
-
};
|
|
216
|
-
const clearPendingToolResults = () => {
|
|
217
|
-
pendingState.clear();
|
|
218
|
-
};
|
|
219
|
-
const guardedAppend = (message) => {
|
|
314
|
+
}
|
|
315
|
+
guardedAppend(message) {
|
|
220
316
|
let nextMessage = message;
|
|
221
317
|
if (message.role === "assistant") {
|
|
222
|
-
const sanitized = sanitizeToolCallInputs([message], { allowedToolNames: opts
|
|
318
|
+
const sanitized = sanitizeToolCallInputs([message], { allowedToolNames: this.opts.allowedToolNames });
|
|
223
319
|
if (sanitized.length === 0) {
|
|
224
|
-
if (
|
|
320
|
+
if (this.pending.shouldFlushForSanitizedDrop()) this.flushPending();
|
|
225
321
|
return;
|
|
226
322
|
}
|
|
227
323
|
nextMessage = sanitized[0];
|
|
@@ -229,41 +325,37 @@ function installSessionToolResultGuard(sessionManager, opts) {
|
|
|
229
325
|
const nextRole = nextMessage.role;
|
|
230
326
|
if (nextRole === "toolResult") {
|
|
231
327
|
const id = extractToolResultId(nextMessage);
|
|
232
|
-
const toolName = id ?
|
|
233
|
-
if (id)
|
|
234
|
-
const
|
|
328
|
+
const toolName = id ? this.pending.getToolName(id) : void 0;
|
|
329
|
+
if (id) this.pending.delete(id);
|
|
330
|
+
const normalizedToolResult = normalizePersistedToolResultName(nextMessage, toolName);
|
|
331
|
+
const capped = capToolResultForPersistence(this.persistMessage(normalizedToolResult), this.maxToolResultChars);
|
|
332
|
+
const persisted = this.applyBeforeWriteHook(this.persistToolResult(capped, {
|
|
235
333
|
toolCallId: id ?? void 0,
|
|
236
334
|
toolName,
|
|
237
335
|
isSynthetic: false
|
|
238
336
|
}));
|
|
239
337
|
if (!persisted) return;
|
|
240
|
-
return originalAppend(capToolResultForPersistence(persisted, maxToolResultChars));
|
|
338
|
+
return this.originalAppend(capToolResultForPersistence(persisted, this.maxToolResultChars));
|
|
241
339
|
}
|
|
242
340
|
const stopReason = nextMessage.stopReason;
|
|
243
341
|
const toolCalls = nextRole === "assistant" && stopReason !== "aborted" && stopReason !== "error" ? extractToolCallsFromAssistant(nextMessage) : [];
|
|
244
|
-
if (
|
|
245
|
-
if (
|
|
246
|
-
const finalMessage = applyBeforeWriteHook(persistMessage(nextMessage));
|
|
342
|
+
if (this.pending.shouldFlushBeforeNonToolResult(nextRole, toolCalls.length)) this.flushPending();
|
|
343
|
+
if (this.pending.shouldFlushBeforeNewToolCalls(toolCalls.length)) this.flushPending();
|
|
344
|
+
const finalMessage = this.applyBeforeWriteHook(this.persistMessage(nextMessage));
|
|
247
345
|
if (!finalMessage) return;
|
|
248
|
-
const result = originalAppend(finalMessage);
|
|
249
|
-
const sessionFile = sessionManager.getSessionFile?.();
|
|
346
|
+
const result = this.originalAppend(finalMessage);
|
|
347
|
+
const sessionFile = this.sessionManager.getSessionFile?.();
|
|
250
348
|
if (sessionFile) emitSessionTranscriptUpdate({
|
|
251
349
|
sessionFile,
|
|
252
|
-
sessionKey: opts
|
|
350
|
+
sessionKey: this.opts.sessionKey,
|
|
253
351
|
message: finalMessage,
|
|
254
352
|
messageId: typeof result === "string" ? result : void 0
|
|
255
353
|
});
|
|
256
|
-
if (toolCalls.length > 0)
|
|
354
|
+
if (toolCalls.length > 0) this.pending.trackToolCalls(toolCalls);
|
|
257
355
|
return result;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return {
|
|
261
|
-
flushPendingToolResults,
|
|
262
|
-
clearPendingToolResults,
|
|
263
|
-
getPendingIds: pendingState.getPendingIds
|
|
264
|
-
};
|
|
265
|
-
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
266
358
|
//#endregion
|
|
267
|
-
export { getRawSessionAppendMessage, installSessionToolResultGuard };
|
|
359
|
+
export { getRawSessionAppendMessage, guardSessionManager, installSessionToolResultGuard };
|
|
268
360
|
|
|
269
361
|
//# sourceMappingURL=session-tool-result-guard.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-tool-result-guard.js","names":[],"sources":["../../../../src/agent/embedded/session-tool-result-guard.ts"],"sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { SessionManager } from \"@earendil-works/pi-coding-agent\";\nimport {\n boundedJsonUtf8Bytes,\n firstEnumerableOwnKeys,\n jsonUtf8BytesOrInfinity,\n type BoundedJsonUtf8Bytes,\n} from \"../../infra/json-utf8-bytes.js\";\nexport type BeforeMessageWriteHookEvent = { message: AgentMessage };\nexport type BeforeMessageWriteHookResult =\n | { block?: boolean; message?: AgentMessage }\n | undefined;\nimport { emitSessionTranscriptUpdate } from \"../../session/transcript-events.js\";\nimport { normalizeOptionalString } from \"../../utils/string-coerce.js\";\nimport { formatContextLimitTruncationNotice } from \"./tool-result-context-guard.js\";\nimport {\n DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS,\n truncateToolResultMessage,\n} from \"./tool-result-truncation.js\";\nimport {\n getRawSessionAppendMessage,\n setRawSessionAppendMessage,\n} from \"./session-raw-append-message.js\";\nimport { createPendingToolCallState } from \"./session-tool-result-state.js\";\nimport { makeMissingToolResult, sanitizeToolCallInputs } from '../transcript/session-transcript-repair.js';\nimport { extractToolCallsFromAssistant, extractToolResultId } from '../transcript/tool-call-id.js';\n\n/**\n * Truncate oversized text content blocks in a tool result message.\n * Returns the original message if under the limit, or a new message with\n * truncated text blocks otherwise.\n */\nfunction capToolResultSize(msg: AgentMessage, maxChars: number): AgentMessage {\n if ((msg as { role?: string }).role !== \"toolResult\") {\n return msg;\n }\n return truncateToolResultMessage(msg, maxChars, {\n suffix: (truncatedChars) => formatContextLimitTruncationNotice(truncatedChars),\n minKeepChars: 2_000,\n });\n}\n\nfunction resolveMaxToolResultChars(opts?: { maxToolResultChars?: number }): number {\n return Math.max(1, opts?.maxToolResultChars ?? DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS);\n}\n\n// `details` is runtime/UI metadata, not model-visible tool output. Keep the\n// session JSONL useful for debugging without letting metadata blobs dominate\n// disk, replay repair, transcript broadcasts, or future tooling that reads raw\n// sessions. Model-visible text belongs in tool result `content`.\nconst MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES = 8_192;\nconst MAX_PERSISTED_DETAIL_STRING_CHARS = 2_000;\nconst MAX_PERSISTED_DETAIL_SESSION_COUNT = 10;\nconst MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS = 200;\n\nfunction originalDetailsSizeFields(size: BoundedJsonUtf8Bytes): Record<string, number> {\n return size.complete\n ? { originalDetailsBytes: size.bytes }\n : { originalDetailsBytesAtLeast: size.bytes };\n}\n\nfunction truncatePersistedDetailString(\n value: string,\n maxChars = MAX_PERSISTED_DETAIL_STRING_CHARS,\n): string {\n if (value.length <= maxChars) {\n return value;\n }\n return `${value.slice(0, maxChars)}\\n\\n[xopc persisted detail truncated: ${\n value.length - maxChars\n } chars omitted]`;\n}\n\nfunction sanitizePersistedSessionDetail(value: unknown): unknown {\n if (!value || typeof value !== \"object\") {\n return value;\n }\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of [\n \"sessionId\",\n \"status\",\n \"pid\",\n \"startedAt\",\n \"endedAt\",\n \"runtimeMs\",\n \"cwd\",\n \"name\",\n \"truncated\",\n \"exitCode\",\n \"exitSignal\",\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === \"string\" ? truncatePersistedDetailString(field, 500) : field;\n }\n }\n if (typeof src.command === \"string\") {\n out.command = truncatePersistedDetailString(src.command, 500);\n }\n return out;\n}\n\nfunction buildPersistedDetailsFallback(\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n sanitizedBytes?: number,\n): Record<string, unknown> {\n // If even the structured summary is too large, keep only shape and stable\n // status fields. This preserves \"what happened?\" without persisting the raw\n // diagnostics payload that caused the cap to trip.\n const fallback: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n };\n if (sanitizedBytes !== undefined) {\n fallback.sanitizedDetailsBytes = sanitizedBytes;\n }\n if (src) {\n fallback.originalDetailKeys = firstEnumerableOwnKeys(src, 40);\n for (const key of [\"status\", \"sessionId\", \"pid\", \"exitCode\", \"exitSignal\", \"truncated\"]) {\n const field = src[key];\n if (field !== undefined) {\n fallback[key] =\n typeof field === \"string\"\n ? truncatePersistedDetailString(field, MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS)\n : field;\n }\n }\n }\n return fallback;\n}\n\nfunction enforcePersistedDetailsByteCap(\n value: Record<string, unknown>,\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n): Record<string, unknown> {\n const sanitizedBytes = jsonUtf8BytesOrInfinity(value);\n if (sanitizedBytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return value;\n }\n const fallback = buildPersistedDetailsFallback(src, originalSize, sanitizedBytes);\n if (jsonUtf8BytesOrInfinity(fallback) <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return fallback;\n }\n return {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n sanitizedDetailsBytes: sanitizedBytes,\n };\n}\n\nfunction sanitizeToolResultDetailsForPersistence(details: unknown): unknown {\n if (details === undefined || details === null) {\n return details;\n }\n // Measure with an early-exit walker so hostile or enormous details do not\n // need to be fully stringified just to learn they exceed the persistence cap.\n const originalSize = boundedJsonUtf8Bytes(details, MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES);\n if (originalSize.complete && originalSize.bytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return details;\n }\n if (typeof details !== \"object\") {\n return enforcePersistedDetailsByteCap(\n {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n valueType: typeof details,\n },\n undefined,\n originalSize,\n );\n }\n const src = details as Record<string, unknown>;\n const out: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n originalDetailKeys: firstEnumerableOwnKeys(src, 40),\n };\n for (const key of [\n \"status\",\n \"sessionId\",\n \"pid\",\n \"startedAt\",\n \"endedAt\",\n \"cwd\",\n \"name\",\n \"exitCode\",\n \"exitSignal\",\n \"retryInMs\",\n \"total\",\n \"totalLines\",\n \"totalChars\",\n \"truncated\",\n \"fullOutputPath\",\n \"truncation\",\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === \"string\" ? truncatePersistedDetailString(field) : field;\n }\n }\n if (typeof src.tail === \"string\") {\n out.tail = truncatePersistedDetailString(src.tail);\n }\n if (Array.isArray(src.sessions)) {\n out.sessions = src.sessions\n .slice(0, MAX_PERSISTED_DETAIL_SESSION_COUNT)\n .map(sanitizePersistedSessionDetail);\n if (src.sessions.length > MAX_PERSISTED_DETAIL_SESSION_COUNT) {\n out.sessionsTruncated = src.sessions.length - MAX_PERSISTED_DETAIL_SESSION_COUNT;\n }\n }\n return enforcePersistedDetailsByteCap(out, src, originalSize);\n}\n\nfunction capToolResultDetails(msg: AgentMessage): AgentMessage {\n if ((msg as { role?: string }).role !== \"toolResult\") {\n return msg;\n }\n const details = (msg as { details?: unknown }).details;\n const sanitizedDetails = sanitizeToolResultDetailsForPersistence(details);\n if (sanitizedDetails === details) {\n return msg;\n }\n const next = { ...msg } as AgentMessage & { details?: unknown };\n next.details = sanitizedDetails;\n return next;\n}\n\nfunction capToolResultForPersistence(msg: AgentMessage, maxChars: number): AgentMessage {\n return capToolResultDetails(capToolResultSize(msg, maxChars));\n}\n\nfunction normalizePersistedToolResultName(\n message: AgentMessage,\n fallbackName?: string,\n): AgentMessage {\n if ((message as { role?: unknown }).role !== \"toolResult\") {\n return message;\n }\n const toolResult = message as Extract<AgentMessage, { role: \"toolResult\" }>;\n const rawToolName = (toolResult as { toolName?: unknown }).toolName;\n const normalizedToolName = normalizeOptionalString(rawToolName);\n if (normalizedToolName) {\n if (rawToolName === normalizedToolName) {\n return toolResult;\n }\n return { ...toolResult, toolName: normalizedToolName };\n }\n\n const normalizedFallback = normalizeOptionalString(fallbackName);\n if (normalizedFallback) {\n return { ...toolResult, toolName: normalizedFallback };\n }\n\n if (typeof rawToolName === \"string\") {\n return { ...toolResult, toolName: \"unknown\" };\n }\n return toolResult;\n}\n\nexport { getRawSessionAppendMessage };\n\nexport function installSessionToolResultGuard(\n sessionManager: SessionManager,\n opts?: {\n /** Optional session key for transcript update broadcasts. */\n sessionKey?: string;\n /**\n * Optional transform applied to any message before persistence.\n */\n transformMessageForPersistence?: (message: AgentMessage) => AgentMessage;\n /**\n * Optional, synchronous transform applied to toolResult messages *before* they are\n * persisted to the session transcript.\n */\n transformToolResultForPersistence?: (\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ) => AgentMessage;\n /**\n * Whether to synthesize missing tool results to satisfy strict providers.\n * Defaults to true.\n */\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n /**\n * Optional set/list of tool names accepted for assistant toolCall/toolUse blocks.\n * When set, tool calls with unknown names are dropped before persistence.\n */\n allowedToolNames?: Iterable<string>;\n /**\n * Synchronous hook invoked before any message is written to the session JSONL.\n * If the hook returns { block: true }, the message is silently dropped.\n * If it returns { message }, the modified message is written instead.\n */\n beforeMessageWriteHook?: (\n event: BeforeMessageWriteHookEvent,\n ) => BeforeMessageWriteHookResult;\n maxToolResultChars?: number;\n },\n): {\n flushPendingToolResults: () => void;\n clearPendingToolResults: () => void;\n getPendingIds: () => string[];\n} {\n const originalAppend = getRawSessionAppendMessage(sessionManager);\n setRawSessionAppendMessage(sessionManager, originalAppend);\n const pendingState = createPendingToolCallState();\n const persistMessage = (message: AgentMessage) => {\n const transformer = opts?.transformMessageForPersistence;\n return transformer ? transformer(message) : message;\n };\n\n const persistToolResult = (\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ) => {\n const transformer = opts?.transformToolResultForPersistence;\n return transformer ? transformer(message, meta) : message;\n };\n\n const allowSyntheticToolResults = opts?.allowSyntheticToolResults ?? true;\n const missingToolResultText = opts?.missingToolResultText;\n const beforeWrite = opts?.beforeMessageWriteHook;\n const maxToolResultChars = resolveMaxToolResultChars(opts);\n\n /**\n * Run the before_message_write hook. Returns the (possibly modified) message,\n * or null if the message should be blocked.\n */\n const applyBeforeWriteHook = (msg: AgentMessage): AgentMessage | null => {\n if (!beforeWrite) {\n return msg;\n }\n const result = beforeWrite({ message: msg });\n if (result?.block) {\n return null;\n }\n if (result?.message) {\n return result.message;\n }\n return msg;\n };\n\n const flushPendingToolResults = () => {\n if (pendingState.size() === 0) {\n return;\n }\n if (allowSyntheticToolResults) {\n for (const [id, name] of pendingState.entries()) {\n const synthetic = makeMissingToolResult({\n toolCallId: id,\n toolName: name,\n text: missingToolResultText,\n });\n const flushed = applyBeforeWriteHook(\n persistToolResult(persistMessage(synthetic), {\n toolCallId: id,\n toolName: name,\n isSynthetic: true,\n }),\n );\n if (flushed) {\n originalAppend(capToolResultForPersistence(flushed, maxToolResultChars) as never);\n }\n }\n }\n pendingState.clear();\n };\n\n const clearPendingToolResults = () => {\n pendingState.clear();\n };\n\n const guardedAppend = (message: AgentMessage) => {\n let nextMessage = message;\n const role = (message as { role?: unknown }).role;\n if (role === \"assistant\") {\n const sanitized = sanitizeToolCallInputs([message], {\n allowedToolNames: opts?.allowedToolNames,\n });\n if (sanitized.length === 0) {\n if (pendingState.shouldFlushForSanitizedDrop()) {\n flushPendingToolResults();\n }\n return undefined;\n }\n nextMessage = sanitized[0];\n }\n const nextRole = (nextMessage as { role?: unknown }).role;\n\n if (nextRole === \"toolResult\") {\n const id = extractToolResultId(nextMessage as Extract<AgentMessage, { role: \"toolResult\" }>);\n const toolName = id ? pendingState.getToolName(id) : undefined;\n if (id) {\n pendingState.delete(id);\n }\n const normalizedToolResult = normalizePersistedToolResultName(nextMessage, toolName);\n // Apply hard size cap before persistence to prevent oversized tool results\n // from consuming the entire context window on subsequent LLM calls.\n const capped = capToolResultForPersistence(\n persistMessage(normalizedToolResult),\n maxToolResultChars,\n );\n const persisted = applyBeforeWriteHook(\n persistToolResult(capped, {\n toolCallId: id ?? undefined,\n toolName,\n isSynthetic: false,\n }),\n );\n if (!persisted) {\n return undefined;\n }\n return originalAppend(capToolResultForPersistence(persisted, maxToolResultChars) as never);\n }\n\n // Skip tool call extraction for aborted/errored assistant messages.\n // When stopReason is \"error\" or \"aborted\", the tool_use blocks may be incomplete\n // and should not have synthetic tool_results created. Creating synthetic results\n // for incomplete tool calls causes API 400 errors:\n // \"unexpected tool_use_id found in tool_result blocks\"\n // This matches the behavior in repairToolUseResultPairing (session-transcript-repair.ts)\n const stopReason = (nextMessage as { stopReason?: string }).stopReason;\n const toolCalls =\n nextRole === \"assistant\" && stopReason !== \"aborted\" && stopReason !== \"error\"\n ? extractToolCallsFromAssistant(nextMessage as Extract<AgentMessage, { role: \"assistant\" }>)\n : [];\n\n // Always clear pending tool call state before appending non-tool-result messages.\n // flushPendingToolResults() only inserts synthetic results when allowSyntheticToolResults\n // is true; it always clears the pending map. Without this, providers that disable\n // synthetic results (e.g. OpenAI) accumulate stale pending state when a user message\n // interrupts in-flight tool calls, leaving orphaned tool_use blocks in the transcript\n // that cause API 400 errors on subsequent requests.\n if (pendingState.shouldFlushBeforeNonToolResult(nextRole, toolCalls.length)) {\n flushPendingToolResults();\n }\n // If new tool calls arrive while older ones are pending, flush the old ones first.\n if (pendingState.shouldFlushBeforeNewToolCalls(toolCalls.length)) {\n flushPendingToolResults();\n }\n\n const finalMessage = applyBeforeWriteHook(persistMessage(nextMessage));\n if (!finalMessage) {\n return undefined;\n }\n const result = originalAppend(finalMessage as never);\n\n const sessionFile = (\n sessionManager as { getSessionFile?: () => string | null }\n ).getSessionFile?.();\n if (sessionFile) {\n emitSessionTranscriptUpdate({\n sessionFile,\n sessionKey: opts?.sessionKey,\n message: finalMessage,\n messageId: typeof result === \"string\" ? result : undefined,\n });\n }\n\n if (toolCalls.length > 0) {\n pendingState.trackToolCalls(toolCalls);\n }\n\n return result;\n };\n\n // Monkey-patch appendMessage with our guarded version.\n sessionManager.appendMessage = guardedAppend as SessionManager[\"appendMessage\"];\n\n return {\n flushPendingToolResults,\n clearPendingToolResults,\n getPendingIds: pendingState.getPendingIds,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session-tool-result-guard.js","names":[],"sources":["../../../../src/agent/embedded/session-tool-result-guard.ts"],"sourcesContent":["/**\n * Session tool-result guard — wraps a pi `SessionManager.appendMessage` to:\n * 1. cap oversized tool-result text + details so they cannot blow up the next\n * LLM request (size + persistence limits).\n * 2. track pending tool-call IDs so missing tool results can be synthesised\n * (some providers refuse a turn that has an orphan tool_use block).\n * 3. drop assistant `toolCall` blocks whose tool name is not in the allowlist\n * (these would also trigger provider 400s).\n * 4. broadcast `xopc:transcript-row` updates so the gateway UI can stream them.\n *\n * Previously this module shipped with three sibling files\n * (`session-tool-result-state.ts`, `session-raw-append-message.ts`,\n * `session-tool-result-guard-wrapper.ts`). They are now consolidated here as\n * private constructs around the `ToolResultGuard` class. Pi-coding-agent owns\n * the `SessionManager` instance and calls `appendMessage` from inside the\n * runtime, so we still need to monkey-patch that method — but the patched\n * implementation is just `guard.guardedAppend.bind(guard)` and all state lives\n * on the class.\n */\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport type { SessionManager } from '@earendil-works/pi-coding-agent';\n\nimport type { Config } from '../../config/schema.js';\nimport {\n boundedJsonUtf8Bytes,\n firstEnumerableOwnKeys,\n jsonUtf8BytesOrInfinity,\n type BoundedJsonUtf8Bytes,\n} from '../../infra/json-utf8-bytes.js';\nimport { emitSessionTranscriptUpdate } from '../../session/transcript-events.js';\nimport { normalizeOptionalString } from '../../utils/string-coerce.js';\nimport { formatContextLimitTruncationNotice } from './tool-result-context-guard.js';\nimport {\n DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS,\n resolveLiveToolResultMaxChars,\n truncateToolResultMessage,\n} from './tool-result-truncation.js';\nimport {\n makeMissingToolResult,\n sanitizeToolCallInputs,\n} from '../transcript/session-transcript-repair.js';\nimport {\n extractToolCallsFromAssistant,\n extractToolResultId,\n} from '../transcript/tool-call-id.js';\n\n// ── Public surface ──────────────────────────────────────────────────────────\n\nexport type BeforeMessageWriteHookEvent = { message: AgentMessage };\nexport type BeforeMessageWriteHookResult =\n | { block?: boolean; message?: AgentMessage }\n | undefined;\n\nexport interface ToolResultGuardOptions {\n /** Optional session key for transcript update broadcasts. */\n sessionKey?: string;\n /** Optional transform applied to any message before persistence. */\n transformMessageForPersistence?: (message: AgentMessage) => AgentMessage;\n /**\n * Optional, synchronous transform applied to toolResult messages *before* they are\n * persisted to the session transcript.\n */\n transformToolResultForPersistence?: (\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ) => AgentMessage;\n /**\n * Whether to synthesize missing tool results to satisfy strict providers.\n * Defaults to true.\n */\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n /**\n * Optional set/list of tool names accepted for assistant toolCall/toolUse blocks.\n * When set, tool calls with unknown names are dropped before persistence.\n */\n allowedToolNames?: Iterable<string>;\n /**\n * Synchronous hook invoked before any message is written to the session JSONL.\n * If the hook returns { block: true }, the message is silently dropped.\n * If it returns { message }, the modified message is written instead.\n */\n beforeMessageWriteHook?: (event: BeforeMessageWriteHookEvent) => BeforeMessageWriteHookResult;\n maxToolResultChars?: number;\n}\n\nexport interface InstallSessionToolResultGuardResult {\n flushPendingToolResults: () => void;\n clearPendingToolResults: () => void;\n getPendingIds: () => string[];\n}\n\n/** Idempotent wrapper that also adds the helper methods consumers expect. */\nexport type GuardedPiTranscriptManager = SessionManager & {\n flushPendingToolResults?: () => void;\n clearPendingToolResults?: () => void;\n};\n\n/**\n * Install the guard on a SessionManager and return its control API.\n * Subsequent assistant/toolResult writes by pi-coding-agent flow through the\n * guard transparently.\n */\nexport function installSessionToolResultGuard(\n sessionManager: SessionManager,\n opts: ToolResultGuardOptions = {},\n): InstallSessionToolResultGuardResult {\n const guard = new ToolResultGuard(sessionManager, opts);\n guard.attach();\n return {\n flushPendingToolResults: () => guard.flushPending(),\n clearPendingToolResults: () => guard.clearPending(),\n getPendingIds: () => guard.getPendingIds(),\n };\n}\n\n/**\n * Convenience wrapper used by the embedded runner pool: install the guard\n * (idempotent), pin the size cap from the model context window, and expose\n * `flushPendingToolResults` / `clearPendingToolResults` directly on the\n * SessionManager instance so callers do not need to keep the install result.\n */\nexport function guardSessionManager(\n sessionManager: SessionManager,\n opts?: {\n agentId?: string;\n sessionKey?: string;\n config?: Config;\n contextWindowTokens?: number;\n allowSyntheticToolResults?: boolean;\n missingToolResultText?: string;\n allowedToolNames?: Iterable<string>;\n },\n): GuardedPiTranscriptManager {\n if (typeof (sessionManager as GuardedPiTranscriptManager).flushPendingToolResults === 'function') {\n return sessionManager as GuardedPiTranscriptManager;\n }\n\n const result = installSessionToolResultGuard(sessionManager, {\n sessionKey: opts?.sessionKey,\n allowSyntheticToolResults: opts?.allowSyntheticToolResults,\n missingToolResultText: opts?.missingToolResultText,\n allowedToolNames: opts?.allowedToolNames,\n maxToolResultChars:\n typeof opts?.contextWindowTokens === 'number'\n ? resolveLiveToolResultMaxChars({\n contextWindowTokens: opts.contextWindowTokens,\n cfg: opts?.config,\n agentId: opts?.agentId,\n })\n : undefined,\n });\n const tagged = sessionManager as GuardedPiTranscriptManager;\n tagged.flushPendingToolResults = result.flushPendingToolResults;\n tagged.clearPendingToolResults = result.clearPendingToolResults;\n return tagged;\n}\n\n/**\n * Recover the original (un-guarded) appendMessage for a session manager.\n * Useful for callers that need a low-level \"bypass the guard\" write path.\n */\nexport function getRawSessionAppendMessage(\n sessionManager: SessionManager,\n): SessionManager['appendMessage'] {\n const stored = (sessionManager as SessionManagerWithRawAppend)[RAW_APPEND_MESSAGE];\n return stored ?? sessionManager.appendMessage.bind(sessionManager);\n}\n\n// ── Internal: persistence + truncation helpers ──────────────────────────────\n\nfunction resolveMaxToolResultChars(opts: { maxToolResultChars?: number }): number {\n return Math.max(1, opts.maxToolResultChars ?? DEFAULT_MAX_LIVE_TOOL_RESULT_CHARS);\n}\n\nfunction capToolResultSize(msg: AgentMessage, maxChars: number): AgentMessage {\n if ((msg as { role?: string }).role !== 'toolResult') {\n return msg;\n }\n return truncateToolResultMessage(msg, maxChars, {\n suffix: (truncatedChars) => formatContextLimitTruncationNotice(truncatedChars),\n minKeepChars: 2_000,\n });\n}\n\n// `details` is runtime/UI metadata, not model-visible tool output. Keep the\n// session JSONL useful for debugging without letting metadata blobs dominate\n// disk, replay repair, transcript broadcasts, or future tooling that reads raw\n// sessions. Model-visible text belongs in tool result `content`.\nconst MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES = 8_192;\nconst MAX_PERSISTED_DETAIL_STRING_CHARS = 2_000;\nconst MAX_PERSISTED_DETAIL_SESSION_COUNT = 10;\nconst MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS = 200;\n\nfunction originalDetailsSizeFields(size: BoundedJsonUtf8Bytes): Record<string, number> {\n return size.complete\n ? { originalDetailsBytes: size.bytes }\n : { originalDetailsBytesAtLeast: size.bytes };\n}\n\nfunction truncatePersistedDetailString(\n value: string,\n maxChars = MAX_PERSISTED_DETAIL_STRING_CHARS,\n): string {\n if (value.length <= maxChars) {\n return value;\n }\n return `${value.slice(0, maxChars)}\\n\\n[xopc persisted detail truncated: ${\n value.length - maxChars\n } chars omitted]`;\n}\n\nfunction sanitizePersistedSessionDetail(value: unknown): unknown {\n if (!value || typeof value !== 'object') {\n return value;\n }\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of [\n 'sessionId',\n 'status',\n 'pid',\n 'startedAt',\n 'endedAt',\n 'runtimeMs',\n 'cwd',\n 'name',\n 'truncated',\n 'exitCode',\n 'exitSignal',\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === 'string' ? truncatePersistedDetailString(field, 500) : field;\n }\n }\n if (typeof src.command === 'string') {\n out.command = truncatePersistedDetailString(src.command, 500);\n }\n return out;\n}\n\nfunction buildPersistedDetailsFallback(\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n sanitizedBytes?: number,\n): Record<string, unknown> {\n const fallback: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n };\n if (sanitizedBytes !== undefined) {\n fallback.sanitizedDetailsBytes = sanitizedBytes;\n }\n if (src) {\n fallback.originalDetailKeys = firstEnumerableOwnKeys(src, 40);\n for (const key of ['status', 'sessionId', 'pid', 'exitCode', 'exitSignal', 'truncated']) {\n const field = src[key];\n if (field !== undefined) {\n fallback[key] =\n typeof field === 'string'\n ? truncatePersistedDetailString(field, MAX_PERSISTED_DETAIL_FALLBACK_STRING_CHARS)\n : field;\n }\n }\n }\n return fallback;\n}\n\nfunction enforcePersistedDetailsByteCap(\n value: Record<string, unknown>,\n src: Record<string, unknown> | undefined,\n originalSize: BoundedJsonUtf8Bytes,\n): Record<string, unknown> {\n const sanitizedBytes = jsonUtf8BytesOrInfinity(value);\n if (sanitizedBytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return value;\n }\n const fallback = buildPersistedDetailsFallback(src, originalSize, sanitizedBytes);\n if (jsonUtf8BytesOrInfinity(fallback) <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return fallback;\n }\n return {\n persistedDetailsTruncated: true,\n finalDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n sanitizedDetailsBytes: sanitizedBytes,\n };\n}\n\nfunction sanitizeToolResultDetailsForPersistence(details: unknown): unknown {\n if (details === undefined || details === null) {\n return details;\n }\n const originalSize = boundedJsonUtf8Bytes(details, MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES);\n if (originalSize.complete && originalSize.bytes <= MAX_PERSISTED_TOOL_RESULT_DETAILS_BYTES) {\n return details;\n }\n if (typeof details !== 'object') {\n return enforcePersistedDetailsByteCap(\n {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n valueType: typeof details,\n },\n undefined,\n originalSize,\n );\n }\n const src = details as Record<string, unknown>;\n const out: Record<string, unknown> = {\n persistedDetailsTruncated: true,\n ...originalDetailsSizeFields(originalSize),\n originalDetailKeys: firstEnumerableOwnKeys(src, 40),\n };\n for (const key of [\n 'status',\n 'sessionId',\n 'pid',\n 'startedAt',\n 'endedAt',\n 'cwd',\n 'name',\n 'exitCode',\n 'exitSignal',\n 'retryInMs',\n 'total',\n 'totalLines',\n 'totalChars',\n 'truncated',\n 'fullOutputPath',\n 'truncation',\n ]) {\n const field = src[key];\n if (field !== undefined) {\n out[key] = typeof field === 'string' ? truncatePersistedDetailString(field) : field;\n }\n }\n if (typeof src.tail === 'string') {\n out.tail = truncatePersistedDetailString(src.tail);\n }\n if (Array.isArray(src.sessions)) {\n out.sessions = src.sessions\n .slice(0, MAX_PERSISTED_DETAIL_SESSION_COUNT)\n .map(sanitizePersistedSessionDetail);\n if (src.sessions.length > MAX_PERSISTED_DETAIL_SESSION_COUNT) {\n out.sessionsTruncated = src.sessions.length - MAX_PERSISTED_DETAIL_SESSION_COUNT;\n }\n }\n return enforcePersistedDetailsByteCap(out, src, originalSize);\n}\n\nfunction capToolResultDetails(msg: AgentMessage): AgentMessage {\n if ((msg as { role?: string }).role !== 'toolResult') {\n return msg;\n }\n const details = (msg as { details?: unknown }).details;\n const sanitizedDetails = sanitizeToolResultDetailsForPersistence(details);\n if (sanitizedDetails === details) {\n return msg;\n }\n const next = { ...msg } as AgentMessage & { details?: unknown };\n next.details = sanitizedDetails;\n return next;\n}\n\nfunction capToolResultForPersistence(msg: AgentMessage, maxChars: number): AgentMessage {\n return capToolResultDetails(capToolResultSize(msg, maxChars));\n}\n\nfunction normalizePersistedToolResultName(\n message: AgentMessage,\n fallbackName?: string,\n): AgentMessage {\n if ((message as { role?: unknown }).role !== 'toolResult') {\n return message;\n }\n const toolResult = message as Extract<AgentMessage, { role: 'toolResult' }>;\n const rawToolName = (toolResult as { toolName?: unknown }).toolName;\n const normalizedToolName = normalizeOptionalString(rawToolName);\n if (normalizedToolName) {\n if (rawToolName === normalizedToolName) {\n return toolResult;\n }\n return { ...toolResult, toolName: normalizedToolName };\n }\n\n const normalizedFallback = normalizeOptionalString(fallbackName);\n if (normalizedFallback) {\n return { ...toolResult, toolName: normalizedFallback };\n }\n\n if (typeof rawToolName === 'string') {\n return { ...toolResult, toolName: 'unknown' };\n }\n return toolResult;\n}\n\n// ── Internal: raw-append symbol storage ─────────────────────────────────────\n\nconst RAW_APPEND_MESSAGE = Symbol('xopc.session.rawAppendMessage');\n\ntype SessionManagerWithRawAppend = SessionManager & {\n [RAW_APPEND_MESSAGE]?: SessionManager['appendMessage'];\n};\n\nfunction rememberOriginalAppend(\n sessionManager: SessionManager,\n): SessionManager['appendMessage'] {\n const tagged = sessionManager as SessionManagerWithRawAppend;\n const stored = tagged[RAW_APPEND_MESSAGE];\n if (stored) {\n return stored;\n }\n const original = sessionManager.appendMessage.bind(sessionManager);\n tagged[RAW_APPEND_MESSAGE] = original;\n return original;\n}\n\n// ── Internal: pending tool-call state ──────────────────────────────────────\n\ntype PendingToolCall = { id: string; name?: string };\n\nclass PendingToolCallTracker {\n private readonly pending = new Map<string, string | undefined>();\n\n size(): number {\n return this.pending.size;\n }\n\n getToolName(id: string): string | undefined {\n return this.pending.get(id);\n }\n\n delete(id: string): void {\n this.pending.delete(id);\n }\n\n clear(): void {\n this.pending.clear();\n }\n\n trackToolCalls(calls: readonly PendingToolCall[]): void {\n for (const call of calls) {\n this.pending.set(call.id, call.name);\n }\n }\n\n entries(): IterableIterator<[string, string | undefined]> {\n return this.pending.entries();\n }\n\n getPendingIds(): string[] {\n return Array.from(this.pending.keys());\n }\n\n shouldFlushForSanitizedDrop(): boolean {\n return this.pending.size > 0;\n }\n\n shouldFlushBeforeNonToolResult(nextRole: unknown, toolCallCount: number): boolean {\n return this.pending.size > 0 && (toolCallCount === 0 || nextRole !== 'assistant');\n }\n\n shouldFlushBeforeNewToolCalls(toolCallCount: number): boolean {\n return this.pending.size > 0 && toolCallCount > 0;\n }\n}\n\n// ── ToolResultGuard class ──────────────────────────────────────────────────\n\nclass ToolResultGuard {\n private readonly sessionManager: SessionManager;\n private readonly opts: ToolResultGuardOptions;\n private readonly pending = new PendingToolCallTracker();\n private readonly originalAppend: SessionManager['appendMessage'];\n private readonly allowSyntheticToolResults: boolean;\n private readonly maxToolResultChars: number;\n\n constructor(sessionManager: SessionManager, opts: ToolResultGuardOptions) {\n this.sessionManager = sessionManager;\n this.opts = opts;\n this.originalAppend = rememberOriginalAppend(sessionManager);\n this.allowSyntheticToolResults = opts.allowSyntheticToolResults ?? true;\n this.maxToolResultChars = resolveMaxToolResultChars(opts);\n }\n\n /** Monkey-patch the session manager so pi-coding-agent's internal appendMessage flows through us. */\n attach(): void {\n const bound = this.guardedAppend.bind(this);\n this.sessionManager.appendMessage = bound as SessionManager['appendMessage'];\n }\n\n flushPending(): void {\n if (this.pending.size() === 0) {\n return;\n }\n if (this.allowSyntheticToolResults) {\n for (const [id, name] of this.pending.entries()) {\n const synthetic = makeMissingToolResult({\n toolCallId: id,\n toolName: name,\n text: this.opts.missingToolResultText,\n });\n const flushed = this.applyBeforeWriteHook(\n this.persistToolResult(this.persistMessage(synthetic), {\n toolCallId: id,\n toolName: name,\n isSynthetic: true,\n }),\n );\n if (flushed) {\n this.originalAppend(capToolResultForPersistence(flushed, this.maxToolResultChars) as never);\n }\n }\n }\n this.pending.clear();\n }\n\n clearPending(): void {\n this.pending.clear();\n }\n\n getPendingIds(): string[] {\n return this.pending.getPendingIds();\n }\n\n private persistMessage(message: AgentMessage): AgentMessage {\n const transformer = this.opts.transformMessageForPersistence;\n return transformer ? transformer(message) : message;\n }\n\n private persistToolResult(\n message: AgentMessage,\n meta: { toolCallId?: string; toolName?: string; isSynthetic?: boolean },\n ): AgentMessage {\n const transformer = this.opts.transformToolResultForPersistence;\n return transformer ? transformer(message, meta) : message;\n }\n\n /**\n * Run the before_message_write hook. Returns the (possibly modified) message,\n * or null if the message should be blocked.\n */\n private applyBeforeWriteHook(msg: AgentMessage): AgentMessage | null {\n const beforeWrite = this.opts.beforeMessageWriteHook;\n if (!beforeWrite) {\n return msg;\n }\n const result = beforeWrite({ message: msg });\n if (result?.block) {\n return null;\n }\n if (result?.message) {\n return result.message;\n }\n return msg;\n }\n\n private guardedAppend(message: AgentMessage): unknown {\n let nextMessage = message;\n const role = (message as { role?: unknown }).role;\n if (role === 'assistant') {\n const sanitized = sanitizeToolCallInputs([message], {\n allowedToolNames: this.opts.allowedToolNames,\n });\n if (sanitized.length === 0) {\n if (this.pending.shouldFlushForSanitizedDrop()) {\n this.flushPending();\n }\n return undefined;\n }\n nextMessage = sanitized[0];\n }\n const nextRole = (nextMessage as { role?: unknown }).role;\n\n if (nextRole === 'toolResult') {\n const id = extractToolResultId(nextMessage as Extract<AgentMessage, { role: 'toolResult' }>);\n const toolName = id ? this.pending.getToolName(id) : undefined;\n if (id) {\n this.pending.delete(id);\n }\n const normalizedToolResult = normalizePersistedToolResultName(nextMessage, toolName);\n // Apply hard size cap before persistence to prevent oversized tool results\n // from consuming the entire context window on subsequent LLM calls.\n const capped = capToolResultForPersistence(\n this.persistMessage(normalizedToolResult),\n this.maxToolResultChars,\n );\n const persisted = this.applyBeforeWriteHook(\n this.persistToolResult(capped, {\n toolCallId: id ?? undefined,\n toolName,\n isSynthetic: false,\n }),\n );\n if (!persisted) {\n return undefined;\n }\n return this.originalAppend(capToolResultForPersistence(persisted, this.maxToolResultChars) as never);\n }\n\n // Skip tool call extraction for aborted/errored assistant messages.\n // When stopReason is \"error\" or \"aborted\", the tool_use blocks may be incomplete\n // and should not have synthetic tool_results created. Creating synthetic results\n // for incomplete tool calls causes API 400 errors:\n // \"unexpected tool_use_id found in tool_result blocks\"\n // This matches the behavior in repairToolUseResultPairing (session-transcript-repair.ts)\n const stopReason = (nextMessage as { stopReason?: string }).stopReason;\n const toolCalls =\n nextRole === 'assistant' && stopReason !== 'aborted' && stopReason !== 'error'\n ? extractToolCallsFromAssistant(nextMessage as Extract<AgentMessage, { role: 'assistant' }>)\n : [];\n\n // Always clear pending tool call state before appending non-tool-result messages.\n // flushPendingToolResults() only inserts synthetic results when allowSyntheticToolResults\n // is true; it always clears the pending map. Without this, providers that disable\n // synthetic results (e.g. OpenAI) accumulate stale pending state when a user message\n // interrupts in-flight tool calls, leaving orphaned tool_use blocks in the transcript\n // that cause API 400 errors on subsequent requests.\n if (this.pending.shouldFlushBeforeNonToolResult(nextRole, toolCalls.length)) {\n this.flushPending();\n }\n // If new tool calls arrive while older ones are pending, flush the old ones first.\n if (this.pending.shouldFlushBeforeNewToolCalls(toolCalls.length)) {\n this.flushPending();\n }\n\n const finalMessage = this.applyBeforeWriteHook(this.persistMessage(nextMessage));\n if (!finalMessage) {\n return undefined;\n }\n const result = this.originalAppend(finalMessage as never);\n\n const sessionFile = (\n this.sessionManager as { getSessionFile?: () => string | null }\n ).getSessionFile?.();\n if (sessionFile) {\n emitSessionTranscriptUpdate({\n sessionFile,\n sessionKey: this.opts.sessionKey,\n message: finalMessage,\n messageId: typeof result === 'string' ? result : undefined,\n });\n }\n\n if (toolCalls.length > 0) {\n this.pending.trackToolCalls(toolCalls);\n }\n\n return result;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { extractProfileAgentId } from "../../config/agent-profile.js";
|
|
1
|
+
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
3
2
|
import { createLogger } from "../../utils/logger/index.js";
|
|
4
3
|
import { init_logger } from "../../utils/logger.js";
|
|
5
|
-
import {
|
|
4
|
+
import { init_agent_scope, resolveAgentHomeDir } from "../agent-scope.js";
|
|
5
|
+
import { extractProfileAgentId } from "../../config/agent-profile.js";
|
|
6
6
|
import { checklistCounts } from "./checklist-types.js";
|
|
7
7
|
import "./goal-run-types.js";
|
|
8
|
-
import { join } from "node:path";
|
|
9
8
|
import { createHash, randomUUID } from "node:crypto";
|
|
10
9
|
import { readFile } from "node:fs/promises";
|
|
10
|
+
import { join } from "node:path";
|
|
11
11
|
//#region src/agent/goals/goal-run-store.ts
|
|
12
12
|
init_agent_scope();
|
|
13
13
|
init_write_file_atomic();
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PersistentGoalService — owns the "/goal" runtime: continuation scheduling,
|
|
3
|
+
* the `PersistentGoalApis` bag that command handlers receive, and the post-turn
|
|
4
|
+
* verdict hook called from `OutboundCoordinator`.
|
|
5
|
+
*
|
|
6
|
+
* Previously this logic was scattered across `AgentService`:
|
|
7
|
+
* - `setPersistentGoalWebchatContinuationScheduler` + a private callback field
|
|
8
|
+
* - `schedulePersistentGoalContinuation` (bus vs webchat fork)
|
|
9
|
+
* - `getPersistentGoalApisForCommand` (~40-line API factory)
|
|
10
|
+
* - `recordPersistentGoalStreamOutcome` / `takePersistentGoalStreamOutcome`
|
|
11
|
+
* - the `/goal` half of `emitSessionTurnComplete` (delegated to
|
|
12
|
+
* `handlePersistentGoalPostTurn`)
|
|
13
|
+
*
|
|
14
|
+
* Concentrating it here gives the rest of `AgentService` a cleaner surface
|
|
15
|
+
* (one collaborator instead of five methods) and makes the goal runtime
|
|
16
|
+
* unit-testable in isolation.
|
|
17
|
+
*/
|
|
18
|
+
import type { Config } from '../../config/schema.js';
|
|
19
|
+
import type { MessageBus } from '../../infra/bus/index.js';
|
|
20
|
+
import type { ModelManager } from '../models/index.js';
|
|
21
|
+
import type { SessionStore } from '../../session/store.js';
|
|
22
|
+
import type { SessionStateBag } from '../session/index.js';
|
|
23
|
+
import type { PersistentGoalApis } from './persistent-goal-apis.js';
|
|
24
|
+
export interface PersistentGoalRouting {
|
|
25
|
+
sessionKey: string;
|
|
26
|
+
channel: string;
|
|
27
|
+
chatId: string;
|
|
28
|
+
inboundMetadata?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
export interface SessionTurnCompletionForGoal {
|
|
31
|
+
sessionKey: string;
|
|
32
|
+
channel: string;
|
|
33
|
+
chatId: string;
|
|
34
|
+
assistantPlainText: string;
|
|
35
|
+
aborted: boolean;
|
|
36
|
+
streamError?: string;
|
|
37
|
+
skipPersistentGoalPostTurn?: boolean;
|
|
38
|
+
outboundMetadata?: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
export interface PersistentGoalServiceOptions {
|
|
41
|
+
bus: MessageBus;
|
|
42
|
+
sessionStore: SessionStore;
|
|
43
|
+
modelManager: ModelManager;
|
|
44
|
+
sessionState: SessionStateBag;
|
|
45
|
+
/** Effective config snapshot accessor. */
|
|
46
|
+
getConfig: () => Config | undefined;
|
|
47
|
+
/** Resolve the workspace directory for `appendAssistantReceipt` writes. */
|
|
48
|
+
getResolvedWorkspaceForSession: (sessionKey: string) => string;
|
|
49
|
+
/** Notify the gateway UI after a metadata change (replaces the in-bag emit). */
|
|
50
|
+
onSessionMetadataUpdated?: (sessionKey: string) => void;
|
|
51
|
+
/** Push an assistant token + transcript refresh into a live webchat stream. */
|
|
52
|
+
notifyWebchatTranscriptAppend: (sessionKey: string, assistantText: string) => void;
|
|
53
|
+
}
|
|
54
|
+
export declare class PersistentGoalService {
|
|
55
|
+
private readonly opts;
|
|
56
|
+
/** Gateway only: webchat continuations bypass the bus and reuse `runGatewayAgent`. */
|
|
57
|
+
private webchatContinuationScheduler?;
|
|
58
|
+
constructor(opts: PersistentGoalServiceOptions);
|
|
59
|
+
/** Register the gateway-side webchat continuation hook (set from `web-agent` wiring). */
|
|
60
|
+
setWebchatContinuationScheduler(fn: ((sessionKey: string, message: string) => void) | undefined): void;
|
|
61
|
+
/**
|
|
62
|
+
* Continue a session after `/goal` decides the previous turn needs follow-up.
|
|
63
|
+
* Webchat sessions go through the scheduler; bus-driven channels re-publish the
|
|
64
|
+
* follow-up message as an inbound bus event so the existing inbound loop picks it up.
|
|
65
|
+
*/
|
|
66
|
+
scheduleContinuation(sessionKey: string, message: string, routing: {
|
|
67
|
+
channel: string;
|
|
68
|
+
chatId: string;
|
|
69
|
+
inboundMetadata?: Record<string, unknown>;
|
|
70
|
+
}): void;
|
|
71
|
+
/** Build the per-command `PersistentGoalApis` bag (transcript writers + scheduler closures). */
|
|
72
|
+
buildApisForRouting(routing: PersistentGoalRouting): PersistentGoalApis;
|
|
73
|
+
recordStreamOutcome(sessionKey: string, outcome: {
|
|
74
|
+
skipPersistentGoalPostTurn: boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
takeStreamOutcome(sessionKey: string): {
|
|
77
|
+
skipPersistentGoalPostTurn: boolean;
|
|
78
|
+
} | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Run the `/goal` post-turn verdict for a completed user turn (called from
|
|
81
|
+
* `OutboundCoordinator.emitSessionTurnComplete`).
|
|
82
|
+
*/
|
|
83
|
+
runPostTurn(payload: SessionTurnCompletionForGoal): Promise<void>;
|
|
84
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createLogger } from "../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { init_session_key, parseSessionKey } from "../../routing/session-key.js";
|
|
4
|
+
import { appendPiTranscriptMessage } from "../../session/parity/jsonl-transcript-io.js";
|
|
5
|
+
import { handlePersistentGoalPostTurn } from "./post-turn.js";
|
|
6
|
+
//#region src/agent/goals/persistent-goal-service.ts
|
|
7
|
+
init_session_key();
|
|
8
|
+
init_logger();
|
|
9
|
+
const log = createLogger("PersistentGoalService");
|
|
10
|
+
var PersistentGoalService = class {
|
|
11
|
+
opts;
|
|
12
|
+
/** Gateway only: webchat continuations bypass the bus and reuse `runGatewayAgent`. */
|
|
13
|
+
webchatContinuationScheduler;
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
this.opts = opts;
|
|
16
|
+
}
|
|
17
|
+
/** Register the gateway-side webchat continuation hook (set from `web-agent` wiring). */
|
|
18
|
+
setWebchatContinuationScheduler(fn) {
|
|
19
|
+
this.webchatContinuationScheduler = fn;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Continue a session after `/goal` decides the previous turn needs follow-up.
|
|
23
|
+
* Webchat sessions go through the scheduler; bus-driven channels re-publish the
|
|
24
|
+
* follow-up message as an inbound bus event so the existing inbound loop picks it up.
|
|
25
|
+
*/
|
|
26
|
+
scheduleContinuation(sessionKey, message, routing) {
|
|
27
|
+
if (parseSessionKey(sessionKey)?.source === "webchat" && this.webchatContinuationScheduler) {
|
|
28
|
+
this.webchatContinuationScheduler(sessionKey, message);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
queueMicrotask(() => {
|
|
32
|
+
this.opts.bus.publishInbound({
|
|
33
|
+
channel: routing.channel,
|
|
34
|
+
chat_id: routing.chatId,
|
|
35
|
+
sender_id: "persistent-goal",
|
|
36
|
+
content: message,
|
|
37
|
+
metadata: {
|
|
38
|
+
sessionKey,
|
|
39
|
+
...routing.inboundMetadata
|
|
40
|
+
}
|
|
41
|
+
}).catch((err) => {
|
|
42
|
+
log.warn({
|
|
43
|
+
err,
|
|
44
|
+
sessionKey
|
|
45
|
+
}, "Persistent goal: publishInbound failed");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/** Build the per-command `PersistentGoalApis` bag (transcript writers + scheduler closures). */
|
|
50
|
+
buildApisForRouting(routing) {
|
|
51
|
+
return {
|
|
52
|
+
getSessionMetadata: (k) => this.opts.sessionStore.getMetadata(k),
|
|
53
|
+
updateSessionMetadata: async (k, u) => {
|
|
54
|
+
await this.opts.sessionStore.updateMetadata(k, u);
|
|
55
|
+
this.opts.onSessionMetadataUpdated?.(k);
|
|
56
|
+
},
|
|
57
|
+
loadMessages: (k) => this.opts.sessionStore.loadMessages(k),
|
|
58
|
+
saveMessages: (k, m) => this.opts.sessionStore.saveMessages(k, m),
|
|
59
|
+
appendAssistantReceipt: async (k, text) => {
|
|
60
|
+
const trimmed = text.trim();
|
|
61
|
+
if (!trimmed) return;
|
|
62
|
+
const { absPath } = await this.opts.sessionStore.resolveTranscriptPath(k);
|
|
63
|
+
await appendPiTranscriptMessage({
|
|
64
|
+
absPath,
|
|
65
|
+
cwd: this.opts.getResolvedWorkspaceForSession(k),
|
|
66
|
+
message: {
|
|
67
|
+
role: "assistant",
|
|
68
|
+
content: [{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: trimmed
|
|
71
|
+
}],
|
|
72
|
+
timestamp: Date.now()
|
|
73
|
+
},
|
|
74
|
+
sessionKey: k
|
|
75
|
+
});
|
|
76
|
+
this.opts.notifyWebchatTranscriptAppend(k, trimmed);
|
|
77
|
+
},
|
|
78
|
+
scheduleContinuation: (sk, msg) => {
|
|
79
|
+
this.scheduleContinuation(sk, msg, {
|
|
80
|
+
channel: routing.channel,
|
|
81
|
+
chatId: routing.chatId,
|
|
82
|
+
inboundMetadata: routing.inboundMetadata
|
|
83
|
+
});
|
|
84
|
+
},
|
|
85
|
+
inboundConcurrentDepth: (sk) => this.opts.sessionState.getInboundTurnDepth(sk)
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
recordStreamOutcome(sessionKey, outcome) {
|
|
89
|
+
this.opts.sessionState.recordPersistentGoalStreamOutcome(sessionKey, outcome);
|
|
90
|
+
}
|
|
91
|
+
takeStreamOutcome(sessionKey) {
|
|
92
|
+
return this.opts.sessionState.takePersistentGoalStreamOutcome(sessionKey);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Run the `/goal` post-turn verdict for a completed user turn (called from
|
|
96
|
+
* `OutboundCoordinator.emitSessionTurnComplete`).
|
|
97
|
+
*/
|
|
98
|
+
async runPostTurn(payload) {
|
|
99
|
+
const apis = this.buildApisForRouting({
|
|
100
|
+
sessionKey: payload.sessionKey,
|
|
101
|
+
channel: payload.channel,
|
|
102
|
+
chatId: payload.chatId,
|
|
103
|
+
inboundMetadata: payload.outboundMetadata
|
|
104
|
+
});
|
|
105
|
+
const publishVerdict = !(parseSessionKey(payload.sessionKey)?.source === "webchat") && payload.channel !== "cli" ? async (text) => {
|
|
106
|
+
await this.opts.bus.publishOutbound({
|
|
107
|
+
channel: payload.channel,
|
|
108
|
+
chat_id: payload.chatId,
|
|
109
|
+
content: text,
|
|
110
|
+
type: "message",
|
|
111
|
+
metadata: {
|
|
112
|
+
accountId: payload.outboundMetadata?.accountId,
|
|
113
|
+
threadId: payload.outboundMetadata?.threadId
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
} : void 0;
|
|
117
|
+
let runtimeSessionModelRef;
|
|
118
|
+
try {
|
|
119
|
+
runtimeSessionModelRef = this.opts.modelManager.getModelForSession(payload.sessionKey);
|
|
120
|
+
} catch {
|
|
121
|
+
runtimeSessionModelRef = void 0;
|
|
122
|
+
}
|
|
123
|
+
await handlePersistentGoalPostTurn({
|
|
124
|
+
apis,
|
|
125
|
+
sessionKey: payload.sessionKey,
|
|
126
|
+
assistantPlainText: payload.assistantPlainText,
|
|
127
|
+
aborted: payload.aborted,
|
|
128
|
+
...payload.streamError !== void 0 ? { streamError: payload.streamError } : {},
|
|
129
|
+
skipPersistentGoalPostTurn: payload.skipPersistentGoalPostTurn ?? false,
|
|
130
|
+
config: this.opts.getConfig(),
|
|
131
|
+
runtimeSessionModelRef,
|
|
132
|
+
publishVerdictToChannel: publishVerdict
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
//#endregion
|
|
137
|
+
export { PersistentGoalService };
|
|
138
|
+
|
|
139
|
+
//# sourceMappingURL=persistent-goal-service.js.map
|