Skip to content

fix: VMware Tanzu Platform provider - bug fixes, streaming, UI improvements#8126

Merged
DOsinga merged 4 commits intoblock:mainfrom
nkuhn-vmw:feat/tanzu-ai-provider
Mar 26, 2026
Merged

fix: VMware Tanzu Platform provider - bug fixes, streaming, UI improvements#8126
DOsinga merged 4 commits intoblock:mainfrom
nkuhn-vmw:feat/tanzu-ai-provider

Conversation

@nkuhn-vmw
Copy link
Copy Markdown
Contributor

Summary

This PR fixes several bugs and adds improvements to the VMware Tanzu Platform (formerly "Tanzu AI Services") provider that was merged in v1.28.0. We apologize for not catching these issues in the initial PR — they surfaced during hands-on validation across macOS, Linux (Ubuntu 22.04), and Windows 11 with both single-model and multi-model Tanzu AI Services plans.

Bug Fixes

  • Env var expansion at wrong time${TANZU_AI_ENDPOINT} was expanded at provider registration (startup), before the user configured the provider via the UI. The expansion silently failed, leaving the raw placeholder in the base URL, causing Invalid base URL '${TANZU_AI_ENDPOINT}/openai/v1/chat/completions': relative URL without a base. Fixed by moving expansion into a lazy closure that runs at provider instantiation time.

  • Missing API key silently ignoredOpenAiProvider::from_custom_config() used .ok() on the secret lookup, falling back to NoAuth. Users got cryptic 401 errors instead of a clear message. Now returns: "Required API key TANZU_AI_API_KEY is not set. Configure it via goose configure or set the TANZU_AI_API_KEY environment variable."

  • Required TANZU_AI_ENDPOINT hidden in UI — All env_vars config keys were hardcoded to primary=false, hiding required fields in a collapsed "Show options" section. Added primary field to EnvVarConfig struct, defaulting to the value of required when unset.

  • Input backspace buggetRenderValue() returned undefined for secret fields and fell back to serverValue for non-secret fields when the user cleared the input (empty string is falsy in JS). This caused the input to snap back to the stored URL and broke backspace on Linux. Fixed by checking entry?.value !== undefined instead of truthy check.

Improvements

  • Renamed from "Tanzu AI Services" to "VMware Tanzu Platform" with updated description: "Enterprise-managed LLM access through AI Services on VMware Tanzu Platform."
  • Streaming enabled by default (supports_streaming: true) with a user-toggleable TANZU_AI_STREAMING config parameter
  • Boolean config keys render as checkboxes — Any env_var with a "true"/"false" default now renders as a checkbox toggle instead of a text input (generic improvement, benefits all declarative providers)
  • VMware Tanzu logo added to provider UI (3 resolutions: 43px, 86px, 128px)
  • Documentation — Full getting-started guide with validated CF CLI commands, CLI testing guide, and Windows build script

Files Changed

File Change
declarative_providers.rs Lazy env var expansion, primary field on EnvVarConfig, resolve_config() with streaming override, updated tests
tanzu.json Renamed, streaming enabled, TANZU_AI_STREAMING env var with primary: true
openai.rs Explicit API key error instead of silent .ok()
provider_registry.rs primary defaults to required for env_var config keys
init.rs Updated test assertion for new display name
DefaultProviderSetupForm.tsx Fixed backspace bug, added boolean checkbox rendering
ProviderLogo.tsx Added tanzu_ai logo mapping
tanzu*.png VMware Tanzu logo icons (3 resolutions)
providers.md Updated provider table entry
tanzu-ai-services.md Full getting-started guide (CF CLI, Desktop, CLI)
tanzu-cli-testing-guide.md CLI validation guide
build-windows.ps1 Windows build script

Test Plan

Extensive manual testing was performed across all three platforms with real VMware Tanzu Platform environments:

Environments Tested

  • macOS (Apple Silicon, arm64) — Goose Desktop + CLI
  • Ubuntu Linux 22.04 (x86_64) — Goose Desktop (.deb) + CLI
  • Windows 11 (x86_64) — Goose Desktop

Tanzu Plans Tested

  • Single-model plan (tanzu-Qwen3-Coder-30B-A3B-vllm-v1) — Qwen/Qwen3-Coder-30B-A3B-Instruct-FP8
  • Multi-model plan (tanzu-all-models) — 4 models including Qwen3-Coder, gpt-oss-120b, gpt-oss-20b, nomic-embed

Functional Tests

  • Provider appears in provider list with correct name and logo
  • TANZU_AI_ENDPOINT field visible above the fold (not hidden)
  • Streaming checkbox visible and checked by default
  • Dynamic model fetching from endpoint (/openai/v1/models)
  • Chat completions work with streaming enabled
  • Chat completions work with streaming disabled
  • Switching between single-model and multi-model endpoints
  • CLI: goose session with env vars (TANZU_AI_ENDPOINT, TANZU_AI_API_KEY)
  • CLI: Multiple models on same endpoint (Qwen3-Coder, gpt-oss-120b)
  • Clear error message when API key is missing
  • Clear error message when endpoint is missing
  • Input fields can be fully cleared and retyped (backspace works on Linux)
  • Curl verification of models, chat, and streaming endpoints

CF CLI Validation (end-to-end)

  • cf marketplace -e genai — lists plans
  • cf create-service genai <plan> <name> --wait — creates instance
  • cf create-service-key <instance> <key> --wait — creates credentials
  • cf service-key <instance> <key> — retrieves credentials
  • Credential JSON structure validated for both single-model and multi-model plans
  • Cleanup: cf delete-service-key and cf delete-service

Automated Tests

  • test_tanzu_json_deserializes — JSON config parsing
  • test_tanzu_declarative_provider_registry_wiring — provider registration
  • test_expand_env_vars_* — all 6 env var expansion tests
  • test_existing_json_files_still_deserialize_without_new_fields — backwards compatibility
  • test_openai_compatible_providers_config_keys — config key wiring
  • Full workspace cargo check — clean

🤖 Generated with Claude Code

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fba205de08

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +418 to +420
.get_param::<String>(&var.name)
.ok()
.or_else(|| var.default.clone());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Parse streaming override as bool

resolve_config reads *_STREAMING with get_param::<String>(), but config/env parsing can return native booleans for values like TANZU_AI_STREAMING=false. In that case deserialization to String fails, .ok() drops the override, and the code falls back to the default ("true" in tanzu.json), so users cannot disable streaming via normal environment variable syntax.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed — resolve_config now tries get_param:: first, then falls back to get_param::, so both YAML string "true" and native bool true are handled correctly.

}

function getBooleanValue(parameter: ConfigKey): boolean {
const val = getRenderValue(parameter).toLowerCase();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize boolean config before calling toLowerCase

The form assumes getRenderValue() always returns a string, but read() can yield booleans (for example when config/env contains unquoted true/false). When that happens, getRenderValue(parameter) can be a boolean and toLowerCase() throws at runtime, breaking provider configuration UI for those users.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed — getBooleanValue now wraps the value with String() before calling toLowerCase(), handling both string and native boolean returns from config.

@nkuhn-vmw nkuhn-vmw force-pushed the feat/tanzu-ai-provider branch from fba205d to fd2973f Compare March 26, 2026 00:31
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd2973fdb2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +153 to +155
Some(global_config.get_secret::<String>(&config.api_key_env).map_err(|_| {
anyhow::anyhow!(
"Required API key {} is not set. Configure it via `goose configure` or set the {} environment variable.",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve secret-read errors when loading API key

This map_err(|_| ...) rewrites every get_secret failure into "API key is not set", including non-NotFound cases like keyring access failures or deserialization errors. In those cases users get a misleading remediation path and lose the real root cause, which makes provider setup/debugging much harder. Please only translate NotFound into this friendly message and propagate other error variants unchanged.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Fixed — map_err now matches on ConfigError::NotFound to give the friendly "not set" message, and propagates all other error variants (keyring failures, deserialization errors, etc.) with their original context.

Comment on lines +101 to +104
if ($LASTEXITCODE -ne 0) {
Write-Host "Make failed! Trying with squirrel only..." -ForegroundColor Yellow
npx electron-forge make --targets=@electron-forge/maker-squirrel
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exit script when fallback installer build fails

When electron-forge make fails, the fallback make --targets=@electron-forge/maker-squirrel is executed but its exit code is never checked. If that fallback also fails (e.g., missing maker dependency), the script still continues to "Build Complete" and exits successfully, which can silently produce no installer in automation or manual release workflows.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed — the fallback build now checks LASTEXITCODE and exits with error if it also fails.

@nkuhn-vmw nkuhn-vmw force-pushed the feat/tanzu-ai-provider branch from fd2973f to f97a328 Compare March 26, 2026 12:17
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f97a328da2

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +153 to +154
if (val === '' && parameter.default) {
return parameter.default.toLowerCase() === 'true';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve false values for boolean provider toggles

Boolean config values read as native false get collapsed to an empty render value and then this fallback path applies the default, so a stored false (for example TANZU_AI_STREAMING=false from config/env) is shown as checked and can be written back as true on submit. This makes the new streaming toggle unreliable for users who explicitly disabled it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — native bool false was indeed falsy and got collapsed to empty string. Fixed by using explicit String() conversion on serverValue instead of the || operator.

Comment on lines +83 to +84
pnpm run generate-api
Write-Host " API types generated." -ForegroundColor Green
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail fast when API type generation exits non-zero

The script does not check $LASTEXITCODE after pnpm run generate-api, so a generator failure is treated as success and the build continues into packaging/installer steps with stale or missing generated API types. This can silently produce broken release artifacts in CI or manual release runs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added LASTEXITCODE check after generate-api step.

…ements

- Fix lazy env var expansion (resolve at instantiation, not registration)
- Fix API key error handling (explicit error instead of silent 401)
- Fix input backspace bug (controlled component for all fields)
- Rename to "VMware Tanzu Platform" with updated description
- Enable streaming with user-toggleable checkbox
- Add VMware Tanzu logo to provider UI
- Add primary field to EnvVarConfig for UI visibility
- Add boolean parameter rendering as checkboxes in provider form
- Regenerate OpenAPI schema for EnvVarConfig.primary field
- Add CLI testing guide and user documentation
- Add Windows build script

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: Nick Kuhn <[email protected]>
@nkuhn-vmw nkuhn-vmw force-pushed the feat/tanzu-ai-provider branch from f97a328 to 2fa76f7 Compare March 26, 2026 13:55
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2fa76f7cd4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

---
sidebar_position: 15
title: VMware Tanzu Platform
description: Connect Goose to VMware Tanzu Platform AI Services
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use lowercase goose in docs copy

documentation/AGENTS.md requires the product name to always be written as lowercase goose within the documentation tree, but this new guide introduces Goose in user-facing text (and repeats it in multiple places), which violates the documented style contract for this directory and should be normalized before merge.

Useful? React with 👍 / 👎.

Comment on lines +158 to +159
if (val === '' && parameter.default) {
return parameter.default.toLowerCase() === 'true';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve explicit false for boolean provider toggles

This default branch makes an empty render value fall back to the parameter default, so users with an explicit false value can be shown true and have that written back on submit. Fresh evidence: loadConfigValues still gates assignment with if (configValue), so when /config/read returns JSON false (for example TANZU_AI_STREAMING: false), the stored value is dropped before the new boolean rendering path runs, and this fallback re-enables the toggle.

Useful? React with 👍 / 👎.

Douwe Osinga added 2 commits March 26, 2026 10:09
- loadConfigValues: preserve explicit false from server (if (configValue)
  dropped native boolean false, causing stored TANZU_AI_STREAMING=false to
  be replaced by the default true on next load)
- docs: lowercase goose per documentation/AGENTS.md brand guidelines
- remove binary .docx file (does not belong in source repo)

Signed-off-by: Douwe Osinga <[email protected]>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d6aa6b75d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


## Prerequisites

- Goose CLI built from the `feat/tanzu-ai-provider` branch
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use lowercase goose in docs per style guide

documentation/AGENTS.md requires the product name to be written as lowercase goose throughout the documentation tree, but this new guide uses Goose in user-facing copy (for example, in the prerequisites line here, and again later in the file). This violates the documented docs standard and should be normalized before merge.

Useful? React with 👍 / 👎.

@DOsinga DOsinga added this pull request to the merge queue Mar 26, 2026
Merged via the queue into block:main with commit c936514 Mar 26, 2026
24 checks passed
michaelneale added a commit that referenced this pull request Mar 26, 2026
* main: (337 commits)
  fix: replace panics with user-friendly errors in CLI session builder (#7901)
  fix: read GOOSE_CONTEXT_LIMIT from config.yaml, not just env vars (#7900)
  fix: deliver truncation notice as separate content block (#7899)
  fix: use platform-appropriate commands in developer extension instructions (#7898)
  fix: replace any with proper SVG types in icon components (#7873)
  chore: remove debug console.log statements, stale comments, and dead code (#8142)
  feat: Gemini OAuth provider (#8129)
  chore(deps): bump picomatch from 2.3.1 to 2.3.2 in /documentation (#8123)
  feat: show installed skills in UI (#7910)
  fix(deps): gate keyring platform features behind target-specific deps (#8039)
  chore(deps): bump yaml from 2.8.2 to 2.8.3 in /evals/open-model-gym/suite (#8124)
  fix: strip message wrapper in CLI session title generation (#7996)
  fix(providers): fall back to configured models when models endpoint fetch fails (#7530)
  chore(deps): bump brace-expansion from 5.0.3 to 5.0.5 in /evals/open-model-gym/suite (#8139)
  fix: prevent Ollama provider from hanging on tool-calling requests (#7723)
  fix: VMware Tanzu Platform provider - bug fixes, streaming, UI improvements (#8126)
  feat: allow GOOSE_CLI_SHOW_THINKING to be set in config.yaml (#8097)
  fix: GitHub Copilot auth fails to open browser in Desktop app (#6957) (#8019)
  fix(ci): produce .tar.gz archives for Zed ACP registry compatibility (#8054)
  feat: add GOOSE_SHOW_FULL_OUTPUT config to disable tool output truncation (#7919)
  ...

# Conflicts:
#	crates/goose/src/providers/formats/openai.rs
hydrosquall pushed a commit to hydrosquall/goose that referenced this pull request Mar 31, 2026
…ements (block#8126)

Signed-off-by: Nick Kuhn <[email protected]>
Signed-off-by: Douwe Osinga <[email protected]>
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Co-authored-by: Douwe Osinga <[email protected]>
Signed-off-by: Cameron Yick <[email protected]>
blackgirlbytes pushed a commit that referenced this pull request Apr 2, 2026
* main: (337 commits)
  fix: replace panics with user-friendly errors in CLI session builder (#7901)
  fix: read GOOSE_CONTEXT_LIMIT from config.yaml, not just env vars (#7900)
  fix: deliver truncation notice as separate content block (#7899)
  fix: use platform-appropriate commands in developer extension instructions (#7898)
  fix: replace any with proper SVG types in icon components (#7873)
  chore: remove debug console.log statements, stale comments, and dead code (#8142)
  feat: Gemini OAuth provider (#8129)
  chore(deps): bump picomatch from 2.3.1 to 2.3.2 in /documentation (#8123)
  feat: show installed skills in UI (#7910)
  fix(deps): gate keyring platform features behind target-specific deps (#8039)
  chore(deps): bump yaml from 2.8.2 to 2.8.3 in /evals/open-model-gym/suite (#8124)
  fix: strip message wrapper in CLI session title generation (#7996)
  fix(providers): fall back to configured models when models endpoint fetch fails (#7530)
  chore(deps): bump brace-expansion from 5.0.3 to 5.0.5 in /evals/open-model-gym/suite (#8139)
  fix: prevent Ollama provider from hanging on tool-calling requests (#7723)
  fix: VMware Tanzu Platform provider - bug fixes, streaming, UI improvements (#8126)
  feat: allow GOOSE_CLI_SHOW_THINKING to be set in config.yaml (#8097)
  fix: GitHub Copilot auth fails to open browser in Desktop app (#6957) (#8019)
  fix(ci): produce .tar.gz archives for Zed ACP registry compatibility (#8054)
  feat: add GOOSE_SHOW_FULL_OUTPUT config to disable tool output truncation (#7919)
  ...

# Conflicts:
#	crates/goose/src/providers/formats/openai.rs
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.

2 participants