From 506ed6b40efef703e41b47a4510c34a8db93ff1d Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 15 May 2026 17:26:36 -0700 Subject: [PATCH] feat: GSTACK_* env-key shim for Conductor workspaces New lib/conductor-env-shim.ts promotes GSTACK_ANTHROPIC_API_KEY and GSTACK_OPENAI_API_KEY to canonical names when canonical is empty. Wired into the four TS entry points that hit paid APIs or gbrain embeddings: gstack-gbrain-sync.ts, gstack-model-benchmark, preflight-agent-sdk.ts, test/helpers/e2e-helpers.ts. Side-effect-only import, 15 lines total. Co-Authored-By: Claude Opus 4.7 (1M context) --- bin/gstack-gbrain-sync.ts | 1 + bin/gstack-model-benchmark | 1 + lib/conductor-env-shim.ts | 14 ++++++++++++++ scripts/preflight-agent-sdk.ts | 1 + test/helpers/e2e-helpers.ts | 1 + 5 files changed, 18 insertions(+) create mode 100644 lib/conductor-env-shim.ts diff --git a/bin/gstack-gbrain-sync.ts b/bin/gstack-gbrain-sync.ts index 732ee430c..4fc658ac4 100644 --- a/bin/gstack-gbrain-sync.ts +++ b/bin/gstack-gbrain-sync.ts @@ -35,6 +35,7 @@ import { execSync, spawnSync } from "child_process"; import { homedir } from "os"; import { createHash } from "crypto"; +import "../lib/conductor-env-shim"; import { detectEngineTier, withErrorContext, canonicalizeRemote } from "../lib/gstack-memory-helpers"; import { ensureSourceRegistered, sourcePageCount } from "../lib/gbrain-sources"; import { localEngineStatus, type LocalEngineStatus } from "../lib/gbrain-local-status"; diff --git a/bin/gstack-model-benchmark b/bin/gstack-model-benchmark index 7c48c910b..34227652c 100755 --- a/bin/gstack-model-benchmark +++ b/bin/gstack-model-benchmark @@ -24,6 +24,7 @@ * gstack-model-benchmark --prompt "hi" --models claude,gpt,gemini --dry-run */ +import '../lib/conductor-env-shim'; import * as fs from 'fs'; import * as path from 'path'; import { runBenchmark, formatTable, formatJson, formatMarkdown, type BenchmarkInput } from '../test/helpers/benchmark-runner'; diff --git a/lib/conductor-env-shim.ts b/lib/conductor-env-shim.ts new file mode 100644 index 000000000..7056525ec --- /dev/null +++ b/lib/conductor-env-shim.ts @@ -0,0 +1,14 @@ +/** + * Conductor workspaces don't inherit the user's interactive shell env, so the + * canonical ANTHROPIC_API_KEY / OPENAI_API_KEY may be missing while + * Conductor's GSTACK_-prefixed forms are present. Promote the GSTACK_ form to + * canonical when canonical is empty, so subprocesses (gbrain embed, + * @anthropic-ai/claude-agent-sdk, etc) pick it up. + * + * Import this for its side effect: `import "../lib/conductor-env-shim";` + */ +for (const key of ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"] as const) { + if (!process.env[key] && process.env[`GSTACK_${key}`]) { + process.env[key] = process.env[`GSTACK_${key}`]; + } +} diff --git a/scripts/preflight-agent-sdk.ts b/scripts/preflight-agent-sdk.ts index 8a0bc5618..6b3e9ea7c 100644 --- a/scripts/preflight-agent-sdk.ts +++ b/scripts/preflight-agent-sdk.ts @@ -16,6 +16,7 @@ * side effects beyond stdout and a ~15 token API call. */ +import '../lib/conductor-env-shim'; import { query, type SDKMessage } from '@anthropic-ai/claude-agent-sdk'; import { readOverlay } from './resolvers/model-overlay'; import { resolveClaudeBinary } from '../browse/src/claude-bin'; diff --git a/test/helpers/e2e-helpers.ts b/test/helpers/e2e-helpers.ts index e51baa3f7..32510f13a 100644 --- a/test/helpers/e2e-helpers.ts +++ b/test/helpers/e2e-helpers.ts @@ -5,6 +5,7 @@ * tests across multiple files by category. */ +import '../../lib/conductor-env-shim'; import { describe, test, beforeAll, afterAll, expect } from 'bun:test'; import type { SkillTestResult } from './session-runner'; import { EvalCollector, judgePassed } from './eval-store';