Skip to content

feat(settings): Spend controls in the workspace, compute keys actually applied#84

Merged
Aayam Bansal (aayambansal) merged 1 commit into
mainfrom
feat/spend-ui-and-compute-env
Jul 5, 2026
Merged

feat(settings): Spend controls in the workspace, compute keys actually applied#84
Aayam Bansal (aayambansal) merged 1 commit into
mainfrom
feat/spend-ui-and-compute-env

Conversation

@aayambansal

@aayambansal Aayam Bansal (aayambansal) commented Jul 5, 2026

Copy link
Copy Markdown
Member

Fixes #71
Fixes #72

Compute keys are now applied (#71)

The Compute panel encrypted and stored GPU provider keys, showed a green "connected" badge — and nothing ever read them back. This adds ComputeSettings.applyComputeEnv(), mirroring applyCredentialEnv in the credentials store exactly:

  • Decrypts each connected provider's key and injects it into the process env under the canonical names the real consumers (cloud-compute / ml-training skills, session prompts, bash subprocesses via subprocessEnv) read. Where two spellings exist in the wild, both are set: TENSORPOOL_KEY/TENSORPOOL_API_KEY, LAMBDA_API_KEY/LAMBDA_LABS_API_KEY, PRIME_API_KEY/PRIME_INTELLECT_API_KEY, VAST_API_KEY, RUNPOD_API_KEY. Modal's combined ak-… : as-… key splits into MODAL_TOKEN_ID + MODAL_TOKEN_SECRET (a half-pasted key maps to nothing rather than half a credential).
  • Runs at the same boot location as applyCredentialEnv (index.ts middleware) and again after every provider connect/disconnect, so a saved key applies live without a restart.
  • Same semantics as the credentials store: removed entries are cleaned out of the env, an explicit shell export always wins, decrypted values are registered for output redaction, and the whole thing is best-effort (a corrupt store never breaks boot or a save response).

last_used is left as-is: there is no code path that observes an actual compute run (usage reporting is LLM-step-only), so any timestamp written here — e.g. at boot-time injection — would just mean "CLI started", which is more misleading than "never". Wiring it honestly needs a compute-run hook and is out of scope.

Spend panel + copy fixes (#72)

Error copy pointed at "Settings → Spend", which didn't exist, and the only way to flip billing.llm was hand-editing openscience.json. This ships the panel:

  • New Spend panel in the workspace settings rail (registered in registry.ts), reading GET /settings/billing and writing PUT /settings/billing through the generated SDK (client.settings.billing.get/update).
  • LLM spend: managed / byok / auto. Auto (unset) is now round-trippable — the PUT accepts llm: null to clear the toggle back to auto-detect (config schema made nullable, llmBillingMode() normalizes null to undefined, SDK types regenerated from the OpenAPI spec — the gen diff is exactly the nullable field).
  • Compute spend: managed / byok.
  • Wallet card shows the signed-in state + balance from the GET, with a sign-in hint when there's no Atlas session.
  • The PUT handler still mirrors the LLM toggle to the server-side account billing mode via OpenScience.setBillingMode + resync (verified, unchanged) — so the gate (config) and the Usage panel (account mode) stay in sync through the one control. Auto skips the mirror since it has no server-side counterpart.
  • Usage.tsx no longer says "Switch to managed mode (Credentials)" — it points at Settings → Spend. processor.ts already said Settings → Spend, which is now true, so it's untouched.

Verification

  • cd backend/cli && bun test — 836 pass, 0 fail (includes new tests below).
  • bun run typecheck — clean across all 6 packages.
  • bun run --cwd frontend/workspace build — passes.
  • New test/server/settings-compute.test.ts exercises the real routes + store (no mocks): connect applies every canonical var, modal splits, shell exports win, disconnect removes injected vars but never a shell export, re-save updates in place, and the key never appears in a response body. There was no pre-existing applyCredentialEnv test to mirror, so this follows the settings-billing.test.ts route-test pattern instead.
  • New billing test: PUT llm: null persists null and reads back as auto.
  • Exercised live against openscience serve: GET/PUT /settings/billing round-trips managed/byok/null (null persists correctly through both the JSON merge and JSONC patch paths), and compute provider connect stores ciphertext only and never returns the key.

@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openscience Ready Ready Preview, Comment Jul 5, 2026 11:57am

Request Review

…y applied

Compute panel keys now do something: applyComputeEnv() mirrors the
credentials store's pattern — decrypt the stored GPU provider keys and
inject them under the canonical env var names the skills read (Modal's
combined key splits into token id + secret), at boot and after every
connect/disconnect, with removed-entry cleanup, shell-export precedence,
and output redaction.

Ship the Spend settings panel: LLM spend (managed / byok / auto) and
compute spend (managed / byok) driven by GET/PUT /settings/billing via
the generated SDK, plus wallet balance and signed-in state. The PUT
route keeps the server-side account billing mode in sync and now accepts
llm: null to set the toggle back to auto (config schema + SDK types
regenerated). Usage panel copy now points at the real control.

Fixes #71
Fixes #72
@aayambansal Aayam Bansal (aayambansal) force-pushed the feat/spend-ui-and-compute-env branch from 621c73f to b8be62c Compare July 5, 2026 11:57
@aayambansal Aayam Bansal (aayambansal) merged commit 2ba3fea into main Jul 5, 2026
12 checks passed
@aayambansal Aayam Bansal (aayambansal) deleted the feat/spend-ui-and-compute-env branch July 5, 2026 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Spend toggle has no UI and error messages point at settings that don't exist Compute panel stores GPU keys that nothing ever reads

1 participant