@xopcai/xopc 0.0.162 → 0.0.163
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 +4 -2
- package/README.zh-CN.md +4 -2
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-hpcNv9MZ.js → activity-store-Xj95LzTv.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Zf9UQEmQ.js → agent-avatar-dicebear-C-QeUFwU.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DVKlWKJE.js +2 -0
- package/dist/gateway/static/root/assets/{api-Dnatri09.js → api-BTLmAm1_.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BBTR9wJP.js → app-management-settings-panel-zc6Gf-S5.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C2zpLCHD.js → appearance-settings-0fMLnOWn.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BZXEJDIV.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-9eR_ODY1.js → archive-plugin-DOiR_E21.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DPuWYUeX.js → attachment-load-BxmYl1D1.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-Dw49OJRl.js → automation-suggestion-card-BhZOirad.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-B8CnkoXv.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BdkJpDFm.js → binary-plugins-DTTKsvgk.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CAi7SXYU.js → block-editor-C7se7iqg.js} +31 -31
- package/dist/gateway/static/root/assets/browser-settings-page-BCPWKI9V.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-Dx6wkGz1.js → browser-workflow-inputs-kxmStCcv.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-Skertc-A.js → browser-workflows-page-CwYf9OM_.js} +2 -2
- package/dist/gateway/static/root/assets/capabilities-settings-panel-C7lr_mX2.js +2 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-CNFl7dM3.js → capability-presets-api-BZKh2cWX.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-Ble9kHRu.js +2 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-DYQyGDw4.js → channel-recipient-api-r7tdbnJE.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-CtQQQHrv.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-_VirfMKW.js +1 -0
- package/dist/gateway/static/root/assets/{connector-logo-Bng6kxYF.js → connector-logo-BpnQYAxA.js} +1 -1
- package/dist/gateway/static/root/assets/connectors-page-BXWJSJeY.js +2 -0
- package/dist/gateway/static/root/assets/desktop-pet-B86W4a5c.js +1 -0
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BVUyefSd.js → desktop-pet-settings-uv8Grtgk.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DjSZAPz_.js → directory-picker-path-field-C4TTvf7p.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-CAZk2AM4.js → dreaming-settings-CzJAUPvM.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-C2F6vTTd.js → extension-debug-page-Ci2mOYUt.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-AnIt4bn4.js → extension-page-DeXdmhXQ.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-C93vaOsU.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-api-DLFyZv33.js → gateway-config-api-C31Hlblp.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DnQAA-qq.js → gateway-settings-D3zS6RZh.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DbzLyJ3R.js → gateway-startup-retry-CSRvCqxh.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-DrnKFC6M.js → goal-create-dialog-CWp2b7__.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-Dtm29FxD.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-REmr3QCr.js → goals-config-api-D4wYNRrf.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-jMzBJs6e.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-Dz0F3uRO.js → goals-settings-Bx2jVvhQ.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-CQFY5gYs.js → heartbeat-settings-BEIF1eXy.js} +1 -1
- package/dist/gateway/static/root/assets/index-BXtJvaQl.css +1 -0
- package/dist/gateway/static/root/assets/{index-C8JkTS6d.js → index-HZdBKfk_.js} +70 -70
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BnOQXU5k.js → keyboard-shortcuts-settings-DOEDpvTM.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-CseW9jD3.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-KsOtWOyM.js → local-apps-page-B0OpGpxv.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-0lpYdNDr.js → locale-store-Ys6RP7Be.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-DVqPbth5.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-D5GRg10r.js → markdown-split-CEZwysCH.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C1ryULGs.js → media-plugins-CpGKE7B0.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BzI9Wx30.js +5 -0
- package/dist/gateway/static/root/assets/{notes-page-CIeZ1_DT.js → notes-page-CdiuDZ5a.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-mrc3xtpn.js +4 -0
- package/dist/gateway/static/root/assets/{page-tabs-Caj1-E_X.js → page-tabs-BkH5AVV2.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DKwEce-9.js → preview-open-alternatives-CQai8f9D.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-B90ZskkN.js → product-open-page-B2kSdB2b.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CfhPJLkH.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-BfMoKjdm.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CrDtcsZ9.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BDYt53uQ.js → save-bar-controls-NGYnO7n7.js} +1 -1
- package/dist/gateway/static/root/assets/schedule-field-nLOphnv3.js +1 -0
- package/dist/gateway/static/root/assets/{schema-form-D7oCARF7.js → schema-form-D0e90ndE.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-D3DbF3dV.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BZp0O2dH.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CARTHCxH.js → settings-form-section-X2Sl-EAk.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-DEwYqESe.js → settings-loading-skeleton-DOnUabm7.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-B6vVdHeQ.js → settings-page-C4UUNi1n.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-D3srt5Bi.js → settings-page-layout-C1yYqbT6.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-84iao4DZ.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-Ck9SxiXw.js → share-preview-page-Cfy_pH7V.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DtcwQvRG.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-L7j5Gc8Z.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-1Ps8PjsP.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DLBUQSk2.js → system-settings-panel-Da81RJ6G.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-C1oaqeD2.js → theme-store-DflSp9o4.js} +1 -1
- package/dist/gateway/static/root/assets/time-picker-BIkOW-2L.js +1 -0
- package/dist/gateway/static/root/assets/{typed-models-lib-Divbg_C4.js → typed-models-lib--HptwFcD.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-CP9a_rAf.js → use-channel-catalog-CMHY4ZfW.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-BYAAs2iW.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-nvIZerol.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-page-J35JkJ7_.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-C4wYDYqV.js +1 -0
- package/dist/gateway/static/root/assets/work-page-DMvitV6c.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-DbDPYQwB.js → workflow-run-setup-panel-D96MHABy.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-JMN0nMbM.js +11 -0
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/client-error-format.d.ts +1 -1
- package/dist/src/agent/client-error-format.js +6 -2
- package/dist/src/agent/embedded/run-for-session.js +38 -31
- package/dist/src/agent/embedded/session-runner.d.ts +1 -0
- package/dist/src/agent/embedded/session-runner.js +12 -4
- package/dist/src/agent/failover-error.d.ts +1 -1
- package/dist/src/agent/image/generation/openai-compatible-image-provider.d.ts +2 -6
- package/dist/src/agent/image/generation/openai-compatible-image-provider.js +1 -3
- package/dist/src/agent/image/generation/provider-registry.d.ts +5 -46
- package/dist/src/agent/image/generation/provider-registry.js +24 -73
- package/dist/{extensions/dashscope/src/image-generation-provider.d.ts → src/agent/image/generation/providers/dashscope.d.ts} +3 -6
- package/dist/{extensions/dashscope/src/image-generation-provider.js → src/agent/image/generation/providers/dashscope.js} +36 -59
- package/dist/{extensions/fal/src/image-generation-provider.d.ts → src/agent/image/generation/providers/fal.d.ts} +1 -1
- package/dist/{extensions/fal/src/image-generation-provider.js → src/agent/image/generation/providers/fal.js} +19 -29
- package/dist/{extensions/google/src/image-generation-provider.d.ts → src/agent/image/generation/providers/google.d.ts} +2 -2
- package/dist/{extensions/google/src/image-generation-provider.js → src/agent/image/generation/providers/google.js} +23 -30
- package/dist/{extensions/minimax/src/image-generation-provider.d.ts → src/agent/image/generation/providers/minimax.d.ts} +2 -5
- package/dist/{extensions/minimax/src/image-generation-provider.js → src/agent/image/generation/providers/minimax.js} +35 -51
- package/dist/{extensions/openai/src/image-generation-provider.d.ts → src/agent/image/generation/providers/openai.d.ts} +2 -2
- package/dist/{extensions/openai/src/image-generation-provider.js → src/agent/image/generation/providers/openai.js} +13 -38
- package/dist/src/agent/image/generation/runtime-types.d.ts +1 -0
- package/dist/src/agent/image/generation/runtime.d.ts +1 -3
- package/dist/src/agent/image/generation/runtime.js +6 -6
- package/dist/src/agent/image/generation/types.d.ts +23 -3
- package/dist/src/agent/image/index.d.ts +1 -1
- package/dist/src/agent/image/index.js +2 -2
- package/dist/src/agent/media-generation/runtime-shared.d.ts +2 -0
- package/dist/src/agent/media-generation/runtime-shared.js +1 -0
- package/dist/src/agent/tools/factory.js +4 -1
- package/dist/src/agent/tools/image-generate-tool.d.ts +2 -0
- package/dist/src/agent/tools/image-generate-tool.js +14 -7
- package/dist/src/auth/sync-provider-auth.d.ts +3 -0
- package/dist/src/auth/sync-provider-auth.js +12 -1
- package/dist/src/cli/commands/models.js +2 -5
- package/dist/src/cli/commands/onboard/model.js +3 -2
- package/dist/src/cli/commands/setup-shared/types.d.ts +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/models-json.d.ts +6 -0
- package/dist/src/config/models-json.js +2 -6
- package/dist/src/config/schema.d.ts +26 -15
- package/dist/src/config/schema.js +23 -12
- package/dist/src/gateway/hono/app.js +12 -6
- package/dist/src/gateway/hono/lib/safe-providers-config.d.ts +0 -3
- package/dist/src/gateway/hono/lib/safe-providers-config.js +1 -3
- package/dist/src/gateway/hono/middleware/strict-rate-limit.d.ts +4 -0
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +8 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -11
- package/dist/src/gateway/hono/routes/deps.d.ts +1 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js +9 -2
- package/dist/src/gateway/hono/routes/models.js +151 -129
- package/dist/src/gateway/image-generation-setup.d.ts +40 -0
- package/dist/src/gateway/image-generation-setup.js +130 -0
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +12 -0
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +10 -0
- package/dist/src/media-shared/http/private-network.d.ts +1 -1
- package/dist/src/media-shared/http/private-network.js +1 -1
- package/dist/src/providers/auth-runtime/resolve-api-key.d.ts +2 -4
- package/dist/src/providers/auth-runtime/resolve-api-key.js +2 -4
- package/dist/src/providers/auth-runtime/resolve-auth.d.ts +3 -4
- package/dist/src/providers/auth-runtime/resolve-auth.js +18 -18
- package/dist/src/providers/domestic-presets.d.ts +22 -0
- package/dist/src/providers/domestic-presets.js +25 -0
- package/dist/src/providers/model-catalog-store.d.ts +71 -0
- package/dist/src/providers/model-catalog-store.js +102 -0
- package/dist/src/providers/model-catalog-sync-service.d.ts +41 -0
- package/dist/src/providers/model-catalog-sync-service.js +142 -0
- package/dist/src/providers/model-reference-auditor.d.ts +14 -0
- package/dist/src/providers/model-reference-auditor.js +71 -0
- package/dist/src/providers/model-registry.d.ts +4 -1
- package/dist/src/providers/model-registry.js +35 -2
- package/dist/src/providers/presentation.js +2 -0
- package/dist/src/providers/xopc-cloud-connection.d.ts +51 -0
- package/dist/src/providers/xopc-cloud-connection.js +196 -0
- package/dist/src/session/index.d.ts +1 -1
- package/dist/src/session/index.js +2 -2
- package/dist/src/session/session-title.d.ts +2 -0
- package/dist/src/session/session-title.js +24 -3
- package/package.json +5 -7
- package/dist/extensions/dashscope/src/index.d.ts +0 -4
- package/dist/extensions/dashscope/src/index.js +0 -2
- package/dist/extensions/dashscope/xopc.extension.json +0 -15
- package/dist/extensions/fal/src/index.d.ts +0 -4
- package/dist/extensions/fal/src/index.js +0 -2
- package/dist/extensions/fal/xopc.extension.json +0 -14
- package/dist/extensions/google/src/index.d.ts +0 -4
- package/dist/extensions/google/src/index.js +0 -2
- package/dist/extensions/google/xopc.extension.json +0 -14
- package/dist/extensions/minimax/src/index.d.ts +0 -4
- package/dist/extensions/minimax/src/index.js +0 -2
- package/dist/extensions/minimax/xopc.extension.json +0 -15
- package/dist/extensions/openai/src/index.d.ts +0 -4
- package/dist/extensions/openai/src/index.js +0 -2
- package/dist/extensions/openai/xopc.extension.json +0 -14
- package/dist/gateway/static/root/assets/agents-DfVkZlHc.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-BMtAa4Ra.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-BiSAMYTr.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-DHmaEJS2.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-B5wSgf4f.js +0 -2
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DyvFZwBj.js +0 -2
- package/dist/gateway/static/root/assets/channels-settings-BBKEqDZn.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-Drk110ve.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-HpgaUDQ1.js +0 -2
- package/dist/gateway/static/root/assets/desktop-pet-Bpf6oegd.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-CLSc6682.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-Cw1hpJkZ.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-BDGkTVma.js +0 -2
- package/dist/gateway/static/root/assets/index-hmrG55qg.css +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-Bdef1b7F.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-CwLPgrWh.js +0 -7
- package/dist/gateway/static/root/assets/messages-BwQ3WssU.js +0 -5
- package/dist/gateway/static/root/assets/notes-workbench-Cf06q19x.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-SHTurM4t.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BcC2qUAw.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-6vGefBHv.js +0 -1
- package/dist/gateway/static/root/assets/schedule-field-Bcdni4Pj.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-C5014a53.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CDY3ZI1K.js +0 -1
- package/dist/gateway/static/root/assets/settings-collapsible-section-6eNF8Jey.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-z-rF0Hdg.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CHZFXE_d.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-B7p2QNXt.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-ncw3tX9P.js +0 -2
- package/dist/gateway/static/root/assets/user-context-page-iYfeSLKI.js +0 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-CrwkicvT.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-page-BQWxyPg8.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-50ZzGay5.js +0 -1
- package/dist/gateway/static/root/assets/work-page-DPqEahx7.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-C3eIC5HZ.js +0 -11
- package/dist/src/agent/image/generation/bundled-registry.d.ts +0 -18
- package/dist/src/agent/image/generation/bundled-registry.js +0 -35
- package/dist/src/agent/image/generation/bundled.d.ts +0 -10
- package/dist/src/agent/image/generation/bundled.js +0 -15
- package/dist/src/agent/image/generation/image-provider-ui.d.ts +0 -20
- package/dist/src/agent/image/generation/image-provider-ui.js +0 -1
- package/dist/src/gateway/image-capabilities.d.ts +0 -28
- package/dist/src/gateway/image-capabilities.js +0 -78
- package/dist/src/generated/bundled-image-generation-providers.d.ts +0 -14
- package/dist/src/generated/bundled-image-generation-providers.js +0 -17
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Resolution order:
|
|
6
6
|
* 1. AuthProfileStore (per-agent / per-profile; noop in Step 1)
|
|
7
|
-
* 2.
|
|
8
|
-
* 3. PROVIDER_ENV_MAP[providerId] env vars (or `<PROVIDER>_API_KEY` fallback)
|
|
7
|
+
* 2. PROVIDER_ENV_MAP[providerId] env vars (or `<PROVIDER>_API_KEY` fallback)
|
|
9
8
|
*
|
|
10
9
|
* Distinct from `src/providers/index.ts#getApiKeySync` which is keyed to the
|
|
11
10
|
* LLM model registry. Capability providers care only about per-vendor API
|
|
@@ -21,7 +20,6 @@ import type { ResolveApiKeyOptions } from './types.js';
|
|
|
21
20
|
*
|
|
22
21
|
* Resolution order (matches spec §8.4):
|
|
23
22
|
* 1. AuthProfileStore (per-agent profile — may be OAuth)
|
|
24
|
-
* 2.
|
|
25
|
-
* 3. PROVIDER_ENV_MAP[providerId] env vars
|
|
23
|
+
* 2. PROVIDER_ENV_MAP[providerId] env vars
|
|
26
24
|
*/
|
|
27
25
|
export declare function resolveApiKeyForProvider(options: ResolveApiKeyOptions): string | undefined;
|
|
@@ -6,8 +6,7 @@ import { resolveAuthProfileForProvider } from "./resolve-auth.js";
|
|
|
6
6
|
*
|
|
7
7
|
* Resolution order:
|
|
8
8
|
* 1. AuthProfileStore (per-agent / per-profile; noop in Step 1)
|
|
9
|
-
* 2.
|
|
10
|
-
* 3. PROVIDER_ENV_MAP[providerId] env vars (or `<PROVIDER>_API_KEY` fallback)
|
|
9
|
+
* 2. PROVIDER_ENV_MAP[providerId] env vars (or `<PROVIDER>_API_KEY` fallback)
|
|
11
10
|
*
|
|
12
11
|
* Distinct from `src/providers/index.ts#getApiKeySync` which is keyed to the
|
|
13
12
|
* LLM model registry. Capability providers care only about per-vendor API
|
|
@@ -22,8 +21,7 @@ import { resolveAuthProfileForProvider } from "./resolve-auth.js";
|
|
|
22
21
|
*
|
|
23
22
|
* Resolution order (matches spec §8.4):
|
|
24
23
|
* 1. AuthProfileStore (per-agent profile — may be OAuth)
|
|
25
|
-
* 2.
|
|
26
|
-
* 3. PROVIDER_ENV_MAP[providerId] env vars
|
|
24
|
+
* 2. PROVIDER_ENV_MAP[providerId] env vars
|
|
27
25
|
*/
|
|
28
26
|
function resolveApiKeyForProvider(options) {
|
|
29
27
|
return resolveAuthProfileForProvider(options).apiKey;
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Resolution order matches `resolveApiKeyForProvider`:
|
|
8
8
|
* 1. AuthProfileStore (per-agent profile — may be OAuth)
|
|
9
|
-
* 2.
|
|
10
|
-
* 3. PROVIDER_ENV_MAP[providerId] env vars
|
|
9
|
+
* 2. Environment variables
|
|
11
10
|
*
|
|
12
11
|
* Returns:
|
|
13
12
|
* - `mode: 'oauth' | 'azure-key' | 'api-key'`
|
|
@@ -19,8 +18,8 @@ export interface ProviderAuthResolution {
|
|
|
19
18
|
apiKey?: string;
|
|
20
19
|
mode: ProviderAuthMode;
|
|
21
20
|
profileId?: string;
|
|
22
|
-
/** Source bucket
|
|
23
|
-
source: 'store' | '
|
|
21
|
+
/** Source bucket. */
|
|
22
|
+
source: 'store' | 'env' | 'none';
|
|
24
23
|
/** Vendor metadata copied from the matched profile (azure resource etc.). */
|
|
25
24
|
meta?: Record<string, unknown>;
|
|
26
25
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { init_sync_provider_auth, resolveProviderApiKeyForAgentSync } from "../../auth/sync-provider-auth.js";
|
|
1
2
|
import { getApiKeyFromEnv, init_env_keys } from "../env-keys.js";
|
|
2
3
|
import { getDefaultAuthProfileStore } from "./auth-profile-store.js";
|
|
3
4
|
//#region src/providers/auth-runtime/resolve-auth.ts
|
|
4
5
|
init_env_keys();
|
|
6
|
+
init_sync_provider_auth();
|
|
5
7
|
function resolveAuthProfileForProvider(options) {
|
|
6
8
|
const { providerId } = options;
|
|
7
9
|
if (!providerId) return {
|
|
@@ -20,22 +22,28 @@ function resolveAuthProfileForProvider(options) {
|
|
|
20
22
|
meta: profile.meta
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
if (!options.store && !options.envReader) {
|
|
26
|
+
const storedKey = resolveProviderApiKeyForAgentSync(providerId, options.agentId, options.cfg);
|
|
27
|
+
if (storedKey) {
|
|
28
|
+
const azure = readCfgAzureMeta(options.cfg, providerId);
|
|
29
|
+
return {
|
|
30
|
+
apiKey: storedKey,
|
|
31
|
+
mode: azure ? "azure-key" : "api-key",
|
|
32
|
+
source: "store",
|
|
33
|
+
meta: azure
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const envKey = options.envReader ? readFromCustomEnv(options.envReader, providerId) : getApiKeyFromEnv(providerId);
|
|
38
|
+
if (envKey) {
|
|
25
39
|
const azure = readCfgAzureMeta(options.cfg, providerId);
|
|
26
40
|
return {
|
|
27
|
-
apiKey:
|
|
41
|
+
apiKey: envKey,
|
|
28
42
|
mode: azure ? "azure-key" : "api-key",
|
|
29
|
-
source: "
|
|
43
|
+
source: "env",
|
|
30
44
|
meta: azure
|
|
31
45
|
};
|
|
32
46
|
}
|
|
33
|
-
const envKey = options.envReader ? readFromCustomEnv(options.envReader, providerId) : getApiKeyFromEnv(providerId);
|
|
34
|
-
if (envKey) return {
|
|
35
|
-
apiKey: envKey,
|
|
36
|
-
mode: "api-key",
|
|
37
|
-
source: "env"
|
|
38
|
-
};
|
|
39
47
|
return {
|
|
40
48
|
apiKey: void 0,
|
|
41
49
|
mode: "api-key",
|
|
@@ -49,14 +57,6 @@ function pickProfile(store, providerId, profileName) {
|
|
|
49
57
|
return;
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
|
-
function readCfgApiKey(cfg, providerId) {
|
|
53
|
-
const providers = cfg?.providers;
|
|
54
|
-
if (!providers || typeof providers !== "object") return void 0;
|
|
55
|
-
const entry = providers[providerId];
|
|
56
|
-
if (!entry || typeof entry !== "object") return void 0;
|
|
57
|
-
const apiKey = entry.apiKey;
|
|
58
|
-
return typeof apiKey === "string" && apiKey.length > 0 ? apiKey : void 0;
|
|
59
|
-
}
|
|
60
60
|
function readCfgAzureMeta(cfg, providerId) {
|
|
61
61
|
const providers = cfg?.providers;
|
|
62
62
|
if (!providers || typeof providers !== "object") return void 0;
|
|
@@ -30,8 +30,30 @@ export interface DomesticProviderPreset {
|
|
|
30
30
|
models: DomesticProviderModelPreset[];
|
|
31
31
|
aliases: string[];
|
|
32
32
|
quirks?: string[];
|
|
33
|
+
onboardingIcon?: string;
|
|
34
|
+
requiresModelDiscovery?: boolean;
|
|
33
35
|
}
|
|
34
36
|
export declare const DOMESTIC_PROVIDER_PRESETS: readonly [{
|
|
37
|
+
readonly id: "xopc-cloud";
|
|
38
|
+
readonly displayName: "XOPC Model Service";
|
|
39
|
+
readonly description: "Official XOPC OpenAI-compatible model service. Available models are loaded from your account.";
|
|
40
|
+
readonly docsUrl: "https://console.xopc.ai/models";
|
|
41
|
+
readonly apiKeyUrl: "https://console.xopc.ai/models";
|
|
42
|
+
readonly envVars: ["XOPC_MODEL_API_KEY"];
|
|
43
|
+
readonly api: "openai-completions";
|
|
44
|
+
readonly baseUrlPresets: [{
|
|
45
|
+
readonly id: "official";
|
|
46
|
+
readonly label: "XOPC Official";
|
|
47
|
+
readonly baseUrl: "https://router.xopc.ai/v1";
|
|
48
|
+
}];
|
|
49
|
+
readonly defaultBaseUrlPreset: "official";
|
|
50
|
+
readonly defaultModel: "";
|
|
51
|
+
readonly models: [];
|
|
52
|
+
readonly aliases: ["xopc", "xopc cloud", "xopc models"];
|
|
53
|
+
readonly onboardingIcon: "☁️";
|
|
54
|
+
readonly requiresModelDiscovery: true;
|
|
55
|
+
readonly quirks: ["Connect through XOPC Console; credentials and available models are configured automatically."];
|
|
56
|
+
}, {
|
|
35
57
|
readonly id: "dashscope-cn";
|
|
36
58
|
readonly displayName: "Alibaba Bailian / DashScope China";
|
|
37
59
|
readonly description: "Alibaba Bailian Qwen models through the China DashScope OpenAI-compatible endpoint.";
|
|
@@ -87,6 +87,31 @@ const MINIMAX_MODELS = [
|
|
|
87
87
|
}
|
|
88
88
|
];
|
|
89
89
|
const DOMESTIC_PROVIDER_PRESETS = [
|
|
90
|
+
{
|
|
91
|
+
id: "xopc-cloud",
|
|
92
|
+
displayName: "XOPC Model Service",
|
|
93
|
+
description: "Official XOPC OpenAI-compatible model service. Available models are loaded from your account.",
|
|
94
|
+
docsUrl: "https://console.xopc.ai/models",
|
|
95
|
+
apiKeyUrl: "https://console.xopc.ai/models",
|
|
96
|
+
envVars: ["XOPC_MODEL_API_KEY"],
|
|
97
|
+
api: "openai-completions",
|
|
98
|
+
baseUrlPresets: [{
|
|
99
|
+
id: "official",
|
|
100
|
+
label: "XOPC Official",
|
|
101
|
+
baseUrl: "https://router.xopc.ai/v1"
|
|
102
|
+
}],
|
|
103
|
+
defaultBaseUrlPreset: "official",
|
|
104
|
+
defaultModel: "",
|
|
105
|
+
models: [],
|
|
106
|
+
aliases: [
|
|
107
|
+
"xopc",
|
|
108
|
+
"xopc cloud",
|
|
109
|
+
"xopc models"
|
|
110
|
+
],
|
|
111
|
+
onboardingIcon: "☁️",
|
|
112
|
+
requiresModelDiscovery: true,
|
|
113
|
+
quirks: ["Connect through XOPC Console; credentials and available models are configured automatically."]
|
|
114
|
+
},
|
|
90
115
|
{
|
|
91
116
|
id: "dashscope-cn",
|
|
92
117
|
displayName: "Alibaba Bailian / DashScope China",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const CatalogModelSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
availability: z.ZodEnum<{
|
|
6
|
+
available: "available";
|
|
7
|
+
unavailable: "unavailable";
|
|
8
|
+
}>;
|
|
9
|
+
maxOutputTokens: z.ZodNullable<z.ZodNumber>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
declare const CatalogSourceSchema: z.ZodObject<{
|
|
12
|
+
providerId: z.ZodString;
|
|
13
|
+
baseUrl: z.ZodString;
|
|
14
|
+
api: z.ZodEnum<{
|
|
15
|
+
"openai-completions": "openai-completions";
|
|
16
|
+
"openai-responses": "openai-responses";
|
|
17
|
+
}>;
|
|
18
|
+
etag: z.ZodNullable<z.ZodString>;
|
|
19
|
+
recommendedModel: z.ZodNullable<z.ZodString>;
|
|
20
|
+
lastSuccessAt: z.ZodNumber;
|
|
21
|
+
models: z.ZodArray<z.ZodObject<{
|
|
22
|
+
id: z.ZodString;
|
|
23
|
+
name: z.ZodString;
|
|
24
|
+
availability: z.ZodEnum<{
|
|
25
|
+
available: "available";
|
|
26
|
+
unavailable: "unavailable";
|
|
27
|
+
}>;
|
|
28
|
+
maxOutputTokens: z.ZodNullable<z.ZodNumber>;
|
|
29
|
+
}, z.core.$strip>>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
declare const ModelCatalogSchema: z.ZodObject<{
|
|
32
|
+
sources: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
33
|
+
providerId: z.ZodString;
|
|
34
|
+
baseUrl: z.ZodString;
|
|
35
|
+
api: z.ZodEnum<{
|
|
36
|
+
"openai-completions": "openai-completions";
|
|
37
|
+
"openai-responses": "openai-responses";
|
|
38
|
+
}>;
|
|
39
|
+
etag: z.ZodNullable<z.ZodString>;
|
|
40
|
+
recommendedModel: z.ZodNullable<z.ZodString>;
|
|
41
|
+
lastSuccessAt: z.ZodNumber;
|
|
42
|
+
models: z.ZodArray<z.ZodObject<{
|
|
43
|
+
id: z.ZodString;
|
|
44
|
+
name: z.ZodString;
|
|
45
|
+
availability: z.ZodEnum<{
|
|
46
|
+
available: "available";
|
|
47
|
+
unavailable: "unavailable";
|
|
48
|
+
}>;
|
|
49
|
+
maxOutputTokens: z.ZodNullable<z.ZodNumber>;
|
|
50
|
+
}, z.core.$strip>>;
|
|
51
|
+
}, z.core.$strip>>;
|
|
52
|
+
}, z.core.$strip>;
|
|
53
|
+
export type CatalogModel = z.infer<typeof CatalogModelSchema>;
|
|
54
|
+
export type CatalogSource = z.infer<typeof CatalogSourceSchema>;
|
|
55
|
+
export type ModelCatalogSnapshot = z.infer<typeof ModelCatalogSchema>;
|
|
56
|
+
export type AvailableCatalogModel = Omit<CatalogModel, 'availability'>;
|
|
57
|
+
export declare class ModelCatalogStore {
|
|
58
|
+
private readonly path;
|
|
59
|
+
constructor(path?: string);
|
|
60
|
+
load(): ModelCatalogSnapshot;
|
|
61
|
+
getSource(sourceId: string): CatalogSource | undefined;
|
|
62
|
+
saveSource(sourceId: string, source: CatalogSource): void;
|
|
63
|
+
removeSource(sourceId: string): boolean;
|
|
64
|
+
replaceSourceModels(sourceId: string, source: Omit<CatalogSource, 'models'>, models: AvailableCatalogModel[]): {
|
|
65
|
+
addedCount: number;
|
|
66
|
+
unavailableCount: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export declare function getModelCatalogStore(): ModelCatalogStore;
|
|
70
|
+
export declare function resetModelCatalogStore(): void;
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
3
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
4
|
+
import { init_logger } from "../utils/logger.js";
|
|
5
|
+
import { init_write_file_atomic, writeTextAtomicSync } from "../infra/write-file-atomic.js";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
//#region src/providers/model-catalog-store.ts
|
|
10
|
+
function getModelCatalogStore() {
|
|
11
|
+
globalModelCatalogStore ??= new ModelCatalogStore();
|
|
12
|
+
return globalModelCatalogStore;
|
|
13
|
+
}
|
|
14
|
+
function resetModelCatalogStore() {
|
|
15
|
+
globalModelCatalogStore = void 0;
|
|
16
|
+
}
|
|
17
|
+
var log, CatalogModelSchema, CatalogSourceSchema, ModelCatalogSchema, ModelCatalogStore, globalModelCatalogStore;
|
|
18
|
+
var init_model_catalog_store = __esmMin((() => {
|
|
19
|
+
init_paths_state();
|
|
20
|
+
init_write_file_atomic();
|
|
21
|
+
init_logger();
|
|
22
|
+
log = createLogger("ModelCatalogStore");
|
|
23
|
+
CatalogModelSchema = z.object({
|
|
24
|
+
id: z.string().min(1),
|
|
25
|
+
name: z.string().min(1),
|
|
26
|
+
availability: z.enum(["available", "unavailable"]),
|
|
27
|
+
maxOutputTokens: z.number().positive().nullable()
|
|
28
|
+
});
|
|
29
|
+
CatalogSourceSchema = z.object({
|
|
30
|
+
providerId: z.string().min(1),
|
|
31
|
+
baseUrl: z.string().url(),
|
|
32
|
+
api: z.enum(["openai-completions", "openai-responses"]),
|
|
33
|
+
etag: z.string().nullable(),
|
|
34
|
+
recommendedModel: z.string().nullable(),
|
|
35
|
+
lastSuccessAt: z.number().int().nonnegative(),
|
|
36
|
+
models: z.array(CatalogModelSchema)
|
|
37
|
+
});
|
|
38
|
+
ModelCatalogSchema = z.object({ sources: z.record(z.string(), CatalogSourceSchema) });
|
|
39
|
+
ModelCatalogStore = class {
|
|
40
|
+
constructor(path = join(resolveStateDir(), "model-catalog.json")) {
|
|
41
|
+
this.path = path;
|
|
42
|
+
}
|
|
43
|
+
load() {
|
|
44
|
+
if (!existsSync(this.path)) return { sources: {} };
|
|
45
|
+
try {
|
|
46
|
+
const parsed = ModelCatalogSchema.safeParse(JSON.parse(readFileSync(this.path, "utf8")));
|
|
47
|
+
if (parsed.success) return parsed.data;
|
|
48
|
+
log.warn({
|
|
49
|
+
path: this.path,
|
|
50
|
+
errorMessage: parsed.error.message
|
|
51
|
+
}, "Ignoring invalid model catalog snapshot");
|
|
52
|
+
} catch (err) {
|
|
53
|
+
log.warn({
|
|
54
|
+
err,
|
|
55
|
+
path: this.path
|
|
56
|
+
}, "Ignoring unreadable model catalog snapshot");
|
|
57
|
+
}
|
|
58
|
+
return { sources: {} };
|
|
59
|
+
}
|
|
60
|
+
getSource(sourceId) {
|
|
61
|
+
return this.load().sources[sourceId];
|
|
62
|
+
}
|
|
63
|
+
saveSource(sourceId, source) {
|
|
64
|
+
const current = this.load();
|
|
65
|
+
const next = ModelCatalogSchema.parse({ sources: {
|
|
66
|
+
...current.sources,
|
|
67
|
+
[sourceId]: source
|
|
68
|
+
} });
|
|
69
|
+
writeTextAtomicSync(this.path, `${JSON.stringify(next, null, 2)}\n`, { mode: 384 });
|
|
70
|
+
}
|
|
71
|
+
removeSource(sourceId) {
|
|
72
|
+
const current = this.load();
|
|
73
|
+
if (!current.sources[sourceId]) return false;
|
|
74
|
+
const { [sourceId]: _removed, ...sources } = current.sources;
|
|
75
|
+
writeTextAtomicSync(this.path, `${JSON.stringify({ sources }, null, 2)}\n`, { mode: 384 });
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
replaceSourceModels(sourceId, source, models) {
|
|
79
|
+
const previous = this.getSource(sourceId);
|
|
80
|
+
const nextIds = new Set(models.map((model) => model.id));
|
|
81
|
+
const previousAvailableIds = new Set((previous?.models ?? []).filter((model) => model.availability === "available").map((model) => model.id));
|
|
82
|
+
const unavailable = (previous?.models ?? []).filter((model) => !nextIds.has(model.id)).map((model) => ({
|
|
83
|
+
...model,
|
|
84
|
+
availability: "unavailable"
|
|
85
|
+
}));
|
|
86
|
+
this.saveSource(sourceId, {
|
|
87
|
+
...source,
|
|
88
|
+
models: [...models.map((model) => ({
|
|
89
|
+
...model,
|
|
90
|
+
availability: "available"
|
|
91
|
+
})), ...unavailable]
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
addedCount: models.filter((model) => !previousAvailableIds.has(model.id)).length,
|
|
95
|
+
unavailableCount: unavailable.length
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}));
|
|
100
|
+
//#endregion
|
|
101
|
+
init_model_catalog_store();
|
|
102
|
+
export { ModelCatalogStore, getModelCatalogStore, init_model_catalog_store, resetModelCatalogStore };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
import { type ModelsJsonConfig } from '../config/models-json.js';
|
|
3
|
+
import { type ModelCatalogStore } from './model-catalog-store.js';
|
|
4
|
+
import { discoverProviderModels } from './model-discovery.js';
|
|
5
|
+
import { XopcCloudConnectionService } from './xopc-cloud-connection.js';
|
|
6
|
+
export interface ModelCatalogSyncStatus {
|
|
7
|
+
running: boolean;
|
|
8
|
+
refreshing: boolean;
|
|
9
|
+
lastAttemptAt?: number;
|
|
10
|
+
lastSuccessAt?: number;
|
|
11
|
+
lastError?: string;
|
|
12
|
+
sourceErrors?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
export declare class ModelCatalogSyncService {
|
|
15
|
+
private readonly options;
|
|
16
|
+
private readonly xopcCloud;
|
|
17
|
+
private timer;
|
|
18
|
+
private refreshPromise;
|
|
19
|
+
private refreshAllPromise;
|
|
20
|
+
private status;
|
|
21
|
+
constructor(options?: {
|
|
22
|
+
intervalMs?: number;
|
|
23
|
+
onUpdated?: (modelCount: number) => void;
|
|
24
|
+
xopcCloud?: XopcCloudConnectionService;
|
|
25
|
+
getConfig?: () => Config;
|
|
26
|
+
catalogStore?: ModelCatalogStore;
|
|
27
|
+
loadProviders?: () => ModelsJsonConfig['providers'];
|
|
28
|
+
discoverModels?: typeof discoverProviderModels;
|
|
29
|
+
refreshModels?: () => void;
|
|
30
|
+
getModelCount?: () => number;
|
|
31
|
+
});
|
|
32
|
+
start(): void;
|
|
33
|
+
stop(): void;
|
|
34
|
+
getStatus(): ModelCatalogSyncStatus;
|
|
35
|
+
getXopcCloudConnection(): XopcCloudConnectionService;
|
|
36
|
+
refreshNow(): Promise<Awaited<ReturnType<XopcCloudConnectionService['refreshCatalog']>>>;
|
|
37
|
+
refreshAll(): Promise<{
|
|
38
|
+
updatedSources: string[];
|
|
39
|
+
}>;
|
|
40
|
+
private refreshAllSources;
|
|
41
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { init_models_json, loadModelsJson } from "../config/models-json.js";
|
|
4
|
+
import { getModelCatalogStore, init_model_catalog_store } from "./model-catalog-store.js";
|
|
5
|
+
import { getModelRegistry, init_model_registry } from "./model-registry.js";
|
|
6
|
+
import { discoverProviderModels, isProviderApiDiscoverable } from "./model-discovery.js";
|
|
7
|
+
import { XopcCloudConnectionService } from "./xopc-cloud-connection.js";
|
|
8
|
+
//#region src/providers/model-catalog-sync-service.ts
|
|
9
|
+
init_logger();
|
|
10
|
+
init_models_json();
|
|
11
|
+
init_model_catalog_store();
|
|
12
|
+
init_model_registry();
|
|
13
|
+
const log = createLogger("ModelCatalogSync");
|
|
14
|
+
const DEFAULT_INTERVAL_MS = 360 * 6e4;
|
|
15
|
+
var ModelCatalogSyncService = class {
|
|
16
|
+
xopcCloud;
|
|
17
|
+
timer = null;
|
|
18
|
+
refreshPromise = null;
|
|
19
|
+
refreshAllPromise = null;
|
|
20
|
+
status = {
|
|
21
|
+
running: false,
|
|
22
|
+
refreshing: false
|
|
23
|
+
};
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
this.options = options;
|
|
26
|
+
this.xopcCloud = options.xopcCloud ?? new XopcCloudConnectionService();
|
|
27
|
+
try {
|
|
28
|
+
const lastSuccessAt = getModelCatalogStore().getSource("xopc-cloud")?.lastSuccessAt;
|
|
29
|
+
if (lastSuccessAt !== void 0) this.status.lastSuccessAt = lastSuccessAt;
|
|
30
|
+
} catch {}
|
|
31
|
+
}
|
|
32
|
+
start() {
|
|
33
|
+
if (this.status.running) return;
|
|
34
|
+
const settings = this.options.getConfig?.().modelCatalog;
|
|
35
|
+
if (settings?.enabled === false) return;
|
|
36
|
+
this.status.running = true;
|
|
37
|
+
if (settings?.refreshOnStartup !== false) queueMicrotask(() => void this.refreshAll().catch(() => {}));
|
|
38
|
+
const intervalMs = this.options.intervalMs ?? (settings?.intervalHours ?? 6) * 60 * 6e4;
|
|
39
|
+
this.timer = setInterval(() => void this.refreshAll().catch(() => {}), intervalMs || DEFAULT_INTERVAL_MS);
|
|
40
|
+
this.timer.unref();
|
|
41
|
+
}
|
|
42
|
+
stop() {
|
|
43
|
+
if (this.timer) clearInterval(this.timer);
|
|
44
|
+
this.timer = null;
|
|
45
|
+
this.status.running = false;
|
|
46
|
+
}
|
|
47
|
+
getStatus() {
|
|
48
|
+
return { ...this.status };
|
|
49
|
+
}
|
|
50
|
+
getXopcCloudConnection() {
|
|
51
|
+
return this.xopcCloud;
|
|
52
|
+
}
|
|
53
|
+
refreshNow() {
|
|
54
|
+
if (this.refreshPromise) return this.refreshPromise;
|
|
55
|
+
this.status.refreshing = true;
|
|
56
|
+
this.status.lastAttemptAt = Date.now();
|
|
57
|
+
this.refreshPromise = this.xopcCloud.refreshCatalog().then((result) => {
|
|
58
|
+
if (result.status === "updated") {
|
|
59
|
+
this.status.lastSuccessAt = Date.now();
|
|
60
|
+
this.status.lastError = void 0;
|
|
61
|
+
this.options.onUpdated?.(result.modelCount ?? 0);
|
|
62
|
+
} else if (result.status === "unchanged") {
|
|
63
|
+
this.status.lastSuccessAt = Date.now();
|
|
64
|
+
this.status.lastError = void 0;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}).catch((err) => {
|
|
68
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
69
|
+
this.status.lastError = errorMessage;
|
|
70
|
+
log.warn({
|
|
71
|
+
err,
|
|
72
|
+
errorMessage
|
|
73
|
+
}, `Model catalog refresh failed: ${errorMessage}`);
|
|
74
|
+
throw err;
|
|
75
|
+
}).finally(() => {
|
|
76
|
+
this.status.refreshing = false;
|
|
77
|
+
this.refreshPromise = null;
|
|
78
|
+
});
|
|
79
|
+
return this.refreshPromise;
|
|
80
|
+
}
|
|
81
|
+
refreshAll() {
|
|
82
|
+
if (this.refreshAllPromise) return this.refreshAllPromise;
|
|
83
|
+
this.status.refreshing = true;
|
|
84
|
+
this.refreshAllPromise = this.refreshAllSources().finally(() => {
|
|
85
|
+
this.status.refreshing = false;
|
|
86
|
+
this.refreshAllPromise = null;
|
|
87
|
+
});
|
|
88
|
+
return this.refreshAllPromise;
|
|
89
|
+
}
|
|
90
|
+
async refreshAllSources() {
|
|
91
|
+
const updatedSources = [];
|
|
92
|
+
const sourceErrors = {};
|
|
93
|
+
try {
|
|
94
|
+
if ((await this.refreshNow()).status === "updated") updatedSources.push("xopc-cloud");
|
|
95
|
+
} catch (err) {
|
|
96
|
+
sourceErrors["xopc-cloud"] = err instanceof Error ? err.message : String(err);
|
|
97
|
+
}
|
|
98
|
+
this.status.refreshing = true;
|
|
99
|
+
const providers = this.options.loadProviders?.() ?? loadModelsJson().config.providers;
|
|
100
|
+
const discoverable = Object.entries(providers).filter(([, provider]) => provider.modelDiscovery?.enabled === true && typeof provider.baseUrl === "string" && isProviderApiDiscoverable(provider.api));
|
|
101
|
+
const catalogStore = this.options.catalogStore ?? getModelCatalogStore();
|
|
102
|
+
const enabledSourceIds = new Set(discoverable.map(([providerId]) => `provider:${providerId}`));
|
|
103
|
+
const removedSource = Object.keys(catalogStore.load().sources).filter((sourceId) => sourceId.startsWith("provider:") && !enabledSourceIds.has(sourceId)).map((sourceId) => catalogStore.removeSource(sourceId)).some(Boolean);
|
|
104
|
+
const results = await Promise.all(discoverable.map(async ([providerId, provider]) => {
|
|
105
|
+
try {
|
|
106
|
+
const models = await (this.options.discoverModels ?? discoverProviderModels)({
|
|
107
|
+
providerId,
|
|
108
|
+
baseUrl: provider.baseUrl,
|
|
109
|
+
apiKey: provider.apiKey,
|
|
110
|
+
api: provider.api,
|
|
111
|
+
headers: provider.headers
|
|
112
|
+
});
|
|
113
|
+
catalogStore.replaceSourceModels(`provider:${providerId}`, {
|
|
114
|
+
providerId,
|
|
115
|
+
baseUrl: provider.baseUrl,
|
|
116
|
+
api: provider.api === "openai-responses" ? "openai-responses" : "openai-completions",
|
|
117
|
+
etag: null,
|
|
118
|
+
recommendedModel: null,
|
|
119
|
+
lastSuccessAt: Date.now()
|
|
120
|
+
}, models.map((model) => ({
|
|
121
|
+
id: model.id,
|
|
122
|
+
name: model.name ?? model.id,
|
|
123
|
+
maxOutputTokens: null
|
|
124
|
+
})));
|
|
125
|
+
return providerId;
|
|
126
|
+
} catch (err) {
|
|
127
|
+
sourceErrors[providerId] = err instanceof Error ? err.message : String(err);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
131
|
+
for (const providerId of results) if (providerId) updatedSources.push(providerId);
|
|
132
|
+
if (results.some(Boolean) || removedSource) {
|
|
133
|
+
(this.options.refreshModels ?? (() => getModelRegistry().refresh()))();
|
|
134
|
+
this.status.lastSuccessAt = Date.now();
|
|
135
|
+
this.options.onUpdated?.(this.options.getModelCount?.() ?? getModelRegistry().getAll().length);
|
|
136
|
+
}
|
|
137
|
+
this.status.sourceErrors = Object.keys(sourceErrors).length > 0 ? sourceErrors : void 0;
|
|
138
|
+
return { updatedSources };
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
export { ModelCatalogSyncService };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Config } from '../config/schema.js';
|
|
2
|
+
import type { SessionAgentConfig } from '../session/config-types.js';
|
|
3
|
+
import { type ModelCatalogSnapshot } from './model-catalog-store.js';
|
|
4
|
+
import { type ModelRegistry } from './model-registry.js';
|
|
5
|
+
export interface ModelReferenceHealth {
|
|
6
|
+
ref: string;
|
|
7
|
+
availability: 'available' | 'unavailable';
|
|
8
|
+
locations: string[];
|
|
9
|
+
suggestedRef?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function auditModelReferences(config: Config, sessionConfigs?: ReadonlyMap<string, SessionAgentConfig>, deps?: {
|
|
12
|
+
registry?: ModelRegistry;
|
|
13
|
+
catalog?: ModelCatalogSnapshot;
|
|
14
|
+
}): ModelReferenceHealth[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getModelCatalogStore, init_model_catalog_store } from "./model-catalog-store.js";
|
|
2
|
+
import { getModelRegistry, init_model_registry } from "./model-registry.js";
|
|
3
|
+
//#region src/providers/model-reference-auditor.ts
|
|
4
|
+
init_model_catalog_store();
|
|
5
|
+
init_model_registry();
|
|
6
|
+
function asRecord(value) {
|
|
7
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
8
|
+
}
|
|
9
|
+
function addRef(out, value, location) {
|
|
10
|
+
if (typeof value === "string" && value.trim()) out.push({
|
|
11
|
+
ref: value.trim(),
|
|
12
|
+
location
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function collectToolModel(out, value, location) {
|
|
16
|
+
const model = asRecord(value);
|
|
17
|
+
if (!model) return;
|
|
18
|
+
addRef(out, model.primary, `${location}.primary`);
|
|
19
|
+
if (Array.isArray(model.fallbacks)) model.fallbacks.forEach((ref, index) => addRef(out, ref, `${location}.fallbacks[${index}]`));
|
|
20
|
+
}
|
|
21
|
+
function collectModelPolicy(out, value, location) {
|
|
22
|
+
const policy = asRecord(value);
|
|
23
|
+
if (!policy) return;
|
|
24
|
+
const roles = asRecord(policy.roles);
|
|
25
|
+
for (const [roleId, roleValue] of Object.entries(roles ?? {})) {
|
|
26
|
+
const role = asRecord(roleValue);
|
|
27
|
+
if (!role) continue;
|
|
28
|
+
addRef(out, role.model, `${location}.roles.${roleId}.model`);
|
|
29
|
+
if (Array.isArray(role.fallbacks)) role.fallbacks.forEach((ref, index) => addRef(out, ref, `${location}.roles.${roleId}.fallbacks[${index}]`));
|
|
30
|
+
}
|
|
31
|
+
collectToolModel(out, policy.imageModel, `${location}.imageModel`);
|
|
32
|
+
collectToolModel(out, policy.imageGenerationModel, `${location}.imageGenerationModel`);
|
|
33
|
+
}
|
|
34
|
+
function collectReferences(config, sessionConfigs) {
|
|
35
|
+
const out = [];
|
|
36
|
+
for (const [presetId, preset] of Object.entries(config.agents.capabilityPresets)) collectModelPolicy(out, preset.models, `agents.capabilityPresets.${presetId}.models`);
|
|
37
|
+
for (const agent of config.agents.list) collectModelPolicy(out, agent.models, `agents.list.${agent.id}.models`);
|
|
38
|
+
for (const [sessionKey, sessionConfig] of sessionConfigs) addRef(out, sessionConfig.modelOverride, `sessions.${sessionKey}.modelOverride`);
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
function suggestedRef(ref, catalog) {
|
|
42
|
+
const providerId = ref.split("/")[0];
|
|
43
|
+
const source = Object.values(catalog.sources).find((entry) => entry.providerId === providerId);
|
|
44
|
+
if (!source) return void 0;
|
|
45
|
+
const available = new Set(source.models.filter((model) => model.availability === "available").map((model) => model.id));
|
|
46
|
+
if (source.recommendedModel && available.has(source.recommendedModel)) return `${providerId}/${source.recommendedModel}`;
|
|
47
|
+
const first = source.models.find((model) => model.availability === "available");
|
|
48
|
+
return first ? `${providerId}/${first.id}` : void 0;
|
|
49
|
+
}
|
|
50
|
+
function auditModelReferences(config, sessionConfigs = /* @__PURE__ */ new Map(), deps = {}) {
|
|
51
|
+
const registry = deps.registry ?? getModelRegistry();
|
|
52
|
+
const catalog = deps.catalog ?? getModelCatalogStore().load();
|
|
53
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
54
|
+
for (const reference of collectReferences(config, sessionConfigs)) {
|
|
55
|
+
const locations = grouped.get(reference.ref) ?? [];
|
|
56
|
+
locations.push(reference.location);
|
|
57
|
+
grouped.set(reference.ref, locations);
|
|
58
|
+
}
|
|
59
|
+
return [...grouped.entries()].map(([ref, locations]) => {
|
|
60
|
+
const availability = registry.resolve(ref) ? "available" : "unavailable";
|
|
61
|
+
const suggestion = availability === "unavailable" ? suggestedRef(ref, catalog) : void 0;
|
|
62
|
+
return {
|
|
63
|
+
ref,
|
|
64
|
+
availability,
|
|
65
|
+
locations,
|
|
66
|
+
...suggestion ? { suggestedRef: suggestion } : {}
|
|
67
|
+
};
|
|
68
|
+
}).sort((a, b) => a.ref.localeCompare(b.ref));
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { auditModelReferences };
|
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
* - Hot reload support
|
|
11
11
|
*/
|
|
12
12
|
import { type Api, type Model } from '@earendil-works/pi-ai/compat';
|
|
13
|
+
import { type ModelCatalogStore } from './model-catalog-store.js';
|
|
13
14
|
/**
|
|
14
15
|
* Model Registry - manages all models (built-in + custom)
|
|
15
16
|
*/
|
|
16
17
|
export declare class ModelRegistry {
|
|
17
18
|
private modelsJsonPath;
|
|
19
|
+
private catalogStore;
|
|
18
20
|
private models;
|
|
19
21
|
private customProviderApiKeys;
|
|
20
22
|
private loadError;
|
|
@@ -22,7 +24,7 @@ export declare class ModelRegistry {
|
|
|
22
24
|
private prewarmPromise;
|
|
23
25
|
private _availableModelsCache;
|
|
24
26
|
private _authStatusCache;
|
|
25
|
-
constructor(modelsJsonPath?: string);
|
|
27
|
+
constructor(modelsJsonPath?: string, catalogStore?: ModelCatalogStore);
|
|
26
28
|
isLoaded(): boolean;
|
|
27
29
|
/** Synchronously materialize the catalog (idempotent). */
|
|
28
30
|
ensureLoaded(): void;
|
|
@@ -69,6 +71,7 @@ export declare class ModelRegistry {
|
|
|
69
71
|
* Clears caches to ensure fresh data
|
|
70
72
|
*/
|
|
71
73
|
private loadModels;
|
|
74
|
+
private loadRemoteModels;
|
|
72
75
|
/**
|
|
73
76
|
* Load built-in models and apply provider/model overrides
|
|
74
77
|
*/
|