Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions desktop/scripts/check-file-sizes.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,17 @@ const overrides = new Map([
// linux-updater isAutoUpdateSupported() binding + onboarding has_profile_event field.
// config-bridge-aware requirements: getRuntimeFileConfig command adds ~15 lines.
// +26 lines from PRs landing on main between prior rebase and this rebase.
["src/shared/api/tauri.ts", 1375],
// baked-env-required-badge: getBakedBuildEnvKeys wrapper adds ~16 lines. Queued to split.
["src/shared/api/tauri.ts", 1388],
// readiness-gate: PersonaDialog.tsx threads computeLocalModeGate +
// requiredCredentialEnvKeys + RequiredFieldLabel so the "New agent" dialog
// shows required markers and credential amber rows (parity with
// CreateAgentDialog). +23 lines of gate wiring. Queued to split.
// config-bridge-aware requirements: useRuntimeFileConfigQuery wiring adds
// ~16 lines. Queued to split.
["src/features/agents/ui/PersonaDialog.tsx", 1032],
// baked-env-required-badge: useBakedBuildEnvKeysQuery + bakedEnvKeys wiring
// + correct exclusion-semantics for requiredEnvKeys adds ~14 lines. Queued to split.
["src/features/agents/ui/PersonaDialog.tsx", 1046],
// harness-persona-sync feature growth, queued to split in the resolver-unify
// refactor followup. discovery.rs is dominated by the new test module
// (the effective_agent_command / divergent / create-time override matrix);
Expand Down
21 changes: 21 additions & 0 deletions desktop/src-tauri/src/commands/agent_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,27 @@ pub fn get_runtime_file_config(runtime_id: String) -> Option<RuntimeFileConfigSu
}
}

/// Return the key names of all non-empty baked build env vars.
///
/// Internal (Block) builds bake provider credentials and other env pairs into
/// the binary at compile time via `BUZZ_BUILD_AGENT_ENV`. The backend readiness
/// gate already treats these keys as satisfying their requirements (Layer 1 of
/// `resolve_effective_agent_env`). This command exposes the *key names only* —
/// never the values — so the frontend dialogs can apply the same logic and avoid
/// surfacing a spurious "Required" badge for keys that are covered by the baked
/// env.
///
/// OSS builds have no baked env, so this returns an empty list — OSS behavior
/// is unchanged.
#[tauri::command]
pub fn get_baked_build_env_keys() -> Vec<String> {
crate::managed_agents::baked_build_env()
.into_iter()
.filter(|(_, v)| !v.is_empty())
.map(|(k, _)| k)
.collect()
}

/// Get the full config surface for a managed agent.
///
/// Returns normalized + advanced config from all available tiers.
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ pub fn run() {
discover_agent_models,
get_agent_config_surface,
get_runtime_file_config,
get_baked_build_env_keys,
put_agent_session_config,
mesh_availability,
mesh_start_node,
Expand Down
4 changes: 3 additions & 1 deletion desktop/src-tauri/src/managed_agents/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
mod agent_env;
pub(crate) mod agent_events;
pub(crate) use agent_env::{build_buzz_agent_provider_defaults, discovery_env_with_baked_floor};
pub(crate) use agent_env::{
baked_build_env, build_buzz_agent_provider_defaults, discovery_env_with_baked_floor,
};
mod backend;
pub(crate) mod config_bridge;
mod discovery;
Expand Down
26 changes: 26 additions & 0 deletions desktop/src/features/agents/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
discoverBackendProviders,
discoverManagedAgentPrereqs,
getAgentConfigSurface,
getBakedBuildEnvKeys,
getManagedAgentLog,
getRuntimeFileConfig,
installAcpRuntime,
Expand Down Expand Up @@ -647,6 +648,31 @@ export function useRuntimeFileConfigQuery(
});
}

export const bakedBuildEnvKeysQueryKey = ["baked-build-env-keys"] as const;

/**
* Query the key names of baked build env vars.
*
* Internal (Block) builds bake provider credentials into the binary at compile
* time. This query returns the *key names only* so dialogs can treat baked keys
* as satisfying their requirements — mirroring the backend readiness gate.
*
* The value is a compile-time constant, so `staleTime: Infinity` is correct.
* In web-dev and E2E contexts where the Tauri command doesn't exist the query
* fails soft and resolves to `undefined` without crashing (same class as
* `useRuntimeFileConfigQuery`).
*/
export function useBakedBuildEnvKeysQuery(options?: { enabled?: boolean }) {
return useQuery({
queryKey: bakedBuildEnvKeysQueryKey,
queryFn: () => getBakedBuildEnvKeys(),
enabled: options?.enabled ?? true,
staleTime: Infinity,
refetchInterval: false,
retry: false,
});
}

export function useTeamsQuery() {
return useQuery({
queryKey: teamsQueryKey,
Expand Down
41 changes: 30 additions & 11 deletions desktop/src/features/agents/ui/CreateAgentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
useAcpRuntimesQuery,
useAvailableAcpRuntimes,
useBackendProvidersQuery,
useBakedBuildEnvKeysQuery,
useCreateManagedAgentMutation,
useManagedAgentPrereqsQuery,
useRuntimeFileConfigQuery,
Expand Down Expand Up @@ -41,6 +42,7 @@ import { meshPrepareRelayMeshClient } from "@/shared/api/tauriMesh";
import type { MeshServeTarget } from "@/shared/api/tauriMesh";
import { useLastRuntime } from "@/features/agents/lib/useLastRuntime";
import {
getBakedSatisfiedEnvKeys,
requiredCredentialEnvKeys,
runtimeSupportsLlmProviderSelection,
shouldClearKnownModelForSelectionScope,
Expand Down Expand Up @@ -182,28 +184,45 @@ export function CreateAgentDialog({
selectedRuntimeId,
{ enabled: open },
);
const { data: bakedEnvKeys } = useBakedBuildEnvKeysQuery({ enabled: open });

// All required keys for the selected runtime + provider.
const allRequiredEnvKeys = React.useMemo(
() =>
requiredCredentialEnvKeys(
selectedRuntimeId,
runtimeSupportsLlmProviderSelection(selectedRuntimeId) ? provider : "",
),
[selectedRuntimeId, provider],
);

// Keys covered by the baked build env (Block-internal builds only) — silenced,
// produce no amber row or info row.
const bakedSatisfiedEnvKeys = React.useMemo(
() => getBakedSatisfiedEnvKeys(allRequiredEnvKeys, envVars, bakedEnvKeys),
[allRequiredEnvKeys, envVars, bakedEnvKeys],
);

// Credential keys satisfied by the runtime file config (e.g. goose config.yaml).
// These are shown as "Set in goose config" rows rather than amber required rows.
const fileSatisfiedEnvKeys = React.useMemo(() => {
if (!runtimeFileConfig) return [] as string[];
const allKeys = requiredCredentialEnvKeys(
selectedRuntimeId,
runtimeSupportsLlmProviderSelection(selectedRuntimeId) ? provider : "",
);
return allKeys.filter(
return allRequiredEnvKeys.filter(
(key) =>
(envVars[key] ?? "").length === 0 &&
!bakedSatisfiedEnvKeys.includes(key) &&
runtimeFileConfig.satisfiedEnvKeys.includes(key),
);
}, [runtimeFileConfig, selectedRuntimeId, provider, envVars]);
}, [runtimeFileConfig, allRequiredEnvKeys, envVars, bakedSatisfiedEnvKeys]);

const requiredEnvKeys = React.useMemo(
() =>
requiredCredentialEnvKeys(
selectedRuntimeId,
runtimeSupportsLlmProviderSelection(selectedRuntimeId) ? provider : "",
).filter((key) => !fileSatisfiedEnvKeys.includes(key)),
[selectedRuntimeId, provider, fileSatisfiedEnvKeys],
allRequiredEnvKeys.filter(
(key) =>
!bakedSatisfiedEnvKeys.includes(key) &&
!fileSatisfiedEnvKeys.includes(key),
),
[allRequiredEnvKeys, bakedSatisfiedEnvKeys, fileSatisfiedEnvKeys],
);

// Clear model when provider scope changes, mirroring EditAgentDialog.
Expand Down
24 changes: 19 additions & 5 deletions desktop/src/features/agents/ui/PersonaDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
CUSTOM_PROVIDER_DROPDOWN_VALUE,
computeLocalModeGate,
formatRuntimeOptionLabel,
getBakedSatisfiedEnvKeys,
getDefaultLlmProviderLabel,
getDefaultPersonaRuntime,
getModelSelectValue,
Expand All @@ -69,7 +70,7 @@ import {
MODEL_DISCOVERY_LOADING_VALUE,
usePersonaModelDiscovery,
} from "./usePersonaModelDiscovery";
import { useRuntimeFileConfigQuery } from "../hooks";
import { useBakedBuildEnvKeysQuery, useRuntimeFileConfigQuery } from "../hooks";

type PersonaDialogProps = {
open: boolean;
Expand Down Expand Up @@ -431,7 +432,9 @@ export function PersonaDialog({
const { data: runtimeFileConfig } = useRuntimeFileConfigQuery(runtime, {
enabled: open,
});
const { data: bakedEnvKeys } = useBakedBuildEnvKeysQuery({ enabled: open });
const localModeGate = computeLocalModeGate({
bakedEnvKeys,
envVars,
isProviderMode: false,
model,
Expand All @@ -440,12 +443,23 @@ export function PersonaDialog({
runtimeFileConfig,
useMesh: false,
});
// Required keys for EnvVarsEditor amber rows: exclude file-satisfied keys
// so they render in the "Set in goose config" row instead.
const requiredEnvKeys = requiredCredentialEnvKeys(
// Required keys for EnvVarsEditor amber locked rows: all required keys except
// those silenced by baked env or file config. Filled keys stay in the amber
// row (exclusion semantics, not missing-only), matching the other consumers.
const allRequiredEnvKeys = requiredCredentialEnvKeys(
runtime,
trimmedProvider,
).filter((key) => !localModeGate.fileSatisfiedEnvKeys.includes(key));
);
const bakedSatisfiedPersonaKeys = getBakedSatisfiedEnvKeys(
allRequiredEnvKeys,
envVars,
bakedEnvKeys,
);
const requiredEnvKeys = allRequiredEnvKeys.filter(
(key) =>
!bakedSatisfiedPersonaKeys.includes(key) &&
!localModeGate.fileSatisfiedEnvKeys.includes(key),
);
// Provider required-ness is a static property of the runtime — it does not
// change based on whether the field is currently filled. Using the dynamic
// missingNormalizedFields check would flip the asterisk off once a value is
Expand Down
Loading
Loading