@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,7 +1,12 @@
|
|
|
1
1
|
import { OpenCode } from '@opencode/client';
|
|
2
|
+
import { buildLlmSessionMetadata } from '../session-metadata/system-session.js';
|
|
3
|
+
import { ensureLlmTempDirectory } from './temp-directory.js';
|
|
2
4
|
|
|
3
5
|
const LLM_AGENT_NAME = 'openchamber-llm';
|
|
6
|
+
const TEXT_AGENT_NAME = 'openchamber-text';
|
|
4
7
|
const GENERATE_TIMEOUT_MS = 90_000;
|
|
8
|
+
const AGENT_READY_WAIT_MS = 5_000;
|
|
9
|
+
const AGENT_READY_POLL_MS = 250;
|
|
5
10
|
/** Single attachment payload cap (decoded bytes). Composer UI allows larger drafts; gateway enforces this. */
|
|
6
11
|
export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
|
|
7
12
|
const MAX_INLINE_FILE_CHARS = 100_000;
|
|
@@ -31,6 +36,21 @@ Report execution and failures from supplied tool results only.
|
|
|
31
36
|
Do not call native OpenCode tools, MCP tools, or skill tools. Native permissions are denied for this generator session.
|
|
32
37
|
`;
|
|
33
38
|
|
|
39
|
+
/** Neutral deny-all agent for text-only `session.generate`; the caller's instructions travel in the prompt. */
|
|
40
|
+
const TEXT_AGENT_MARKDOWN = `---
|
|
41
|
+
mode: primary
|
|
42
|
+
hidden: true
|
|
43
|
+
permissions:
|
|
44
|
+
- action: "*"
|
|
45
|
+
resource: "*"
|
|
46
|
+
effect: deny
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
Follow the instructions in the request and respond in the requested format.
|
|
50
|
+
Native OpenCode, MCP, and skill tools are denied for this generator session.
|
|
51
|
+
When the request defines an application tool-call format (such as fenced JSON), write it as plain text in your reply; the application executes it.
|
|
52
|
+
`;
|
|
53
|
+
|
|
34
54
|
const failGenerate = (message, code = 'upstream_error') => {
|
|
35
55
|
const error = new Error(message);
|
|
36
56
|
error.code = code;
|
|
@@ -267,26 +287,52 @@ export function subscribeThrowawayTextDeltas({ globalEventHub, sessionID, onText
|
|
|
267
287
|
}
|
|
268
288
|
|
|
269
289
|
/**
|
|
270
|
-
*
|
|
290
|
+
* OpenCode loads a new location's config lazily: the first requests against a
|
|
291
|
+
* fresh temp directory can report no agents at all. Poll `agent.get` within a
|
|
292
|
+
* bounded window instead of failing on that first read.
|
|
293
|
+
*/
|
|
294
|
+
const readGeneratorAgent = async ({ client, location, signal, agentID, waitMs, pollMs }) => {
|
|
295
|
+
const deadline = Date.now() + waitMs;
|
|
296
|
+
for (;;) {
|
|
297
|
+
try {
|
|
298
|
+
return await client.agent.get({
|
|
299
|
+
agentID,
|
|
300
|
+
...(location ? { location } : {}),
|
|
301
|
+
}, { signal });
|
|
302
|
+
} catch (error) {
|
|
303
|
+
rethrowIfAborted(error, signal);
|
|
304
|
+
if (Date.now() + pollMs > deadline) throw error;
|
|
305
|
+
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Verify the generator agent ends with deny-all permissions.
|
|
271
312
|
* Title alone is never treated as isolation. Failure must happen before prompt.
|
|
272
313
|
*/
|
|
273
|
-
export async function assertLlmAgentDenyAll({
|
|
314
|
+
export async function assertLlmAgentDenyAll({
|
|
315
|
+
client,
|
|
316
|
+
location,
|
|
317
|
+
signal,
|
|
318
|
+
agentID = LLM_AGENT_NAME,
|
|
319
|
+
waitMs = AGENT_READY_WAIT_MS,
|
|
320
|
+
pollMs = AGENT_READY_POLL_MS,
|
|
321
|
+
}) {
|
|
274
322
|
let result;
|
|
275
323
|
try {
|
|
276
|
-
result = await
|
|
277
|
-
agentID: LLM_AGENT_NAME,
|
|
278
|
-
...(location ? { location } : {}),
|
|
279
|
-
}, { signal });
|
|
324
|
+
result = await readGeneratorAgent({ client, location, signal, agentID, waitMs, pollMs });
|
|
280
325
|
} catch (error) {
|
|
326
|
+
rethrowIfAborted(error, signal);
|
|
281
327
|
failGenerate(
|
|
282
|
-
`OpenCode LLM agent is unavailable (${clientErrorMessage(error, 'agent.get failed')});
|
|
328
|
+
`OpenCode LLM agent is unavailable (${clientErrorMessage(error, 'agent.get failed')}); generation blocked`,
|
|
283
329
|
'llm_attachment_generation_unavailable',
|
|
284
330
|
);
|
|
285
331
|
}
|
|
286
332
|
const permissions = result?.data?.permissions;
|
|
287
333
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
288
334
|
failGenerate(
|
|
289
|
-
'OpenCode LLM agent permissions are missing;
|
|
335
|
+
'OpenCode LLM agent permissions are missing; generation blocked',
|
|
290
336
|
'llm_attachment_generation_unavailable',
|
|
291
337
|
);
|
|
292
338
|
}
|
|
@@ -298,7 +344,7 @@ export async function assertLlmAgentDenyAll({ client, location, signal }) {
|
|
|
298
344
|
|| last.effect !== 'deny'
|
|
299
345
|
) {
|
|
300
346
|
failGenerate(
|
|
301
|
-
'OpenCode LLM agent final permission is not deny-all;
|
|
347
|
+
'OpenCode LLM agent final permission is not deny-all; generation blocked',
|
|
302
348
|
'llm_attachment_generation_unavailable',
|
|
303
349
|
);
|
|
304
350
|
}
|
|
@@ -339,63 +385,57 @@ const makeClient = ({ baseUrl, headers, clientFactory }) => {
|
|
|
339
385
|
return OpenCode.make({ baseUrl, headers });
|
|
340
386
|
};
|
|
341
387
|
|
|
342
|
-
async
|
|
343
|
-
|
|
344
|
-
location,
|
|
345
|
-
providerID,
|
|
346
|
-
modelID,
|
|
347
|
-
variant,
|
|
348
|
-
prompt,
|
|
349
|
-
signal,
|
|
350
|
-
}) {
|
|
351
|
-
let result;
|
|
388
|
+
const prepareGeneratorDirectory = async ({ ensureTempDirectory, agentName, agentMarkdown }) => {
|
|
389
|
+
let workingDirectory;
|
|
352
390
|
try {
|
|
353
|
-
|
|
354
|
-
...(location ? { location } : {}),
|
|
355
|
-
prompt,
|
|
356
|
-
model: modelRef(providerID, modelID, variant),
|
|
357
|
-
}, { signal });
|
|
391
|
+
workingDirectory = await ensureTempDirectory({ agentName, agentMarkdown });
|
|
358
392
|
} catch (error) {
|
|
359
|
-
|
|
360
|
-
|
|
393
|
+
failGenerate(
|
|
394
|
+
`LLM temp directory failed (${clientErrorMessage(error, 'ensure failed')})`,
|
|
395
|
+
'llm_attachment_generation_unavailable',
|
|
396
|
+
);
|
|
361
397
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return
|
|
369
|
-
}
|
|
398
|
+
if (typeof workingDirectory !== 'string' || !workingDirectory.trim()) {
|
|
399
|
+
failGenerate(
|
|
400
|
+
'LLM temp directory is empty; generation blocked',
|
|
401
|
+
'llm_attachment_generation_unavailable',
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
return workingDirectory.trim();
|
|
405
|
+
};
|
|
370
406
|
|
|
371
|
-
|
|
407
|
+
/**
|
|
408
|
+
* Run `work(sessionID)` inside a throwaway OpenCode session owned by a
|
|
409
|
+
* verified deny-all agent. The session is always removed afterwards;
|
|
410
|
+
* cancellation interrupts it first.
|
|
411
|
+
*/
|
|
412
|
+
async function withThrowawaySession({
|
|
372
413
|
client,
|
|
373
414
|
workingDirectory,
|
|
415
|
+
agentName,
|
|
374
416
|
providerID,
|
|
375
417
|
modelID,
|
|
376
418
|
variant,
|
|
377
|
-
system,
|
|
378
|
-
prompt,
|
|
379
|
-
imageFiles,
|
|
380
419
|
signal,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}) {
|
|
420
|
+
persistSessionMetadata,
|
|
421
|
+
onSystemSessionPersisted,
|
|
422
|
+
}, work) {
|
|
384
423
|
const location = { directory: workingDirectory };
|
|
385
424
|
|
|
386
425
|
// Permission isolation must be verified before any prompt. Never use title as isolation.
|
|
387
|
-
await assertLlmAgentDenyAll({ client, location, signal });
|
|
426
|
+
await assertLlmAgentDenyAll({ client, location, signal, agentID: agentName });
|
|
388
427
|
|
|
389
428
|
let sessionID = null;
|
|
390
|
-
let unsubscribeDeltas = null;
|
|
391
429
|
try {
|
|
392
430
|
let created;
|
|
431
|
+
const isolationMetadata = buildLlmSessionMetadata();
|
|
393
432
|
try {
|
|
394
433
|
created = await client.session.create({
|
|
395
434
|
title: '[openchamber-llm] generate',
|
|
396
|
-
agent:
|
|
435
|
+
agent: agentName,
|
|
397
436
|
model: modelRef(providerID, modelID, variant),
|
|
398
437
|
location,
|
|
438
|
+
metadata: isolationMetadata,
|
|
399
439
|
}, { signal });
|
|
400
440
|
} catch (error) {
|
|
401
441
|
// Temp workspace invisible to OpenCode must fail explicitly.
|
|
@@ -408,7 +448,72 @@ async function generateViaAttachmentSession({
|
|
|
408
448
|
if (!sessionID) {
|
|
409
449
|
failGenerate('OpenCode LLM session create returned no id', 'llm_attachment_generation_unavailable');
|
|
410
450
|
}
|
|
451
|
+
if (typeof persistSessionMetadata === 'function') {
|
|
452
|
+
try {
|
|
453
|
+
await persistSessionMetadata(sessionID, isolationMetadata);
|
|
454
|
+
onSystemSessionPersisted?.({
|
|
455
|
+
sessionID,
|
|
456
|
+
directory: workingDirectory,
|
|
457
|
+
metadata: isolationMetadata,
|
|
458
|
+
});
|
|
459
|
+
} catch (error) {
|
|
460
|
+
console.warn('[llm] failed to persist system session metadata:', error?.message || error);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
return await work(sessionID);
|
|
464
|
+
} finally {
|
|
465
|
+
if (sessionID) {
|
|
466
|
+
if (signal?.aborted) {
|
|
467
|
+
try {
|
|
468
|
+
await client.session.interrupt({ sessionID, continue: false });
|
|
469
|
+
} catch {
|
|
470
|
+
// Best-effort interrupt on timeout/abort.
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
await client.session.remove({ sessionID });
|
|
475
|
+
} catch (error) {
|
|
476
|
+
console.warn('[llm] failed to remove throwaway OpenCode session:', error?.message || error);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
411
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Text-only generation through `session.generate`: one model call with the
|
|
484
|
+
* session's provider context (so session-scoped providers such as OpenCode Go
|
|
485
|
+
* work), no tool loop, and no messages written to the session.
|
|
486
|
+
*/
|
|
487
|
+
async function generateViaSessionGenerate({ client, prompt, signal, ...sessionOptions }) {
|
|
488
|
+
return withThrowawaySession({ client, signal, ...sessionOptions }, async (sessionID) => {
|
|
489
|
+
let result;
|
|
490
|
+
try {
|
|
491
|
+
result = await client.session.generate({ sessionID, prompt }, { signal });
|
|
492
|
+
} catch (error) {
|
|
493
|
+
rethrowIfAborted(error, signal);
|
|
494
|
+
failGenerate(clientErrorMessage(error, 'OpenCode session.generate failed'));
|
|
495
|
+
}
|
|
496
|
+
const text = typeof result?.text === 'string'
|
|
497
|
+
? result.text.trim()
|
|
498
|
+
: typeof result?.data?.text === 'string'
|
|
499
|
+
? result.data.text.trim()
|
|
500
|
+
: '';
|
|
501
|
+
if (!text) failGenerate('OpenCode session.generate returned no text');
|
|
502
|
+
return { text, source: 'session.generate' };
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
async function generateViaAttachmentSession({
|
|
507
|
+
client,
|
|
508
|
+
system,
|
|
509
|
+
prompt,
|
|
510
|
+
imageFiles,
|
|
511
|
+
signal,
|
|
512
|
+
onTextDelta,
|
|
513
|
+
globalEventHub,
|
|
514
|
+
...sessionOptions
|
|
515
|
+
}) {
|
|
516
|
+
return withThrowawaySession({ client, signal, ...sessionOptions }, async (sessionID) => {
|
|
412
517
|
if (system) {
|
|
413
518
|
try {
|
|
414
519
|
await client.session.instructions.entry.put({
|
|
@@ -421,89 +526,81 @@ async function generateViaAttachmentSession({
|
|
|
421
526
|
}
|
|
422
527
|
}
|
|
423
528
|
|
|
424
|
-
unsubscribeDeltas = subscribeThrowawayTextDeltas({
|
|
529
|
+
const unsubscribeDeltas = subscribeThrowawayTextDeltas({
|
|
425
530
|
globalEventHub,
|
|
426
531
|
sessionID,
|
|
427
532
|
onTextDelta,
|
|
428
533
|
});
|
|
429
|
-
|
|
430
|
-
const files = imageFiles.map((part) => ({
|
|
431
|
-
uri: part.url,
|
|
432
|
-
...(part.filename ? { name: part.filename } : {}),
|
|
433
|
-
}));
|
|
434
|
-
|
|
435
534
|
try {
|
|
436
|
-
await client
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
rethrowIfAborted(error, signal);
|
|
444
|
-
failGenerate(clientErrorMessage(error, 'session.prompt failed'));
|
|
535
|
+
return await promptAttachmentSession({ client, sessionID, prompt, imageFiles, signal });
|
|
536
|
+
} finally {
|
|
537
|
+
try {
|
|
538
|
+
unsubscribeDeltas?.();
|
|
539
|
+
} catch {
|
|
540
|
+
// Unsubscribe must not mask generate errors or block session remove.
|
|
541
|
+
}
|
|
445
542
|
}
|
|
543
|
+
});
|
|
544
|
+
}
|
|
446
545
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
546
|
+
async function promptAttachmentSession({ client, sessionID, prompt, imageFiles, signal }) {
|
|
547
|
+
const files = imageFiles.map((part) => ({
|
|
548
|
+
uri: part.url,
|
|
549
|
+
...(part.filename ? { name: part.filename } : {}),
|
|
550
|
+
}));
|
|
453
551
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
552
|
+
try {
|
|
553
|
+
await client.session.prompt({
|
|
554
|
+
sessionID,
|
|
555
|
+
text: prompt || '[attachment]',
|
|
556
|
+
...(files.length > 0 ? { files } : {}),
|
|
557
|
+
delivery: 'steer',
|
|
558
|
+
}, { signal });
|
|
559
|
+
} catch (error) {
|
|
560
|
+
rethrowIfAborted(error, signal);
|
|
561
|
+
failGenerate(clientErrorMessage(error, 'session.prompt failed'));
|
|
562
|
+
}
|
|
465
563
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
} catch (error) {
|
|
490
|
-
console.warn('[llm] failed to remove throwaway OpenCode session:', error?.message || error);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
564
|
+
try {
|
|
565
|
+
await client.session.wait({ sessionID }, { signal });
|
|
566
|
+
} catch (error) {
|
|
567
|
+
rethrowIfAborted(error, signal);
|
|
568
|
+
failGenerate(clientErrorMessage(error, 'session.wait failed'));
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
let listed;
|
|
572
|
+
try {
|
|
573
|
+
listed = await client.message.list({
|
|
574
|
+
sessionID,
|
|
575
|
+
limit: 20,
|
|
576
|
+
order: 'desc',
|
|
577
|
+
}, { signal });
|
|
578
|
+
} catch (error) {
|
|
579
|
+
rethrowIfAborted(error, signal);
|
|
580
|
+
failGenerate(clientErrorMessage(error, 'message.list failed'));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const messages = Array.isArray(listed?.data) ? listed.data : [];
|
|
584
|
+
const text = assistantTextFromMessages(messages);
|
|
585
|
+
if (!text.trim()) {
|
|
586
|
+
failGenerate('OpenCode LLM generator returned no assistant text');
|
|
493
587
|
}
|
|
588
|
+
return { text: text.trim(), source: 'attachment-session' };
|
|
494
589
|
}
|
|
495
590
|
|
|
496
591
|
/**
|
|
497
592
|
* Generate assistant text through OpenCode's connected providers via
|
|
498
593
|
* `@opencode/client`.
|
|
499
594
|
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
595
|
+
* Both paths run in a throwaway session owned by a verified deny-all agent in
|
|
596
|
+
* the LLM temp directory, and the session is removed afterwards.
|
|
597
|
+
* - Pure text: `session.generate` (single model call, nothing written).
|
|
598
|
+
* - Vision image attachments: `session.prompt` + wait + message list.
|
|
502
599
|
* - Non-vision: keep `[image: …]` descriptions; never forward image bytes.
|
|
503
600
|
*
|
|
504
601
|
* Optional internal streaming: `onTextDelta` + `globalEventHub` forwards real
|
|
505
602
|
* `session.text.delta` tokens on the attachment-session path only.
|
|
506
|
-
* `generate
|
|
603
|
+
* `session.generate` cannot emit live deltas (no fake typewriter).
|
|
507
604
|
*
|
|
508
605
|
* Optional `signal` from the contact continuation is combined with the generator
|
|
509
606
|
* deadline. Cancellation still runs throwaway-session cleanup.
|
|
@@ -516,10 +613,12 @@ export async function generateOpenCodeText({
|
|
|
516
613
|
messages,
|
|
517
614
|
variant,
|
|
518
615
|
clientFactory,
|
|
519
|
-
ensureTempDirectory,
|
|
616
|
+
ensureTempDirectory = ensureLlmTempDirectory,
|
|
520
617
|
forwardImageParts = false,
|
|
521
618
|
onTextDelta = null,
|
|
522
619
|
globalEventHub = null,
|
|
620
|
+
persistSessionMetadata = null,
|
|
621
|
+
onSystemSessionPersisted = null,
|
|
523
622
|
signal: parentSignal = null,
|
|
524
623
|
timeoutMs = GENERATE_TIMEOUT_MS,
|
|
525
624
|
}) {
|
|
@@ -555,56 +654,47 @@ export async function generateOpenCodeText({
|
|
|
555
654
|
}, deadlineMs);
|
|
556
655
|
timeout.unref?.();
|
|
557
656
|
|
|
657
|
+
const sessionOptions = {
|
|
658
|
+
client,
|
|
659
|
+
providerID,
|
|
660
|
+
modelID,
|
|
661
|
+
variant,
|
|
662
|
+
signal: requestSignal,
|
|
663
|
+
persistSessionMetadata,
|
|
664
|
+
onSystemSessionPersisted,
|
|
665
|
+
};
|
|
666
|
+
|
|
558
667
|
try {
|
|
559
668
|
if (imageFiles.length > 0) {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
}
|
|
566
|
-
let workingDirectory;
|
|
567
|
-
try {
|
|
568
|
-
workingDirectory = await ensureTempDirectory({
|
|
569
|
-
agentName: LLM_AGENT_NAME,
|
|
570
|
-
agentMarkdown: AGENT_MARKDOWN,
|
|
571
|
-
});
|
|
572
|
-
} catch (error) {
|
|
573
|
-
failGenerate(
|
|
574
|
-
`LLM temp directory failed (${clientErrorMessage(error, 'ensure failed')})`,
|
|
575
|
-
'llm_attachment_generation_unavailable',
|
|
576
|
-
);
|
|
577
|
-
}
|
|
578
|
-
if (typeof workingDirectory !== 'string' || !workingDirectory.trim()) {
|
|
579
|
-
failGenerate(
|
|
580
|
-
'LLM temp directory is empty; attachment generation blocked',
|
|
581
|
-
'llm_attachment_generation_unavailable',
|
|
582
|
-
);
|
|
583
|
-
}
|
|
669
|
+
const workingDirectory = await prepareGeneratorDirectory({
|
|
670
|
+
ensureTempDirectory,
|
|
671
|
+
agentName: LLM_AGENT_NAME,
|
|
672
|
+
agentMarkdown: AGENT_MARKDOWN,
|
|
673
|
+
});
|
|
584
674
|
return await generateViaAttachmentSession({
|
|
585
|
-
|
|
586
|
-
workingDirectory
|
|
587
|
-
|
|
588
|
-
modelID,
|
|
589
|
-
variant,
|
|
675
|
+
...sessionOptions,
|
|
676
|
+
workingDirectory,
|
|
677
|
+
agentName: LLM_AGENT_NAME,
|
|
590
678
|
system: flattened.system,
|
|
591
679
|
prompt: flattened.prompt,
|
|
592
680
|
imageFiles,
|
|
593
|
-
signal: requestSignal,
|
|
594
681
|
onTextDelta,
|
|
595
682
|
globalEventHub,
|
|
596
683
|
});
|
|
597
684
|
}
|
|
598
685
|
|
|
599
|
-
// Text path:
|
|
686
|
+
// Text path: the system prompt is prepended into the single prompt string.
|
|
687
|
+
const workingDirectory = await prepareGeneratorDirectory({
|
|
688
|
+
ensureTempDirectory,
|
|
689
|
+
agentName: TEXT_AGENT_NAME,
|
|
690
|
+
agentMarkdown: TEXT_AGENT_MARKDOWN,
|
|
691
|
+
});
|
|
600
692
|
const prompt = [flattened.system, flattened.prompt].filter((part) => String(part || '').trim()).join('\n\n');
|
|
601
|
-
return await
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
variant,
|
|
693
|
+
return await generateViaSessionGenerate({
|
|
694
|
+
...sessionOptions,
|
|
695
|
+
workingDirectory,
|
|
696
|
+
agentName: TEXT_AGENT_NAME,
|
|
606
697
|
prompt,
|
|
607
|
-
signal: requestSignal,
|
|
608
698
|
});
|
|
609
699
|
} finally {
|
|
610
700
|
clearTimeout(timeout);
|
|
@@ -625,6 +715,8 @@ export const _test = {
|
|
|
625
715
|
assertValidAttachmentParts,
|
|
626
716
|
LLM_AGENT_NAME,
|
|
627
717
|
AGENT_MARKDOWN,
|
|
718
|
+
TEXT_AGENT_NAME,
|
|
719
|
+
TEXT_AGENT_MARKDOWN,
|
|
628
720
|
MAX_ATTACHMENT_BYTES,
|
|
629
721
|
GENERATE_TIMEOUT_MS,
|
|
630
722
|
};
|