@vantran-se/openchamber-web 1.24.3 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -8
- package/bin/lib/commands-connect-url.js +3 -8
- package/bin/lib/commands-tunnel.js +3 -0
- package/dist/assets/{CodeMirrorCommentWidgets-BjJHrzmU.js → CodeMirrorCommentWidgets-ntXIbhV2.js} +1 -1
- package/dist/assets/DiffView-CjxUovbM.js +4 -0
- package/dist/assets/FilesView-DFWD0RQR.js +17 -0
- package/dist/assets/{GitView-CDOJy5Ay.js → GitView-BWa7e5vw.js} +4 -4
- package/dist/assets/{GuestAttachDialog-D3S0Rjic.js → GuestAttachDialog-DdOuyZzp.js} +1 -1
- package/dist/assets/GuestSurfacePane-DDfzid3U.js +1 -0
- package/dist/assets/{JsonTreeView-D0C9nU7K.js → JsonTreeView-3sGwqexh.js} +1 -1
- package/dist/assets/LinearIssuesView-C6dpIdjw.js +1 -0
- package/dist/assets/MarkdownImageGallery-Q7YR_tl4.js +1 -0
- package/dist/assets/MarkdownRendererImpl-DxDV56bL.js +12 -0
- package/dist/assets/OnboardingScreen-rK4Stg__.js +1 -0
- package/dist/assets/{PatchDiff-DnEhjXcC.js → PatchDiff-DS-IMU1j.js} +1 -1
- package/dist/assets/{PierreDiffViewer-DyxZVVVR.js → PierreDiffViewer-DW23KWKZ.js} +1 -1
- package/dist/assets/PlanView-BCk_VobP.js +5 -0
- package/dist/assets/PluginPane-BPP1dbck.js +3 -0
- package/dist/assets/SettingsView-kMmrpn43.js +29 -0
- package/dist/assets/SettingsWindow-BpvD6IYQ.js +1 -0
- package/dist/assets/SubmoduleDiffSummary-BLttSS1X.js +1 -0
- package/dist/assets/ToolOutputDialog-CtqDqbyr.js +15 -0
- package/dist/assets/ToolPartDiffPreview-5FcKdyRy.js +8 -0
- package/dist/assets/{VirtualizedFileDiff-0pyr_mHY.js → VirtualizedFileDiff-C763hNCR.js} +4 -4
- package/dist/assets/{WalkthroughView-yNj4nOP5.js → WalkthroughView-lap5btCF.js} +2 -2
- package/dist/assets/appThemeRegistry-u4zw1l0B.js +1 -0
- package/dist/assets/{commitAndPush-DvJKa3Ks.js → commitAndPush-CwGJfJG-.js} +1 -1
- package/dist/assets/{computeVirtualFileMetrics-DxTBMuu-.js → computeVirtualFileMetrics-DW5jjX4n.js} +1 -1
- package/dist/assets/de-CndEg67T.js +10 -0
- package/dist/assets/es-DglvPlaC.js +16 -0
- package/dist/assets/fr-DejPCpbS.js +14 -0
- package/dist/assets/index-C2r64QfD.js +1 -0
- package/dist/assets/index-CLcM8HKx.css +1 -0
- package/dist/assets/index-CvLgnuNI.js +41 -0
- package/dist/assets/{isDiffPlainText-D7FkBMP6.js → isDiffPlainText-D47a6hMP.js} +1 -1
- package/dist/assets/{isFilePlainText-CL2vsrIZ.js → isFilePlainText-B-mGgeKl.js} +1 -1
- package/dist/assets/ja-CVpQawCd.js +16 -0
- package/dist/assets/ko-Bw446h9j.js +16 -0
- package/dist/assets/main-Bz4WWXbr.js +2 -0
- package/dist/assets/main-oreqDsOV.js +896 -0
- package/dist/assets/{markdownCore-Dh7WEsdM.js → markdownCore-D2e5sp9y.js} +4 -4
- package/dist/assets/miniChat-D1v2gsBI.js +2 -0
- package/dist/assets/mobile-DBj3lCf2.js +2 -0
- package/dist/assets/{patchFileDiff-Bsba8KFp.js → patchFileDiff-BpeUOV91.js} +3 -3
- package/dist/assets/pl-BYNlPdhm.js +16 -0
- package/dist/assets/pt-BR-CL-Yfv9H.js +16 -0
- package/dist/assets/renderElectronMiniChatApp-DVtfEB2z.js +2 -0
- package/dist/assets/renderMobileApp-DFp9-xbG.js +25 -0
- package/dist/assets/runtimeEndpointReset-CsIpUep1.js +27 -0
- package/dist/assets/scheduledTasksApi-B5OHVpPM.js +1 -0
- package/dist/assets/{shikiHighlight-8_3csmr6.js → shikiHighlight-DNm2Z_Jc.js} +1 -1
- package/dist/assets/{textMateThemeFromAppTheme-CHo2fCgW.js → textMateThemeFromAppTheme-DGF2kG7g.js} +1 -1
- package/dist/assets/tr-DzmbxLy-.js +7 -0
- package/dist/assets/uk-C7vQnwro.js +16 -0
- package/dist/assets/useAppFontEffects-Ci3FEaPf.js +7337 -0
- package/dist/assets/{useInlineCommentController-DkQ_gqpn.js → useInlineCommentController-CuUuakrt.js} +2 -2
- package/dist/assets/useRootScrollLock-CQIsyERq.js +2 -0
- package/dist/assets/{vendor-codemirror-language-data-CdzUmUyZ.js → vendor-codemirror-language-data-CQa7_1cr.js} +2 -2
- package/dist/assets/vendor-cron-parser-CjvYVigk.js +2 -0
- package/dist/assets/vendor-opencode-client-_BAHQo4R.js +12 -0
- package/dist/assets/{vendor-remixicon-react-BDmGmFCA.js → vendor-remixicon-react-D6dZ0UwF.js} +1 -1
- package/dist/assets/{vendor-zod-CgAdXWZO.js → vendor-zod-Gea9uBlY.js} +1 -1
- package/dist/assets/{web-components-B8IcVQAA.js → web-components-B6tKQyJN.js} +2 -2
- package/dist/assets/zh-CN-Cl0srS-z.js +16 -0
- package/dist/assets/zh-TW-DtII5bDb.js +16 -0
- package/dist/index.html +13 -7
- package/dist/mini-chat.html +5 -5
- package/dist/mobile.html +5 -5
- package/package.json +6 -5
- package/server/index.d.ts +1 -0
- package/server/index.js +246 -91
- package/server/lib/agent-tool/DOCUMENTATION.md +32 -15
- package/server/lib/agent-tool/runtime.js +135 -54
- package/server/lib/agent-tool/runtime.test.js +155 -87
- package/server/lib/browser-control/DOCUMENTATION.md +37 -2
- package/server/lib/browser-control/provider.js +217 -0
- package/server/lib/browser-control/provider.test.js +251 -0
- package/server/lib/context-obligatory/runtime.js +61 -50
- package/server/lib/context-obligatory/runtime.test.js +62 -162
- package/server/lib/event-stream/DOCUMENTATION.md +12 -1
- package/server/lib/event-stream/delta-coalescer.js +0 -0
- package/server/lib/event-stream/delta-coalescer.test.js +68 -57
- package/server/lib/event-stream/directory-ws-bridge.js +1 -1
- package/server/lib/event-stream/global-hub.js +10 -1
- package/server/lib/event-stream/global-hub.test.js +27 -26
- package/server/lib/event-stream/index.js +6 -0
- package/server/lib/event-stream/protocol.js +26 -19
- package/server/lib/event-stream/protocol.test.js +18 -7
- package/server/lib/event-stream/rebind.test.js +5 -5
- package/server/lib/event-stream/runtime.test.js +17 -15
- package/server/lib/event-stream/translate-v2.js +313 -0
- package/server/lib/event-stream/translate-v2.test.js +209 -0
- package/server/lib/event-stream/upstream-reader.test.js +16 -16
- package/server/lib/fs/DOCUMENTATION.md +4 -2
- package/server/lib/fs/byte-range.js +35 -0
- package/server/lib/fs/byte-range.test.js +31 -0
- package/server/lib/fs/routes.js +47 -42
- package/server/lib/fs/routes.test.js +123 -18
- package/server/lib/git/service.js +12 -0
- package/server/lib/github/DOCUMENTATION.md +1 -1
- package/server/lib/github/pr-status.js +22 -2
- package/server/lib/github/pr-status.test.js +27 -14
- package/server/lib/guests/DOCUMENTATION.md +13 -0
- package/server/lib/guests/catalog.js +12 -0
- package/server/lib/guests/catalog.test.js +33 -0
- package/server/lib/guests/routes.js +10 -1
- package/server/lib/guests/service.js +192 -14
- package/server/lib/guests/service.test.js +201 -1
- package/server/lib/guests/surface.js +630 -0
- package/server/lib/guests/surface.test.js +486 -0
- package/server/lib/markdown-image-grants/routes.js +18 -5
- package/server/lib/markdown-image-grants/routes.test.js +9 -6
- package/server/lib/message-queue/DOCUMENTATION.md +33 -22
- package/server/lib/message-queue/runtime.js +155 -100
- package/server/lib/message-queue/runtime.test.js +168 -82
- package/server/lib/notifications/DOCUMENTATION.md +28 -0
- package/server/lib/notifications/control-stream.http.test.js +68 -0
- package/server/lib/notifications/emitter-runtime.js +15 -0
- package/server/lib/notifications/emitter-runtime.test.js +32 -0
- package/server/lib/notifications/push-runtime.js +5 -1
- package/server/lib/notifications/push-runtime.test.js +2 -2
- package/server/lib/notifications/routes.js +1 -1
- package/server/lib/notifications/runtime.js +115 -26
- package/server/lib/notifications/template-runtime.js +13 -15
- package/server/lib/notifications/template-runtime.test.js +16 -9
- package/server/lib/notifications/trigger-runtime.test.js +187 -0
- package/server/lib/openchamber-control/DOCUMENTATION.md +10 -0
- package/server/lib/openchamber-control/actions.js +3 -2
- package/server/lib/openchamber-control/error.js +1 -1
- package/server/lib/openchamber-control/file-open.js +59 -0
- package/server/lib/openchamber-control/file-open.test.js +57 -0
- package/server/lib/openchamber-control/routes.test.js +12 -0
- package/server/lib/openchamber-control/service.js +102 -49
- package/server/lib/openchamber-control/service.test.js +84 -44
- package/server/lib/openchamber-sessions/archive-store.js +224 -0
- package/server/lib/openchamber-sessions/archive-store.test.js +187 -0
- package/server/lib/openchamber-sessions/opencode-client.js +22 -0
- package/server/lib/openchamber-sessions/routes.js +398 -328
- package/server/lib/openchamber-sessions/routes.test.js +777 -740
- package/server/lib/openchamber-sessions/session-metadata-store.js +285 -0
- package/server/lib/openchamber-sessions/session-metadata-store.test.js +259 -0
- package/server/lib/opencode/DOCUMENTATION.md +449 -29
- package/server/lib/opencode/agents.js +233 -327
- package/server/lib/opencode/auth.js +41 -44
- package/server/lib/opencode/auth.test.js +92 -0
- package/server/lib/opencode/cli-upgrade.d.ts +4 -0
- package/server/lib/opencode/cli-upgrade.js +18 -0
- package/server/lib/opencode/cli-upgrade.test.js +36 -0
- package/server/lib/opencode/commands.js +164 -145
- package/server/lib/opencode/compatibility.d.ts +16 -0
- package/server/lib/opencode/compatibility.js +88 -0
- package/server/lib/opencode/compatibility.test.js +62 -0
- package/server/lib/opencode/config-entity-routes.js +58 -29
- package/server/lib/opencode/config-entity-v2.test.js +290 -0
- package/server/lib/opencode/config-mutation-response.js +17 -7
- package/server/lib/opencode/config-mutation-response.test.js +4 -7
- package/server/lib/opencode/config-paths.test.js +2 -2
- package/server/lib/opencode/config-v2.d.ts +183 -0
- package/server/lib/opencode/config-v2.js +801 -0
- package/server/lib/opencode/config-v2.test.js +466 -0
- package/server/lib/opencode/credential-db.js +144 -0
- package/server/lib/opencode/credential-db.test.js +104 -0
- package/server/lib/opencode/env-runtime.js +48 -9
- package/server/lib/opencode/env-runtime.test.js +45 -0
- package/server/lib/opencode/feature-routes-runtime.js +15 -5
- package/server/lib/opencode/lifecycle-process.test.js +7 -4
- package/server/lib/opencode/lifecycle.js +85 -30
- package/server/lib/opencode/lifecycle.test.js +80 -8
- package/server/lib/opencode/login-shell-env.js +27 -0
- package/server/lib/opencode/managed-config-file.js +119 -0
- package/server/lib/opencode/managed-config-file.test.js +152 -0
- package/server/lib/opencode/managed-plugin-config.js +33 -13
- package/server/lib/opencode/mcp.js +43 -149
- package/server/lib/opencode/network-runtime.js +6 -7
- package/server/lib/opencode/openchamber-routes.test.js +2 -5
- package/server/lib/opencode/plugin-routes.js +3 -3
- package/server/lib/opencode/plugin-routes.test.js +6 -24
- package/server/lib/opencode/plugins.js +91 -40
- package/server/lib/opencode/plugins.test.js +28 -15
- package/server/lib/opencode/providers.js +63 -83
- package/server/lib/opencode/providers.test.js +128 -59
- package/server/lib/opencode/proxy-agent-wiring.test.js +4 -2
- package/server/lib/opencode/proxy.js +179 -129
- package/server/lib/opencode/pwa-manifest-routes.js +4 -2
- package/server/lib/opencode/pwa-manifest-routes.test.js +3 -2
- package/server/lib/opencode/response-envelope.js +14 -0
- package/server/lib/opencode/response-envelope.test.js +23 -0
- package/server/lib/opencode/routes-upgrade.test.js +73 -116
- package/server/lib/opencode/routes.js +121 -428
- package/server/lib/opencode/server-utils-runtime.js +10 -4
- package/server/lib/opencode/session-activity.js +78 -0
- package/server/lib/opencode/session-runtime.js +21 -10
- package/server/lib/opencode/session-runtime.test.js +9 -9
- package/server/lib/opencode/settings-helpers.js +9 -9
- package/server/lib/opencode/settings-helpers.test.js +7 -12
- package/server/lib/opencode/settings-registry.json +6 -8
- package/server/lib/opencode/settings-runtime.js +18 -1
- package/server/lib/opencode/settings-runtime.test.js +31 -2
- package/server/lib/opencode/shared.js +54 -22
- package/server/lib/opencode/shared.test.js +8 -4
- package/server/lib/opencode/shutdown-runtime.js +54 -7
- package/server/lib/opencode/shutdown-runtime.test.js +224 -30
- package/server/lib/opencode/skill-routes.js +23 -24
- package/server/lib/opencode/skills.js +7 -5
- package/server/lib/opencode/tunnel-wiring-runtime.js +2 -1
- package/server/lib/opencode/upgrade-capability.test.js +1 -1
- package/server/lib/opencode/v1-migration-topup.js +288 -0
- package/server/lib/opencode/v1-migration-topup.test.js +266 -0
- package/server/lib/opencode/v2-install.d.ts +8 -0
- package/server/lib/opencode/v2-install.js +158 -0
- package/server/lib/opencode/v2-install.test.js +124 -0
- package/server/lib/opencode/watcher.js +10 -3
- package/server/lib/opencode/watcher.test.js +17 -21
- package/server/lib/opencode/websearch-config.js +66 -0
- package/server/lib/package-manager.js +55 -68
- package/server/lib/package-manager.test.js +241 -75
- package/server/lib/permission-auto-accept/runtime.js +38 -22
- package/server/lib/permission-auto-accept/runtime.test.js +39 -17
- package/server/lib/quota/DOCUMENTATION.md +4 -0
- package/server/lib/quota/providers/xai.js +4 -4
- package/server/lib/relay/tunnel-host.js +4 -1
- package/server/lib/relay/tunnel-host.test.js +7 -0
- package/server/lib/routing/DOCUMENTATION.md +52 -21
- package/server/lib/routing/defaults.js +23 -6
- package/server/lib/routing/jev.js +17 -7
- package/server/lib/routing/routes.http.test.js +68 -33
- package/server/lib/routing/routes.js +65 -22
- package/server/lib/routing/runtime.js +145 -48
- package/server/lib/routing/runtime.test.js +79 -55
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +4 -0
- package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +51 -46
- package/server/lib/scheduled-tasks/runtime.js +81 -74
- package/server/lib/scheduled-tasks/runtime.test.js +53 -1
- package/server/lib/session-assist/DOCUMENTATION.md +8 -3
- package/server/lib/session-assist/context.js +122 -46
- package/server/lib/session-assist/context.test.js +117 -49
- package/server/lib/session-assist/runtime.js +52 -22
- package/server/lib/session-assist/runtime.test.js +145 -173
- package/server/lib/session-goal/DOCUMENTATION.md +23 -15
- package/server/lib/session-goal/create.js +9 -12
- package/server/lib/session-goal/create.test.js +27 -28
- package/server/lib/session-goal/runtime.js +164 -77
- package/server/lib/session-goal/runtime.test.js +271 -519
- package/server/lib/session-knowledge/DOCUMENTATION.md +5 -0
- package/server/lib/session-knowledge/runtime.js +59 -41
- package/server/lib/session-knowledge/runtime.test.js +90 -20
- package/server/lib/small-model/DOCUMENTATION.md +154 -208
- package/server/lib/small-model/client.js +113 -0
- package/server/lib/small-model/index.js +296 -158
- package/server/lib/small-model/index.test.js +423 -256
- package/server/lib/small-model/routes.js +1 -1
- package/server/lib/spaces/DOCUMENTATION.md +807 -0
- package/server/lib/spaces/code-in-bait.js +185 -0
- package/server/lib/spaces/code-in.js +641 -0
- package/server/lib/spaces/code-in.test.js +1048 -0
- package/server/lib/spaces/errors.js +8 -0
- package/server/lib/spaces/exec-http.js +94 -0
- package/server/lib/spaces/gatekeeper-channel.js +202 -0
- package/server/lib/spaces/gatekeeper-channel.test.js +215 -0
- package/server/lib/spaces/gatekeeper-program.cjs +914 -0
- package/server/lib/spaces/gatekeeper-program.test.js +1391 -0
- package/server/lib/spaces/hardening.js +457 -0
- package/server/lib/spaces/hardening.test.js +368 -0
- package/server/lib/spaces/host-git.js +127 -0
- package/server/lib/spaces/host-git.test.js +137 -0
- package/server/lib/spaces/labels.js +234 -0
- package/server/lib/spaces/labels.test.js +219 -0
- package/server/lib/spaces/layout.js +184 -0
- package/server/lib/spaces/layout.test.js +30 -0
- package/server/lib/spaces/manager.js +82 -0
- package/server/lib/spaces/manager.test.js +114 -0
- package/server/lib/spaces/places/code-in.docker.live.test.js +216 -0
- package/server/lib/spaces/places/contract-suite.js +156 -0
- package/server/lib/spaces/places/contract.docker.live.test.js +7 -0
- package/server/lib/spaces/places/contract.test.js +6 -0
- package/server/lib/spaces/places/docker-engine.js +126 -0
- package/server/lib/spaces/places/docker-live-support.js +202 -0
- package/server/lib/spaces/places/docker-tools.js +186 -0
- package/server/lib/spaces/places/docker.js +587 -0
- package/server/lib/spaces/places/docker.test.js +1610 -0
- package/server/lib/spaces/places/escape-suite.js +1018 -0
- package/server/lib/spaces/places/escape.docker.live.test.js +7 -0
- package/server/lib/spaces/places/fake-docker.js +375 -0
- package/server/lib/spaces/places/memory-place.js +103 -0
- package/server/lib/spaces/places/packed.docker.live.test.js +77 -0
- package/server/lib/spaces/places/registry.js +43 -0
- package/server/lib/spaces/places/registry.test.js +50 -0
- package/server/lib/spaces/places/server.docker.live.test.js +225 -0
- package/server/lib/spaces/run-command.js +261 -0
- package/server/lib/spaces/run-command.test.js +396 -0
- package/server/lib/spaces/space-server.js +190 -0
- package/server/lib/spaces/space-server.test.js +335 -0
- package/server/lib/spaces/tools-filler.js +82 -0
- package/server/lib/spaces/tools-filler.test.js +148 -0
- package/server/lib/spaces/tools-pack.js +49 -0
- package/server/lib/spaces/tools-pack.test.js +57 -0
- package/server/lib/spaces/tools.js +138 -0
- package/server/lib/spaces/tools.test.js +153 -0
- package/server/lib/tts/openai-sdk.js +11 -0
- package/server/lib/tts/service.js +7 -5
- package/server/lib/tts/stt.js +3 -2
- package/server/lib/tunnels/DOCUMENTATION.md +2 -0
- package/server/lib/tunnels/routes.js +7 -0
- package/server/lib/tunnels/routes.test.js +55 -0
- package/server/lib/ui-auth/ui-auth.js +38 -2
- package/server/lib/ui-auth/ui-auth.test.js +42 -0
- package/server/lib/ui-auth/ui-passkeys.js +12 -10
- package/server/lib/walkthrough/DOCUMENTATION.md +10 -1
- package/server/lib/walkthrough/pull-request.js +61 -8
- package/server/lib/walkthrough/pull-request.test.js +54 -1
- package/server/lib/walkthrough/routes.js +20 -0
- package/server/lib/walkthrough/routes.test.js +19 -0
- package/server/opencode-proxy.test.js +190 -166
- package/server/opencode-worktree-readiness.test.js +5 -4
- package/dist/assets/DiffView-COVQhWGd.js +0 -4
- package/dist/assets/FilesView-B1V5JxFX.js +0 -13
- package/dist/assets/LinearIssuesView-D7FKg1XJ.js +0 -1
- package/dist/assets/MarkdownImageGallery-BrFjAVEf.js +0 -1
- package/dist/assets/MarkdownRendererImpl-DWepTafh.js +0 -12
- package/dist/assets/OnboardingScreen-Dyxxiqdt.js +0 -1
- package/dist/assets/PlanView-LW2z_EAP.js +0 -5
- package/dist/assets/PluginPane-B4tKno2h.js +0 -3
- package/dist/assets/SettingsView-DEaMulN9.js +0 -29
- package/dist/assets/SettingsWindow-FLDJXOgQ.js +0 -1
- package/dist/assets/SubmoduleDiffSummary-CvVwD-Vi.js +0 -1
- package/dist/assets/ToolOutputDialog-BiP0x2Rw.js +0 -15
- package/dist/assets/ToolPartDiffPreview-CkR4msKP.js +0 -8
- package/dist/assets/appThemeRegistry-BuUKhbYQ.js +0 -1
- package/dist/assets/de-DgxgFyGG.js +0 -10
- package/dist/assets/es-BFsZj5F_.js +0 -16
- package/dist/assets/fr-jdZ5KKQi.js +0 -14
- package/dist/assets/index-CKHjPKbq.js +0 -1
- package/dist/assets/index-Cbci4i1W.js +0 -40
- package/dist/assets/index-DqaMWNrC.css +0 -1
- package/dist/assets/ja-C5kKrhO4.js +0 -16
- package/dist/assets/ko-DXDTT_0O.js +0 -16
- package/dist/assets/main-CZALtVek.js +0 -896
- package/dist/assets/main-CgXMBNvG.js +0 -2
- package/dist/assets/miniChat-CwTmDixi.js +0 -2
- package/dist/assets/mobile-CLf2vCtO.js +0 -2
- package/dist/assets/pl-D-7x4Y8Q.js +0 -16
- package/dist/assets/pt-BR-CSBZrHa8.js +0 -16
- package/dist/assets/renderElectronMiniChatApp-C5gAFBk0.js +0 -2
- package/dist/assets/renderMobileApp-V4hYd32H.js +0 -25
- package/dist/assets/runtimeEndpointReset-DhlHCn-2.js +0 -25
- package/dist/assets/scheduledTasksApi-DzjbLd8P.js +0 -1
- package/dist/assets/tr-Dr-oJ22L.js +0 -7
- package/dist/assets/uk-9Nx83UcI.js +0 -16
- package/dist/assets/useAppFontEffects-khZXpFL_.js +0 -7333
- package/dist/assets/useRootScrollLock-DdvHf9Pt.js +0 -2
- package/dist/assets/vendor-cron-parser-CUcP7OfX.js +0 -2
- package/dist/assets/vendor-opencode-sdk-BJ73u-bH.js +0 -7
- package/dist/assets/zh-CN-Bxy_Hj3r.js +0 -16
- package/dist/assets/zh-TW-0BB4gpHM.js +0 -16
- package/server/lib/opencode/mcp-oauth-callback.test.js +0 -111
- package/server/lib/routing/feature-flag.js +0 -11
- package/server/lib/small-model/call.js +0 -851
- package/server/lib/small-model/call.test.js +0 -1292
- package/server/lib/small-model/catalog.js +0 -13
- package/server/lib/small-model/resolve.js +0 -131
- package/server/lib/small-model/resolve.test.js +0 -197
- package/server/lib/small-model/runtime-providers.js +0 -164
- package/server/lib/small-model/runtime-providers.test.js +0 -118
- package/server/lib/system-prompt/DOCUMENTATION.md +0 -36
- package/server/lib/system-prompt/runtime.js +0 -49
- package/server/lib/system-prompt/runtime.test.js +0 -76
- package/server/lib/walkthrough/reproduce-2607.test.js +0 -148
|
@@ -1,229 +1,175 @@
|
|
|
1
1
|
# Small Model
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Background LLM calls for OpenChamber's own features — session titles, goal
|
|
4
|
+
distillation, session assist, the changes walkthrough. Every call goes to the
|
|
5
|
+
running OpenCode through `POST /api/experimental/generate`; OpenChamber never talks to a
|
|
6
|
+
provider directly and never handles a provider credential.
|
|
7
7
|
|
|
8
8
|
## Security boundary
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
other runtime API.
|
|
10
|
+
The client sends a prompt. This server forwards it to OpenCode, which owns the
|
|
11
|
+
credentials, the provider dispatch and the token refresh. Routes live under
|
|
12
|
+
`/api/*` and are gated by the ui-auth middleware like every other runtime API.
|
|
14
13
|
|
|
15
14
|
## Files
|
|
16
15
|
|
|
17
|
-
- `
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- `resolve.js` — model selection, mirroring OpenCode's `getSmallModel` chain:
|
|
28
|
-
0. OpenChamber's own settings override (Settings → Sessions → Small Model):
|
|
29
|
-
when `smallModelUseDefault` is `false`, `smallModelOverride`
|
|
30
|
-
(`provider/model`) outranks everything below. Sanitized in
|
|
31
|
-
`settings-helpers.js` (server), `persistence.ts` (client), and
|
|
32
|
-
`bridge-settings-runtime.ts` (VS Code).
|
|
33
|
-
1. `small_model` from the merged OpenCode config layers (`provider/model`).
|
|
34
|
-
2. Family-priority scan (`gemini-flash` → `gpt-nano` → `claude-haiku`)
|
|
35
|
-
**within the session's provider first** (`preferredProviderID`, like
|
|
36
|
-
OpenCode resolves within the current provider), then over the other
|
|
37
|
-
providers with a usable auth entry, newest `release_date` first.
|
|
38
|
-
3. GitHub Copilot hidden utility models (`gpt-*-nano/mini`) — these never
|
|
39
|
-
appear in the catalog, so they participate as the `gpt-nano` family entry
|
|
40
|
-
and as a final utility fallback.
|
|
41
|
-
4. Last resort: the session's own model (`preferredModelID`) when no small
|
|
42
|
-
model resolves anywhere — costlier, but always valid.
|
|
43
|
-
- Input clamp: the prompt is measured against the resolved model's catalog
|
|
44
|
-
`limit.context` (minus an output reserve, ~4 chars/token estimate;
|
|
45
|
-
conservative default when the model is not in the catalog). `onOverflow`
|
|
46
|
-
decides what an oversized prompt means:
|
|
47
|
-
- `truncate` (default) clips the tail and reports `inputTruncated: true`.
|
|
48
|
-
Correct for callers that degrade gracefully (summaries, commit messages).
|
|
49
|
-
- `error` throws a `413` with `code: 'context-too-small'` plus
|
|
50
|
-
`requiredChars`/`availableChars`. Correct for callers whose output would be
|
|
51
|
-
quietly wrong on a clipped input, so they can ask the user for a roomier
|
|
52
|
-
model instead of returning confident nonsense.
|
|
53
|
-
- Structured output: pass `responseSchema` (a JSON Schema) to get
|
|
54
|
-
schema-shaped JSON back as `text`. Wire support differs per format —
|
|
55
|
-
`response_format: {type: 'json_schema'}` for OpenAI-compatible chat,
|
|
56
|
-
`text.format` for the Responses API, a forced single tool call for the
|
|
57
|
-
Anthropic messages API, and `generationConfig.responseSchema` for Google
|
|
58
|
-
(whose OpenAPI-flavored dialect drops unknown JSON Schema keywords). The
|
|
59
|
-
ChatGPT-plan codex backend has no equivalent and rejects a schema request
|
|
60
|
-
with `code: 'structured-output-unsupported'` rather than silently returning
|
|
61
|
-
prose.
|
|
62
|
-
- Output budget: `maxOutputTokens` is capped at the catalog's `limit.output` for
|
|
63
|
-
the model, and the **same number** is reserved from the input allowance. The
|
|
64
|
-
two must not drift — a caller that asks for a large answer while the reserve
|
|
65
|
-
stays at the default overruns the context, and the failure looks like a
|
|
66
|
-
truncation bug rather than a budgeting one. `describeSmallModel` takes
|
|
67
|
-
`outputReserveTokens` so readiness checks agree with what generation will do.
|
|
68
|
-
It may be a **function** of `{ contextTokens, outputTokenLimit }` for callers
|
|
69
|
-
that want as much answer room as the resolved model allows — they cannot name
|
|
70
|
-
a number before knowing which model they got. The resolved value comes back as
|
|
71
|
-
`outputTokens`, which is what the caller should then request, so the reserve
|
|
72
|
-
and the request are the same number by construction.
|
|
73
|
-
- Reasoning models can spend the entire output budget thinking and return
|
|
74
|
-
nothing. That case (empty content with `finish_reason: 'length'`, or content
|
|
75
|
-
empty while `reasoning_content` is populated) throws with
|
|
76
|
-
`code: 'output-exhausted'` so callers can offer a different model instead of
|
|
77
|
-
showing a transport error.
|
|
78
|
-
- `timeoutMs` overrides the 60s default per call; `signal` lets a caller abort
|
|
79
|
-
a request that is no longer wanted. Both apply to every wire format.
|
|
80
|
-
- `describeSmallModel()` additionally reports `inputCharBudget`,
|
|
81
|
-
`contextTokens`, `contextKnown`, `structuredOutput`, and `hasLogin`. The last
|
|
82
|
-
is whether the resolved provider has a usable credential (`auth.json` or
|
|
83
|
-
config `provider.<id>.options.apiKey`) — settings/config overrides can name a
|
|
84
|
-
provider with none, and callers such as the walkthrough refuse before the
|
|
85
|
-
request. `structuredOutput` is tri-state: `true`/`false` from the catalog,
|
|
86
|
-
`null` when the catalog omits the field — which it does for roughly half of
|
|
87
|
-
all models, aggregators and proxies especially. Callers must treat `null` as
|
|
88
|
-
"try it", not "unsupported".
|
|
89
|
-
- Missing credentials throw with `statusCode: 401` and
|
|
90
|
-
`code: 'no-provider-login'` rather than a bare `Error`, so UI callers can show
|
|
91
|
-
a blocker instead of a raw 500 message.
|
|
92
|
-
- `call.js` — wire formats and per-provider auth, replicating OpenCode's
|
|
93
|
-
plugin auth loaders:
|
|
94
|
-
- OpenCode-hosted providers receive `x-opencode-session`. Session-backed
|
|
95
|
-
features reuse the real OpenCode session id, walkthrough retries reuse the
|
|
96
|
-
walkthrough cache key, and standalone one-shot actions receive a fresh
|
|
97
|
-
opaque id for that generation.
|
|
98
|
-
- **GitHub Copilot**: fetches the requested model's authenticated `/models`
|
|
99
|
-
metadata from `https://api.githubcopilot.com` (or
|
|
100
|
-
`copilot-api.<enterprise>`) and honors its advertised endpoint, preferring
|
|
101
|
-
Anthropic-compatible `/v1/messages`, then OpenAI `/responses`, then
|
|
102
|
-
`/chat/completions`. Models without `supported_endpoints` retain the legacy
|
|
103
|
-
Chat Completions default; metadata, missing-model, and unsupported-endpoint
|
|
104
|
-
failures are surfaced instead of guessing. The stored device-OAuth token is
|
|
105
|
-
used as the bearer with no token exchange or expiry.
|
|
106
|
-
- **OpenAI OAuth (ChatGPT plan)**: streaming Responses API on
|
|
107
|
-
`https://chatgpt.com/backend-api/codex/responses` with
|
|
108
|
-
`ChatGPT-Account-Id`; expired tokens are refreshed against
|
|
109
|
-
`auth.openai.com` (single-flight) and written back to `auth.json`.
|
|
110
|
-
- **Anthropic** (`type: api`): `/messages` with `x-api-key`, against
|
|
111
|
-
`provider.anthropic.options.baseURL` when configured (used as-is, matching
|
|
112
|
-
`@ai-sdk/anthropic` — no `/v1` is inserted) or `https://api.anthropic.com/v1`
|
|
113
|
-
otherwise.
|
|
114
|
-
- **Google** (`type: api`): `generateContent` with `x-goog-api-key`; Gemini 3
|
|
115
|
-
uses `thinkingLevel`, Gemini 2.x uses `thinkingBudget: 0`, and all other
|
|
116
|
-
models omit `thinkingConfig` entirely.
|
|
117
|
-
- Everything else: OpenAI-compatible `/chat/completions` against the
|
|
118
|
-
provider's base URL, resolved from (1) `provider.<id>.options.baseURL`
|
|
119
|
-
in the OpenCode config, (2) the hardcoded `https://api.openai.com/v1`
|
|
120
|
-
endpoint, (3) the selected model's endpoint OpenCode resolved at runtime,
|
|
121
|
-
(4) the provider-level runtime endpoint, (5) the provider's `api` field
|
|
122
|
-
from the models.dev catalog, or (6) `SDK_DEFAULT_BASE_URLS` — providers
|
|
123
|
-
such as Groq, xAI, and Mistral keep their endpoint inside a dedicated AI
|
|
124
|
-
SDK package, so neither the catalog nor OpenCode reports one. The
|
|
125
|
-
credential follows
|
|
126
|
-
the same shape: config `options.apiKey`, then the runtime credential, then
|
|
127
|
-
the auth.json entry. `provider.<id>.options.headers` is sent with the
|
|
128
|
-
request and overrides the bearer default, so gateways that authenticate on
|
|
129
|
-
their own header work here exactly as they do in a chat turn. Configured API
|
|
130
|
-
keys and header values honor OpenCode's `{env:NAME}` and `{file:path}`
|
|
131
|
-
substitutions; file contents and resolved credentials remain server-side.
|
|
132
|
-
- `thinking: { type: 'disabled' }` is sent in two cases, mirroring OpenCode's
|
|
133
|
-
`transform.ts`. The GLM switch belongs to the endpoint, not the model
|
|
134
|
-
family: it goes to a provider whose id contains `zai`/`zhipu` or whose
|
|
135
|
-
base URL is on `api.z.ai`/`bigmodel.cn`, because the same GLM model served
|
|
136
|
-
by another provider (OpenCode Go) rejects the unknown field with a 400.
|
|
137
|
-
The MiniMax M3 switch goes only behind the `@ai-sdk/openai-compatible` and
|
|
138
|
-
`@ai-sdk/anthropic` adapters (runtime model, then catalog model, then
|
|
139
|
-
catalog provider `npm`); a provider that reports no adapter counts as
|
|
140
|
-
OpenAI-compatible.
|
|
141
|
-
- The runtime credential is refused for providers listed in
|
|
142
|
-
`OWN_CREDENTIAL_HANDLING`. Their branches need the stored entry rather than
|
|
143
|
-
a bearer token: the clearest case is the ChatGPT-plan `openai` login, whose
|
|
144
|
-
runtime `options.apiKey` is an OAuth access token that `api.openai.com`
|
|
145
|
-
answers with 401.
|
|
146
|
-
- `[small-model:diagnostic]` logs record provider/model, input character
|
|
147
|
-
counts, output budget, thinking toggle, HTTP/finish status, and
|
|
148
|
-
content/reasoning lengths without logging prompts, response text, or
|
|
149
|
-
credentials. Goal audit parsing similarly emits
|
|
150
|
-
`[session-goal:diagnostic]` structural verdict metadata.
|
|
151
|
-
- `catalog.js` — models.dev catalog via the shared in-process cache
|
|
152
|
-
(`../opencode/models-metadata.js`, also serving
|
|
153
|
-
`/api/openchamber/models-metadata`).
|
|
16
|
+
- `client.js` — the connection to the running OpenCode. `server/index.js` wires
|
|
17
|
+
it once with `buildOpenCodeUrl` and `getOpenCodeAuthHeaders`; the client is
|
|
18
|
+
built per call because the port and the server password both change across an
|
|
19
|
+
OpenCode restart. Scoping is the `x-opencode-directory` header, URI-encoded.
|
|
20
|
+
Also caches the model list for 30 seconds — a generation needs the model's
|
|
21
|
+
context and output limits, and a round trip per session title is the wrong
|
|
22
|
+
trade. An unreachable OpenCode keeps the previous answer rather than
|
|
23
|
+
retracting it.
|
|
24
|
+
- `index.js` — `generateSmallModelText()`, `describeSmallModel()`,
|
|
25
|
+
`listAuthenticatedProviders()`.
|
|
154
26
|
- `routes.js` — `GET /api/small-model` (resolution preview) and
|
|
155
27
|
`POST /api/small-model/generate` (`{ prompt, system?, maxOutputTokens?,
|
|
156
28
|
model?, directory? }` → `{ text, providerID, modelID, source }`).
|
|
29
|
+
- `runtime-providers.js` — compatibility re-export so `server/index.js` keeps
|
|
30
|
+
resolving its import. Delete it once that import points at `client.js`.
|
|
31
|
+
|
|
32
|
+
## Free tier and the session fallback
|
|
33
|
+
|
|
34
|
+
OpenCode's free zen models are listed as enabled without a login, but
|
|
35
|
+
`/api/experimental/generate` refuses them ("free tier can only be used in OpenCode") and
|
|
36
|
+
`/api/model/default` answers nothing, so on a fresh install with no provider
|
|
37
|
+
login `generateSmallModelText` throws `404`. What happens next is per feature:
|
|
38
|
+
|
|
39
|
+
- Commit message and PR description (`packages/ui/src/lib/gitApi.ts`) fall back
|
|
40
|
+
to `POST /api/session/:id/generate`, which runs on the open session's own
|
|
41
|
+
model with the session as context and does not touch its history. Verified
|
|
42
|
+
on OpenCode 2.0.2: the reply comes back and the message count stays at zero.
|
|
43
|
+
- Session renaming, the session goal and the walkthrough do NOT fall back —
|
|
44
|
+
feeding a whole session into a model to write a title or audit a goal is the
|
|
45
|
+
wrong cost. Their entry points read `available` from `GET /api/small-model`
|
|
46
|
+
(`packages/ui/src/stores/useSmallModelStore.ts`) and show a disabled control
|
|
47
|
+
with the reason; the walkthrough uses its own readiness (`no-model`).
|
|
48
|
+
- Session assist is server-side and simply does nothing when
|
|
49
|
+
`describeSmallModel` answers null.
|
|
50
|
+
- Notes summarization and spoken summaries keep the original text and silence
|
|
51
|
+
the 404.
|
|
52
|
+
|
|
53
|
+
## Model resolution
|
|
54
|
+
|
|
55
|
+
Four things are decided here, in order:
|
|
56
|
+
|
|
57
|
+
1. An explicit `model` on the request (`provider/model`) — `source: 'request'`.
|
|
58
|
+
2. OpenChamber's settings override (Settings → Sessions → Small Model): when
|
|
59
|
+
`smallModelUseDefault` is `false`, `smallModelOverride` wins —
|
|
60
|
+
`source: 'settings'`.
|
|
61
|
+
3. The small model of the session's provider (`preferredProviderID`) —
|
|
62
|
+
`source: 'session-provider-small'` — found by `pickSmallModelInProvider`:
|
|
63
|
+
the newest enabled, active, text-in text-out model of the first family in
|
|
64
|
+
`SMALL_MODEL_FAMILY_PRIORITY` (`gpt-luna`, `gemini-flash-lite`,
|
|
65
|
+
`gemini-flash`, `claude-haiku`, then `gpt-nano`, `gpt-mini`) that the
|
|
66
|
+
provider has. The first four are OpenCode's own list for its session
|
|
67
|
+
titles (`Catalog.model.small`), repeated here because OpenCode does not
|
|
68
|
+
expose it over HTTP; the last two are v1's additions so a provider with
|
|
69
|
+
only utility models (Copilot) still gets a cheap one. Families are
|
|
70
|
+
models.dev `family` values, not model ids (`gpt-luna` is the family of
|
|
71
|
+
`gpt-5.6-luna`); a model without one — a custom provider, a subscription
|
|
72
|
+
outside the catalog — gets its family read from its id (`familyOf`:
|
|
73
|
+
luna / flash-lite / flash / haiku / nano / mini). A caller that passes `restrictToPreferredProvider`
|
|
74
|
+
(session titles, the session goal, session assist, notes from a selection)
|
|
75
|
+
and finds none then takes the session's own model — `source:
|
|
76
|
+
'session-model'`: costlier than a small model elsewhere, but never another
|
|
77
|
+
provider's subscription.
|
|
78
|
+
4. The small model of any provider OpenCode can call, same family order,
|
|
79
|
+
newest first — `source: 'small'`. Where callers without a session (commit
|
|
80
|
+
messages, spoken summaries) usually land.
|
|
81
|
+
5. Otherwise `GET /api/model/default` — `source: 'default'`. This is
|
|
82
|
+
OpenCode's default chat model, not a small one; it is the last resort.
|
|
83
|
+
|
|
84
|
+
Claude Code is refused unconditionally (`422`,
|
|
85
|
+
`code: 'small-model-provider-unsupported'`). A plugin can publish an
|
|
86
|
+
OpenAI-compatible endpoint for it, but that endpoint is a façade over the
|
|
87
|
+
Claude Agent SDK, which spawns the Claude Code CLI per request and spends the
|
|
88
|
+
user's Claude subscription rate limit. An available endpoint does not lift the
|
|
89
|
+
refusal — the cost is the reason, not the transport.
|
|
90
|
+
|
|
91
|
+
## Prompt shape
|
|
92
|
+
|
|
93
|
+
`/api/experimental/generate` takes one prompt and no system message, so `system` leads the
|
|
94
|
+
prompt, separated by a blank line.
|
|
95
|
+
|
|
96
|
+
Input clamp: the prompt is measured against the resolved model's `limit.context`
|
|
97
|
+
as OpenCode reports it, minus an output reserve, at ~4 chars/token. A model
|
|
98
|
+
OpenCode does not list gets a conservative 64k default. `onOverflow` decides
|
|
99
|
+
what an oversized prompt means:
|
|
100
|
+
|
|
101
|
+
- `truncate` (default) clips the tail and reports `inputTruncated: true`.
|
|
102
|
+
Correct for callers that degrade gracefully (summaries, commit messages).
|
|
103
|
+
- `error` throws a `413` with `code: 'context-too-small'` plus
|
|
104
|
+
`requiredChars`/`availableChars`. Correct for callers whose output would be
|
|
105
|
+
quietly wrong on a clipped input, so they can ask the user for a roomier
|
|
106
|
+
model instead of returning confident nonsense.
|
|
107
|
+
|
|
108
|
+
Output budget: `maxOutputTokens` is capped at the model's `limit.output`, and
|
|
109
|
+
the **same number** is reserved from the input allowance. `/api/experimental/generate` takes
|
|
110
|
+
no output budget of its own, so this number only shapes the reserve — but the
|
|
111
|
+
two sides must stay equal or a caller that asks for a large answer overruns the
|
|
112
|
+
context and the failure looks like a truncation bug.
|
|
113
|
+
`describeSmallModel` takes `outputReserveTokens` so readiness checks agree with
|
|
114
|
+
what generation will do. It may be a **function** of
|
|
115
|
+
`{ contextTokens, outputTokenLimit }` for callers that want as much answer room
|
|
116
|
+
as the resolved model allows — they cannot name a number before knowing which
|
|
117
|
+
model they got. The resolved value comes back as `outputTokens`.
|
|
118
|
+
|
|
119
|
+
`timeoutMs` overrides the 60s default; `signal` aborts a request that is no
|
|
120
|
+
longer wanted. The timeout covers generation, retry waits and structured-output
|
|
121
|
+
retries together.
|
|
122
|
+
|
|
123
|
+
OpenCode 2 can reject an explicit model before its cold catalog finishes loading.
|
|
124
|
+
An `InvalidRequestError` whose message exactly names the selected model as
|
|
125
|
+
`Model unavailable: provider/model` gets one retry after 500 ms, with the same
|
|
126
|
+
model and prompt. Cancellation also stops the wait. Other errors are not retried.
|
|
127
|
+
If the model remains unavailable, the route returns 503 with
|
|
128
|
+
`code: 'small-model-unavailable'` and the model-specific reason. Commit and PR
|
|
129
|
+
generation own their error toast and suppress the shared request toast.
|
|
130
|
+
|
|
131
|
+
## Structured output
|
|
132
|
+
|
|
133
|
+
`/api/experimental/generate` has no structured-output mode. `responseSchema` is therefore
|
|
134
|
+
emulated: the schema is appended to the prompt as "Reply with JSON matching this
|
|
135
|
+
schema and nothing else: …", and the reply is parsed here. A ```json fence is
|
|
136
|
+
stripped. An unparseable reply is retried **once** — a model that ignored the
|
|
137
|
+
shape often honours it on a second pass, and the alternative is failing a
|
|
138
|
+
walkthrough over a stray sentence of preamble. A second failure throws with
|
|
139
|
+
`code: 'structured-output-unsupported'` (`422`).
|
|
140
|
+
|
|
141
|
+
`describeSmallModel` reports `structuredOutput: null`, never `false`. The
|
|
142
|
+
capability is not knowable before the call, and callers must read `null` as
|
|
143
|
+
"try it".
|
|
157
144
|
|
|
158
145
|
## Which providers the pickers may offer
|
|
159
146
|
|
|
160
147
|
`listAuthenticatedProviders()` answers one question for the Small Model and
|
|
161
|
-
Changes Walkthrough pickers
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
auth.json scan as before, plus the credential and endpoint OpenCode resolved
|
|
165
|
-
for a plugin provider.
|
|
166
|
-
|
|
167
|
-
**opencode zen is excluded without a real login.** When the user has no zen
|
|
168
|
-
credential, OpenCode substitutes the sentinel `options.apiKey = "public"` and
|
|
169
|
-
trims its catalog to the free models. Those run on OpenCode's own subsidised
|
|
170
|
-
infrastructure and are meant to be reached through OpenCode, so the sentinel is
|
|
171
|
-
never accepted as a credential — see `ZEN_ANONYMOUS_API_KEY`.
|
|
172
|
-
|
|
173
|
-
### Why there is no capability probe
|
|
174
|
-
|
|
175
|
-
A plugin may implement its whole integration inside `options.fetch` —
|
|
176
|
-
rewriting the path, signing the request, translating the payload — and OpenCode
|
|
177
|
-
cannot serialise a function. Such a provider advertises an ordinary base URL
|
|
178
|
-
that answers nothing we know how to ask, and no reported field distinguishes it
|
|
179
|
-
from a plain one.
|
|
180
|
-
|
|
181
|
-
Asking the endpoint (`GET /models`) does identify that case correctly. It was
|
|
182
|
-
measured against all 166 providers carrying an `api` URL in the models.dev
|
|
183
|
-
catalog, and it also denies six of them — `cloudflare-workers-ai`,
|
|
184
|
-
`infomaniak`, `iflowcn`, `inference`, `kuae-cloud-coding-plan`,
|
|
185
|
-
`thinkingmachines` — which work fine and simply have no `/models` route. At a
|
|
186
|
-
3.6% false-negative rate on providers known to work, the probe removes more
|
|
187
|
-
working models from the picker than broken ones, and a provider that silently
|
|
188
|
-
vanishes explains nothing while one that fails on use says why.
|
|
189
|
-
|
|
190
|
-
So availability stops at credential and endpoint, and the protocol verdict is
|
|
191
|
-
left to the call. A provider whose protocol lives in a plugin's `fetch` stays
|
|
192
|
-
selectable and fails when used — which is what it did before this resolution
|
|
193
|
-
existed.
|
|
194
|
-
|
|
195
|
-
Claude Code is refused unconditionally. A plugin can publish an
|
|
196
|
-
OpenAI-compatible endpoint for it, but that endpoint is a façade over the
|
|
197
|
-
Claude Agent SDK, which spawns the Claude Code CLI per request and spends the
|
|
198
|
-
user's Claude subscription rate limit. Paying that for a session title or a
|
|
199
|
-
summary is the wrong trade, so an available endpoint does not lift the
|
|
200
|
-
refusal — the cost is the reason, not the transport.
|
|
148
|
+
Changes Walkthrough pickers: which providers OpenCode can call right now. A
|
|
149
|
+
provider counts when it has at least one enabled model in `GET /api/model` —
|
|
150
|
+
the same test OpenCode applies before letting a chat turn use it.
|
|
201
151
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
is
|
|
152
|
+
`GET /api/provider` only contributes names. It comes back empty on setups where
|
|
153
|
+
models are perfectly usable, so an empty provider list is never read as "no
|
|
154
|
+
providers". Claude Code is removed from the result for the reason above.
|
|
155
|
+
|
|
156
|
+
The field is served as `authenticatedProviders` on `GET /api/small-model`. The
|
|
157
|
+
name predates this resolution; it now means "callable".
|
|
158
|
+
|
|
159
|
+
## describeSmallModel
|
|
160
|
+
|
|
161
|
+
Reports which model would be used without calling it: `providerID`, `modelID`,
|
|
162
|
+
`source`, plus `inputCharBudget`, `contextTokens`, `contextKnown`,
|
|
163
|
+
`outputTokens`, `outputTokenLimit`, `structuredOutput` and `hasLogin`.
|
|
164
|
+
|
|
165
|
+
`hasLogin` is `false` when OpenCode lists the model as disabled — a settings
|
|
166
|
+
override can name a model there is no credential for, and the walkthrough
|
|
167
|
+
refuses before the user pays for a failed request. A model OpenCode does not
|
|
168
|
+
list at all is not evidence either way, so it counts as usable.
|
|
169
|
+
|
|
170
|
+
Returns `null` when OpenCode is not reachable.
|
|
205
171
|
|
|
206
172
|
## Registration
|
|
207
173
|
|
|
208
174
|
Mounted lazily from `feature-routes-runtime.js` (same pattern as quota): the
|
|
209
175
|
module is imported on first request, not at server startup.
|
|
210
|
-
|
|
211
|
-
## Known limitations
|
|
212
|
-
|
|
213
|
-
- OpenCode's free models (`opencode/big-pickle`, `*-free`) work without a
|
|
214
|
-
token only through OpenCode's own server — direct calls are rejected, and
|
|
215
|
-
piggybacking on their subsidized infra is out of bounds by design. Every
|
|
216
|
-
resolution step therefore requires a credential we are allowed to use:
|
|
217
|
-
a session on an unauthenticated `opencode` provider falls through to the
|
|
218
|
-
global scan (or a clean 404 on a vanilla setup with no logins). The runtime
|
|
219
|
-
snapshot does not weaken this — OpenCode reports the sentinel
|
|
220
|
-
`apiKey: "public"` for that state, and this module refuses to read it as a
|
|
221
|
-
credential.
|
|
222
|
-
|
|
223
|
-
- Anthropic OAuth (Claude Pro/Max) entries are not supported — OpenCode itself
|
|
224
|
-
keeps those outside `auth.json` in this generation; only `type: api` keys
|
|
225
|
-
work for Anthropic.
|
|
226
|
-
- Amazon Bedrock, GitLab, Azure and other credential-chain providers are out
|
|
227
|
-
of scope; they need more than a key/token (regions, resource names).
|
|
228
|
-
- Responses from the codex backend are collected from the SSE stream; the
|
|
229
|
-
endpoint itself is non-streaming by design (small utility calls).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { OpenCode } from '@opencode/client';
|
|
2
|
+
|
|
3
|
+
// The running OpenCode instance is the only transport this module has. It is
|
|
4
|
+
// wired once from `server/index.js`, and re-read on every call because the
|
|
5
|
+
// port and the server password both move across an OpenCode restart.
|
|
6
|
+
let connection = null;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Wires this module to the running OpenCode instance. Pass `null` to detach.
|
|
10
|
+
* Until it is wired, every lookup answers "no client", which the callers
|
|
11
|
+
* report as "no small model available" rather than guessing.
|
|
12
|
+
*/
|
|
13
|
+
export function configureOpenCodeRuntimeProviders(next) {
|
|
14
|
+
connection = next ?? null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Drops anything cached about the running instance. An OpenCode restart can
|
|
19
|
+
* change the port, the password and the model list.
|
|
20
|
+
*/
|
|
21
|
+
export function resetOpenCodeRuntimeProviders() {
|
|
22
|
+
modelCache = null;
|
|
23
|
+
modelCacheKey = '';
|
|
24
|
+
modelCacheAt = 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const stripTrailingSlash = (value) => value.replace(/\/+$/, '');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A `@opencode/client` bound to the running instance and scoped to
|
|
31
|
+
* `directory`, or `null` when OpenCode is not reachable yet.
|
|
32
|
+
*
|
|
33
|
+
* Built per call on purpose: `OpenCode.make` only closes over a base URL and
|
|
34
|
+
* headers, and both change when OpenCode restarts.
|
|
35
|
+
*/
|
|
36
|
+
export function getSmallModelClient(directory) {
|
|
37
|
+
if (!connection) return null;
|
|
38
|
+
let baseUrl;
|
|
39
|
+
try {
|
|
40
|
+
baseUrl = stripTrailingSlash(connection.buildOpenCodeUrl('', ''));
|
|
41
|
+
} catch {
|
|
42
|
+
// The port is not known yet — OpenCode has not finished starting.
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const headers = { ...connection.getOpenCodeAuthHeaders() };
|
|
46
|
+
if (typeof directory === 'string' && directory.trim()) {
|
|
47
|
+
headers['x-opencode-directory'] = encodeURIComponent(directory.trim());
|
|
48
|
+
}
|
|
49
|
+
return OpenCode.make({ baseUrl, headers });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const MODEL_CACHE_TTL_MS = 30_000;
|
|
53
|
+
let modelCache = null;
|
|
54
|
+
let modelCacheKey = '';
|
|
55
|
+
let modelCacheAt = 0;
|
|
56
|
+
|
|
57
|
+
const unwrap = (payload) => (Array.isArray(payload?.data) ? payload.data : []);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Every model the running OpenCode knows about for `directory`.
|
|
61
|
+
*
|
|
62
|
+
* Cached briefly: a generation needs the model's context and output limits,
|
|
63
|
+
* and paying a round trip for them on every title or summary would be the
|
|
64
|
+
* wrong trade. An empty array means "asked and got nothing", so callers fall
|
|
65
|
+
* back to conservative defaults rather than refusing.
|
|
66
|
+
*/
|
|
67
|
+
export async function listModelInfos(client, directory) {
|
|
68
|
+
const key = typeof directory === 'string' ? directory : '';
|
|
69
|
+
if (modelCache && modelCacheKey === key && Date.now() - modelCacheAt < MODEL_CACHE_TTL_MS) {
|
|
70
|
+
return modelCache;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const models = unwrap(await client.model.list());
|
|
74
|
+
modelCache = models;
|
|
75
|
+
modelCacheKey = key;
|
|
76
|
+
modelCacheAt = Date.now();
|
|
77
|
+
return models;
|
|
78
|
+
} catch {
|
|
79
|
+
// Keep the previous answer for this directory when there is one: a
|
|
80
|
+
// momentarily unreachable OpenCode must not retract model limits.
|
|
81
|
+
return modelCacheKey === key && modelCache ? modelCache : [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function listProviderInfos(client) {
|
|
86
|
+
try {
|
|
87
|
+
return unwrap(await client.provider.list());
|
|
88
|
+
} catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The model OpenCode would pick on its own, or `null` when it cannot say.
|
|
95
|
+
*/
|
|
96
|
+
export async function getDefaultModelInfo(client) {
|
|
97
|
+
try {
|
|
98
|
+
const payload = await client.model.default();
|
|
99
|
+
const info = payload?.data ?? payload;
|
|
100
|
+
return info && typeof info === 'object' && typeof info.id === 'string' ? info : null;
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The model entry for a `provider/model` reference. `modelID` and `id` are
|
|
108
|
+
* both accepted because OpenCode reports the same model under both.
|
|
109
|
+
*/
|
|
110
|
+
export function findModelInfo(models, providerID, modelID) {
|
|
111
|
+
return models.find((model) => model?.providerID === providerID
|
|
112
|
+
&& (model.id === modelID || model.modelID === modelID)) ?? null;
|
|
113
|
+
}
|