@openchambery/web 2.0.0-beta.1 → 2.0.0-beta.4
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 +15 -11
- package/bin/cli-opencode.test.js +4 -4
- package/bin/cli.js +1 -1
- package/bin/lib/cli-startup.js +1 -1
- package/bin/lib/cli-startup.test.js +18 -4
- package/dist/assets/{AgentAvatar-CLWWNu_Q.js → AgentAvatar-Q1SmFRx2.js} +1 -1
- package/dist/assets/AssistantView-CwXkiCAd.js +3 -0
- package/dist/assets/{DiagramView-xuSJTnv7.js → DiagramView-BW92schO.js} +1 -1
- package/dist/assets/{FadeInOnReveal-Ov0D96d0.js → FadeInOnReveal-BZmwl-zE.js} +1 -1
- package/dist/assets/{Icon-DD-BuMfZ.js → Icon-AQPvxMiU.js} +1 -1
- package/dist/assets/{MarkdownRenderer-bc_p1H7l.js → MarkdownRenderer-Bv05iDZZ.js} +2 -2
- package/dist/assets/{MarkdownRendererImpl-SKi4oG0c.js → MarkdownRendererImpl-C81xqYib.js} +3 -3
- package/dist/assets/MarkstreamRendererImpl-CXUCQuKJ.js +3 -0
- package/dist/assets/{MobileDetailNavigation-Bnx59U_J.js → MobileDetailNavigation-BMgIu7zc.js} +1 -1
- package/dist/assets/{MobileShareBridge-BQlP4J-F.js → MobileShareBridge-BOXGNHmC.js} +2 -2
- package/dist/assets/MobileSurface-xuc_z0_G.js +2 -0
- package/dist/assets/{MultiRunWindow-ChZGob0v.js → MultiRunWindow-B5At2Z95.js} +1 -1
- package/dist/assets/{OnboardingScreen-DtQJxZG-.js → OnboardingScreen-bsPLgz4r.js} +1 -1
- package/dist/assets/OverlayScrollbar-4wp4migh.js +2 -0
- package/dist/assets/SettingsView-CJ6tcH5_.js +25 -0
- package/dist/assets/{SettingsWindow-DfnsFa8y.js → SettingsWindow-CMtX2bMl.js} +1 -1
- package/dist/assets/{TerminalView-Dh9MWCpS.js → TerminalView-Dvr-ysTS.js} +1 -1
- package/dist/assets/{ToolOutputDialog-BejmjrRk.js → ToolOutputDialog-uH1ZZDSS.js} +2 -2
- package/dist/assets/appThemeRegistry-DK7q2juD.js +1 -0
- package/dist/assets/{assistant-attachment-cache-C0aRnFkj.js → assistant-attachment-cache-DphJleHr.js} +1 -1
- package/dist/assets/{button-D-rATN7w.js → button-CcNJUxUd.js} +1 -1
- package/dist/assets/collapsible-ZmZ6rLWs.js +3 -0
- package/dist/assets/context-menu-B2LXJgXL.js +1 -0
- package/dist/assets/{desktopHosts-B1ixEylr.js → desktopHosts-C6HrP0jq.js} +1 -1
- package/dist/assets/{desktopRelayRestore-4JmFUw8r.js → desktopRelayRestore-DdVBp45U.js} +1 -1
- package/dist/assets/{diagram-DQf7Y_uR.js → diagram-CxTs9hCQ.js} +1 -1
- package/dist/assets/{dialog-bfbvR4VH.js → dialog-KMVL9QKF.js} +1 -1
- package/dist/assets/es-CN3E_zXj.js +15 -0
- package/dist/assets/{fileMentionTouchSelection-BvrNCroG.js → fileMentionTouchSelection-7RIwlpkB.js} +1 -1
- package/dist/assets/{fileQueries-DQc8EJUf.js → fileQueries-CjdBRy8y.js} +1 -1
- package/dist/assets/fr-9zZvQZD2.js +13 -0
- package/dist/assets/gitApi-yuWg9BN4.js +10 -0
- package/dist/assets/{imageSource-BlAJJUEI.js → imageSource-9vQBq3zp.js} +1 -1
- package/dist/assets/{input-8r6F_Fza.js → input-CrIvk3HZ.js} +1 -1
- package/dist/assets/insertionBoundaries-BiUCSkx-.js +1 -0
- package/dist/assets/ja-Dnjk_82N.js +15 -0
- package/dist/assets/ko-BxCEE99C.js +15 -0
- package/dist/assets/{main-CCE_4y5F.js → main-C9mIBo77.js} +2 -2
- package/dist/assets/main-DiL6w6KF.js +169 -0
- package/dist/assets/markdown-worker-bS5OgGO3.js +2 -0
- package/dist/assets/{markdownHeightCache-1Qo6y6IJ.js → markdownHeightCache-BmXVY_gc.js} +1 -1
- package/dist/assets/{markdownTheme-DOfGg-A7.js → markdownTheme-CKac3wKC.js} +1 -1
- package/dist/assets/mcpQueries-C7jknHV8.js +1 -0
- package/dist/assets/miniChat-CwtUaElU.js +2 -0
- package/dist/assets/mobile-DB-6--ws.js +2 -0
- package/dist/assets/multirun-TAsxFI8e.js +4 -0
- package/dist/assets/{persistence-Ce3AnpEr.js → persistence-56kq8Z4V.js} +2 -2
- package/dist/assets/pl-CNNsWnPM.js +15 -0
- package/dist/assets/platform-C13fMVEs.js +6 -0
- package/dist/assets/pt-BR-BZB2DJMp.js +15 -0
- package/dist/assets/{relay-image-stream-DM7atqJs.js → relay-image-stream-DrdVj99c.js} +1 -1
- package/dist/assets/renderElectronMiniChatApp-CGj0MNRU.js +2 -0
- package/dist/assets/renderMobileApp-CGMMqbsO.js +28 -0
- package/dist/assets/runtime-fetch-Fs9ZV2V8.js +1 -0
- package/dist/assets/{runtimeConfig-BMvqa5we.js → runtimeConfig-BEANkvOd.js} +1 -1
- package/dist/assets/runtimeEndpointReset-A_ZBUJFS.js +147 -0
- package/dist/assets/sessionChangeSummary-qOLrP9fw.js +2 -0
- package/dist/assets/{sessionLookup-gh-hVRIc.js → sessionLookup-34XFmP9C.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-CudoSgV4.js → sortable-tabs-strip-DyEV0Heg.js} +1 -1
- package/dist/assets/src-ubCWXZhR.css +2 -0
- package/dist/assets/store-DLCiZaA6.js +15 -0
- package/dist/assets/{terminalApi-DiF6JmBP.js → terminalApi-CXaBEoa_.js} +1 -1
- package/dist/assets/textarea-BBOlRI9O.js +1 -0
- package/dist/assets/{tooltip-CQvpK-UV.js → tooltip-CPI4fr1a.js} +1 -1
- package/dist/assets/uk-rwQrxeYM.js +15 -0
- package/dist/assets/{url-_z7evzdK.js → url-DRDQXjyX.js} +1 -1
- package/dist/assets/{useAppFontEffects-Cpmpo7Wb.js → useAppFontEffects-CiDe42I5.js} +57 -43
- package/dist/assets/{useAssistantUIStore-CMutVh9B.js → useAssistantUIStore-asNG6K7n.js} +1 -1
- package/dist/assets/useDesktopWindowControlsLayout-BlizAlOt.js +1 -0
- package/dist/assets/useEffectiveDirectory-C_CouL5v.js +1 -0
- package/dist/assets/{useFontPreferences-DcbXQOkc.js → useFontPreferences-B0oUZAiB.js} +1 -1
- package/dist/assets/useMobileNavigationStore-DfPClaW-.js +414 -0
- package/dist/assets/{useRuntimeAPIs-DSLXJybW.js → useRuntimeAPIs-DwLtO0c_.js} +1 -1
- package/dist/assets/useSessionAutoCleanup-DtrfbxAp.js +2 -0
- package/dist/assets/{useThemeSystem-DMzWVJaW.js → useThemeSystem-BlNUWH47.js} +1 -1
- package/dist/assets/useUIStore-CQYKJnrg.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-Bqn4AiBL.js → useWorkerHighlightedLines-CPNYz6Wf.js} +2 -2
- package/dist/assets/{vendor-base-ui-CnHfUmDN.js → vendor-base-ui-CDjyofeD.js} +1 -1
- package/dist/assets/{vendor-cmdk-CeAGfrLo.js → vendor-cmdk-BFH0UpXX.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-accessibility-BY5LhhUB.js → vendor-dnd-kit-accessibility-BrR3AKvM.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-core-CvWxUPdb.js → vendor-dnd-kit-core-CNfdvk6H.js} +1 -1
- package/dist/assets/{vendor-dnd-kit-sortable-hHdP9lLb.js → vendor-dnd-kit-sortable-DQUaTeGj.js} +1 -1
- package/dist/assets/{vendor-framer-motion-DFy_BSVd.js → vendor-framer-motion-4dogsUk3.js} +1 -1
- package/dist/assets/{vendor-legendapp-list-WE32lwNk.js → vendor-legendapp-list-BU7MdPZR.js} +1 -1
- package/dist/assets/{vendor-markstream-react-DX55XLGO.js → vendor-markstream-react-qHC2FykU.js} +3 -3
- package/dist/assets/{vendor-pierre-diffs-DX7XTPG3.js → vendor-pierre-diffs-CUfqC003.js} +1 -1
- package/dist/assets/{vendor-react-DLPElpoQ.js → vendor-react-C94A0AHl.js} +1 -1
- package/dist/assets/{vendor-react-drawio-ECtEwvbc.js → vendor-react-drawio-FVlWqKVE.js} +1 -1
- package/dist/assets/{vendor-reactuses-core-BnW6GxJt.js → vendor-reactuses-core-C2A3EjUi.js} +1 -1
- package/dist/assets/{vendor-sonner-DVzioF3d.js → vendor-sonner-DNqHmUQs.js} +1 -1
- package/dist/assets/{vendor-stream-diffs-DWy3xSmp.js → vendor-stream-diffs-CwbKsmlv.js} +2 -2
- package/dist/assets/{vendor-tanstack-react-query-D7pys_c9.js → vendor-tanstack-react-query-D0iFK57C.js} +1 -1
- package/dist/assets/{vendor-tanstack-react-virtual-tlDgH6PG.js → vendor-tanstack-react-virtual-B2kV6cnT.js} +1 -1
- package/dist/assets/{vendor-zustand-B4dlGEM2.js → vendor-zustand-BqLKf6ZY.js} +1 -1
- package/dist/assets/zh-CN-BvmBDnkD.js +15 -0
- package/dist/assets/zh-TW-9wcHTX0y.js +15 -0
- package/dist/index.html +13 -13
- package/dist/mini-chat.html +13 -13
- package/dist/mobile.html +13 -13
- package/package.json +1 -1
- package/server/index.js +327 -62
- package/server/lib/assistants/DOCUMENTATION.md +14 -9
- package/server/lib/assistants/contracts.js +11 -1
- package/server/lib/assistants/projection-history.test.js +265 -18
- package/server/lib/assistants/routes.js +6 -0
- package/server/lib/assistants/service.js +417 -231
- package/server/lib/assistants/service.test.js +392 -148
- package/server/lib/conversations/DOCUMENTATION.md +1 -1
- package/server/lib/conversations/service.js +1 -0
- package/server/lib/conversations/service.test.js +16 -0
- package/server/lib/conversations/validation.js +11 -1
- package/server/lib/event-stream/DOCUMENTATION.md +3 -1
- package/server/lib/event-stream/directory-ws-bridge.js +13 -2
- package/server/lib/event-stream/global-hub.js +49 -4
- package/server/lib/event-stream/reasoning-projection.js +16 -1
- package/server/lib/event-stream/reasoning-projection.test.js +15 -0
- package/server/lib/event-stream/runtime.js +57 -20
- package/server/lib/event-stream/runtime.test.js +112 -0
- package/server/lib/llm/DOCUMENTATION.md +33 -9
- package/server/lib/llm/catalog.js +1 -1
- package/server/lib/llm/completions.js +5 -1
- package/server/lib/llm/completions.test.js +3 -3
- package/server/lib/llm/generate.js +237 -145
- package/server/lib/llm/generate.test.js +201 -46
- package/server/lib/llm/routes.js +2 -0
- package/server/lib/message-queue/runtime.js +15 -2
- package/server/lib/notifications/runtime.js +23 -5
- package/server/lib/notifications/runtime.test.js +11 -0
- package/server/lib/opencode/DOCUMENTATION.md +85 -17
- package/server/lib/opencode/agent-document.d.ts +28 -0
- package/server/lib/opencode/agent-document.js +280 -0
- package/server/lib/opencode/agent-document.test.js +137 -0
- package/server/lib/opencode/agents.js +96 -0
- package/server/lib/opencode/auth-state-runtime.js +5 -0
- package/server/lib/opencode/bootstrap-runtime.js +2 -0
- package/server/lib/opencode/config-entity-routes.js +42 -99
- package/server/lib/opencode/config-entity-routes.test.js +107 -0
- package/server/lib/opencode/config-hot-reload.integration.test.js +105 -0
- package/server/lib/opencode/ensure-cli.js +1 -2
- package/server/lib/opencode/env-runtime.js +40 -26
- package/server/lib/opencode/env-runtime.test.js +10 -17
- package/server/lib/opencode/feature-routes-runtime.js +43 -4
- package/server/lib/opencode/feature-routes-runtime.test.js +18 -0
- package/server/lib/opencode/http-server-connections.js +98 -0
- package/server/lib/opencode/http-server-connections.test.js +321 -0
- package/server/lib/opencode/lifecycle.js +349 -39
- package/server/lib/opencode/lifecycle.test.js +322 -0
- package/server/lib/opencode/managed-capabilities-runtime.js +15 -2
- package/server/lib/opencode/managed-capabilities-runtime.test.js +1 -0
- package/server/lib/opencode/openchamber-routes.js +7 -1
- package/server/lib/opencode/opencode2-pin.js +4 -4
- package/server/lib/opencode/opencode2-pin.test.js +1 -0
- package/server/lib/opencode/opencode2-sidecar.e2e.test.js +127 -4
- package/server/lib/opencode/owned-runtime-upgrade.js +431 -0
- package/server/lib/opencode/owned-runtime-upgrade.test.js +160 -0
- package/server/lib/opencode/plugin-routes.js +3 -18
- package/server/lib/opencode/plugin-routes.test.js +9 -9
- package/server/lib/opencode/provider-catalog.js +58 -12
- package/server/lib/opencode/provider-catalog.test.js +48 -0
- package/server/lib/opencode/proxy.js +252 -46
- package/server/lib/opencode/proxy.test.js +235 -2
- package/server/lib/opencode/routes.js +296 -62
- package/server/lib/opencode/routes.test.js +278 -12
- package/server/lib/opencode/runtime-contract.js +401 -0
- package/server/lib/opencode/runtime-contract.test.js +214 -0
- package/server/lib/opencode/server-opencode-fetch.js +242 -0
- package/server/lib/opencode/server-opencode-fetch.test.js +130 -0
- package/server/lib/opencode/server-utils-runtime.js +33 -0
- package/server/lib/opencode/shared-service.integration.test.js +66 -0
- package/server/lib/opencode/shared-service.js +147 -0
- package/server/lib/opencode/shared-service.test.js +93 -0
- package/server/lib/opencode/shared.js +3 -3
- package/server/lib/opencode/shutdown-runtime.js +15 -6
- package/server/lib/opencode/shutdown-runtime.test.js +49 -1
- package/server/lib/opencode/skill-routes.js +20 -33
- package/server/lib/opencode/skill-routes.test.js +35 -2
- package/server/lib/opencode/skills.test.js +15 -0
- package/server/lib/opencode/startup-pipeline-runtime.js +4 -0
- package/server/lib/opencode/static-routes-runtime.js +3 -1
- package/server/lib/opencode/static-routes-runtime.test.js +33 -0
- package/server/lib/opencode/v2-client.js +14 -3
- package/server/lib/opencode/v2-plugin-host-shim/index.mjs +155 -0
- package/server/lib/opencode/v2-plugin-host-shim/package.json +4 -0
- package/server/lib/permission-auto-accept/DOCUMENTATION.md +5 -5
- package/server/lib/permission-auto-accept/runtime.js +14 -7
- package/server/lib/permission-auto-accept/runtime.test.js +27 -12
- package/server/lib/relay/reasoning-projection.e2e.test.ts +22 -7
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +8 -0
- package/server/lib/scheduled-tasks/runtime.js +52 -4
- package/server/lib/scheduled-tasks/runtime.test.js +80 -1
- package/server/lib/session-goal/DOCUMENTATION.md +113 -13
- package/server/lib/session-goal/routes.js +9 -0
- package/server/lib/session-goal/runtime.js +1579 -117
- package/server/lib/session-goal/runtime.test.js +1453 -84
- package/server/lib/session-index/DOCUMENTATION.md +18 -15
- package/server/lib/session-index/event-ingest.js +89 -16
- package/server/lib/session-index/event-ingest.test.js +73 -0
- package/server/lib/session-index/host-authority-snapshot.js +92 -0
- package/server/lib/session-index/routes.host-archive.test.js +201 -0
- package/server/lib/session-index/routes.js +63 -10
- package/server/lib/session-index/routes.test.js +8 -8
- package/server/lib/session-index/service.js +7 -1
- package/server/lib/session-index/sync-runtime.js +161 -34
- package/server/lib/session-index/sync-runtime.test.js +155 -1
- package/server/lib/session-metadata/DOCUMENTATION.md +61 -16
- package/server/lib/session-metadata/routes.js +108 -9
- package/server/lib/session-metadata/routes.test.js +47 -2
- package/server/lib/session-metadata/session-archive.d.ts +73 -0
- package/server/lib/session-metadata/session-archive.js +654 -0
- package/server/lib/session-metadata/session-archive.test.js +359 -0
- package/server/lib/session-metadata/session-metadata-store.d.ts +36 -0
- package/server/lib/session-metadata/session-metadata-store.js +212 -72
- package/server/lib/session-metadata/session-metadata-store.test.js +205 -10
- package/server/lib/session-metadata/session-projection.d.ts +41 -0
- package/server/lib/session-metadata/session-projection.js +255 -0
- package/server/lib/session-metadata/session-projection.test.js +64 -0
- package/server/lib/session-metadata/system-session.js +55 -0
- package/server/lib/session-metadata/system-session.test.js +55 -0
- package/server/lib/session-title/DOCUMENTATION.md +40 -7
- package/server/lib/session-title/native-runtime.test.js +167 -0
- package/server/lib/session-title/runtime.js +67 -42
- package/server/lib/session-title/session-access.js +46 -0
- package/server/lib/session-title/session-access.test.js +91 -0
- package/server/lib/session-turn-pages/DOCUMENTATION.md +9 -8
- package/server/lib/session-turn-pages/routes.js +17 -102
- package/server/lib/session-turn-pages/routes.test.js +281 -0
- package/server/lib/session-turn-pages/session-message-projection.d.ts +13 -0
- package/server/lib/session-turn-pages/session-message-projection.js +281 -0
- package/server/lib/small-model/DOCUMENTATION.md +101 -147
- package/server/lib/small-model/catalog.js +31 -51
- package/server/lib/small-model/catalog.test.js +65 -10
- package/server/lib/small-model/custom-api.js +68 -0
- package/server/lib/small-model/custom-api.test.js +64 -0
- package/server/lib/small-model/index.js +124 -240
- package/server/lib/small-model/resolve.js +35 -120
- package/server/lib/small-model/resolve.test.js +20 -110
- package/server/lib/small-model/routes.js +1 -3
- package/server/lib/small-model/summary-settings.test.js +157 -253
- package/server/opencode-proxy.test.js +2 -0
- package/dist/assets/AssistantView-BTCkm8yk.js +0 -3
- package/dist/assets/MarkstreamRendererImpl-CnkodGJW.js +0 -3
- package/dist/assets/MobileSurface-BXLeiZ4d.js +0 -2
- package/dist/assets/OverlayScrollbar-pMwxaCca.js +0 -2
- package/dist/assets/SettingsView-B5I0KDTZ.js +0 -25
- package/dist/assets/appThemeRegistry-COGfxTFV.js +0 -1
- package/dist/assets/collapsible-BXRd5_Hr.js +0 -1
- package/dist/assets/context-menu-jGtH6fR9.js +0 -1
- package/dist/assets/es-c52LTHHe.js +0 -15
- package/dist/assets/fr-PisFbUE8.js +0 -13
- package/dist/assets/gitApi-ButwzQ0N.js +0 -9
- package/dist/assets/insertionBoundaries-DGs7S5zv.js +0 -1
- package/dist/assets/ja-C8Ikun3Z.js +0 -15
- package/dist/assets/ko-ClFys5o2.js +0 -15
- package/dist/assets/main-Dn9rpsgl.js +0 -169
- package/dist/assets/markdown-worker-CptoICmq.js +0 -2
- package/dist/assets/miniChat-BpjxVqgg.js +0 -2
- package/dist/assets/mobile-nMJCaNq1.js +0 -2
- package/dist/assets/multirun-BvSG94mW.js +0 -4
- package/dist/assets/pl-CnaKWN5F.js +0 -15
- package/dist/assets/platform-CWTIp02q.js +0 -4
- package/dist/assets/projectMeta-DOe49dM_.js +0 -3
- package/dist/assets/pt-BR-s8OpfRI6.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-R6dKh79f.js +0 -2
- package/dist/assets/renderMobileApp-y-S8y8v_.js +0 -28
- package/dist/assets/runtime-fetch-zIalUnbb.js +0 -1
- package/dist/assets/runtimeEndpointReset-B6BxhvR0.js +0 -147
- package/dist/assets/sessionChangeSummary-VVBlEXuh.js +0 -2
- package/dist/assets/src-BzX5UI-c.css +0 -2
- package/dist/assets/store-DJczmczv.js +0 -15
- package/dist/assets/textarea-3XR8sUfy.js +0 -1
- package/dist/assets/uk-CaX0iqkB.js +0 -15
- package/dist/assets/useDesktopWindowControlsLayout-B1GX59-L.js +0 -1
- package/dist/assets/useEffectiveDirectory-CN6JoCFw.js +0 -1
- package/dist/assets/useMobileNavigationStore-BVjFtXSy.js +0 -414
- package/dist/assets/useSessionAutoCleanup-BLjymaFt.js +0 -2
- package/dist/assets/useUIStore-Bxv3f23A.js +0 -1
- package/dist/assets/zh-CN-20MYEjha.js +0 -15
- package/dist/assets/zh-TW-DiN04qTw.js +0 -15
- package/server/lib/small-model/call.js +0 -427
- package/server/lib/small-model/call.test.js +0 -382
- package/server/lib/small-model/opencode-session.js +0 -183
- package/server/lib/small-model/opencode-session.test.js +0 -147
|
@@ -1,427 +0,0 @@
|
|
|
1
|
-
import { readAuthFile, writeAuthFile } from '../opencode/auth.js';
|
|
2
|
-
import { readConfig } from '../opencode/shared.js';
|
|
3
|
-
import { getCatalogProvider } from './catalog.js';
|
|
4
|
-
import { getAuthEntryForProvider } from './resolve.js';
|
|
5
|
-
|
|
6
|
-
// Direct, non-streaming text generation against the provider APIs, replicating
|
|
7
|
-
// how OpenCode authenticates each of them (see the plugin auth loaders in the
|
|
8
|
-
// opencode repo). auth.json credentials never leave this process.
|
|
9
|
-
|
|
10
|
-
const REQUEST_TIMEOUT_MS = 60_000;
|
|
11
|
-
// Generous default: thinking models that can't be switched off (DeepSeek,
|
|
12
|
-
// Qwen, …) spend part of this budget on reasoning before the actual answer.
|
|
13
|
-
const DEFAULT_MAX_OUTPUT_TOKENS = 4_000;
|
|
14
|
-
|
|
15
|
-
const USER_AGENT = 'opencode/1.0 openchamber';
|
|
16
|
-
|
|
17
|
-
const CODEX_TOKEN_URL = 'https://auth.openai.com/oauth/token';
|
|
18
|
-
const CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
|
|
19
|
-
const CODEX_RESPONSES_URL = 'https://chatgpt.com/backend-api/codex/responses';
|
|
20
|
-
|
|
21
|
-
const httpError = async (response, provider) => {
|
|
22
|
-
const body = await response.text().catch(() => '');
|
|
23
|
-
const snippet = body ? `: ${body.slice(0, 300)}` : '';
|
|
24
|
-
return new Error(`${provider} request failed with ${response.status}${snippet}`);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// ---------------------------------------------------------------------------
|
|
28
|
-
// OpenAI OAuth (ChatGPT plan / codex) token refresh — single-flight, with the
|
|
29
|
-
// refreshed token written back to auth.json exactly like OpenCode does.
|
|
30
|
-
// ---------------------------------------------------------------------------
|
|
31
|
-
|
|
32
|
-
let openaiRefreshPromise = null;
|
|
33
|
-
|
|
34
|
-
const decodeJwtClaims = (token) => {
|
|
35
|
-
try {
|
|
36
|
-
const payload = token.split('.')[1];
|
|
37
|
-
return JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
|
|
38
|
-
} catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const extractChatgptAccountId = (accessToken) => {
|
|
44
|
-
const claims = decodeJwtClaims(accessToken);
|
|
45
|
-
const auth = claims?.['https://api.openai.com/auth'];
|
|
46
|
-
const value = auth?.chatgpt_account_id;
|
|
47
|
-
return typeof value === 'string' && value ? value : null;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const refreshOpenaiOauth = async (entry) => {
|
|
51
|
-
if (!openaiRefreshPromise) {
|
|
52
|
-
openaiRefreshPromise = (async () => {
|
|
53
|
-
const response = await fetch(CODEX_TOKEN_URL, {
|
|
54
|
-
method: 'POST',
|
|
55
|
-
headers: { 'Content-Type': 'application/json' },
|
|
56
|
-
body: JSON.stringify({
|
|
57
|
-
grant_type: 'refresh_token',
|
|
58
|
-
refresh_token: entry.refresh,
|
|
59
|
-
client_id: CODEX_CLIENT_ID,
|
|
60
|
-
}),
|
|
61
|
-
signal: AbortSignal.timeout(30_000),
|
|
62
|
-
});
|
|
63
|
-
if (!response.ok) {
|
|
64
|
-
throw await httpError(response, 'OpenAI token refresh');
|
|
65
|
-
}
|
|
66
|
-
const payload = await response.json();
|
|
67
|
-
const access = typeof payload?.access_token === 'string' ? payload.access_token : '';
|
|
68
|
-
if (!access) {
|
|
69
|
-
throw new Error('OpenAI token refresh returned no access token');
|
|
70
|
-
}
|
|
71
|
-
const refreshed = {
|
|
72
|
-
...entry,
|
|
73
|
-
type: 'oauth',
|
|
74
|
-
access,
|
|
75
|
-
refresh: typeof payload?.refresh_token === 'string' && payload.refresh_token
|
|
76
|
-
? payload.refresh_token
|
|
77
|
-
: entry.refresh,
|
|
78
|
-
expires: Date.now() + (Number(payload?.expires_in) > 0 ? Number(payload.expires_in) : 3600) * 1000,
|
|
79
|
-
};
|
|
80
|
-
const auth = readAuthFile();
|
|
81
|
-
auth.openai = refreshed;
|
|
82
|
-
writeAuthFile(auth);
|
|
83
|
-
return refreshed;
|
|
84
|
-
})().finally(() => {
|
|
85
|
-
openaiRefreshPromise = null;
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return openaiRefreshPromise;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const ensureFreshOpenaiOauth = async (entry) => {
|
|
92
|
-
if (entry.access && Number(entry.expires) > Date.now()) {
|
|
93
|
-
return entry;
|
|
94
|
-
}
|
|
95
|
-
if (!entry.refresh) {
|
|
96
|
-
throw new Error('OpenAI OAuth entry has no refresh token');
|
|
97
|
-
}
|
|
98
|
-
return refreshOpenaiOauth(entry);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// ---------------------------------------------------------------------------
|
|
102
|
-
// Wire formats
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
|
|
105
|
-
const callOpenaiCompatible = async ({ baseURL, headers, modelID, prompt, system, maxOutputTokens, providerLabel, extraBody }) => {
|
|
106
|
-
const trimmedBase = baseURL.replace(/\/+$/, '');
|
|
107
|
-
const response = await fetch(`${trimmedBase}/chat/completions`, {
|
|
108
|
-
method: 'POST',
|
|
109
|
-
headers: {
|
|
110
|
-
'Content-Type': 'application/json',
|
|
111
|
-
Accept: 'application/json',
|
|
112
|
-
...headers,
|
|
113
|
-
},
|
|
114
|
-
body: JSON.stringify({
|
|
115
|
-
model: modelID,
|
|
116
|
-
messages: [
|
|
117
|
-
...(system ? [{ role: 'system', content: system }] : []),
|
|
118
|
-
{ role: 'user', content: prompt },
|
|
119
|
-
],
|
|
120
|
-
max_tokens: maxOutputTokens,
|
|
121
|
-
stream: false,
|
|
122
|
-
...(extraBody || {}),
|
|
123
|
-
}),
|
|
124
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
125
|
-
});
|
|
126
|
-
if (!response.ok) {
|
|
127
|
-
throw await httpError(response, providerLabel);
|
|
128
|
-
}
|
|
129
|
-
const payload = await response.json();
|
|
130
|
-
const message = payload?.choices?.[0]?.message;
|
|
131
|
-
|
|
132
|
-
// Providers disagree on the content shape: plain string, an array of
|
|
133
|
-
// typed parts, or (thinking models) an empty content with the budget spent
|
|
134
|
-
// on reasoning_content.
|
|
135
|
-
let text = '';
|
|
136
|
-
if (typeof message?.content === 'string') {
|
|
137
|
-
text = message.content;
|
|
138
|
-
} else if (Array.isArray(message?.content)) {
|
|
139
|
-
text = message.content
|
|
140
|
-
.map((part) => (typeof part?.text === 'string' ? part.text : ''))
|
|
141
|
-
.join('');
|
|
142
|
-
}
|
|
143
|
-
if (!text.trim() && typeof message?.reasoning_content === 'string' && message.reasoning_content.trim()) {
|
|
144
|
-
const finishReason = payload?.choices?.[0]?.finish_reason;
|
|
145
|
-
throw new Error(
|
|
146
|
-
`${providerLabel} spent the output budget on reasoning and returned no answer`
|
|
147
|
-
+ (finishReason ? ` (finish_reason: ${finishReason})` : ''),
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
if (!text.trim()) {
|
|
151
|
-
throw new Error(`${providerLabel} returned no message content`);
|
|
152
|
-
}
|
|
153
|
-
return text;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const callAnthropic = async ({ apiKey, modelID, prompt, system, maxOutputTokens }) => {
|
|
157
|
-
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
158
|
-
method: 'POST',
|
|
159
|
-
headers: {
|
|
160
|
-
'Content-Type': 'application/json',
|
|
161
|
-
Accept: 'application/json',
|
|
162
|
-
'x-api-key': apiKey,
|
|
163
|
-
'anthropic-version': '2023-06-01',
|
|
164
|
-
},
|
|
165
|
-
body: JSON.stringify({
|
|
166
|
-
model: modelID,
|
|
167
|
-
max_tokens: maxOutputTokens,
|
|
168
|
-
...(system ? { system } : {}),
|
|
169
|
-
messages: [{ role: 'user', content: prompt }],
|
|
170
|
-
}),
|
|
171
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
172
|
-
});
|
|
173
|
-
if (!response.ok) {
|
|
174
|
-
throw await httpError(response, 'Anthropic');
|
|
175
|
-
}
|
|
176
|
-
const payload = await response.json();
|
|
177
|
-
const text = (payload?.content || [])
|
|
178
|
-
.filter((part) => part?.type === 'text' && typeof part.text === 'string')
|
|
179
|
-
.map((part) => part.text)
|
|
180
|
-
.join('');
|
|
181
|
-
if (!text) {
|
|
182
|
-
throw new Error('Anthropic returned no text content');
|
|
183
|
-
}
|
|
184
|
-
return text;
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const callGoogle = async ({ apiKey, modelID, prompt, system, maxOutputTokens }) => {
|
|
188
|
-
const url = `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(modelID)}:generateContent`;
|
|
189
|
-
const response = await fetch(url, {
|
|
190
|
-
method: 'POST',
|
|
191
|
-
headers: {
|
|
192
|
-
'Content-Type': 'application/json',
|
|
193
|
-
Accept: 'application/json',
|
|
194
|
-
'x-goog-api-key': apiKey,
|
|
195
|
-
},
|
|
196
|
-
body: JSON.stringify({
|
|
197
|
-
contents: [{ role: 'user', parts: [{ text: prompt }] }],
|
|
198
|
-
...(system ? { systemInstruction: { parts: [{ text: system }] } } : {}),
|
|
199
|
-
// thinkingBudget 0 switches Gemini Flash thinking off; Flash is the only
|
|
200
|
-
// family the small-model resolver picks for Google.
|
|
201
|
-
generationConfig: { maxOutputTokens, thinkingConfig: { thinkingBudget: 0 } },
|
|
202
|
-
}),
|
|
203
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
204
|
-
});
|
|
205
|
-
if (!response.ok) {
|
|
206
|
-
throw await httpError(response, 'Google');
|
|
207
|
-
}
|
|
208
|
-
const payload = await response.json();
|
|
209
|
-
const text = (payload?.candidates?.[0]?.content?.parts || [])
|
|
210
|
-
.map((part) => (typeof part?.text === 'string' ? part.text : ''))
|
|
211
|
-
.join('');
|
|
212
|
-
if (!text) {
|
|
213
|
-
throw new Error('Google returned no text content');
|
|
214
|
-
}
|
|
215
|
-
return text;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
// ChatGPT-plan traffic goes to the codex backend, which only speaks the
|
|
219
|
-
// streaming Responses API — collect the output_text deltas from the SSE body.
|
|
220
|
-
const callCodexResponses = async ({ accessToken, accountId, modelID, prompt, system }) => {
|
|
221
|
-
const response = await fetch(CODEX_RESPONSES_URL, {
|
|
222
|
-
method: 'POST',
|
|
223
|
-
headers: {
|
|
224
|
-
'Content-Type': 'application/json',
|
|
225
|
-
Accept: 'text/event-stream',
|
|
226
|
-
Authorization: `Bearer ${accessToken}`,
|
|
227
|
-
...(accountId ? { 'ChatGPT-Account-Id': accountId } : {}),
|
|
228
|
-
originator: 'opencode',
|
|
229
|
-
'User-Agent': USER_AGENT,
|
|
230
|
-
},
|
|
231
|
-
body: JSON.stringify({
|
|
232
|
-
model: modelID,
|
|
233
|
-
...(system ? { instructions: system } : {}),
|
|
234
|
-
input: [
|
|
235
|
-
{
|
|
236
|
-
type: 'message',
|
|
237
|
-
role: 'user',
|
|
238
|
-
content: [{ type: 'input_text', text: prompt }],
|
|
239
|
-
},
|
|
240
|
-
],
|
|
241
|
-
// The codex backend rejects max_output_tokens (OpenCode forces it to
|
|
242
|
-
// undefined for this provider too).
|
|
243
|
-
stream: true,
|
|
244
|
-
store: false,
|
|
245
|
-
}),
|
|
246
|
-
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
247
|
-
});
|
|
248
|
-
if (!response.ok) {
|
|
249
|
-
throw await httpError(response, 'OpenAI (ChatGPT plan)');
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
const raw = await response.text();
|
|
253
|
-
let text = '';
|
|
254
|
-
let completedText = '';
|
|
255
|
-
for (const line of raw.split('\n')) {
|
|
256
|
-
if (!line.startsWith('data:')) continue;
|
|
257
|
-
const data = line.slice(5).trim();
|
|
258
|
-
if (!data || data === '[DONE]') continue;
|
|
259
|
-
let event;
|
|
260
|
-
try {
|
|
261
|
-
event = JSON.parse(data);
|
|
262
|
-
} catch {
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
if (event?.type === 'response.output_text.delta' && typeof event.delta === 'string') {
|
|
266
|
-
text += event.delta;
|
|
267
|
-
}
|
|
268
|
-
if (event?.type === 'response.output_text.done' && typeof event.text === 'string') {
|
|
269
|
-
completedText = event.text;
|
|
270
|
-
}
|
|
271
|
-
if (event?.type === 'response.failed' || event?.type === 'error') {
|
|
272
|
-
const message = event?.response?.error?.message || event?.message || 'response failed';
|
|
273
|
-
throw new Error(`OpenAI (ChatGPT plan) stream error: ${message}`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
const result = completedText || text;
|
|
277
|
-
if (!result) {
|
|
278
|
-
throw new Error('OpenAI (ChatGPT plan) returned no text output');
|
|
279
|
-
}
|
|
280
|
-
return result;
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
// ---------------------------------------------------------------------------
|
|
284
|
-
// Custom provider configuration support
|
|
285
|
-
// ---------------------------------------------------------------------------
|
|
286
|
-
|
|
287
|
-
const readProviderConfig = (workingDirectory, providerID) => {
|
|
288
|
-
try {
|
|
289
|
-
const config = readConfig(workingDirectory);
|
|
290
|
-
const providerCfg = config?.provider?.[providerID];
|
|
291
|
-
if (!providerCfg || typeof providerCfg !== 'object') return null;
|
|
292
|
-
const baseURL = typeof providerCfg?.options?.baseURL === 'string' ? providerCfg.options.baseURL.trim() : null;
|
|
293
|
-
const apiKey = typeof providerCfg?.options?.apiKey === 'string' ? providerCfg.options.apiKey.trim() : null;
|
|
294
|
-
return {
|
|
295
|
-
baseURL,
|
|
296
|
-
// Shape the config-supplied key as a regular api-key auth entry so it
|
|
297
|
-
// can win the precedence check below and flow through the dispatch's
|
|
298
|
-
// `entry.type === 'api' ? entry.key : ...` branch unchanged.
|
|
299
|
-
auth: apiKey ? { type: 'api', key: apiKey } : null,
|
|
300
|
-
};
|
|
301
|
-
} catch {
|
|
302
|
-
// Provider config is non-essential — continue with catalog-only resolution.
|
|
303
|
-
return null;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ---------------------------------------------------------------------------
|
|
308
|
-
// Dispatch
|
|
309
|
-
// ---------------------------------------------------------------------------
|
|
310
|
-
|
|
311
|
-
export async function callSmallModel({ auth, catalog, workingDirectory, providerID, modelID, prompt, system, maxOutputTokens, custom }) {
|
|
312
|
-
const tokens = Number(maxOutputTokens) > 0 ? Number(maxOutputTokens) : DEFAULT_MAX_OUTPUT_TOKENS;
|
|
313
|
-
if (custom) {
|
|
314
|
-
return callOpenaiCompatible({
|
|
315
|
-
baseURL: custom.baseURL,
|
|
316
|
-
headers: { Authorization: `Bearer ${custom.apiToken}` },
|
|
317
|
-
modelID,
|
|
318
|
-
prompt,
|
|
319
|
-
system,
|
|
320
|
-
maxOutputTokens: tokens,
|
|
321
|
-
providerLabel: 'Custom summary API',
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
const providerConfig = readProviderConfig(workingDirectory, providerID);
|
|
325
|
-
// Match OpenCode's resolveSDK precedence:
|
|
326
|
-
// config provider.<id>.options.apiKey (providerConfig.auth) wins; the
|
|
327
|
-
// auth.json entry is only a fallback.
|
|
328
|
-
const entry = providerConfig?.auth || getAuthEntryForProvider(auth, providerID);
|
|
329
|
-
if (!entry) {
|
|
330
|
-
throw new Error(`No OpenCode login found for provider "${providerID}"`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
if (providerID === 'github-copilot') {
|
|
334
|
-
// OpenCode uses the stored device-OAuth token directly as the bearer —
|
|
335
|
-
// access === refresh, no exchange, no expiry.
|
|
336
|
-
const token = entry.refresh || entry.access || entry.key;
|
|
337
|
-
if (!token) {
|
|
338
|
-
throw new Error('GitHub Copilot login has no token');
|
|
339
|
-
}
|
|
340
|
-
const baseURL = entry.enterpriseUrl
|
|
341
|
-
? `https://copilot-api.${String(entry.enterpriseUrl).replace(/^https?:\/\//, '').replace(/\/+$/, '')}`
|
|
342
|
-
: 'https://api.githubcopilot.com';
|
|
343
|
-
return callOpenaiCompatible({
|
|
344
|
-
baseURL,
|
|
345
|
-
headers: {
|
|
346
|
-
Authorization: `Bearer ${token}`,
|
|
347
|
-
'User-Agent': USER_AGENT,
|
|
348
|
-
'Openai-Intent': 'conversation-edits',
|
|
349
|
-
'x-initiator': 'agent',
|
|
350
|
-
'X-GitHub-Api-Version': '2026-06-01',
|
|
351
|
-
},
|
|
352
|
-
modelID,
|
|
353
|
-
prompt,
|
|
354
|
-
system,
|
|
355
|
-
maxOutputTokens: tokens,
|
|
356
|
-
providerLabel: 'GitHub Copilot',
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (providerID === 'openai' && entry.type === 'oauth') {
|
|
361
|
-
const fresh = await ensureFreshOpenaiOauth(entry);
|
|
362
|
-
return callCodexResponses({
|
|
363
|
-
accessToken: fresh.access,
|
|
364
|
-
accountId: fresh.accountId || extractChatgptAccountId(fresh.access),
|
|
365
|
-
modelID,
|
|
366
|
-
prompt,
|
|
367
|
-
system,
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const apiKey = entry.type === 'api' ? entry.key
|
|
372
|
-
: entry.type === 'wellknown' ? entry.token
|
|
373
|
-
: entry.access;
|
|
374
|
-
if (!apiKey) {
|
|
375
|
-
throw new Error(`OpenCode login for "${providerID}" has no usable credential`);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (providerID === 'anthropic') {
|
|
379
|
-
return callAnthropic({ apiKey, modelID, prompt, system, maxOutputTokens: tokens });
|
|
380
|
-
}
|
|
381
|
-
if (providerID === 'google') {
|
|
382
|
-
return callGoogle({ apiKey, modelID, prompt, system, maxOutputTokens: tokens });
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
// Everything else: OpenAI-compatible chat completions. Base URL order:
|
|
386
|
-
// (1) OpenCode merged config provider.<id>.options.baseURL
|
|
387
|
-
// (2) target model api.url from the directory catalog (OpenCode SDK)
|
|
388
|
-
// (3) known provider constants (openai only — other adapters are above)
|
|
389
|
-
// Never uses provider-level models.dev `api` fields.
|
|
390
|
-
const provider = getCatalogProvider(catalog, providerID);
|
|
391
|
-
const providerConfigUrl = providerConfig?.baseURL;
|
|
392
|
-
const modelApiUrl = typeof catalog?.[providerID]?.models?.[modelID]?.api?.url === 'string'
|
|
393
|
-
? catalog[providerID].models[modelID].api.url.trim()
|
|
394
|
-
: '';
|
|
395
|
-
const defaultOpenaiUrl = 'https://api.openai.com/v1';
|
|
396
|
-
const knownProviderUrl = providerID === 'openai' ? defaultOpenaiUrl : null;
|
|
397
|
-
const baseURL = typeof providerConfigUrl === 'string' && providerConfigUrl
|
|
398
|
-
? providerConfigUrl
|
|
399
|
-
: modelApiUrl || knownProviderUrl;
|
|
400
|
-
if (!baseURL) {
|
|
401
|
-
throw new Error(`Provider "${providerID}" has no known API base URL`);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// Thinking models burn the output budget on reasoning and leave content
|
|
405
|
-
// empty — disable thinking where a wire-format switch exists (mirrors
|
|
406
|
-
// OpenCode's smallOptions/variants special cases). There is NO universal
|
|
407
|
-
// parameter: unknown body fields 400 on some providers, so this stays an
|
|
408
|
-
// explicit allowlist. Models without a switch (DeepSeek, Qwen, Kimi, …)
|
|
409
|
-
// just get the generous output budget.
|
|
410
|
-
const lowerModel = modelID.toLowerCase();
|
|
411
|
-
const supportsThinkingToggle = providerID.includes('zai')
|
|
412
|
-
|| providerID.includes('zhipu')
|
|
413
|
-
|| lowerModel.includes('glm')
|
|
414
|
-
|| lowerModel.includes('minimax-m3');
|
|
415
|
-
const extraBody = supportsThinkingToggle ? { thinking: { type: 'disabled' } } : undefined;
|
|
416
|
-
|
|
417
|
-
return callOpenaiCompatible({
|
|
418
|
-
baseURL,
|
|
419
|
-
headers: { Authorization: `Bearer ${apiKey}` },
|
|
420
|
-
modelID,
|
|
421
|
-
prompt,
|
|
422
|
-
system,
|
|
423
|
-
maxOutputTokens: tokens,
|
|
424
|
-
providerLabel: provider?.name || providerID,
|
|
425
|
-
extraBody,
|
|
426
|
-
});
|
|
427
|
-
}
|