@xopcai/xopc 0.0.113 → 0.0.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CBlklyNr.js → agent-avatar-dicebear-DVnBfANm.js} +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-DPXc4hz8.js +6 -0
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CTJ0YnRQ.js +1 -0
- package/dist/gateway/static/root/assets/agents-zJXQfJ_W.js +71 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-28E_WfMe.js → app-management-settings-panel-DzGbdr04.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-Do1z0XgJ.js → appearance-settings-BQpPSTHD.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CPjfyzSD.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BAFlsov_.js → archive-plugin-CXu-Csep.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-V3qGPC3x.js → attachment-load-BAjgOoGY.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-DT8NvA6W.js → binary-plugins-BSBgB2hO.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CdLMEcHd.js → block-editor-BpXw9TTR.js} +3 -3
- package/dist/gateway/static/root/assets/channels-settings-BbPUpzWB.js +1 -0
- package/dist/gateway/static/root/assets/{config-api-Bf5mjpu7.js → config-api-NOoPiIYz.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-settings-CAXYMOdp.js +2 -0
- package/dist/gateway/static/root/assets/{cron-api--pAB_rps.js → cron-api-C9BOqAXd.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-DuUbBeKI.js +3 -0
- package/dist/gateway/static/root/assets/{dreaming-settings-6UZE1FSK.js → dreaming-settings-DQ4DtiK1.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BGhE7msg.js → extension-debug-page-D9kgUHCc.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CvpI45WG.js → extension-page-CGyhXqzR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DAmR5FUe.js → extension-settings-page-DL8Xquqd.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-NZmjSXLl.js → fetch-D0VXA932.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-qhth3BMV.js → format-interval-label-Be8SmgUw.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CaXBt-9R.js → gateway-config-api-C-xjn__h.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DphpbLBc.js → gateway-settings-BMPwIjKI.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Be1omjh3.js → gateway-startup-retry-DERUH61L.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BJsyjJnF.js +1 -0
- package/dist/gateway/static/root/assets/goals-config-api-BPmqWk90.js +1 -0
- package/dist/gateway/static/root/assets/goals-page-BerDgIhw.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-ByTjeAto.js +1 -0
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BzO6G4fD.js → heartbeat-config-api-Bfdzr8oV.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-DCST9-du.js → heartbeat-settings-TbHgcjTn.js} +1 -1
- package/dist/gateway/static/root/assets/index-AkTrf6Pb.js +122 -0
- package/dist/gateway/static/root/assets/index-fh5sXTj9.css +1 -0
- package/dist/gateway/static/root/assets/{interval-presets-DJmshV8n.js → interval-presets-utKbuCRY.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-9AUUlQ5Q.js → keyboard-shortcuts-settings-CjqS6c6V.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DGXuPf5B.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-CYYELqAr.js → markdown-split-DW8C47iB.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-BEcMR2M8.js → media-plugins-D6HwDhDT.js} +1 -1
- package/dist/gateway/static/root/assets/messages-upgxw6Ub.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-Bot16nn7.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-Brlyou8M.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-DNAoPcmm.js → note-image-lightbox-pJM35Pz5.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DvZ4pwc-.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BPLz0AIv.js → preview-open-alternatives-CVwHuyN6.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BZEDmxbZ.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-CrWwWRVK.js → save-bar-controls-Ba-UEk7x.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CF2sadvN.js → schedule-field-CNN9595U.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Di5cKjYE.js → schema-form-DnNMmtD5.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DdGGlsfn.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DlkEkPf9.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-Chh282jW.js → settings-collapsible-section-CmOz80i5.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Dq-83cQd.js → settings-form-section-BmK7JJOV.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DFPTrsPF.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-CYCCfgh4.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-0FXYnSUA.js → share-preview-page-Dp2qGrHC.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Bff1pGd0.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CJGKpBur.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-C6ocduTD.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-W1pTcojB.js → system-settings-panel-5jrIEr5b.js} +1 -1
- package/dist/gateway/static/root/assets/{use-agent-defaults-form-BVRvkK7m.js → use-agent-defaults-form-BuiXLIs5.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CgJibfMM.js → use-channel-catalog-CHlO8J9G.js} +1 -1
- package/dist/gateway/static/root/assets/{use-settings-tab-guard-Bw_qkRQE.js → use-settings-tab-guard-CW5JORnl.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DDoQyghO.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-C7lziaAx.js → voice-player-store-DDDWYHvg.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-CKjeEGqx.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-B604ehHG.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/gateway/static/root/logo.svg +4 -3
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +8 -0
- package/dist/src/agent/agent-manager.js +63 -28
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/bootstrap/project-agents-context.d.ts +2 -0
- package/dist/src/agent/bootstrap/project-agents-context.js +32 -0
- package/dist/src/agent/bootstrap/project-agents-context.js.map +1 -0
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/context/workspace.js +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +8 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/goals/checklist-judge.d.ts +1 -0
- package/dist/src/agent/goals/checklist-judge.js +3 -2
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/evaluate-turn.d.ts +1 -1
- package/dist/src/agent/goals/evaluate-turn.js +1 -0
- package/dist/src/agent/goals/evaluate-turn.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.js +2 -2
- package/dist/src/agent/goals/persistent-goal-service.js +2 -4
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.d.ts +6 -1
- package/dist/src/agent/goals/post-turn.js +15 -6
- package/dist/src/agent/goals/post-turn.js.map +1 -1
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/inbound/inbound-loop.js +5 -1
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -2
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/ipc/inbox.js +3 -3
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.d.ts +27 -0
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +50 -2
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +79 -4
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-types.d.ts +19 -0
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/memory/index.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/btw-query.js +11 -3
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/parse-outbound-session-key.js +13 -8
- package/dist/src/agent/service/parse-outbound-session-key.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +2 -2
- package/dist/src/agent/service/process-direct-one-shot.js +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +2 -2
- package/dist/src/agent/service/process-direct-streaming.js +1 -1
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.d.ts +1 -1
- package/dist/src/agent/service.js +13 -9
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +5 -0
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +2 -2
- package/dist/src/agent/skills/filesystem-watcher.js +5 -4
- package/dist/src/agent/skills/filesystem-watcher.js.map +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +4 -3
- package/dist/src/agent/skills/index.js.map +1 -1
- package/dist/src/agent/skills/installer.js +2 -2
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +3 -2
- package/dist/src/agent/skills/skill-manage-ops.js.map +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/skills/skill-view-path.js +1 -1
- package/dist/src/agent/skills/test-framework.js +1 -1
- package/dist/src/agent/skills/types.d.ts +1 -1
- package/dist/src/agent/skills/watcher.js +2 -5
- package/dist/src/agent/skills/watcher.js.map +1 -1
- package/dist/src/agent/skills/workspace-skills-dir.d.ts +1 -0
- package/dist/src/agent/skills/workspace-skills-dir.js +11 -0
- package/dist/src/agent/skills/workspace-skills-dir.js.map +1 -0
- package/dist/src/agent/starter-agents.js +1 -1
- package/dist/src/agent/tool-manuals/browser.d.ts +1 -1
- package/dist/src/agent/tool-manuals/browser.js +62 -3
- package/dist/src/agent/tool-manuals/browser.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.d.ts +4 -1
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js +13 -4
- package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
- package/dist/src/agent/tools/browser/tool/schemas.d.ts +0 -2
- package/dist/src/agent/tools/browser/tool/schemas.js +1 -2
- package/dist/src/agent/tools/browser/tool/schemas.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -10
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +1 -1
- package/dist/src/agent/tools/grep.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +2 -2
- package/dist/src/agent/tools/skill-manage-tool.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/snapshot.d.ts +10 -0
- package/dist/src/agent/workflow/snapshot.js +136 -1
- package/dist/src/agent/workflow/snapshot.js.map +1 -1
- package/dist/src/agent/workflow/subagent-runner.js +18 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/profiles/store.js +2 -2
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/actions/extension-registry-bridge.js +91 -7
- package/dist/src/browser/actions/extension-registry-bridge.js.map +1 -1
- package/dist/src/browser/actions/registry.js +383 -7
- package/dist/src/browser/actions/registry.js.map +1 -1
- package/dist/src/browser/actions/types.d.ts +11 -3
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/index.js +2 -2
- package/dist/src/browser/pipeline/output.d.ts +18 -16
- package/dist/src/browser/pipeline/output.js +28 -20
- package/dist/src/browser/pipeline/output.js.map +1 -1
- package/dist/src/browser/pipeline/runner.d.ts +7 -14
- package/dist/src/browser/pipeline/runner.js +349 -102
- package/dist/src/browser/pipeline/runner.js.map +1 -1
- package/dist/src/browser/pipeline/schema.d.ts +1 -0
- package/dist/src/browser/pipeline/schema.js +35 -58
- package/dist/src/browser/pipeline/schema.js.map +1 -1
- package/dist/src/browser/pipeline/source.d.ts +2 -0
- package/dist/src/browser/pipeline/source.js +10 -1
- package/dist/src/browser/pipeline/source.js.map +1 -1
- package/dist/src/browser/pipeline/template.d.ts +10 -2
- package/dist/src/browser/pipeline/template.js +50 -8
- package/dist/src/browser/pipeline/template.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/cloakbrowser.js +5 -5
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/catalog/channel-catalog-service.d.ts +2 -1
- package/dist/src/channels/catalog/channel-catalog-service.js +133 -16
- package/dist/src/channels/catalog/channel-catalog-service.js.map +1 -1
- package/dist/src/channels/catalog/channel-catalog-types.d.ts +13 -0
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +5 -7
- package/dist/src/chat-commands/builtins/config.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +5 -0
- package/dist/src/chat-commands/context.js +18 -9
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/index.d.ts +1 -1
- package/dist/src/chat-commands/index.js +2 -2
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/chat-commands/processor.js +22 -21
- package/dist/src/chat-commands/processor.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +3 -15
- package/dist/src/chat-commands/session-key.js +3 -49
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +4 -0
- package/dist/src/cli/commands/browser-cli-helpers.js +11 -5
- package/dist/src/cli/commands/browser-cli-helpers.js.map +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.js +14 -1
- package/dist/src/cli/commands/doctor/checks/channel-config.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +8 -8
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-create.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +2 -2
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension-pack.js +2 -2
- package/dist/src/cli/commands/extension.js +3 -3
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +2 -2
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/skills-test.js +1 -1
- package/dist/src/cli/templates.js +1 -1
- package/dist/src/cli/utils/gateway-client.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/agent-typed-models.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +7 -7
- package/dist/src/config/loader.js +4 -4
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/paths.js +1 -1
- package/dist/src/config/profile.js +1 -1
- package/dist/src/config/reload.js +1 -1
- package/dist/src/config/rules.js +5 -0
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +8 -0
- package/dist/src/config/schema.js +7 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +1 -0
- package/dist/src/config/web-patch.js +1 -0
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/connectors/builtin-catalog.js +180 -1
- package/dist/src/connectors/builtin-catalog.js.map +1 -1
- package/dist/src/connectors/health.js +18 -9
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/types.d.ts +19 -0
- package/dist/src/connectors/usage.js +12 -4
- package/dist/src/connectors/usage.js.map +1 -1
- package/dist/src/cron/executor.js +1 -1
- package/dist/src/cron/service.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +2 -2
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/install.js +2 -2
- package/dist/src/extensions/loader.js +2 -2
- package/dist/src/extensions/lockfile.js +3 -3
- package/dist/src/extensions/security.js +1 -1
- package/dist/src/extensions/types/tui.d.ts +2 -0
- package/dist/src/extensions/update.js +2 -2
- package/dist/src/gateway/agents-admin.js +2 -2
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +13 -1
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +18 -5
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
- package/dist/src/gateway/hono/lib/config-payload.js +7 -4
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +19 -5
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js.map +1 -1
- package/dist/src/gateway/hono/oauth-async.js +1 -1
- package/dist/src/gateway/hono/routes/agent-stream.js +6 -6
- package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/channels.js +18 -14
- package/dist/src/gateway/hono/routes/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +6 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/goals.js +16 -3
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/logs.js +1 -0
- package/dist/src/gateway/hono/routes/logs.js.map +1 -1
- package/dist/src/gateway/hono/routes/mcp.js +27 -8
- package/dist/src/gateway/hono/routes/mcp.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/notes.js +14 -2
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +62 -4
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +5 -68
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/hono/sse.d.ts +2 -2
- package/dist/src/gateway/hono/sse.js +7 -15
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +12 -0
- package/dist/src/gateway/rate-limit/buckets.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +2 -6
- package/dist/src/gateway/resolve-webchat-session-key.js +5 -31
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -1
- package/dist/src/gateway/service/agent-runner.d.ts +2 -3
- package/dist/src/gateway/service/agent-runner.js +9 -22
- package/dist/src/gateway/service/agent-runner.js.map +1 -1
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service/run-gateway-agent.js +9 -7
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +9 -0
- package/dist/src/gateway/service/sessions-api.js +11 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +1 -1
- package/dist/src/gateway/service.js +23 -9
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-file-search.d.ts +9 -0
- package/dist/src/gateway/workspace-file-search.js +76 -0
- package/dist/src/gateway/workspace-file-search.js.map +1 -0
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/goals/goal-notifications.d.ts +2 -0
- package/dist/src/goals/goal-notifications.js +16 -11
- package/dist/src/goals/goal-notifications.js.map +1 -1
- package/dist/src/goals/goal-service.js +1 -6
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/goals/goal-workflow-judge.js +2 -2
- package/dist/src/i18n/goals-bundle.js +1 -1
- package/dist/src/i18n/index.js +1 -1
- package/dist/src/i18n/share-tool-bundle.js +2 -2
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +1 -1
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +2 -2
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +1 -1
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +1 -1
- package/dist/src/notes/agent-context.js +1 -1
- package/dist/src/notes/service.js +1 -1
- package/dist/src/notes/store.js +2 -2
- package/dist/src/project-trust/trust-store.js +4 -2
- package/dist/src/project-trust/trust-store.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +1 -1
- package/dist/src/providers/model-registry.js +4 -4
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +2 -2
- package/dist/src/session/init-session-turn.js +7 -10
- package/dist/src/session/init-session-turn.js.map +1 -1
- package/dist/src/session/manager.d.ts +5 -1
- package/dist/src/session/manager.js +5 -2
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/reset-type.d.ts +0 -2
- package/dist/src/session/reset-type.js +3 -9
- package/dist/src/session/reset-type.js.map +1 -1
- package/dist/src/session/resolve-session.js +10 -21
- package/dist/src/session/resolve-session.js.map +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.d.ts +11 -3
- package/dist/src/session/store.js +30 -14
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +2 -4
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +1 -1
- package/dist/src/storage/sqlite/index.d.ts +2 -2
- package/dist/src/storage/sqlite/index.js +3 -3
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/010_session_id_identity.sql +30 -0
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
- package/dist/src/storage/sqlite/migrations/runner.js +5 -5
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
- package/dist/src/storage/sqlite/row-mappers.d.ts +4 -4
- package/dist/src/storage/sqlite/row-mappers.js +11 -14
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +4 -4
- package/dist/src/storage/sqlite/schema.js.map +1 -1
- package/dist/src/storage/sqlite/schema.sql +37 -10
- package/dist/src/storage/sqlite/session-metadata.d.ts +2 -7
- package/dist/src/storage/sqlite/session-metadata.js +18 -72
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
- package/dist/src/storage/sqlite/session-repository.d.ts +6 -5
- package/dist/src/storage/sqlite/session-repository.js +34 -40
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/storage/sqlite/transcript-repository.d.ts +2 -2
- package/dist/src/storage/sqlite/transcript-repository.js +52 -52
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +18 -4
- package/dist/src/tui/backends/embedded-backend.js +100 -1
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +5 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +45 -2
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/components/chat-log.d.ts +2 -0
- package/dist/src/tui/components/chat-log.js +19 -0
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/extension-host/autocomplete.d.ts +3 -2
- package/dist/src/tui/extension-host/autocomplete.js +29 -12
- package/dist/src/tui/extension-host/autocomplete.js.map +1 -1
- package/dist/src/tui/extension-host/load-extensions.js +1 -1
- package/dist/src/tui/extension-host/runtime.d.ts +12 -0
- package/dist/src/tui/extension-host/runtime.js +6 -4
- package/dist/src/tui/extension-host/runtime.js.map +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-backend.d.ts +23 -0
- package/dist/src/tui/tui-command-formatters.js +4 -4
- package/dist/src/tui/tui-commands.d.ts +16 -3
- package/dist/src/tui/tui-commands.js +134 -27
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-file-autocomplete.d.ts +5 -0
- package/dist/src/tui/tui-file-autocomplete.js +26 -0
- package/dist/src/tui/tui-file-autocomplete.js.map +1 -0
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-picker-overlay.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui-startup-text.js +1 -1
- package/dist/src/tui/tui-startup-text.js.map +1 -1
- package/dist/src/tui/tui.js +106 -17
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/tunnel/frpc-binary.js +4 -4
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/context.d.ts +2 -2
- package/dist/src/utils/logger/context.js +2 -1
- package/dist/src/utils/logger/context.js.map +1 -1
- package/dist/src/utils/logger/log-store.js +2 -1
- package/dist/src/utils/logger/log-store.js.map +1 -1
- package/dist/src/utils/logger/pino-record.js +3 -0
- package/dist/src/utils/logger/pino-record.js.map +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/logger/streams.js +1 -1
- package/dist/src/utils/logger/types.d.ts +5 -0
- package/dist/src/utils/logger/types.js.map +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +13 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agent-browser-settings-page-rGbKc2Hh.js +0 -6
- package/dist/gateway/static/root/assets/agent-defaults-tabbed-page-CtwVbjOA.js +0 -1
- package/dist/gateway/static/root/assets/agents-CCBmGcwc.js +0 -71
- package/dist/gateway/static/root/assets/apps-page-xwCsJS15.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-C044DcYk.js +0 -1
- package/dist/gateway/static/root/assets/connectors-settings-8VEWUOTj.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-DqmNGNOy.js +0 -3
- package/dist/gateway/static/root/assets/goal-detail-page-bv0VRDaf.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-1Ywnt4Cb.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-ceEBjnfc.js +0 -1
- package/dist/gateway/static/root/assets/index-Cxm6xsps.js +0 -122
- package/dist/gateway/static/root/assets/index-b_R4tKqt.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-B_wrxhee.js +0 -2
- package/dist/gateway/static/root/assets/messages-CkT-lcgP.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-D0JDSbNu.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-DpFV-EO6.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-CdkjTch8.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DSYVAi96.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CenkcVjF.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D9sva86V.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DL35U0x0.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Ctwbp9Er.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DIM3JNsr.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DAlNaNzL.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CLrHVzAt.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-vYAO71Gn.js +0 -1
- package/dist/gateway/static/root/assets/workflow-page.utils-sgHjOXOm.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-DYyOTmFx.js +0 -18
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { DEFAULT_AGENT_ID, init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
|
|
2
|
-
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
3
2
|
import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
|
|
3
|
+
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
4
4
|
import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES } from "../agent/context/workspace.js";
|
|
5
5
|
import { isPathUnderWorkspace, resolveWorkspaceSafePath } from "./workspace-editor-path.js";
|
|
6
6
|
import { applyAgentConfig, findAgentEntryIndex, pruneAgentConfig, removeAgentDirsFromDisk } from "../commands/agents.config.js";
|
|
7
7
|
import { resolveEffectiveTypedModels } from "../config/agent-typed-models.js";
|
|
8
8
|
import { GATEWAY_BUILTIN_TOOL_IDS } from "./agent-builtin-tools.js";
|
|
9
9
|
import { seedAgentProfileMarkdownFiles } from "../agent/context/workspace-seed.js";
|
|
10
|
-
import { cp, mkdir, readFile, readdir, realpath, stat, unlink, writeFile } from "node:fs/promises";
|
|
11
10
|
import { join, resolve } from "node:path";
|
|
11
|
+
import { cp, mkdir, readFile, readdir, realpath, stat, unlink, writeFile } from "node:fs/promises";
|
|
12
12
|
//#region src/gateway/agents-admin.ts
|
|
13
13
|
/**
|
|
14
14
|
* Gateway REST helpers for multi-agent management.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { init_agent_scope, resolveAgentProfileDir } from "../agent/agent-scope.js";
|
|
3
|
-
import { init_paths, resolveConfigPath, resolveSkillsDir } from "../config/paths.js";
|
|
4
3
|
import { extractProfileAgentId } from "../config/agent-profile.js";
|
|
4
|
+
import { init_paths, resolveConfigPath, resolveSkillsDir } from "../config/paths.js";
|
|
5
5
|
import { isBareProfileMarkdownFileName, resolveProfileMarkdownPathIfBareName } from "../agent/tools/tool-paths.js";
|
|
6
6
|
import { isPathUnderWorkspace, resolveWorkspaceSafePath } from "./workspace-editor-path.js";
|
|
7
|
-
import { stat } from "node:fs/promises";
|
|
8
7
|
import { basename, isAbsolute, resolve } from "node:path";
|
|
8
|
+
import { stat } from "node:fs/promises";
|
|
9
9
|
//#region src/gateway/file-path-classifier.ts
|
|
10
10
|
init_agent_scope();
|
|
11
11
|
init_paths();
|
|
@@ -124,7 +124,19 @@ var HeartbeatService = class {
|
|
|
124
124
|
reasons: reasonSummary
|
|
125
125
|
}, "Heartbeat: invoking agent");
|
|
126
126
|
if (sessionKey === "heartbeat:main") try {
|
|
127
|
-
await this.deps.sessionStore.saveMessages(sessionKey, []
|
|
127
|
+
await this.deps.sessionStore.saveMessages(sessionKey, [], { metadata: {
|
|
128
|
+
sourceChannel: "heartbeat",
|
|
129
|
+
sourceChatId: "main",
|
|
130
|
+
sessionType: "heartbeat",
|
|
131
|
+
customData: { heartbeatTarget: "main" },
|
|
132
|
+
routing: {
|
|
133
|
+
agentId: "main",
|
|
134
|
+
source: "heartbeat",
|
|
135
|
+
accountId: "default",
|
|
136
|
+
peerKind: "direct",
|
|
137
|
+
peerId: "main"
|
|
138
|
+
}
|
|
139
|
+
} });
|
|
128
140
|
} catch (err) {
|
|
129
141
|
log.warn({
|
|
130
142
|
err,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../../src/gateway/heartbeat/service.ts"],"sourcesContent":["import { readFile } from 'fs/promises';\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { Config } from '../../config/schema.js';\nimport { CronService } from '../../cron/service.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { appendCronEventLines } from '../../heartbeat/event-prompt.js';\nimport { isWithinActiveHours } from '../../heartbeat/active-hours.js';\nimport { isHeartbeatContentEmpty } from '../../heartbeat/content-check.js';\nimport {\n DEFAULT_ACK_MAX_CHARS,\n stripHeartbeatToken,\n shouldSilence,\n} from '../../heartbeat/tokens.js';\nimport { createHeartbeatWake } from '../../heartbeat/wake.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveHeartbeatMdPath } from '../workspace-heartbeat-path.js';\n\nconst log = createLogger('HeartbeatService');\n\nconst DEFAULT_PROMPT =\n 'Read HEARTBEAT.md if it exists. Follow it strictly. If nothing needs attention, reply HEARTBEAT_OK.';\n\nexport interface HeartbeatRunnerConfig {\n enabled: boolean;\n intervalMs: number;\n target?: string;\n targetChatId?: string;\n prompt?: string;\n ackMaxChars?: number;\n isolatedSession?: boolean;\n activeHours?: {\n start: string;\n end: string;\n timezone?: string;\n };\n}\n\nfunction mapConfigToRunner(cfg: Config | undefined): HeartbeatRunnerConfig {\n const h = cfg?.gateway?.heartbeat;\n return {\n enabled: h?.enabled ?? true,\n intervalMs: h?.intervalMs ?? 1_800_000,\n target: h?.target,\n targetChatId: h?.targetChatId,\n prompt: h?.prompt,\n ackMaxChars: h?.ackMaxChars,\n isolatedSession: h?.isolatedSession,\n activeHours: h?.activeHours,\n };\n}\n\n/** Map persisted gateway config to runner options (gateway start / reload). */\nexport function heartbeatRunnerConfigFromConfig(cfg: Config): HeartbeatRunnerConfig {\n return mapConfigToRunner(cfg);\n}\n\nexport interface HeartbeatServiceDeps {\n agentService: AgentService;\n messageBus: MessageBus;\n cronService: CronService;\n sessionStore: SessionStore;\n /** Current app config (for HEARTBEAT.md path under the default agent `profile/` directory). */\n getConfig: () => Config;\n}\n\nexport class HeartbeatService {\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private wake: ReturnType<typeof createHeartbeatWake>;\n private lastHeartbeatText = '';\n private lastHeartbeatAt = 0;\n private runnerConfig: HeartbeatRunnerConfig | null = null;\n\n constructor(private deps: HeartbeatServiceDeps) {\n this.wake = createHeartbeatWake((reasons) => this.runHeartbeatOnce(reasons));\n }\n\n start(config: HeartbeatRunnerConfig): void {\n if (!config.enabled) {\n log.info('Heartbeat disabled');\n this.runnerConfig = null;\n return;\n }\n\n this.runnerConfig = config;\n log.info({ intervalMs: config.intervalMs }, 'Heartbeat timer started (interval wake)');\n\n this.intervalId = setInterval(() => {\n this.wake.request({ reason: 'interval' });\n }, config.intervalMs);\n this.intervalId.unref?.();\n }\n\n /** Cron, exec completion, manual triggers, etc. */\n requestNow(opts?: { reason?: string }): void {\n this.wake.request({ reason: opts?.reason ?? 'manual' });\n }\n\n stop(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n this.wake.stop();\n this.runnerConfig = null;\n log.info('Heartbeat stopped');\n }\n\n updateConfig(config: Config): void {\n const mapped = mapConfigToRunner(config);\n this.stop();\n if (mapped.enabled) {\n this.start(mapped);\n }\n log.info('Heartbeat config updated');\n }\n\n isRunning(): boolean {\n return this.intervalId !== null;\n }\n\n private async runHeartbeatOnce(reasons: string[]): Promise<void> {\n const reasonSummary = [...new Set(reasons)].join(', ') || 'unknown';\n\n const cfg = this.runnerConfig;\n if (!cfg?.enabled) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (disabled)');\n return;\n }\n\n try {\n const metrics = await this.deps.cronService.getMetrics();\n log.trace(\n { runningJobs: metrics.runningJobs, enabledJobs: metrics.enabledJobs },\n 'Heartbeat: cron metrics',\n );\n } catch {\n /* optional */\n }\n\n if (cfg.activeHours && !isWithinActiveHours(cfg.activeHours)) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (outside active hours)');\n return;\n }\n\n const heartbeatPath = resolveHeartbeatMdPath(this.deps.getConfig());\n if (!heartbeatPath) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (no HEARTBEAT path)');\n return;\n }\n let heartbeatContent: string | undefined;\n try {\n const raw = await readFile(heartbeatPath, 'utf-8');\n if (isHeartbeatContentEmpty(raw)) {\n log.debug({ path: heartbeatPath, reasons: reasonSummary }, 'Heartbeat: skip (HEARTBEAT.md empty)');\n return;\n }\n heartbeatContent = raw.trim();\n } catch {\n log.debug({ path: heartbeatPath, reasons: reasonSummary }, 'Heartbeat: HEARTBEAT.md missing; continuing');\n }\n\n const sessionKey = cfg.isolatedSession\n ? `heartbeat:isolated:${Date.now()}`\n : 'heartbeat:main';\n\n let basePrompt = (cfg.prompt?.trim() || DEFAULT_PROMPT).trim();\n if (heartbeatContent) {\n basePrompt = `${basePrompt}\\n\\n---\\nHEARTBEAT.md:\\n${heartbeatContent}\\n---`;\n }\n basePrompt = appendCronEventLines(basePrompt, reasons);\n const prompt = `${basePrompt}\\n\\nCurrent time: ${new Date().toISOString()}`;\n\n const ackMax = cfg.ackMaxChars ?? DEFAULT_ACK_MAX_CHARS;\n\n log.debug({ sessionKey, reasons: reasonSummary }, 'Heartbeat: invoking agent');\n\n // `heartbeat:main` reuses one session key; each run would otherwise append to the transcript\n // until the model rejects the request (context window exceeded). Heartbeat prompts are\n // self-contained (HEARTBEAT.md + this turn's text), so we start from an empty history.\n if (sessionKey === 'heartbeat:main') {\n try {\n await this.deps.sessionStore.saveMessages(sessionKey, []);\n } catch (err) {\n log.warn({ err, sessionKey }, 'Heartbeat: failed to reset main session transcript');\n }\n }\n\n let reply: string;\n try {\n reply = await this.deps.agentService.turnDispatcher.processDirect(prompt, sessionKey);\n } catch (error) {\n log.error({ err: error }, 'Heartbeat: agent call failed');\n return;\n }\n\n if (!reply?.trim()) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (empty model reply)');\n return;\n }\n\n if (shouldSilence(reply, ackMax)) {\n log.info(\n { ackMax, replyChars: reply.length, reasons: reasonSummary },\n 'Heartbeat: not sent — silent (HEARTBEAT_OK / short ack)',\n );\n return;\n }\n\n const { stripped } = stripHeartbeatToken(reply);\n const finalText = stripped || reply.trim();\n\n if (this.isDuplicate(finalText)) {\n log.info(\n { finalTextChars: finalText.length, reasons: reasonSummary },\n 'Heartbeat: not sent — duplicate within 24h',\n );\n return;\n }\n\n const target = cfg.target?.trim();\n const targetChatId = cfg.targetChatId?.trim();\n const hasDeliveryTarget = Boolean(target && targetChatId);\n\n if (hasDeliveryTarget) {\n await this.deps.messageBus.publishOutbound({\n channel: target!,\n chat_id: targetChatId!,\n content: finalText,\n type: 'message',\n });\n log.info(\n {\n reasons: reasonSummary,\n channel: target,\n chatId: targetChatId,\n contentChars: finalText.length,\n },\n 'Heartbeat: sent — outbound queued',\n );\n } else {\n log.info(\n { reasons: reasonSummary, finalTextChars: finalText.length },\n 'Heartbeat: not sent — no delivery target (set gateway.heartbeat.target + targetChatId)',\n );\n }\n\n this.lastHeartbeatText = finalText;\n this.lastHeartbeatAt = Date.now();\n }\n\n private isDuplicate(text: string): boolean {\n const DEDUP_WINDOW_MS = 24 * 60 * 60 * 1000;\n return (\n text.trim() === this.lastHeartbeatText.trim() &&\n Date.now() - this.lastHeartbeatAt < DEDUP_WINDOW_MS\n );\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../../../src/gateway/heartbeat/service.ts"],"sourcesContent":["import { readFile } from 'fs/promises';\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { Config } from '../../config/schema.js';\nimport { CronService } from '../../cron/service.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport type { SessionStore } from '../../session/store.js';\nimport { appendCronEventLines } from '../../heartbeat/event-prompt.js';\nimport { isWithinActiveHours } from '../../heartbeat/active-hours.js';\nimport { isHeartbeatContentEmpty } from '../../heartbeat/content-check.js';\nimport {\n DEFAULT_ACK_MAX_CHARS,\n stripHeartbeatToken,\n shouldSilence,\n} from '../../heartbeat/tokens.js';\nimport { createHeartbeatWake } from '../../heartbeat/wake.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveHeartbeatMdPath } from '../workspace-heartbeat-path.js';\n\nconst log = createLogger('HeartbeatService');\n\nconst DEFAULT_PROMPT =\n 'Read HEARTBEAT.md if it exists. Follow it strictly. If nothing needs attention, reply HEARTBEAT_OK.';\n\nexport interface HeartbeatRunnerConfig {\n enabled: boolean;\n intervalMs: number;\n target?: string;\n targetChatId?: string;\n prompt?: string;\n ackMaxChars?: number;\n isolatedSession?: boolean;\n activeHours?: {\n start: string;\n end: string;\n timezone?: string;\n };\n}\n\nfunction mapConfigToRunner(cfg: Config | undefined): HeartbeatRunnerConfig {\n const h = cfg?.gateway?.heartbeat;\n return {\n enabled: h?.enabled ?? true,\n intervalMs: h?.intervalMs ?? 1_800_000,\n target: h?.target,\n targetChatId: h?.targetChatId,\n prompt: h?.prompt,\n ackMaxChars: h?.ackMaxChars,\n isolatedSession: h?.isolatedSession,\n activeHours: h?.activeHours,\n };\n}\n\n/** Map persisted gateway config to runner options (gateway start / reload). */\nexport function heartbeatRunnerConfigFromConfig(cfg: Config): HeartbeatRunnerConfig {\n return mapConfigToRunner(cfg);\n}\n\nexport interface HeartbeatServiceDeps {\n agentService: AgentService;\n messageBus: MessageBus;\n cronService: CronService;\n sessionStore: SessionStore;\n /** Current app config (for HEARTBEAT.md path under the default agent `profile/` directory). */\n getConfig: () => Config;\n}\n\nexport class HeartbeatService {\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private wake: ReturnType<typeof createHeartbeatWake>;\n private lastHeartbeatText = '';\n private lastHeartbeatAt = 0;\n private runnerConfig: HeartbeatRunnerConfig | null = null;\n\n constructor(private deps: HeartbeatServiceDeps) {\n this.wake = createHeartbeatWake((reasons) => this.runHeartbeatOnce(reasons));\n }\n\n start(config: HeartbeatRunnerConfig): void {\n if (!config.enabled) {\n log.info('Heartbeat disabled');\n this.runnerConfig = null;\n return;\n }\n\n this.runnerConfig = config;\n log.info({ intervalMs: config.intervalMs }, 'Heartbeat timer started (interval wake)');\n\n this.intervalId = setInterval(() => {\n this.wake.request({ reason: 'interval' });\n }, config.intervalMs);\n this.intervalId.unref?.();\n }\n\n /** Cron, exec completion, manual triggers, etc. */\n requestNow(opts?: { reason?: string }): void {\n this.wake.request({ reason: opts?.reason ?? 'manual' });\n }\n\n stop(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n this.wake.stop();\n this.runnerConfig = null;\n log.info('Heartbeat stopped');\n }\n\n updateConfig(config: Config): void {\n const mapped = mapConfigToRunner(config);\n this.stop();\n if (mapped.enabled) {\n this.start(mapped);\n }\n log.info('Heartbeat config updated');\n }\n\n isRunning(): boolean {\n return this.intervalId !== null;\n }\n\n private async runHeartbeatOnce(reasons: string[]): Promise<void> {\n const reasonSummary = [...new Set(reasons)].join(', ') || 'unknown';\n\n const cfg = this.runnerConfig;\n if (!cfg?.enabled) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (disabled)');\n return;\n }\n\n try {\n const metrics = await this.deps.cronService.getMetrics();\n log.trace(\n { runningJobs: metrics.runningJobs, enabledJobs: metrics.enabledJobs },\n 'Heartbeat: cron metrics',\n );\n } catch {\n /* optional */\n }\n\n if (cfg.activeHours && !isWithinActiveHours(cfg.activeHours)) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (outside active hours)');\n return;\n }\n\n const heartbeatPath = resolveHeartbeatMdPath(this.deps.getConfig());\n if (!heartbeatPath) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (no HEARTBEAT path)');\n return;\n }\n let heartbeatContent: string | undefined;\n try {\n const raw = await readFile(heartbeatPath, 'utf-8');\n if (isHeartbeatContentEmpty(raw)) {\n log.debug({ path: heartbeatPath, reasons: reasonSummary }, 'Heartbeat: skip (HEARTBEAT.md empty)');\n return;\n }\n heartbeatContent = raw.trim();\n } catch {\n log.debug({ path: heartbeatPath, reasons: reasonSummary }, 'Heartbeat: HEARTBEAT.md missing; continuing');\n }\n\n const sessionKey = cfg.isolatedSession\n ? `heartbeat:isolated:${Date.now()}`\n : 'heartbeat:main';\n\n let basePrompt = (cfg.prompt?.trim() || DEFAULT_PROMPT).trim();\n if (heartbeatContent) {\n basePrompt = `${basePrompt}\\n\\n---\\nHEARTBEAT.md:\\n${heartbeatContent}\\n---`;\n }\n basePrompt = appendCronEventLines(basePrompt, reasons);\n const prompt = `${basePrompt}\\n\\nCurrent time: ${new Date().toISOString()}`;\n\n const ackMax = cfg.ackMaxChars ?? DEFAULT_ACK_MAX_CHARS;\n\n log.debug({ sessionKey, reasons: reasonSummary }, 'Heartbeat: invoking agent');\n\n // `heartbeat:main` reuses one session key; each run would otherwise append to the transcript\n // until the model rejects the request (context window exceeded). Heartbeat prompts are\n // self-contained (HEARTBEAT.md + this turn's text), so we start from an empty history.\n if (sessionKey === 'heartbeat:main') {\n try {\n await this.deps.sessionStore.saveMessages(sessionKey, [], {\n metadata: {\n sourceChannel: 'heartbeat',\n sourceChatId: 'main',\n sessionType: 'heartbeat',\n customData: { heartbeatTarget: 'main' },\n routing: {\n agentId: 'main',\n source: 'heartbeat',\n accountId: 'default',\n peerKind: 'direct',\n peerId: 'main',\n },\n },\n });\n } catch (err) {\n log.warn({ err, sessionKey }, 'Heartbeat: failed to reset main session transcript');\n }\n }\n\n let reply: string;\n try {\n reply = await this.deps.agentService.turnDispatcher.processDirect(prompt, sessionKey);\n } catch (error) {\n log.error({ err: error }, 'Heartbeat: agent call failed');\n return;\n }\n\n if (!reply?.trim()) {\n log.debug({ reasons: reasonSummary }, 'Heartbeat: skip (empty model reply)');\n return;\n }\n\n if (shouldSilence(reply, ackMax)) {\n log.info(\n { ackMax, replyChars: reply.length, reasons: reasonSummary },\n 'Heartbeat: not sent — silent (HEARTBEAT_OK / short ack)',\n );\n return;\n }\n\n const { stripped } = stripHeartbeatToken(reply);\n const finalText = stripped || reply.trim();\n\n if (this.isDuplicate(finalText)) {\n log.info(\n { finalTextChars: finalText.length, reasons: reasonSummary },\n 'Heartbeat: not sent — duplicate within 24h',\n );\n return;\n }\n\n const target = cfg.target?.trim();\n const targetChatId = cfg.targetChatId?.trim();\n const hasDeliveryTarget = Boolean(target && targetChatId);\n\n if (hasDeliveryTarget) {\n await this.deps.messageBus.publishOutbound({\n channel: target!,\n chat_id: targetChatId!,\n content: finalText,\n type: 'message',\n });\n log.info(\n {\n reasons: reasonSummary,\n channel: target,\n chatId: targetChatId,\n contentChars: finalText.length,\n },\n 'Heartbeat: sent — outbound queued',\n );\n } else {\n log.info(\n { reasons: reasonSummary, finalTextChars: finalText.length },\n 'Heartbeat: not sent — no delivery target (set gateway.heartbeat.target + targetChatId)',\n );\n }\n\n this.lastHeartbeatText = finalText;\n this.lastHeartbeatAt = Date.now();\n }\n\n private isDuplicate(text: string): boolean {\n const DEDUP_WINDOW_MS = 24 * 60 * 60 * 1000;\n return (\n text.trim() === this.lastHeartbeatText.trim() &&\n Date.now() - this.lastHeartbeatAt < DEDUP_WINDOW_MS\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ import { buildGatewayConsoleCspHeader } from "../security/csp.js";
|
|
|
10
10
|
import { checkBrowserOrigin } from "../security/origin-check.js";
|
|
11
11
|
import { auth } from "./middleware/auth.js";
|
|
12
12
|
import { operatorScopes } from "./middleware/scopes.js";
|
|
13
|
-
import { createStrictRateLimitMiddleware } from "./middleware/strict-rate-limit.js";
|
|
13
|
+
import { createChannelRateLimitMiddleware, createStrictRateLimitMiddleware } from "./middleware/strict-rate-limit.js";
|
|
14
14
|
import { logContextMiddleware } from "./middleware/log-context.js";
|
|
15
15
|
import { logger } from "./middleware/logger.js";
|
|
16
16
|
import { routeErrorMiddleware } from "./middleware/route-errors.js";
|
|
@@ -142,8 +142,18 @@ function createHonoApp(config) {
|
|
|
142
142
|
}
|
|
143
143
|
return next();
|
|
144
144
|
}));
|
|
145
|
+
const DEFAULT_API_BODY_MAX = 1 * 1024 * 1024;
|
|
146
|
+
const SKILL_UPLOAD_BODY_MAX = 10 * 1024 * 1024;
|
|
147
|
+
const NOTE_MEDIA_BODY_MAX = 25 * 1024 * 1024;
|
|
148
|
+
const VOICE_TRANSCRIBE_BODY_MAX = 35 * 1024 * 1024;
|
|
149
|
+
const WEBCHAT_AGENT_BODY_MAX = maxWebchatAgentRequestBodyBytes();
|
|
150
|
+
const isNoteMediaUploadRequest = (path, method, contentType) => {
|
|
151
|
+
if (method !== "POST") return false;
|
|
152
|
+
if (/^\/api\/notes\/[^/]+\/media$/.test(path)) return true;
|
|
153
|
+
return path === "/api/notes" && contentType?.includes("multipart/form-data") === true;
|
|
154
|
+
};
|
|
145
155
|
app.use("/api/skills/upload", bodyLimit({
|
|
146
|
-
maxSize:
|
|
156
|
+
maxSize: SKILL_UPLOAD_BODY_MAX,
|
|
147
157
|
onError: (c) => {
|
|
148
158
|
log.warn({
|
|
149
159
|
path: c.req.path,
|
|
@@ -155,10 +165,9 @@ function createHonoApp(config) {
|
|
|
155
165
|
}, 413);
|
|
156
166
|
}
|
|
157
167
|
}));
|
|
158
|
-
const DEFAULT_API_BODY_MAX = 1 * 1024 * 1024;
|
|
159
|
-
const WEBCHAT_AGENT_BODY_MAX = maxWebchatAgentRequestBodyBytes();
|
|
160
168
|
app.use("/api/*", async (c, next) => {
|
|
161
|
-
const
|
|
169
|
+
const contentType = c.req.header("content-type");
|
|
170
|
+
const maxSize = c.req.path === "/api/agent" ? WEBCHAT_AGENT_BODY_MAX : c.req.path === "/api/skills/upload" ? SKILL_UPLOAD_BODY_MAX : c.req.path === "/api/voice/transcribe" ? VOICE_TRANSCRIBE_BODY_MAX : isNoteMediaUploadRequest(c.req.path, c.req.method, contentType) ? NOTE_MEDIA_BODY_MAX : DEFAULT_API_BODY_MAX;
|
|
162
171
|
const maxSizeMb = Math.ceil(maxSize / (1024 * 1024));
|
|
163
172
|
return bodyLimit({
|
|
164
173
|
maxSize,
|
|
@@ -200,6 +209,10 @@ function createHonoApp(config) {
|
|
|
200
209
|
trustedProxies: service.currentConfig.gateway?.trustedProxies,
|
|
201
210
|
allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true
|
|
202
211
|
}) }),
|
|
212
|
+
channelRateLimitMiddleware: createChannelRateLimitMiddleware({ getTrustedProxyContext: () => ({
|
|
213
|
+
trustedProxies: service.currentConfig.gateway?.trustedProxies,
|
|
214
|
+
allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true
|
|
215
|
+
}) }),
|
|
203
216
|
sseConfig: {
|
|
204
217
|
service,
|
|
205
218
|
maxSseConnections: service.currentConfig.gateway.maxSseConnections
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","names":[],"sources":["../../../../src/gateway/hono/app.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport { cors } from 'hono/cors';\nimport { createMiddleware } from 'hono/factory';\nimport { bodyLimit } from 'hono/body-limit';\nimport { getConnInfo } from '@hono/node-server/conninfo';\n\nimport { resolveGatewayEffectiveHost } from '../../config/gateway-bind.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { GatewayService } from '../service.js';\nimport { resolveAllowedBrowserOrigins, resolveGatewayServiceListenPort } from '../host.js';\nimport { loadTunnelState } from '../../tunnel/tunnel-state.js';\nimport { maxWebchatAgentRequestBodyBytes } from '../chat-limits.js';\nimport { buildGatewayConsoleCspHeader } from '../security/csp.js';\nimport { checkBrowserOrigin } from '../security/origin-check.js';\nimport { isLoopbackIpAddress, isTrustedProxyAddress } from '../client-ip.js';\nimport { resolveReverseProxyPublicUrl } from '../public-url.js';\nimport { auth } from './middleware/auth.js';\nimport { operatorScopes } from './middleware/scopes.js';\nimport { createStrictRateLimitMiddleware } from './middleware/strict-rate-limit.js';\nimport { logContextMiddleware } from './middleware/log-context.js';\nimport { logger } from './middleware/logger.js';\nimport { routeErrorMiddleware } from './middleware/route-errors.js';\nimport { registerPublicExtensionAssetRoutes } from './routes/auth-registry-extensions.js';\nimport { registerAuthenticatedRoutes } from './routes/index.js';\nimport { registerPublicGatewayRoutes } from './routes/public-gateway.js';\nimport { resetLazyRouteBundlesForTests } from './routes/lazy-fallback.js';\nimport { prewarmStaticUiCache } from './lib/static-ui.js';\nimport { registerSiteShareMiddleware } from '../../share/site-share-router.js';\nconst log = createLogger('Gateway:App');\n\nexport interface HonoAppConfig {\n service: GatewayService;\n token?: string;\n}\n\n/**\n * Extension sandbox HTML under `/api/extensions/:id/assets/*` ships its own CSP\n * (`frame-ancestors 'self'`). The global gateway middleware must not overwrite it\n * with `frame-ancestors 'none'` / `X-Frame-Options: DENY`, or the console cannot embed iframes.\n */\nexport function isExtensionGatewayUiAssetPath(path: string): boolean {\n return /^\\/api\\/extensions\\/[^/]+\\/assets\\//.test(path);\n}\n\nexport function createHonoApp(config: HonoAppConfig): Hono {\n if (process.env.VITEST) {\n resetLazyRouteBundlesForTests();\n }\n const { service, token } = config;\n const app = new Hono();\n\n const gatewayPort = resolveGatewayServiceListenPort(service);\n\n const resolveBrowserOrigins = (): string[] =>\n resolveAllowedBrowserOrigins({\n configuredOrigins: service.currentConfig.gateway.corsOrigins,\n port: gatewayPort,\n bindHost: resolveGatewayEffectiveHost(service.currentConfig),\n tunnelPublicUrl: loadTunnelState()?.publicUrl,\n reverseProxyPublicUrl: resolveReverseProxyPublicUrl(service.currentConfig),\n });\n\n /**\n * TCP source for the in-flight request, normalized for trusted-proxy checks.\n * Returns undefined when the runtime doesn't expose conninfo (tests, mocks).\n */\n const resolveRequestRemoteAddress = (c: Context): string | undefined => {\n try {\n return getConnInfo(c).remote.address;\n } catch {\n return undefined;\n }\n };\n\n /**\n * A request's TCP source qualifies as a \"trusted proxy hop\" when it's\n * loopback (the user's own machine, where any reverse proxy lives) or\n * listed in `gateway.trustedProxies`. We use this signal to safely\n * auto-allow same-host Origins through CSRF without requiring a manual\n * `corsOrigins` entry for every reverse-proxy hostname.\n */\n const isRequestFromTrustedProxy = (c: Context): boolean => {\n const remote = resolveRequestRemoteAddress(c);\n if (!remote) return false;\n if (isLoopbackIpAddress(remote)) return true;\n return isTrustedProxyAddress(remote, service.currentConfig.gateway?.trustedProxies);\n };\n\n app.use(logContextMiddleware());\n app.use(logger({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }));\n\n // Site-share middleware runs BEFORE CORS/CSP — it owns the request when the\n // Host header matches `*.<publicHostSuffix>` (default `*.share.xopc.ai`) or\n // the path starts with `/site/:token/`. Otherwise it falls through.\n registerSiteShareMiddleware(app, service);\n app.use(\n cors({\n origin: (origin) => {\n const allowed = resolveBrowserOrigins();\n if (!origin) {\n return allowed[0] ?? `http://127.0.0.1:${gatewayPort}`;\n }\n const normalized = origin.toLowerCase();\n const hit = allowed.find((entry) => entry.toLowerCase() === normalized);\n if (hit) return origin;\n return allowed.includes('*') ? '*' : '';\n },\n allowMethods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Session-Id', 'Last-Event-ID'],\n credentials: true,\n maxAge: 86400,\n }),\n );\n\n // Build CSP header once at startup (no inline script hashes needed for SPA)\n const gatewayConsoleCsp = buildGatewayConsoleCspHeader();\n\n // Security headers middleware\n app.use(createMiddleware(async (c, next) => {\n await next();\n if (isExtensionGatewayUiAssetPath(c.req.path)) {\n return;\n }\n c.header('X-Frame-Options', 'DENY');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Referrer-Policy', 'strict-origin-when-cross-origin');\n c.header('X-XSS-Protection', '1; mode=block');\n // microphone=(self): allow same-origin chat voice (composer). microphone=() breaks packaged Electron loading the gateway SPA.\n c.header('Permissions-Policy', 'camera=(), microphone=(self), geolocation=()');\n c.header('Content-Security-Policy', gatewayConsoleCsp);\n }));\n\n // Browser Origin check middleware for API routes (CSRF protection).\n // Non-browser requests (no Origin header) pass through — they are\n // authenticated by the token middleware instead.\n const allowHostHeaderOriginFallback =\n service.currentConfig.gateway?.dangerouslyAllowHostHeaderOriginFallback === true;\n app.use('/api/*', createMiddleware(async (c, next) => {\n // Sandboxed extension iframes (no allow-same-origin) send `Origin: null`.\n // `checkBrowserOrigin` rejects that; these routes rely on CSP instead\n // (`registerPublicExtensionAssetRoutes`).\n if (isExtensionGatewayUiAssetPath(c.req.path)) {\n return next();\n }\n\n const origin = c.req.header('origin');\n if (!origin || origin.trim().toLowerCase() === 'null') {\n // Native apps / opaque origins — authenticated via Bearer token\n return next();\n }\n\n const result = checkBrowserOrigin({\n requestHost: c.req.header('host'),\n origin,\n allowedOrigins: resolveBrowserOrigins(),\n allowHostHeaderOriginFallback,\n autoAllowSameHostFromTrustedProxy: isRequestFromTrustedProxy(c),\n isLocalClient: false,\n });\n\n if (!result.ok) {\n log.warn(\n {\n origin,\n requestHost: c.req.header('host'),\n reason: 'reason' in result ? result.reason : 'unknown',\n path: c.req.path,\n method: c.req.method,\n },\n `Browser origin check failed: ${origin} not in allowed list`,\n );\n return c.json({ error: 'Forbidden', message: 'Origin not allowed' }, 403);\n }\n\n return next();\n }));\n\n app.use('/api/skills/upload', bodyLimit({\n maxSize: 10 * 1024 * 1024,\n onError: (c) => {\n log.warn({ path: c.req.path, maxSizeMb: 10 }, 'Request body too large: skills upload exceeds 10MB limit');\n return c.json({ error: 'Skill package too large', maxSize: '10MB' }, 413);\n },\n }));\n\n const DEFAULT_API_BODY_MAX = 1 * 1024 * 1024;\n const WEBCHAT_AGENT_BODY_MAX = maxWebchatAgentRequestBodyBytes();\n\n app.use('/api/*', async (c, next) => {\n const maxSize = c.req.path === '/api/agent' ? WEBCHAT_AGENT_BODY_MAX : DEFAULT_API_BODY_MAX;\n const maxSizeMb = Math.ceil(maxSize / (1024 * 1024));\n return bodyLimit({\n maxSize,\n onError: (ctx) => {\n log.warn({ path: ctx.req.path, maxSizeMb }, `Request body too large: exceeds ${maxSizeMb}MB limit`);\n return ctx.json({ error: 'Request body too large', maxSize: `${maxSizeMb}MB` }, 413);\n },\n })(c, next);\n });\n\n registerPublicGatewayRoutes(app, service);\n\n // Extension UI assets are served without auth: sandboxed iframes (no allow-same-origin)\n // have an opaque origin of `null` and cannot forward the ?token= from the parent HTML URL.\n // Security is enforced by the strict CSP (frame-ancestors 'self') on every response.\n registerPublicExtensionAssetRoutes(app, service);\n\n const authenticated = new Hono();\n authenticated.use(routeErrorMiddleware());\n authenticated.use(\n auth({\n token,\n getGatewayAuth: () => service.currentConfig.gateway?.auth,\n getResolvedAuth: () => {\n if (typeof service.getResolvedAuth === 'function') {\n return service.getResolvedAuth();\n }\n return token ? { mode: 'token', token } : { mode: 'none' };\n },\n getTrustedProxyContext: () => ({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }),\n }),\n );\n authenticated.use(operatorScopes());\n\n const strictRateLimitMiddleware = createStrictRateLimitMiddleware({\n getTrustedProxyContext: () => ({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }),\n });\n\n const sseConfig = {\n service,\n maxSseConnections: service.currentConfig.gateway.maxSseConnections,\n };\n\n registerAuthenticatedRoutes(app, authenticated, {\n service,\n strictRateLimitMiddleware,\n sseConfig,\n });\n\n const prewarm = prewarmStaticUiCache();\n if (prewarm.loaded > 0) {\n log.debug({ loaded: prewarm.loaded, missing: prewarm.missing }, 'Static UI cache prewarmed');\n }\n\n app.route('/', authenticated);\n\n app.notFound((c) => {\n const isApiRoute = c.req.path.startsWith('/api/');\n const fields = { path: c.req.path, method: c.req.method };\n if (isApiRoute) {\n log.warn(fields, 'Route not found');\n } else {\n log.debug(fields, 'Route not found');\n }\n return c.json({ error: 'Not found' }, 404);\n });\n\n app.onError((err, c) => {\n log.error(\n {\n err,\n phase: 'gateway.http.unhandled',\n path: c.req.path,\n method: c.req.method,\n userAgent: c.req.header('user-agent'),\n },\n `Hono error on ${c.req.method} ${c.req.path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return c.json({ error: 'Internal server error' }, 500);\n });\n\n return app;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"app.js","names":[],"sources":["../../../../src/gateway/hono/app.ts"],"sourcesContent":["import { Hono } from 'hono';\nimport type { Context } from 'hono';\nimport { cors } from 'hono/cors';\nimport { createMiddleware } from 'hono/factory';\nimport { bodyLimit } from 'hono/body-limit';\nimport { getConnInfo } from '@hono/node-server/conninfo';\n\nimport { resolveGatewayEffectiveHost } from '../../config/gateway-bind.js';\nimport { createLogger } from '../../utils/logger.js';\nimport type { GatewayService } from '../service.js';\nimport { resolveAllowedBrowserOrigins, resolveGatewayServiceListenPort } from '../host.js';\nimport { loadTunnelState } from '../../tunnel/tunnel-state.js';\nimport { maxWebchatAgentRequestBodyBytes } from '../chat-limits.js';\nimport { buildGatewayConsoleCspHeader } from '../security/csp.js';\nimport { checkBrowserOrigin } from '../security/origin-check.js';\nimport { isLoopbackIpAddress, isTrustedProxyAddress } from '../client-ip.js';\nimport { resolveReverseProxyPublicUrl } from '../public-url.js';\nimport { auth } from './middleware/auth.js';\nimport { operatorScopes } from './middleware/scopes.js';\nimport {\n createChannelRateLimitMiddleware,\n createStrictRateLimitMiddleware,\n} from './middleware/strict-rate-limit.js';\nimport { logContextMiddleware } from './middleware/log-context.js';\nimport { logger } from './middleware/logger.js';\nimport { routeErrorMiddleware } from './middleware/route-errors.js';\nimport { registerPublicExtensionAssetRoutes } from './routes/auth-registry-extensions.js';\nimport { registerAuthenticatedRoutes } from './routes/index.js';\nimport { registerPublicGatewayRoutes } from './routes/public-gateway.js';\nimport { resetLazyRouteBundlesForTests } from './routes/lazy-fallback.js';\nimport { prewarmStaticUiCache } from './lib/static-ui.js';\nimport { registerSiteShareMiddleware } from '../../share/site-share-router.js';\nconst log = createLogger('Gateway:App');\n\nexport interface HonoAppConfig {\n service: GatewayService;\n token?: string;\n}\n\n/**\n * Extension sandbox HTML under `/api/extensions/:id/assets/*` ships its own CSP\n * (`frame-ancestors 'self'`). The global gateway middleware must not overwrite it\n * with `frame-ancestors 'none'` / `X-Frame-Options: DENY`, or the console cannot embed iframes.\n */\nexport function isExtensionGatewayUiAssetPath(path: string): boolean {\n return /^\\/api\\/extensions\\/[^/]+\\/assets\\//.test(path);\n}\n\nexport function createHonoApp(config: HonoAppConfig): Hono {\n if (process.env.VITEST) {\n resetLazyRouteBundlesForTests();\n }\n const { service, token } = config;\n const app = new Hono();\n\n const gatewayPort = resolveGatewayServiceListenPort(service);\n\n const resolveBrowserOrigins = (): string[] =>\n resolveAllowedBrowserOrigins({\n configuredOrigins: service.currentConfig.gateway.corsOrigins,\n port: gatewayPort,\n bindHost: resolveGatewayEffectiveHost(service.currentConfig),\n tunnelPublicUrl: loadTunnelState()?.publicUrl,\n reverseProxyPublicUrl: resolveReverseProxyPublicUrl(service.currentConfig),\n });\n\n /**\n * TCP source for the in-flight request, normalized for trusted-proxy checks.\n * Returns undefined when the runtime doesn't expose conninfo (tests, mocks).\n */\n const resolveRequestRemoteAddress = (c: Context): string | undefined => {\n try {\n return getConnInfo(c).remote.address;\n } catch {\n return undefined;\n }\n };\n\n /**\n * A request's TCP source qualifies as a \"trusted proxy hop\" when it's\n * loopback (the user's own machine, where any reverse proxy lives) or\n * listed in `gateway.trustedProxies`. We use this signal to safely\n * auto-allow same-host Origins through CSRF without requiring a manual\n * `corsOrigins` entry for every reverse-proxy hostname.\n */\n const isRequestFromTrustedProxy = (c: Context): boolean => {\n const remote = resolveRequestRemoteAddress(c);\n if (!remote) return false;\n if (isLoopbackIpAddress(remote)) return true;\n return isTrustedProxyAddress(remote, service.currentConfig.gateway?.trustedProxies);\n };\n\n app.use(logContextMiddleware());\n app.use(logger({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }));\n\n // Site-share middleware runs BEFORE CORS/CSP — it owns the request when the\n // Host header matches `*.<publicHostSuffix>` (default `*.share.xopc.ai`) or\n // the path starts with `/site/:token/`. Otherwise it falls through.\n registerSiteShareMiddleware(app, service);\n app.use(\n cors({\n origin: (origin) => {\n const allowed = resolveBrowserOrigins();\n if (!origin) {\n return allowed[0] ?? `http://127.0.0.1:${gatewayPort}`;\n }\n const normalized = origin.toLowerCase();\n const hit = allowed.find((entry) => entry.toLowerCase() === normalized);\n if (hit) return origin;\n return allowed.includes('*') ? '*' : '';\n },\n allowMethods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization', 'Accept', 'X-Session-Id', 'Last-Event-ID'],\n credentials: true,\n maxAge: 86400,\n }),\n );\n\n // Build CSP header once at startup (no inline script hashes needed for SPA)\n const gatewayConsoleCsp = buildGatewayConsoleCspHeader();\n\n // Security headers middleware\n app.use(createMiddleware(async (c, next) => {\n await next();\n if (isExtensionGatewayUiAssetPath(c.req.path)) {\n return;\n }\n c.header('X-Frame-Options', 'DENY');\n c.header('X-Content-Type-Options', 'nosniff');\n c.header('Referrer-Policy', 'strict-origin-when-cross-origin');\n c.header('X-XSS-Protection', '1; mode=block');\n // microphone=(self): allow same-origin chat voice (composer). microphone=() breaks packaged Electron loading the gateway SPA.\n c.header('Permissions-Policy', 'camera=(), microphone=(self), geolocation=()');\n c.header('Content-Security-Policy', gatewayConsoleCsp);\n }));\n\n // Browser Origin check middleware for API routes (CSRF protection).\n // Non-browser requests (no Origin header) pass through — they are\n // authenticated by the token middleware instead.\n const allowHostHeaderOriginFallback =\n service.currentConfig.gateway?.dangerouslyAllowHostHeaderOriginFallback === true;\n app.use('/api/*', createMiddleware(async (c, next) => {\n // Sandboxed extension iframes (no allow-same-origin) send `Origin: null`.\n // `checkBrowserOrigin` rejects that; these routes rely on CSP instead\n // (`registerPublicExtensionAssetRoutes`).\n if (isExtensionGatewayUiAssetPath(c.req.path)) {\n return next();\n }\n\n const origin = c.req.header('origin');\n if (!origin || origin.trim().toLowerCase() === 'null') {\n // Native apps / opaque origins — authenticated via Bearer token\n return next();\n }\n\n const result = checkBrowserOrigin({\n requestHost: c.req.header('host'),\n origin,\n allowedOrigins: resolveBrowserOrigins(),\n allowHostHeaderOriginFallback,\n autoAllowSameHostFromTrustedProxy: isRequestFromTrustedProxy(c),\n isLocalClient: false,\n });\n\n if (!result.ok) {\n log.warn(\n {\n origin,\n requestHost: c.req.header('host'),\n reason: 'reason' in result ? result.reason : 'unknown',\n path: c.req.path,\n method: c.req.method,\n },\n `Browser origin check failed: ${origin} not in allowed list`,\n );\n return c.json({ error: 'Forbidden', message: 'Origin not allowed' }, 403);\n }\n\n return next();\n }));\n\n const DEFAULT_API_BODY_MAX = 1 * 1024 * 1024;\n const SKILL_UPLOAD_BODY_MAX = 10 * 1024 * 1024;\n const NOTE_MEDIA_BODY_MAX = 25 * 1024 * 1024;\n const VOICE_TRANSCRIBE_BODY_MAX = 35 * 1024 * 1024;\n const WEBCHAT_AGENT_BODY_MAX = maxWebchatAgentRequestBodyBytes();\n\n const isNoteMediaUploadRequest = (path: string, method: string, contentType: string | undefined): boolean => {\n if (method !== 'POST') return false;\n if (/^\\/api\\/notes\\/[^/]+\\/media$/.test(path)) return true;\n return path === '/api/notes' && contentType?.includes('multipart/form-data') === true;\n };\n\n app.use('/api/skills/upload', bodyLimit({\n maxSize: SKILL_UPLOAD_BODY_MAX,\n onError: (c) => {\n log.warn({ path: c.req.path, maxSizeMb: 10 }, 'Request body too large: skills upload exceeds 10MB limit');\n return c.json({ error: 'Skill package too large', maxSize: '10MB' }, 413);\n },\n }));\n\n app.use('/api/*', async (c, next) => {\n const contentType = c.req.header('content-type');\n const maxSize = c.req.path === '/api/agent'\n ? WEBCHAT_AGENT_BODY_MAX\n : c.req.path === '/api/skills/upload'\n ? SKILL_UPLOAD_BODY_MAX\n : c.req.path === '/api/voice/transcribe'\n ? VOICE_TRANSCRIBE_BODY_MAX\n : isNoteMediaUploadRequest(c.req.path, c.req.method, contentType)\n ? NOTE_MEDIA_BODY_MAX\n : DEFAULT_API_BODY_MAX;\n const maxSizeMb = Math.ceil(maxSize / (1024 * 1024));\n return bodyLimit({\n maxSize,\n onError: (ctx) => {\n log.warn({ path: ctx.req.path, maxSizeMb }, `Request body too large: exceeds ${maxSizeMb}MB limit`);\n return ctx.json({ error: 'Request body too large', maxSize: `${maxSizeMb}MB` }, 413);\n },\n })(c, next);\n });\n\n registerPublicGatewayRoutes(app, service);\n\n // Extension UI assets are served without auth: sandboxed iframes (no allow-same-origin)\n // have an opaque origin of `null` and cannot forward the ?token= from the parent HTML URL.\n // Security is enforced by the strict CSP (frame-ancestors 'self') on every response.\n registerPublicExtensionAssetRoutes(app, service);\n\n const authenticated = new Hono();\n authenticated.use(routeErrorMiddleware());\n authenticated.use(\n auth({\n token,\n getGatewayAuth: () => service.currentConfig.gateway?.auth,\n getResolvedAuth: () => {\n if (typeof service.getResolvedAuth === 'function') {\n return service.getResolvedAuth();\n }\n return token ? { mode: 'token', token } : { mode: 'none' };\n },\n getTrustedProxyContext: () => ({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }),\n }),\n );\n authenticated.use(operatorScopes());\n\n const strictRateLimitMiddleware = createStrictRateLimitMiddleware({\n getTrustedProxyContext: () => ({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }),\n });\n const channelRateLimitMiddleware = createChannelRateLimitMiddleware({\n getTrustedProxyContext: () => ({\n trustedProxies: service.currentConfig.gateway?.trustedProxies,\n allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true,\n }),\n });\n\n const sseConfig = {\n service,\n maxSseConnections: service.currentConfig.gateway.maxSseConnections,\n };\n\n registerAuthenticatedRoutes(app, authenticated, {\n service,\n strictRateLimitMiddleware,\n channelRateLimitMiddleware,\n sseConfig,\n });\n\n const prewarm = prewarmStaticUiCache();\n if (prewarm.loaded > 0) {\n log.debug({ loaded: prewarm.loaded, missing: prewarm.missing }, 'Static UI cache prewarmed');\n }\n\n app.route('/', authenticated);\n\n app.notFound((c) => {\n const isApiRoute = c.req.path.startsWith('/api/');\n const fields = { path: c.req.path, method: c.req.method };\n if (isApiRoute) {\n log.warn(fields, 'Route not found');\n } else {\n log.debug(fields, 'Route not found');\n }\n return c.json({ error: 'Not found' }, 404);\n });\n\n app.onError((err, c) => {\n log.error(\n {\n err,\n phase: 'gateway.http.unhandled',\n path: c.req.path,\n method: c.req.method,\n userAgent: c.req.header('user-agent'),\n },\n `Hono error on ${c.req.method} ${c.req.path}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return c.json({ error: 'Internal server error' }, 500);\n });\n\n return app;\n}\n"],"mappings":"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"}
|
|
@@ -194,8 +194,9 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
|
|
|
194
194
|
};
|
|
195
195
|
channels: {
|
|
196
196
|
[k: string]: {
|
|
197
|
-
enabled:
|
|
197
|
+
enabled: boolean;
|
|
198
198
|
configured: boolean;
|
|
199
|
+
setupStatus: import("../../../channels/catalog/channel-catalog-types.js").ChannelSetupStatus;
|
|
199
200
|
config: Record<string, unknown>;
|
|
200
201
|
schema: Record<string, unknown>;
|
|
201
202
|
uiHints: Record<string, import("../../../extensions/index.js").ChannelConfigUiHint>;
|
|
@@ -266,6 +267,7 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
|
|
|
266
267
|
goals: {
|
|
267
268
|
maxTurns: number;
|
|
268
269
|
checklistMode: boolean;
|
|
270
|
+
checklistDecomposePolicy: "empty_only" | "supplement_existing";
|
|
269
271
|
maxConsecutiveParseFailures: number;
|
|
270
272
|
judgeTimeoutMs: number;
|
|
271
273
|
checklistHistoryChars: number;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
|
|
2
2
|
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
3
|
+
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
|
|
3
4
|
import { init_models_json, loadModelsJson } from "../../../config/models-json.js";
|
|
4
5
|
import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
|
|
5
|
-
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, init_channel_catalog_service, isChannelConfigured } from "../../../channels/catalog/channel-catalog-service.js";
|
|
6
6
|
import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
|
|
7
7
|
import { getAllProviders, init_providers, isProviderConfigured } from "../../../providers/index.js";
|
|
8
8
|
import { resolveShareConfig } from "../../../share/share-config.js";
|
|
@@ -95,10 +95,13 @@ async function buildSafeWebConfigPayload(service, options = {}) {
|
|
|
95
95
|
const catalog = snapshot ? buildChannelCatalogFromSnapshot(snapshot, { locale: options.locale }) : buildChannelCatalogForConfig(config, { locale: options.locale });
|
|
96
96
|
const channelsPayload = Object.fromEntries(catalog.entries.map((entry) => {
|
|
97
97
|
const plugin = typeof service.getChannelRuntimePlugin === "function" ? service.getChannelRuntimePlugin(entry.id) : void 0;
|
|
98
|
-
const
|
|
98
|
+
const channelCfgKey = entry.configPath.startsWith("channels.") ? entry.configPath.slice(9).split(".")[0] || entry.id : entry.id;
|
|
99
|
+
const channelCfg = config.channels?.[channelCfgKey];
|
|
100
|
+
const setupStatus = getChannelSetupStatus(config, entry.id, entry);
|
|
99
101
|
return [entry.id, {
|
|
100
|
-
enabled:
|
|
101
|
-
configured:
|
|
102
|
+
enabled: setupStatus.enabled,
|
|
103
|
+
configured: setupStatus.ready,
|
|
104
|
+
setupStatus,
|
|
102
105
|
config: plugin?.configSurface?.buildConfigSurface(config) ?? channelCfg ?? {},
|
|
103
106
|
schema: entry.configSchema,
|
|
104
107
|
uiHints: entry.uiHints
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-payload.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/lib/config-payload.ts"],"sourcesContent":["import {\n listAgentEntries,\n normalizeAgentId,\n resolveDefaultAgentId,\n} from '../../../agent/agent-scope.js';\nimport {\n buildChannelCatalogForConfig,\n buildChannelCatalogFromSnapshot,\n isChannelConfigured,\n} from '../../../channels/catalog/channel-catalog-service.js';\nimport { normalizeConfiguredMcpServers } from '../../../config/mcp-config-normalize.js';\nimport type { Config } from '../../../config/schema.js';\nimport {\n GENERIC_MASKED_SECRET,\n maskSecretLength,\n} from './mask-secret-length.js';\nimport { maskTunnelSecretForWeb } from '../../../tunnel/env.js';\nimport { resolveShareConfig } from '../../../share/share-config.js';\nimport {\n resolveCronConfigForWeb,\n resolveGoalsConfigForWeb,\n resolveSessionConfigForWeb,\n resolveUpdateConfigForWeb,\n} from '../../../config/web-patch.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { loadModelsJson, getModelsJsonPath } from '../../../config/models-json.js';\nimport { getAllProviders, isProviderConfigured } from '../../../providers/index.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { GatewayService } from '../../service.js';\nimport { safeToolsWebForGet } from '../../config-tools-web.js';\nimport {\n agentImageGenerationModelAutoProviderFallback,\n agentImageGenerationModelTimeoutMs,\n agentModelFallbacksToArray,\n agentModelRefToString,\n} from './agent-model.js';\nimport { buildSafeProvidersConfigForWeb } from './safe-providers-config.js';\nimport { maskSttConfigForWeb, maskTtsConfigForWeb } from './safe-voice-config.js';\n\nfunction readModelsJsonProviderApiKey(providerId: string): string | undefined {\n const { config } = loadModelsJson(getModelsJsonPath());\n const entry = config.providers?.[providerId];\n const key = entry?.apiKey;\n return typeof key === 'string' && key.trim() ? key.trim() : undefined;\n}\n\n/** Length-preserving mask for LLM provider keys in GET `/api/config`. */\nasync function maskLlmProviderApiKeyForWeb(provider: string): Promise<string> {\n const resolver = new CredentialResolver();\n const stored = await resolver.revealGatewayStoredApiKey(provider);\n if (stored) return maskSecretLength(stored);\n\n const fromModelsJson = readModelsJsonProviderApiKey(provider);\n if (fromModelsJson) return maskSecretLength(fromModelsJson);\n\n // Extension plugins manage their own auth; don't show a fake gateway key mask.\n if (getProviderRegistry().has(provider)) return '';\n\n if (await isProviderConfigured(provider)) return GENERIC_MASKED_SECRET;\n return '';\n}\n\n/** MCP block for GET/PATCH `/api/config` (authenticated console editing). */\nexport function buildSafeMcpConfigForWeb(config: Config) {\n const mcp = config.mcp;\n if (!mcp) {\n return { servers: {} as Record<string, Record<string, unknown>> };\n }\n return {\n ...(mcp.sessionIdleTtlMs !== undefined ? { sessionIdleTtlMs: mcp.sessionIdleTtlMs } : {}),\n servers: normalizeConfiguredMcpServers(mcp.servers),\n };\n}\n\nfunction maskBrowserCloudConfigForWeb(cloud: unknown): Record<string, unknown> | null {\n if (!cloud || typeof cloud !== 'object' || Array.isArray(cloud)) {\n return null;\n }\n const raw = cloud as Record<string, unknown>;\n const safe: Record<string, unknown> = {};\n if (typeof raw.apiKey === 'string' && raw.apiKey.trim()) {\n safe.apiKey = maskSecretLength(raw.apiKey);\n }\n if (typeof raw.projectId === 'string' && raw.projectId.trim()) {\n safe.projectId = raw.projectId.trim();\n }\n if (typeof raw.region === 'string' && raw.region.trim()) {\n safe.region = raw.region.trim();\n }\n return Object.keys(safe).length > 0 ? safe : null;\n}\n\nexport function buildSafeBrowserConfigForWeb(browser: Config['agents']['defaults']['browser'] | undefined) {\n if (!browser || typeof browser !== 'object') {\n return {\n enabled: false,\n headless: false,\n allowPrivateUrls: false,\n commandTimeout: null,\n backend: null,\n cloudProvider: null,\n cloud: null,\n cdpUrl: null,\n extension: null,\n cloakbrowser: null,\n humanize: null,\n humanPreset: null,\n dialogPolicy: null,\n dialogTimeoutSeconds: null,\n };\n }\n\n return {\n enabled: browser.enabled !== false,\n headless: browser.headless === true,\n allowPrivateUrls: browser.allowPrivateUrls === true,\n commandTimeout:\n typeof browser.commandTimeout === 'number' && Number.isFinite(browser.commandTimeout)\n ? Math.floor(browser.commandTimeout)\n : null,\n backend:\n browser.backend === 'local' ||\n browser.backend === 'cdp' ||\n browser.backend === 'cloud' ||\n browser.backend === 'extension' ||\n browser.backend === 'cloakbrowser'\n ? browser.backend\n : null,\n cloudProvider:\n browser.cloudProvider === 'browserbase' || browser.cloudProvider === 'browser-use'\n ? browser.cloudProvider\n : null,\n cloud: maskBrowserCloudConfigForWeb(browser.cloud),\n cdpUrl: typeof browser.cdpUrl === 'string' && browser.cdpUrl.trim() ? browser.cdpUrl.trim() : null,\n extension: browser.extension && typeof browser.extension === 'object' && !Array.isArray(browser.extension)\n ? browser.extension\n : null,\n cloakbrowser:\n browser.cloakbrowser && typeof browser.cloakbrowser === 'object' && !Array.isArray(browser.cloakbrowser)\n ? browser.cloakbrowser\n : null,\n humanize: typeof browser.humanize === 'boolean' ? browser.humanize : null,\n humanPreset: browser.humanPreset === 'default' || browser.humanPreset === 'careful' ? browser.humanPreset : null,\n dialogPolicy:\n browser.dialogPolicy === 'must_respond' ||\n browser.dialogPolicy === 'auto_accept' ||\n browser.dialogPolicy === 'auto_dismiss'\n ? browser.dialogPolicy\n : null,\n dialogTimeoutSeconds:\n typeof browser.dialogTimeoutSeconds === 'number' && Number.isFinite(browser.dialogTimeoutSeconds)\n ? Math.floor(browser.dialogTimeoutSeconds)\n : null,\n };\n}\n\n/** Sanitized config snapshot for GET/PATCH `/api/config` (matches persisted `service.currentConfig`). */\nexport async function buildSafeWebConfigPayload(service: GatewayService, options: { locale?: string } = {}) {\n const config = service.currentConfig;\n const extensionLoader =\n typeof service.getExtensionLoader === 'function' ? service.getExtensionLoader() : undefined;\n const snapshot = extensionLoader?.getManifestSnapshot();\n const catalog = snapshot\n ? buildChannelCatalogFromSnapshot(snapshot, { locale: options.locale })\n : buildChannelCatalogForConfig(config, { locale: options.locale });\n const channelsPayload = Object.fromEntries(\n catalog.entries.map((entry) => {\n const plugin =\n typeof service.getChannelRuntimePlugin === 'function'\n ? service.getChannelRuntimePlugin(entry.id)\n : undefined;\n const channelCfg = config.channels?.[entry.id] as Record<string, unknown> | undefined;\n return [\n entry.id,\n {\n enabled: channelCfg?.enabled ?? false,\n configured: isChannelConfigured(config, entry.id),\n config: plugin?.configSurface?.buildConfigSurface(config) ?? channelCfg ?? {},\n schema: entry.configSchema,\n uiHints: entry.uiHints,\n },\n ];\n }),\n );\n return {\n agents: {\n defaultId: resolveDefaultAgentId(config),\n list: listAgentEntries(config)\n .filter((e) => e.enabled !== false)\n .map((e) => ({\n id: normalizeAgentId(e.id),\n })),\n defaults: {\n model: agentModelRefToString(config.agents?.defaults?.models?.chat) ?? '',\n modelFallbacks: agentModelFallbacksToArray(config.agents?.defaults?.models?.chat),\n imageModel: agentModelRefToString(config.agents?.defaults?.imageModel) ?? null,\n imageModelFallbacks: agentModelFallbacksToArray(config.agents?.defaults?.imageModel),\n imageGenerationModel: agentModelRefToString(config.agents?.defaults?.imageGenerationModel) ?? null,\n imageGenerationModelFallbacks: agentModelFallbacksToArray(\n config.agents?.defaults?.imageGenerationModel,\n ),\n imageGenerationModelTimeoutMs: agentImageGenerationModelTimeoutMs(\n config.agents?.defaults?.imageGenerationModel,\n ),\n imageGenerationModelAutoProviderFallback: agentImageGenerationModelAutoProviderFallback(\n config.agents?.defaults?.imageGenerationModel,\n ),\n mediaMaxMb: config.agents?.defaults?.mediaMaxMb,\n maxTokens: config.agents?.defaults?.maxTokens,\n temperature: config.agents?.defaults?.temperature,\n maxToolIterations: config.agents?.defaults?.maxToolIterations,\n workspace: config.agents?.defaults?.workspace,\n thinkingDefault: config.agents?.defaults?.thinkingDefault,\n reasoningDefault: config.agents?.defaults?.reasoningDefault,\n verboseDefault: config.agents?.defaults?.verboseDefault,\n browser: buildSafeBrowserConfigForWeb(config.agents?.defaults?.browser),\n maxTaskDurationMs: config.agents?.defaults?.maxTaskDurationMs,\n maxRequestsPerTurn: config.agents?.defaults?.maxRequestsPerTurn,\n maxToolFailuresPerTurn: config.agents?.defaults?.maxToolFailuresPerTurn,\n compaction: config.agents?.defaults?.compaction,\n pruning: config.agents?.defaults?.pruning,\n memory: config.agents?.defaults?.memory,\n sessionSearch: config.agents?.defaults?.sessionSearch,\n backgroundReview: config.agents?.defaults?.backgroundReview,\n webExtract: config.agents?.defaults?.webExtract,\n delegate: config.agents?.defaults?.delegate,\n executeCode: config.agents?.defaults?.executeCode,\n systemPromptOverride: config.agents?.defaults?.systemPromptOverride,\n skills: config.agents?.defaults?.skills,\n tools: config.agents?.defaults?.tools,\n models: config.agents?.defaults?.models,\n params: config.agents?.defaults?.params,\n },\n },\n channels: channelsPayload,\n providers: Object.fromEntries(\n await Promise.all(\n getAllProviders().map(async (provider) => [\n provider,\n await maskLlmProviderApiKeyForWeb(provider),\n ]),\n ),\n ),\n /** Masked `cfg.providers` for capability keys (image / STT / etc.). */\n providersConfig: buildSafeProvidersConfigForWeb(config.providers),\n gateway: {\n bind: config.gateway?.bind ?? 'loopback',\n customBindHost: config.gateway?.customBindHost,\n port: config.gateway?.port,\n corsOrigins: Array.isArray(config.gateway?.corsOrigins) ? config.gateway.corsOrigins : [],\n trustedProxies: Array.isArray(config.gateway?.trustedProxies)\n ? config.gateway.trustedProxies\n : [],\n allowRealIpFallback: config.gateway?.allowRealIpFallback === true,\n dangerouslyAllowHostHeaderOriginFallback:\n config.gateway?.dangerouslyAllowHostHeaderOriginFallback === true,\n security: {\n strict: config.gateway?.security?.strict === true,\n },\n auth: {\n mode: config.gateway?.auth?.mode || 'token',\n token: config.gateway?.auth?.token ? maskSecretLength(config.gateway.auth.token) : '',\n password: config.gateway?.auth?.password\n ? maskSecretLength(config.gateway.auth.password)\n : '',\n trustedProxy: config.gateway?.auth?.trustedProxy\n ? {\n userHeader: config.gateway.auth.trustedProxy.userHeader,\n requiredHeaders: config.gateway.auth.trustedProxy.requiredHeaders ?? [],\n allowUsers: config.gateway.auth.trustedProxy.allowUsers ?? [],\n allowLoopback: config.gateway.auth.trustedProxy.allowLoopback === true,\n }\n : undefined,\n rateLimit: {\n enabled: config.gateway?.auth?.rateLimit?.enabled !== false,\n maxAttempts:\n typeof config.gateway?.auth?.rateLimit?.maxAttempts === 'number'\n ? config.gateway.auth.rateLimit.maxAttempts\n : 5,\n windowMs:\n typeof config.gateway?.auth?.rateLimit?.windowMs === 'number'\n ? config.gateway.auth.rateLimit.windowMs\n : 900_000,\n blockDurationMs:\n typeof config.gateway?.auth?.rateLimit?.blockDurationMs === 'number'\n ? config.gateway.auth.rateLimit.blockDurationMs\n : typeof config.gateway?.auth?.rateLimit?.lockoutMs === 'number'\n ? config.gateway.auth.rateLimit.lockoutMs\n : 300_000,\n exemptLoopback: config.gateway?.auth?.rateLimit?.exemptLoopback !== false,\n },\n },\n heartbeat: {\n enabled: config.gateway?.heartbeat?.enabled,\n intervalMs: config.gateway?.heartbeat?.intervalMs,\n includeSystemPromptSection: config.gateway?.heartbeat?.includeSystemPromptSection === true,\n target: config.gateway?.heartbeat?.target,\n targetChatId: config.gateway?.heartbeat?.targetChatId,\n prompt: config.gateway?.heartbeat?.prompt,\n ackMaxChars: config.gateway?.heartbeat?.ackMaxChars,\n isolatedSession: config.gateway?.heartbeat?.isolatedSession,\n activeHours: config.gateway?.heartbeat?.activeHours,\n },\n maxSseConnections:\n typeof config.gateway?.maxSseConnections === 'number'\n ? config.gateway.maxSseConnections\n : 100,\n channelConnectDeferMode: config.gateway?.channelConnectDeferMode ?? 'auto',\n channelConnectDeferIds: Array.isArray(config.gateway?.channelConnectDeferIds)\n ? config.gateway.channelConnectDeferIds\n : [],\n channelConnectDeferSkipIds: Array.isArray(config.gateway?.channelConnectDeferSkipIds)\n ? config.gateway.channelConnectDeferSkipIds\n : [],\n share: resolveShareConfig(config.gateway?.share),\n publicUrl: config.gateway?.publicUrl ?? null,\n skillsMarketplaceProvider: config.gateway?.skillsMarketplaceProvider ?? 'skillhub',\n skillsStoreBaseUrl: config.gateway?.skillsStoreBaseUrl ?? 'https://store.xopc.ai',\n },\n cron: resolveCronConfigForWeb(config),\n goals: resolveGoalsConfigForWeb(config),\n session: resolveSessionConfigForWeb(config),\n tunnel: {\n enabled: config.tunnel?.enabled === true,\n autoStart: config.tunnel?.autoStart === true,\n brokerUrl: config.tunnel?.brokerUrl ?? 'https://frp.xopc.ai/api',\n registrationSecret: config.tunnel?.registrationSecret\n ? maskTunnelSecretForWeb(config.tunnel.registrationSecret)\n : '',\n consent: config.tunnel?.consent\n ? {\n version: config.tunnel.consent.version,\n acceptedAt: config.tunnel.consent.acceptedAt,\n }\n : undefined,\n transport: { tls: 'broker_terminated' as const },\n },\n update: {\n ...resolveUpdateConfigForWeb(config),\n },\n stt: maskSttConfigForWeb(config.tools?.media?.audio),\n tts: maskTtsConfigForWeb(config.messages?.tts),\n tools: safeToolsWebForGet(config),\n bindings: Array.isArray(config.bindings) ? config.bindings : [],\n mcp: buildSafeMcpConfigForWeb(config),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config-payload.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/lib/config-payload.ts"],"sourcesContent":["import {\n listAgentEntries,\n normalizeAgentId,\n resolveDefaultAgentId,\n} from '../../../agent/agent-scope.js';\nimport {\n buildChannelCatalogForConfig,\n buildChannelCatalogFromSnapshot,\n getChannelSetupStatus,\n} from '../../../channels/catalog/channel-catalog-service.js';\nimport { normalizeConfiguredMcpServers } from '../../../config/mcp-config-normalize.js';\nimport type { Config } from '../../../config/schema.js';\nimport {\n GENERIC_MASKED_SECRET,\n maskSecretLength,\n} from './mask-secret-length.js';\nimport { maskTunnelSecretForWeb } from '../../../tunnel/env.js';\nimport { resolveShareConfig } from '../../../share/share-config.js';\nimport {\n resolveCronConfigForWeb,\n resolveGoalsConfigForWeb,\n resolveSessionConfigForWeb,\n resolveUpdateConfigForWeb,\n} from '../../../config/web-patch.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { loadModelsJson, getModelsJsonPath } from '../../../config/models-json.js';\nimport { getAllProviders, isProviderConfigured } from '../../../providers/index.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { GatewayService } from '../../service.js';\nimport { safeToolsWebForGet } from '../../config-tools-web.js';\nimport {\n agentImageGenerationModelAutoProviderFallback,\n agentImageGenerationModelTimeoutMs,\n agentModelFallbacksToArray,\n agentModelRefToString,\n} from './agent-model.js';\nimport { buildSafeProvidersConfigForWeb } from './safe-providers-config.js';\nimport { maskSttConfigForWeb, maskTtsConfigForWeb } from './safe-voice-config.js';\n\nfunction readModelsJsonProviderApiKey(providerId: string): string | undefined {\n const { config } = loadModelsJson(getModelsJsonPath());\n const entry = config.providers?.[providerId];\n const key = entry?.apiKey;\n return typeof key === 'string' && key.trim() ? key.trim() : undefined;\n}\n\n/** Length-preserving mask for LLM provider keys in GET `/api/config`. */\nasync function maskLlmProviderApiKeyForWeb(provider: string): Promise<string> {\n const resolver = new CredentialResolver();\n const stored = await resolver.revealGatewayStoredApiKey(provider);\n if (stored) return maskSecretLength(stored);\n\n const fromModelsJson = readModelsJsonProviderApiKey(provider);\n if (fromModelsJson) return maskSecretLength(fromModelsJson);\n\n // Extension plugins manage their own auth; don't show a fake gateway key mask.\n if (getProviderRegistry().has(provider)) return '';\n\n if (await isProviderConfigured(provider)) return GENERIC_MASKED_SECRET;\n return '';\n}\n\n/** MCP block for GET/PATCH `/api/config` (authenticated console editing). */\nexport function buildSafeMcpConfigForWeb(config: Config) {\n const mcp = config.mcp;\n if (!mcp) {\n return { servers: {} as Record<string, Record<string, unknown>> };\n }\n return {\n ...(mcp.sessionIdleTtlMs !== undefined ? { sessionIdleTtlMs: mcp.sessionIdleTtlMs } : {}),\n servers: normalizeConfiguredMcpServers(mcp.servers),\n };\n}\n\nfunction maskBrowserCloudConfigForWeb(cloud: unknown): Record<string, unknown> | null {\n if (!cloud || typeof cloud !== 'object' || Array.isArray(cloud)) {\n return null;\n }\n const raw = cloud as Record<string, unknown>;\n const safe: Record<string, unknown> = {};\n if (typeof raw.apiKey === 'string' && raw.apiKey.trim()) {\n safe.apiKey = maskSecretLength(raw.apiKey);\n }\n if (typeof raw.projectId === 'string' && raw.projectId.trim()) {\n safe.projectId = raw.projectId.trim();\n }\n if (typeof raw.region === 'string' && raw.region.trim()) {\n safe.region = raw.region.trim();\n }\n return Object.keys(safe).length > 0 ? safe : null;\n}\n\nexport function buildSafeBrowserConfigForWeb(browser: Config['agents']['defaults']['browser'] | undefined) {\n if (!browser || typeof browser !== 'object') {\n return {\n enabled: false,\n headless: false,\n allowPrivateUrls: false,\n commandTimeout: null,\n backend: null,\n cloudProvider: null,\n cloud: null,\n cdpUrl: null,\n extension: null,\n cloakbrowser: null,\n humanize: null,\n humanPreset: null,\n dialogPolicy: null,\n dialogTimeoutSeconds: null,\n };\n }\n\n return {\n enabled: browser.enabled !== false,\n headless: browser.headless === true,\n allowPrivateUrls: browser.allowPrivateUrls === true,\n commandTimeout:\n typeof browser.commandTimeout === 'number' && Number.isFinite(browser.commandTimeout)\n ? Math.floor(browser.commandTimeout)\n : null,\n backend:\n browser.backend === 'local' ||\n browser.backend === 'cdp' ||\n browser.backend === 'cloud' ||\n browser.backend === 'extension' ||\n browser.backend === 'cloakbrowser'\n ? browser.backend\n : null,\n cloudProvider:\n browser.cloudProvider === 'browserbase' || browser.cloudProvider === 'browser-use'\n ? browser.cloudProvider\n : null,\n cloud: maskBrowserCloudConfigForWeb(browser.cloud),\n cdpUrl: typeof browser.cdpUrl === 'string' && browser.cdpUrl.trim() ? browser.cdpUrl.trim() : null,\n extension: browser.extension && typeof browser.extension === 'object' && !Array.isArray(browser.extension)\n ? browser.extension\n : null,\n cloakbrowser:\n browser.cloakbrowser && typeof browser.cloakbrowser === 'object' && !Array.isArray(browser.cloakbrowser)\n ? browser.cloakbrowser\n : null,\n humanize: typeof browser.humanize === 'boolean' ? browser.humanize : null,\n humanPreset: browser.humanPreset === 'default' || browser.humanPreset === 'careful' ? browser.humanPreset : null,\n dialogPolicy:\n browser.dialogPolicy === 'must_respond' ||\n browser.dialogPolicy === 'auto_accept' ||\n browser.dialogPolicy === 'auto_dismiss'\n ? browser.dialogPolicy\n : null,\n dialogTimeoutSeconds:\n typeof browser.dialogTimeoutSeconds === 'number' && Number.isFinite(browser.dialogTimeoutSeconds)\n ? Math.floor(browser.dialogTimeoutSeconds)\n : null,\n };\n}\n\n/** Sanitized config snapshot for GET/PATCH `/api/config` (matches persisted `service.currentConfig`). */\nexport async function buildSafeWebConfigPayload(service: GatewayService, options: { locale?: string } = {}) {\n const config = service.currentConfig;\n const extensionLoader =\n typeof service.getExtensionLoader === 'function' ? service.getExtensionLoader() : undefined;\n const snapshot = extensionLoader?.getManifestSnapshot();\n const catalog = snapshot\n ? buildChannelCatalogFromSnapshot(snapshot, { locale: options.locale })\n : buildChannelCatalogForConfig(config, { locale: options.locale });\n const channelsPayload = Object.fromEntries(\n catalog.entries.map((entry) => {\n const plugin =\n typeof service.getChannelRuntimePlugin === 'function'\n ? service.getChannelRuntimePlugin(entry.id)\n : undefined;\n const channelCfgKey = entry.configPath.startsWith('channels.')\n ? entry.configPath.slice('channels.'.length).split('.')[0] || entry.id\n : entry.id;\n const channelCfg = config.channels?.[channelCfgKey] as Record<string, unknown> | undefined;\n const setupStatus = getChannelSetupStatus(config, entry.id, entry);\n return [\n entry.id,\n {\n enabled: setupStatus.enabled,\n configured: setupStatus.ready,\n setupStatus,\n config: plugin?.configSurface?.buildConfigSurface(config) ?? channelCfg ?? {},\n schema: entry.configSchema,\n uiHints: entry.uiHints,\n },\n ];\n }),\n );\n return {\n agents: {\n defaultId: resolveDefaultAgentId(config),\n list: listAgentEntries(config)\n .filter((e) => e.enabled !== false)\n .map((e) => ({\n id: normalizeAgentId(e.id),\n })),\n defaults: {\n model: agentModelRefToString(config.agents?.defaults?.models?.chat) ?? '',\n modelFallbacks: agentModelFallbacksToArray(config.agents?.defaults?.models?.chat),\n imageModel: agentModelRefToString(config.agents?.defaults?.imageModel) ?? null,\n imageModelFallbacks: agentModelFallbacksToArray(config.agents?.defaults?.imageModel),\n imageGenerationModel: agentModelRefToString(config.agents?.defaults?.imageGenerationModel) ?? null,\n imageGenerationModelFallbacks: agentModelFallbacksToArray(\n config.agents?.defaults?.imageGenerationModel,\n ),\n imageGenerationModelTimeoutMs: agentImageGenerationModelTimeoutMs(\n config.agents?.defaults?.imageGenerationModel,\n ),\n imageGenerationModelAutoProviderFallback: agentImageGenerationModelAutoProviderFallback(\n config.agents?.defaults?.imageGenerationModel,\n ),\n mediaMaxMb: config.agents?.defaults?.mediaMaxMb,\n maxTokens: config.agents?.defaults?.maxTokens,\n temperature: config.agents?.defaults?.temperature,\n maxToolIterations: config.agents?.defaults?.maxToolIterations,\n workspace: config.agents?.defaults?.workspace,\n thinkingDefault: config.agents?.defaults?.thinkingDefault,\n reasoningDefault: config.agents?.defaults?.reasoningDefault,\n verboseDefault: config.agents?.defaults?.verboseDefault,\n browser: buildSafeBrowserConfigForWeb(config.agents?.defaults?.browser),\n maxTaskDurationMs: config.agents?.defaults?.maxTaskDurationMs,\n maxRequestsPerTurn: config.agents?.defaults?.maxRequestsPerTurn,\n maxToolFailuresPerTurn: config.agents?.defaults?.maxToolFailuresPerTurn,\n compaction: config.agents?.defaults?.compaction,\n pruning: config.agents?.defaults?.pruning,\n memory: config.agents?.defaults?.memory,\n sessionSearch: config.agents?.defaults?.sessionSearch,\n backgroundReview: config.agents?.defaults?.backgroundReview,\n webExtract: config.agents?.defaults?.webExtract,\n delegate: config.agents?.defaults?.delegate,\n executeCode: config.agents?.defaults?.executeCode,\n systemPromptOverride: config.agents?.defaults?.systemPromptOverride,\n skills: config.agents?.defaults?.skills,\n tools: config.agents?.defaults?.tools,\n models: config.agents?.defaults?.models,\n params: config.agents?.defaults?.params,\n },\n },\n channels: channelsPayload,\n providers: Object.fromEntries(\n await Promise.all(\n getAllProviders().map(async (provider) => [\n provider,\n await maskLlmProviderApiKeyForWeb(provider),\n ]),\n ),\n ),\n /** Masked `cfg.providers` for capability keys (image / STT / etc.). */\n providersConfig: buildSafeProvidersConfigForWeb(config.providers),\n gateway: {\n bind: config.gateway?.bind ?? 'loopback',\n customBindHost: config.gateway?.customBindHost,\n port: config.gateway?.port,\n corsOrigins: Array.isArray(config.gateway?.corsOrigins) ? config.gateway.corsOrigins : [],\n trustedProxies: Array.isArray(config.gateway?.trustedProxies)\n ? config.gateway.trustedProxies\n : [],\n allowRealIpFallback: config.gateway?.allowRealIpFallback === true,\n dangerouslyAllowHostHeaderOriginFallback:\n config.gateway?.dangerouslyAllowHostHeaderOriginFallback === true,\n security: {\n strict: config.gateway?.security?.strict === true,\n },\n auth: {\n mode: config.gateway?.auth?.mode || 'token',\n token: config.gateway?.auth?.token ? maskSecretLength(config.gateway.auth.token) : '',\n password: config.gateway?.auth?.password\n ? maskSecretLength(config.gateway.auth.password)\n : '',\n trustedProxy: config.gateway?.auth?.trustedProxy\n ? {\n userHeader: config.gateway.auth.trustedProxy.userHeader,\n requiredHeaders: config.gateway.auth.trustedProxy.requiredHeaders ?? [],\n allowUsers: config.gateway.auth.trustedProxy.allowUsers ?? [],\n allowLoopback: config.gateway.auth.trustedProxy.allowLoopback === true,\n }\n : undefined,\n rateLimit: {\n enabled: config.gateway?.auth?.rateLimit?.enabled !== false,\n maxAttempts:\n typeof config.gateway?.auth?.rateLimit?.maxAttempts === 'number'\n ? config.gateway.auth.rateLimit.maxAttempts\n : 5,\n windowMs:\n typeof config.gateway?.auth?.rateLimit?.windowMs === 'number'\n ? config.gateway.auth.rateLimit.windowMs\n : 900_000,\n blockDurationMs:\n typeof config.gateway?.auth?.rateLimit?.blockDurationMs === 'number'\n ? config.gateway.auth.rateLimit.blockDurationMs\n : typeof config.gateway?.auth?.rateLimit?.lockoutMs === 'number'\n ? config.gateway.auth.rateLimit.lockoutMs\n : 300_000,\n exemptLoopback: config.gateway?.auth?.rateLimit?.exemptLoopback !== false,\n },\n },\n heartbeat: {\n enabled: config.gateway?.heartbeat?.enabled,\n intervalMs: config.gateway?.heartbeat?.intervalMs,\n includeSystemPromptSection: config.gateway?.heartbeat?.includeSystemPromptSection === true,\n target: config.gateway?.heartbeat?.target,\n targetChatId: config.gateway?.heartbeat?.targetChatId,\n prompt: config.gateway?.heartbeat?.prompt,\n ackMaxChars: config.gateway?.heartbeat?.ackMaxChars,\n isolatedSession: config.gateway?.heartbeat?.isolatedSession,\n activeHours: config.gateway?.heartbeat?.activeHours,\n },\n maxSseConnections:\n typeof config.gateway?.maxSseConnections === 'number'\n ? config.gateway.maxSseConnections\n : 100,\n channelConnectDeferMode: config.gateway?.channelConnectDeferMode ?? 'auto',\n channelConnectDeferIds: Array.isArray(config.gateway?.channelConnectDeferIds)\n ? config.gateway.channelConnectDeferIds\n : [],\n channelConnectDeferSkipIds: Array.isArray(config.gateway?.channelConnectDeferSkipIds)\n ? config.gateway.channelConnectDeferSkipIds\n : [],\n share: resolveShareConfig(config.gateway?.share),\n publicUrl: config.gateway?.publicUrl ?? null,\n skillsMarketplaceProvider: config.gateway?.skillsMarketplaceProvider ?? 'skillhub',\n skillsStoreBaseUrl: config.gateway?.skillsStoreBaseUrl ?? 'https://store.xopc.ai',\n },\n cron: resolveCronConfigForWeb(config),\n goals: resolveGoalsConfigForWeb(config),\n session: resolveSessionConfigForWeb(config),\n tunnel: {\n enabled: config.tunnel?.enabled === true,\n autoStart: config.tunnel?.autoStart === true,\n brokerUrl: config.tunnel?.brokerUrl ?? 'https://frp.xopc.ai/api',\n registrationSecret: config.tunnel?.registrationSecret\n ? maskTunnelSecretForWeb(config.tunnel.registrationSecret)\n : '',\n consent: config.tunnel?.consent\n ? {\n version: config.tunnel.consent.version,\n acceptedAt: config.tunnel.consent.acceptedAt,\n }\n : undefined,\n transport: { tls: 'broker_terminated' as const },\n },\n update: {\n ...resolveUpdateConfigForWeb(config),\n },\n stt: maskSttConfigForWeb(config.tools?.media?.audio),\n tts: maskTtsConfigForWeb(config.messages?.tts),\n tools: safeToolsWebForGet(config),\n bindings: Array.isArray(config.bindings) ? config.bindings : [],\n mcp: buildSafeMcpConfigForWeb(config),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { init_write_file_atomic, writeTextAtomic } from "../../../infra/write-file-atomic.js";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
2
|
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
5
|
//#region src/gateway/hono/lib/extension-store.ts
|
|
6
6
|
init_write_file_atomic();
|
|
7
7
|
/** Extension UI: write-through JSON KV per namespace under ~/.xopc/extensions/{namespace}/storage.json */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
3
1
|
import { dirname, resolve } from "node:path";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
//#region src/gateway/hono/lib/static-ui.ts
|
|
6
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -12,3 +12,7 @@ export declare function createStrictRateLimitMiddleware(deps: StrictRateLimitDep
|
|
|
12
12
|
error: string;
|
|
13
13
|
code: string;
|
|
14
14
|
}, 429, "json">>;
|
|
15
|
+
export declare function createChannelRateLimitMiddleware(deps: StrictRateLimitDeps): import("hono/dist/types/types.js").MiddlewareHandler<any, string, {}, Response & import("hono/dist/types/types.js").TypedResponse<{
|
|
16
|
+
error: string;
|
|
17
|
+
code: string;
|
|
18
|
+
}, 429, "json">>;
|
|
@@ -31,9 +31,9 @@ function resolveClientIp(c, deps) {
|
|
|
31
31
|
}
|
|
32
32
|
return getClientIpFromHeaders({ get: (name) => c.req.header(name) ?? void 0 });
|
|
33
33
|
}
|
|
34
|
-
function
|
|
34
|
+
function createClientRateLimitMiddleware(deps, options) {
|
|
35
35
|
return createMiddleware(async (c, next) => {
|
|
36
|
-
const limiter =
|
|
36
|
+
const limiter = options.limiter();
|
|
37
37
|
const clientIp = resolveClientIp(c, deps);
|
|
38
38
|
const result = limiter.consume(clientIp);
|
|
39
39
|
if (!result.allowed) {
|
|
@@ -43,8 +43,8 @@ function createStrictRateLimitMiddleware(deps) {
|
|
|
43
43
|
path: c.req.path,
|
|
44
44
|
method: c.req.method,
|
|
45
45
|
retryAfterSec,
|
|
46
|
-
reason:
|
|
47
|
-
},
|
|
46
|
+
reason: options.reason
|
|
47
|
+
}, options.exceededMessage);
|
|
48
48
|
c.header("Retry-After", String(retryAfterSec));
|
|
49
49
|
c.header("X-RateLimit-Remaining", "0");
|
|
50
50
|
return c.json({
|
|
@@ -56,7 +56,21 @@ function createStrictRateLimitMiddleware(deps) {
|
|
|
56
56
|
await next();
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
|
+
function createStrictRateLimitMiddleware(deps) {
|
|
60
|
+
return createClientRateLimitMiddleware(deps, {
|
|
61
|
+
limiter: () => buckets.strictApi(),
|
|
62
|
+
exceededMessage: "Strict API rate limit exceeded",
|
|
63
|
+
reason: "strict_rate_limit_exceeded"
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function createChannelRateLimitMiddleware(deps) {
|
|
67
|
+
return createClientRateLimitMiddleware(deps, {
|
|
68
|
+
limiter: () => buckets.channelApi(),
|
|
69
|
+
exceededMessage: "Channel API rate limit exceeded",
|
|
70
|
+
reason: "channel_rate_limit_exceeded"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
59
73
|
//#endregion
|
|
60
|
-
export { createStrictRateLimitMiddleware };
|
|
74
|
+
export { createChannelRateLimitMiddleware, createStrictRateLimitMiddleware };
|
|
61
75
|
|
|
62
76
|
//# sourceMappingURL=strict-rate-limit.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"strict-rate-limit.js","names":[],"sources":["../../../../../src/gateway/hono/middleware/strict-rate-limit.ts"],"sourcesContent":["/**\n * Per-client request-rate gate for sensitive admin/mutation endpoints.\n * Backed by `buckets.strictApi()` — see {@link ../../rate-limit/buckets.ts}.\n */\n\nimport { createMiddleware } from 'hono/factory';\nimport type { Context } from 'hono';\nimport { getConnInfo } from '@hono/node-server/conninfo';\n\nimport { buckets } from '../../rate-limit/index.js';\nimport { getClientIpFromHeaders } from '../../security/loopback.js';\nimport { resolveClientIpFromRequest } from '../../client-ip.js';\nimport { createLogger } from '../../../utils/logger.js';\n\nconst log = createLogger('Hono:StrictRateLimit');\n\nexport type StrictRateLimitDeps = {\n getTrustedProxyContext: () => {\n trustedProxies?: string[];\n allowRealIpFallback?: boolean;\n };\n};\n\nfunction resolveClientIp(c: Context, deps: StrictRateLimitDeps): string {\n const { trustedProxies, allowRealIpFallback } = deps.getTrustedProxyContext();\n if (trustedProxies?.length) {\n let remoteAddress: string | undefined;\n try {\n remoteAddress = getConnInfo(c).remote.address;\n } catch {\n remoteAddress = undefined;\n }\n return resolveClientIpFromRequest({\n remoteAddress,\n getHeader: (name) => c.req.header(name),\n trustedProxies,\n allowRealIpFallback,\n });\n }\n return getClientIpFromHeaders({ get: (name) => c.req.header(name) ?? undefined });\n}\n\
|
|
1
|
+
{"version":3,"file":"strict-rate-limit.js","names":[],"sources":["../../../../../src/gateway/hono/middleware/strict-rate-limit.ts"],"sourcesContent":["/**\n * Per-client request-rate gate for sensitive admin/mutation endpoints.\n * Backed by `buckets.strictApi()` — see {@link ../../rate-limit/buckets.ts}.\n */\n\nimport { createMiddleware } from 'hono/factory';\nimport type { Context } from 'hono';\nimport { getConnInfo } from '@hono/node-server/conninfo';\n\nimport { buckets } from '../../rate-limit/index.js';\nimport { getClientIpFromHeaders } from '../../security/loopback.js';\nimport { resolveClientIpFromRequest } from '../../client-ip.js';\nimport { createLogger } from '../../../utils/logger.js';\n\nconst log = createLogger('Hono:StrictRateLimit');\n\nexport type StrictRateLimitDeps = {\n getTrustedProxyContext: () => {\n trustedProxies?: string[];\n allowRealIpFallback?: boolean;\n };\n};\n\nfunction resolveClientIp(c: Context, deps: StrictRateLimitDeps): string {\n const { trustedProxies, allowRealIpFallback } = deps.getTrustedProxyContext();\n if (trustedProxies?.length) {\n let remoteAddress: string | undefined;\n try {\n remoteAddress = getConnInfo(c).remote.address;\n } catch {\n remoteAddress = undefined;\n }\n return resolveClientIpFromRequest({\n remoteAddress,\n getHeader: (name) => c.req.header(name),\n trustedProxies,\n allowRealIpFallback,\n });\n }\n return getClientIpFromHeaders({ get: (name) => c.req.header(name) ?? undefined });\n}\n\nfunction createClientRateLimitMiddleware(\n deps: StrictRateLimitDeps,\n options: {\n limiter: () => ReturnType<typeof buckets.strictApi>;\n exceededMessage: string;\n reason: string;\n },\n) {\n return createMiddleware(async (c, next) => {\n const limiter = options.limiter();\n const clientIp = resolveClientIp(c, deps);\n const result = limiter.consume(clientIp);\n\n if (!result.allowed) {\n const retryAfterSec = Math.ceil(result.retryAfterMs / 1000);\n log.warn(\n {\n clientIp,\n path: c.req.path,\n method: c.req.method,\n retryAfterSec,\n reason: options.reason,\n },\n options.exceededMessage,\n );\n c.header('Retry-After', String(retryAfterSec));\n c.header('X-RateLimit-Remaining', '0');\n return c.json({ error: 'Too many requests', code: 'rate_limited' }, 429);\n }\n\n c.header('X-RateLimit-Remaining', String(result.remaining));\n await next();\n });\n}\n\nexport function createStrictRateLimitMiddleware(deps: StrictRateLimitDeps) {\n return createClientRateLimitMiddleware(deps, {\n limiter: () => buckets.strictApi(),\n exceededMessage: 'Strict API rate limit exceeded',\n reason: 'strict_rate_limit_exceeded',\n });\n}\n\nexport function createChannelRateLimitMiddleware(deps: StrictRateLimitDeps) {\n return createClientRateLimitMiddleware(deps, {\n limiter: () => buckets.channelApi(),\n exceededMessage: 'Channel API rate limit exceeded',\n reason: 'channel_rate_limit_exceeded',\n });\n}\n"],"mappings":";;;;;;;;;;;;;aAYwD;AAExD,MAAM,MAAM,aAAa,uBAAuB;AAShD,SAAS,gBAAgB,GAAY,MAAmC;CACtE,MAAM,EAAE,gBAAgB,wBAAwB,KAAK,wBAAwB;AAC7E,KAAI,gBAAgB,QAAQ;EAC1B,IAAI;AACJ,MAAI;AACF,mBAAgB,YAAY,EAAE,CAAC,OAAO;UAChC;AACN,mBAAgB,KAAA;;AAElB,SAAO,2BAA2B;GAChC;GACA,YAAY,SAAS,EAAE,IAAI,OAAO,KAAK;GACvC;GACA;GACD,CAAC;;AAEJ,QAAO,uBAAuB,EAAE,MAAM,SAAS,EAAE,IAAI,OAAO,KAAK,IAAI,KAAA,GAAW,CAAC;;AAGnF,SAAS,gCACP,MACA,SAKA;AACA,QAAO,iBAAiB,OAAO,GAAG,SAAS;EACzC,MAAM,UAAU,QAAQ,SAAS;EACjC,MAAM,WAAW,gBAAgB,GAAG,KAAK;EACzC,MAAM,SAAS,QAAQ,QAAQ,SAAS;AAExC,MAAI,CAAC,OAAO,SAAS;GACnB,MAAM,gBAAgB,KAAK,KAAK,OAAO,eAAe,IAAK;AAC3D,OAAI,KACF;IACE;IACA,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,IAAI;IACd;IACA,QAAQ,QAAQ;IACjB,EACD,QAAQ,gBACT;AACD,KAAE,OAAO,eAAe,OAAO,cAAc,CAAC;AAC9C,KAAE,OAAO,yBAAyB,IAAI;AACtC,UAAO,EAAE,KAAK;IAAE,OAAO;IAAqB,MAAM;IAAgB,EAAE,IAAI;;AAG1E,IAAE,OAAO,yBAAyB,OAAO,OAAO,UAAU,CAAC;AAC3D,QAAM,MAAM;GACZ;;AAGJ,SAAgB,gCAAgC,MAA2B;AACzE,QAAO,gCAAgC,MAAM;EAC3C,eAAe,QAAQ,WAAW;EAClC,iBAAiB;EACjB,QAAQ;EACT,CAAC;;AAGJ,SAAgB,iCAAiC,MAA2B;AAC1E,QAAO,gCAAgC,MAAM;EAC3C,eAAe,QAAQ,YAAY;EACnC,iBAAiB;EACjB,QAAQ;EACT,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
|
|
4
|
-
import { anthropicOAuthProvider } from "../../auth/oauth/anthropic.js";
|
|
5
4
|
import { isLoopbackHost } from "../host.js";
|
|
6
5
|
import { resolveReverseProxyPublicUrl } from "../public-url.js";
|
|
6
|
+
import { anthropicOAuthProvider } from "../../auth/oauth/anthropic.js";
|
|
7
7
|
import { minimaxOAuthProvider } from "../../auth/oauth/minimax.js";
|
|
8
8
|
import { minimaxCnOAuthProvider } from "../../auth/oauth/minimax-cn.js";
|
|
9
9
|
import { kimiCodingOAuthProvider } from "../../auth/oauth/kimi-coding.js";
|
|
@@ -31,24 +31,24 @@ function registerAgentStreamRoutes(authenticated, deps) {
|
|
|
31
31
|
message: "Invalid JSON body"
|
|
32
32
|
}
|
|
33
33
|
}, 400);
|
|
34
|
-
const
|
|
34
|
+
const sessionKey = typeof body.sessionKey === "string" ? body.sessionKey.trim() : "";
|
|
35
35
|
const message = typeof body.message === "string" ? body.message : "";
|
|
36
|
-
if (!
|
|
36
|
+
if (!sessionKey) return c.json({
|
|
37
37
|
ok: false,
|
|
38
38
|
error: {
|
|
39
39
|
code: "BAD_REQUEST",
|
|
40
|
-
message: "Missing
|
|
40
|
+
message: "Missing sessionKey"
|
|
41
41
|
}
|
|
42
42
|
}, 400);
|
|
43
|
-
const result = await service.steerWebchatAgent(
|
|
43
|
+
const result = await service.steerWebchatAgent(sessionKey, message);
|
|
44
44
|
if (result.ok === false) {
|
|
45
45
|
logRouteWarn(log, c, `Agent steer failed: ${result.code}`, "gateway.route.agent", {
|
|
46
|
-
|
|
46
|
+
sessionKey,
|
|
47
47
|
code: result.code
|
|
48
48
|
});
|
|
49
49
|
const code = result.code;
|
|
50
50
|
const status = code === "BAD_REQUEST" ? 400 : code === "NO_ACTIVE_RUN" ? 409 : 500;
|
|
51
|
-
const msg = code === "NO_ACTIVE_RUN" ? "No active agent run for this
|
|
51
|
+
const msg = code === "NO_ACTIVE_RUN" ? "No active agent run for this session" : code === "STEER_FAILED" ? "Steer failed" : "Message required";
|
|
52
52
|
return c.json({
|
|
53
53
|
ok: false,
|
|
54
54
|
error: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-stream.js","names":[],"sources":["../../../../../src/gateway/hono/routes/agent-stream.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n createAgentResumeHandler,\n createAgentSSEHandler,\n createEventsSSEHandler,\n createSendHandler,\n} from '../sse.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteWarn } from '../lib/route-logger.js';\n\nconst log = createGatewayRouteLogger('AgentStream');\n\nexport function registerAgentStreamRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware, sseConfig } = deps;\n\n authenticated.post('/api/agent', strictRateLimitMiddleware, createAgentSSEHandler(sseConfig));\n\n authenticated.post('/api/agent/resume', strictRateLimitMiddleware, createAgentResumeHandler(sseConfig));\n\n authenticated.post('/api/agent/abort', strictRateLimitMiddleware, async (c) => {\n const body = await c.req.json().catch(() => null);\n const runId =\n body && typeof body === 'object' && typeof (body as { runId?: unknown }).runId === 'string'\n ? (body as { runId: string }).runId.trim()\n : '';\n if (!runId) {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Missing runId' } },\n 400,\n );\n }\n const aborted = service.abortAgentRun(runId);\n return c.json({ ok: true, payload: { aborted } });\n });\n\n authenticated.post('/api/agent/steer', strictRateLimitMiddleware, async (c) => {\n const body = await c.req.json().catch(() => null);\n if (!body || typeof body !== 'object') {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } },\n 400,\n );\n }\n const
|
|
1
|
+
{"version":3,"file":"agent-stream.js","names":[],"sources":["../../../../../src/gateway/hono/routes/agent-stream.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n createAgentResumeHandler,\n createAgentSSEHandler,\n createEventsSSEHandler,\n createSendHandler,\n} from '../sse.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { createGatewayRouteLogger, logRouteWarn } from '../lib/route-logger.js';\n\nconst log = createGatewayRouteLogger('AgentStream');\n\nexport function registerAgentStreamRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware, sseConfig } = deps;\n\n authenticated.post('/api/agent', strictRateLimitMiddleware, createAgentSSEHandler(sseConfig));\n\n authenticated.post('/api/agent/resume', strictRateLimitMiddleware, createAgentResumeHandler(sseConfig));\n\n authenticated.post('/api/agent/abort', strictRateLimitMiddleware, async (c) => {\n const body = await c.req.json().catch(() => null);\n const runId =\n body && typeof body === 'object' && typeof (body as { runId?: unknown }).runId === 'string'\n ? (body as { runId: string }).runId.trim()\n : '';\n if (!runId) {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Missing runId' } },\n 400,\n );\n }\n const aborted = service.abortAgentRun(runId);\n return c.json({ ok: true, payload: { aborted } });\n });\n\n authenticated.post('/api/agent/steer', strictRateLimitMiddleware, async (c) => {\n const body = await c.req.json().catch(() => null);\n if (!body || typeof body !== 'object') {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Invalid JSON body' } },\n 400,\n );\n }\n const sessionKey =\n typeof (body as { sessionKey?: unknown }).sessionKey === 'string'\n ? (body as { sessionKey: string }).sessionKey.trim()\n : '';\n const message =\n typeof (body as { message?: unknown }).message === 'string'\n ? (body as { message: string }).message\n : '';\n if (!sessionKey) {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Missing sessionKey' } },\n 400,\n );\n }\n const result = await service.steerWebchatAgent(sessionKey, message);\n if (result.ok === false) {\n logRouteWarn(log, c, `Agent steer failed: ${result.code}`, 'gateway.route.agent', { sessionKey, code: result.code });\n const code = result.code;\n const status = code === 'BAD_REQUEST' ? 400 : code === 'NO_ACTIVE_RUN' ? 409 : 500;\n const msg =\n code === 'NO_ACTIVE_RUN'\n ? 'No active agent run for this session'\n : code === 'STEER_FAILED'\n ? 'Steer failed'\n : 'Message required';\n return c.json({ ok: false, error: { code, message: msg } }, status);\n }\n return c.json({ ok: true, payload: { steered: true } });\n });\n\n authenticated.post('/api/clarify/:requestId', strictRateLimitMiddleware, async (c) => {\n const requestId = c.req.param('requestId')?.trim() ?? '';\n if (!requestId) {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Missing requestId' } },\n 400,\n );\n }\n const body = await c.req.json().catch(() => null);\n const skip =\n body &&\n typeof body === 'object' &&\n (body as { skip?: unknown }).skip === true;\n const rawAnswer =\n body && typeof body === 'object' && typeof (body as { answer?: unknown }).answer === 'string'\n ? (body as { answer: string }).answer\n : '';\n const answer = typeof rawAnswer === 'string' ? rawAnswer.trim() : '';\n if (!skip && !answer) {\n return c.json(\n { ok: false, error: { code: 'BAD_REQUEST', message: 'Missing answer field' } },\n 400,\n );\n }\n const handled = service.submitClarifyResponse(requestId, skip ? '' : answer);\n if (!handled) {\n return c.json(\n { ok: false, error: { code: 'NOT_FOUND', message: 'No pending clarification with this ID' } },\n 404,\n );\n }\n return c.json({ ok: true, payload: { received: true } });\n });\n\n authenticated.post('/api/send', strictRateLimitMiddleware, createSendHandler(sseConfig));\n\n authenticated.get('/api/events', createEventsSSEHandler(sseConfig));\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { init_agent_scope, normalizeAgentId } from "../../../agent/agent-scope.js";
|
|
2
1
|
import { AgentModelsSchema, init_schema, parseModelRef } from "../../../config/schema.js";
|
|
2
|
+
import { init_agent_scope, normalizeAgentId } from "../../../agent/agent-scope.js";
|
|
3
3
|
import { init_providers, isProviderConfigured, resolveModel } from "../../../providers/index.js";
|
|
4
4
|
import { getVoiceModelsConfig } from "../../../config/voice.js";
|
|
5
5
|
import { deleteAgentAvatarFile, finalizeCreateAgentDirs, listAgentProfileFiles, listGatewayAgents, prepareCreateAgent, prepareDeleteAgent, prepareUpdateAgent, readAgentAvatarFile, readAgentProfileFile, runAfterDeletePurge, writeAgentAvatarFromBase64, writeAgentProfileFile } from "../../agents-admin.js";
|