@xopcai/xopc 0.0.117 → 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 +26 -24
- package/README.zh-CN.md +46 -42
- 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-BBLhJ2C6.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-DdDx0V4z.js → apps-page-DU0dz9Zo.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DZsVqMhU.js → archive-plugin-BkVIgZzA.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CIol6JWX.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-B3UauMfp.js → binary-plugins-B4TO_bsn.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-2HJoFchH.js → block-editor-DJRWwWNI.js} +6 -6
- 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-DX5WRE_t.js → extension-debug-page-DYh402XV.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Buah7Bw-.js → extension-page-Cr_TizrN.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DuroLVnf.js → extension-settings-page-BU1KoKRj.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B5zdl27C.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-gT4ZhE7h.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-B3kL8KGY.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-AR-fVh0P.js → goals-config-api-DqxVi0p5.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-Cpb21ezg.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-DefCgF4o.js → logs-page-DLXPcksQ.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-ChbR9LGO.js → markdown-split-CpHxbtWJ.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-B82oP80n.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-CDknITM3.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-DV3xQsWB.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-BODCXnvY.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-qtfEI6QM.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-BHZKjVcS.js → settings-collapsible-section-BouO6JTi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-5i35D-J1.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-B0H63tDv.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-BCjP_VHb.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-CeEevm7z.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-BlF9V05n.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 +6 -9
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +0 -2
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/background-review/prompts.d.ts +2 -2
- package/dist/src/agent/background-review/prompts.js +2 -2
- package/dist/src/agent/background-review/prompts.js.map +1 -1
- package/dist/src/agent/background-review/settings.d.ts +1 -1
- package/dist/src/agent/background-review/settings.js +7 -8
- package/dist/src/agent/background-review/settings.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
- package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
- package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +17 -16
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/types.d.ts +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/context/workspace.d.ts +4 -2
- package/dist/src/agent/context/workspace.js +5 -4
- package/dist/src/agent/context/workspace.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.js +106 -15
- 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 +10 -11
- 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/memory/builtin-memory-store.d.ts +4 -2
- package/dist/src/agent/memory/builtin-memory-store.js +11 -6
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.js +36 -7
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
- package/dist/src/agent/memory/candidate-extractor.js +60 -0
- package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
- package/dist/src/agent/memory/manager.d.ts +2 -1
- package/dist/src/agent/memory/manager.js +27 -3
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.js +3 -0
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
- package/dist/src/agent/memory/types.d.ts +27 -4
- 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/memory/index.d.ts +4 -2
- package/dist/src/agent/prompt/memory/index.js +18 -12
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.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 +4 -31
- 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/reply/post-compaction-context.js +1 -3
- package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
- package/dist/src/agent/reply/startup-context.js +1 -5
- package/dist/src/agent/reply/startup-context.js.map +1 -1
- package/dist/src/agent/service.d.ts +4 -12
- package/dist/src/agent/service.js +10 -48
- 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/curated-memory-tool.js +57 -2
- package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
- 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/tools/web-extract.js +6 -8
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent-manifest/index.js +2 -2
- package/dist/src/agent-manifest/resolver.d.ts +4 -2
- package/dist/src/agent-manifest/resolver.js +6 -3
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +238 -0
- package/dist/src/agent-manifest/schema.js +16 -5
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/agent-manifest/validator.d.ts +3 -2
- package/dist/src/agent-manifest/validator.js +2 -1
- package/dist/src/agent-manifest/validator.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/pipeline.d.ts +1 -1
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/channels/plugin-types.d.ts +3 -0
- package/dist/src/chat-commands/agent-edit.js +0 -1
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/model.js +2 -2
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- 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.d.ts +1 -1
- package/dist/src/cli/command-manifest.js +1 -5
- 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/checks/provider-auth.js +1 -0
- package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +0 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
- 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 +33 -14
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/models.js +13 -31
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.js +17 -10
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +2 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/tui.js +26 -4
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +10 -5
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/registry.js +1 -1
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/cli/templates.d.ts +1 -1
- package/dist/src/cli/templates.js +1 -11
- package/dist/src/cli/templates.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 +42 -12
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +5 -3
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.js +3 -5
- 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 +8 -10
- package/dist/src/config/paths.js +16 -16
- 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 +45 -44
- package/dist/src/config/schema.js +68 -52
- 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 +8 -0
- package/dist/src/gateway/agents-admin.js +63 -34
- 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/chat-stream/mapper.js +9 -2
- package/dist/src/gateway/chat-stream/mapper.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/global-defaults-admin.d.ts +36 -0
- package/dist/src/gateway/global-defaults-admin.js +146 -0
- package/dist/src/gateway/global-defaults-admin.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 +33 -1
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
- package/dist/src/gateway/hono/routes/commands-skills.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/global-defaults.d.ts +3 -0
- package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
- package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
- 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 +21 -9
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +75 -4
- package/dist/src/gateway/hono/routes/memory.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/models.js +1 -1
- 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/marketplace-service.d.ts +4 -4
- package/dist/src/gateway/service/marketplace-service.js +11 -7
- package/dist/src/gateway/service/marketplace-service.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 +27 -2
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/index.d.ts +4 -5
- package/dist/src/providers/index.js +16 -16
- package/dist/src/providers/index.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/session-workspace.js +2 -7
- package/dist/src/session/session-workspace.js.map +1 -1
- package/dist/src/session/store.js +0 -5
- package/dist/src/session/store.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 +1 -3
- package/dist/src/storage/sqlite/index.js +2 -4
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/memory-index-repository.js +15 -14
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +44 -1
- package/dist/src/storage/sqlite/memory-records-repository.js +164 -20
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
- package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
- 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 +9 -0
- package/dist/src/tui/backends/embedded-backend.js +55 -27
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +4 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +30 -3
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/tui-header.d.ts +0 -1
- package/dist/src/tui/components/tui-header.js +3 -8
- package/dist/src/tui/components/tui-header.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-startup-resources.js +2 -1
- package/dist/src/tui/tui-startup-resources.js.map +1 -1
- package/dist/src/tui/tui-startup-text.js +12 -12
- package/dist/src/tui/tui-startup-text.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 +11 -3
- 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-C6xgagZd.js +0 -71
- package/dist/gateway/static/root/assets/app-management-settings-panel-CBpLONvG.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-CGcc54yj.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-CUOO-PQk.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-XQoMTI0A.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CfqF-kGr.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BYyRzsex.js +0 -1
- package/dist/gateway/static/root/assets/cn-JdwAhgNB.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DIvEz4NX.js +0 -2
- package/dist/gateway/static/root/assets/createLucideIcon-DPHK1VkS.js +0 -1
- package/dist/gateway/static/root/assets/cron-api-R41aQCX9.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-nCMWCf0p.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-D97nFqQD.js +0 -3
- package/dist/gateway/static/root/assets/dreaming-settings-Bceaw1PG.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-Dn_QKIqb.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-iISWAZRm.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-DCUROLMQ.js +0 -1
- package/dist/gateway/static/root/assets/goals-settings-CPAuFwoD.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-D7bKFEeO.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CC69vNx0.js +0 -1
- package/dist/gateway/static/root/assets/index-CwhK8qCh.js +0 -122
- package/dist/gateway/static/root/assets/index-CyfhARL-.css +0 -1
- package/dist/gateway/static/root/assets/interval-presets-0DtsnxE0.js +0 -1
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BPREtN8B.js +0 -1
- package/dist/gateway/static/root/assets/messages-Cf1O9JB0.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DmKiIihT.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-CxxfLRJZ.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-X2slSx7V.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BvmUWqgu.js +0 -1
- package/dist/gateway/static/root/assets/schedule-field-CgJSCD3B.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B0yESuuL.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-q2M8RKOo.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CGozabLD.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-FoOSe6nU.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-Cy5zWyYQ.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DaZNFro9.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CnwtUzvw.js +0 -2
- package/dist/gateway/static/root/assets/system-settings-panel-DXs2VmBt.js +0 -1
- package/dist/gateway/static/root/assets/typed-models-lib-4gPuydz_.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DvKiOglO.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CAVZcONQ.js +0 -18
- package/dist/src/agent/context/workspace-templates/USER.md +0 -24
- 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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { getDefaultModelSync, init_providers, resolveModel } from "../providers/index.js";
|
|
4
|
+
import { publishAutomationProductEvent } from "../automations/product-events.js";
|
|
4
5
|
import { buildNoteAttachmentRef } from "./attachment-ref.js";
|
|
5
6
|
import { parseNoteMarkdown } from "./note-markdown.js";
|
|
6
7
|
import { NotesStore } from "./store.js";
|
|
@@ -33,6 +34,22 @@ function splitMeaningfulLines(markdown) {
|
|
|
33
34
|
function summarizeIdea(markdown) {
|
|
34
35
|
return splitMeaningfulLines(markdown).slice(0, 3).join(";").slice(0, 140);
|
|
35
36
|
}
|
|
37
|
+
function publishNoteEvent(type, note, extra) {
|
|
38
|
+
publishAutomationProductEvent({
|
|
39
|
+
type,
|
|
40
|
+
source: "notes",
|
|
41
|
+
payload: {
|
|
42
|
+
noteId: note.id,
|
|
43
|
+
kind: note.kind,
|
|
44
|
+
status: note.status,
|
|
45
|
+
title: note.title,
|
|
46
|
+
capturedVia: note.capturedVia,
|
|
47
|
+
tagCount: note.tags?.length ?? 0,
|
|
48
|
+
hasAttachments: Boolean(note.attachments?.length),
|
|
49
|
+
...extra
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
36
53
|
function inferCatalysisStage(note) {
|
|
37
54
|
const text = `${note.title ?? ""}\n${note.markdown}`;
|
|
38
55
|
if (/上线|发布|launch|ship/i.test(text)) return "shipped";
|
|
@@ -108,7 +125,9 @@ function buildCatalysisPrompt(note) {
|
|
|
108
125
|
return `请把下面的 Markdown 笔记催化成可执行的想法报告,输出 JSON:\n{\n "title": string,\n "valueHypothesis": string,\n "targetUsers": string[],\n "keyQuestions": string[],\n "mvpPath": string[],\n "risks": string[],\n "nextActions": [{"text": string, "kind": "task"|"workflow"|"research"|"share"|"chat"}],\n "confidence": number\n}\n\n标题:${note.title?.trim() || "未命名笔记"}\n\nMarkdown:\n${note.markdown.trim() || "(无正文)"}`;
|
|
109
126
|
}
|
|
110
127
|
async function buildAiCatalysisReport(note, config) {
|
|
111
|
-
const
|
|
128
|
+
const modelRef = getDefaultModelSync(config);
|
|
129
|
+
if (!modelRef) throw new Error("No global default model configured");
|
|
130
|
+
const response = await complete(resolveModel(modelRef), { messages: [{
|
|
112
131
|
role: "user",
|
|
113
132
|
content: buildCatalysisPrompt(note),
|
|
114
133
|
timestamp: Date.now()
|
|
@@ -172,6 +191,7 @@ var NotesService = class {
|
|
|
172
191
|
localVersion: 1
|
|
173
192
|
};
|
|
174
193
|
await this.store.addNote(note);
|
|
194
|
+
publishNoteEvent("note.created", note);
|
|
175
195
|
log.debug({
|
|
176
196
|
id: note.id,
|
|
177
197
|
kind: note.kind
|
|
@@ -193,7 +213,12 @@ var NotesService = class {
|
|
|
193
213
|
normalizedPatch.localVersion = patch.localVersion ?? (existing.localVersion ?? 1) + 1;
|
|
194
214
|
}
|
|
195
215
|
const updatedRaw = await this.store.updateNote(id, normalizedPatch);
|
|
196
|
-
|
|
216
|
+
const updated = updatedRaw ? await this.reconcileAttachments(updatedRaw) : null;
|
|
217
|
+
if (updated) publishNoteEvent("note.updated", updated, {
|
|
218
|
+
contentTouched,
|
|
219
|
+
trigger
|
|
220
|
+
});
|
|
221
|
+
return updated;
|
|
197
222
|
}
|
|
198
223
|
async reconcileAttachments(note) {
|
|
199
224
|
const { kept, removed } = partitionAttachmentsByReference(note);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../../../src/notes/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../providers/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteAttachmentRef } from './attachment-ref.js';\nimport { partitionAttachmentsByReference } from './note-attachment-sync.js';\nimport { parseNoteMarkdown } from './note-markdown.js';\nimport { buildNoteAgentContextArtifact, getCachedNoteAgentContextArtifact } from './agent-context.js';\nimport { NotesStore } from './store.js';\nimport type {\n CaptureSource,\n CreateNoteParams,\n Note,\n NoteAiPatch,\n NoteAttachment,\n NoteCatalysisAction,\n NoteCatalysisMeta,\n NoteCatalysisReport,\n NoteIndexEntry,\n NoteKind,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesService');\nconst MAX_SNAPSHOTS_PER_NOTE = 50;\nconst SNAPSHOT_THROTTLE_MS = 60_000;\n\nfunction inferKind(markdown?: string, hasAttachments?: boolean, attachments?: NoteAttachment[]): NoteKind {\n if (hasAttachments && attachments?.length && attachments.every((item) => item.type === 'audio')) return 'voice';\n if (hasAttachments) return 'media';\n if (!markdown) return 'thought';\n const lower = markdown.toLowerCase();\n if (/^(todo|task|remind|buy|call|email|meet|finish|submit|send)\\b/i.test(lower) || /\\b(明天|今天|记得|别忘|待办|提醒)\\b/.test(markdown)) return 'todo';\n if (/^https?:\\/\\//.test(markdown.trim())) return 'bookmark';\n return 'thought';\n}\n\nfunction deriveDefaultTitle(markdown?: string): string | undefined {\n const normalized = parseNoteMarkdown(markdown ?? '').plainText.trim().replace(/\\s+/g, ' ');\n return normalized ? Array.from(normalized).slice(0, 10).join('') : undefined;\n}\n\nfunction splitMeaningfulLines(markdown?: string): string[] {\n return parseNoteMarkdown(markdown ?? '').plainText.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n}\n\nfunction summarizeIdea(markdown?: string): string {\n const lines = splitMeaningfulLines(markdown);\n return lines.slice(0, 3).join(';').slice(0, 140);\n}\n\nfunction inferCatalysisStage(note: Note): NonNullable<NoteCatalysisMeta['stage']> {\n const text = `${note.title ?? ''}\\n${note.markdown}`;\n if (/上线|发布|launch|ship/i.test(text)) return 'shipped';\n if (/验证|访谈|用户|测试|validate/i.test(text)) return 'validating';\n if (/开发|实现|构建|build|mvp/i.test(text)) return 'developing';\n if (/想法|机会|问题|idea|seed/i.test(text)) return 'seed';\n return 'incubating';\n}\n\nfunction buildCatalysisReport(note: Note): NoteCatalysisReport {\n const summary = summarizeIdea(note.markdown || note.title);\n const title = note.title?.trim() || summary.slice(0, 28) || '未命名想法';\n const actions: NoteCatalysisAction[] = [\n { kind: 'research', text: `验证「${title}」的真实需求和目标用户` },\n { kind: 'task', text: `拆解「${title}」的最小可行下一步` },\n { kind: 'chat', text: `继续和 AI 讨论「${title}」的方案` },\n ];\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title,\n valueHypothesis: summary || '这条笔记可能包含一个待澄清的想法。',\n targetUsers: ['待确认的核心用户'],\n keyQuestions: ['用户为什么现在需要它?', '最小可验证版本是什么?', '如何判断它值得继续投入?'],\n mvpPath: ['定义目标用户', '写出最小场景', '完成一次验证'],\n risks: ['需求不够明确', '执行路径过大'],\n nextActions: actions,\n confidence: summary ? 0.58 : 0.35,\n };\n}\n\nfunction normalizeAiCatalysisReport(note: Note, data: Record<string, unknown>): NoteCatalysisReport {\n const fallback = buildCatalysisReport(note);\n const stringArray = (value: unknown, fallbackValue: string[]) => Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string').slice(0, 12) : fallbackValue;\n const actions = Array.isArray(data.nextActions)\n ? data.nextActions.map((item): NoteCatalysisAction | null => {\n if (!item || typeof item !== 'object') return null;\n const row = item as { kind?: unknown; text?: unknown };\n const kind = row.kind === 'task' || row.kind === 'workflow' || row.kind === 'research' || row.kind === 'share' || row.kind === 'chat' ? row.kind : 'task';\n return typeof row.text === 'string' && row.text.trim() ? { kind, text: row.text.trim() } : null;\n }).filter((item): item is NoteCatalysisAction => Boolean(item)).slice(0, 12)\n : fallback.nextActions;\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title: typeof data.title === 'string' && data.title.trim() ? data.title.trim() : fallback.title,\n valueHypothesis: typeof data.valueHypothesis === 'string' && data.valueHypothesis.trim() ? data.valueHypothesis.trim() : fallback.valueHypothesis,\n targetUsers: stringArray(data.targetUsers, fallback.targetUsers),\n keyQuestions: stringArray(data.keyQuestions, fallback.keyQuestions),\n mvpPath: stringArray(data.mvpPath, fallback.mvpPath),\n risks: stringArray(data.risks, fallback.risks),\n nextActions: actions,\n confidence: typeof data.confidence === 'number' ? Math.max(0, Math.min(1, data.confidence)) : fallback.confidence,\n };\n}\n\nfunction buildCatalysisPrompt(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const markdown = note.markdown.trim() || '(无正文)';\n return `请把下面的 Markdown 笔记催化成可执行的想法报告,输出 JSON:\\n{\\n \"title\": string,\\n \"valueHypothesis\": string,\\n \"targetUsers\": string[],\\n \"keyQuestions\": string[],\\n \"mvpPath\": string[],\\n \"risks\": string[],\\n \"nextActions\": [{\"text\": string, \"kind\": \"task\"|\"workflow\"|\"research\"|\"share\"|\"chat\"}],\\n \"confidence\": number\\n}\\n\\n标题:${title}\\n\\nMarkdown:\\n${markdown}`;\n}\n\nasync function buildAiCatalysisReport(note: Note, config?: Config): Promise<NoteCatalysisReport> {\n const modelRef = getDefaultModelSync(config) ?? 'openai/gpt-5.5';\n const resolved = resolveModel(modelRef);\n const messages: UserMessage[] = [{ role: 'user', content: buildCatalysisPrompt(note), timestamp: Date.now() }];\n const response = await complete(resolved, { messages }, { temperature: 0.2 });\n let responseText = '';\n if (Array.isArray(response.content)) {\n for (const part of response.content) {\n if (part && typeof part === 'object' && (part as { type?: string }).type === 'text') {\n responseText += String((part as { text?: string }).text || '');\n }\n }\n }\n const raw = responseText.trim().replace(/^```json\\s*/i, '').replace(/```$/i, '').trim();\n return normalizeAiCatalysisReport(note, JSON.parse(raw) as Record<string, unknown>);\n}\n\nexport class NotesService {\n private lastSnapshotAt = new Map<string, number>();\n\n constructor(private readonly store = new NotesStore()) {}\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n }\n\n async quickCapture(markdown: string, source: CaptureSource): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const note: Note = {\n id,\n title: deriveDefaultTitle(markdown),\n kind: inferKind(markdown),\n status: 'inbox',\n markdown,\n createdAt: now,\n updatedAt: now,\n capturedVia: source,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Quick capture');\n return note;\n }\n\n async createNote(params: CreateNoteParams): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const markdown = params.markdown ?? '';\n const note: Note = {\n id,\n title: params.title ?? deriveDefaultTitle(markdown),\n kind: params.kind ?? inferKind(markdown),\n status: 'inbox',\n markdown,\n attachments: [],\n createdAt: now,\n updatedAt: now,\n capturedVia: params.capturedVia,\n tags: params.tags,\n pinned: params.pinned,\n groupId: params.groupId,\n taskMeta: params.taskMeta,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Note created');\n return note;\n }\n\n async getNote(id: string): Promise<Note | null> {\n return this.store.getNote(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>, trigger: SnapshotTrigger = 'edit'): Promise<Note | null> {\n const existing = await this.store.getNote(id);\n if (!existing) return null;\n const contentTouched = patch.markdown !== undefined || patch.title !== undefined;\n if (contentTouched) await this.maybeSaveSnapshot(existing, trigger);\n\n const normalizedPatch: Partial<Note> = { ...patch };\n if (patch.markdown !== undefined) {\n normalizedPatch.kind = patch.kind ?? inferKind(patch.markdown, Boolean(existing.attachments?.length), existing.attachments);\n }\n if (contentTouched || patch.attachments) {\n normalizedPatch.remoteVersion = (existing.remoteVersion ?? 1) + 1;\n normalizedPatch.localVersion = patch.localVersion ?? (existing.localVersion ?? 1) + 1;\n }\n\n const updatedRaw = await this.store.updateNote(id, normalizedPatch);\n return updatedRaw ? this.reconcileAttachments(updatedRaw) : null;\n }\n\n private async reconcileAttachments(note: Note): Promise<Note> {\n const { kept, removed } = partitionAttachmentsByReference(note);\n if (removed.length === 0) return note;\n for (const attachment of removed) await this.store.deleteAttachmentFile(note.id, attachment.relativePath);\n log.debug({ noteId: note.id, removedIds: removed.map((attachment) => attachment.id) }, 'Pruned orphan note attachments');\n const hasAttachments = kept.length > 0;\n const updated = await this.store.updateNote(note.id, { attachments: kept, kind: inferKind(note.markdown, hasAttachments, kept) });\n return updated ?? { ...note, attachments: kept };\n }\n\n async syncNote(id: string, patch: Partial<Note>, baseRemoteVersion?: number): Promise<{ note: Note | null; conflict: boolean }> {\n const existing = await this.store.getNote(id);\n if (!existing) return { note: null, conflict: false };\n if (baseRemoteVersion !== undefined && existing.remoteVersion !== undefined && baseRemoteVersion < existing.remoteVersion) {\n return { note: existing, conflict: true };\n }\n const updated = await this.updateNote(id, patch, 'sync');\n return { note: updated, conflict: false };\n }\n\n async createAiEditPatch(id: string, instruction: string, markdownOverride?: string): Promise<{ message: string; patch: NoteAiPatch } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const source = markdownOverride ?? note.markdown;\n const parsed = parseNoteMarkdown(source, id);\n const wantsTodos = /待办|todo|task|行动|提醒/i.test(instruction);\n const wantsSummary = /摘要|总结|summary|压缩/i.test(instruction);\n let generated = '';\n if (wantsTodos) {\n const lines = source.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n generated = (lines.length ? lines : [parsed.plainText]).slice(0, 12).map((line) => `- [ ] ${line.replace(/^[-*\\d.\\s\\[\\]x]+/i, '').trim()}`).join('\\n');\n } else if (wantsSummary) {\n generated = `> [!SUMMARY]\\n> ${parsed.plainText.slice(0, 220)}`;\n } else {\n generated = `${source.trimEnd()}\\n\\n## AI 整理\\n\\n${instruction.trim()}`;\n }\n return {\n message: 'AI edit patch generated',\n patch: {\n id: randomUUID(),\n summary: instruction,\n operations: [{ type: 'replaceRange', from: 0, to: source.length, markdown: generated || source }],\n },\n };\n }\n\n async catalyzeNote(id: string, config?: Config): Promise<{ note: Note; report: NoteCatalysisReport } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n let report: NoteCatalysisReport;\n try {\n report = await buildAiCatalysisReport(note, config);\n } catch (err) {\n log.warn({ err, noteId: id }, 'AI note catalysis failed; using local fallback report');\n report = buildCatalysisReport(note);\n }\n const updated = await this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: 'catalyzed',\n stage: inferCatalysisStage(note),\n lastCatalyzedAt: Date.now(),\n confidence: report.confidence,\n report,\n ...note.aiDeep?.catalysis,\n },\n },\n ai: { ...note.ai, intent: note.ai?.intent ?? 'idea', summary: note.ai?.summary ?? report.valueHypothesis },\n status: note.status === 'inbox' ? 'processed' : note.status,\n }, 'ai_edit');\n return updated ? { note: updated, report } : null;\n }\n\n async recordCatalysisFeedback(id: string, feedback: 'helpful' | 'not_helpful' | 'neutral'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return this.updateNote(id, { aiDeep: { ...note.aiDeep, processedAt: Date.now(), catalysis: { status: note.aiDeep?.catalysis?.status ?? 'catalyzed', ...note.aiDeep?.catalysis, feedback } } });\n }\n\n async linkNoteThread(id: string, sessionKey: string): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const existingKeys = note.aiDeep?.catalysis?.linkedSessionKeys ?? [];\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'none',\n ...note.aiDeep?.catalysis,\n sourceSessionKey: note.aiDeep?.catalysis?.sourceSessionKey ?? sessionKey,\n linkedSessionKeys: Array.from(new Set([...existingKeys, sessionKey])),\n },\n },\n }, 'sync');\n }\n\n async listNoteThreads(id: string): Promise<string[] | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return Array.from(new Set([note.aiDeep?.catalysis?.sourceSessionKey, ...(note.aiDeep?.catalysis?.linkedSessionKeys ?? [])].filter((key): key is string => Boolean(key))));\n }\n\n async getAgentContextStatus(id: string, config?: Config, force = false): Promise<{ noteUpdatedAt: number; artifact: import('./agent-context.js').NoteAgentContextArtifact | null; stale: boolean } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const cached = getCachedNoteAgentContextArtifact(id);\n if (!force && cached && cached.noteUpdatedAt === note.updatedAt) {\n return { noteUpdatedAt: note.updatedAt, artifact: cached, stale: false };\n }\n const artifact = await buildNoteAgentContextArtifact({ note, notesService: this, config, force });\n return { noteUpdatedAt: note.updatedAt, artifact, stale: false };\n }\n\n async appendTextToNote(id: string, content: string, heading = 'AI 讨论沉淀'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const trimmed = content.trim();\n if (!trimmed) return note;\n const current = note.markdown.trimEnd();\n const nextMarkdown = `${current}${current ? '\\n\\n' : ''}## ${heading}\\n\\n${trimmed}\\n`;\n return this.updateNote(id, { markdown: nextMarkdown }, 'ai_edit');\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const removed = await this.store.deleteNote(id);\n if (removed) await this.store.deleteAllSnapshots(id);\n return removed;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean }> {\n return this.store.listNotes(query);\n }\n\n async addAttachment(noteId: string, file: { name: string; buffer: Buffer; mimeType: string; duration?: number }): Promise<NoteAttachment | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const { relativePath, size } = await this.store.saveAttachment(noteId, file.name, file.buffer);\n const attachment: NoteAttachment = {\n id: randomUUID(),\n type: file.mimeType.startsWith('image/') ? 'image' : file.mimeType.startsWith('audio/') ? 'audio' : file.mimeType.startsWith('video/') ? 'video' : 'file',\n mimeType: file.mimeType,\n fileName: file.name,\n size,\n relativePath,\n duration: file.duration,\n };\n const attachments = [...(note.attachments || []), attachment];\n const kind = note.kind === 'thought' && attachment.type === 'audio' ? 'voice' : note.kind === 'thought' ? 'media' : note.kind;\n await this.store.updateNote(noteId, { attachments, kind });\n return attachment;\n }\n\n async getAttachmentPath(noteId: string, attachmentId: string): Promise<{ filePath: string; mimeType: string; fileName: string } | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const attachment = note.attachments?.find((a) => a.id === attachmentId);\n if (!attachment) return null;\n return { filePath: this.store.resolveAttachmentPath(noteId, attachment.relativePath), mimeType: attachment.mimeType, fileName: attachment.fileName };\n }\n\n async listNoteHistory(noteId: string): Promise<NoteSnapshotEntry[]> { return this.store.listSnapshots(noteId); }\n async getNoteSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> { return this.store.getSnapshot(noteId, timestamp); }\n\n async restoreNoteSnapshot(noteId: string, timestamp: number): Promise<Note | null> {\n const snapshot = await this.store.getSnapshot(noteId, timestamp);\n const existing = await this.store.getNote(noteId);\n if (!snapshot || !existing) return null;\n await this.maybeSaveSnapshot(existing, 'restore');\n this.lastSnapshotAt.set(noteId, Date.now());\n await this.store.pruneSnapshots(noteId, MAX_SNAPSHOTS_PER_NOTE);\n return this.store.updateNote(noteId, { title: snapshot.title, markdown: snapshot.markdown, tags: snapshot.tags, kind: snapshot.kind, status: snapshot.status });\n }\n\n async flush(): Promise<void> { await this.store.flush(); }\n async moveToGroup(noteId: string, groupId: string | null): Promise<Note | null> { return this.updateNote(noteId, { groupId: groupId ?? undefined }); }\n\n async createTask(title: string, source: CaptureSource, opts: { dueAt?: number; priority?: 'high' | 'medium' | 'low'; sourceSessionKey?: string; sourceNoteId?: string; groupId?: string } = {}): Promise<Note> {\n return this.createNote({\n title,\n markdown: `- [ ] ${title}`,\n kind: 'task',\n capturedVia: source,\n groupId: opts.groupId,\n taskMeta: { done: false, dueAt: opts.dueAt, priority: opts.priority, sourceSessionKey: opts.sourceSessionKey, sourceNoteId: opts.sourceNoteId },\n });\n }\n\n async toggleTaskDone(noteId: string): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n const done = !note.taskMeta?.done;\n const markdown = note.markdown.replace(/^- \\[[ xX]\\]/m, `- [${done ? 'x' : ' '}]`);\n return this.updateNote(noteId, { markdown, taskMeta: { ...note.taskMeta, done } });\n }\n\n async updateTaskMeta(noteId: string, patch: Partial<import('./types.js').NoteTaskMeta>): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n return this.updateNote(noteId, { taskMeta: { ...note.taskMeta, done: note.taskMeta?.done ?? false, ...patch } });\n }\n\n async recordOpen(noteId: string): Promise<Note | null> {\n return this.updateNote(noteId, { lastOpenedAt: Date.now() } as Partial<Note>);\n }\n\n private async maybeSaveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n if (trigger !== 'edit') {\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n return;\n }\n const last = this.lastSnapshotAt.get(note.id) ?? 0;\n if (Date.now() - last < SNAPSHOT_THROTTLE_MS) return;\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n }\n}\n\nexport { buildNoteAttachmentRef };\n"],"mappings":";;;;;;;;;;;gBAK0E;aACxB;AAuBlD,MAAM,MAAM,aAAa,eAAe;AACxC,MAAM,yBAAyB;AAC/B,MAAM,uBAAuB;AAE7B,SAAS,UAAU,UAAmB,gBAA0B,aAA0C;AACxG,KAAI,kBAAkB,aAAa,UAAU,YAAY,OAAO,SAAS,KAAK,SAAS,QAAQ,CAAE,QAAO;AACxG,KAAI,eAAgB,QAAO;AAC3B,KAAI,CAAC,SAAU,QAAO;CACtB,MAAM,QAAQ,SAAS,aAAa;AACpC,KAAI,gEAAgE,KAAK,MAAM,IAAI,0BAA0B,KAAK,SAAS,CAAE,QAAO;AACpI,KAAI,eAAe,KAAK,SAAS,MAAM,CAAC,CAAE,QAAO;AACjD,QAAO;;AAGT,SAAS,mBAAmB,UAAuC;CACjE,MAAM,aAAa,kBAAkB,YAAY,GAAG,CAAC,UAAU,MAAM,CAAC,QAAQ,QAAQ,IAAI;AAC1F,QAAO,aAAa,MAAM,KAAK,WAAW,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,KAAA;;AAGrE,SAAS,qBAAqB,UAA6B;AACzD,QAAO,kBAAkB,YAAY,GAAG,CAAC,UAAU,MAAM,WAAW,CAAC,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC,OAAO,QAAQ;;AAGjH,SAAS,cAAc,UAA2B;AAEhD,QADc,qBAAqB,SACvB,CAAC,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI;;AAGlD,SAAS,oBAAoB,MAAqD;CAChF,MAAM,OAAO,GAAG,KAAK,SAAS,GAAG,IAAI,KAAK;AAC1C,KAAI,qBAAqB,KAAK,KAAK,CAAE,QAAO;AAC5C,KAAI,wBAAwB,KAAK,KAAK,CAAE,QAAO;AAC/C,KAAI,sBAAsB,KAAK,KAAK,CAAE,QAAO;AAC7C,KAAI,sBAAsB,KAAK,KAAK,CAAE,QAAO;AAC7C,QAAO;;AAGT,SAAS,qBAAqB,MAAiC;CAC7D,MAAM,UAAU,cAAc,KAAK,YAAY,KAAK,MAAM;CAC1D,MAAM,QAAQ,KAAK,OAAO,MAAM,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI;CAC5D,MAAM,UAAiC;EACrC;GAAE,MAAM;GAAY,MAAM,MAAM,MAAM;GAAc;EACpD;GAAE,MAAM;GAAQ,MAAM,MAAM,MAAM;GAAY;EAC9C;GAAE,MAAM;GAAQ,MAAM,aAAa,MAAM;GAAO;EACjD;AACD,QAAO;EACL,gBAAgB,KAAK;EACrB,aAAa,KAAK,KAAK;EACvB;EACA,iBAAiB,WAAW;EAC5B,aAAa,CAAC,WAAW;EACzB,cAAc;GAAC;GAAe;GAAe;GAAe;EAC5D,SAAS;GAAC;GAAU;GAAU;GAAS;EACvC,OAAO,CAAC,UAAU,SAAS;EAC3B,aAAa;EACb,YAAY,UAAU,MAAO;EAC9B;;AAGH,SAAS,2BAA2B,MAAY,MAAoD;CAClG,MAAM,WAAW,qBAAqB,KAAK;CAC3C,MAAM,eAAe,OAAgB,kBAA4B,MAAM,QAAQ,MAAM,GAAG,MAAM,QAAQ,SAAyB,OAAO,SAAS,SAAS,CAAC,MAAM,GAAG,GAAG,GAAG;CACxK,MAAM,UAAU,MAAM,QAAQ,KAAK,YAAY,GAC3C,KAAK,YAAY,KAAK,SAAqC;AAC3D,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;EAC9C,MAAM,MAAM;EACZ,MAAM,OAAO,IAAI,SAAS,UAAU,IAAI,SAAS,cAAc,IAAI,SAAS,cAAc,IAAI,SAAS,WAAW,IAAI,SAAS,SAAS,IAAI,OAAO;AACnJ,SAAO,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,MAAM,GAAG;GAAE;GAAM,MAAM,IAAI,KAAK,MAAM;GAAE,GAAG;GAC3F,CAAC,QAAQ,SAAsC,QAAQ,KAAK,CAAC,CAAC,MAAM,GAAG,GAAG,GAC1E,SAAS;AACb,QAAO;EACL,gBAAgB,KAAK;EACrB,aAAa,KAAK,KAAK;EACvB,OAAO,OAAO,KAAK,UAAU,YAAY,KAAK,MAAM,MAAM,GAAG,KAAK,MAAM,MAAM,GAAG,SAAS;EAC1F,iBAAiB,OAAO,KAAK,oBAAoB,YAAY,KAAK,gBAAgB,MAAM,GAAG,KAAK,gBAAgB,MAAM,GAAG,SAAS;EAClI,aAAa,YAAY,KAAK,aAAa,SAAS,YAAY;EAChE,cAAc,YAAY,KAAK,cAAc,SAAS,aAAa;EACnE,SAAS,YAAY,KAAK,SAAS,SAAS,QAAQ;EACpD,OAAO,YAAY,KAAK,OAAO,SAAS,MAAM;EAC9C,aAAa;EACb,YAAY,OAAO,KAAK,eAAe,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC,GAAG,SAAS;EACxG;;AAGH,SAAS,qBAAqB,MAAoB;AAGhD,QAAO,iUAFO,KAAK,OAAO,MAAM,IAAI,QAE0S,iBAD7T,KAAK,SAAS,MAAM,IAAI;;AAI3C,eAAe,uBAAuB,MAAY,QAA+C;CAI/F,MAAM,WAAW,MAAM,SAFN,aADA,oBAAoB,OAAO,IAAI,iBAGR,EAAE,EAAE,UAAA,CADX;EAAE,MAAM;EAAQ,SAAS,qBAAqB,KAAK;EAAE,WAAW,KAAK,KAAK;EAAE,CACzD,EAAE,EAAE,EAAE,aAAa,IAAK,CAAC;CAC7E,IAAI,eAAe;AACnB,KAAI,MAAM,QAAQ,SAAS,QAAQ;OAC5B,MAAM,QAAQ,SAAS,QAC1B,KAAI,QAAQ,OAAO,SAAS,YAAa,KAA2B,SAAS,OAC3E,iBAAgB,OAAQ,KAA2B,QAAQ,GAAG;;CAIpE,MAAM,MAAM,aAAa,MAAM,CAAC,QAAQ,gBAAgB,GAAG,CAAC,QAAQ,SAAS,GAAG,CAAC,MAAM;AACvF,QAAO,2BAA2B,MAAM,KAAK,MAAM,IAAI,CAA4B;;AAGrF,IAAa,eAAb,MAA0B;CACxB,iCAAyB,IAAI,KAAqB;CAElD,YAAY,QAAyB,IAAI,YAAY,EAAE;AAA1B,OAAA,QAAA;;CAE7B,MAAM,aAA4B;AAChC,QAAM,KAAK,MAAM,YAAY;;CAG/B,MAAM,aAAa,UAAkB,QAAsC;EACzE,MAAM,KAAK,YAAY;EACvB,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,OAAa;GACjB;GACA,OAAO,mBAAmB,SAAS;GACnC,MAAM,UAAU,SAAS;GACzB,QAAQ;GACR;GACA,WAAW;GACX,WAAW;GACX,aAAa;GACb,eAAe;GACf,cAAc;GACf;AACD,QAAM,KAAK,MAAM,QAAQ,KAAK;AAC9B,MAAI,MAAM;GAAE,IAAI,KAAK;GAAI,MAAM,KAAK;GAAM,EAAE,gBAAgB;AAC5D,SAAO;;CAGT,MAAM,WAAW,QAAyC;EACxD,MAAM,KAAK,YAAY;EACvB,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,WAAW,OAAO,YAAY;EACpC,MAAM,OAAa;GACjB;GACA,OAAO,OAAO,SAAS,mBAAmB,SAAS;GACnD,MAAM,OAAO,QAAQ,UAAU,SAAS;GACxC,QAAQ;GACR;GACA,aAAa,EAAE;GACf,WAAW;GACX,WAAW;GACX,aAAa,OAAO;GACpB,MAAM,OAAO;GACb,QAAQ,OAAO;GACf,SAAS,OAAO;GAChB,UAAU,OAAO;GACjB,eAAe;GACf,cAAc;GACf;AACD,QAAM,KAAK,MAAM,QAAQ,KAAK;AAC9B,MAAI,MAAM;GAAE,IAAI,KAAK;GAAI,MAAM,KAAK;GAAM,EAAE,eAAe;AAC3D,SAAO;;CAGT,MAAM,QAAQ,IAAkC;AAC9C,SAAO,KAAK,MAAM,QAAQ,GAAG;;CAG/B,MAAM,WAAW,IAAY,OAAsB,UAA2B,QAA8B;EAC1G,MAAM,WAAW,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC7C,MAAI,CAAC,SAAU,QAAO;EACtB,MAAM,iBAAiB,MAAM,aAAa,KAAA,KAAa,MAAM,UAAU,KAAA;AACvE,MAAI,eAAgB,OAAM,KAAK,kBAAkB,UAAU,QAAQ;EAEnE,MAAM,kBAAiC,EAAE,GAAG,OAAO;AACnD,MAAI,MAAM,aAAa,KAAA,EACrB,iBAAgB,OAAO,MAAM,QAAQ,UAAU,MAAM,UAAU,QAAQ,SAAS,aAAa,OAAO,EAAE,SAAS,YAAY;AAE7H,MAAI,kBAAkB,MAAM,aAAa;AACvC,mBAAgB,iBAAiB,SAAS,iBAAiB,KAAK;AAChE,mBAAgB,eAAe,MAAM,iBAAiB,SAAS,gBAAgB,KAAK;;EAGtF,MAAM,aAAa,MAAM,KAAK,MAAM,WAAW,IAAI,gBAAgB;AACnE,SAAO,aAAa,KAAK,qBAAqB,WAAW,GAAG;;CAG9D,MAAc,qBAAqB,MAA2B;EAC5D,MAAM,EAAE,MAAM,YAAY,gCAAgC,KAAK;AAC/D,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,OAAK,MAAM,cAAc,QAAS,OAAM,KAAK,MAAM,qBAAqB,KAAK,IAAI,WAAW,aAAa;AACzG,MAAI,MAAM;GAAE,QAAQ,KAAK;GAAI,YAAY,QAAQ,KAAK,eAAe,WAAW,GAAG;GAAE,EAAE,iCAAiC;EACxH,MAAM,iBAAiB,KAAK,SAAS;AAErC,SAAO,MADe,KAAK,MAAM,WAAW,KAAK,IAAI;GAAE,aAAa;GAAM,MAAM,UAAU,KAAK,UAAU,gBAAgB,KAAK;GAAE,CAAC,IAC/G;GAAE,GAAG;GAAM,aAAa;GAAM;;CAGlD,MAAM,SAAS,IAAY,OAAsB,mBAA+E;EAC9H,MAAM,WAAW,MAAM,KAAK,MAAM,QAAQ,GAAG;AAC7C,MAAI,CAAC,SAAU,QAAO;GAAE,MAAM;GAAM,UAAU;GAAO;AACrD,MAAI,sBAAsB,KAAA,KAAa,SAAS,kBAAkB,KAAA,KAAa,oBAAoB,SAAS,cAC1G,QAAO;GAAE,MAAM;GAAU,UAAU;GAAM;AAG3C,SAAO;GAAE,MAAM,MADO,KAAK,WAAW,IAAI,OAAO,OAAO;GAChC,UAAU;GAAO;;CAG3C,MAAM,kBAAkB,IAAY,aAAqB,kBAAoF;EAC3I,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,SAAS,oBAAoB,KAAK;EACxC,MAAM,SAAS,kBAAkB,QAAQ,GAAG;EAC5C,MAAM,aAAa,sBAAsB,KAAK,YAAY;EAC1D,MAAM,eAAe,oBAAoB,KAAK,YAAY;EAC1D,IAAI,YAAY;AAChB,MAAI,YAAY;GACd,MAAM,QAAQ,OAAO,MAAM,WAAW,CAAC,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC,OAAO,QAAQ;AACjF,gBAAa,MAAM,SAAS,QAAQ,CAAC,OAAO,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,KAAK,SAAS,SAAS,KAAK,QAAQ,qBAAqB,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,KAAK;aAC7I,aACT,aAAY,mBAAmB,OAAO,UAAU,MAAM,GAAG,IAAI;MAE7D,aAAY,GAAG,OAAO,SAAS,CAAC,kBAAkB,YAAY,MAAM;AAEtE,SAAO;GACL,SAAS;GACT,OAAO;IACL,IAAI,YAAY;IAChB,SAAS;IACT,YAAY,CAAC;KAAE,MAAM;KAAgB,MAAM;KAAG,IAAI,OAAO;KAAQ,UAAU,aAAa;KAAQ,CAAC;IAClG;GACF;;CAGH,MAAM,aAAa,IAAY,QAA8E;EAC3G,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;EAClB,IAAI;AACJ,MAAI;AACF,YAAS,MAAM,uBAAuB,MAAM,OAAO;WAC5C,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK,QAAQ;IAAI,EAAE,wDAAwD;AACtF,YAAS,qBAAqB,KAAK;;EAErC,MAAM,UAAU,MAAM,KAAK,WAAW,IAAI;GACxC,QAAQ;IACN,GAAG,KAAK;IACR,aAAa,KAAK,KAAK;IACvB,WAAW;KACT,QAAQ;KACR,OAAO,oBAAoB,KAAK;KAChC,iBAAiB,KAAK,KAAK;KAC3B,YAAY,OAAO;KACnB;KACA,GAAG,KAAK,QAAQ;KACjB;IACF;GACD,IAAI;IAAE,GAAG,KAAK;IAAI,QAAQ,KAAK,IAAI,UAAU;IAAQ,SAAS,KAAK,IAAI,WAAW,OAAO;IAAiB;GAC1G,QAAQ,KAAK,WAAW,UAAU,cAAc,KAAK;GACtD,EAAE,UAAU;AACb,SAAO,UAAU;GAAE,MAAM;GAAS;GAAQ,GAAG;;CAG/C,MAAM,wBAAwB,IAAY,UAAuE;EAC/G,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,WAAW,IAAI,EAAE,QAAQ;GAAE,GAAG,KAAK;GAAQ,aAAa,KAAK,KAAK;GAAE,WAAW;IAAE,QAAQ,KAAK,QAAQ,WAAW,UAAU;IAAa,GAAG,KAAK,QAAQ;IAAW;IAAU;GAAE,EAAE,CAAC;;CAGhM,MAAM,eAAe,IAAY,YAA0C;EACzE,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,eAAe,KAAK,QAAQ,WAAW,qBAAqB,EAAE;AACpE,SAAO,KAAK,WAAW,IAAI,EACzB,QAAQ;GACN,GAAG,KAAK;GACR,aAAa,KAAK,KAAK;GACvB,WAAW;IACT,QAAQ,KAAK,QAAQ,WAAW,UAAU;IAC1C,GAAG,KAAK,QAAQ;IAChB,kBAAkB,KAAK,QAAQ,WAAW,oBAAoB;IAC9D,mBAAmB,MAAM,KAAK,IAAI,IAAI,CAAC,GAAG,cAAc,WAAW,CAAC,CAAC;IACtE;GACF,EACF,EAAE,OAAO;;CAGZ,MAAM,gBAAgB,IAAsC;EAC1D,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,QAAQ,WAAW,kBAAkB,GAAI,KAAK,QAAQ,WAAW,qBAAqB,EAAE,CAAE,CAAC,QAAQ,QAAuB,QAAQ,IAAI,CAAC,CAAC,CAAC;;CAG3K,MAAM,sBAAsB,IAAY,QAAiB,QAAQ,OAA0I;EACzM,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,SAAS,kCAAkC,GAAG;AACpD,MAAI,CAAC,SAAS,UAAU,OAAO,kBAAkB,KAAK,UACpD,QAAO;GAAE,eAAe,KAAK;GAAW,UAAU;GAAQ,OAAO;GAAO;EAE1E,MAAM,WAAW,MAAM,8BAA8B;GAAE;GAAM,cAAc;GAAM;GAAQ;GAAO,CAAC;AACjG,SAAO;GAAE,eAAe,KAAK;GAAW;GAAU,OAAO;GAAO;;CAGlE,MAAM,iBAAiB,IAAY,SAAiB,UAAU,WAAiC;EAC7F,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,UAAU,QAAQ,MAAM;AAC9B,MAAI,CAAC,QAAS,QAAO;EACrB,MAAM,UAAU,KAAK,SAAS,SAAS;EACvC,MAAM,eAAe,GAAG,UAAU,UAAU,SAAS,GAAG,KAAK,QAAQ,MAAM,QAAQ;AACnF,SAAO,KAAK,WAAW,IAAI,EAAE,UAAU,cAAc,EAAE,UAAU;;CAGnE,MAAM,WAAW,IAA8B;EAC7C,MAAM,UAAU,MAAM,KAAK,MAAM,WAAW,GAAG;AAC/C,MAAI,QAAS,OAAM,KAAK,MAAM,mBAAmB,GAAG;AACpD,SAAO;;CAGT,MAAM,UAAU,QAAwB,EAAE,EAAwG;AAChJ,SAAO,KAAK,MAAM,UAAU,MAAM;;CAGpC,MAAM,cAAc,QAAgB,MAA6G;EAC/I,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO;AAC7C,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,EAAE,cAAc,SAAS,MAAM,KAAK,MAAM,eAAe,QAAQ,KAAK,MAAM,KAAK,OAAO;EAC9F,MAAM,aAA6B;GACjC,IAAI,YAAY;GAChB,MAAM,KAAK,SAAS,WAAW,SAAS,GAAG,UAAU,KAAK,SAAS,WAAW,SAAS,GAAG,UAAU,KAAK,SAAS,WAAW,SAAS,GAAG,UAAU;GACnJ,UAAU,KAAK;GACf,UAAU,KAAK;GACf;GACA;GACA,UAAU,KAAK;GAChB;EACD,MAAM,cAAc,CAAC,GAAI,KAAK,eAAe,EAAE,EAAG,WAAW;EAC7D,MAAM,OAAO,KAAK,SAAS,aAAa,WAAW,SAAS,UAAU,UAAU,KAAK,SAAS,YAAY,UAAU,KAAK;AACzH,QAAM,KAAK,MAAM,WAAW,QAAQ;GAAE;GAAa;GAAM,CAAC;AAC1D,SAAO;;CAGT,MAAM,kBAAkB,QAAgB,cAAgG;EACtI,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO;AAC7C,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,aAAa,KAAK,aAAa,MAAM,MAAM,EAAE,OAAO,aAAa;AACvE,MAAI,CAAC,WAAY,QAAO;AACxB,SAAO;GAAE,UAAU,KAAK,MAAM,sBAAsB,QAAQ,WAAW,aAAa;GAAE,UAAU,WAAW;GAAU,UAAU,WAAW;GAAU;;CAGtJ,MAAM,gBAAgB,QAA8C;AAAE,SAAO,KAAK,MAAM,cAAc,OAAO;;CAC7G,MAAM,gBAAgB,QAAgB,WAAiD;AAAE,SAAO,KAAK,MAAM,YAAY,QAAQ,UAAU;;CAEzI,MAAM,oBAAoB,QAAgB,WAAyC;EACjF,MAAM,WAAW,MAAM,KAAK,MAAM,YAAY,QAAQ,UAAU;EAChE,MAAM,WAAW,MAAM,KAAK,MAAM,QAAQ,OAAO;AACjD,MAAI,CAAC,YAAY,CAAC,SAAU,QAAO;AACnC,QAAM,KAAK,kBAAkB,UAAU,UAAU;AACjD,OAAK,eAAe,IAAI,QAAQ,KAAK,KAAK,CAAC;AAC3C,QAAM,KAAK,MAAM,eAAe,QAAQ,uBAAuB;AAC/D,SAAO,KAAK,MAAM,WAAW,QAAQ;GAAE,OAAO,SAAS;GAAO,UAAU,SAAS;GAAU,MAAM,SAAS;GAAM,MAAM,SAAS;GAAM,QAAQ,SAAS;GAAQ,CAAC;;CAGjK,MAAM,QAAuB;AAAE,QAAM,KAAK,MAAM,OAAO;;CACvD,MAAM,YAAY,QAAgB,SAA8C;AAAE,SAAO,KAAK,WAAW,QAAQ,EAAE,SAAS,WAAW,KAAA,GAAW,CAAC;;CAEnJ,MAAM,WAAW,OAAe,QAAuB,OAAqI,EAAE,EAAiB;AAC7M,SAAO,KAAK,WAAW;GACrB;GACA,UAAU,SAAS;GACnB,MAAM;GACN,aAAa;GACb,SAAS,KAAK;GACd,UAAU;IAAE,MAAM;IAAO,OAAO,KAAK;IAAO,UAAU,KAAK;IAAU,kBAAkB,KAAK;IAAkB,cAAc,KAAK;IAAc;GAChJ,CAAC;;CAGJ,MAAM,eAAe,QAAsC;EACzD,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO;AAC7C,MAAI,CAAC,QAAQ,KAAK,SAAS,OAAQ,QAAO;EAC1C,MAAM,OAAO,CAAC,KAAK,UAAU;EAC7B,MAAM,WAAW,KAAK,SAAS,QAAQ,iBAAiB,MAAM,OAAO,MAAM,IAAI,GAAG;AAClF,SAAO,KAAK,WAAW,QAAQ;GAAE;GAAU,UAAU;IAAE,GAAG,KAAK;IAAU;IAAM;GAAE,CAAC;;CAGpF,MAAM,eAAe,QAAgB,OAAyE;EAC5G,MAAM,OAAO,MAAM,KAAK,MAAM,QAAQ,OAAO;AAC7C,MAAI,CAAC,QAAQ,KAAK,SAAS,OAAQ,QAAO;AAC1C,SAAO,KAAK,WAAW,QAAQ,EAAE,UAAU;GAAE,GAAG,KAAK;GAAU,MAAM,KAAK,UAAU,QAAQ;GAAO,GAAG;GAAO,EAAE,CAAC;;CAGlH,MAAM,WAAW,QAAsC;AACrD,SAAO,KAAK,WAAW,QAAQ,EAAE,cAAc,KAAK,KAAK,EAAE,CAAkB;;CAG/E,MAAc,kBAAkB,MAAY,SAAyC;AACnF,MAAI,YAAY,QAAQ;AACtB,SAAM,KAAK,MAAM,aAAa,MAAM,QAAQ;AAC5C,QAAK,eAAe,IAAI,KAAK,IAAI,KAAK,KAAK,CAAC;AAC5C,SAAM,KAAK,MAAM,eAAe,KAAK,IAAI,uBAAuB;AAChE;;EAEF,MAAM,OAAO,KAAK,eAAe,IAAI,KAAK,GAAG,IAAI;AACjD,MAAI,KAAK,KAAK,GAAG,OAAO,qBAAsB;AAC9C,QAAM,KAAK,MAAM,aAAa,MAAM,QAAQ;AAC5C,OAAK,eAAe,IAAI,KAAK,IAAI,KAAK,KAAK,CAAC;AAC5C,QAAM,KAAK,MAAM,eAAe,KAAK,IAAI,uBAAuB"}
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../../src/notes/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport { publishAutomationProductEvent } from '../automations/product-events.js';\nimport type { Config } from '../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../providers/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteAttachmentRef } from './attachment-ref.js';\nimport { partitionAttachmentsByReference } from './note-attachment-sync.js';\nimport { parseNoteMarkdown } from './note-markdown.js';\nimport { buildNoteAgentContextArtifact, getCachedNoteAgentContextArtifact } from './agent-context.js';\nimport { NotesStore } from './store.js';\nimport type {\n CaptureSource,\n CreateNoteParams,\n Note,\n NoteAiPatch,\n NoteAttachment,\n NoteCatalysisAction,\n NoteCatalysisMeta,\n NoteCatalysisReport,\n NoteIndexEntry,\n NoteKind,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesService');\nconst MAX_SNAPSHOTS_PER_NOTE = 50;\nconst SNAPSHOT_THROTTLE_MS = 60_000;\n\nfunction inferKind(markdown?: string, hasAttachments?: boolean, attachments?: NoteAttachment[]): NoteKind {\n if (hasAttachments && attachments?.length && attachments.every((item) => item.type === 'audio')) return 'voice';\n if (hasAttachments) return 'media';\n if (!markdown) return 'thought';\n const lower = markdown.toLowerCase();\n if (/^(todo|task|remind|buy|call|email|meet|finish|submit|send)\\b/i.test(lower) || /\\b(明天|今天|记得|别忘|待办|提醒)\\b/.test(markdown)) return 'todo';\n if (/^https?:\\/\\//.test(markdown.trim())) return 'bookmark';\n return 'thought';\n}\n\nfunction deriveDefaultTitle(markdown?: string): string | undefined {\n const normalized = parseNoteMarkdown(markdown ?? '').plainText.trim().replace(/\\s+/g, ' ');\n return normalized ? Array.from(normalized).slice(0, 10).join('') : undefined;\n}\n\nfunction splitMeaningfulLines(markdown?: string): string[] {\n return parseNoteMarkdown(markdown ?? '').plainText.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n}\n\nfunction summarizeIdea(markdown?: string): string {\n const lines = splitMeaningfulLines(markdown);\n return lines.slice(0, 3).join(';').slice(0, 140);\n}\n\nfunction publishNoteEvent(\n type: 'note.created' | 'note.updated',\n note: Note,\n extra?: Record<string, unknown>,\n): void {\n publishAutomationProductEvent({\n type,\n source: 'notes',\n payload: {\n noteId: note.id,\n kind: note.kind,\n status: note.status,\n title: note.title,\n capturedVia: note.capturedVia,\n tagCount: note.tags?.length ?? 0,\n hasAttachments: Boolean(note.attachments?.length),\n ...extra,\n },\n });\n}\n\nfunction inferCatalysisStage(note: Note): NonNullable<NoteCatalysisMeta['stage']> {\n const text = `${note.title ?? ''}\\n${note.markdown}`;\n if (/上线|发布|launch|ship/i.test(text)) return 'shipped';\n if (/验证|访谈|用户|测试|validate/i.test(text)) return 'validating';\n if (/开发|实现|构建|build|mvp/i.test(text)) return 'developing';\n if (/想法|机会|问题|idea|seed/i.test(text)) return 'seed';\n return 'incubating';\n}\n\nfunction buildCatalysisReport(note: Note): NoteCatalysisReport {\n const summary = summarizeIdea(note.markdown || note.title);\n const title = note.title?.trim() || summary.slice(0, 28) || '未命名想法';\n const actions: NoteCatalysisAction[] = [\n { kind: 'research', text: `验证「${title}」的真实需求和目标用户` },\n { kind: 'task', text: `拆解「${title}」的最小可行下一步` },\n { kind: 'chat', text: `继续和 AI 讨论「${title}」的方案` },\n ];\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title,\n valueHypothesis: summary || '这条笔记可能包含一个待澄清的想法。',\n targetUsers: ['待确认的核心用户'],\n keyQuestions: ['用户为什么现在需要它?', '最小可验证版本是什么?', '如何判断它值得继续投入?'],\n mvpPath: ['定义目标用户', '写出最小场景', '完成一次验证'],\n risks: ['需求不够明确', '执行路径过大'],\n nextActions: actions,\n confidence: summary ? 0.58 : 0.35,\n };\n}\n\nfunction normalizeAiCatalysisReport(note: Note, data: Record<string, unknown>): NoteCatalysisReport {\n const fallback = buildCatalysisReport(note);\n const stringArray = (value: unknown, fallbackValue: string[]) => Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string').slice(0, 12) : fallbackValue;\n const actions = Array.isArray(data.nextActions)\n ? data.nextActions.map((item): NoteCatalysisAction | null => {\n if (!item || typeof item !== 'object') return null;\n const row = item as { kind?: unknown; text?: unknown };\n const kind = row.kind === 'task' || row.kind === 'workflow' || row.kind === 'research' || row.kind === 'share' || row.kind === 'chat' ? row.kind : 'task';\n return typeof row.text === 'string' && row.text.trim() ? { kind, text: row.text.trim() } : null;\n }).filter((item): item is NoteCatalysisAction => Boolean(item)).slice(0, 12)\n : fallback.nextActions;\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title: typeof data.title === 'string' && data.title.trim() ? data.title.trim() : fallback.title,\n valueHypothesis: typeof data.valueHypothesis === 'string' && data.valueHypothesis.trim() ? data.valueHypothesis.trim() : fallback.valueHypothesis,\n targetUsers: stringArray(data.targetUsers, fallback.targetUsers),\n keyQuestions: stringArray(data.keyQuestions, fallback.keyQuestions),\n mvpPath: stringArray(data.mvpPath, fallback.mvpPath),\n risks: stringArray(data.risks, fallback.risks),\n nextActions: actions,\n confidence: typeof data.confidence === 'number' ? Math.max(0, Math.min(1, data.confidence)) : fallback.confidence,\n };\n}\n\nfunction buildCatalysisPrompt(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const markdown = note.markdown.trim() || '(无正文)';\n return `请把下面的 Markdown 笔记催化成可执行的想法报告,输出 JSON:\\n{\\n \"title\": string,\\n \"valueHypothesis\": string,\\n \"targetUsers\": string[],\\n \"keyQuestions\": string[],\\n \"mvpPath\": string[],\\n \"risks\": string[],\\n \"nextActions\": [{\"text\": string, \"kind\": \"task\"|\"workflow\"|\"research\"|\"share\"|\"chat\"}],\\n \"confidence\": number\\n}\\n\\n标题:${title}\\n\\nMarkdown:\\n${markdown}`;\n}\n\nasync function buildAiCatalysisReport(note: Note, config?: Config): Promise<NoteCatalysisReport> {\n const modelRef = getDefaultModelSync(config);\n if (!modelRef) {\n throw new Error('No global default model configured');\n }\n const resolved = resolveModel(modelRef);\n const messages: UserMessage[] = [{ role: 'user', content: buildCatalysisPrompt(note), timestamp: Date.now() }];\n const response = await complete(resolved, { messages }, { temperature: 0.2 });\n let responseText = '';\n if (Array.isArray(response.content)) {\n for (const part of response.content) {\n if (part && typeof part === 'object' && (part as { type?: string }).type === 'text') {\n responseText += String((part as { text?: string }).text || '');\n }\n }\n }\n const raw = responseText.trim().replace(/^```json\\s*/i, '').replace(/```$/i, '').trim();\n return normalizeAiCatalysisReport(note, JSON.parse(raw) as Record<string, unknown>);\n}\n\nexport class NotesService {\n private lastSnapshotAt = new Map<string, number>();\n\n constructor(private readonly store = new NotesStore()) {}\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n }\n\n async quickCapture(markdown: string, source: CaptureSource): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const note: Note = {\n id,\n title: deriveDefaultTitle(markdown),\n kind: inferKind(markdown),\n status: 'inbox',\n markdown,\n createdAt: now,\n updatedAt: now,\n capturedVia: source,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Quick capture');\n return note;\n }\n\n async createNote(params: CreateNoteParams): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const markdown = params.markdown ?? '';\n const note: Note = {\n id,\n title: params.title ?? deriveDefaultTitle(markdown),\n kind: params.kind ?? inferKind(markdown),\n status: 'inbox',\n markdown,\n attachments: [],\n createdAt: now,\n updatedAt: now,\n capturedVia: params.capturedVia,\n tags: params.tags,\n pinned: params.pinned,\n groupId: params.groupId,\n taskMeta: params.taskMeta,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n publishNoteEvent('note.created', note);\n log.debug({ id: note.id, kind: note.kind }, 'Note created');\n return note;\n }\n\n async getNote(id: string): Promise<Note | null> {\n return this.store.getNote(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>, trigger: SnapshotTrigger = 'edit'): Promise<Note | null> {\n const existing = await this.store.getNote(id);\n if (!existing) return null;\n const contentTouched = patch.markdown !== undefined || patch.title !== undefined;\n if (contentTouched) await this.maybeSaveSnapshot(existing, trigger);\n\n const normalizedPatch: Partial<Note> = { ...patch };\n if (patch.markdown !== undefined) {\n normalizedPatch.kind = patch.kind ?? inferKind(patch.markdown, Boolean(existing.attachments?.length), existing.attachments);\n }\n if (contentTouched || patch.attachments) {\n normalizedPatch.remoteVersion = (existing.remoteVersion ?? 1) + 1;\n normalizedPatch.localVersion = patch.localVersion ?? (existing.localVersion ?? 1) + 1;\n }\n\n const updatedRaw = await this.store.updateNote(id, normalizedPatch);\n const updated = updatedRaw ? await this.reconcileAttachments(updatedRaw) : null;\n if (updated) {\n publishNoteEvent('note.updated', updated, {\n contentTouched,\n trigger,\n });\n }\n return updated;\n }\n\n private async reconcileAttachments(note: Note): Promise<Note> {\n const { kept, removed } = partitionAttachmentsByReference(note);\n if (removed.length === 0) return note;\n for (const attachment of removed) await this.store.deleteAttachmentFile(note.id, attachment.relativePath);\n log.debug({ noteId: note.id, removedIds: removed.map((attachment) => attachment.id) }, 'Pruned orphan note attachments');\n const hasAttachments = kept.length > 0;\n const updated = await this.store.updateNote(note.id, { attachments: kept, kind: inferKind(note.markdown, hasAttachments, kept) });\n return updated ?? { ...note, attachments: kept };\n }\n\n async syncNote(id: string, patch: Partial<Note>, baseRemoteVersion?: number): Promise<{ note: Note | null; conflict: boolean }> {\n const existing = await this.store.getNote(id);\n if (!existing) return { note: null, conflict: false };\n if (baseRemoteVersion !== undefined && existing.remoteVersion !== undefined && baseRemoteVersion < existing.remoteVersion) {\n return { note: existing, conflict: true };\n }\n const updated = await this.updateNote(id, patch, 'sync');\n return { note: updated, conflict: false };\n }\n\n async createAiEditPatch(id: string, instruction: string, markdownOverride?: string): Promise<{ message: string; patch: NoteAiPatch } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const source = markdownOverride ?? note.markdown;\n const parsed = parseNoteMarkdown(source, id);\n const wantsTodos = /待办|todo|task|行动|提醒/i.test(instruction);\n const wantsSummary = /摘要|总结|summary|压缩/i.test(instruction);\n let generated = '';\n if (wantsTodos) {\n const lines = source.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n generated = (lines.length ? lines : [parsed.plainText]).slice(0, 12).map((line) => `- [ ] ${line.replace(/^[-*\\d.\\s\\[\\]x]+/i, '').trim()}`).join('\\n');\n } else if (wantsSummary) {\n generated = `> [!SUMMARY]\\n> ${parsed.plainText.slice(0, 220)}`;\n } else {\n generated = `${source.trimEnd()}\\n\\n## AI 整理\\n\\n${instruction.trim()}`;\n }\n return {\n message: 'AI edit patch generated',\n patch: {\n id: randomUUID(),\n summary: instruction,\n operations: [{ type: 'replaceRange', from: 0, to: source.length, markdown: generated || source }],\n },\n };\n }\n\n async catalyzeNote(id: string, config?: Config): Promise<{ note: Note; report: NoteCatalysisReport } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n let report: NoteCatalysisReport;\n try {\n report = await buildAiCatalysisReport(note, config);\n } catch (err) {\n log.warn({ err, noteId: id }, 'AI note catalysis failed; using local fallback report');\n report = buildCatalysisReport(note);\n }\n const updated = await this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: 'catalyzed',\n stage: inferCatalysisStage(note),\n lastCatalyzedAt: Date.now(),\n confidence: report.confidence,\n report,\n ...note.aiDeep?.catalysis,\n },\n },\n ai: { ...note.ai, intent: note.ai?.intent ?? 'idea', summary: note.ai?.summary ?? report.valueHypothesis },\n status: note.status === 'inbox' ? 'processed' : note.status,\n }, 'ai_edit');\n return updated ? { note: updated, report } : null;\n }\n\n async recordCatalysisFeedback(id: string, feedback: 'helpful' | 'not_helpful' | 'neutral'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return this.updateNote(id, { aiDeep: { ...note.aiDeep, processedAt: Date.now(), catalysis: { status: note.aiDeep?.catalysis?.status ?? 'catalyzed', ...note.aiDeep?.catalysis, feedback } } });\n }\n\n async linkNoteThread(id: string, sessionKey: string): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const existingKeys = note.aiDeep?.catalysis?.linkedSessionKeys ?? [];\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'none',\n ...note.aiDeep?.catalysis,\n sourceSessionKey: note.aiDeep?.catalysis?.sourceSessionKey ?? sessionKey,\n linkedSessionKeys: Array.from(new Set([...existingKeys, sessionKey])),\n },\n },\n }, 'sync');\n }\n\n async listNoteThreads(id: string): Promise<string[] | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return Array.from(new Set([note.aiDeep?.catalysis?.sourceSessionKey, ...(note.aiDeep?.catalysis?.linkedSessionKeys ?? [])].filter((key): key is string => Boolean(key))));\n }\n\n async getAgentContextStatus(id: string, config?: Config, force = false): Promise<{ noteUpdatedAt: number; artifact: import('./agent-context.js').NoteAgentContextArtifact | null; stale: boolean } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const cached = getCachedNoteAgentContextArtifact(id);\n if (!force && cached && cached.noteUpdatedAt === note.updatedAt) {\n return { noteUpdatedAt: note.updatedAt, artifact: cached, stale: false };\n }\n const artifact = await buildNoteAgentContextArtifact({ note, notesService: this, config, force });\n return { noteUpdatedAt: note.updatedAt, artifact, stale: false };\n }\n\n async appendTextToNote(id: string, content: string, heading = 'AI 讨论沉淀'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const trimmed = content.trim();\n if (!trimmed) return note;\n const current = note.markdown.trimEnd();\n const nextMarkdown = `${current}${current ? '\\n\\n' : ''}## ${heading}\\n\\n${trimmed}\\n`;\n return this.updateNote(id, { markdown: nextMarkdown }, 'ai_edit');\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const removed = await this.store.deleteNote(id);\n if (removed) await this.store.deleteAllSnapshots(id);\n return removed;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean }> {\n return this.store.listNotes(query);\n }\n\n async addAttachment(noteId: string, file: { name: string; buffer: Buffer; mimeType: string; duration?: number }): Promise<NoteAttachment | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const { relativePath, size } = await this.store.saveAttachment(noteId, file.name, file.buffer);\n const attachment: NoteAttachment = {\n id: randomUUID(),\n type: file.mimeType.startsWith('image/') ? 'image' : file.mimeType.startsWith('audio/') ? 'audio' : file.mimeType.startsWith('video/') ? 'video' : 'file',\n mimeType: file.mimeType,\n fileName: file.name,\n size,\n relativePath,\n duration: file.duration,\n };\n const attachments = [...(note.attachments || []), attachment];\n const kind = note.kind === 'thought' && attachment.type === 'audio' ? 'voice' : note.kind === 'thought' ? 'media' : note.kind;\n await this.store.updateNote(noteId, { attachments, kind });\n return attachment;\n }\n\n async getAttachmentPath(noteId: string, attachmentId: string): Promise<{ filePath: string; mimeType: string; fileName: string } | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const attachment = note.attachments?.find((a) => a.id === attachmentId);\n if (!attachment) return null;\n return { filePath: this.store.resolveAttachmentPath(noteId, attachment.relativePath), mimeType: attachment.mimeType, fileName: attachment.fileName };\n }\n\n async listNoteHistory(noteId: string): Promise<NoteSnapshotEntry[]> { return this.store.listSnapshots(noteId); }\n async getNoteSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> { return this.store.getSnapshot(noteId, timestamp); }\n\n async restoreNoteSnapshot(noteId: string, timestamp: number): Promise<Note | null> {\n const snapshot = await this.store.getSnapshot(noteId, timestamp);\n const existing = await this.store.getNote(noteId);\n if (!snapshot || !existing) return null;\n await this.maybeSaveSnapshot(existing, 'restore');\n this.lastSnapshotAt.set(noteId, Date.now());\n await this.store.pruneSnapshots(noteId, MAX_SNAPSHOTS_PER_NOTE);\n return this.store.updateNote(noteId, { title: snapshot.title, markdown: snapshot.markdown, tags: snapshot.tags, kind: snapshot.kind, status: snapshot.status });\n }\n\n async flush(): Promise<void> { await this.store.flush(); }\n async moveToGroup(noteId: string, groupId: string | null): Promise<Note | null> { return this.updateNote(noteId, { groupId: groupId ?? undefined }); }\n\n async createTask(title: string, source: CaptureSource, opts: { dueAt?: number; priority?: 'high' | 'medium' | 'low'; sourceSessionKey?: string; sourceNoteId?: string; groupId?: string } = {}): Promise<Note> {\n return this.createNote({\n title,\n markdown: `- [ ] ${title}`,\n kind: 'task',\n capturedVia: source,\n groupId: opts.groupId,\n taskMeta: { done: false, dueAt: opts.dueAt, priority: opts.priority, sourceSessionKey: opts.sourceSessionKey, sourceNoteId: opts.sourceNoteId },\n });\n }\n\n async toggleTaskDone(noteId: string): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n const done = !note.taskMeta?.done;\n const markdown = note.markdown.replace(/^- \\[[ xX]\\]/m, `- [${done ? 'x' : ' '}]`);\n return this.updateNote(noteId, { markdown, taskMeta: { ...note.taskMeta, done } });\n }\n\n async updateTaskMeta(noteId: string, patch: Partial<import('./types.js').NoteTaskMeta>): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n return this.updateNote(noteId, { taskMeta: { ...note.taskMeta, done: note.taskMeta?.done ?? false, ...patch } });\n }\n\n async recordOpen(noteId: string): Promise<Note | null> {\n return this.updateNote(noteId, { lastOpenedAt: Date.now() } as Partial<Note>);\n }\n\n private async maybeSaveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n if (trigger !== 'edit') {\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n return;\n }\n const last = this.lastSnapshotAt.get(note.id) ?? 0;\n if (Date.now() - last < SNAPSHOT_THROTTLE_MS) return;\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n }\n}\n\nexport { buildNoteAttachmentRef };\n"],"mappings":"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"}
|
|
@@ -60,17 +60,16 @@ export declare function providerSupportsApiKey(provider: string): boolean;
|
|
|
60
60
|
/**
|
|
61
61
|
* Get a default model reference.
|
|
62
62
|
* Priority:
|
|
63
|
-
* 1.
|
|
64
|
-
* 2.
|
|
63
|
+
* 1. Effective model inherited from the global default preset / agent presets / agent override
|
|
64
|
+
* 2. Empty string when onboarding still needs to choose a global default model
|
|
65
65
|
*/
|
|
66
66
|
export declare function getDefaultModel(config?: Config | null | undefined): Promise<string>;
|
|
67
67
|
/**
|
|
68
68
|
* Synchronous default model resolution for constructors and sync code paths.
|
|
69
69
|
* Uses catalog/registry only (no async credential checks).
|
|
70
70
|
*
|
|
71
|
-
* When no model is explicitly configured, returns
|
|
72
|
-
*
|
|
73
|
-
* full catalog.
|
|
71
|
+
* When no model is explicitly configured, returns an empty string so setup
|
|
72
|
+
* flows can prompt for the global default model.
|
|
74
73
|
*/
|
|
75
74
|
export declare function getDefaultModelSync(config?: Config | null | undefined): string;
|
|
76
75
|
export { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';
|
|
@@ -83,10 +83,12 @@ function getApiKeySync(provider) {
|
|
|
83
83
|
* @throws if model not found
|
|
84
84
|
*/
|
|
85
85
|
function resolveModel(ref) {
|
|
86
|
-
const
|
|
86
|
+
const trimmedRef = typeof ref === "string" ? ref.trim() : "";
|
|
87
|
+
if (!trimmedRef) throw new Error("No default model configured. Choose a model in onboarding or set agents.capabilityPresets.default.models.roles.<role>.model.");
|
|
88
|
+
const customModel = getModelRegistry().resolve(trimmedRef);
|
|
87
89
|
if (customModel) return customModel;
|
|
88
|
-
if (
|
|
89
|
-
const [provider, modelId] =
|
|
90
|
+
if (trimmedRef.includes("/")) {
|
|
91
|
+
const [provider, modelId] = trimmedRef.split("/");
|
|
90
92
|
const piAiModel = getModel(provider, modelId);
|
|
91
93
|
if (piAiModel) return normalizeProviderModel(piAiModel);
|
|
92
94
|
const plugin = getProviderRegistry().get(provider);
|
|
@@ -94,20 +96,20 @@ function resolveModel(ref) {
|
|
|
94
96
|
const pluginModel = plugin.models.find((m) => m.id === modelId);
|
|
95
97
|
if (pluginModel) return pluginModelToModel(provider, pluginModel);
|
|
96
98
|
}
|
|
97
|
-
throw new Error(`Model not found: ${
|
|
99
|
+
throw new Error(`Model not found: ${trimmedRef}`);
|
|
98
100
|
}
|
|
99
101
|
for (const provider of getProviders()) try {
|
|
100
|
-
const found = getModels(provider).find((m) => m.id ===
|
|
102
|
+
const found = getModels(provider).find((m) => m.id === trimmedRef);
|
|
101
103
|
if (found) return normalizeProviderModel(found);
|
|
102
104
|
} catch {
|
|
103
105
|
continue;
|
|
104
106
|
}
|
|
105
107
|
const pluginRegistry = getProviderRegistry();
|
|
106
108
|
for (const plugin of pluginRegistry.listAll()) {
|
|
107
|
-
const found = plugin.models.find((m) => m.id ===
|
|
109
|
+
const found = plugin.models.find((m) => m.id === trimmedRef);
|
|
108
110
|
if (found) return pluginModelToModel(plugin.id, found);
|
|
109
111
|
}
|
|
110
|
-
throw new Error(`Model not found: ${
|
|
112
|
+
throw new Error(`Model not found: ${trimmedRef}. Use format: provider/model-id`);
|
|
111
113
|
}
|
|
112
114
|
function getModelsByProvider(provider) {
|
|
113
115
|
const fromRegistry = getModelRegistry().getAll().filter((m) => m.provider === provider).map(normalizeProviderModel);
|
|
@@ -263,8 +265,8 @@ function providerSupportsApiKey(provider) {
|
|
|
263
265
|
/**
|
|
264
266
|
* Get a default model reference.
|
|
265
267
|
* Priority:
|
|
266
|
-
* 1.
|
|
267
|
-
* 2.
|
|
268
|
+
* 1. Effective model inherited from the global default preset / agent presets / agent override
|
|
269
|
+
* 2. Empty string when onboarding still needs to choose a global default model
|
|
268
270
|
*/
|
|
269
271
|
async function getDefaultModel(config) {
|
|
270
272
|
const modelRef = config ? getAgentDefaultModelRef(config) : void 0;
|
|
@@ -273,22 +275,21 @@ async function getDefaultModel(config) {
|
|
|
273
275
|
if (configured) return `${configured.provider}/${configured.id}`;
|
|
274
276
|
return modelRef;
|
|
275
277
|
}
|
|
276
|
-
return
|
|
278
|
+
return "";
|
|
277
279
|
}
|
|
278
280
|
/**
|
|
279
281
|
* Synchronous default model resolution for constructors and sync code paths.
|
|
280
282
|
* Uses catalog/registry only (no async credential checks).
|
|
281
283
|
*
|
|
282
|
-
* When no model is explicitly configured, returns
|
|
283
|
-
*
|
|
284
|
-
* full catalog.
|
|
284
|
+
* When no model is explicitly configured, returns an empty string so setup
|
|
285
|
+
* flows can prompt for the global default model.
|
|
285
286
|
*/
|
|
286
287
|
function getDefaultModelSync(config) {
|
|
287
288
|
const modelRef = config ? getAgentDefaultModelRef(config) : void 0;
|
|
288
289
|
if (modelRef) return modelRef;
|
|
289
|
-
return
|
|
290
|
+
return "";
|
|
290
291
|
}
|
|
291
|
-
var EXTENSION_PROVIDER_BASE_URL, OPENAI_CODEX_CANONICAL_BASE_URL, PROVIDER_META
|
|
292
|
+
var EXTENSION_PROVIDER_BASE_URL, OPENAI_CODEX_CANONICAL_BASE_URL, PROVIDER_META;
|
|
292
293
|
var init_providers = __esmMin((() => {
|
|
293
294
|
init_schema();
|
|
294
295
|
init_model_registry();
|
|
@@ -485,7 +486,6 @@ var init_providers = __esmMin((() => {
|
|
|
485
486
|
supportsApiKey: false
|
|
486
487
|
}
|
|
487
488
|
};
|
|
488
|
-
DEFAULT_FALLBACK_MODEL = "openai/gpt-5.5";
|
|
489
489
|
}));
|
|
490
490
|
//#endregion
|
|
491
491
|
init_providers();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@earendil-works/pi-ai';\nimport { getAgentDefaultModelRef, type Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\nconst OPENAI_CODEX_CANONICAL_BASE_URL = 'https://chatgpt.com/backend-api/codex';\n\nfunction normalizeProviderModel(model: Model<Api>): Model<Api> {\n\tif (model.provider === 'openai-codex' && model.api === 'openai-codex-responses') {\n\t\treturn { ...model, baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL } as Model<Api>;\n\t}\n\treturn model;\n}\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(ref);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (ref.includes('/')) {\n\t\tconst [provider, modelId] = ref.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return normalizeProviderModel(piAiModel as Model<Api>);\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${ref}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === ref);\n\t\t\tif (found) return normalizeProviderModel(found as Model<Api>);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === ref);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${ref}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider).map(normalizeProviderModel);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport type ProviderAuthMode = ProviderActiveKeySource;\nexport type ProviderAuthStatus = 'connected' | 'expired' | 'not_connected';\n\nexport interface ProviderAuthState {\n authMode: ProviderAuthMode;\n authStatus: ProviderAuthStatus;\n expiresAt?: number;\n}\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n const authState = await getProviderAuthState(provider);\n return authState.authMode;\n}\n\nexport async function getProviderAuthState(provider: string): Promise<ProviderAuthState> {\n if (getProviderRegistry().has(provider)) {\n return { authMode: 'extension', authStatus: 'connected' };\n }\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return { authMode: 'agent', authStatus: 'connected' };\n if (fromCredentials === 'global') return { authMode: 'gateway', authStatus: 'connected' };\n if (fromCredentials === 'oauth') {\n const token = await resolver.loadOAuthTokenRecord(provider);\n const expired = Boolean(token?.expiresAt && token.expiresAt < Date.now());\n return {\n authMode: 'oauth',\n authStatus: expired ? 'expired' : 'connected',\n ...(token?.expiresAt ? { expiresAt: token.expiresAt } : {}),\n };\n }\n if (fromCredentials === 'env') return { authMode: 'env', authStatus: 'connected' };\n\n const expiredOAuthToken = await resolver.loadOAuthTokenRecord(provider);\n if (expiredOAuthToken?.expiresAt && expiredOAuthToken.expiresAt < Date.now()) {\n return {\n authMode: 'oauth',\n authStatus: 'expired',\n expiresAt: expiredOAuthToken.expiresAt,\n };\n }\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return { authMode: 'models_json', authStatus: 'connected' };\n }\n\n return { authMode: 'none', authStatus: 'not_connected' };\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll().map(normalizeProviderModel);\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\tconst configuredByProvider = new Map<string, boolean>();\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t\tcontinue;\n\t\t}\n\t\tlet configured = configuredByProvider.get(model.provider);\n\t\tif (configured === undefined) {\n\t\t\tconfigured = await isProviderConfigured(model.provider);\n\t\t\tconfiguredByProvider.set(model.provider, configured);\n\t\t}\n\t\tif (configured) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@earendil-works/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google AI', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n moonshotai: { name: 'Moonshot AI (Kimi · International)', category: 'common', supportsApiKey: true },\n 'moonshotai-cn': { name: 'Moonshot AI (Kimi · China)', category: 'common', supportsApiKey: true },\n fireworks: { name: 'Fireworks AI', category: 'specialty', supportsApiKey: true },\n together: { name: 'Together AI', category: 'specialty', supportsApiKey: true },\n 'cloudflare-workers-ai': { name: 'Cloudflare Workers AI', category: 'enterprise', supportsApiKey: true },\n 'cloudflare-ai-gateway': { name: 'Cloudflare AI Gateway', category: 'enterprise', supportsApiKey: true },\n xiaomi: { name: 'Xiaomi Mimo', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-cn': { name: 'Xiaomi Token Plan (CN)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-ams': { name: 'Xiaomi Token Plan (AMS)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-sgp': { name: 'Xiaomi Token Plan (SGP)', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/** Preferred default model when no explicit model is configured. */\nconst DEFAULT_FALLBACK_MODEL = 'openai/gpt-5.5';\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Explicitly configured model in the default agent manifest (if set and available)\n * 2. Default fallback: openai/gpt-5.5\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m =>\n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is explicitly configured, returns the preferred default\n * (`openai/gpt-5.5`) rather than picking an arbitrary first model from the\n * full catalog.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n return modelRef;\n }\n\n return DEFAULT_FALLBACK_MODEL;\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["getPiAiModel","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/index.ts"],"sourcesContent":["/**\n * Model provider module - integrates built-in models with custom models from models.json\n */\n\nimport {\n\tgetModel as getPiAiModel,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype Api,\n} from '@earendil-works/pi-ai';\nimport { getAgentDefaultModelRef, type Config } from '../config/schema.js';\nimport { getModelRegistry } from './model-registry.js';\nimport { CredentialResolver, resolveApiKey, hasCredentials } from '../auth/credentials.js';\nimport { hasProviderAuthOnDiskSync } from '../auth/sync-provider-auth.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\nimport { getProviderRegistry } from './plugin-registry.js';\nimport type { ProviderModelDefinition } from '../extensions/types/providers.js';\n\nexport { getApiKeyFromEnv, PROVIDER_ENV_MAP } from './env-keys.js';\n\n/** Sentinel base URL: model is served by an extension {@link ProviderPluginRegistry} provider. */\nexport const EXTENSION_PROVIDER_BASE_URL = 'extension://provider-plugin';\nconst OPENAI_CODEX_CANONICAL_BASE_URL = 'https://chatgpt.com/backend-api/codex';\n\nfunction normalizeProviderModel(model: Model<Api>): Model<Api> {\n\tif (model.provider === 'openai-codex' && model.api === 'openai-codex-responses') {\n\t\treturn { ...model, baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL } as Model<Api>;\n\t}\n\treturn model;\n}\n\n/** Map a plugin registry model to the pi-ai {@link Model} shape. */\nexport function pluginModelToModel(providerId: string, definition: ProviderModelDefinition): Model<Api> {\n\treturn {\n\t\tprovider: providerId,\n\t\tid: definition.id,\n\t\tname: definition.name,\n\t\tapi: 'openai-completions' as Api,\n\t\tbaseUrl: EXTENSION_PROVIDER_BASE_URL,\n\t\treasoning: false,\n\t\tinput: definition.supportsImages ? (['text', 'image'] as ('text' | 'image')[]) : (['text'] as ('text' | 'image')[]),\n\t\tcontextWindow: definition.contextWindow ?? 128000,\n\t\tmaxTokens: definition.maxOutputTokens ?? 4096,\n\t\tcost: {\n\t\t\tinput: definition.pricing?.input ?? 0,\n\t\t\toutput: definition.pricing?.output ?? 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t},\n\t} as Model<Api>;\n}\n\n/**\n * Get API key synchronously: checks registry (models.json) first, then environment variables.\n * Use this for Agent's getApiKey callback which must be synchronous.\n */\nexport function getApiKeySync(provider: string): string | undefined {\n const pluginRegistry = getProviderRegistry();\n if (pluginRegistry.has(provider)) return 'extension-managed';\n\n const registry = getModelRegistry();\n const registryKey = registry.getApiKey(provider);\n if (registryKey) {\n return registryKey;\n }\n return getApiKeyFromEnv(provider);\n}\n\n/**\n * Resolve model reference. Supports:\n * - \"provider/modelId\" format\n * - \"modelId\" auto-detection via pi-ai or custom models\n * @throws if model not found\n */\nexport function resolveModel(ref: string): Model<Api> {\n\tconst trimmedRef = typeof ref === 'string' ? ref.trim() : '';\n\tif (!trimmedRef) {\n\t\tthrow new Error(\n\t\t\t'No default model configured. Choose a model in onboarding or set agents.capabilityPresets.default.models.roles.<role>.model.',\n\t\t);\n\t}\n\n\t// First try ModelRegistry (includes custom models)\n\tconst registry = getModelRegistry();\n\tconst customModel = registry.resolve(trimmedRef);\n\tif (customModel) {\n\t\treturn customModel;\n\t}\n\n\tif (trimmedRef.includes('/')) {\n\t\tconst [provider, modelId] = trimmedRef.split('/');\n\t\tconst piAiModel = getPiAiModel(provider as any, modelId as any);\n\t\tif (piAiModel) return normalizeProviderModel(piAiModel as Model<Api>);\n\n\t\tconst pluginRegistry = getProviderRegistry();\n\t\tconst plugin = pluginRegistry.get(provider);\n\t\tif (plugin) {\n\t\t\tconst pluginModel = plugin.models.find(m => m.id === modelId);\n\t\t\tif (pluginModel) return pluginModelToModel(provider, pluginModel);\n\t\t}\n\t\tthrow new Error(`Model not found: ${trimmedRef}`);\n\t}\n\n\tfor (const provider of getPiAiProviders()) {\n\t\ttry {\n\t\t\tconst models = getPiAiModels(provider);\n\t\t\tconst found = models.find(m => m.id === trimmedRef);\n\t\t\tif (found) return normalizeProviderModel(found as Model<Api>);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tconst pluginRegistry = getProviderRegistry();\n\tfor (const plugin of pluginRegistry.listAll()) {\n\t\tconst found = plugin.models.find(m => m.id === trimmedRef);\n\t\tif (found) return pluginModelToModel(plugin.id, found);\n\t}\n\n\tthrow new Error(`Model not found: ${trimmedRef}. Use format: provider/model-id`);\n}\n\nexport function getModelsByProvider(provider: string): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst fromRegistry = registry.getAll().filter(m => m.provider === provider).map(normalizeProviderModel);\n\tconst plugin = getProviderRegistry().get(provider);\n\tif (!plugin) return fromRegistry;\n\tconst pluginModels = plugin.models.map(m => pluginModelToModel(provider, m));\n\treturn [...fromRegistry, ...pluginModels];\n}\n\nexport function getAllProviders(): string[] {\n\tconst registry = getModelRegistry();\n\tconst providers = new Set<string>();\n\n\t// Add built-in providers\n\tfor (const p of getPiAiProviders()) {\n\t\tproviders.add(p);\n\t}\n\n\t// Add custom providers from registry\n\tfor (const m of registry.getAll()) {\n\t\tproviders.add(m.provider);\n\t}\n\n\tfor (const plugin of getProviderRegistry().listAll()) {\n\t\tproviders.add(plugin.id);\n\t}\n\n\treturn Array.from(providers);\n}\n\nexport async function getApiKey(provider: string): Promise<string | undefined> {\n\tif (getProviderRegistry().has(provider)) return 'extension-managed';\n\n\t// Use new credential resolver first (checks: agent private > global > oauth > env)\n\tconst credentialKey = await resolveApiKey(provider);\n\tif (credentialKey) {\n\t\treturn credentialKey;\n\t}\n\n\t// Check registry for custom providers (from models.json)\n\tconst registry = getModelRegistry();\n\tconst registryKey = registry.getApiKey(provider);\n\tif (registryKey) {\n\t\treturn registryKey;\n\t}\n\n\t// Fallback to environment variables\n\treturn getApiKeyFromEnv(provider);\n}\n\n/**\n * Synchronous version for use in non-async contexts\n * Only checks environment variables and registry, not credential system\n */\nexport function isProviderConfiguredSync(provider: string): boolean {\n\tif (getProviderRegistry().has(provider)) return true;\n\n\t// Check registry for custom providers\n\tconst registry = getModelRegistry();\n\tif (registry.getApiKey(provider)) {\n\t\treturn true;\n\t}\n\t// Check environment variables\n\tif (getApiKeyFromEnv(provider)) {\n\t\treturn true;\n\t}\n\t// Gateway UI / CLI store keys in auth-profiles.json (async CredentialResolver); sync path for fallback list\n\treturn hasProviderAuthOnDiskSync(provider);\n}\n\nexport async function isProviderConfigured(provider: string): Promise<boolean> {\n if (getProviderRegistry().has(provider)) return true;\n\n // Check registry first for custom providers (from models.json)\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return true;\n }\n return await hasCredentials(provider);\n}\n\n/** Where runtime {@link getApiKey} resolves the key from (no secret values). */\nexport type ProviderActiveKeySource = 'none' | 'agent' | 'gateway' | 'oauth' | 'env' | 'models_json' | 'extension';\n\nexport type ProviderAuthMode = ProviderActiveKeySource;\nexport type ProviderAuthStatus = 'connected' | 'expired' | 'not_connected';\n\nexport interface ProviderAuthState {\n authMode: ProviderAuthMode;\n authStatus: ProviderAuthStatus;\n expiresAt?: number;\n}\n\nexport async function getProviderActiveKeySource(provider: string): Promise<ProviderActiveKeySource> {\n const authState = await getProviderAuthState(provider);\n return authState.authMode;\n}\n\nexport async function getProviderAuthState(provider: string): Promise<ProviderAuthState> {\n if (getProviderRegistry().has(provider)) {\n return { authMode: 'extension', authStatus: 'connected' };\n }\n\n const resolver = new CredentialResolver();\n const fromCredentials = await resolver.resolveApiKeySource(provider);\n if (fromCredentials === 'agent') return { authMode: 'agent', authStatus: 'connected' };\n if (fromCredentials === 'global') return { authMode: 'gateway', authStatus: 'connected' };\n if (fromCredentials === 'oauth') {\n const token = await resolver.loadOAuthTokenRecord(provider);\n const expired = Boolean(token?.expiresAt && token.expiresAt < Date.now());\n return {\n authMode: 'oauth',\n authStatus: expired ? 'expired' : 'connected',\n ...(token?.expiresAt ? { expiresAt: token.expiresAt } : {}),\n };\n }\n if (fromCredentials === 'env') return { authMode: 'env', authStatus: 'connected' };\n\n const expiredOAuthToken = await resolver.loadOAuthTokenRecord(provider);\n if (expiredOAuthToken?.expiresAt && expiredOAuthToken.expiresAt < Date.now()) {\n return {\n authMode: 'oauth',\n authStatus: 'expired',\n expiresAt: expiredOAuthToken.expiresAt,\n };\n }\n\n const registry = getModelRegistry();\n if (registry.getApiKey(provider)) {\n return { authMode: 'models_json', authStatus: 'connected' };\n }\n\n return { authMode: 'none', authStatus: 'not_connected' };\n}\n\nexport async function getConfiguredProviders(): Promise<string[]> {\n\tconst allProviders = getAllProviders();\n\tconst configured: string[] = [];\n\tfor (const p of allProviders) {\n\t\tif (await isProviderConfigured(p)) {\n\t\t\tconfigured.push(p);\n\t\t}\n\t}\n\treturn configured;\n}\n\nexport function getAllModels(): readonly Model<Api>[] {\n\tconst registry = getModelRegistry();\n\tconst registryModels = registry.getAll().map(normalizeProviderModel);\n\tconst pluginProviders = getProviderRegistry().listAll();\n\tif (pluginProviders.length === 0) return registryModels;\n\n\tconst existingIds = new Set(registryModels.map(m => `${m.provider}/${m.id}`));\n\tconst merged: Model<Api>[] = [...registryModels];\n\tfor (const plugin of pluginProviders) {\n\t\tfor (const model of plugin.models) {\n\t\t\tconst compositeId = `${plugin.id}/${model.id}`;\n\t\t\tif (!existingIds.has(compositeId)) {\n\t\t\t\tmerged.push(pluginModelToModel(plugin.id, model));\n\t\t\t\texistingIds.add(compositeId);\n\t\t\t}\n\t\t}\n\t}\n\treturn merged;\n}\n\nexport async function getAvailableModels(): Promise<readonly Model<Api>[]> {\n\tconst allModels = getAllModels();\n\tconst pluginRegistry = getProviderRegistry();\n\tconst available: Model<Api>[] = [];\n\tconst configuredByProvider = new Map<string, boolean>();\n\n\tfor (const model of allModels) {\n\t\tif (pluginRegistry.has(model.provider)) {\n\t\t\tavailable.push(model);\n\t\t\tcontinue;\n\t\t}\n\t\tlet configured = configuredByProvider.get(model.provider);\n\t\tif (configured === undefined) {\n\t\t\tconfigured = await isProviderConfigured(model.provider);\n\t\t\tconfiguredByProvider.set(model.provider, configured);\n\t\t}\n\t\tif (configured) {\n\t\t\tavailable.push(model);\n\t\t}\n\t}\n\treturn available;\n}\n\nexport type { Model, Api } from '@earendil-works/pi-ai';\n\nexport type ProviderCategory = 'common' | 'specialty' | 'oauth' | 'enterprise' | 'extension';\n\nexport interface ProviderMeta {\n name: string;\n category: ProviderCategory;\n supportsOAuth?: boolean;\n supportsApiKey?: boolean;\n}\n\nexport const PROVIDER_META: Record<string, ProviderMeta> = {\n 'openai': { name: 'OpenAI', category: 'common', supportsApiKey: true },\n 'anthropic': { name: 'Anthropic', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'deepseek': { name: 'DeepSeek', category: 'common', supportsApiKey: true },\n 'google': { name: 'Google AI', category: 'common', supportsApiKey: true },\n 'groq': { name: 'Groq', category: 'common', supportsApiKey: true },\n 'minimax': { name: 'MiniMax', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'minimax-cn': { name: 'MiniMax CN', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'kimi-coding': { name: 'Kimi For Coding', category: 'common', supportsApiKey: true, supportsOAuth: true },\n 'xai': { name: 'xAI', category: 'specialty', supportsApiKey: true },\n 'mistral': { name: 'Mistral AI', category: 'specialty', supportsApiKey: true },\n 'cerebras': { name: 'Cerebras', category: 'specialty', supportsApiKey: true },\n 'openrouter': { name: 'OpenRouter', category: 'specialty', supportsApiKey: true },\n 'huggingface': { name: 'Hugging Face', category: 'specialty', supportsApiKey: true },\n moonshotai: { name: 'Moonshot AI (Kimi · International)', category: 'common', supportsApiKey: true },\n 'moonshotai-cn': { name: 'Moonshot AI (Kimi · China)', category: 'common', supportsApiKey: true },\n fireworks: { name: 'Fireworks AI', category: 'specialty', supportsApiKey: true },\n together: { name: 'Together AI', category: 'specialty', supportsApiKey: true },\n 'cloudflare-workers-ai': { name: 'Cloudflare Workers AI', category: 'enterprise', supportsApiKey: true },\n 'cloudflare-ai-gateway': { name: 'Cloudflare AI Gateway', category: 'enterprise', supportsApiKey: true },\n xiaomi: { name: 'Xiaomi Mimo', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-cn': { name: 'Xiaomi Token Plan (CN)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-ams': { name: 'Xiaomi Token Plan (AMS)', category: 'specialty', supportsApiKey: true },\n 'xiaomi-token-plan-sgp': { name: 'Xiaomi Token Plan (SGP)', category: 'specialty', supportsApiKey: true },\n 'opencode': { name: 'OpenCode', category: 'specialty', supportsApiKey: true },\n 'opencode-go': { name: 'OpenCode Go', category: 'specialty', supportsApiKey: true },\n /** DashScope (Alibaba) — image, speech, STT; not an LLM KnownProvider. */\n 'dashscope': { name: 'DashScope (Alibaba)', category: 'specialty', supportsApiKey: true },\n /** International GLM (api.z.ai). Auth: API key (ZAI_API_KEY); no published OAuth for this HTTP API. */\n 'zai': { name: 'Zhipu GLM (International · z.ai)', category: 'common', supportsApiKey: true },\n 'amazon-bedrock': { name: 'Amazon Bedrock', category: 'enterprise', supportsApiKey: true },\n 'azure-openai-responses': { name: 'Azure OpenAI', category: 'enterprise', supportsApiKey: true },\n 'google-vertex': { name: 'Google Vertex AI', category: 'enterprise', supportsApiKey: true },\n 'vercel-ai-gateway': { name: 'Vercel AI Gateway', category: 'enterprise', supportsApiKey: true },\n 'github-copilot': { name: 'GitHub Copilot (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'openai-codex': { name: 'OpenAI Codex (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-gemini-cli': { name: 'Google Gemini CLI (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n 'google-antigravity': { name: 'Google Antigravity (OAuth)', category: 'oauth', supportsOAuth: true, supportsApiKey: false },\n};\n\nexport function getSortedProviders(): string[] {\n const all = getAllProviders();\n const catOrder: Record<ProviderCategory, number> = { common: 0, specialty: 1, enterprise: 2, oauth: 3, extension: 4 };\n const pluginRegistry = getProviderRegistry();\n\n return [...all].sort((a, b) => {\n const catA = pluginRegistry.has(a) ? 'extension' : (PROVIDER_META[a]?.category ?? 'specialty');\n const catB = pluginRegistry.has(b) ? 'extension' : (PROVIDER_META[b]?.category ?? 'specialty');\n if (catOrder[catA] !== catOrder[catB]) {\n return catOrder[catA] - catOrder[catB];\n }\n return a.localeCompare(b);\n });\n}\n\nexport function getProviderDisplayName(provider: string): string {\n const plugin = getProviderRegistry().get(provider);\n if (plugin) return plugin.name;\n return PROVIDER_META[provider]?.name || provider;\n}\n\nexport function providerSupportsOAuth(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsOAuth ?? false;\n}\n\nexport function providerSupportsApiKey(provider: string): boolean {\n return PROVIDER_META[provider]?.supportsApiKey ?? true;\n}\n\n// ============================================\n// Dynamic Default Model Resolution\n// ============================================\n\n/**\n * Get a default model reference.\n * Priority:\n * 1. Effective model inherited from the global default preset / agent presets / agent override\n * 2. Empty string when onboarding still needs to choose a global default model\n */\nexport async function getDefaultModel(config?: Config | null | undefined): Promise<string> {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n const availableModels = await getAvailableModels();\n const configured = availableModels.find(m =>\n `${m.provider}/${m.id}` === modelRef ||\n m.id === modelRef\n );\n if (configured) {\n return `${configured.provider}/${configured.id}`;\n }\n return modelRef;\n }\n\n return '';\n}\n\n/**\n * Synchronous default model resolution for constructors and sync code paths.\n * Uses catalog/registry only (no async credential checks).\n *\n * When no model is explicitly configured, returns an empty string so setup\n * flows can prompt for the global default model.\n */\nexport function getDefaultModelSync(config?: Config | null | undefined): string {\n const modelRef = config ? getAgentDefaultModelRef(config) : undefined;\n if (modelRef) {\n return modelRef;\n }\n\n return '';\n}\n\n// Re-export ModelRegistry for advanced use cases\nexport { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAS,uBAAuB,OAA+B;AAC9D,KAAI,MAAM,aAAa,kBAAkB,MAAM,QAAQ,yBACtD,QAAO;EAAE,GAAG;EAAO,SAAS;EAAiC;AAE9D,QAAO;;;AAIR,SAAgB,mBAAmB,YAAoB,YAAiD;AACvG,QAAO;EACN,UAAU;EACV,IAAI,WAAW;EACf,MAAM,WAAW;EACjB,KAAK;EACL,SAAS;EACT,WAAW;EACX,OAAO,WAAW,iBAAkB,CAAC,QAAQ,QAAQ,GAA6B,CAAC,OAAO;EAC1F,eAAe,WAAW,iBAAiB;EAC3C,WAAW,WAAW,mBAAmB;EACzC,MAAM;GACL,OAAO,WAAW,SAAS,SAAS;GACpC,QAAQ,WAAW,SAAS,UAAU;GACtC,WAAW;GACX,YAAY;GACZ;EACD;;;;;;AAOF,SAAgB,cAAc,UAAsC;AAElE,KADuB,qBACL,CAAC,IAAI,SAAS,CAAE,QAAO;CAGzC,MAAM,cADW,kBACW,CAAC,UAAU,SAAS;AAChD,KAAI,YACF,QAAO;AAET,QAAO,iBAAiB,SAAS;;;;;;;;AASnC,SAAgB,aAAa,KAAyB;CACrD,MAAM,aAAa,OAAO,QAAQ,WAAW,IAAI,MAAM,GAAG;AAC1D,KAAI,CAAC,WACJ,OAAM,IAAI,MACT,+HACA;CAKF,MAAM,cADW,kBACW,CAAC,QAAQ,WAAW;AAChD,KAAI,YACH,QAAO;AAGR,KAAI,WAAW,SAAS,IAAI,EAAE;EAC7B,MAAM,CAAC,UAAU,WAAW,WAAW,MAAM,IAAI;EACjD,MAAM,YAAYA,SAAa,UAAiB,QAAe;AAC/D,MAAI,UAAW,QAAO,uBAAuB,UAAwB;EAGrE,MAAM,SADiB,qBACM,CAAC,IAAI,SAAS;AAC3C,MAAI,QAAQ;GACX,MAAM,cAAc,OAAO,OAAO,MAAK,MAAK,EAAE,OAAO,QAAQ;AAC7D,OAAI,YAAa,QAAO,mBAAmB,UAAU,YAAY;;AAElE,QAAM,IAAI,MAAM,oBAAoB,aAAa;;AAGlD,MAAK,MAAM,YAAYC,cAAkB,CACxC,KAAI;EAEH,MAAM,QADSC,UAAc,SACT,CAAC,MAAK,MAAK,EAAE,OAAO,WAAW;AACnD,MAAI,MAAO,QAAO,uBAAuB,MAAoB;SACtD;AACP;;CAIF,MAAM,iBAAiB,qBAAqB;AAC5C,MAAK,MAAM,UAAU,eAAe,SAAS,EAAE;EAC9C,MAAM,QAAQ,OAAO,OAAO,MAAK,MAAK,EAAE,OAAO,WAAW;AAC1D,MAAI,MAAO,QAAO,mBAAmB,OAAO,IAAI,MAAM;;AAGvD,OAAM,IAAI,MAAM,oBAAoB,WAAW,iCAAiC;;AAGjF,SAAgB,oBAAoB,UAAyC;CAE5E,MAAM,eADW,kBACY,CAAC,QAAQ,CAAC,QAAO,MAAK,EAAE,aAAa,SAAS,CAAC,IAAI,uBAAuB;CACvG,MAAM,SAAS,qBAAqB,CAAC,IAAI,SAAS;AAClD,KAAI,CAAC,OAAQ,QAAO;CACpB,MAAM,eAAe,OAAO,OAAO,KAAI,MAAK,mBAAmB,UAAU,EAAE,CAAC;AAC5E,QAAO,CAAC,GAAG,cAAc,GAAG,aAAa;;AAG1C,SAAgB,kBAA4B;CAC3C,MAAM,WAAW,kBAAkB;CACnC,MAAM,4BAAY,IAAI,KAAa;AAGnC,MAAK,MAAM,KAAKD,cAAkB,CACjC,WAAU,IAAI,EAAE;AAIjB,MAAK,MAAM,KAAK,SAAS,QAAQ,CAChC,WAAU,IAAI,EAAE,SAAS;AAG1B,MAAK,MAAM,UAAU,qBAAqB,CAAC,SAAS,CACnD,WAAU,IAAI,OAAO,GAAG;AAGzB,QAAO,MAAM,KAAK,UAAU;;AAG7B,eAAsB,UAAU,UAA+C;AAC9E,KAAI,qBAAqB,CAAC,IAAI,SAAS,CAAE,QAAO;CAGhD,MAAM,gBAAgB,MAAM,cAAc,SAAS;AACnD,KAAI,cACH,QAAO;CAKR,MAAM,cADW,kBACW,CAAC,UAAU,SAAS;AAChD,KAAI,YACH,QAAO;AAIR,QAAO,iBAAiB,SAAS;;;;;;AAOlC,SAAgB,yBAAyB,UAA2B;AACnE,KAAI,qBAAqB,CAAC,IAAI,SAAS,CAAE,QAAO;AAIhD,KADiB,kBACL,CAAC,UAAU,SAAS,CAC/B,QAAO;AAGR,KAAI,iBAAiB,SAAS,CAC7B,QAAO;AAGR,QAAO,0BAA0B,SAAS;;AAG3C,eAAsB,qBAAqB,UAAoC;AAC7E,KAAI,qBAAqB,CAAC,IAAI,SAAS,CAAE,QAAO;AAIhD,KADiB,kBACL,CAAC,UAAU,SAAS,CAC9B,QAAO;AAET,QAAO,MAAM,eAAe,SAAS;;AAevC,eAAsB,2BAA2B,UAAoD;AAEnG,SAAO,MADiB,qBAAqB,SAAS,EACrC;;AAGnB,eAAsB,qBAAqB,UAA8C;AACvF,KAAI,qBAAqB,CAAC,IAAI,SAAS,CACrC,QAAO;EAAE,UAAU;EAAa,YAAY;EAAa;CAG3D,MAAM,WAAW,IAAI,oBAAoB;CACzC,MAAM,kBAAkB,MAAM,SAAS,oBAAoB,SAAS;AACpE,KAAI,oBAAoB,QAAS,QAAO;EAAE,UAAU;EAAS,YAAY;EAAa;AACtF,KAAI,oBAAoB,SAAU,QAAO;EAAE,UAAU;EAAW,YAAY;EAAa;AACzF,KAAI,oBAAoB,SAAS;EAC/B,MAAM,QAAQ,MAAM,SAAS,qBAAqB,SAAS;AAE3D,SAAO;GACL,UAAU;GACV,YAHc,QAAQ,OAAO,aAAa,MAAM,YAAY,KAAK,KAAK,CAGnD,GAAG,YAAY;GAClC,GAAI,OAAO,YAAY,EAAE,WAAW,MAAM,WAAW,GAAG,EAAE;GAC3D;;AAEH,KAAI,oBAAoB,MAAO,QAAO;EAAE,UAAU;EAAO,YAAY;EAAa;CAElF,MAAM,oBAAoB,MAAM,SAAS,qBAAqB,SAAS;AACvE,KAAI,mBAAmB,aAAa,kBAAkB,YAAY,KAAK,KAAK,CAC1E,QAAO;EACL,UAAU;EACV,YAAY;EACZ,WAAW,kBAAkB;EAC9B;AAIH,KADiB,kBACL,CAAC,UAAU,SAAS,CAC9B,QAAO;EAAE,UAAU;EAAe,YAAY;EAAa;AAG7D,QAAO;EAAE,UAAU;EAAQ,YAAY;EAAiB;;AAG1D,eAAsB,yBAA4C;CACjE,MAAM,eAAe,iBAAiB;CACtC,MAAM,aAAuB,EAAE;AAC/B,MAAK,MAAM,KAAK,aACf,KAAI,MAAM,qBAAqB,EAAE,CAChC,YAAW,KAAK,EAAE;AAGpB,QAAO;;AAGR,SAAgB,eAAsC;CAErD,MAAM,iBADW,kBACc,CAAC,QAAQ,CAAC,IAAI,uBAAuB;CACpE,MAAM,kBAAkB,qBAAqB,CAAC,SAAS;AACvD,KAAI,gBAAgB,WAAW,EAAG,QAAO;CAEzC,MAAM,cAAc,IAAI,IAAI,eAAe,KAAI,MAAK,GAAG,EAAE,SAAS,GAAG,EAAE,KAAK,CAAC;CAC7E,MAAM,SAAuB,CAAC,GAAG,eAAe;AAChD,MAAK,MAAM,UAAU,gBACpB,MAAK,MAAM,SAAS,OAAO,QAAQ;EAClC,MAAM,cAAc,GAAG,OAAO,GAAG,GAAG,MAAM;AAC1C,MAAI,CAAC,YAAY,IAAI,YAAY,EAAE;AAClC,UAAO,KAAK,mBAAmB,OAAO,IAAI,MAAM,CAAC;AACjD,eAAY,IAAI,YAAY;;;AAI/B,QAAO;;AAGR,eAAsB,qBAAqD;CAC1E,MAAM,YAAY,cAAc;CAChC,MAAM,iBAAiB,qBAAqB;CAC5C,MAAM,YAA0B,EAAE;CAClC,MAAM,uCAAuB,IAAI,KAAsB;AAEvD,MAAK,MAAM,SAAS,WAAW;AAC9B,MAAI,eAAe,IAAI,MAAM,SAAS,EAAE;AACvC,aAAU,KAAK,MAAM;AACrB;;EAED,IAAI,aAAa,qBAAqB,IAAI,MAAM,SAAS;AACzD,MAAI,eAAe,KAAA,GAAW;AAC7B,gBAAa,MAAM,qBAAqB,MAAM,SAAS;AACvD,wBAAqB,IAAI,MAAM,UAAU,WAAW;;AAErD,MAAI,WACH,WAAU,KAAK,MAAM;;AAGvB,QAAO;;AAsDR,SAAgB,qBAA+B;CAC7C,MAAM,MAAM,iBAAiB;CAC7B,MAAM,WAA6C;EAAE,QAAQ;EAAG,WAAW;EAAG,YAAY;EAAG,OAAO;EAAG,WAAW;EAAG;CACrH,MAAM,iBAAiB,qBAAqB;AAE5C,QAAO,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,MAAM;EAC7B,MAAM,OAAO,eAAe,IAAI,EAAE,GAAG,cAAe,cAAc,IAAI,YAAY;EAClF,MAAM,OAAO,eAAe,IAAI,EAAE,GAAG,cAAe,cAAc,IAAI,YAAY;AAClF,MAAI,SAAS,UAAU,SAAS,MAC9B,QAAO,SAAS,QAAQ,SAAS;AAEnC,SAAO,EAAE,cAAc,EAAE;GACzB;;AAGJ,SAAgB,uBAAuB,UAA0B;CAC/D,MAAM,SAAS,qBAAqB,CAAC,IAAI,SAAS;AAClD,KAAI,OAAQ,QAAO,OAAO;AAC1B,QAAO,cAAc,WAAW,QAAQ;;AAG1C,SAAgB,sBAAsB,UAA2B;AAC/D,QAAO,cAAc,WAAW,iBAAiB;;AAGnD,SAAgB,uBAAuB,UAA2B;AAChE,QAAO,cAAc,WAAW,kBAAkB;;;;;;;;AAapD,eAAsB,gBAAgB,QAAqD;CACzF,MAAM,WAAW,SAAS,wBAAwB,OAAO,GAAG,KAAA;AAC5D,KAAI,UAAU;EAEZ,MAAM,cAAa,MADW,oBAAoB,EACf,MAAK,MACtC,GAAG,EAAE,SAAS,GAAG,EAAE,SAAS,YAC5B,EAAE,OAAO,SACV;AACD,MAAI,WACF,QAAO,GAAG,WAAW,SAAS,GAAG,WAAW;AAE9C,SAAO;;AAGT,QAAO;;;;;;;;;AAUT,SAAgB,oBAAoB,QAA4C;CAC9E,MAAM,WAAW,SAAS,wBAAwB,OAAO,GAAG,KAAA;AAC5D,KAAI,SACF,QAAO;AAGT,QAAO;;;;cArakE;sBACpB;mBACoC;0BACjB;gBACzB;uBACU;AAM9C,+BAA8B;AACrC,mCAAkC;AA4S3B,iBAA8C;EACzD,UAAU;GAAE,MAAM;GAAU,UAAU;GAAU,gBAAgB;GAAM;EACtE,aAAa;GAAE,MAAM;GAAa,UAAU;GAAU,gBAAgB;GAAM,eAAe;GAAM;EACjG,YAAY;GAAE,MAAM;GAAY,UAAU;GAAU,gBAAgB;GAAM;EAC1E,UAAU;GAAE,MAAM;GAAa,UAAU;GAAU,gBAAgB;GAAM;EACzE,QAAQ;GAAE,MAAM;GAAQ,UAAU;GAAU,gBAAgB;GAAM;EAClE,WAAW;GAAE,MAAM;GAAW,UAAU;GAAU,gBAAgB;GAAM,eAAe;GAAM;EAC7F,cAAc;GAAE,MAAM;GAAc,UAAU;GAAU,gBAAgB;GAAM,eAAe;GAAM;EACnG,eAAe;GAAE,MAAM;GAAmB,UAAU;GAAU,gBAAgB;GAAM,eAAe;GAAM;EACzG,OAAO;GAAE,MAAM;GAAO,UAAU;GAAa,gBAAgB;GAAM;EACnE,WAAW;GAAE,MAAM;GAAc,UAAU;GAAa,gBAAgB;GAAM;EAC9E,YAAY;GAAE,MAAM;GAAY,UAAU;GAAa,gBAAgB;GAAM;EAC7E,cAAc;GAAE,MAAM;GAAc,UAAU;GAAa,gBAAgB;GAAM;EACjF,eAAe;GAAE,MAAM;GAAgB,UAAU;GAAa,gBAAgB;GAAM;EACpF,YAAY;GAAE,MAAM;GAAsC,UAAU;GAAU,gBAAgB;GAAM;EACpG,iBAAiB;GAAE,MAAM;GAA8B,UAAU;GAAU,gBAAgB;GAAM;EACjG,WAAW;GAAE,MAAM;GAAgB,UAAU;GAAa,gBAAgB;GAAM;EAChF,UAAU;GAAE,MAAM;GAAe,UAAU;GAAa,gBAAgB;GAAM;EAC9E,yBAAyB;GAAE,MAAM;GAAyB,UAAU;GAAc,gBAAgB;GAAM;EACxG,yBAAyB;GAAE,MAAM;GAAyB,UAAU;GAAc,gBAAgB;GAAM;EACxG,QAAQ;GAAE,MAAM;GAAe,UAAU;GAAa,gBAAgB;GAAM;EAC5E,wBAAwB;GAAE,MAAM;GAA0B,UAAU;GAAa,gBAAgB;GAAM;EACvG,yBAAyB;GAAE,MAAM;GAA2B,UAAU;GAAa,gBAAgB;GAAM;EACzG,yBAAyB;GAAE,MAAM;GAA2B,UAAU;GAAa,gBAAgB;GAAM;EACzG,YAAY;GAAE,MAAM;GAAY,UAAU;GAAa,gBAAgB;GAAM;EAC7E,eAAe;GAAE,MAAM;GAAe,UAAU;GAAa,gBAAgB;GAAM;;EAEnF,aAAa;GAAE,MAAM;GAAuB,UAAU;GAAa,gBAAgB;GAAM;;EAEzF,OAAO;GAAE,MAAM;GAAoC,UAAU;GAAU,gBAAgB;GAAM;EAC7F,kBAAkB;GAAE,MAAM;GAAkB,UAAU;GAAc,gBAAgB;GAAM;EAC1F,0BAA0B;GAAE,MAAM;GAAgB,UAAU;GAAc,gBAAgB;GAAM;EAChG,iBAAiB;GAAE,MAAM;GAAoB,UAAU;GAAc,gBAAgB;GAAM;EAC3F,qBAAqB;GAAE,MAAM;GAAqB,UAAU;GAAc,gBAAgB;GAAM;EAChG,kBAAkB;GAAE,MAAM;GAA0B,UAAU;GAAS,eAAe;GAAM,gBAAgB;GAAO;EACnH,gBAAgB;GAAE,MAAM;GAAwB,UAAU;GAAS,eAAe;GAAM,gBAAgB;GAAO;EAC/G,qBAAqB;GAAE,MAAM;GAA6B,UAAU;GAAS,eAAe;GAAM,gBAAgB;GAAO;EACzH,sBAAsB;GAAE,MAAM;GAA8B,UAAU;GAAS,eAAe;GAAM,gBAAgB;GAAO;EAC5H"}
|
|
@@ -102,7 +102,6 @@ var init_model_registry = __esmMin((() => {
|
|
|
102
102
|
loaded = false;
|
|
103
103
|
prewarmPromise = null;
|
|
104
104
|
_availableModelsCache;
|
|
105
|
-
_providersCache;
|
|
106
105
|
_authStatusCache = /* @__PURE__ */ new Map();
|
|
107
106
|
constructor(modelsJsonPath = resolveModelsJsonPath()) {
|
|
108
107
|
this.modelsJsonPath = modelsJsonPath;
|
|
@@ -133,7 +132,6 @@ var init_model_registry = __esmMin((() => {
|
|
|
133
132
|
this.customProviderApiKeys.clear();
|
|
134
133
|
this.loadError = void 0;
|
|
135
134
|
this._availableModelsCache = void 0;
|
|
136
|
-
this._providersCache = void 0;
|
|
137
135
|
this._authStatusCache.clear();
|
|
138
136
|
this.prewarmPromise = null;
|
|
139
137
|
this.loadModels();
|
|
@@ -207,7 +205,6 @@ var init_model_registry = __esmMin((() => {
|
|
|
207
205
|
*/
|
|
208
206
|
loadModels() {
|
|
209
207
|
this._availableModelsCache = void 0;
|
|
210
|
-
this._providersCache = void 0;
|
|
211
208
|
this._authStatusCache.clear();
|
|
212
209
|
const { models: customModels, overrides, modelOverrides, apiKeyConfigs, error } = this.loadCustomModels();
|
|
213
210
|
if (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-registry.js","names":["getModelsJsonPath","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/model-registry.ts"],"sourcesContent":["/**\n * Model Registry - manages built-in and custom models from models.json\n * \n * Features:\n * - Loads built-in models from @earendil-works/pi-ai\n * - Loads custom models from ~/.xopc/models.json\n * - Supports provider baseUrl/headers overrides\n * - Supports per-model overrides (modelOverrides)\n * - API key resolution with shell commands, env vars, and literals\n * - Hot reload support\n */\n\nimport {\n\ttype Api,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype KnownProvider,\n} from '@earendil-works/pi-ai';\nimport { existsSync, readFileSync } from 'fs';\nimport { resolveConfigValue, resolveHeaders } from '../config/resolve-config-value.js';\nimport { getModelsJsonPath } from '../config/models-json.js';\nimport type {\n\tModelsJsonConfig,\n\tModelOverride,\n} from '../config/models-json.js';\nimport { validateModelsConfig, getDefaultModelValues } from '../config/models-json.js';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\n\nconst log = createLogger('ModelRegistry');\n\n/** Provider override config (baseUrl, headers, apiKey) without custom models */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\theaders?: Record<string, string>;\n\tapiKey?: string;\n}\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\t/** Custom provider API key configs for fallback resolution */\n\tapiKeyConfigs: Map<string, string>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn {\n\t\tmodels: [],\n\t\toverrides: new Map(),\n\t\tmodelOverrides: new Map(),\n\t\tapiKeyConfigs: new Map(),\n\t\terror,\n\t};\n}\n\n/**\n * Deep merge compat settings\n */\nfunction mergeCompat(\n\tbaseCompat: Model<Api>['compat'],\n\toverrideCompat: ModelOverride['compat'],\n): Model<Api>['compat'] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as Record<string, unknown> | undefined;\n\tconst override = overrideCompat as Record<string, unknown>;\n\tconst merged = { ...base, ...override } as Record<string, unknown>;\n\n\t// Deep merge nested routing objects\n\tconst baseCompletions = base as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown } | undefined;\n\tconst overrideCompletions = override as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown };\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions?.openRouterRouting) {\n\t\t(merged as { openRouterRouting: unknown }).openRouterRouting = {\n\t\t\t...((baseCompletions?.openRouterRouting as object) || {}),\n\t\t\t...((overrideCompletions?.openRouterRouting as object) || {}),\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions?.vercelGatewayRouting) {\n\t\t(merged as { vercelGatewayRouting: unknown }).vercelGatewayRouting = {\n\t\t\t...((baseCompletions?.vercelGatewayRouting as object) || {}),\n\t\t\t...((overrideCompletions?.vercelGatewayRouting as object) || {}),\n\t\t};\n\t}\n\n\treturn merged as Model<Api>['compat'];\n}\n\n/**\n * Apply a model override to a model\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.input !== undefined) result.input = override.input as ('text' | 'image')[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Merge headers\n\tif (override.headers) {\n\t\tconst resolvedHeaders = resolveHeaders(override.headers);\n\t\tresult.headers = resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers;\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/**\n * Model Registry - manages all models (built-in + custom)\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate customProviderApiKeys: Map<string, string> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\tprivate loaded = false;\n\tprivate prewarmPromise: Promise<void> | null = null;\n\n\t// Performance caches\n\tprivate _availableModelsCache: Model<Api>[] | undefined;\n\tprivate _providersCache: string[] | undefined;\n\tprivate _authStatusCache: Map<string, boolean> = new Map();\n\n\tconstructor(private modelsJsonPath: string = getModelsJsonPath()) {\n\t\t// Catalog loads on first use or via prewarm() — keeps gateway constructor off the hot path.\n\t}\n\n\tisLoaded(): boolean {\n\t\treturn this.loaded;\n\t}\n\n\t/** Synchronously materialize the catalog (idempotent). */\n\tensureLoaded(): void {\n\t\tif (this.loaded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t}\n\n\t/** Background-friendly catalog load (idempotent). */\n\tprewarm(): Promise<void> {\n\t\tif (this.loaded) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tif (this.prewarmPromise) {\n\t\t\treturn this.prewarmPromise;\n\t\t}\n\t\tthis.prewarmPromise = Promise.resolve().then(() => {\n\t\t\tthis.ensureLoaded();\n\t\t});\n\t\treturn this.prewarmPromise;\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json)\n\t * Clears all caches\n\t */\n\trefresh(): void {\n\t\tthis.customProviderApiKeys.clear();\n\t\tthis.loadError = undefined;\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._providersCache = undefined;\n\t\tthis._authStatusCache.clear();\n\t\tthis.prewarmPromise = null;\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t\tlog.info('Model registry refreshed');\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error)\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom)\n\t * Results are cached until refresh() is called\n\t */\n\tgetAll(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured\n\t * Results are cached on first call until refresh()\n\t */\n\tgetAvailable(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\t// Lazy initialization with caching\n\t\tif (!this._availableModelsCache) {\n\t\t\tthis._availableModelsCache = this.models.filter((m) => this.hasAuth(m.provider));\n\t\t}\n\t\treturn this._availableModelsCache;\n\t}\n\n\t/**\n\t * Find a model by provider and ID\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Resolve a model reference (provider/modelId or just modelId)\n\t */\n\tresolve(ref: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\t// Handle provider/modelId format\n\t\tif (ref.includes('/')) {\n\t\t\tconst [provider, modelId] = ref.split('/');\n\t\t\treturn this.find(provider, modelId);\n\t\t}\n\n\t\t// Try to find by model ID only (search all providers)\n\t\tfor (const model of this.models) {\n\t\t\tif (model.id === ref) {\n\t\t\t\treturn model;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get API key for a provider (for custom providers from models.json)\n\t */\n\tgetApiKey(provider: string): string | undefined {\n\t\tthis.ensureLoaded();\n\t\t// First check custom provider configs\n\t\tconst keyConfig = this.customProviderApiKeys.get(provider);\n\t\tif (keyConfig) {\n\t\t\treturn resolveConfigValue(keyConfig);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Check if a provider has auth configured\n\t * Results are cached until refresh() is called\n\t */\n\tprivate hasAuth(provider: string): boolean {\n\t\t// Check cache first\n\t\tif (this._authStatusCache.has(provider)) {\n\t\t\treturn this._authStatusCache.get(provider)!;\n\t\t}\n\n\t\t// Compute and cache\n\t\tlet result: boolean;\n\t\t\n\t\t// Check custom provider configs from models.json first\n\t\tif (this.customProviderApiKeys.has(provider)) {\n\t\t\tconst key = this.getApiKey(provider);\n\t\t\tresult = !!key;\n\t\t} else {\n\t\t\t// Also check environment variables\n\t\t\tconst envKey = getApiKeyFromEnv(provider);\n\t\t\tresult = !!envKey;\n\t\t}\n\n\t\tthis._authStatusCache.set(provider, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Load all models\n\t * Clears caches to ensure fresh data\n\t */\n\tprivate loadModels(): void {\n\t\t// Clear caches before loading\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._providersCache = undefined;\n\t\tthis._authStatusCache.clear();\n\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\tapiKeyConfigs,\n\t\t\terror,\n\t\t} = this.loadCustomModels();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\tlog.warn({ error }, 'Failed to load models.json, using built-in models only');\n\t\t}\n\n\t\t// Store API key configs for fallback resolution\n\t\tthis.customProviderApiKeys = apiKeyConfigs;\n\n\t\t// Load built-in models with overrides applied\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\n\t\t// Merge custom models\n\t\tthis.models = this.mergeCustomModels(builtInModels, customModels);\n\n\t\tlog.debug(\n\t\t\t{ builtIn: builtInModels.length, custom: customModels.length, total: this.models.length },\n\t\t\t'Models loaded'\n\t\t);\n\t}\n\n\t/**\n\t * Load built-in models and apply provider/model overrides\n\t */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getPiAiProviders().flatMap((provider) => {\n\t\t\ttry {\n\t\t\t\tconst models = getPiAiModels(provider as KnownProvider) as Model<Api>[];\n\t\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\t\treturn models.map((m) => {\n\t\t\t\t\tlet model = m;\n\n\t\t\t\t\t// Apply provider-level baseUrl/headers override\n\t\t\t\t\tif (providerOverride) {\n\t\t\t\t\t\tconst resolvedHeaders = resolveHeaders(providerOverride.headers);\n\t\t\t\t\t\tmodel = {\n\t\t\t\t\t\t\t...model,\n\t\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\t\theaders: resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply per-model override\n\t\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\t\tif (modelOverride) {\n\t\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn model;\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst errorMsg = err instanceof Error ? err.message : String(err);\n\t\t\t\tlog.error({ provider, error: errorMsg }, 'Failed to load built-in models for provider');\n\t\t\t\treturn [];\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Merge custom models into built-in list (custom wins on conflicts)\n\t */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex(\n\t\t\t\t(m) => m.provider === customModel.provider && m.id === customModel.id\n\t\t\t);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\t/**\n\t * Load custom models from models.json\n\t */\n\tprivate loadCustomModels(): CustomModelsResult {\n\t\tif (!existsSync(this.modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.modelsJsonPath, 'utf-8');\n\t\t\tconst config: ModelsJsonConfig = JSON.parse(content);\n\n\t\t\t// Validate schema\n\t\t\tconst validation = validateModelsConfig(config);\n\t\t\tif (!validation.valid) {\n\t\t\t\tconst errors = validation.errors\n\t\t\t\t\t.map((e) => ` - ${e.path}: ${e.message}`)\n\t\t\t\t\t.join('\\n');\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Invalid models.json schema:\\n${errors}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\t\t\tconst apiKeyConfigs = new Map<string, string>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\t// Apply provider-level baseUrl/headers/apiKey override\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.headers || providerConfig.apiKey) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\theaders: providerConfig.headers,\n\t\t\t\t\t\tapiKey: providerConfig.apiKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Store API key config for fallback resolver\n\t\t\t\tif (providerConfig.apiKey) {\n\t\t\t\t\tapiKeyConfigs.set(providerName, providerConfig.apiKey);\n\t\t\t\t}\n\n\t\t\t\t// Store model overrides\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmodels: this.parseModels(config),\n\t\t\t\toverrides,\n\t\t\t\tmodelOverrides,\n\t\t\t\tapiKeyConfigs,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Failed to parse models.json: ${error.message}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Parse custom models from config\n\t */\n\tprivate parseModels(config: ModelsJsonConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst defaults = getDefaultModelValues();\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue;\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api || providerConfig.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\t// Merge headers: provider headers are base, model headers override\n\t\t\t\t// Resolve env vars and shell commands in header values\n\t\t\t\tconst providerHeaders = resolveHeaders(providerConfig.headers);\n\t\t\t\tconst modelHeaders = resolveHeaders(modelDef.headers);\n\t\t\t\tlet headers =\n\t\t\t\t\tproviderHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;\n\n\t\t\t\t// If authHeader is true, add Authorization header with resolved API key\n\t\t\t\tif (providerConfig.authHeader && providerConfig.apiKey) {\n\t\t\t\t\tconst resolvedKey = resolveConfigValue(providerConfig.apiKey);\n\t\t\t\t\tif (resolvedKey) {\n\t\t\t\t\t\theaders = { ...headers, Authorization: `Bearer ${resolvedKey}` };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: providerConfig.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tinput: (modelDef.input ?? defaults.input) as ('text' | 'image')[],\n\t\t\t\t\tcost: modelDef.cost ?? defaults.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? defaults.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? defaults.maxTokens,\n\t\t\t\t\theaders,\n\t\t\t\t\tcompat: modelDef.compat as Model<Api>['compat'],\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n}\n\n// ============================================\n// Global Registry Instance\n// ============================================\n\nlet globalRegistry: ModelRegistry | undefined;\n\nexport function getModelRegistry(): ModelRegistry {\n\tif (!globalRegistry) {\n\t\tglobalRegistry = new ModelRegistry();\n\t}\n\treturn globalRegistry;\n}\n\nexport function resetModelRegistry(): void {\n\tglobalRegistry = undefined;\n}\n\n/** Schedule catalog load on a background turn (gateway post-ready sidecar). */\nexport function prewarmModelRegistry(): Promise<void> {\n\treturn getModelRegistry().prewarm();\n}"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model-registry.js","names":["getModelsJsonPath","getPiAiProviders","getPiAiModels"],"sources":["../../../src/providers/model-registry.ts"],"sourcesContent":["/**\n * Model Registry - manages built-in and custom models from models.json\n * \n * Features:\n * - Loads built-in models from @earendil-works/pi-ai\n * - Loads custom models from ~/.xopc/models.json\n * - Supports provider baseUrl/headers overrides\n * - Supports per-model overrides (modelOverrides)\n * - API key resolution with shell commands, env vars, and literals\n * - Hot reload support\n */\n\nimport {\n\ttype Api,\n\tgetModels as getPiAiModels,\n\tgetProviders as getPiAiProviders,\n\ttype Model,\n\ttype KnownProvider,\n} from '@earendil-works/pi-ai';\nimport { existsSync, readFileSync } from 'fs';\nimport { resolveConfigValue, resolveHeaders } from '../config/resolve-config-value.js';\nimport { getModelsJsonPath } from '../config/models-json.js';\nimport type {\n\tModelsJsonConfig,\n\tModelOverride,\n} from '../config/models-json.js';\nimport { validateModelsConfig, getDefaultModelValues } from '../config/models-json.js';\nimport { createLogger } from '../utils/logger.js';\nimport { getApiKeyFromEnv } from './env-keys.js';\n\nconst log = createLogger('ModelRegistry');\n\n/** Provider override config (baseUrl, headers, apiKey) without custom models */\ninterface ProviderOverride {\n\tbaseUrl?: string;\n\theaders?: Record<string, string>;\n\tapiKey?: string;\n}\n\n/** Result of loading custom models from models.json */\ninterface CustomModelsResult {\n\tmodels: Model<Api>[];\n\t/** Providers with baseUrl/headers/apiKey overrides for built-in models */\n\toverrides: Map<string, ProviderOverride>;\n\t/** Per-model overrides: provider -> modelId -> override */\n\tmodelOverrides: Map<string, Map<string, ModelOverride>>;\n\t/** Custom provider API key configs for fallback resolution */\n\tapiKeyConfigs: Map<string, string>;\n\terror: string | undefined;\n}\n\nfunction emptyCustomModelsResult(error?: string): CustomModelsResult {\n\treturn {\n\t\tmodels: [],\n\t\toverrides: new Map(),\n\t\tmodelOverrides: new Map(),\n\t\tapiKeyConfigs: new Map(),\n\t\terror,\n\t};\n}\n\n/**\n * Deep merge compat settings\n */\nfunction mergeCompat(\n\tbaseCompat: Model<Api>['compat'],\n\toverrideCompat: ModelOverride['compat'],\n): Model<Api>['compat'] | undefined {\n\tif (!overrideCompat) return baseCompat;\n\n\tconst base = baseCompat as Record<string, unknown> | undefined;\n\tconst override = overrideCompat as Record<string, unknown>;\n\tconst merged = { ...base, ...override } as Record<string, unknown>;\n\n\t// Deep merge nested routing objects\n\tconst baseCompletions = base as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown } | undefined;\n\tconst overrideCompletions = override as { openRouterRouting?: unknown; vercelGatewayRouting?: unknown };\n\n\tif (baseCompletions?.openRouterRouting || overrideCompletions?.openRouterRouting) {\n\t\t(merged as { openRouterRouting: unknown }).openRouterRouting = {\n\t\t\t...((baseCompletions?.openRouterRouting as object) || {}),\n\t\t\t...((overrideCompletions?.openRouterRouting as object) || {}),\n\t\t};\n\t}\n\n\tif (baseCompletions?.vercelGatewayRouting || overrideCompletions?.vercelGatewayRouting) {\n\t\t(merged as { vercelGatewayRouting: unknown }).vercelGatewayRouting = {\n\t\t\t...((baseCompletions?.vercelGatewayRouting as object) || {}),\n\t\t\t...((overrideCompletions?.vercelGatewayRouting as object) || {}),\n\t\t};\n\t}\n\n\treturn merged as Model<Api>['compat'];\n}\n\n/**\n * Apply a model override to a model\n */\nfunction applyModelOverride(model: Model<Api>, override: ModelOverride): Model<Api> {\n\tconst result = { ...model };\n\n\tif (override.name !== undefined) result.name = override.name;\n\tif (override.reasoning !== undefined) result.reasoning = override.reasoning;\n\tif (override.input !== undefined) result.input = override.input as ('text' | 'image')[];\n\tif (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;\n\tif (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;\n\n\t// Merge cost (partial override)\n\tif (override.cost) {\n\t\tresult.cost = {\n\t\t\tinput: override.cost.input ?? model.cost.input,\n\t\t\toutput: override.cost.output ?? model.cost.output,\n\t\t\tcacheRead: override.cost.cacheRead ?? model.cost.cacheRead,\n\t\t\tcacheWrite: override.cost.cacheWrite ?? model.cost.cacheWrite,\n\t\t};\n\t}\n\n\t// Merge headers\n\tif (override.headers) {\n\t\tconst resolvedHeaders = resolveHeaders(override.headers);\n\t\tresult.headers = resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers;\n\t}\n\n\t// Deep merge compat\n\tresult.compat = mergeCompat(model.compat, override.compat);\n\n\treturn result;\n}\n\n/**\n * Model Registry - manages all models (built-in + custom)\n */\nexport class ModelRegistry {\n\tprivate models: Model<Api>[] = [];\n\tprivate customProviderApiKeys: Map<string, string> = new Map();\n\tprivate loadError: string | undefined = undefined;\n\tprivate loaded = false;\n\tprivate prewarmPromise: Promise<void> | null = null;\n\n\t// Performance caches\n\tprivate _availableModelsCache: Model<Api>[] | undefined;\n\tprivate _authStatusCache: Map<string, boolean> = new Map();\n\n\tconstructor(private modelsJsonPath: string = getModelsJsonPath()) {\n\t\t// Catalog loads on first use or via prewarm() — keeps gateway constructor off the hot path.\n\t}\n\n\tisLoaded(): boolean {\n\t\treturn this.loaded;\n\t}\n\n\t/** Synchronously materialize the catalog (idempotent). */\n\tensureLoaded(): void {\n\t\tif (this.loaded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t}\n\n\t/** Background-friendly catalog load (idempotent). */\n\tprewarm(): Promise<void> {\n\t\tif (this.loaded) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tif (this.prewarmPromise) {\n\t\t\treturn this.prewarmPromise;\n\t\t}\n\t\tthis.prewarmPromise = Promise.resolve().then(() => {\n\t\t\tthis.ensureLoaded();\n\t\t});\n\t\treturn this.prewarmPromise;\n\t}\n\n\t/**\n\t * Reload models from disk (built-in + custom from models.json)\n\t * Clears all caches\n\t */\n\trefresh(): void {\n\t\tthis.customProviderApiKeys.clear();\n\t\tthis.loadError = undefined;\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._authStatusCache.clear();\n\t\tthis.prewarmPromise = null;\n\t\tthis.loadModels();\n\t\tthis.loaded = true;\n\t\tlog.info('Model registry refreshed');\n\t}\n\n\t/**\n\t * Get any error from loading models.json (undefined if no error)\n\t */\n\tgetError(): string | undefined {\n\t\treturn this.loadError;\n\t}\n\n\t/**\n\t * Get all models (built-in + custom)\n\t * Results are cached until refresh() is called\n\t */\n\tgetAll(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\treturn this.models;\n\t}\n\n\t/**\n\t * Get only models that have auth configured\n\t * Results are cached on first call until refresh()\n\t */\n\tgetAvailable(): readonly Model<Api>[] {\n\t\tthis.ensureLoaded();\n\t\t// Lazy initialization with caching\n\t\tif (!this._availableModelsCache) {\n\t\t\tthis._availableModelsCache = this.models.filter((m) => this.hasAuth(m.provider));\n\t\t}\n\t\treturn this._availableModelsCache;\n\t}\n\n\t/**\n\t * Find a model by provider and ID\n\t */\n\tfind(provider: string, modelId: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\treturn this.models.find((m) => m.provider === provider && m.id === modelId);\n\t}\n\n\t/**\n\t * Resolve a model reference (provider/modelId or just modelId)\n\t */\n\tresolve(ref: string): Model<Api> | undefined {\n\t\tthis.ensureLoaded();\n\t\t// Handle provider/modelId format\n\t\tif (ref.includes('/')) {\n\t\t\tconst [provider, modelId] = ref.split('/');\n\t\t\treturn this.find(provider, modelId);\n\t\t}\n\n\t\t// Try to find by model ID only (search all providers)\n\t\tfor (const model of this.models) {\n\t\t\tif (model.id === ref) {\n\t\t\t\treturn model;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get API key for a provider (for custom providers from models.json)\n\t */\n\tgetApiKey(provider: string): string | undefined {\n\t\tthis.ensureLoaded();\n\t\t// First check custom provider configs\n\t\tconst keyConfig = this.customProviderApiKeys.get(provider);\n\t\tif (keyConfig) {\n\t\t\treturn resolveConfigValue(keyConfig);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Check if a provider has auth configured\n\t * Results are cached until refresh() is called\n\t */\n\tprivate hasAuth(provider: string): boolean {\n\t\t// Check cache first\n\t\tif (this._authStatusCache.has(provider)) {\n\t\t\treturn this._authStatusCache.get(provider)!;\n\t\t}\n\n\t\t// Compute and cache\n\t\tlet result: boolean;\n\t\t\n\t\t// Check custom provider configs from models.json first\n\t\tif (this.customProviderApiKeys.has(provider)) {\n\t\t\tconst key = this.getApiKey(provider);\n\t\t\tresult = !!key;\n\t\t} else {\n\t\t\t// Also check environment variables\n\t\t\tconst envKey = getApiKeyFromEnv(provider);\n\t\t\tresult = !!envKey;\n\t\t}\n\n\t\tthis._authStatusCache.set(provider, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Load all models\n\t * Clears caches to ensure fresh data\n\t */\n\tprivate loadModels(): void {\n\t\t// Clear caches before loading\n\t\tthis._availableModelsCache = undefined;\n\t\tthis._authStatusCache.clear();\n\n\t\t// Load custom models and overrides from models.json\n\t\tconst {\n\t\t\tmodels: customModels,\n\t\t\toverrides,\n\t\t\tmodelOverrides,\n\t\t\tapiKeyConfigs,\n\t\t\terror,\n\t\t} = this.loadCustomModels();\n\n\t\tif (error) {\n\t\t\tthis.loadError = error;\n\t\t\tlog.warn({ error }, 'Failed to load models.json, using built-in models only');\n\t\t}\n\n\t\t// Store API key configs for fallback resolution\n\t\tthis.customProviderApiKeys = apiKeyConfigs;\n\n\t\t// Load built-in models with overrides applied\n\t\tconst builtInModels = this.loadBuiltInModels(overrides, modelOverrides);\n\n\t\t// Merge custom models\n\t\tthis.models = this.mergeCustomModels(builtInModels, customModels);\n\n\t\tlog.debug(\n\t\t\t{ builtIn: builtInModels.length, custom: customModels.length, total: this.models.length },\n\t\t\t'Models loaded'\n\t\t);\n\t}\n\n\t/**\n\t * Load built-in models and apply provider/model overrides\n\t */\n\tprivate loadBuiltInModels(\n\t\toverrides: Map<string, ProviderOverride>,\n\t\tmodelOverrides: Map<string, Map<string, ModelOverride>>,\n\t): Model<Api>[] {\n\t\treturn getPiAiProviders().flatMap((provider) => {\n\t\t\ttry {\n\t\t\t\tconst models = getPiAiModels(provider as KnownProvider) as Model<Api>[];\n\t\t\t\tconst providerOverride = overrides.get(provider);\n\t\t\t\tconst perModelOverrides = modelOverrides.get(provider);\n\n\t\t\t\treturn models.map((m) => {\n\t\t\t\t\tlet model = m;\n\n\t\t\t\t\t// Apply provider-level baseUrl/headers override\n\t\t\t\t\tif (providerOverride) {\n\t\t\t\t\t\tconst resolvedHeaders = resolveHeaders(providerOverride.headers);\n\t\t\t\t\t\tmodel = {\n\t\t\t\t\t\t\t...model,\n\t\t\t\t\t\t\tbaseUrl: providerOverride.baseUrl ?? model.baseUrl,\n\t\t\t\t\t\t\theaders: resolvedHeaders ? { ...model.headers, ...resolvedHeaders } : model.headers,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply per-model override\n\t\t\t\t\tconst modelOverride = perModelOverrides?.get(m.id);\n\t\t\t\t\tif (modelOverride) {\n\t\t\t\t\t\tmodel = applyModelOverride(model, modelOverride);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn model;\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst errorMsg = err instanceof Error ? err.message : String(err);\n\t\t\t\tlog.error({ provider, error: errorMsg }, 'Failed to load built-in models for provider');\n\t\t\t\treturn [];\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Merge custom models into built-in list (custom wins on conflicts)\n\t */\n\tprivate mergeCustomModels(builtInModels: Model<Api>[], customModels: Model<Api>[]): Model<Api>[] {\n\t\tconst merged = [...builtInModels];\n\t\tfor (const customModel of customModels) {\n\t\t\tconst existingIndex = merged.findIndex(\n\t\t\t\t(m) => m.provider === customModel.provider && m.id === customModel.id\n\t\t\t);\n\t\t\tif (existingIndex >= 0) {\n\t\t\t\tmerged[existingIndex] = customModel;\n\t\t\t} else {\n\t\t\t\tmerged.push(customModel);\n\t\t\t}\n\t\t}\n\t\treturn merged;\n\t}\n\n\t/**\n\t * Load custom models from models.json\n\t */\n\tprivate loadCustomModels(): CustomModelsResult {\n\t\tif (!existsSync(this.modelsJsonPath)) {\n\t\t\treturn emptyCustomModelsResult();\n\t\t}\n\n\t\ttry {\n\t\t\tconst content = readFileSync(this.modelsJsonPath, 'utf-8');\n\t\t\tconst config: ModelsJsonConfig = JSON.parse(content);\n\n\t\t\t// Validate schema\n\t\t\tconst validation = validateModelsConfig(config);\n\t\t\tif (!validation.valid) {\n\t\t\t\tconst errors = validation.errors\n\t\t\t\t\t.map((e) => ` - ${e.path}: ${e.message}`)\n\t\t\t\t\t.join('\\n');\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Invalid models.json schema:\\n${errors}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst overrides = new Map<string, ProviderOverride>();\n\t\t\tconst modelOverrides = new Map<string, Map<string, ModelOverride>>();\n\t\t\tconst apiKeyConfigs = new Map<string, string>();\n\n\t\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\t\t// Apply provider-level baseUrl/headers/apiKey override\n\t\t\t\tif (providerConfig.baseUrl || providerConfig.headers || providerConfig.apiKey) {\n\t\t\t\t\toverrides.set(providerName, {\n\t\t\t\t\t\tbaseUrl: providerConfig.baseUrl,\n\t\t\t\t\t\theaders: providerConfig.headers,\n\t\t\t\t\t\tapiKey: providerConfig.apiKey,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Store API key config for fallback resolver\n\t\t\t\tif (providerConfig.apiKey) {\n\t\t\t\t\tapiKeyConfigs.set(providerName, providerConfig.apiKey);\n\t\t\t\t}\n\n\t\t\t\t// Store model overrides\n\t\t\t\tif (providerConfig.modelOverrides) {\n\t\t\t\t\tmodelOverrides.set(providerName, new Map(Object.entries(providerConfig.modelOverrides)));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tmodels: this.parseModels(config),\n\t\t\t\toverrides,\n\t\t\t\tmodelOverrides,\n\t\t\t\tapiKeyConfigs,\n\t\t\t\terror: undefined,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (error instanceof SyntaxError) {\n\t\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t\t`Failed to parse models.json: ${error.message}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn emptyCustomModelsResult(\n\t\t\t\t`Failed to load models.json: ${error instanceof Error ? error.message : error}\\n\\nFile: ${this.modelsJsonPath}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Parse custom models from config\n\t */\n\tprivate parseModels(config: ModelsJsonConfig): Model<Api>[] {\n\t\tconst models: Model<Api>[] = [];\n\t\tconst defaults = getDefaultModelValues();\n\n\t\tfor (const [providerName, providerConfig] of Object.entries(config.providers)) {\n\t\t\tconst modelDefs = providerConfig.models ?? [];\n\t\t\tif (modelDefs.length === 0) continue;\n\n\t\t\tfor (const modelDef of modelDefs) {\n\t\t\t\tconst api = modelDef.api || providerConfig.api;\n\t\t\t\tif (!api) continue;\n\n\t\t\t\t// Merge headers: provider headers are base, model headers override\n\t\t\t\t// Resolve env vars and shell commands in header values\n\t\t\t\tconst providerHeaders = resolveHeaders(providerConfig.headers);\n\t\t\t\tconst modelHeaders = resolveHeaders(modelDef.headers);\n\t\t\t\tlet headers =\n\t\t\t\t\tproviderHeaders || modelHeaders ? { ...providerHeaders, ...modelHeaders } : undefined;\n\n\t\t\t\t// If authHeader is true, add Authorization header with resolved API key\n\t\t\t\tif (providerConfig.authHeader && providerConfig.apiKey) {\n\t\t\t\t\tconst resolvedKey = resolveConfigValue(providerConfig.apiKey);\n\t\t\t\t\tif (resolvedKey) {\n\t\t\t\t\t\theaders = { ...headers, Authorization: `Bearer ${resolvedKey}` };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmodels.push({\n\t\t\t\t\tid: modelDef.id,\n\t\t\t\t\tname: modelDef.name ?? modelDef.id,\n\t\t\t\t\tapi: api as Api,\n\t\t\t\t\tprovider: providerName,\n\t\t\t\t\tbaseUrl: providerConfig.baseUrl!,\n\t\t\t\t\treasoning: modelDef.reasoning ?? false,\n\t\t\t\t\tinput: (modelDef.input ?? defaults.input) as ('text' | 'image')[],\n\t\t\t\t\tcost: modelDef.cost ?? defaults.cost,\n\t\t\t\t\tcontextWindow: modelDef.contextWindow ?? defaults.contextWindow,\n\t\t\t\t\tmaxTokens: modelDef.maxTokens ?? defaults.maxTokens,\n\t\t\t\t\theaders,\n\t\t\t\t\tcompat: modelDef.compat as Model<Api>['compat'],\n\t\t\t\t} as Model<Api>);\n\t\t\t}\n\t\t}\n\n\t\treturn models;\n\t}\n}\n\n// ============================================\n// Global Registry Instance\n// ============================================\n\nlet globalRegistry: ModelRegistry | undefined;\n\nexport function getModelRegistry(): ModelRegistry {\n\tif (!globalRegistry) {\n\t\tglobalRegistry = new ModelRegistry();\n\t}\n\treturn globalRegistry;\n}\n\nexport function resetModelRegistry(): void {\n\tglobalRegistry = undefined;\n}\n\n/** Schedule catalog load on a background turn (gateway post-ready sidecar). */\nexport function prewarmModelRegistry(): Promise<void> {\n\treturn getModelRegistry().prewarm();\n}\n"],"mappings":"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"}
|