Repository navigation
feat(engine): self-hosted Engine and sandbox runtime support - #889
Merged
Bagatur (baskaryan) merged 77 commits intoJul 31, 2026
Merged
Conversation
…ndboxes-helm # Conflicts: # charts/langsmith/Chart.yaml # charts/langsmith/README.md
…ndboxes-helm # Conflicts: # charts/langsmith/Chart.yaml
Wires the co-hosted Insights+Engine LangGraph deployment for self-hosted, gated behind engine.enabled (default false, so Insights-only installs are unchanged). - engine values block (enabled / intelligenceBaseUrl / encryptionKey) and engine_encryption_key in the chart secret. - Engine pods get ENGINE_INTELLIGENCE_BASE_URL, ISSUES_AGENT_ENCRYPTION_KEY, and the per-service X-Service-Key JWT verifier secrets. - smith-go (platform-backend + ingest-queue) gets FORGE_AGENT_LANGGRAPH_URL, SMITH_GO_SERVICE_JWT_SECRET, ISSUES_AGENT_ENCRYPTION_KEY, and FORGE_AGENT_ASSISTANT_ID=engine. The combined langgraph.json names the graph `engine`; combined_auth rejects smith-go's default `smith_issues_agent` (403). - Insights image selects the combined langsmith-insights-engine image when engine.enabled, else standalone langsmith-clio. - smith-backend (backend + queue) gets CLIO_ASSISTANT_ID=insights when engine.enabled: the combined image names the CLIO graph `insights`, not the default `agent`. - validate.yaml: require insights.enabled, encryptionKey, and intelligenceBaseUrl when engine.enabled. Based on v16-stable rather than main: this ships in v16, and main's agent-bootstrap removal touches the same three files, so a cherry-pick back would conflict. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Engine and Insights run as one image on one deployment, so their deployment config now lives in a single block instead of two sibling product blocks. - engine / insights stay as top-level product toggles (enabled, encryptionKey; engine also carries intelligenceBaseUrl). Both encryption keys stay per product: they are different secrets for different products. - New engineInsightsAgent block holds the shared deployment config moved from insights: namePrefix, apiServer, queue, postgres, redis. namePrefix keeps its "standalone-insights" value so no Kubernetes resource is renamed and the postgres/redis StatefulSets keep their volumes. - images.insightsAgentImage + images.insightsEngineImage collapse into images.engineInsightsAgentImage. validate.yaml requires the combined insights-engine image when engine.enabled. - The shared deployment now renders when either product is on, so Engine can run with Insights disabled. Replaces the earlier "engine requires insights.enabled" guard. - validate.yaml hard-fails on the moved keys rather than silently ignoring them, so an upgrade cannot quietly drop a customized database or resource setting. Agent-feature validation now checks encryptionKey per product and postgres/redis per deployment. Rendered output for an Insights-only install is byte-identical to before. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both keys are shared with a counterpart service (engine with smith-go, insights with smith-backend), so rotating either was a flash cut: payloads encrypted just before the swap fail to decrypt after it. Add encryptionKeyPrevious for both products, written to the engine_encryption_key_previous / insights_encryption_key_previous secret fields and exposed as ISSUES_AGENT_ENCRYPTION_KEY_PREVIOUS / CLIO_ENCRYPTION_KEY_PREVIOUS. Both are optional: true, since a previous key is absent in the common case and the chart cannot see inside an existing secret when config.existingSecretName is set. smith-clio already accepted CLIO_ENCRYPTION_KEY_PREVIOUS but the chart never wired it, so rotation was unreachable from Helm for either product. The agent side for engine is langchainplus worktree-engine-key-rotation. Also adds the engine.* rows missing from the README values table. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
api_key_salt is the API-key hashing and service-JWT signing salt, not an API key. It was only set because smith-go rejected an empty FORGE_AGENT_LANGSMITH_API_KEY even when authenticating with a service-key JWT, which is the only mode self-hosted uses. Had the API-key fallback ever been taken, the salt would have gone out as x-api-key. smith-go now requires the key only in API-key mode (langchainplus worktree-engine-service-key-auth), so drop the variable. Engine dispatch authenticates with the x-service-key JWT signed from SMITH_GO_SERVICE_JWT_SECRET. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…m' into feat/engine-self-hosted-v16-sandboxes # Conflicts: # charts/langsmith/README.md # charts/langsmith/templates/ingest-queue/deployment.yaml # charts/langsmith/templates/platform-backend/deployment.yaml
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(engine): set auth prerequisites on the engine validation tests Both engine cases asserted on the engine failure message but tripped the earlier apiKeySalt and auth guards first, so they passed for the wrong reason and never reached the assertion under test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(engine): wire the sandbox tenant id for self-hosted Engine The Engine signs its sandbox calls with a service key that must carry a tenant_id claim, read from ISSUES_AGENT_SANDBOX_TENANT_ID. The chart set no such value, so a self-hosted Engine raised at sandbox-create time. Engine sandboxes live in one designated workspace rather than the run's own tenant: a sandbox in the customer's workspace would consume their sandbox quota, be visible and stoppable by them, and hold a GitHub App token for the repo under analysis. SaaS uses a LangChain-internal workspace; self-hosted has no vendor-owned one and there is no system-tenant primitive yet, so the operator designates one. The values comment spells out the consequences so that choice is informed. Required only when sandboxes are enabled, and validated at template time — otherwise the failure surfaces as a runtime error on the first Engine run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(engine): require sandboxes, and the tenant, whenever engine is enabled The tenant id was only required when config.sandboxes.enabled, but the agent raises whenever X_SERVICE_AUTH_JWT_SECRET is set -- which is on every pod, independent of that flag. So engine.enabled with sandboxes disabled passed validation and then failed at the first sandbox call. Engine cannot run without sandboxes at all: every run shells out to the langsmith CLI inside one. Make that a guard of its own, which lets the tenant guard key on engine.enabled alone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * feat(engine): point the Engine at its sandbox snapshot and base image Engine runs boot from a named snapshot the Engine builds itself on first use, so a self-hosted install needs no deploy-time snapshot build — that build wants egress to the Wolfi, astral.sh, npm and GitHub hosts, which a customer cluster may not have. The image goes through langsmith.image, so images.registry rewrites it for a mirrored registry like every other chart image. Both values default, so this adds no required configuration. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Revert "feat(engine): point the Engine at its sandbox snapshot and base image" This reverts commit c36b767. * test(engine): drop the sandboxes-disabled tenant assertion Reverting the snapshot wiring restored this case, but the tenant env var is no longer gated on config.sandboxes.enabled, and engine.enabled now requires sandboxes — so the combination it asserts cannot render. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both defaulted to SaaS, so a self-hosted Engine created sandboxes against api.smith.langchain.com and its in-sandbox CLI had nowhere reachable to call. LANGSMITH_SANDBOX_ENDPOINT is derived in-cluster like GO_ENDPOINT -- that hop is Engine pod to platform-backend, so the service URL is fine. engine.cliEndpoint has to be supplied: the sandbox runs the langsmith CLI against it, so it must be externally routable, and setting it is also what adds the host to the sandbox egress allow-list and to the proxy's credential-injection rules. The chart cannot infer that from ingress, base path and custom domains, so it is required when engine.enabled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(engine): derive the sandbox CLI endpoint from config.hostname engine.cliEndpoint was required whenever engine.enabled was true, which broke self-hosted-ci. The value is almost always <config.hostname>/api, so default it to the existing sandboxes.platformEndpoint helper and keep engine.cliEndpoint as an override for hosts config.hostname doesn't name. Validation now rejects only what cannot be inferred: no hostname at all, or a hostname no sandbox could reach (loopback, in-cluster .svc). Those still need an explicit override, since the sandbox proxy allow-lists this host and injects LangSmith credentials for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(engine): drop engine.cliEndpoint from the chart (#883) langchainplus #32399 removes LANGSMITH_CLI_ENDPOINT from the agent, which now derives the in-sandbox CLI URL from LANGCHAIN_PLATFORM_ENDPOINT — already on the pod via the shared config map whenever sandboxes are enabled, which Engine requires. So the chart has nothing left to set. Removes the values key, the env var, and the helper. The validation stays but keys off config.hostname alone, since that is what the platform endpoint is derived from and an unreachable one still has to be caught. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(engine): keep the README diff to the rows this branch changes helm-docs reordered ~191 identical rows, because nothing in the repo pins a version and the last person to regenerate used a different one. Restored the base file and applied only the engine.sandboxTenantId row by hand, so the diff shows what this branch actually changed. Leaves the sandboxes keys Daniel's merge never documented; that regeneration belongs with a version pin, not here. Also renames a test whose title still mentioned the removed cli endpoint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The branch forked at #591 and was 18 commits behind, which has to be reconciled before it can target v16-stable. Conflicts: - images: keep the engineInsightsAgentImage rename, take v16-stable's tags - insights.extraEnv: keep the engine block, add the IAM auth provider vars - validate.yaml: keep both migration guards; the IAM provider check reads engineInsightsAgent, where postgres/redis moved to - agent_iam_provider_test.yaml: same, so its fixtures resolve - README.md: regenerated with helm-docs Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3 tasks done
Bagatur (baskaryan)
added a commit
that referenced
this pull request
Jul 31, 2026
…890) langchainplus #32383 published the 0.16.27rc1 images. Clusters that track the published stable chart, such as aks.smith.langchain.dev, only pick up the cherry-picks in that release once the chart is cut. Independent of helm #889 (self-hosted Engine), which is still in review. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Mukil Loganathan (langchain-infra)
approved these changes
Jul 31, 2026
Bagatur (baskaryan)
marked this pull request as ready for review
July 31, 2026 01:15
Picks up the 0.16.0-rc.23 / 0.16.27rc1 chart cut (#890). Conflicts: keep the engineInsightsAgentImage rename with v16-stable's bumped tag; README regenerated. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3 of 5 tasks
Bagatur (baskaryan)
added a commit
that referenced
this pull request
Jul 31, 2026
…892) * chore(langsmith): bump chart to 0.16.0-rc.25 / appVersion 0.16.29rc1 rc.24 pairs Engine support (#889) with 0.16.28rc1 images, which predate the sandbox WebSocket auth fix. Enabling Engine on that chart gives runs that die on SandboxConnectionError. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(langsmith): retarget the chart bump to appVersion 0.16.30rc1 Folded the 0.16.29rc1 cut into this one: 0.16.30rc1 is the first release that publishes langsmith-insights-engine (langchainplus #32518), so a single chart bump covers both the WebSocket fix and Engine becoming installable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Jul 31, 2026
Bagatur (baskaryan)
added a commit
that referenced
this pull request
Aug 19, 2026
* feat(engine): bring Engine/Insights chart support to main The Engine work landed on v16-stable and was never forward-ported, so main has no Engine support at all and still ships langsmith-clio as the insights image. v17 would ship without Engine. Ports the Insights/Engine parts of #889, #893, #896, #897, #898, #900, #901, #909, #910 and #914: the co-hosted deployment on the combined image, the engine values block and its validate guards, Engine env for the co-host and for smith-go, the kill-switch when Engine is off, and the image rename across the insights templates and packaging scripts. Reconstructed against main rather than cherry-picked. The branches have diverged in both directions, so replaying commits would have dragged v16's older image tags and superseded comments back over main. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore(engine): trim the engine values comments The README's Engine section carries the requirements and the workspace guidance, so the value comments only need a line each. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings self-hosted Engine to the v16 train: the sandbox runtime it depends on, and the chart wiring to turn Engine on. 67 commits, +3826/-511 across 58 chart files.
Draft while #881 is settled — it targets this branch and would otherwise be stranded once this merges.
What lands
Sandbox runtime (
config.sandboxes.enabled, Daniel's work). Newtemplates/sandboxes/: the sandbox-host StatefulSet and RBAC, the JuiceFS CSI driver (controller, node DaemonSet, CSIDriver, RBAC, configmap), and the proxy CA. Off by default; when on, it installs cluster-scoped CSI resources, so only one sandbox-enabled release should manage them per cluster.Engine (
engine.enabled). Off by default. Requires the combinedlangsmith-insights-engineimage, which serves both theinsightsandenginegraphs — published publicly by the self-hosted release workflow.Insights and Engine now share one deployment. Scaling, database and resource settings moved from
insights.*to a newengineInsightsAgent.*block, andimages.{insightsAgentImage,insightsEngineImage}becameimages.engineInsightsAgentImage.insights.enabledandinsights.encryptionKeystay where they are. Every moved key has a migrationfailnaming its replacement, so an operator carrying the old values gets told rather than silently ignored.Upgrade notes
engine.enabledadditionally requiresconfig.sandboxes.enabled,engine.encryptionKey,engine.intelligenceBaseUrl,engine.sandboxTenantId, and aconfig.hostnamea sandbox can actually reach — validation rejects loopback and in-cluster addresses, since that host is allow-listed for sandbox egress and receives injected credentials.engine.cliEndpointno longer exists: the agent derives the in-sandbox CLI URL fromLANGCHAIN_PLATFORM_ENDPOINT. Needs an agent image with langchainplus #32399 —0.16.27rc1and later.Test Plan
helm unittest charts/langsmith— 248/248 across 19 suiteshelm lintcleanself-hosted-ci's real values: noLANGSMITH_CLI_ENDPOINT,LANGCHAIN_PLATFORM_ENDPOINT=https://eks.smith.langchain.dev/apiv16-stablemerged in (Merge v16-stable into feat/engine-self-hosted-v16-sandboxes #888) — branch is 0 behindself-hosted-cideploys from this branch, so the next run is the first end-to-end Engine testBefore merging
0.16.27rc1contains langchainplus #31926appVersion→0.16.27rc1,version→0.16.0-rc.23, image tags, regenerate README