Skip to content

feat(setup): read the setup agent config through the gonfalon relay (4/6) - #897

Draft
atornsii wants to merge 9 commits into
atorns/agent-3-macos-sandboxfrom
atorns/agent-4-ai-sdk-relay
Draft

atornsii wants to merge 9 commits into
atorns/agent-3-macos-sandboxfrom
atorns/agent-4-ai-sdk-relay

Conversation

@atornsii

@atornsii atornsii commented Oct 20, 2026 •

Copy link
Copy Markdown

This adds the Go AI SDK (github.com/launchdarkly/go-ai-sdk, pinned to commit 6152dc9) and reads the ldcli-setup-agent AI Config through the SDK relay in gonfalon. No SDK key is on the user's machine.

How it works

  1. When the user is logged in, setup starts a loopback proxy on 127.0.0.1 under a random path.
  2. The SDK gets the placeholder key ldcli-placeholder, and every SDK option points at the proxy. The CLI sets each option in code, because the SDK reads LD_ variables that ldcli also uses.
  3. The proxy adds the access token in LD-CLI-Token and forwards to <base-uri>/internal/ldcli-setup-agent/sdk/.... The relay adds the real key. The header does not start with X-LD-, because gonfalon strips client headers with that prefix.
  4. The SDK polls once, evaluates the config with the detected facts as context attributes, and returns the instructions and model. The config's instructions decide the task, and the first message gives only the facts from setup.

A quick check before the SDK starts makes a refusal fall back at once (the Go SDK retries a refused stream until its timeout), and it reads the environment ID from the LD-Setup-Agent-Environment-ID header. The SDK's logging is off, so it does not break the wizard's screen. If the config cannot load, setup uses the built-in instructions.

Testing

A test starts the real AI SDK through the proxy against a fake relay. Other tests cover the proxy (token header, path mapping, secret path, streaming), refusals and an unreachable relay (fallback in less than one second), the options, the context, and the provider mapping. The path was tested end to end against a local gonfalon with the relay stack (launchdarkly/gonfalon#75196 to #75199) and a catfood config.

Diagram

flowchart TD
  setup["setup.go<br/>withConfigSource<br/>runner.Config = source"]:::chg
  oc["opencode.go<br/>Start: Config.Resolve<br/>uses cfg.Task"]:::chg
  aic["aiconfig.go<br/>NewAIConfigSource, start, Close<br/>checkRelay, initQuietClient<br/>Resolve: InspectConfig<br/>configFromAI, openCodeModel"]:::new
  prompt["prompt.go<br/>BuildFacts"]:::chg
  proxy["relay_proxy.go<br/>startRelayProxy<br/>adds LD-CLI-Token"]:::new
  sdk[["go-ai-sdk/aiserver<br/>InitWithClient, InspectConfig"]]:::ext
  relay[["gonfalon relay<br/>/internal/ldcli-setup-agent/sdk"]]:::ext
  setup -->|NewAIConfigSource, Close| aic
  setup -->|sets Config| oc
  oc -->|Resolve task| aic
  aic -->|BuildFacts| prompt
  aic -->|startRelayProxy| proxy
  aic -->|checkRelay| relay
  aic -->|init, inspect| sdk
  sdk -->|polling, events| proxy
  proxy -->|forwards with token| relay
  classDef new fill:#e6f0fa,stroke:#1d6fb8,stroke-width:2px,color:#19202b
  classDef chg fill:#fbf1e1,stroke:#a86a12,stroke-width:2px,color:#19202b
  classDef earlier fill:#ffffff,stroke:#7a8494,stroke-dasharray:5 4,color:#19202b
  classDef ext fill:#eceefa,stroke:#4e5a9c,stroke-width:2px,color:#19202b
Loading

Blue boxes are new files, orange boxes are changed files, dashed boxes are files from an earlier PR, and purple boxes are outside ldcli. A solid arrow goes from the caller to the code that it calls. A dashed arrow shows data that moves without a direct call.

setup.go builds an AIConfigSource from the base URI and the access token, gives it to the runner as its config source, and closes it after the command. When the runner starts, it calls Resolve. The first call starts the proxy from relay_proxy.go, makes a quick check of the relay, and starts the AI SDK client with all its URIs on the proxy. Resolve then calls InspectConfig for ldcli-setup-agent and returns the instructions and model. The first message comes from BuildFacts in prompt.go. If any step fails, Resolve returns the built-in instructions.

This PR plugs a new ConfigSource into the runner from #894. opencode.go changes only to use the task text from the config.

Stack

This is one of six PRs for the ldcli setup agent. Review and merge them in order, after #877 (Go 1.26):

  1. OpenCode adapter
  2. Wizard agent step
  3. macOS sandbox
  4. AI SDK and relay
  5. OpenCode handler
  6. Run fixes

They replace #876 and #878.

🤖 Generated with Claude Code

The setup agent now gets its instructions and model from the
ldcli-setup-agent AI Config on catfood. The CLI evaluates the config
locally with the Go AI SDK, with the detected facts as context
attributes, so targeting can give each kind of project its own
instructions and model. When the config loads, its instructions decide
the task, and the first message gives only the facts from setup.

No SDK key is on the user's machine. The SDK gets the placeholder key
ldcli-placeholder, and a loopback proxy adds the user's access token in
LD-CLI-Token and forwards each request to the relay at
/internal/ldcli-setup-agent/sdk under the user's base URI. The relay
adds the real key. The proxy accepts requests only under a random path.

The SDK client polls once, because setup reads the config once per run.
A quick check before the SDK starts makes a refusal fall back at once,
and it reads the environment ID from the relay. The CLI sets every SDK
option in code, because the SDK reads LD_ variables that ldcli also
uses, and it turns the SDK's logging off.

If the user is not logged in, or the config cannot load, setup uses the
built-in instructions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@atornsii

atornsii commented Oct 20, 2026 •

Copy link
Copy Markdown
Author

Holding in Draft as I wait for the GO AI SDK to be released. As of now it is using a pseudo version.

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.

1 participant