Introduce layered YAML config loader, replaces .env Config which remains for backwards compat (but deprecated)#2342
Merged
Merged
Conversation
Adds a layered YAML configuration loader as the foundation for migrating
TypeAgent off flat .env files. This phase is fully backwards compatible:
the loader populates process.env, so all existing getEnvSetting / EnvVars
consumers in aiclient and elsewhere keep working unchanged.
Package contents:
- flatten: nested YAML to flat EnvVars-shaped keys (with env: / extra:
top-level passthrough so existing flat-key conventions like
AZURE_OPENAI_ENDPOINT_GPT_4_O_EASTUS_PTU work verbatim).
- schema: lightweight zod validation with file-path-aware errors.
- loader: async loadConfig() and sync loadConfigSync() with precedence
.env (legacy) -> config.defaults.yaml -> config.local.yaml ->
process.env. Existing process.env values are preserved.
- 31 unit tests covering flattening, merging, precedence, source
tracking, strict / non-strict modes, and idempotency.
Workspace integration:
- ts/config.defaults.yaml committed with non-secret universal defaults
(max_concurrency, max_timeout, max_retryattempts, response_format).
- ts/.gitignore now excludes config.local.yaml.
Live Azure Key Vault fetch, encrypted on-disk caching, the
typeagent config CLI family (import / push / show / refresh / check /
sync), and the ~40-call-site sweep are added in subsequent phases.
Refs: dev/robgruen/config plan.
Introduces live Key Vault fetch as a new layer in the precedence
chain, sitting between defaults and local YAML per the locked design:
.env (legacy) -> defaults -> Key Vault -> local -> process.env
New module packages/config/src/keyVault.ts:
- DEFAULT_SECRET_NAME = 'typeagent-config'
- makeAzureFetcher(credential): SecretClient-backed fetcher with
per-vault caching, mirroring the auth pattern used by aiclient
and tools/scripts/getKeys.mjs. 404 is treated as a soft miss.
- fetchKeyVaultConfig(options): downloads, validates, parses YAML.
Honors a 25 KiB byte cap matching the Azure secret-size limit.
failOnError defaults to false so transient outages let the loader
fall through to lower layers (offline-friendly).
- Test isolation guard: refuses live SDK calls under Jest unless
TYPEAGENT_ALLOW_KEYVAULT_IN_TESTS=1, or a stub fetcher is
injected. This keeps unit suites hermetic.
Loader integration:
- loadConfig is now a real async loader (no longer a thin wrapper).
- When options.keyVault is provided it splices the KV layer into
the precedence chain at the correct position, then delegates the
final merge / process.env application to a shared helper.
- loadConfigSync ignores keyVault (sync API stays file-only).
Tests (21 new, 52 passing total):
- keyVault.spec.ts: parse, default secret name, missing / empty,
failOnError on / off, oversize, top-level array rejection,
schema validation, isolation guard on / off, env opt-in.
- loaderKeyVault.spec.ts: KV beats defaults, local beats KV, KV
beats .env, missing secret falls through, source-tracking
attribution, no-op when keyVault not provided.
Dependencies: @azure/identity ^4.10.0, @azure/keyvault-secrets ^4.9.0
(version-aligned with packages/aiclient).
Refs: dev/robgruen/config plan, Phase 2.
Lands the user-facing CLI for the new config system. Three commands
now ship; push / refresh / sync are deferred to Phase 2.5 because
they need the encrypted backup path.
New modules:
- src/import.ts: parseDotEnvText / parseDotEnvFile / importDotEnv /
flatEnvToConfigTree / writeConfigYamlFile. The importer places
every flat key into the 'extra:' passthrough bucket, which
guarantees a byte-identical round trip through flatten().
Round-trip equivalence is verified before the file is written;
failure throws. Structured rewriting (e.g., AZURE_OPENAI_* into
nested form) lands incrementally on top of this safety net.
- src/redact.ts: shouldRedact / redactFlat / redactTree. Pattern
based on /key|secret|password|token|credential/i, with explicit
allow-list for the 'identity' managed-identity sentinel and
empty strings. Used by 'show' (default) and 'check'.
- src/cli.ts: pluggable runCli(argv, io) entry point. CliIO
interface lets tests capture stdout / stderr without touching
the real streams. Subcommands:
import <path/to/.env> [--out <yaml>] (default ./config.local.yaml)
show [--source] [--reveal-secrets]
check [--vault <name>] [--secret <s>]
- bin/typeagent-config.mjs: thin shim that invokes runCli.
Package wiring:
- package.json gains 'bin: typeagent-config' and an './cli' subpath
export so other packages can call runCli programmatically.
- 'bin/' added to the published 'files' list.
- index.ts re-exports the importer, redactor, and CLI surface.
Tests (34 new, 86 passing total):
- import.spec.ts: dotenv parsing, extra-bucket placement, round
trip through flatten, end-to-end import file → tree, missing-file
error.
- redact.spec.ts: secret-key detection, identity / empty allow
list, non-string passthrough, deep tree redaction, no mutation.
- cli.spec.ts: help + unknown commands, import success path with
YAML output assertions, missing-file error, unknown flag handling
for each subcommand, check vault-name requirement.
Refs: dev/robgruen/config plan, Phase 2.7 (push / refresh / sync
deferred to Phase 2.5).
…ens for newer models
…peAgent into dev/robgruen/config
…peAgent into dev/robgruen/config
…tEmbedding" endpoint selection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request migrates the configuration system from legacy
.envfiles to a new, more flexible YAML-based approach usingconfig.local.yaml, powered by the@typeagent/configpackage. It updates documentation, adds sample and default config files, and refactors all example projects to use the new configuration loader. Legacy.envfiles are now deprecated and will be removed after September 2026.