@xopcai/xopc 0.0.118 → 0.0.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/README.zh-CN.md +2 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dzUrQoeZ.js → agent-avatar-dicebear-CU8J6zou.js} +1 -1
- package/dist/gateway/static/root/assets/agents-B0hkpLhP.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-B9vfYoEr.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-ClOzIO24.js +1 -0
- package/dist/gateway/static/root/assets/{apps-page--wMEL00f.js → apps-page-DU0dz9Zo.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-Cki4SfU2.js → archive-plugin-BkVIgZzA.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-D-KnS2Do.js → attachment-load-CaCMWh1D.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-DhGDpKP3.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-CTedroVo.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-D2sgvJja.js → binary-plugins-B4TO_bsn.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DIq-4Gvb.js → block-editor-DJRWwWNI.js} +28 -28
- package/dist/gateway/static/root/assets/browser-settings-page-FCDwOOBK.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-Befi89CL.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-_G8eb2vJ.js +1 -0
- package/dist/gateway/static/root/assets/channel-recipient-api-BNSuJb5f.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-C3d5JBJX.js +1 -0
- package/dist/gateway/static/root/assets/cn-BQ_8x0bT.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-yaUNvt5u.js +2 -0
- package/dist/gateway/static/root/assets/cron-expression-B3B1eqnr.js +2 -0
- package/dist/gateway/static/root/assets/dreaming-settings-DNrdg1Ve.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-DYu1KaFQ.js → extension-debug-page-DYh402XV.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-B3W6QwlZ.js → extension-page-Cr_TizrN.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-D7VQ-cxE.js → extension-settings-page-BU1KoKRj.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B7xDPu-R.js → fetch-Y7AEX4H3.js} +1 -1
- package/dist/gateway/static/root/assets/format-cron-label-arqgGlVV.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-BTBLSeUu.js → gateway-config-api-RbMmAOpX.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-C79wkXef.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CYj9FWCp.js → gateway-startup-retry-DiD_Tx4N.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-9paXuHdo.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CQQgzPr3.js → goals-config-api-DqxVi0p5.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BHitvJAv.js → goals-page-CS0R-Af2.js} +2 -2
- package/dist/gateway/static/root/assets/goals-settings-CSuzZ8Ae.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-DXPaYJm3.js +1 -0
- package/dist/gateway/static/root/assets/index-BoKafJIZ.js +191 -0
- package/dist/gateway/static/root/assets/index-CArhCcYn.css +1 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-Dvg53qnd.js +1 -0
- package/dist/gateway/static/root/assets/{logs-page-C2Uqvae9.js → logs-page-DLXPcksQ.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-BwOFrJ2E.js → markdown-split-CpHxbtWJ.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Cnz6Q5G6.js → media-plugins-SFPQRSxq.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CrDHEbss.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BDF2iyRk.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-CSb_hwig.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-B-Svpmza.js → note-image-lightbox-BUYURRgn.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-BsIBSFyZ.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Bss4TiwP.js → preview-open-alternatives-BHz9iWYA.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CwzSovcS.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BRNjdgKq.js → save-bar-controls-CefkOlRg.js} +1 -1
- package/dist/gateway/static/root/assets/schedule-field-CmTRoOcE.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-Dub9sy8r.js → schema-form-FMKv1vGu.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-PHmX-NmA.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BRAeKJN4.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BeFLavGi.js → settings-collapsible-section-BouO6JTi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-dmyaPOTG.js → settings-form-section-D-4lBl6X.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-KKrbFjy8.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-layout-BJ4Gsef5.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-CrUjHPQo.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-C8glrdqe.js → share-preview-page-BDy2btRN.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-B18OBmH5.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-C28-2uKQ.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Bm2ebkwl.js +2 -0
- package/dist/gateway/static/root/assets/system-settings-panel-CRngrlnZ.js +1 -0
- package/dist/gateway/static/root/assets/typed-models-lib-BltBc0b-.js +1 -0
- package/dist/gateway/static/root/assets/{use-channel-catalog-DqlWTsDb.js → use-channel-catalog-CjN-51e6.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-DJ1dKwZy.js +1 -0
- package/dist/gateway/static/root/assets/utils-B5M5-YvK.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-C73IVZeC.js → voice-api-key-field-CeEevm7z.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-player-store-C_ArLJPM.js → voice-player-store-B7ykUlHM.js} +1 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-C4PzUQjB.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-BL84_-Ky.js +18 -0
- package/dist/gateway/static/root/index.html +6 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +4 -5
- package/dist/src/agent/agent-manager.js +4 -8
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.js +102 -14
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/fallback/candidates.d.ts +0 -8
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/index.js +1 -1
- package/dist/src/agent/lifecycle/handlers/compaction.d.ts +1 -3
- package/dist/src/agent/lifecycle/handlers/compaction.js +1 -16
- package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
- package/dist/src/agent/lifecycle/progress.d.ts +0 -1
- package/dist/src/agent/lifecycle/progress.js +1 -6
- package/dist/src/agent/lifecycle/progress.js.map +1 -1
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +1 -2
- package/dist/src/agent/lifecycle/timeout-wrapper.js +1 -7
- package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
- package/dist/src/agent/middleware/self-verify.d.ts +0 -1
- package/dist/src/agent/middleware/self-verify.js +0 -2
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/models/index.d.ts +1 -1
- package/dist/src/agent/models/manager.d.ts +4 -20
- package/dist/src/agent/models/manager.js +9 -126
- package/dist/src/agent/models/manager.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -9
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +2 -2
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.d.ts +0 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +0 -12
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/subagent-context.js +1 -1
- package/dist/src/agent/prompt/subagent-context.js.map +1 -1
- package/dist/src/agent/prompt/types.d.ts +1 -1
- package/dist/src/agent/service.d.ts +1 -9
- package/dist/src/agent/service.js +3 -40
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +2 -2
- package/dist/src/agent/session/session-config-service.d.ts +11 -11
- package/dist/src/agent/session/session-config-service.js +14 -14
- package/dist/src/agent/session/session-config-service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +3 -2
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/starter-agents.js +12 -12
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/automation-tool.d.ts +14 -0
- package/dist/src/agent/tools/automation-tool.js +102 -0
- package/dist/src/agent/tools/automation-tool.js.map +1 -0
- package/dist/src/agent/tools/delegate-tool.js +1 -1
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -3
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -1
- package/dist/src/agent/tools/index.js +2 -2
- package/dist/src/agent-manifest/resolver.d.ts +1 -0
- package/dist/src/agent-manifest/resolver.js +1 -0
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +6 -0
- package/dist/src/agent-manifest/schema.js +12 -3
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +1 -1
- package/dist/src/ai-assist/text-assist.js +56 -0
- package/dist/src/ai-assist/text-assist.js.map +1 -1
- package/dist/src/auth/profiles/store.js.map +1 -1
- package/dist/src/automations/api/routes.d.ts +3 -0
- package/dist/src/automations/api/routes.js +193 -0
- package/dist/src/automations/api/routes.js.map +1 -0
- package/dist/src/automations/domain/index.d.ts +3 -0
- package/dist/src/automations/domain/index.js +3 -0
- package/dist/src/automations/domain/schedule.d.ts +4 -0
- package/dist/src/automations/domain/schedule.js +37 -0
- package/dist/src/automations/domain/schedule.js.map +1 -0
- package/dist/src/automations/domain/types.d.ts +160 -0
- package/dist/src/automations/domain/validation.d.ts +370 -0
- package/dist/src/automations/domain/validation.js +149 -0
- package/dist/src/automations/domain/validation.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-prompt.d.ts +26 -0
- package/dist/src/automations/draft/automation-draft-prompt.js +127 -0
- package/dist/src/automations/draft/automation-draft-prompt.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-service.d.ts +12 -0
- package/dist/src/automations/draft/automation-draft-service.js +135 -0
- package/dist/src/automations/draft/automation-draft-service.js.map +1 -0
- package/dist/src/automations/draft/automation-draft-validator.d.ts +99 -0
- package/dist/src/automations/draft/automation-draft-validator.js +105 -0
- package/dist/src/automations/draft/automation-draft-validator.js.map +1 -0
- package/dist/src/automations/draft/automation-draft.types.d.ts +40 -0
- package/dist/src/automations/draft/index.d.ts +3 -0
- package/dist/src/automations/draft/index.js +3 -0
- package/dist/src/automations/index.d.ts +3 -0
- package/dist/src/automations/index.js +8 -0
- package/dist/src/automations/product-events.d.ts +5 -0
- package/dist/src/automations/product-events.js +21 -0
- package/dist/src/automations/product-events.js.map +1 -0
- package/dist/src/automations/service/action-executor.d.ts +9 -0
- package/dist/src/automations/service/action-executor.js +157 -0
- package/dist/src/automations/service/action-executor.js.map +1 -0
- package/dist/src/automations/service/automation-service.d.ts +54 -0
- package/dist/src/automations/service/automation-service.js +404 -0
- package/dist/src/automations/service/automation-service.js.map +1 -0
- package/dist/src/automations/service/index.d.ts +2 -0
- package/dist/src/automations/service/index.js +3 -0
- package/dist/src/automations/storage/automation-repository.d.ts +6 -0
- package/dist/src/automations/storage/automation-repository.js +61 -0
- package/dist/src/automations/storage/automation-repository.js.map +1 -0
- package/dist/src/automations/storage/automation-run-repository.d.ts +17 -0
- package/dist/src/automations/storage/automation-run-repository.js +130 -0
- package/dist/src/automations/storage/automation-run-repository.js.map +1 -0
- package/dist/src/automations/storage/index.d.ts +2 -0
- package/dist/src/automations/storage/index.js +3 -0
- package/dist/src/channels/plugin-types.d.ts +3 -0
- package/dist/src/chat-commands/builtins/thinking.js.map +1 -1
- package/dist/src/cli/command-catalog.js +0 -39
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +0 -1
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +0 -4
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/agents.js +7 -6
- package/dist/src/cli/commands/agents.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/{cron-health.d.ts → migrations.d.ts} +1 -1
- package/dist/src/cli/commands/doctor/checks/migrations.js +40 -0
- package/dist/src/cli/commands/doctor/checks/migrations.js.map +1 -0
- package/dist/src/cli/commands/doctor/flow.js +2 -2
- package/dist/src/cli/commands/doctor/flow.js.map +1 -1
- package/dist/src/cli/commands/gateway/call.js +2 -2
- package/dist/src/cli/commands/gateway/call.js.map +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/gateway/run-foreground.js +4 -2
- package/dist/src/cli/commands/gateway/run-foreground.js.map +1 -1
- package/dist/src/cli/commands/init.js +26 -8
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/tui.js +24 -2
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -0
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/commands/agents.config.d.ts +9 -0
- package/dist/src/commands/agents.config.js +40 -2
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +4 -3
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/config-surface.d.ts +3 -0
- package/dist/src/config/index.d.ts +0 -1
- package/dist/src/config/index.js +3 -3
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/paths.d.ts +0 -9
- package/dist/src/config/paths.js +1 -14
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +0 -1
- package/dist/src/config/profile.js.map +1 -1
- package/dist/src/config/rules.js +0 -5
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +13 -12
- package/dist/src/config/schema.js +22 -26
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/web-patch.d.ts +0 -12
- package/dist/src/config/web-patch.js +2 -29
- package/dist/src/config/web-patch.js.map +1 -1
- package/dist/src/extensions/api.d.ts +2 -0
- package/dist/src/extensions/api.js +10 -0
- package/dist/src/extensions/api.js.map +1 -1
- package/dist/src/extensions/extension-registry-impl.d.ts +4 -1
- package/dist/src/extensions/extension-registry-impl.js +8 -0
- package/dist/src/extensions/extension-registry-impl.js.map +1 -1
- package/dist/src/extensions/loader.d.ts +3 -3
- package/dist/src/extensions/loader.js +3 -3
- package/dist/src/extensions/loader.js.map +1 -1
- package/dist/src/extensions/sdk/testing.d.ts +2 -0
- package/dist/src/extensions/sdk/testing.js +7 -0
- package/dist/src/extensions/sdk/testing.js.map +1 -1
- package/dist/src/extensions/types/core.d.ts +10 -1
- package/dist/src/extensions/types/index.d.ts +1 -1
- package/dist/src/extensions/types/{phase4.d.ts → registration.d.ts} +2 -2
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +1 -1
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +1 -0
- package/dist/src/gateway/agents-admin.js +13 -15
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/capability-presets-admin.d.ts +1 -0
- package/dist/src/gateway/capability-presets-admin.js +19 -10
- package/dist/src/gateway/capability-presets-admin.js.map +1 -1
- package/dist/src/gateway/dreaming-automation-reconciler.d.ts +11 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +105 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -0
- package/dist/src/gateway/heartbeat/service.d.ts +0 -2
- package/dist/src/gateway/heartbeat/service.js +0 -7
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +5 -6
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.d.ts +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +12 -6
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +27 -37
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +2 -2
- package/dist/src/gateway/hono/routes/home.js +34 -25
- package/dist/src/gateway/hono/routes/home.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +10 -6
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/migrations.d.ts +3 -0
- package/dist/src/gateway/hono/routes/migrations.js +35 -0
- package/dist/src/gateway/hono/routes/migrations.js.map +1 -0
- package/dist/src/gateway/hono/routes/public-gateway.js +2 -1
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +14 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/run-loop.js +2 -0
- package/dist/src/gateway/run-loop.js.map +1 -1
- package/dist/src/gateway/security/operator-scopes.js +5 -1
- package/dist/src/gateway/security/operator-scopes.js.map +1 -1
- package/dist/src/gateway/service/config-coordinator.d.ts +4 -4
- package/dist/src/gateway/service/config-coordinator.js +14 -8
- package/dist/src/gateway/service/config-coordinator.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +2 -1
- package/dist/src/gateway/service/sessions-api.js +6 -1
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +7 -3
- package/dist/src/gateway/service.js +61 -27
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-service.js +45 -4
- package/dist/src/goals/goal-service.js.map +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/migrations/config/default-capability-preset.d.ts +10 -0
- package/dist/src/migrations/config/default-capability-preset.js +135 -0
- package/dist/src/migrations/config/default-capability-preset.js.map +1 -0
- package/dist/src/migrations/index.d.ts +4 -0
- package/dist/src/migrations/index.js +4 -0
- package/dist/src/migrations/registry.d.ts +8 -0
- package/dist/src/migrations/registry.js +18 -0
- package/dist/src/migrations/registry.js.map +1 -0
- package/dist/src/migrations/runner.d.ts +17 -0
- package/dist/src/migrations/runner.js +191 -0
- package/dist/src/migrations/runner.js.map +1 -0
- package/dist/src/migrations/types.d.ts +34 -0
- package/dist/src/notes/service.js +24 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/model-registry.d.ts +0 -1
- package/dist/src/providers/model-registry.js +0 -3
- package/dist/src/providers/model-registry.js.map +1 -1
- package/dist/src/routing/resolve-tui-session-key.d.ts +3 -0
- package/dist/src/routing/resolve-tui-session-key.js +14 -3
- package/dist/src/routing/resolve-tui-session-key.js.map +1 -1
- package/dist/src/session/transcript-outline.d.ts +47 -0
- package/dist/src/session/transcript-outline.js +481 -0
- package/dist/src/session/transcript-outline.js.map +1 -0
- package/dist/src/storage/sqlite/index.d.ts +0 -2
- package/dist/src/storage/sqlite/index.js +1 -3
- package/dist/src/storage/sqlite/migrations/016_automations.sql +47 -0
- package/dist/src/storage/sqlite/migrations/017_automation_run_events.sql +14 -0
- package/dist/src/storage/sqlite/migrations/018_automation_safety.sql +1 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +56 -46
- package/dist/src/tui/backends/embedded-backend.d.ts +6 -0
- package/dist/src/tui/backends/embedded-backend.js +18 -7
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +14 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +4 -0
- package/dist/src/tui/tui-commands.d.ts +5 -0
- package/dist/src/tui/tui-commands.js +43 -0
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-transcript-tree.d.ts +1 -1
- package/dist/src/tui/tui-transcript-tree.js +17 -257
- package/dist/src/tui/tui-transcript-tree.js.map +1 -1
- package/dist/src/tui/tui-types.d.ts +2 -0
- package/dist/src/tui/tui-types.js.map +1 -1
- package/dist/src/tui/tui.js +7 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/workflows/domain/index.js +1 -1
- package/dist/src/workflows/domain/run.d.ts +7 -7
- package/dist/src/workflows/domain/run.js.map +1 -1
- package/dist/src/workflows/index.js +2 -2
- package/dist/src/workflows/service/workflow-run-service.d.ts +2 -0
- package/dist/src/workflows/service/workflow-run-service.js +31 -9
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.types.d.ts +1 -1
- package/package.json +4 -2
- package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-bxYJVJpx.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-BCIykXlI.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-CorhiHlg.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +0 -1
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +0 -2
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-qGwmL-24.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-Dw89Obml.js +0 -1
- package/dist/gateway/static/root/assets/format-cron-label-BsotZDO5.js +0 -2
- package/dist/gateway/static/root/assets/format-interval-label-BzxafKxR.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-Cmwy58rS.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +0 -1
- package/dist/gateway/static/root/assets/goals-settings-CYVY4NGp.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-DriO_CN9.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +0 -1
- package/dist/gateway/static/root/assets/index-C17Tsd_b.css +0 -1
- package/dist/gateway/static/root/assets/index-Cc41r16l.js +0 -191
- package/dist/gateway/static/root/assets/interval-presets-DFPCKW_W.js +0 -1
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CcVcqstx.js +0 -1
- package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +0 -1
- package/dist/gateway/static/root/assets/schedule-field-CUCKODde.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-DI-LN_8G.js +0 -1
- package/dist/gateway/static/root/assets/typed-models-lib-kX9duch4.js +0 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +0 -1
- package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +0 -18
- package/dist/src/agent/fallback/error.d.ts +0 -22
- package/dist/src/agent/fallback/error.js +0 -32
- package/dist/src/agent/fallback/error.js.map +0 -1
- package/dist/src/agent/fallback/index.d.ts +0 -5
- package/dist/src/agent/fallback/index.js +0 -9
- package/dist/src/agent/fallback/index.js.map +0 -1
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.d.ts +0 -29
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js +0 -76
- package/dist/src/agent/orchestration/run-agent-turn-with-fallbacks.js.map +0 -1
- package/dist/src/agent/service/reconcile-dreaming-cron.d.ts +0 -6
- package/dist/src/agent/service/reconcile-dreaming-cron.js +0 -84
- package/dist/src/agent/service/reconcile-dreaming-cron.js.map +0 -1
- package/dist/src/agent/tools/cronjob-tool.d.ts +0 -29
- package/dist/src/agent/tools/cronjob-tool.js +0 -274
- package/dist/src/agent/tools/cronjob-tool.js.map +0 -1
- package/dist/src/cli/commands/cron-cli.d.ts +0 -2
- package/dist/src/cli/commands/cron-cli.js +0 -15
- package/dist/src/cli/commands/cron-cli.js.map +0 -1
- package/dist/src/cli/commands/cron.d.ts +0 -4
- package/dist/src/cli/commands/cron.js +0 -188
- package/dist/src/cli/commands/cron.js.map +0 -1
- package/dist/src/cli/commands/doctor/checks/cron-health.js +0 -35
- package/dist/src/cli/commands/doctor/checks/cron-health.js.map +0 -1
- package/dist/src/cron/execution-types.d.ts +0 -42
- package/dist/src/cron/executor.d.ts +0 -67
- package/dist/src/cron/executor.js +0 -669
- package/dist/src/cron/executor.js.map +0 -1
- package/dist/src/cron/index.d.ts +0 -7
- package/dist/src/cron/index.js +0 -7
- package/dist/src/cron/job-content.d.ts +0 -5
- package/dist/src/cron/job-content.js +0 -15
- package/dist/src/cron/job-content.js.map +0 -1
- package/dist/src/cron/run-log-store.d.ts +0 -12
- package/dist/src/cron/run-log-store.js +0 -58
- package/dist/src/cron/run-log-store.js.map +0 -1
- package/dist/src/cron/schedule.d.ts +0 -10
- package/dist/src/cron/schedule.js +0 -85
- package/dist/src/cron/schedule.js.map +0 -1
- package/dist/src/cron/service.d.ts +0 -58
- package/dist/src/cron/service.js +0 -419
- package/dist/src/cron/service.js.map +0 -1
- package/dist/src/cron/types.d.ts +0 -183
- package/dist/src/cron/validation.d.ts +0 -500
- package/dist/src/cron/validation.js +0 -192
- package/dist/src/cron/validation.js.map +0 -1
- package/dist/src/cron/workflow-run-completion.d.ts +0 -23
- package/dist/src/cron/workflow-run-completion.js +0 -72
- package/dist/src/cron/workflow-run-completion.js.map +0 -1
- package/dist/src/extensions/types/phase4.js +0 -1
- package/dist/src/gateway/hono/routes/cron.d.ts +0 -3
- package/dist/src/gateway/hono/routes/cron.js +0 -109
- package/dist/src/gateway/hono/routes/cron.js.map +0 -1
- package/dist/src/storage/sqlite/cron-job-repository.d.ts +0 -6
- package/dist/src/storage/sqlite/cron-job-repository.js +0 -70
- package/dist/src/storage/sqlite/cron-job-repository.js.map +0 -1
- package/dist/src/storage/sqlite/cron-run-repository.d.ts +0 -5
- package/dist/src/storage/sqlite/cron-run-repository.js +0 -96
- package/dist/src/storage/sqlite/cron-run-repository.js.map +0 -1
- /package/dist/src/{cron → automations/domain}/types.js +0 -0
- /package/dist/src/{config/defaults.d.ts → automations/draft/automation-draft.types.js} +0 -0
- /package/dist/src/{config/defaults.js → extensions/types/registration.js} +0 -0
- /package/dist/src/{cron/execution-types.js → migrations/types.js} +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { init_agent_scope, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
2
|
+
import { DREAMING_CRON_NAME, DREAMING_CRON_TAG, DREAMING_LIGHT_CRON_NAME, DREAMING_LIGHT_SWEEP_TOKEN, DREAMING_REM_CRON_NAME, DREAMING_REM_SWEEP_TOKEN, DREAMING_SWEEP_TOKEN } from "../agent/memory/dreaming/constants.js";
|
|
3
|
+
import { resolveDreamingConfig } from "../agent/memory/dreaming/config.js";
|
|
4
|
+
import { getWorkspacePath } from "../config/workspace-path-helpers.js";
|
|
5
|
+
//#region src/gateway/dreaming-automation-reconciler.ts
|
|
6
|
+
init_agent_scope();
|
|
7
|
+
const DREAMING_AUTOMATIONS = [
|
|
8
|
+
{
|
|
9
|
+
id: "system-dreaming-light",
|
|
10
|
+
phase: "light",
|
|
11
|
+
name: DREAMING_LIGHT_CRON_NAME,
|
|
12
|
+
token: DREAMING_LIGHT_SWEEP_TOKEN
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: "system-dreaming-deep",
|
|
16
|
+
phase: "deep",
|
|
17
|
+
name: DREAMING_CRON_NAME,
|
|
18
|
+
token: DREAMING_SWEEP_TOKEN
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: "system-dreaming-rem",
|
|
22
|
+
phase: "rem",
|
|
23
|
+
name: DREAMING_REM_CRON_NAME,
|
|
24
|
+
token: DREAMING_REM_SWEEP_TOKEN
|
|
25
|
+
}
|
|
26
|
+
];
|
|
27
|
+
function phaseDescription(phase) {
|
|
28
|
+
return `${phase === "light" ? "Light sweep" : phase === "deep" ? "Deep promotion" : "REM pattern discovery"} for memory dreaming. ${DREAMING_CRON_TAG}`;
|
|
29
|
+
}
|
|
30
|
+
function buildTrigger(config, phase) {
|
|
31
|
+
return {
|
|
32
|
+
kind: "schedule",
|
|
33
|
+
schedule: {
|
|
34
|
+
kind: "cron",
|
|
35
|
+
expr: config.phases[phase].cron,
|
|
36
|
+
...config.timezone ? { tz: config.timezone } : {}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function buildAction(config, agentId, token) {
|
|
41
|
+
const workspaceDir = getWorkspacePath(config);
|
|
42
|
+
return {
|
|
43
|
+
kind: "agent",
|
|
44
|
+
agentId,
|
|
45
|
+
instruction: token,
|
|
46
|
+
...workspaceDir ? { workingDirectory: workspaceDir } : {},
|
|
47
|
+
timeoutSeconds: 3600
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function automationNeedsUpdate(current, next) {
|
|
51
|
+
return current.name !== next.name || current.description !== next.description || current.enabled !== next.enabled || JSON.stringify(current.trigger) !== JSON.stringify(next.trigger) || JSON.stringify(current.action) !== JSON.stringify(next.action) || current.safety?.mode !== "auto_apply" || current.afterRun?.kind !== "none" || current.reliability?.disableAfterConsecutiveFailures !== 3;
|
|
52
|
+
}
|
|
53
|
+
async function reconcileDreamingAutomations(params) {
|
|
54
|
+
const { config, automationService } = params;
|
|
55
|
+
const resolved = resolveDreamingConfig(config);
|
|
56
|
+
const agentId = resolveDefaultAgentId(config);
|
|
57
|
+
const result = {
|
|
58
|
+
created: [],
|
|
59
|
+
updated: [],
|
|
60
|
+
disabled: []
|
|
61
|
+
};
|
|
62
|
+
for (const spec of DREAMING_AUTOMATIONS) {
|
|
63
|
+
const current = await automationService.get(spec.id);
|
|
64
|
+
const enabled = resolved.enabled && resolved.phases[spec.phase].enabled;
|
|
65
|
+
if (!resolved.enabled) {
|
|
66
|
+
if (current?.enabled) {
|
|
67
|
+
await automationService.update(spec.id, { enabled: false });
|
|
68
|
+
result.disabled.push(spec.id);
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const next = {
|
|
73
|
+
name: spec.name,
|
|
74
|
+
description: phaseDescription(spec.phase),
|
|
75
|
+
enabled,
|
|
76
|
+
trigger: buildTrigger(resolved, spec.phase),
|
|
77
|
+
action: buildAction(config, agentId, spec.token)
|
|
78
|
+
};
|
|
79
|
+
if (!current) {
|
|
80
|
+
await automationService.create({
|
|
81
|
+
id: spec.id,
|
|
82
|
+
...next,
|
|
83
|
+
safety: { mode: "auto_apply" },
|
|
84
|
+
afterRun: { kind: "none" },
|
|
85
|
+
reliability: { disableAfterConsecutiveFailures: 3 }
|
|
86
|
+
});
|
|
87
|
+
result.created.push(spec.id);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (automationNeedsUpdate(current, next)) {
|
|
91
|
+
await automationService.update(spec.id, {
|
|
92
|
+
...next,
|
|
93
|
+
safety: { mode: "auto_apply" },
|
|
94
|
+
afterRun: { kind: "none" },
|
|
95
|
+
reliability: { disableAfterConsecutiveFailures: 3 }
|
|
96
|
+
});
|
|
97
|
+
result.updated.push(spec.id);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
export { reconcileDreamingAutomations };
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=dreaming-automation-reconciler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dreaming-automation-reconciler.js","names":[],"sources":["../../../src/gateway/dreaming-automation-reconciler.ts"],"sourcesContent":["import type { Config } from '../config/schema.js';\nimport { getWorkspacePath } from '../config/workspace-path-helpers.js';\nimport { resolveDefaultAgentId } from '../agent/agent-scope.js';\nimport { resolveDreamingConfig, type DreamingResolvedConfig } from '../agent/memory/dreaming/config.js';\nimport {\n DREAMING_CRON_NAME,\n DREAMING_CRON_TAG,\n DREAMING_LIGHT_CRON_NAME,\n DREAMING_LIGHT_SWEEP_TOKEN,\n DREAMING_REM_CRON_NAME,\n DREAMING_REM_SWEEP_TOKEN,\n DREAMING_SWEEP_TOKEN,\n type DreamingPhaseId,\n} from '../agent/memory/dreaming/constants.js';\nimport type { AutomationService } from '../automations/index.js';\nimport type { Automation, AutomationAction, AutomationTrigger } from '../automations/domain/types.js';\n\ntype DreamingAutomationSpec = {\n id: string;\n phase: DreamingPhaseId;\n name: string;\n token: string;\n};\n\nconst DREAMING_AUTOMATIONS: readonly DreamingAutomationSpec[] = [\n {\n id: 'system-dreaming-light',\n phase: 'light',\n name: DREAMING_LIGHT_CRON_NAME,\n token: DREAMING_LIGHT_SWEEP_TOKEN,\n },\n {\n id: 'system-dreaming-deep',\n phase: 'deep',\n name: DREAMING_CRON_NAME,\n token: DREAMING_SWEEP_TOKEN,\n },\n {\n id: 'system-dreaming-rem',\n phase: 'rem',\n name: DREAMING_REM_CRON_NAME,\n token: DREAMING_REM_SWEEP_TOKEN,\n },\n];\n\nexport type DreamingAutomationReconcileResult = {\n created: string[];\n updated: string[];\n disabled: string[];\n};\n\nfunction phaseDescription(phase: DreamingPhaseId): string {\n const label = phase === 'light' ? 'Light sweep' : phase === 'deep' ? 'Deep promotion' : 'REM pattern discovery';\n return `${label} for memory dreaming. ${DREAMING_CRON_TAG}`;\n}\n\nfunction buildTrigger(config: DreamingResolvedConfig, phase: DreamingPhaseId): AutomationTrigger {\n const phaseConfig = config.phases[phase];\n return {\n kind: 'schedule',\n schedule: {\n kind: 'cron',\n expr: phaseConfig.cron,\n ...(config.timezone ? { tz: config.timezone } : {}),\n },\n };\n}\n\nfunction buildAction(config: Config, agentId: string, token: string): AutomationAction {\n const workspaceDir = getWorkspacePath(config);\n return {\n kind: 'agent',\n agentId,\n instruction: token,\n ...(workspaceDir ? { workingDirectory: workspaceDir } : {}),\n timeoutSeconds: 3600,\n };\n}\n\nfunction automationNeedsUpdate(current: Automation, next: {\n name: string;\n description: string;\n enabled: boolean;\n trigger: AutomationTrigger;\n action: AutomationAction;\n}): boolean {\n return (\n current.name !== next.name ||\n current.description !== next.description ||\n current.enabled !== next.enabled ||\n JSON.stringify(current.trigger) !== JSON.stringify(next.trigger) ||\n JSON.stringify(current.action) !== JSON.stringify(next.action) ||\n current.safety?.mode !== 'auto_apply' ||\n current.afterRun?.kind !== 'none' ||\n current.reliability?.disableAfterConsecutiveFailures !== 3\n );\n}\n\nexport async function reconcileDreamingAutomations(params: {\n config: Config;\n automationService: AutomationService;\n}): Promise<DreamingAutomationReconcileResult> {\n const { config, automationService } = params;\n const resolved = resolveDreamingConfig(config);\n const agentId = resolveDefaultAgentId(config);\n const result: DreamingAutomationReconcileResult = { created: [], updated: [], disabled: [] };\n\n for (const spec of DREAMING_AUTOMATIONS) {\n const current = await automationService.get(spec.id);\n const enabled = resolved.enabled && resolved.phases[spec.phase].enabled;\n\n if (!resolved.enabled) {\n if (current?.enabled) {\n await automationService.update(spec.id, { enabled: false });\n result.disabled.push(spec.id);\n }\n continue;\n }\n\n const next = {\n name: spec.name,\n description: phaseDescription(spec.phase),\n enabled,\n trigger: buildTrigger(resolved, spec.phase),\n action: buildAction(config, agentId, spec.token),\n };\n\n if (!current) {\n await automationService.create({\n id: spec.id,\n ...next,\n safety: { mode: 'auto_apply' },\n afterRun: { kind: 'none' },\n reliability: { disableAfterConsecutiveFailures: 3 },\n });\n result.created.push(spec.id);\n continue;\n }\n\n if (automationNeedsUpdate(current, next)) {\n await automationService.update(spec.id, {\n ...next,\n safety: { mode: 'auto_apply' },\n afterRun: { kind: 'none' },\n reliability: { disableAfterConsecutiveFailures: 3 },\n });\n result.updated.push(spec.id);\n }\n }\n\n return result;\n}\n"],"mappings":";;;;;kBAEgE;AAsBhE,MAAM,uBAA0D;CAC9D;EACE,IAAI;EACJ,OAAO;EACP,MAAM;EACN,OAAO;EACR;CACD;EACE,IAAI;EACJ,OAAO;EACP,MAAM;EACN,OAAO;EACR;CACD;EACE,IAAI;EACJ,OAAO;EACP,MAAM;EACN,OAAO;EACR;CACF;AAQD,SAAS,iBAAiB,OAAgC;AAExD,QAAO,GADO,UAAU,UAAU,gBAAgB,UAAU,SAAS,mBAAmB,wBACxE,wBAAwB;;AAG1C,SAAS,aAAa,QAAgC,OAA2C;AAE/F,QAAO;EACL,MAAM;EACN,UAAU;GACR,MAAM;GACN,MALgB,OAAO,OAAO,OAKZ;GAClB,GAAI,OAAO,WAAW,EAAE,IAAI,OAAO,UAAU,GAAG,EAAE;GACnD;EACF;;AAGH,SAAS,YAAY,QAAgB,SAAiB,OAAiC;CACrF,MAAM,eAAe,iBAAiB,OAAO;AAC7C,QAAO;EACL,MAAM;EACN;EACA,aAAa;EACb,GAAI,eAAe,EAAE,kBAAkB,cAAc,GAAG,EAAE;EAC1D,gBAAgB;EACjB;;AAGH,SAAS,sBAAsB,SAAqB,MAMxC;AACV,QACE,QAAQ,SAAS,KAAK,QACtB,QAAQ,gBAAgB,KAAK,eAC7B,QAAQ,YAAY,KAAK,WACzB,KAAK,UAAU,QAAQ,QAAQ,KAAK,KAAK,UAAU,KAAK,QAAQ,IAChE,KAAK,UAAU,QAAQ,OAAO,KAAK,KAAK,UAAU,KAAK,OAAO,IAC9D,QAAQ,QAAQ,SAAS,gBACzB,QAAQ,UAAU,SAAS,UAC3B,QAAQ,aAAa,oCAAoC;;AAI7D,eAAsB,6BAA6B,QAGJ;CAC7C,MAAM,EAAE,QAAQ,sBAAsB;CACtC,MAAM,WAAW,sBAAsB,OAAO;CAC9C,MAAM,UAAU,sBAAsB,OAAO;CAC7C,MAAM,SAA4C;EAAE,SAAS,EAAE;EAAE,SAAS,EAAE;EAAE,UAAU,EAAE;EAAE;AAE5F,MAAK,MAAM,QAAQ,sBAAsB;EACvC,MAAM,UAAU,MAAM,kBAAkB,IAAI,KAAK,GAAG;EACpD,MAAM,UAAU,SAAS,WAAW,SAAS,OAAO,KAAK,OAAO;AAEhE,MAAI,CAAC,SAAS,SAAS;AACrB,OAAI,SAAS,SAAS;AACpB,UAAM,kBAAkB,OAAO,KAAK,IAAI,EAAE,SAAS,OAAO,CAAC;AAC3D,WAAO,SAAS,KAAK,KAAK,GAAG;;AAE/B;;EAGF,MAAM,OAAO;GACX,MAAM,KAAK;GACX,aAAa,iBAAiB,KAAK,MAAM;GACzC;GACA,SAAS,aAAa,UAAU,KAAK,MAAM;GAC3C,QAAQ,YAAY,QAAQ,SAAS,KAAK,MAAM;GACjD;AAED,MAAI,CAAC,SAAS;AACZ,SAAM,kBAAkB,OAAO;IAC7B,IAAI,KAAK;IACT,GAAG;IACH,QAAQ,EAAE,MAAM,cAAc;IAC9B,UAAU,EAAE,MAAM,QAAQ;IAC1B,aAAa,EAAE,iCAAiC,GAAG;IACpD,CAAC;AACF,UAAO,QAAQ,KAAK,KAAK,GAAG;AAC5B;;AAGF,MAAI,sBAAsB,SAAS,KAAK,EAAE;AACxC,SAAM,kBAAkB,OAAO,KAAK,IAAI;IACtC,GAAG;IACH,QAAQ,EAAE,MAAM,cAAc;IAC9B,UAAU,EAAE,MAAM,QAAQ;IAC1B,aAAa,EAAE,iCAAiC,GAAG;IACpD,CAAC;AACF,UAAO,QAAQ,KAAK,KAAK,GAAG;;;AAIhC,QAAO"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { AgentService } from '../../agent/service.js';
|
|
2
2
|
import type { Config } from '../../config/schema.js';
|
|
3
|
-
import { CronService } from '../../cron/service.js';
|
|
4
3
|
import type { MessageBus } from '../../infra/bus/index.js';
|
|
5
4
|
import type { SessionStore } from '../../session/store.js';
|
|
6
5
|
export interface HeartbeatRunnerConfig {
|
|
@@ -22,7 +21,6 @@ export declare function heartbeatRunnerConfigFromConfig(cfg: Config): HeartbeatR
|
|
|
22
21
|
export interface HeartbeatServiceDeps {
|
|
23
22
|
agentService: AgentService;
|
|
24
23
|
messageBus: MessageBus;
|
|
25
|
-
cronService: CronService;
|
|
26
24
|
sessionStore: SessionStore;
|
|
27
25
|
/** Current app config (for HEARTBEAT.md path under the default agent `profile/` directory). */
|
|
28
26
|
getConfig: () => Config;
|
|
@@ -80,13 +80,6 @@ var HeartbeatService = class {
|
|
|
80
80
|
log.debug({ reasons: reasonSummary }, "Heartbeat: skip (disabled)");
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
|
-
try {
|
|
84
|
-
const metrics = await this.deps.cronService.getMetrics();
|
|
85
|
-
log.trace({
|
|
86
|
-
runningJobs: metrics.runningJobs,
|
|
87
|
-
enabledJobs: metrics.enabledJobs
|
|
88
|
-
}, "Heartbeat: cron metrics");
|
|
89
|
-
} catch {}
|
|
90
83
|
if (cfg.activeHours && !isWithinActiveHours(cfg.activeHours)) {
|
|
91
84
|
log.debug({ reasons: reasonSummary }, "Heartbeat: skip (outside active hours)");
|
|
92
85
|
return;
|
|
@@ -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 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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"}
|
|
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 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 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 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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"}
|
|
@@ -44,6 +44,7 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
|
|
|
44
44
|
defaultRole: string;
|
|
45
45
|
roles: Record<string, {
|
|
46
46
|
model: string;
|
|
47
|
+
fallbacks?: string[];
|
|
47
48
|
description?: string;
|
|
48
49
|
}>;
|
|
49
50
|
policy?: {
|
|
@@ -165,6 +166,7 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
|
|
|
165
166
|
defaultRole?: string;
|
|
166
167
|
roles?: Record<string, {
|
|
167
168
|
model: string;
|
|
169
|
+
fallbacks?: string[];
|
|
168
170
|
description?: string;
|
|
169
171
|
}>;
|
|
170
172
|
policy?: {
|
|
@@ -365,12 +367,6 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
|
|
|
365
367
|
dialogPolicy: unknown;
|
|
366
368
|
dialogTimeoutSeconds: number;
|
|
367
369
|
};
|
|
368
|
-
cron: {
|
|
369
|
-
enabled: boolean;
|
|
370
|
-
maxConcurrentJobs: number;
|
|
371
|
-
historyRetentionDays: number;
|
|
372
|
-
enableMetrics: boolean;
|
|
373
|
-
};
|
|
374
370
|
goals: {
|
|
375
371
|
maxTurns: number;
|
|
376
372
|
checklistMode: boolean;
|
|
@@ -401,6 +397,9 @@ export declare function buildSafeWebConfigPayload(service: GatewayService, optio
|
|
|
401
397
|
maxEntries: number;
|
|
402
398
|
};
|
|
403
399
|
};
|
|
400
|
+
tui: {
|
|
401
|
+
defaultAgent: string;
|
|
402
|
+
};
|
|
404
403
|
tunnel: {
|
|
405
404
|
enabled: boolean;
|
|
406
405
|
autoStart: boolean;
|
|
@@ -7,7 +7,7 @@ import { getProviderRegistry, init_plugin_registry } from "../../../providers/pl
|
|
|
7
7
|
import { getAllProviders, init_providers, isProviderConfigured } from "../../../providers/index.js";
|
|
8
8
|
import { resolveShareConfig } from "../../../share/share-config.js";
|
|
9
9
|
import { normalizeConfiguredMcpServers } from "../../../config/mcp-config-normalize.js";
|
|
10
|
-
import {
|
|
10
|
+
import { resolveGoalsConfigForWeb, resolveSessionConfigForWeb, resolveUpdateConfigForWeb } from "../../../config/web-patch.js";
|
|
11
11
|
import { GENERIC_MASKED_SECRET, maskSecretLength } from "./mask-secret-length.js";
|
|
12
12
|
import { safeToolsWebForGet } from "../../config-tools-web.js";
|
|
13
13
|
import { maskTunnelSecretForWeb } from "../../../tunnel/env.js";
|
|
@@ -174,9 +174,9 @@ async function buildSafeWebConfigPayload(service, options = {}) {
|
|
|
174
174
|
skillsStoreBaseUrl: config.gateway?.skillsStoreBaseUrl ?? "https://store.xopc.ai"
|
|
175
175
|
},
|
|
176
176
|
browser: buildSafeBrowserConfigForWeb(config.browser),
|
|
177
|
-
cron: resolveCronConfigForWeb(config),
|
|
178
177
|
goals: resolveGoalsConfigForWeb(config),
|
|
179
178
|
session: resolveSessionConfigForWeb(config),
|
|
179
|
+
tui: { defaultAgent: config.tui?.defaultAgent ?? "coder" },
|
|
180
180
|
tunnel: {
|
|
181
181
|
enabled: config.tunnel?.enabled === true,
|
|
182
182
|
autoStart: config.tunnel?.autoStart === true,
|
|
@@ -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 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 { 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: unknown) {\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 as Record<string, unknown>).enabled !== false,\n headless: (browser as Record<string, unknown>).headless === true,\n allowPrivateUrls: (browser as Record<string, unknown>).allowPrivateUrls === true,\n commandTimeout:\n typeof (browser as Record<string, unknown>).commandTimeout === 'number' &&\n Number.isFinite((browser as Record<string, unknown>).commandTimeout as number)\n ? Math.floor((browser as Record<string, unknown>).commandTimeout as number)\n : null,\n backend:\n (browser as Record<string, unknown>).backend === 'local' ||\n (browser as Record<string, unknown>).backend === 'cdp' ||\n (browser as Record<string, unknown>).backend === 'cloud' ||\n (browser as Record<string, unknown>).backend === 'extension' ||\n (browser as Record<string, unknown>).backend === 'cloakbrowser'\n ? (browser as Record<string, unknown>).backend\n : null,\n cloudProvider:\n (browser as Record<string, unknown>).cloudProvider === 'browserbase' ||\n (browser as Record<string, unknown>).cloudProvider === 'browser-use'\n ? (browser as Record<string, unknown>).cloudProvider\n : null,\n cloud: maskBrowserCloudConfigForWeb((browser as Record<string, unknown>).cloud),\n cdpUrl:\n typeof (browser as Record<string, unknown>).cdpUrl === 'string' &&\n ((browser as Record<string, unknown>).cdpUrl as string).trim()\n ? ((browser as Record<string, unknown>).cdpUrl as string).trim()\n : null,\n extension:\n (browser as Record<string, unknown>).extension &&\n typeof (browser as Record<string, unknown>).extension === 'object' &&\n !Array.isArray((browser as Record<string, unknown>).extension)\n ? (browser as Record<string, unknown>).extension\n : null,\n cloakbrowser:\n (browser as Record<string, unknown>).cloakbrowser &&\n typeof (browser as Record<string, unknown>).cloakbrowser === 'object' &&\n !Array.isArray((browser as Record<string, unknown>).cloakbrowser)\n ? (browser as Record<string, unknown>).cloakbrowser\n : null,\n humanize:\n typeof (browser as Record<string, unknown>).humanize === 'boolean'\n ? (browser as Record<string, unknown>).humanize\n : null,\n humanPreset:\n (browser as Record<string, unknown>).humanPreset === 'default' ||\n (browser as Record<string, unknown>).humanPreset === 'careful'\n ? (browser as Record<string, unknown>).humanPreset\n : null,\n dialogPolicy:\n (browser as Record<string, unknown>).dialogPolicy === 'must_respond' ||\n (browser as Record<string, unknown>).dialogPolicy === 'auto_accept' ||\n (browser as Record<string, unknown>).dialogPolicy === 'auto_dismiss'\n ? (browser as Record<string, unknown>).dialogPolicy\n : null,\n dialogTimeoutSeconds:\n typeof (browser as Record<string, unknown>).dialogTimeoutSeconds === 'number' &&\n Number.isFinite((browser as Record<string, unknown>).dialogTimeoutSeconds as number)\n ? Math.floor((browser as Record<string, unknown>).dialogTimeoutSeconds as number)\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 identity: e.identity,\n workspace: e.workspace,\n models: e.models,\n tools: e.tools,\n skills: e.skills,\n memory: e.memory,\n workflows: e.workflows,\n boundaries: e.boundaries,\n })),\n capabilityPresets: config.agents?.capabilityPresets ?? {},\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 browser: buildSafeBrowserConfigForWeb(config.browser),\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 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 { 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: unknown) {\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 as Record<string, unknown>).enabled !== false,\n headless: (browser as Record<string, unknown>).headless === true,\n allowPrivateUrls: (browser as Record<string, unknown>).allowPrivateUrls === true,\n commandTimeout:\n typeof (browser as Record<string, unknown>).commandTimeout === 'number' &&\n Number.isFinite((browser as Record<string, unknown>).commandTimeout as number)\n ? Math.floor((browser as Record<string, unknown>).commandTimeout as number)\n : null,\n backend:\n (browser as Record<string, unknown>).backend === 'local' ||\n (browser as Record<string, unknown>).backend === 'cdp' ||\n (browser as Record<string, unknown>).backend === 'cloud' ||\n (browser as Record<string, unknown>).backend === 'extension' ||\n (browser as Record<string, unknown>).backend === 'cloakbrowser'\n ? (browser as Record<string, unknown>).backend\n : null,\n cloudProvider:\n (browser as Record<string, unknown>).cloudProvider === 'browserbase' ||\n (browser as Record<string, unknown>).cloudProvider === 'browser-use'\n ? (browser as Record<string, unknown>).cloudProvider\n : null,\n cloud: maskBrowserCloudConfigForWeb((browser as Record<string, unknown>).cloud),\n cdpUrl:\n typeof (browser as Record<string, unknown>).cdpUrl === 'string' &&\n ((browser as Record<string, unknown>).cdpUrl as string).trim()\n ? ((browser as Record<string, unknown>).cdpUrl as string).trim()\n : null,\n extension:\n (browser as Record<string, unknown>).extension &&\n typeof (browser as Record<string, unknown>).extension === 'object' &&\n !Array.isArray((browser as Record<string, unknown>).extension)\n ? (browser as Record<string, unknown>).extension\n : null,\n cloakbrowser:\n (browser as Record<string, unknown>).cloakbrowser &&\n typeof (browser as Record<string, unknown>).cloakbrowser === 'object' &&\n !Array.isArray((browser as Record<string, unknown>).cloakbrowser)\n ? (browser as Record<string, unknown>).cloakbrowser\n : null,\n humanize:\n typeof (browser as Record<string, unknown>).humanize === 'boolean'\n ? (browser as Record<string, unknown>).humanize\n : null,\n humanPreset:\n (browser as Record<string, unknown>).humanPreset === 'default' ||\n (browser as Record<string, unknown>).humanPreset === 'careful'\n ? (browser as Record<string, unknown>).humanPreset\n : null,\n dialogPolicy:\n (browser as Record<string, unknown>).dialogPolicy === 'must_respond' ||\n (browser as Record<string, unknown>).dialogPolicy === 'auto_accept' ||\n (browser as Record<string, unknown>).dialogPolicy === 'auto_dismiss'\n ? (browser as Record<string, unknown>).dialogPolicy\n : null,\n dialogTimeoutSeconds:\n typeof (browser as Record<string, unknown>).dialogTimeoutSeconds === 'number' &&\n Number.isFinite((browser as Record<string, unknown>).dialogTimeoutSeconds as number)\n ? Math.floor((browser as Record<string, unknown>).dialogTimeoutSeconds as number)\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 identity: e.identity,\n workspace: e.workspace,\n models: e.models,\n tools: e.tools,\n skills: e.skills,\n memory: e.memory,\n workflows: e.workflows,\n boundaries: e.boundaries,\n })),\n capabilityPresets: config.agents?.capabilityPresets ?? {},\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 browser: buildSafeBrowserConfigForWeb(config.browser),\n goals: resolveGoalsConfigForWeb(config),\n session: resolveSessionConfigForWeb(config),\n tui: {\n defaultAgent: config.tui?.defaultAgent ?? 'coder',\n },\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","names":[],"sources":["../../../../../src/gateway/hono/routes/agents.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { AgentModelsSchema, type Config, parseModelRef } from '../../../config/schema.js';\nimport { MemoryPolicySchema, ToolPolicySetSchema } from '../../../agent-manifest/schema.js';\nimport { getVoiceModelsConfig } from '../../../config/voice.js';\nimport {\n isProviderConfigured,\n resolveModel,\n} from '../../../providers/index.js';\nimport { normalizeAgentId } from '../../../agent/agent-scope.js';\nimport {\n deleteAgentAvatarFile,\n finalizeCreateAgentDirs,\n getGatewayAgentEffectiveManifest,\n listAgentProfileFiles,\n listGatewayAgents,\n prepareCreateAgent,\n prepareDeleteAgent,\n prepareUpdateAgent,\n readAgentAvatarFile,\n readAgentProfileFile,\n readUserProfileFile,\n runAfterDeletePurge,\n writeAgentAvatarFromBase64,\n writeAgentProfileFile,\n writeUserProfileFile,\n type CreateAgentBody,\n} from '../../agents-admin.js';\nimport {\n resolveImageGenerationCapabilities,\n resolveImageUnderstandingCapabilities,\n} from '../../image-capabilities.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction parseProfileFiles(raw: unknown): Record<string, string> | undefined | { error: string } {\n if (raw === undefined) {\n return undefined;\n }\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n return { error: 'profileFiles must be an object' };\n }\n const profileFiles: Record<string, string> = {};\n for (const [name, content] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof content !== 'string') {\n return { error: `profileFiles[\"${name}\"] must be a string` };\n }\n profileFiles[name] = content;\n }\n return profileFiles;\n}\n\nfunction isParseError(value: unknown): value is { error: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'error' in value &&\n typeof (value as { error: string }).error === 'string'\n );\n}\n\nfunction parseCreateAgentBody(raw: unknown): CreateAgentBody | { error: string } {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n return { error: 'each agent must be an object' };\n }\n const body = raw as Record<string, unknown>;\n if (Object.hasOwn(body, 'model')) {\n return { error: 'model is not supported; use models.defaultRole and models.roles' };\n }\n if (Object.hasOwn(body, 'toolsDisable')) {\n return { error: 'toolsDisable was removed; use tools.builtin policies' };\n }\n if (Object.hasOwn(body, 'typedModels')) {\n return { error: 'typedModels is not supported; use models.roles' };\n }\n if (Object.hasOwn(body, 'agentDir')) {\n return { error: 'agentDir was removed from agent manifests' };\n }\n if (Object.hasOwn(body, 'name')) {\n return { error: 'name is not supported; write IDENTITY.md in profileFiles' };\n }\n if (Object.hasOwn(body, 'description')) {\n return { error: 'description is not supported; write IDENTITY.md in profileFiles' };\n }\n const workspace = typeof body.workspace === 'string' ? body.workspace : '';\n const models = Object.hasOwn(body, 'models')\n ? AgentModelsSchema.safeParse(body.models)\n : undefined;\n if (models && !models.success) {\n return { error: `models ${models.error.issues[0]?.message ?? 'is invalid'}` };\n }\n const id = typeof body.id === 'string' ? body.id : undefined;\n const skills = Object.hasOwn(body, 'skills')\n ? Array.isArray(body.skills)\n ? body.skills.map((x: unknown) => String(x).trim()).filter(Boolean)\n : null\n : undefined;\n if (skills === null) {\n return { error: 'skills must be an array' };\n }\n const toolsRaw = Object.hasOwn(body, 'tools') ? body.tools : undefined;\n let tools: CreateAgentBody['tools'] | undefined;\n if (toolsRaw !== undefined) {\n if (toolsRaw === null || typeof toolsRaw !== 'object' || Array.isArray(toolsRaw)) {\n return { error: 'tools must be an object' };\n }\n const parsedTools = ToolPolicySetSchema.safeParse(toolsRaw);\n if (!parsedTools.success) {\n return { error: `tools ${parsedTools.error.issues[0]?.message ?? 'is invalid'}` };\n }\n tools = parsedTools.data;\n }\n let profileFiles: Record<string, string> | undefined;\n if (Object.hasOwn(body, 'profileFiles')) {\n const parsed = parseProfileFiles(body.profileFiles);\n if (isParseError(parsed)) {\n return parsed;\n }\n profileFiles = parsed;\n }\n if (!profileFiles?.['IDENTITY.md'] && typeof body.cloneFrom !== 'string') {\n return { error: 'profileFiles.IDENTITY.md is required' };\n }\n const cloneFrom = typeof body.cloneFrom === 'string' ? body.cloneFrom : undefined;\n return {\n workspace,\n ...(models && models.data !== undefined ? { models: models.data } : {}),\n ...(id !== undefined ? { id } : {}),\n ...(skills !== undefined ? { skills } : {}),\n ...(tools !== undefined ? { tools } : {}),\n ...(profileFiles !== undefined ? { profileFiles } : {}),\n ...(cloneFrom !== undefined ? { cloneFrom } : {}),\n };\n}\n\ntype PatchModels = {\n defaultRole?: string | null;\n roles?: Record<string, { model: string; description?: string }>;\n};\n\nfunction parsePatchModels(raw: unknown): PatchModels | null | undefined | { error: string } {\n if (raw === undefined) {\n return undefined;\n }\n if (raw === null) {\n return null;\n }\n if (typeof raw !== 'object' || Array.isArray(raw)) {\n return { error: 'models must be an object or null' };\n }\n const body = raw as Record<string, unknown>;\n const out: PatchModels = {};\n if (Object.hasOwn(body, 'defaultRole')) {\n out.defaultRole = body.defaultRole === null ? null : String(body.defaultRole ?? '').trim();\n }\n if (Object.hasOwn(body, 'roles')) {\n if (body.roles === null) {\n return { error: 'models.roles must be an object' };\n } else {\n const parsed = AgentModelsSchema.safeParse({ roles: body.roles });\n if (!parsed.success) {\n return { error: `models.roles ${parsed.error.issues[0]?.message ?? 'is invalid'}` };\n }\n out.roles = parsed.data?.roles;\n }\n }\n return out;\n}\n\nexport function registerAgentsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n authenticated.get('/api/agents', async (c) => {\n const cfg = service.currentConfig as Config;\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const payload = await listGatewayAgents(cfg, { locale });\n return c.json({ ok: true, payload });\n });\n\n authenticated.get('/api/user-profile', async (c) => {\n const res = await readUserProfileFile();\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.put('/api/user-profile', strictRateLimitMiddleware, async (c) => {\n let content = '';\n try {\n const body = (await c.req.json()) as { content?: unknown };\n content = typeof body.content === 'string' ? body.content : '';\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const res = await writeUserProfileFile(content);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.post('/api/agents', strictRateLimitMiddleware, async (c) => {\n let body: Record<string, unknown> = {};\n try {\n body = (await c.req.json()) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const parsed = parseCreateAgentBody(body);\n if ('error' in parsed) {\n return c.json({ ok: false, error: { message: parsed.error } }, 400);\n }\n const prep = prepareCreateAgent(service.currentConfig as Config, parsed);\n if (prep.ok === false) {\n return c.json({ ok: false, error: { message: prep.error } }, prep.status ?? 400);\n }\n const { nextConfig, agentId } = prep.data;\n const save = await service.saveConfig(nextConfig);\n if (!save.saved) {\n return c.json({ ok: false, error: { message: save.error ?? 'save failed' } }, 500);\n }\n const finalized = await finalizeCreateAgentDirs(service.currentConfig as Config, agentId, {\n ...(parsed.profileFiles !== undefined ? { profileFiles: parsed.profileFiles } : {}),\n ...(parsed.cloneFrom ? { cloneFrom: parsed.cloneFrom } : {}),\n });\n if (finalized.ok === false) {\n return c.json({ ok: false, error: { message: finalized.error } }, finalized.status ?? 400);\n }\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const agentsPayload = await listGatewayAgents(service.currentConfig as Config, { locale });\n return c.json({\n ok: true,\n payload: {\n agentId,\n agents: agentsPayload,\n },\n });\n });\n\n authenticated.get('/api/agents/:id/effective-manifest', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = getGatewayAgentEffectiveManifest(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.patch('/api/agents/:id', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n let body: Record<string, unknown> = {};\n try {\n body = (await c.req.json()) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n if (Object.hasOwn(body, 'model')) {\n return c.json({ ok: false, error: { message: 'model is not supported; use models.defaultRole and models.roles' } }, 400);\n }\n if (Object.hasOwn(body, 'typedModels')) {\n return c.json({ ok: false, error: { message: 'typedModels is not supported; use models.roles' } }, 400);\n }\n if (Object.hasOwn(body, 'toolsDisable')) {\n return c.json({ ok: false, error: { message: 'toolsDisable was removed; use tools.builtin policies' } }, 400);\n }\n if (Object.hasOwn(body, 'agentDir')) {\n return c.json({ ok: false, error: { message: 'agentDir was removed from agent manifests' } }, 400);\n }\n if (Object.hasOwn(body, 'name')) {\n return c.json({ ok: false, error: { message: 'name is not supported; edit IDENTITY.md' } }, 400);\n }\n if (Object.hasOwn(body, 'description')) {\n return c.json({ ok: false, error: { message: 'description is not supported; edit IDENTITY.md' } }, 400);\n }\n const skillsPatch =\n body.skills === null\n ? null\n : Array.isArray(body.skills)\n ? body.skills.map((x: unknown) => String(x).trim()).filter(Boolean)\n : undefined;\n const extendsPatch = Object.hasOwn(body, 'extends')\n ? Array.isArray(body.extends)\n ? body.extends.map((x: unknown) => String(x).trim()).filter(Boolean)\n : undefined\n : undefined;\n if (Object.hasOwn(body, 'extends') && extendsPatch === undefined) {\n return c.json({ ok: false, error: { message: 'extends must be an array' } }, 400);\n }\n let toolsPatch: CreateAgentBody['tools'] | null | undefined;\n if (Object.hasOwn(body, 'tools')) {\n if (body.tools === null) {\n toolsPatch = null;\n } else if (typeof body.tools === 'object' && !Array.isArray(body.tools)) {\n const parsedTools = ToolPolicySetSchema.safeParse(body.tools);\n if (!parsedTools.success) {\n return c.json({ ok: false, error: { message: `tools ${parsedTools.error.issues[0]?.message ?? 'is invalid'}` } }, 400);\n }\n toolsPatch = parsedTools.data;\n } else {\n return c.json({ ok: false, error: { message: 'tools must be an object or null' } }, 400);\n }\n }\n const modelsPatch = Object.hasOwn(body, 'models') ? parsePatchModels(body.models) : undefined;\n if (isParseError(modelsPatch)) {\n return c.json({ ok: false, error: { message: modelsPatch.error } }, 400);\n }\n let memoryPatch: Config['agents']['list'][number]['memory'] | undefined;\n if (Object.hasOwn(body, 'memory')) {\n const parsedMemory = MemoryPolicySchema.safeParse(body.memory);\n if (!parsedMemory.success) {\n return c.json({ ok: false, error: { message: `memory ${parsedMemory.error.issues[0]?.message ?? 'is invalid'}` } }, 400);\n }\n memoryPatch = parsedMemory.data;\n }\n\n const prep = prepareUpdateAgent(service.currentConfig as Config, id, {\n workspace: typeof body.workspace === 'string' ? body.workspace : undefined,\n ...(extendsPatch !== undefined ? { extends: extendsPatch } : {}),\n ...(modelsPatch !== undefined ? { models: modelsPatch } : {}),\n setDefault: body.setDefault === true,\n ...(skillsPatch !== undefined ? { skills: skillsPatch } : {}),\n ...(toolsPatch !== undefined ? { tools: toolsPatch } : {}),\n ...(memoryPatch !== undefined ? { memory: memoryPatch } : {}),\n });\n if (prep.ok === false) {\n return c.json({ ok: false, error: { message: prep.error } }, prep.status ?? 400);\n }\n const save = await service.saveConfig(prep.data.nextConfig);\n if (!save.saved) {\n return c.json({ ok: false, error: { message: save.error ?? 'save failed' } }, 500);\n }\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const agentsPayload = await listGatewayAgents(service.currentConfig as Config, { locale });\n return c.json({ ok: true, payload: agentsPayload });\n });\n\n authenticated.delete('/api/agents/:id', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const purge = c.req.query('purge') === '1' || c.req.query('purge') === 'true';\n const prep = prepareDeleteAgent(service.currentConfig as Config, id);\n if (prep.ok === false) {\n return c.json({ ok: false, error: { message: prep.error } }, prep.status ?? 400);\n }\n const { nextConfig, agentId } = prep.data;\n const save = await service.saveConfig(nextConfig);\n if (!save.saved) {\n return c.json({ ok: false, error: { message: save.error ?? 'save failed' } }, 500);\n }\n if (purge) {\n await runAfterDeletePurge(service.currentConfig as Config, agentId);\n }\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const agentsPayload = await listGatewayAgents(service.currentConfig as Config, { locale });\n return c.json({\n ok: true,\n payload: { agentId, purged: purge, agents: agentsPayload },\n });\n });\n\n authenticated.get('/api/agents/:id/avatar', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = await readAgentAvatarFile(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return new Response(res.data.buffer, {\n status: 200,\n headers: {\n 'Content-Type': res.data.contentType,\n 'Cache-Control': 'private, max-age=3600',\n },\n });\n });\n\n authenticated.put('/api/agents/:id/avatar', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n let body: Record<string, unknown> = {};\n try {\n body = (await c.req.json()) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const base64 = typeof body.base64 === 'string' ? body.base64 : '';\n const mimeType = typeof body.mimeType === 'string' ? body.mimeType : '';\n const res = await writeAgentAvatarFromBase64(service.currentConfig as Config, id, base64, mimeType);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId } });\n });\n\n authenticated.delete('/api/agents/:id/avatar', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = await deleteAgentAvatarFile(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId } });\n });\n\n authenticated.get('/api/agents/:id/files', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = await listAgentProfileFiles(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.get('/api/agents/:id/files/:name', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const name = decodeURIComponent(c.req.param('name') ?? '');\n const res = await readAgentProfileFile(service.currentConfig as Config, id, name);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId, name, content: res.data.content } });\n });\n\n authenticated.put('/api/agents/:id/files/:name', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const name = decodeURIComponent(c.req.param('name') ?? '');\n let content = '';\n try {\n const body = (await c.req.json()) as { content?: unknown };\n content = typeof body.content === 'string' ? body.content : '';\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const res = await writeAgentProfileFile(service.currentConfig as Config, id, name, content);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId, name } });\n });\n\n // GET /api/voice/models - Get available STT/TTS models\n authenticated.get('/api/voice/models', (c) => {\n const models = getVoiceModelsConfig();\n return c.json({ ok: true, payload: { models } });\n });\n\n authenticated.get('/api/image/capabilities', async (c) => {\n const config = service.currentConfig as Config;\n const imageGenerationProviders = await resolveImageGenerationCapabilities(config);\n const imageUnderstandingProviders = await resolveImageUnderstandingCapabilities(config);\n return c.json({\n ok: true,\n payload: {\n current: {\n imageModel: null,\n imageModelFallbacks: [],\n imageGenerationModel: null,\n imageGenerationModelFallbacks: [],\n mediaMaxMb: null,\n },\n imageGeneration: { providers: imageGenerationProviders },\n imageUnderstanding: { providers: imageUnderstandingProviders },\n },\n });\n });\n\n authenticated.post('/api/image/validate-model', strictRateLimitMiddleware, async (c) => {\n let body: { modelRef?: unknown };\n try {\n body = (await c.req.json()) as { modelRef?: unknown };\n } catch {\n return c.json({ ok: false, error: 'Invalid JSON' }, 400);\n }\n const modelRef = body.modelRef;\n if (!modelRef || typeof modelRef !== 'string') {\n return c.json({ ok: false, error: 'modelRef is required' }, 400);\n }\n\n const parsed = parseModelRef(modelRef);\n if (!parsed) {\n return c.json({\n ok: true,\n payload: {\n valid: false,\n reason: 'invalid_format',\n message: 'Model reference must be in \"provider/model\" format',\n },\n });\n }\n\n const configured = await isProviderConfigured(parsed.provider);\n if (!configured) {\n return c.json({\n ok: true,\n payload: {\n valid: false,\n reason: 'provider_not_configured',\n message: `Provider \"${parsed.provider}\" is not configured. Set the API key first.`,\n provider: parsed.provider,\n },\n });\n }\n\n try {\n resolveModel(modelRef);\n } catch {\n return c.json({\n ok: true,\n payload: {\n valid: false,\n reason: 'model_not_found',\n message: `Model not found in registry: ${modelRef}`,\n provider: parsed.provider,\n model: parsed.model,\n },\n });\n }\n\n return c.json({\n ok: true,\n payload: {\n valid: true,\n provider: parsed.provider,\n model: parsed.model,\n },\n });\n });\n\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agents.js","names":[],"sources":["../../../../../src/gateway/hono/routes/agents.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { AgentModelsSchema, type Config, parseModelRef } from '../../../config/schema.js';\nimport { MemoryPolicySchema, ToolPolicySetSchema } from '../../../agent-manifest/schema.js';\nimport { getVoiceModelsConfig } from '../../../config/voice.js';\nimport {\n isProviderConfigured,\n resolveModel,\n} from '../../../providers/index.js';\nimport { normalizeAgentId } from '../../../agent/agent-scope.js';\nimport {\n deleteAgentAvatarFile,\n finalizeCreateAgentDirs,\n getGatewayAgentEffectiveManifest,\n listAgentProfileFiles,\n listGatewayAgents,\n prepareCreateAgent,\n prepareDeleteAgent,\n prepareUpdateAgent,\n readAgentAvatarFile,\n readAgentProfileFile,\n readUserProfileFile,\n runAfterDeletePurge,\n writeAgentAvatarFromBase64,\n writeAgentProfileFile,\n writeUserProfileFile,\n type CreateAgentBody,\n} from '../../agents-admin.js';\nimport {\n resolveImageGenerationCapabilities,\n resolveImageUnderstandingCapabilities,\n} from '../../image-capabilities.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction parseProfileFiles(raw: unknown): Record<string, string> | undefined | { error: string } {\n if (raw === undefined) {\n return undefined;\n }\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n return { error: 'profileFiles must be an object' };\n }\n const profileFiles: Record<string, string> = {};\n for (const [name, content] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof content !== 'string') {\n return { error: `profileFiles[\"${name}\"] must be a string` };\n }\n profileFiles[name] = content;\n }\n return profileFiles;\n}\n\nfunction isParseError(value: unknown): value is { error: string } {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'error' in value &&\n typeof (value as { error: string }).error === 'string'\n );\n}\n\nfunction parseCreateAgentBody(raw: unknown): CreateAgentBody | { error: string } {\n if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n return { error: 'each agent must be an object' };\n }\n const body = raw as Record<string, unknown>;\n if (Object.hasOwn(body, 'model')) {\n return { error: 'model is not supported; use models.defaultRole and models.roles' };\n }\n if (Object.hasOwn(body, 'toolsDisable')) {\n return { error: 'toolsDisable was removed; use tools.builtin policies' };\n }\n if (Object.hasOwn(body, 'typedModels')) {\n return { error: 'typedModels is not supported; use models.roles' };\n }\n if (Object.hasOwn(body, 'agentDir')) {\n return { error: 'agentDir was removed from agent manifests' };\n }\n if (Object.hasOwn(body, 'name')) {\n return { error: 'name is not supported; write IDENTITY.md in profileFiles' };\n }\n if (Object.hasOwn(body, 'description')) {\n return { error: 'description is not supported; write IDENTITY.md in profileFiles' };\n }\n const workspace = typeof body.workspace === 'string' ? body.workspace : '';\n const models = Object.hasOwn(body, 'models')\n ? AgentModelsSchema.safeParse(body.models)\n : undefined;\n if (models && !models.success) {\n return { error: `models ${models.error.issues[0]?.message ?? 'is invalid'}` };\n }\n const id = typeof body.id === 'string' ? body.id : undefined;\n const skills = Object.hasOwn(body, 'skills')\n ? Array.isArray(body.skills)\n ? body.skills.map((x: unknown) => String(x).trim()).filter(Boolean)\n : null\n : undefined;\n if (skills === null) {\n return { error: 'skills must be an array' };\n }\n const toolsRaw = Object.hasOwn(body, 'tools') ? body.tools : undefined;\n let tools: CreateAgentBody['tools'] | undefined;\n if (toolsRaw !== undefined) {\n if (toolsRaw === null || typeof toolsRaw !== 'object' || Array.isArray(toolsRaw)) {\n return { error: 'tools must be an object' };\n }\n const parsedTools = ToolPolicySetSchema.safeParse(toolsRaw);\n if (!parsedTools.success) {\n return { error: `tools ${parsedTools.error.issues[0]?.message ?? 'is invalid'}` };\n }\n tools = parsedTools.data;\n }\n let profileFiles: Record<string, string> | undefined;\n if (Object.hasOwn(body, 'profileFiles')) {\n const parsed = parseProfileFiles(body.profileFiles);\n if (isParseError(parsed)) {\n return parsed;\n }\n profileFiles = parsed;\n }\n if (!profileFiles?.['IDENTITY.md'] && typeof body.cloneFrom !== 'string') {\n return { error: 'profileFiles.IDENTITY.md is required' };\n }\n const cloneFrom = typeof body.cloneFrom === 'string' ? body.cloneFrom : undefined;\n return {\n workspace,\n ...(models && models.data !== undefined ? { models: models.data } : {}),\n ...(id !== undefined ? { id } : {}),\n ...(skills !== undefined ? { skills } : {}),\n ...(tools !== undefined ? { tools } : {}),\n ...(profileFiles !== undefined ? { profileFiles } : {}),\n ...(cloneFrom !== undefined ? { cloneFrom } : {}),\n };\n}\n\ntype PatchModels = {\n defaultRole?: string | null;\n roles?: Record<string, { model: string; fallbacks?: string[]; description?: string }>;\n};\n\nfunction parsePatchModels(raw: unknown): PatchModels | null | undefined | { error: string } {\n if (raw === undefined) {\n return undefined;\n }\n if (raw === null) {\n return null;\n }\n if (typeof raw !== 'object' || Array.isArray(raw)) {\n return { error: 'models must be an object or null' };\n }\n const body = raw as Record<string, unknown>;\n const out: PatchModels = {};\n if (Object.hasOwn(body, 'defaultRole')) {\n out.defaultRole = body.defaultRole === null ? null : String(body.defaultRole ?? '').trim();\n }\n if (Object.hasOwn(body, 'roles')) {\n if (body.roles === null) {\n return { error: 'models.roles must be an object' };\n } else {\n const parsed = AgentModelsSchema.safeParse({ roles: body.roles });\n if (!parsed.success) {\n return { error: `models.roles ${parsed.error.issues[0]?.message ?? 'is invalid'}` };\n }\n out.roles = parsed.data?.roles;\n }\n }\n return out;\n}\n\nexport function registerAgentsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n authenticated.get('/api/agents', async (c) => {\n const cfg = service.currentConfig as Config;\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const payload = await listGatewayAgents(cfg, { locale });\n return c.json({ ok: true, payload });\n });\n\n authenticated.get('/api/user-profile', async (c) => {\n const res = await readUserProfileFile();\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.put('/api/user-profile', strictRateLimitMiddleware, async (c) => {\n let content = '';\n try {\n const body = (await c.req.json()) as { content?: unknown };\n content = typeof body.content === 'string' ? body.content : '';\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const res = await writeUserProfileFile(content);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.post('/api/agents', strictRateLimitMiddleware, async (c) => {\n let body: Record<string, unknown> = {};\n try {\n body = (await c.req.json()) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const parsed = parseCreateAgentBody(body);\n if ('error' in parsed) {\n return c.json({ ok: false, error: { message: parsed.error } }, 400);\n }\n const prep = prepareCreateAgent(service.currentConfig as Config, parsed);\n if (prep.ok === false) {\n return c.json({ ok: false, error: { message: prep.error } }, prep.status ?? 400);\n }\n const { nextConfig, agentId } = prep.data;\n const save = await service.saveConfig(nextConfig);\n if (!save.saved) {\n return c.json({ ok: false, error: { message: save.error ?? 'save failed' } }, 500);\n }\n const finalized = await finalizeCreateAgentDirs(service.currentConfig as Config, agentId, {\n ...(parsed.profileFiles !== undefined ? { profileFiles: parsed.profileFiles } : {}),\n ...(parsed.cloneFrom ? { cloneFrom: parsed.cloneFrom } : {}),\n });\n if (finalized.ok === false) {\n return c.json({ ok: false, error: { message: finalized.error } }, finalized.status ?? 400);\n }\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const agentsPayload = await listGatewayAgents(service.currentConfig as Config, { locale });\n return c.json({\n ok: true,\n payload: {\n agentId,\n agents: agentsPayload,\n },\n });\n });\n\n authenticated.get('/api/agents/:id/effective-manifest', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = getGatewayAgentEffectiveManifest(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.patch('/api/agents/:id', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n let body: Record<string, unknown> = {};\n try {\n body = (await c.req.json()) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n if (Object.hasOwn(body, 'model')) {\n return c.json({ ok: false, error: { message: 'model is not supported; use models.defaultRole and models.roles' } }, 400);\n }\n if (Object.hasOwn(body, 'typedModels')) {\n return c.json({ ok: false, error: { message: 'typedModels is not supported; use models.roles' } }, 400);\n }\n if (Object.hasOwn(body, 'toolsDisable')) {\n return c.json({ ok: false, error: { message: 'toolsDisable was removed; use tools.builtin policies' } }, 400);\n }\n if (Object.hasOwn(body, 'agentDir')) {\n return c.json({ ok: false, error: { message: 'agentDir was removed from agent manifests' } }, 400);\n }\n if (Object.hasOwn(body, 'name')) {\n return c.json({ ok: false, error: { message: 'name is not supported; edit IDENTITY.md' } }, 400);\n }\n if (Object.hasOwn(body, 'description')) {\n return c.json({ ok: false, error: { message: 'description is not supported; edit IDENTITY.md' } }, 400);\n }\n const skillsPatch =\n body.skills === null\n ? null\n : Array.isArray(body.skills)\n ? body.skills.map((x: unknown) => String(x).trim()).filter(Boolean)\n : undefined;\n const extendsPatch = Object.hasOwn(body, 'extends')\n ? Array.isArray(body.extends)\n ? body.extends.map((x: unknown) => String(x).trim()).filter(Boolean)\n : undefined\n : undefined;\n if (Object.hasOwn(body, 'extends') && extendsPatch === undefined) {\n return c.json({ ok: false, error: { message: 'extends must be an array' } }, 400);\n }\n let toolsPatch: CreateAgentBody['tools'] | null | undefined;\n if (Object.hasOwn(body, 'tools')) {\n if (body.tools === null) {\n toolsPatch = null;\n } else if (typeof body.tools === 'object' && !Array.isArray(body.tools)) {\n const parsedTools = ToolPolicySetSchema.safeParse(body.tools);\n if (!parsedTools.success) {\n return c.json({ ok: false, error: { message: `tools ${parsedTools.error.issues[0]?.message ?? 'is invalid'}` } }, 400);\n }\n toolsPatch = parsedTools.data;\n } else {\n return c.json({ ok: false, error: { message: 'tools must be an object or null' } }, 400);\n }\n }\n const modelsPatch = Object.hasOwn(body, 'models') ? parsePatchModels(body.models) : undefined;\n if (isParseError(modelsPatch)) {\n return c.json({ ok: false, error: { message: modelsPatch.error } }, 400);\n }\n let memoryPatch: Config['agents']['list'][number]['memory'] | undefined;\n if (Object.hasOwn(body, 'memory')) {\n const parsedMemory = MemoryPolicySchema.safeParse(body.memory);\n if (!parsedMemory.success) {\n return c.json({ ok: false, error: { message: `memory ${parsedMemory.error.issues[0]?.message ?? 'is invalid'}` } }, 400);\n }\n memoryPatch = parsedMemory.data;\n }\n\n const prep = prepareUpdateAgent(service.currentConfig as Config, id, {\n workspace: typeof body.workspace === 'string' ? body.workspace : undefined,\n ...(extendsPatch !== undefined ? { extends: extendsPatch } : {}),\n ...(modelsPatch !== undefined ? { models: modelsPatch } : {}),\n setDefault: body.setDefault === true,\n ...(skillsPatch !== undefined ? { skills: skillsPatch } : {}),\n ...(toolsPatch !== undefined ? { tools: toolsPatch } : {}),\n ...(memoryPatch !== undefined ? { memory: memoryPatch } : {}),\n });\n if (prep.ok === false) {\n return c.json({ ok: false, error: { message: prep.error } }, prep.status ?? 400);\n }\n const save = await service.saveConfig(prep.data.nextConfig);\n if (!save.saved) {\n return c.json({ ok: false, error: { message: save.error ?? 'save failed' } }, 500);\n }\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const agentsPayload = await listGatewayAgents(service.currentConfig as Config, { locale });\n return c.json({ ok: true, payload: agentsPayload });\n });\n\n authenticated.delete('/api/agents/:id', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const purge = c.req.query('purge') === '1' || c.req.query('purge') === 'true';\n const prep = prepareDeleteAgent(service.currentConfig as Config, id);\n if (prep.ok === false) {\n return c.json({ ok: false, error: { message: prep.error } }, prep.status ?? 400);\n }\n const { nextConfig, agentId } = prep.data;\n const save = await service.saveConfig(nextConfig);\n if (!save.saved) {\n return c.json({ ok: false, error: { message: save.error ?? 'save failed' } }, 500);\n }\n if (purge) {\n await runAfterDeletePurge(service.currentConfig as Config, agentId);\n }\n const locale = c.req.query('locale') || c.req.header('Accept-Language')?.split(',')[0]?.trim();\n const agentsPayload = await listGatewayAgents(service.currentConfig as Config, { locale });\n return c.json({\n ok: true,\n payload: { agentId, purged: purge, agents: agentsPayload },\n });\n });\n\n authenticated.get('/api/agents/:id/avatar', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = await readAgentAvatarFile(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return new Response(res.data.buffer, {\n status: 200,\n headers: {\n 'Content-Type': res.data.contentType,\n 'Cache-Control': 'private, max-age=3600',\n },\n });\n });\n\n authenticated.put('/api/agents/:id/avatar', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n let body: Record<string, unknown> = {};\n try {\n body = (await c.req.json()) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const base64 = typeof body.base64 === 'string' ? body.base64 : '';\n const mimeType = typeof body.mimeType === 'string' ? body.mimeType : '';\n const res = await writeAgentAvatarFromBase64(service.currentConfig as Config, id, base64, mimeType);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId } });\n });\n\n authenticated.delete('/api/agents/:id/avatar', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = await deleteAgentAvatarFile(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId } });\n });\n\n authenticated.get('/api/agents/:id/files', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const res = await listAgentProfileFiles(service.currentConfig as Config, id);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: res.data });\n });\n\n authenticated.get('/api/agents/:id/files/:name', async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const name = decodeURIComponent(c.req.param('name') ?? '');\n const res = await readAgentProfileFile(service.currentConfig as Config, id, name);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId, name, content: res.data.content } });\n });\n\n authenticated.put('/api/agents/:id/files/:name', strictRateLimitMiddleware, async (c) => {\n const id = normalizeAgentId(c.req.param('id') ?? '');\n const name = decodeURIComponent(c.req.param('name') ?? '');\n let content = '';\n try {\n const body = (await c.req.json()) as { content?: unknown };\n content = typeof body.content === 'string' ? body.content : '';\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const res = await writeAgentProfileFile(service.currentConfig as Config, id, name, content);\n if (res.ok === false) {\n return c.json({ ok: false, error: { message: res.error } }, res.status ?? 400);\n }\n return c.json({ ok: true, payload: { agentId: res.data.agentId, name } });\n });\n\n // GET /api/voice/models - Get available STT/TTS models\n authenticated.get('/api/voice/models', (c) => {\n const models = getVoiceModelsConfig();\n return c.json({ ok: true, payload: { models } });\n });\n\n authenticated.get('/api/image/capabilities', async (c) => {\n const config = service.currentConfig as Config;\n const imageGenerationProviders = await resolveImageGenerationCapabilities(config);\n const imageUnderstandingProviders = await resolveImageUnderstandingCapabilities(config);\n return c.json({\n ok: true,\n payload: {\n current: {\n imageModel: null,\n imageModelFallbacks: [],\n imageGenerationModel: null,\n imageGenerationModelFallbacks: [],\n mediaMaxMb: null,\n },\n imageGeneration: { providers: imageGenerationProviders },\n imageUnderstanding: { providers: imageUnderstandingProviders },\n },\n });\n });\n\n authenticated.post('/api/image/validate-model', strictRateLimitMiddleware, async (c) => {\n let body: { modelRef?: unknown };\n try {\n body = (await c.req.json()) as { modelRef?: unknown };\n } catch {\n return c.json({ ok: false, error: 'Invalid JSON' }, 400);\n }\n const modelRef = body.modelRef;\n if (!modelRef || typeof modelRef !== 'string') {\n return c.json({ ok: false, error: 'modelRef is required' }, 400);\n }\n\n const parsed = parseModelRef(modelRef);\n if (!parsed) {\n return c.json({\n ok: true,\n payload: {\n valid: false,\n reason: 'invalid_format',\n message: 'Model reference must be in \"provider/model\" format',\n },\n });\n }\n\n const configured = await isProviderConfigured(parsed.provider);\n if (!configured) {\n return c.json({\n ok: true,\n payload: {\n valid: false,\n reason: 'provider_not_configured',\n message: `Provider \"${parsed.provider}\" is not configured. Set the API key first.`,\n provider: parsed.provider,\n },\n });\n }\n\n try {\n resolveModel(modelRef);\n } catch {\n return c.json({\n ok: true,\n payload: {\n valid: false,\n reason: 'model_not_found',\n message: `Model not found in registry: ${modelRef}`,\n provider: parsed.provider,\n model: parsed.model,\n },\n });\n }\n\n return c.json({\n ok: true,\n payload: {\n valid: true,\n provider: parsed.provider,\n model: parsed.model,\n },\n });\n });\n\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `PATCH /api/config` — tail sections that are each <50 lines:
|
|
3
|
-
* update /
|
|
3
|
+
* update / goals / session / gateway.{skillsMarketplaceProvider,
|
|
4
4
|
* skillsStoreBaseUrl} / providers / providersConfig / stt / tts / tools /
|
|
5
5
|
* tunnel / bindings / mcp.
|
|
6
6
|
*
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { BindingsConfigSchema, BrowserConfigSchema, McpConfigSchema, init_schema } from "../../../../config/schema.js";
|
|
2
2
|
import { CredentialResolver, init_credentials } from "../../../../auth/credentials.js";
|
|
3
3
|
import { canonicalizeConfiguredMcpServer } from "../../../../config/mcp-config-normalize.js";
|
|
4
|
-
import {
|
|
4
|
+
import { setTuiDefaultAgentConfig } from "../../../../commands/agents.config.js";
|
|
5
|
+
import { mergeGatewaySkillsMarketplacePatch, mergeGoalsConfigPatch, mergeSessionConfigPatch, mergeUpdateConfigPatch } from "../../../../config/web-patch.js";
|
|
5
6
|
import { assertGatewayAuthConfigured, resolveGatewayAuth } from "../../../auth.js";
|
|
6
7
|
import { isMaskedSecretPatchValue } from "../../lib/mask-secret-length.js";
|
|
7
8
|
import { applyToolsWebPatch } from "../../../config-tools-web.js";
|
|
@@ -17,11 +18,6 @@ async function applyMiscPatch(config, body) {
|
|
|
17
18
|
const updateResult = mergeUpdateConfigPatch(config, body.update);
|
|
18
19
|
if (updateResult.ok === false) return patchError(updateResult.message);
|
|
19
20
|
}
|
|
20
|
-
if (body.cron !== void 0) {
|
|
21
|
-
if (typeof body.cron !== "object" || body.cron === null || Array.isArray(body.cron)) return patchError("cron must be an object");
|
|
22
|
-
const cronResult = mergeCronConfigPatch(config, body.cron);
|
|
23
|
-
if (cronResult.ok === false) return patchError(cronResult.message);
|
|
24
|
-
}
|
|
25
21
|
if (body.goals !== void 0) {
|
|
26
22
|
if (typeof body.goals !== "object" || body.goals === null || Array.isArray(body.goals)) return patchError("goals must be an object");
|
|
27
23
|
const goalsResult = mergeGoalsConfigPatch(config, body.goals);
|
|
@@ -32,6 +28,16 @@ async function applyMiscPatch(config, body) {
|
|
|
32
28
|
const sessionResult = mergeSessionConfigPatch(config, body.session);
|
|
33
29
|
if (sessionResult.ok === false) return patchError(sessionResult.message);
|
|
34
30
|
}
|
|
31
|
+
if (body.tui !== void 0) {
|
|
32
|
+
if (typeof body.tui !== "object" || body.tui === null || Array.isArray(body.tui)) return patchError("tui must be an object");
|
|
33
|
+
const tuiPatch = body.tui;
|
|
34
|
+
if (tuiPatch.defaultAgent !== void 0) {
|
|
35
|
+
if (typeof tuiPatch.defaultAgent !== "string" || !tuiPatch.defaultAgent.trim()) return patchError("tui.defaultAgent must be a non-empty string");
|
|
36
|
+
const result = setTuiDefaultAgentConfig(config, tuiPatch.defaultAgent);
|
|
37
|
+
if (result.ok === false) return patchError(result.message);
|
|
38
|
+
config.tui = result.config.tui;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
35
41
|
if (body.browser !== void 0) {
|
|
36
42
|
if (typeof body.browser !== "object" || body.browser === null || Array.isArray(body.browser)) return patchError("browser must be an object");
|
|
37
43
|
const parsed = BrowserConfigSchema.safeParse(body.browser);
|