@knowzai/cli 0.1.0
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/LICENSE +21 -0
- package/assets/portable/.env.example +250 -0
- package/assets/portable/docker-compose.yml +444 -0
- package/assets/portable/postgres-initdb/00-databases-and-extensions.sql +16 -0
- package/assets/portable/releases.json +37 -0
- package/assets/portable/runtime-contract.json +149 -0
- package/bin/run.js +4 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/base-command.d.ts +47 -0
- package/dist/base-command.d.ts.map +1 -0
- package/dist/base-command.js +98 -0
- package/dist/base-command.js.map +1 -0
- package/dist/commands/activate.d.ts +39 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +103 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/ask.d.ts +14 -0
- package/dist/commands/ask.d.ts.map +1 -0
- package/dist/commands/ask.js +33 -0
- package/dist/commands/ask.js.map +1 -0
- package/dist/commands/auth/status.d.ts +7 -0
- package/dist/commands/auth/status.d.ts.map +1 -0
- package/dist/commands/auth/status.js +26 -0
- package/dist/commands/auth/status.js.map +1 -0
- package/dist/commands/backup.d.ts +15 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +52 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/capture/observe.d.ts +23 -0
- package/dist/commands/capture/observe.d.ts.map +1 -0
- package/dist/commands/capture/observe.js +68 -0
- package/dist/commands/capture/observe.js.map +1 -0
- package/dist/commands/capture/seal.d.ts +27 -0
- package/dist/commands/capture/seal.d.ts.map +1 -0
- package/dist/commands/capture/seal.js +144 -0
- package/dist/commands/capture/seal.js.map +1 -0
- package/dist/commands/capture/status.d.ts +33 -0
- package/dist/commands/capture/status.d.ts.map +1 -0
- package/dist/commands/capture/status.js +52 -0
- package/dist/commands/capture/status.js.map +1 -0
- package/dist/commands/chat.d.ts +21 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +142 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/cmek/decrypt.d.ts +13 -0
- package/dist/commands/cmek/decrypt.d.ts.map +1 -0
- package/dist/commands/cmek/decrypt.js +25 -0
- package/dist/commands/cmek/decrypt.js.map +1 -0
- package/dist/commands/cmek/encrypt.d.ts +15 -0
- package/dist/commands/cmek/encrypt.d.ts.map +1 -0
- package/dist/commands/cmek/encrypt.js +26 -0
- package/dist/commands/cmek/encrypt.js.map +1 -0
- package/dist/commands/cmek/init.d.ts +13 -0
- package/dist/commands/cmek/init.d.ts.map +1 -0
- package/dist/commands/cmek/init.js +27 -0
- package/dist/commands/cmek/init.js.map +1 -0
- package/dist/commands/cmek/status.d.ts +11 -0
- package/dist/commands/cmek/status.d.ts.map +1 -0
- package/dist/commands/cmek/status.js +23 -0
- package/dist/commands/cmek/status.js.map +1 -0
- package/dist/commands/completion.d.ts +13 -0
- package/dist/commands/completion.d.ts.map +1 -0
- package/dist/commands/completion.js +19 -0
- package/dist/commands/completion.js.map +1 -0
- package/dist/commands/config/get.d.ts +13 -0
- package/dist/commands/config/get.d.ts.map +1 -0
- package/dist/commands/config/get.js +28 -0
- package/dist/commands/config/get.js.map +1 -0
- package/dist/commands/config/list.d.ts +7 -0
- package/dist/commands/config/list.d.ts.map +1 -0
- package/dist/commands/config/list.js +28 -0
- package/dist/commands/config/list.js.map +1 -0
- package/dist/commands/config/path.d.ts +9 -0
- package/dist/commands/config/path.d.ts.map +1 -0
- package/dist/commands/config/path.js +15 -0
- package/dist/commands/config/path.js.map +1 -0
- package/dist/commands/config/set.d.ts +16 -0
- package/dist/commands/config/set.d.ts.map +1 -0
- package/dist/commands/config/set.js +36 -0
- package/dist/commands/config/set.js.map +1 -0
- package/dist/commands/doctor.d.ts +56 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +151 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/down.d.ts +30 -0
- package/dist/commands/down.d.ts.map +1 -0
- package/dist/commands/down.js +20 -0
- package/dist/commands/down.js.map +1 -0
- package/dist/commands/entities/find.d.ts +16 -0
- package/dist/commands/entities/find.d.ts.map +1 -0
- package/dist/commands/entities/find.js +27 -0
- package/dist/commands/entities/find.js.map +1 -0
- package/dist/commands/hooks/install.d.ts +19 -0
- package/dist/commands/hooks/install.d.ts.map +1 -0
- package/dist/commands/hooks/install.js +53 -0
- package/dist/commands/hooks/install.js.map +1 -0
- package/dist/commands/index/graph.d.ts +11 -0
- package/dist/commands/index/graph.d.ts.map +1 -0
- package/dist/commands/index/graph.js +31 -0
- package/dist/commands/index/graph.js.map +1 -0
- package/dist/commands/index/scan.d.ts +22 -0
- package/dist/commands/index/scan.d.ts.map +1 -0
- package/dist/commands/index/scan.js +48 -0
- package/dist/commands/index/scan.js.map +1 -0
- package/dist/commands/index/search.d.ts +18 -0
- package/dist/commands/index/search.d.ts.map +1 -0
- package/dist/commands/index/search.js +40 -0
- package/dist/commands/index/search.js.map +1 -0
- package/dist/commands/ingest/add.d.ts +15 -0
- package/dist/commands/ingest/add.d.ts.map +1 -0
- package/dist/commands/ingest/add.js +50 -0
- package/dist/commands/ingest/add.js.map +1 -0
- package/dist/commands/knowledge/amend.d.ts +19 -0
- package/dist/commands/knowledge/amend.d.ts.map +1 -0
- package/dist/commands/knowledge/amend.js +27 -0
- package/dist/commands/knowledge/amend.js.map +1 -0
- package/dist/commands/knowledge/comment.d.ts +16 -0
- package/dist/commands/knowledge/comment.d.ts.map +1 -0
- package/dist/commands/knowledge/comment.js +27 -0
- package/dist/commands/knowledge/comment.js.map +1 -0
- package/dist/commands/knowledge/comments.d.ts +11 -0
- package/dist/commands/knowledge/comments.d.ts.map +1 -0
- package/dist/commands/knowledge/comments.js +20 -0
- package/dist/commands/knowledge/comments.js.map +1 -0
- package/dist/commands/knowledge/create.d.ts +18 -0
- package/dist/commands/knowledge/create.d.ts.map +1 -0
- package/dist/commands/knowledge/create.js +45 -0
- package/dist/commands/knowledge/create.js.map +1 -0
- package/dist/commands/knowledge/delete.d.ts +14 -0
- package/dist/commands/knowledge/delete.d.ts.map +1 -0
- package/dist/commands/knowledge/delete.js +30 -0
- package/dist/commands/knowledge/delete.js.map +1 -0
- package/dist/commands/knowledge/get.d.ts +13 -0
- package/dist/commands/knowledge/get.d.ts.map +1 -0
- package/dist/commands/knowledge/get.js +20 -0
- package/dist/commands/knowledge/get.js.map +1 -0
- package/dist/commands/knowledge/list.d.ts +13 -0
- package/dist/commands/knowledge/list.d.ts.map +1 -0
- package/dist/commands/knowledge/list.js +31 -0
- package/dist/commands/knowledge/list.js.map +1 -0
- package/dist/commands/knowledge/status.d.ts +11 -0
- package/dist/commands/knowledge/status.d.ts.map +1 -0
- package/dist/commands/knowledge/status.js +23 -0
- package/dist/commands/knowledge/status.js.map +1 -0
- package/dist/commands/knowledge/update.d.ts +16 -0
- package/dist/commands/knowledge/update.d.ts.map +1 -0
- package/dist/commands/knowledge/update.js +32 -0
- package/dist/commands/knowledge/update.js.map +1 -0
- package/dist/commands/knowledge/versions.d.ts +11 -0
- package/dist/commands/knowledge/versions.d.ts.map +1 -0
- package/dist/commands/knowledge/versions.js +22 -0
- package/dist/commands/knowledge/versions.js.map +1 -0
- package/dist/commands/local/info.d.ts +17 -0
- package/dist/commands/local/info.d.ts.map +1 -0
- package/dist/commands/local/info.js +26 -0
- package/dist/commands/local/info.js.map +1 -0
- package/dist/commands/local/init.d.ts +16 -0
- package/dist/commands/local/init.d.ts.map +1 -0
- package/dist/commands/local/init.js +31 -0
- package/dist/commands/local/init.js.map +1 -0
- package/dist/commands/local/list.d.ts +13 -0
- package/dist/commands/local/list.d.ts.map +1 -0
- package/dist/commands/local/list.js +29 -0
- package/dist/commands/local/list.js.map +1 -0
- package/dist/commands/local/reset.d.ts +12 -0
- package/dist/commands/local/reset.d.ts.map +1 -0
- package/dist/commands/local/reset.js +34 -0
- package/dist/commands/local/reset.js.map +1 -0
- package/dist/commands/local/show.d.ts +15 -0
- package/dist/commands/local/show.d.ts.map +1 -0
- package/dist/commands/local/show.js +33 -0
- package/dist/commands/local/show.js.map +1 -0
- package/dist/commands/login.d.ts +23 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +139 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +11 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +23 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/menu.d.ts +10 -0
- package/dist/commands/menu.d.ts.map +1 -0
- package/dist/commands/menu.js +50 -0
- package/dist/commands/menu.js.map +1 -0
- package/dist/commands/pg/destroy.d.ts +13 -0
- package/dist/commands/pg/destroy.d.ts.map +1 -0
- package/dist/commands/pg/destroy.js +36 -0
- package/dist/commands/pg/destroy.js.map +1 -0
- package/dist/commands/pg/down.d.ts +12 -0
- package/dist/commands/pg/down.d.ts.map +1 -0
- package/dist/commands/pg/down.js +20 -0
- package/dist/commands/pg/down.js.map +1 -0
- package/dist/commands/pg/status.d.ts +13 -0
- package/dist/commands/pg/status.d.ts.map +1 -0
- package/dist/commands/pg/status.js +28 -0
- package/dist/commands/pg/status.js.map +1 -0
- package/dist/commands/pg/up.d.ts +13 -0
- package/dist/commands/pg/up.d.ts.map +1 -0
- package/dist/commands/pg/up.js +34 -0
- package/dist/commands/pg/up.js.map +1 -0
- package/dist/commands/platform/destroy.d.ts +18 -0
- package/dist/commands/platform/destroy.d.ts.map +1 -0
- package/dist/commands/platform/destroy.js +41 -0
- package/dist/commands/platform/destroy.js.map +1 -0
- package/dist/commands/platform/doctor.d.ts +11 -0
- package/dist/commands/platform/doctor.d.ts.map +1 -0
- package/dist/commands/platform/doctor.js +18 -0
- package/dist/commands/platform/doctor.js.map +1 -0
- package/dist/commands/platform/down.d.ts +26 -0
- package/dist/commands/platform/down.d.ts.map +1 -0
- package/dist/commands/platform/down.js +16 -0
- package/dist/commands/platform/down.js.map +1 -0
- package/dist/commands/platform/logs.d.ts +26 -0
- package/dist/commands/platform/logs.d.ts.map +1 -0
- package/dist/commands/platform/logs.js +24 -0
- package/dist/commands/platform/logs.js.map +1 -0
- package/dist/commands/platform/reset.d.ts +26 -0
- package/dist/commands/platform/reset.d.ts.map +1 -0
- package/dist/commands/platform/reset.js +49 -0
- package/dist/commands/platform/reset.js.map +1 -0
- package/dist/commands/platform/setup.d.ts +24 -0
- package/dist/commands/platform/setup.d.ts.map +1 -0
- package/dist/commands/platform/setup.js +21 -0
- package/dist/commands/platform/setup.js.map +1 -0
- package/dist/commands/platform/status.d.ts +28 -0
- package/dist/commands/platform/status.d.ts.map +1 -0
- package/dist/commands/platform/status.js +37 -0
- package/dist/commands/platform/status.js.map +1 -0
- package/dist/commands/platform/up.d.ts +42 -0
- package/dist/commands/platform/up.d.ts.map +1 -0
- package/dist/commands/platform/up.js +22 -0
- package/dist/commands/platform/up.js.map +1 -0
- package/dist/commands/platform/upgrade.d.ts +14 -0
- package/dist/commands/platform/upgrade.d.ts.map +1 -0
- package/dist/commands/platform/upgrade.js +22 -0
- package/dist/commands/platform/upgrade.js.map +1 -0
- package/dist/commands/profile/add.d.ts +18 -0
- package/dist/commands/profile/add.d.ts.map +1 -0
- package/dist/commands/profile/add.js +26 -0
- package/dist/commands/profile/add.js.map +1 -0
- package/dist/commands/profile/list.d.ts +10 -0
- package/dist/commands/profile/list.d.ts.map +1 -0
- package/dist/commands/profile/list.js +20 -0
- package/dist/commands/profile/list.js.map +1 -0
- package/dist/commands/profile/remove.d.ts +15 -0
- package/dist/commands/profile/remove.d.ts.map +1 -0
- package/dist/commands/profile/remove.js +19 -0
- package/dist/commands/profile/remove.js.map +1 -0
- package/dist/commands/profile/use.d.ts +12 -0
- package/dist/commands/profile/use.d.ts.map +1 -0
- package/dist/commands/profile/use.js +18 -0
- package/dist/commands/profile/use.js.map +1 -0
- package/dist/commands/recall.d.ts +29 -0
- package/dist/commands/recall.d.ts.map +1 -0
- package/dist/commands/recall.js +94 -0
- package/dist/commands/recall.js.map +1 -0
- package/dist/commands/repo/context.d.ts +24 -0
- package/dist/commands/repo/context.d.ts.map +1 -0
- package/dist/commands/repo/context.js +52 -0
- package/dist/commands/repo/context.js.map +1 -0
- package/dist/commands/repo/graph.d.ts +24 -0
- package/dist/commands/repo/graph.d.ts.map +1 -0
- package/dist/commands/repo/graph.js +72 -0
- package/dist/commands/repo/graph.js.map +1 -0
- package/dist/commands/repo/index/index.d.ts +28 -0
- package/dist/commands/repo/index/index.d.ts.map +1 -0
- package/dist/commands/repo/index/index.js +76 -0
- package/dist/commands/repo/index/index.js.map +1 -0
- package/dist/commands/repo/search.d.ts +22 -0
- package/dist/commands/repo/search.d.ts.map +1 -0
- package/dist/commands/repo/search.js +50 -0
- package/dist/commands/repo/search.js.map +1 -0
- package/dist/commands/repo/setup.d.ts +41 -0
- package/dist/commands/repo/setup.d.ts.map +1 -0
- package/dist/commands/repo/setup.js +144 -0
- package/dist/commands/repo/setup.js.map +1 -0
- package/dist/commands/repo/status.d.ts +31 -0
- package/dist/commands/repo/status.d.ts.map +1 -0
- package/dist/commands/repo/status.js +60 -0
- package/dist/commands/repo/status.js.map +1 -0
- package/dist/commands/restore.d.ts +16 -0
- package/dist/commands/restore.d.ts.map +1 -0
- package/dist/commands/restore.js +53 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/search.d.ts +14 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +32 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/setup.d.ts +24 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +21 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/stats.d.ts +6 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +16 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/status.d.ts +20 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +33 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync/conflicts.d.ts +14 -0
- package/dist/commands/sync/conflicts.d.ts.map +1 -0
- package/dist/commands/sync/conflicts.js +23 -0
- package/dist/commands/sync/conflicts.js.map +1 -0
- package/dist/commands/sync/pull.d.ts +13 -0
- package/dist/commands/sync/pull.d.ts.map +1 -0
- package/dist/commands/sync/pull.js +26 -0
- package/dist/commands/sync/pull.js.map +1 -0
- package/dist/commands/sync/push.d.ts +13 -0
- package/dist/commands/sync/push.d.ts.map +1 -0
- package/dist/commands/sync/push.js +26 -0
- package/dist/commands/sync/push.js.map +1 -0
- package/dist/commands/sync/recover.d.ts +16 -0
- package/dist/commands/sync/recover.d.ts.map +1 -0
- package/dist/commands/sync/recover.js +29 -0
- package/dist/commands/sync/recover.js.map +1 -0
- package/dist/commands/sync/resolve.d.ts +21 -0
- package/dist/commands/sync/resolve.d.ts.map +1 -0
- package/dist/commands/sync/resolve.js +38 -0
- package/dist/commands/sync/resolve.js.map +1 -0
- package/dist/commands/sync/run.d.ts +13 -0
- package/dist/commands/sync/run.d.ts.map +1 -0
- package/dist/commands/sync/run.js +26 -0
- package/dist/commands/sync/run.js.map +1 -0
- package/dist/commands/sync/status.d.ts +13 -0
- package/dist/commands/sync/status.d.ts.map +1 -0
- package/dist/commands/sync/status.js +28 -0
- package/dist/commands/sync/status.js.map +1 -0
- package/dist/commands/topics/list.d.ts +11 -0
- package/dist/commands/topics/list.d.ts.map +1 -0
- package/dist/commands/topics/list.js +20 -0
- package/dist/commands/topics/list.js.map +1 -0
- package/dist/commands/tui.d.ts +10 -0
- package/dist/commands/tui.d.ts.map +1 -0
- package/dist/commands/tui.js +124 -0
- package/dist/commands/tui.js.map +1 -0
- package/dist/commands/up.d.ts +108 -0
- package/dist/commands/up.d.ts.map +1 -0
- package/dist/commands/up.js +210 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/commands/vault/contents.d.ts +14 -0
- package/dist/commands/vault/contents.d.ts.map +1 -0
- package/dist/commands/vault/contents.js +24 -0
- package/dist/commands/vault/contents.js.map +1 -0
- package/dist/commands/vault/create.d.ts +15 -0
- package/dist/commands/vault/create.d.ts.map +1 -0
- package/dist/commands/vault/create.js +26 -0
- package/dist/commands/vault/create.js.map +1 -0
- package/dist/commands/vault/get.d.ts +10 -0
- package/dist/commands/vault/get.d.ts.map +1 -0
- package/dist/commands/vault/get.js +25 -0
- package/dist/commands/vault/get.js.map +1 -0
- package/dist/commands/vault/list.d.ts +7 -0
- package/dist/commands/vault/list.d.ts.map +1 -0
- package/dist/commands/vault/list.js +17 -0
- package/dist/commands/vault/list.js.map +1 -0
- package/dist/commands/web.d.ts +14 -0
- package/dist/commands/web.d.ts.map +1 -0
- package/dist/commands/web.js +50 -0
- package/dist/commands/web.js.map +1 -0
- package/dist/commands/whoami.d.ts +7 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +24 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/hooks/init/launch-menu.d.ts +10 -0
- package/dist/hooks/init/launch-menu.d.ts.map +1 -0
- package/dist/hooks/init/launch-menu.js +11 -0
- package/dist/hooks/init/launch-menu.js.map +1 -0
- package/dist/lib/activate.d.ts +92 -0
- package/dist/lib/activate.d.ts.map +1 -0
- package/dist/lib/activate.js +292 -0
- package/dist/lib/activate.js.map +1 -0
- package/dist/lib/browser.d.ts +30 -0
- package/dist/lib/browser.d.ts.map +1 -0
- package/dist/lib/browser.js +45 -0
- package/dist/lib/browser.js.map +1 -0
- package/dist/lib/chat.d.ts +41 -0
- package/dist/lib/chat.d.ts.map +1 -0
- package/dist/lib/chat.js +63 -0
- package/dist/lib/chat.js.map +1 -0
- package/dist/lib/claude-hooks.d.ts +34 -0
- package/dist/lib/claude-hooks.d.ts.map +1 -0
- package/dist/lib/claude-hooks.js +85 -0
- package/dist/lib/claude-hooks.js.map +1 -0
- package/dist/lib/completion.d.ts +9 -0
- package/dist/lib/completion.d.ts.map +1 -0
- package/dist/lib/completion.js +57 -0
- package/dist/lib/completion.js.map +1 -0
- package/dist/lib/container-engine.d.ts +45 -0
- package/dist/lib/container-engine.d.ts.map +1 -0
- package/dist/lib/container-engine.js +348 -0
- package/dist/lib/container-engine.js.map +1 -0
- package/dist/lib/content.d.ts +9 -0
- package/dist/lib/content.d.ts.map +1 -0
- package/dist/lib/content.js +20 -0
- package/dist/lib/content.js.map +1 -0
- package/dist/lib/doctor-fixture.d.ts +8 -0
- package/dist/lib/doctor-fixture.d.ts.map +1 -0
- package/dist/lib/doctor-fixture.js +50 -0
- package/dist/lib/doctor-fixture.js.map +1 -0
- package/dist/lib/embedding-guard.d.ts +34 -0
- package/dist/lib/embedding-guard.d.ts.map +1 -0
- package/dist/lib/embedding-guard.js +50 -0
- package/dist/lib/embedding-guard.js.map +1 -0
- package/dist/lib/hook-io.d.ts +24 -0
- package/dist/lib/hook-io.d.ts.map +1 -0
- package/dist/lib/hook-io.js +73 -0
- package/dist/lib/hook-io.js.map +1 -0
- package/dist/lib/ingest.d.ts +24 -0
- package/dist/lib/ingest.d.ts.map +1 -0
- package/dist/lib/ingest.js +44 -0
- package/dist/lib/ingest.js.map +1 -0
- package/dist/lib/login.d.ts +40 -0
- package/dist/lib/login.d.ts.map +1 -0
- package/dist/lib/login.js +56 -0
- package/dist/lib/login.js.map +1 -0
- package/dist/lib/pending-captures.d.ts +25 -0
- package/dist/lib/pending-captures.d.ts.map +1 -0
- package/dist/lib/pending-captures.js +143 -0
- package/dist/lib/pending-captures.js.map +1 -0
- package/dist/lib/platform-backup.d.ts +110 -0
- package/dist/lib/platform-backup.d.ts.map +1 -0
- package/dist/lib/platform-backup.js +579 -0
- package/dist/lib/platform-backup.js.map +1 -0
- package/dist/lib/platform-command-shared.d.ts +132 -0
- package/dist/lib/platform-command-shared.d.ts.map +1 -0
- package/dist/lib/platform-command-shared.js +159 -0
- package/dist/lib/platform-command-shared.js.map +1 -0
- package/dist/lib/platform-frontdoor-runtime.d.ts +33 -0
- package/dist/lib/platform-frontdoor-runtime.d.ts.map +1 -0
- package/dist/lib/platform-frontdoor-runtime.js +285 -0
- package/dist/lib/platform-frontdoor-runtime.js.map +1 -0
- package/dist/lib/platform-frontdoor.d.ts +155 -0
- package/dist/lib/platform-frontdoor.d.ts.map +1 -0
- package/dist/lib/platform-frontdoor.js +467 -0
- package/dist/lib/platform-frontdoor.js.map +1 -0
- package/dist/lib/platform-image-source.d.ts +81 -0
- package/dist/lib/platform-image-source.d.ts.map +1 -0
- package/dist/lib/platform-image-source.js +143 -0
- package/dist/lib/platform-image-source.js.map +1 -0
- package/dist/lib/platform-lifecycle.d.ts +112 -0
- package/dist/lib/platform-lifecycle.d.ts.map +1 -0
- package/dist/lib/platform-lifecycle.js +725 -0
- package/dist/lib/platform-lifecycle.js.map +1 -0
- package/dist/lib/platform-onboarding.d.ts +128 -0
- package/dist/lib/platform-onboarding.d.ts.map +1 -0
- package/dist/lib/platform-onboarding.js +227 -0
- package/dist/lib/platform-onboarding.js.map +1 -0
- package/dist/lib/platform-preflight.d.ts +48 -0
- package/dist/lib/platform-preflight.d.ts.map +1 -0
- package/dist/lib/platform-preflight.js +90 -0
- package/dist/lib/platform-preflight.js.map +1 -0
- package/dist/lib/platform-profile-purge.d.ts +18 -0
- package/dist/lib/platform-profile-purge.d.ts.map +1 -0
- package/dist/lib/platform-profile-purge.js +26 -0
- package/dist/lib/platform-profile-purge.js.map +1 -0
- package/dist/lib/platform-provider-fields.d.ts +2 -0
- package/dist/lib/platform-provider-fields.d.ts.map +1 -0
- package/dist/lib/platform-provider-fields.js +2 -0
- package/dist/lib/platform-provider-fields.js.map +1 -0
- package/dist/lib/platform-provider-probe.d.ts +75 -0
- package/dist/lib/platform-provider-probe.d.ts.map +1 -0
- package/dist/lib/platform-provider-probe.js +781 -0
- package/dist/lib/platform-provider-probe.js.map +1 -0
- package/dist/lib/platform-provider-prompt.d.ts +118 -0
- package/dist/lib/platform-provider-prompt.d.ts.map +1 -0
- package/dist/lib/platform-provider-prompt.js +245 -0
- package/dist/lib/platform-provider-prompt.js.map +1 -0
- package/dist/lib/platform-release-manifest.d.ts +34 -0
- package/dist/lib/platform-release-manifest.d.ts.map +1 -0
- package/dist/lib/platform-release-manifest.js +100 -0
- package/dist/lib/platform-release-manifest.js.map +1 -0
- package/dist/lib/platform-runtime.d.ts +212 -0
- package/dist/lib/platform-runtime.d.ts.map +1 -0
- package/dist/lib/platform-runtime.js +866 -0
- package/dist/lib/platform-runtime.js.map +1 -0
- package/dist/lib/poll.d.ts +9 -0
- package/dist/lib/poll.d.ts.map +1 -0
- package/dist/lib/poll.js +18 -0
- package/dist/lib/poll.js.map +1 -0
- package/dist/lib/prompt.d.ts +7 -0
- package/dist/lib/prompt.d.ts.map +1 -0
- package/dist/lib/prompt.js +28 -0
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/provider-presets.d.ts +108 -0
- package/dist/lib/provider-presets.d.ts.map +1 -0
- package/dist/lib/provider-presets.js +184 -0
- package/dist/lib/provider-presets.js.map +1 -0
- package/dist/lib/recall.d.ts +32 -0
- package/dist/lib/recall.d.ts.map +1 -0
- package/dist/lib/recall.js +69 -0
- package/dist/lib/recall.js.map +1 -0
- package/dist/lib/redact.d.ts +41 -0
- package/dist/lib/redact.d.ts.map +1 -0
- package/dist/lib/redact.js +130 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/render.d.ts +55 -0
- package/dist/lib/render.d.ts.map +1 -0
- package/dist/lib/render.js +172 -0
- package/dist/lib/render.js.map +1 -0
- package/dist/lib/repo-binding.d.ts +53 -0
- package/dist/lib/repo-binding.d.ts.map +1 -0
- package/dist/lib/repo-binding.js +127 -0
- package/dist/lib/repo-binding.js.map +1 -0
- package/dist/lib/repo-command-support.d.ts +18 -0
- package/dist/lib/repo-command-support.d.ts.map +1 -0
- package/dist/lib/repo-command-support.js +54 -0
- package/dist/lib/repo-command-support.js.map +1 -0
- package/dist/lib/seal-core.d.ts +34 -0
- package/dist/lib/seal-core.d.ts.map +1 -0
- package/dist/lib/seal-core.js +154 -0
- package/dist/lib/seal-core.js.map +1 -0
- package/dist/lib/setup-console.d.ts +46 -0
- package/dist/lib/setup-console.d.ts.map +1 -0
- package/dist/lib/setup-console.js +191 -0
- package/dist/lib/setup-console.js.map +1 -0
- package/dist/lib/setup-page.d.ts +21 -0
- package/dist/lib/setup-page.d.ts.map +1 -0
- package/dist/lib/setup-page.js +656 -0
- package/dist/lib/setup-page.js.map +1 -0
- package/dist/lib/setup-plan.d.ts +52 -0
- package/dist/lib/setup-plan.d.ts.map +1 -0
- package/dist/lib/setup-plan.js +154 -0
- package/dist/lib/setup-plan.js.map +1 -0
- package/dist/lib/setup-server.d.ts +71 -0
- package/dist/lib/setup-server.d.ts.map +1 -0
- package/dist/lib/setup-server.js +936 -0
- package/dist/lib/setup-server.js.map +1 -0
- package/dist/lib/tui.d.ts +77 -0
- package/dist/lib/tui.d.ts.map +1 -0
- package/dist/lib/tui.js +126 -0
- package/dist/lib/tui.js.map +1 -0
- package/dist/lib/ui.d.ts +23 -0
- package/dist/lib/ui.d.ts.map +1 -0
- package/dist/lib/ui.js +100 -0
- package/dist/lib/ui.js.map +1 -0
- package/dist/lib/vault.d.ts +10 -0
- package/dist/lib/vault.d.ts.map +1 -0
- package/dist/lib/vault.js +18 -0
- package/dist/lib/vault.js.map +1 -0
- package/dist/menu/forms.d.ts +13 -0
- package/dist/menu/forms.d.ts.map +1 -0
- package/dist/menu/forms.js +45 -0
- package/dist/menu/forms.js.map +1 -0
- package/dist/menu/frontends.d.ts +32 -0
- package/dist/menu/frontends.d.ts.map +1 -0
- package/dist/menu/frontends.js +31 -0
- package/dist/menu/frontends.js.map +1 -0
- package/dist/menu/help.d.ts +11 -0
- package/dist/menu/help.d.ts.map +1 -0
- package/dist/menu/help.js +33 -0
- package/dist/menu/help.js.map +1 -0
- package/dist/menu/palette.d.ts +28 -0
- package/dist/menu/palette.d.ts.map +1 -0
- package/dist/menu/palette.js +57 -0
- package/dist/menu/palette.js.map +1 -0
- package/dist/menu/reducer.d.ts +19 -0
- package/dist/menu/reducer.d.ts.map +1 -0
- package/dist/menu/reducer.js +37 -0
- package/dist/menu/reducer.js.map +1 -0
- package/dist/menu/run.d.ts +34 -0
- package/dist/menu/run.d.ts.map +1 -0
- package/dist/menu/run.js +490 -0
- package/dist/menu/run.js.map +1 -0
- package/dist/menu/screens.d.ts +15 -0
- package/dist/menu/screens.d.ts.map +1 -0
- package/dist/menu/screens.js +251 -0
- package/dist/menu/screens.js.map +1 -0
- package/dist/menu/should-launch.d.ts +19 -0
- package/dist/menu/should-launch.d.ts.map +1 -0
- package/dist/menu/should-launch.js +22 -0
- package/dist/menu/should-launch.js.map +1 -0
- package/dist/menu/types.d.ts +95 -0
- package/dist/menu/types.d.ts.map +1 -0
- package/dist/menu/types.js +7 -0
- package/dist/menu/types.js.map +1 -0
- package/oclif.manifest.json +7995 -0
- package/package.json +133 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
import { registerSecret, validateCloudAiKeyFormat } from '@knowzai/core';
|
|
2
|
+
import { createSign } from 'node:crypto';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { normalizeAzureOpenAiEndpoint } from './platform-runtime.js';
|
|
5
|
+
import { KNOWZ_CLOUD_ENDPOINT } from './provider-presets.js';
|
|
6
|
+
/** Bounded, secret-safe model discovery for the managed Knowz Cloud preset. */
|
|
7
|
+
export async function discoverKnowzCloudModels(credential, deps = {}) {
|
|
8
|
+
const empty = (warning) => ({ chatModels: [], embeddingModels: [], warning });
|
|
9
|
+
if (!validateCloudAiKeyFormat(credential).ok)
|
|
10
|
+
return empty('A valid Knowz Cloud AI key is required for model discovery.');
|
|
11
|
+
registerSecret(credential);
|
|
12
|
+
const controller = new AbortController();
|
|
13
|
+
const timeout = setTimeout(() => controller.abort(), Math.min(15_000, Math.max(1, deps.timeoutMs ?? 5_000)));
|
|
14
|
+
try {
|
|
15
|
+
const response = await (deps.fetchFn ?? globalThis.fetch)(`${KNOWZ_CLOUD_ENDPOINT}/models`, {
|
|
16
|
+
method: 'GET', redirect: 'manual', signal: controller.signal,
|
|
17
|
+
headers: { authorization: `Bearer ${credential}`, accept: 'application/json' },
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
if (response.status === 402)
|
|
21
|
+
return empty('Knowz Cloud credits are exhausted; choose models manually after topping up.');
|
|
22
|
+
if (response.status === 404)
|
|
23
|
+
return empty('Knowz Cloud AI is not enabled or the model catalog is unavailable; enter model names manually.');
|
|
24
|
+
if (response.status === 401 || response.status === 403)
|
|
25
|
+
return empty('Knowz Cloud authentication failed; verify the AI key.');
|
|
26
|
+
return empty(`Knowz Cloud model discovery returned HTTP ${response.status}; enter model names manually.`);
|
|
27
|
+
}
|
|
28
|
+
const body = await readCappedJson(response, 64 * 1024, controller.signal);
|
|
29
|
+
const data = body && typeof body === 'object' && !Array.isArray(body)
|
|
30
|
+
? body.data
|
|
31
|
+
: undefined;
|
|
32
|
+
if (!Array.isArray(data))
|
|
33
|
+
return empty('Knowz Cloud returned an invalid model catalog; enter model names manually.');
|
|
34
|
+
const chatModels = [];
|
|
35
|
+
const embeddingModels = [];
|
|
36
|
+
for (const item of data) {
|
|
37
|
+
if (!item || typeof item !== 'object' || Array.isArray(item))
|
|
38
|
+
continue;
|
|
39
|
+
const row = item;
|
|
40
|
+
let id;
|
|
41
|
+
try {
|
|
42
|
+
id = validateModelName(row.id);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const capabilities = Array.isArray(row.capabilities)
|
|
48
|
+
? row.capabilities.filter((value) => typeof value === 'string')
|
|
49
|
+
: [];
|
|
50
|
+
if (capabilities.includes('embeddings'))
|
|
51
|
+
embeddingModels.push(id);
|
|
52
|
+
if (capabilities.includes('chat.completions'))
|
|
53
|
+
chatModels.push(id);
|
|
54
|
+
}
|
|
55
|
+
if (chatModels.length === 0 || embeddingModels.length === 0) {
|
|
56
|
+
return { chatModels, embeddingModels, warning: 'Knowz Cloud did not advertise both chat and embedding models; enter missing model names manually.' };
|
|
57
|
+
}
|
|
58
|
+
return { chatModels, embeddingModels };
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return empty('Knowz Cloud model discovery could not reach the gateway; enter model names manually.');
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
clearTimeout(timeout);
|
|
65
|
+
controller.abort();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Keep these in sync with Knowz.Shared AiModelDefaults.cs. They are deliberately server-owned:
|
|
69
|
+
// the setup browser cannot submit an arbitrary Azure deployment name or prompt.
|
|
70
|
+
export const AZURE_CHAT_DEPLOYMENTS = ['gpt-5.4-mini', 'gpt-5.4'];
|
|
71
|
+
// Portable Azure is pinned to a 1536-native embedding model — text-embedding-3-large (3072) is
|
|
72
|
+
// intentionally excluded (the transport does not truncate). See FEAT_PortableEmbeddingGuardrails.
|
|
73
|
+
export const AZURE_EMBEDDING_DEPLOYMENTS = ['text-embedding-3-small'];
|
|
74
|
+
export const AZURE_MODEL_API_VERSION = '2025-04-01-preview';
|
|
75
|
+
// Keep these pinned to ConfigurationKeys.Vertex.DefaultChatModel and the portable runtime embedding default.
|
|
76
|
+
export const VERTEX_CHAT_DEFAULT = 'gemini-2.5-flash';
|
|
77
|
+
export const VERTEX_EMBEDDING_DEFAULT = 'gemini-embedding-001';
|
|
78
|
+
// Re-exported from provider-presets (defined there to avoid a probe->presets->probe cycle) so the
|
|
79
|
+
// setup page + prompt import all model defaults from one place.
|
|
80
|
+
export { QWEN3_EMBEDDING_DEFAULT, QWEN3_EMBEDDING_DIMENSIONS } from './provider-presets.js';
|
|
81
|
+
export const PROBE_VISION_PNG_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
|
|
82
|
+
// `:` is Ollama's tag separator (llama3.2:1b). `/` stays REJECTED by contract —
|
|
83
|
+
// model names reach URL paths and the path-unsafe fixtures pin that. (Vertex
|
|
84
|
+
// publisher prefixes like google/gemini-… are stripped before validation;
|
|
85
|
+
// namespaced Ollama models are a tracked follow-up.)
|
|
86
|
+
const MODEL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/;
|
|
87
|
+
const VERTEX_REGION_PATTERN = /^[a-z][a-z0-9-]{1,30}$/;
|
|
88
|
+
const VERTEX_PROJECT_PATTERN = /^[a-z][a-z0-9-]{4,29}$/;
|
|
89
|
+
// Must fit a full-dimension embedding response: gemini-embedding-001 returns
|
|
90
|
+
// 3072 floats ≈ 100KB of JSON (observed 101,336 bytes live). Still a hard
|
|
91
|
+
// bound on endpoint-controlled data — just one that legitimate embedding
|
|
92
|
+
// probes cannot exceed.
|
|
93
|
+
const MODEL_RESPONSE_LIMIT = 256 * 1024;
|
|
94
|
+
const GOOGLE_TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
95
|
+
const GOOGLE_CLOUD_SCOPE = 'https://www.googleapis.com/auth/cloud-platform';
|
|
96
|
+
function record(value) {
|
|
97
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
98
|
+
? value
|
|
99
|
+
: undefined;
|
|
100
|
+
}
|
|
101
|
+
function base64UrlJson(value) {
|
|
102
|
+
return Buffer.from(JSON.stringify(value)).toString('base64url');
|
|
103
|
+
}
|
|
104
|
+
function serviceAccountAssertion(adc) {
|
|
105
|
+
const clientEmail = typeof adc.client_email === 'string' ? adc.client_email : undefined;
|
|
106
|
+
const privateKey = typeof adc.private_key === 'string' ? adc.private_key : undefined;
|
|
107
|
+
if (!clientEmail || !privateKey)
|
|
108
|
+
return undefined;
|
|
109
|
+
registerSecret(privateKey);
|
|
110
|
+
const issuedAt = Math.floor(Date.now() / 1_000);
|
|
111
|
+
const header = base64UrlJson({ alg: 'RS256', typ: 'JWT' });
|
|
112
|
+
const payload = base64UrlJson({
|
|
113
|
+
iss: clientEmail,
|
|
114
|
+
scope: GOOGLE_CLOUD_SCOPE,
|
|
115
|
+
aud: GOOGLE_TOKEN_URL,
|
|
116
|
+
iat: issuedAt,
|
|
117
|
+
exp: issuedAt + 3_600,
|
|
118
|
+
});
|
|
119
|
+
const signer = createSign('RSA-SHA256');
|
|
120
|
+
signer.update(`${header}.${payload}`);
|
|
121
|
+
signer.end();
|
|
122
|
+
return `${header}.${payload}.${signer.sign(privateKey).toString('base64url')}`;
|
|
123
|
+
}
|
|
124
|
+
function tokenRequestBody(adc) {
|
|
125
|
+
if (adc.type === 'service_account') {
|
|
126
|
+
const assertion = serviceAccountAssertion(adc);
|
|
127
|
+
if (!assertion)
|
|
128
|
+
return undefined;
|
|
129
|
+
return new URLSearchParams({
|
|
130
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
131
|
+
assertion,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (adc.type === 'authorized_user') {
|
|
135
|
+
const clientId = typeof adc.client_id === 'string' ? adc.client_id : undefined;
|
|
136
|
+
const clientSecret = typeof adc.client_secret === 'string' ? adc.client_secret : undefined;
|
|
137
|
+
const refreshToken = typeof adc.refresh_token === 'string' ? adc.refresh_token : undefined;
|
|
138
|
+
if (!clientId || !clientSecret || !refreshToken)
|
|
139
|
+
return undefined;
|
|
140
|
+
registerSecret(clientSecret);
|
|
141
|
+
registerSecret(refreshToken);
|
|
142
|
+
return new URLSearchParams({
|
|
143
|
+
grant_type: 'refresh_token',
|
|
144
|
+
client_id: clientId,
|
|
145
|
+
client_secret: clientSecret,
|
|
146
|
+
refresh_token: refreshToken,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
async function mintGoogleAccessToken(requestBody, fetchFn, controller) {
|
|
152
|
+
let response;
|
|
153
|
+
try {
|
|
154
|
+
response = await fetchFn(GOOGLE_TOKEN_URL, {
|
|
155
|
+
method: 'POST',
|
|
156
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
157
|
+
body: requestBody.toString(),
|
|
158
|
+
redirect: 'manual',
|
|
159
|
+
signal: controller.signal,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return { ok: false, warning: 'Vertex authentication service could not be reached.' };
|
|
164
|
+
}
|
|
165
|
+
let body;
|
|
166
|
+
try {
|
|
167
|
+
body = await readCappedJson(response, MODEL_RESPONSE_LIMIT, controller.signal);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return { ok: false, warning: 'Authentication failed — check the ADC credentials' };
|
|
171
|
+
}
|
|
172
|
+
if (!response.ok)
|
|
173
|
+
return { ok: false, warning: 'Authentication failed — check the ADC credentials' };
|
|
174
|
+
const accessToken = record(body)?.access_token;
|
|
175
|
+
if (typeof accessToken !== 'string' || !accessToken) {
|
|
176
|
+
return { ok: false, warning: 'Authentication failed — check the ADC credentials' };
|
|
177
|
+
}
|
|
178
|
+
registerSecret(accessToken);
|
|
179
|
+
return { ok: true, accessToken };
|
|
180
|
+
}
|
|
181
|
+
async function probeGcpProvider(selection, deps) {
|
|
182
|
+
const project = selection.gcp?.project?.trim();
|
|
183
|
+
const adcPath = selection.gcp?.adcPath?.trim();
|
|
184
|
+
if (!project || !adcPath) {
|
|
185
|
+
return { ok: false, warning: 'Add a Vertex project and ADC credentials path to test.' };
|
|
186
|
+
}
|
|
187
|
+
let adc;
|
|
188
|
+
try {
|
|
189
|
+
const readFileFn = deps.readFileFn ?? ((path) => readFileSync(path, 'utf8'));
|
|
190
|
+
adc = record(JSON.parse(readFileFn(adcPath)));
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return { ok: false, warning: 'ADC credentials file could not be read or parsed.' };
|
|
194
|
+
}
|
|
195
|
+
if (!adc)
|
|
196
|
+
return { ok: false, warning: 'ADC credentials file could not be read or parsed.' };
|
|
197
|
+
if (adc.type !== 'service_account' && adc.type !== 'authorized_user') {
|
|
198
|
+
return { ok: false, warning: 'Unsupported ADC credential type.' };
|
|
199
|
+
}
|
|
200
|
+
let requestBody;
|
|
201
|
+
try {
|
|
202
|
+
requestBody = tokenRequestBody(adc);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return { ok: false, warning: 'ADC credentials file could not be read or parsed.' };
|
|
206
|
+
}
|
|
207
|
+
if (!requestBody)
|
|
208
|
+
return { ok: false, warning: 'ADC credentials file could not be read or parsed.' };
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
const timeoutMs = Math.min(15_000, Math.max(1, deps.timeoutMs ?? 15_000));
|
|
211
|
+
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
212
|
+
let timeout;
|
|
213
|
+
const run = async () => {
|
|
214
|
+
const result = await mintGoogleAccessToken(requestBody, fetchFn, controller);
|
|
215
|
+
return result.ok ? { ok: true } : result;
|
|
216
|
+
};
|
|
217
|
+
try {
|
|
218
|
+
return await Promise.race([
|
|
219
|
+
run(),
|
|
220
|
+
new Promise((resolve) => {
|
|
221
|
+
timeout = setTimeout(() => {
|
|
222
|
+
controller.abort();
|
|
223
|
+
resolve({ ok: false, timedOut: true, warning: 'Vertex authentication timed out.' });
|
|
224
|
+
}, timeoutMs);
|
|
225
|
+
}),
|
|
226
|
+
]);
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
if (timeout)
|
|
230
|
+
clearTimeout(timeout);
|
|
231
|
+
controller.abort();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export function validateModelName(value) {
|
|
235
|
+
if (typeof value !== 'string' || !MODEL_NAME_PATTERN.test(value)) {
|
|
236
|
+
throw new Error('Configured model name contains unsupported characters.');
|
|
237
|
+
}
|
|
238
|
+
return value;
|
|
239
|
+
}
|
|
240
|
+
function openAiModelsUrl(endpoint) {
|
|
241
|
+
const url = new URL(endpoint);
|
|
242
|
+
const path = url.pathname.replace(/\/$/, '');
|
|
243
|
+
url.pathname = path.endsWith('/v1') ? `${path}/models` : `${path}/v1/models`;
|
|
244
|
+
url.search = '';
|
|
245
|
+
url.hash = '';
|
|
246
|
+
return url.toString();
|
|
247
|
+
}
|
|
248
|
+
/** Advisory, read-only provider reachability check. It never returns response bodies or raw errors. */
|
|
249
|
+
/**
|
|
250
|
+
* Azure AI Foundry *project* endpoints (services.ai.azure.com / ai.azure.com) do
|
|
251
|
+
* not serve the /openai/deployments/... data plane the portable runtime uses —
|
|
252
|
+
* users must supply the Azure OpenAI *resource* endpoint instead. Detecting the
|
|
253
|
+
* host here converts a baffling 404 into an actionable message.
|
|
254
|
+
*/
|
|
255
|
+
export function foundryEndpointWarning(endpoint) {
|
|
256
|
+
if (typeof endpoint !== 'string' || !endpoint.trim())
|
|
257
|
+
return undefined;
|
|
258
|
+
try {
|
|
259
|
+
const host = new URL(endpoint).hostname.toLowerCase();
|
|
260
|
+
if (host.endsWith('.services.ai.azure.com') || host === 'ai.azure.com' || host.endsWith('.ai.azure.com')) {
|
|
261
|
+
return 'This looks like an AI Foundry project endpoint — use the Azure OpenAI resource endpoint instead (https://<resource>.openai.azure.com, shown under the resource’s Keys & Endpoint)';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch { /* unparsable endpoints fall through to the normal probe error paths */ }
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* `host.docker.internal` (and `gateway.docker.internal`) name the host from
|
|
269
|
+
* INSIDE containers — the runtime env needs that spelling, but the setup
|
|
270
|
+
* probes run on the host itself where those names do not resolve. Rewrite to
|
|
271
|
+
* loopback for the probe request only; the stored endpoint is untouched.
|
|
272
|
+
*/
|
|
273
|
+
export function hostReachableEndpoint(endpoint) {
|
|
274
|
+
try {
|
|
275
|
+
const url = new URL(endpoint);
|
|
276
|
+
if (url.hostname === 'host.docker.internal' || url.hostname === 'gateway.docker.internal') {
|
|
277
|
+
url.hostname = '127.0.0.1';
|
|
278
|
+
return url.toString();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch { /* invalid URLs fall through to the normal probe error paths */ }
|
|
282
|
+
return endpoint;
|
|
283
|
+
}
|
|
284
|
+
export async function probeProvider(selection, deps = {}) {
|
|
285
|
+
if (selection.provider === 'offline') {
|
|
286
|
+
return { ok: true, skipped: true };
|
|
287
|
+
}
|
|
288
|
+
if (selection.provider === 'gcp')
|
|
289
|
+
return probeGcpProvider(selection, deps);
|
|
290
|
+
if (selection.provider === 'azure') {
|
|
291
|
+
const foundry = foundryEndpointWarning(selection.azure?.endpoint);
|
|
292
|
+
if (foundry)
|
|
293
|
+
return { ok: false, warning: foundry, safeDetail: foundry };
|
|
294
|
+
}
|
|
295
|
+
const key = selection.provider === 'azure'
|
|
296
|
+
? selection.azure?.apiKey
|
|
297
|
+
: selection.openAiCompatible?.apiKey;
|
|
298
|
+
if (key)
|
|
299
|
+
registerSecret(key);
|
|
300
|
+
const endpoint = selection.provider === 'azure'
|
|
301
|
+
? selection.azure?.endpoint
|
|
302
|
+
: selection.openAiCompatible?.endpoint;
|
|
303
|
+
if (!endpoint) {
|
|
304
|
+
return { ok: false, warning: `Provider '${selection.provider}' has no endpoint to validate.` };
|
|
305
|
+
}
|
|
306
|
+
const headers = new Headers();
|
|
307
|
+
if (selection.provider === 'azure' && key)
|
|
308
|
+
headers.set('api-key', key);
|
|
309
|
+
if (selection.provider !== 'azure' && key)
|
|
310
|
+
headers.set('authorization', `Bearer ${key}`);
|
|
311
|
+
// A bare HEAD on the resource root 404s on healthy Azure OpenAI resources;
|
|
312
|
+
// the deployments list is the authoritative reachability + auth signal.
|
|
313
|
+
const url = selection.provider === 'azure'
|
|
314
|
+
? azureModelsProbeUrl(normalizeAzureOpenAiEndpoint(endpoint))
|
|
315
|
+
: openAiModelsUrl(hostReachableEndpoint(endpoint));
|
|
316
|
+
const controller = new AbortController();
|
|
317
|
+
const timeoutMs = Math.min(15_000, Math.max(1, deps.timeoutMs ?? 5_000));
|
|
318
|
+
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
319
|
+
let timeout;
|
|
320
|
+
try {
|
|
321
|
+
const outcome = await Promise.race([
|
|
322
|
+
fetchFn(url, {
|
|
323
|
+
method: 'GET',
|
|
324
|
+
headers,
|
|
325
|
+
redirect: 'manual',
|
|
326
|
+
signal: controller.signal,
|
|
327
|
+
}).then((response) => ({ response })),
|
|
328
|
+
new Promise((resolve) => {
|
|
329
|
+
timeout = setTimeout(() => {
|
|
330
|
+
controller.abort();
|
|
331
|
+
resolve({ timedOut: true });
|
|
332
|
+
}, timeoutMs);
|
|
333
|
+
}),
|
|
334
|
+
]);
|
|
335
|
+
if ('timedOut' in outcome) {
|
|
336
|
+
return {
|
|
337
|
+
ok: false,
|
|
338
|
+
timedOut: true,
|
|
339
|
+
warning: `Provider '${selection.provider}' validation timed out after ${timeoutMs}ms.`,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
if (!outcome.response.ok) {
|
|
343
|
+
return {
|
|
344
|
+
ok: false,
|
|
345
|
+
warning: `Provider '${selection.provider}' validation returned HTTP ${outcome.response.status}.`,
|
|
346
|
+
// Status code only — no response text — so this may cross to the page.
|
|
347
|
+
safeDetail: `Provider returned HTTP ${outcome.response.status} at the configured endpoint`,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return { ok: true };
|
|
351
|
+
}
|
|
352
|
+
catch {
|
|
353
|
+
return { ok: false, warning: `Provider '${selection.provider}' could not be reached.` };
|
|
354
|
+
}
|
|
355
|
+
finally {
|
|
356
|
+
if (timeout)
|
|
357
|
+
clearTimeout(timeout);
|
|
358
|
+
controller.abort();
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function compatModelUrl(endpoint, route) {
|
|
362
|
+
const url = new URL(endpoint);
|
|
363
|
+
const path = url.pathname.replace(/\/$/, '');
|
|
364
|
+
url.pathname = `${path.endsWith('/v1') ? path : `${path}/v1`}/${route}`;
|
|
365
|
+
url.search = '';
|
|
366
|
+
url.hash = '';
|
|
367
|
+
return url.toString();
|
|
368
|
+
}
|
|
369
|
+
const AZURE_MODELS_API_VERSION = '2024-10-21';
|
|
370
|
+
// GET /openai/models is served by BOTH classic Azure OpenAI resources and the newer
|
|
371
|
+
// Foundry-native resources; the legacy /openai/deployments list API 404s on the latter
|
|
372
|
+
// (observed live 2026-07-18), so it must not be the connection probe.
|
|
373
|
+
function azureModelsProbeUrl(endpoint) {
|
|
374
|
+
const url = new URL(endpoint);
|
|
375
|
+
const path = url.pathname.replace(/\/$/, '');
|
|
376
|
+
url.pathname = `${path}/openai/models`;
|
|
377
|
+
url.search = '';
|
|
378
|
+
url.hash = '';
|
|
379
|
+
url.searchParams.set('api-version', AZURE_MODELS_API_VERSION);
|
|
380
|
+
return url.toString();
|
|
381
|
+
}
|
|
382
|
+
function azureModelUrl(endpoint, deployment, route) {
|
|
383
|
+
const url = new URL(normalizeAzureOpenAiEndpoint(endpoint));
|
|
384
|
+
const path = url.pathname.replace(/\/$/, '');
|
|
385
|
+
url.pathname = `${path}/openai/deployments/${encodeURIComponent(deployment)}/${route}`;
|
|
386
|
+
url.search = '';
|
|
387
|
+
url.hash = '';
|
|
388
|
+
url.searchParams.set('api-version', AZURE_MODEL_API_VERSION);
|
|
389
|
+
return url.toString();
|
|
390
|
+
}
|
|
391
|
+
async function readCappedJson(response, limit, signal) {
|
|
392
|
+
if (!response.body)
|
|
393
|
+
return undefined;
|
|
394
|
+
const reader = response.body.getReader();
|
|
395
|
+
const chunks = [];
|
|
396
|
+
let total = 0;
|
|
397
|
+
let rejectAbort;
|
|
398
|
+
const aborted = new Promise((_resolve, reject) => { rejectAbort = reject; });
|
|
399
|
+
const onAbort = () => rejectAbort(new Error('MODEL_RESPONSE_ABORTED'));
|
|
400
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
401
|
+
try {
|
|
402
|
+
while (true) {
|
|
403
|
+
const { value, done } = await Promise.race([reader.read(), aborted]);
|
|
404
|
+
if (done)
|
|
405
|
+
break;
|
|
406
|
+
if (!value)
|
|
407
|
+
continue;
|
|
408
|
+
total += value.byteLength;
|
|
409
|
+
if (total > limit)
|
|
410
|
+
throw new Error('MODEL_RESPONSE_TOO_LARGE');
|
|
411
|
+
chunks.push(value);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
signal.removeEventListener('abort', onAbort);
|
|
416
|
+
if (total > limit || signal.aborted)
|
|
417
|
+
void reader.cancel().catch(() => undefined);
|
|
418
|
+
}
|
|
419
|
+
const bytes = new Uint8Array(total);
|
|
420
|
+
let offset = 0;
|
|
421
|
+
for (const chunk of chunks) {
|
|
422
|
+
bytes.set(chunk, offset);
|
|
423
|
+
offset += chunk.byteLength;
|
|
424
|
+
}
|
|
425
|
+
try {
|
|
426
|
+
return JSON.parse(new TextDecoder().decode(bytes));
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
return undefined;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function responseErrorCode(body) {
|
|
433
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
434
|
+
return undefined;
|
|
435
|
+
const error = body.error;
|
|
436
|
+
if (!error || typeof error !== 'object' || Array.isArray(error))
|
|
437
|
+
return undefined;
|
|
438
|
+
const code = error.code;
|
|
439
|
+
return typeof code === 'string' ? code.toLowerCase() : undefined;
|
|
440
|
+
}
|
|
441
|
+
function failureCategory(status, body) {
|
|
442
|
+
if (status === 401 || status === 403)
|
|
443
|
+
return 'auth';
|
|
444
|
+
if (status === 404)
|
|
445
|
+
return 'model';
|
|
446
|
+
if (status >= 300 && status < 400)
|
|
447
|
+
return 'endpoint';
|
|
448
|
+
const code = responseErrorCode(body);
|
|
449
|
+
if (code && ['invalid_api_key', 'unauthorized', 'authentication_error'].includes(code))
|
|
450
|
+
return 'auth';
|
|
451
|
+
if (code && ['model_not_found', 'deploymentnotfound', 'deployment_not_found'].includes(code))
|
|
452
|
+
return 'model';
|
|
453
|
+
if (code && ['invalid_endpoint', 'not_found'].includes(code))
|
|
454
|
+
return 'endpoint';
|
|
455
|
+
return 'unknown';
|
|
456
|
+
}
|
|
457
|
+
function failureMessage(category) {
|
|
458
|
+
if (category === 'auth')
|
|
459
|
+
return 'Authentication failed — check the provider credentials';
|
|
460
|
+
if (category === 'network')
|
|
461
|
+
return 'Provider could not be reached — check the URL/network';
|
|
462
|
+
if (category === 'endpoint')
|
|
463
|
+
return 'Provider endpoint is not configured or redirected unexpectedly';
|
|
464
|
+
if (category === 'model')
|
|
465
|
+
return 'Provider responded but the configured model is unavailable';
|
|
466
|
+
return 'Model test failed — check the provider configuration';
|
|
467
|
+
}
|
|
468
|
+
function responseHasExpectedShape(body, role) {
|
|
469
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
470
|
+
return false;
|
|
471
|
+
const record = body;
|
|
472
|
+
return role === 'embedding'
|
|
473
|
+
? Array.isArray(record.data) && record.data.length > 0
|
|
474
|
+
: Array.isArray(record.choices) && record.choices.length > 0;
|
|
475
|
+
}
|
|
476
|
+
function vertexModelName(value, fallback) {
|
|
477
|
+
const configured = typeof value === 'string' && value.trim() ? value.trim() : fallback;
|
|
478
|
+
const publisherStripped = configured.startsWith('google/') ? configured.slice('google/'.length) : configured;
|
|
479
|
+
return validateModelName(publisherStripped);
|
|
480
|
+
}
|
|
481
|
+
function vertexModelUrl(project, region, modelName, verb) {
|
|
482
|
+
return `https://${region}-aiplatform.googleapis.com/v1/projects/${encodeURIComponent(project)}` +
|
|
483
|
+
`/locations/${encodeURIComponent(region)}/publishers/google/models/${encodeURIComponent(modelName)}:${verb}`;
|
|
484
|
+
}
|
|
485
|
+
function vertexResponseHasExpectedShape(body, role) {
|
|
486
|
+
const value = record(body);
|
|
487
|
+
if (!value)
|
|
488
|
+
return false;
|
|
489
|
+
return role === 'embedding'
|
|
490
|
+
? Array.isArray(value.predictions) && value.predictions.length > 0
|
|
491
|
+
: Array.isArray(value.candidates) && value.candidates.length > 0;
|
|
492
|
+
}
|
|
493
|
+
async function probeGcpModel(selection, deps) {
|
|
494
|
+
const project = typeof selection.providerFields.project === 'string'
|
|
495
|
+
? selection.providerFields.project.trim()
|
|
496
|
+
: '';
|
|
497
|
+
const adcPath = typeof selection.providerFields.adcPath === 'string'
|
|
498
|
+
? selection.providerFields.adcPath.trim()
|
|
499
|
+
: '';
|
|
500
|
+
if (!project || !adcPath) {
|
|
501
|
+
return {
|
|
502
|
+
ok: false,
|
|
503
|
+
category: 'endpoint',
|
|
504
|
+
message: 'Add a Vertex project and ADC credentials path to test.',
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
const region = typeof selection.providerFields.region === 'string' && selection.providerFields.region.trim()
|
|
508
|
+
? selection.providerFields.region.trim()
|
|
509
|
+
: 'us-central1';
|
|
510
|
+
let modelName;
|
|
511
|
+
try {
|
|
512
|
+
if (!VERTEX_PROJECT_PATTERN.test(project) || !VERTEX_REGION_PATTERN.test(region))
|
|
513
|
+
throw new Error('invalid');
|
|
514
|
+
modelName = selection.modelRole === 'embedding'
|
|
515
|
+
? vertexModelName(selection.providerFields.embeddingModel, VERTEX_EMBEDDING_DEFAULT)
|
|
516
|
+
: vertexModelName(selection.providerFields.chatModel, VERTEX_CHAT_DEFAULT);
|
|
517
|
+
}
|
|
518
|
+
catch {
|
|
519
|
+
return {
|
|
520
|
+
ok: false,
|
|
521
|
+
category: 'endpoint',
|
|
522
|
+
message: 'Vertex project, region, or model configuration is invalid',
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
let adc;
|
|
526
|
+
try {
|
|
527
|
+
const readFileFn = deps.readFileFn ?? ((path) => readFileSync(path, 'utf8'));
|
|
528
|
+
adc = record(JSON.parse(readFileFn(adcPath)));
|
|
529
|
+
}
|
|
530
|
+
catch {
|
|
531
|
+
return { ok: false, category: 'endpoint', message: 'ADC credentials file could not be read or parsed.' };
|
|
532
|
+
}
|
|
533
|
+
if (!adc)
|
|
534
|
+
return { ok: false, category: 'endpoint', message: 'ADC credentials file could not be read or parsed.' };
|
|
535
|
+
if (adc.type !== 'service_account' && adc.type !== 'authorized_user') {
|
|
536
|
+
return { ok: false, category: 'endpoint', message: 'Unsupported ADC credential type.' };
|
|
537
|
+
}
|
|
538
|
+
let requestBody;
|
|
539
|
+
try {
|
|
540
|
+
requestBody = tokenRequestBody(adc);
|
|
541
|
+
}
|
|
542
|
+
catch {
|
|
543
|
+
return { ok: false, category: 'endpoint', message: 'ADC credentials file could not be read or parsed.' };
|
|
544
|
+
}
|
|
545
|
+
if (!requestBody) {
|
|
546
|
+
return { ok: false, category: 'endpoint', message: 'ADC credentials file could not be read or parsed.' };
|
|
547
|
+
}
|
|
548
|
+
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
549
|
+
const timeoutMs = Math.min(15_000, Math.max(1, deps.timeoutMs ?? 15_000));
|
|
550
|
+
const bodyLimit = Math.min(MODEL_RESPONSE_LIMIT, Math.max(1, deps.responseBodyLimitBytes ?? MODEL_RESPONSE_LIMIT));
|
|
551
|
+
const now = deps.now ?? Date.now;
|
|
552
|
+
const startedAt = now();
|
|
553
|
+
const controller = new AbortController();
|
|
554
|
+
let timeout;
|
|
555
|
+
const run = async () => {
|
|
556
|
+
const token = await mintGoogleAccessToken(requestBody, fetchFn, controller);
|
|
557
|
+
if (!token.ok) {
|
|
558
|
+
const category = /could not be reached/i.test(token.warning) ? 'network' : 'auth';
|
|
559
|
+
return {
|
|
560
|
+
ok: false,
|
|
561
|
+
category,
|
|
562
|
+
message: category === 'auth' ? 'Authentication failed — check the ADC credentials' : failureMessage(category),
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
const verb = selection.modelRole === 'embedding' ? 'predict' : 'generateContent';
|
|
566
|
+
const url = vertexModelUrl(project, region, modelName, verb);
|
|
567
|
+
const payload = selection.modelRole === 'embedding'
|
|
568
|
+
? { instances: [{ content: 'ok' }] }
|
|
569
|
+
: selection.modelRole === 'vision'
|
|
570
|
+
? {
|
|
571
|
+
contents: [{
|
|
572
|
+
role: 'user',
|
|
573
|
+
parts: [
|
|
574
|
+
{ text: 'Reply with OK.' },
|
|
575
|
+
{ inlineData: { mimeType: 'image/png', data: PROBE_VISION_PNG_BASE64 } },
|
|
576
|
+
],
|
|
577
|
+
}],
|
|
578
|
+
generationConfig: { maxOutputTokens: 8 },
|
|
579
|
+
}
|
|
580
|
+
: {
|
|
581
|
+
contents: [{ role: 'user', parts: [{ text: 'Reply with OK.' }] }],
|
|
582
|
+
generationConfig: { maxOutputTokens: 8 },
|
|
583
|
+
};
|
|
584
|
+
let response;
|
|
585
|
+
try {
|
|
586
|
+
response = await fetchFn(url, {
|
|
587
|
+
method: 'POST',
|
|
588
|
+
headers: {
|
|
589
|
+
authorization: `Bearer ${token.accessToken}`,
|
|
590
|
+
'content-type': 'application/json',
|
|
591
|
+
},
|
|
592
|
+
body: JSON.stringify(payload),
|
|
593
|
+
redirect: 'manual',
|
|
594
|
+
signal: controller.signal,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
return { ok: false, category: 'network', message: failureMessage('network') };
|
|
599
|
+
}
|
|
600
|
+
let body;
|
|
601
|
+
try {
|
|
602
|
+
body = await readCappedJson(response, bodyLimit, controller.signal);
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
return { ok: false, category: 'unknown', message: failureMessage('unknown') };
|
|
606
|
+
}
|
|
607
|
+
if (response.ok && vertexResponseHasExpectedShape(body, selection.modelRole)) {
|
|
608
|
+
return {
|
|
609
|
+
ok: true,
|
|
610
|
+
latencyMs: Math.max(0, Math.round(now() - startedAt)),
|
|
611
|
+
modelName,
|
|
612
|
+
message: 'Responded',
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
const category = response.ok ? 'unknown' : failureCategory(response.status, body);
|
|
616
|
+
return { ok: false, category, message: failureMessage(category) };
|
|
617
|
+
};
|
|
618
|
+
try {
|
|
619
|
+
return await Promise.race([
|
|
620
|
+
run(),
|
|
621
|
+
new Promise((resolve) => {
|
|
622
|
+
timeout = setTimeout(() => {
|
|
623
|
+
controller.abort();
|
|
624
|
+
resolve({ ok: false, category: 'network', message: 'Timed out — check the URL/network' });
|
|
625
|
+
}, timeoutMs);
|
|
626
|
+
}),
|
|
627
|
+
]);
|
|
628
|
+
}
|
|
629
|
+
finally {
|
|
630
|
+
if (timeout)
|
|
631
|
+
clearTimeout(timeout);
|
|
632
|
+
controller.abort();
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Sends one bounded, constant model request from the CLI process. Endpoint-controlled response text is
|
|
637
|
+
* shape-checked and discarded; only canned outcome copy crosses back to the setup browser.
|
|
638
|
+
*/
|
|
639
|
+
export async function probeModel(selection, deps = {}) {
|
|
640
|
+
if (selection.provider === 'offline') {
|
|
641
|
+
return { ok: true, message: 'Offline stub — no model to test' };
|
|
642
|
+
}
|
|
643
|
+
if (selection.provider === 'gcp')
|
|
644
|
+
return probeGcpModel(selection, deps);
|
|
645
|
+
const endpoint = selection.providerFields.endpoint;
|
|
646
|
+
const apiKey = selection.providerFields.apiKey;
|
|
647
|
+
if (typeof apiKey === 'string' && apiKey)
|
|
648
|
+
registerSecret(apiKey);
|
|
649
|
+
if (typeof endpoint !== 'string' || !endpoint.trim()) {
|
|
650
|
+
return { ok: false, category: 'endpoint', message: 'Add a provider endpoint before testing the model' };
|
|
651
|
+
}
|
|
652
|
+
if (selection.provider === 'azure') {
|
|
653
|
+
const foundry = foundryEndpointWarning(endpoint);
|
|
654
|
+
if (foundry)
|
|
655
|
+
return { ok: false, category: 'endpoint', message: foundry };
|
|
656
|
+
}
|
|
657
|
+
let candidates;
|
|
658
|
+
try {
|
|
659
|
+
if (selection.provider === 'azure') {
|
|
660
|
+
candidates = selection.modelRole === 'embedding' ? AZURE_EMBEDDING_DEPLOYMENTS : AZURE_CHAT_DEPLOYMENTS;
|
|
661
|
+
}
|
|
662
|
+
else {
|
|
663
|
+
const field = selection.modelRole === 'embedding' ? 'embeddingModel' : 'chatModel';
|
|
664
|
+
candidates = [validateModelName(selection.providerFields[field])];
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
catch {
|
|
668
|
+
return { ok: false, category: 'model', message: 'Configured model name is missing or invalid' };
|
|
669
|
+
}
|
|
670
|
+
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
671
|
+
const timeoutMs = Math.min(15_000, Math.max(1, deps.timeoutMs ?? 15_000));
|
|
672
|
+
const bodyLimit = Math.min(MODEL_RESPONSE_LIMIT, Math.max(1, deps.responseBodyLimitBytes ?? MODEL_RESPONSE_LIMIT));
|
|
673
|
+
const now = deps.now ?? Date.now;
|
|
674
|
+
const startedAt = now();
|
|
675
|
+
const controller = new AbortController();
|
|
676
|
+
let timeout;
|
|
677
|
+
const run = async () => {
|
|
678
|
+
for (const modelName of candidates) {
|
|
679
|
+
validateModelName(modelName);
|
|
680
|
+
const route = selection.modelRole === 'embedding' ? 'embeddings' : 'chat/completions';
|
|
681
|
+
const url = selection.provider === 'azure'
|
|
682
|
+
? azureModelUrl(endpoint, modelName, route)
|
|
683
|
+
: compatModelUrl(hostReachableEndpoint(endpoint), route);
|
|
684
|
+
const headers = new Headers({ 'content-type': 'application/json' });
|
|
685
|
+
if (selection.provider === 'azure' && typeof apiKey === 'string')
|
|
686
|
+
headers.set('api-key', apiKey);
|
|
687
|
+
if (selection.provider !== 'azure' && typeof apiKey === 'string' && apiKey) {
|
|
688
|
+
headers.set('authorization', `Bearer ${apiKey}`);
|
|
689
|
+
}
|
|
690
|
+
const payload = selection.modelRole === 'embedding'
|
|
691
|
+
? { model: modelName, input: 'ok' }
|
|
692
|
+
: selection.modelRole === 'vision'
|
|
693
|
+
? {
|
|
694
|
+
model: modelName,
|
|
695
|
+
messages: [{
|
|
696
|
+
role: 'user',
|
|
697
|
+
content: [
|
|
698
|
+
{ type: 'text', text: 'Reply with OK.' },
|
|
699
|
+
{
|
|
700
|
+
type: 'image_url',
|
|
701
|
+
image_url: { url: `data:image/png;base64,${PROBE_VISION_PNG_BASE64}` },
|
|
702
|
+
},
|
|
703
|
+
],
|
|
704
|
+
}],
|
|
705
|
+
...(selection.provider === 'azure' ? { max_completion_tokens: 16 } : { max_tokens: 8 }),
|
|
706
|
+
stream: false,
|
|
707
|
+
}
|
|
708
|
+
: {
|
|
709
|
+
model: modelName,
|
|
710
|
+
messages: [{ role: 'user', content: 'Reply with OK.' }],
|
|
711
|
+
// gpt-5.x-family models reject max_tokens ("use max_completion_tokens");
|
|
712
|
+
// OpenAI-compatible servers (Ollama/vLLM) still speak max_tokens.
|
|
713
|
+
...(selection.provider === 'azure' ? { max_completion_tokens: 16 } : { max_tokens: 8 }),
|
|
714
|
+
stream: false,
|
|
715
|
+
};
|
|
716
|
+
let response;
|
|
717
|
+
try {
|
|
718
|
+
response = await fetchFn(url, {
|
|
719
|
+
method: 'POST',
|
|
720
|
+
headers,
|
|
721
|
+
body: JSON.stringify(payload),
|
|
722
|
+
redirect: 'manual',
|
|
723
|
+
signal: controller.signal,
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
catch {
|
|
727
|
+
return { ok: false, category: 'network', message: failureMessage('network') };
|
|
728
|
+
}
|
|
729
|
+
let body;
|
|
730
|
+
try {
|
|
731
|
+
body = await readCappedJson(response, bodyLimit, controller.signal);
|
|
732
|
+
}
|
|
733
|
+
catch {
|
|
734
|
+
return { ok: false, category: 'unknown', message: failureMessage('unknown') };
|
|
735
|
+
}
|
|
736
|
+
if (response.ok && responseHasExpectedShape(body, selection.modelRole)) {
|
|
737
|
+
return {
|
|
738
|
+
ok: true,
|
|
739
|
+
latencyMs: Math.max(0, Math.round(now() - startedAt)),
|
|
740
|
+
modelName,
|
|
741
|
+
message: 'Responded',
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
if (selection.provider === 'azure' && response.status === 404)
|
|
745
|
+
continue;
|
|
746
|
+
const category = response.ok ? 'unknown' : failureCategory(response.status, body);
|
|
747
|
+
return { ok: false, category, message: failureMessage(category) };
|
|
748
|
+
}
|
|
749
|
+
return selection.modelRole !== 'embedding'
|
|
750
|
+
? {
|
|
751
|
+
ok: false,
|
|
752
|
+
category: 'model',
|
|
753
|
+
message: `Endpoint reachable, but no deployment named ${AZURE_CHAT_DEPLOYMENTS.join(' or ')} exists on it — deploy the model with that exact deployment name (deployment names are not model names)`,
|
|
754
|
+
}
|
|
755
|
+
: {
|
|
756
|
+
ok: false,
|
|
757
|
+
category: 'model',
|
|
758
|
+
message: `Endpoint reachable, but no deployment named ${AZURE_EMBEDDING_DEPLOYMENTS.join(' or ')} exists on it — deploy the model with that exact deployment name (deployment names are not model names)`,
|
|
759
|
+
};
|
|
760
|
+
};
|
|
761
|
+
try {
|
|
762
|
+
return await Promise.race([
|
|
763
|
+
run(),
|
|
764
|
+
new Promise((resolve) => {
|
|
765
|
+
timeout = setTimeout(() => {
|
|
766
|
+
resolve({ ok: false, category: 'network', message: 'Timed out — check the URL/network' });
|
|
767
|
+
controller.abort();
|
|
768
|
+
}, timeoutMs);
|
|
769
|
+
}),
|
|
770
|
+
]);
|
|
771
|
+
}
|
|
772
|
+
catch {
|
|
773
|
+
return { ok: false, category: 'unknown', message: failureMessage('unknown') };
|
|
774
|
+
}
|
|
775
|
+
finally {
|
|
776
|
+
if (timeout)
|
|
777
|
+
clearTimeout(timeout);
|
|
778
|
+
controller.abort();
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
//# sourceMappingURL=platform-provider-probe.js.map
|