fix(cli): load the agent's .env into locally run ACP and worker processes - #515
fix(cli): load the agent's .env into locally run ACP and worker processes#515michaelxu2288 wants to merge 2 commits into
Conversation
…sses The docs say a .env next to manifest.yaml is loaded automatically for local development, but nothing did: agentex agents run built the child environment from os.environ plus the manifest, and EnvironmentVariables.refresh() looks for .env two directories above the installed module (site-packages), never the agent folder. Values in .env only reached a process when some import happened to call load_dotenv() first (litellm does, on import). That is why the OpenAI Agents Temporal template worked (its model client is built lazily after imports) while the Pydantic AI one failed at import time with openai.OpenAIError: Missing credentials. Merge <manifest dir>/.env into the environment handed to both the ACP and worker subprocesses, without overriding variables already set in the shell (python-dotenv semantics). Add tests for merge, shell precedence, and the no-file / no-manifest_dir cases. Claude-Session: https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
| for key, value in dotenv_values(env_file).items(): | ||
| if value is not None and key not in env: | ||
| env[key] = value |
There was a problem hiding this comment.
Dotenv defaults are overwritten
The .env values are loaded before env_vars is built, and the later unconditional env.update(env_vars) replaces overlapping values. For example, a local Temporal project with REDIS_URL=redis://custom:6380 in .env still receives redis://localhost:6379. This makes the new loading behavior ineffective for common runtime settings such as REDIS_URL, TEMPORAL_ADDRESS, and ENVIRONMENT. Please apply dotenv values after the built-in defaults while preserving the intended shell and manifest precedence, and add a regression test for an overlapping key.
Knowledge Base Used: Command-line workflows
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/cli/handlers/run_handlers.py
Line: 423-425
Comment:
**Dotenv defaults are overwritten**
The `.env` values are loaded before `env_vars` is built, and the later unconditional `env.update(env_vars)` replaces overlapping values. For example, a local Temporal project with `REDIS_URL=redis://custom:6380` in `.env` still receives `redis://localhost:6379`. This makes the new loading behavior ineffective for common runtime settings such as `REDIS_URL`, `TEMPORAL_ADDRESS`, and `ENVIRONMENT`. Please apply dotenv values after the built-in defaults while preserving the intended shell and manifest precedence, and add a regression test for an overlapping key.
**Knowledge Base Used:** [Command-line workflows](https://app.greptile.com/scale-ai/-/custom-context/knowledge-base/scaleapi/scale-agentex-python/-/docs/command-line-workflows.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Good catch. Pushed 0a24841: .env is now applied after the built-in local defaults, so a custom REDIS_URL or TEMPORAL_ADDRESS in .env takes effect, while the manifest's env block and variables already set in the shell still win, and ENVIRONMENT stays pinned to development (that is what makes it a local run). Added test_dotenv_overrides_builtin_local_defaults_but_not_environment covering exactly the overlapping-key case; the four env tests pass.
…apping the key The worker is a separate process and agents run does not load the project .env into it today, so the LITELLM_API_KEY -> OPENAI_API_KEY mapping ran against an empty environment. Call load_dotenv() first (as acp.py already does), so the template works on its own; scaleapi#515 makes the CLI load .env for both processes as well. Claude-Session: https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
Loading .env before env_vars meant env.update(env_vars) clobbered any overlapping key, so a custom REDIS_URL or TEMPORAL_ADDRESS in .env had no effect. Apply .env after the defaults, below the manifest env block and the shell, and keep ENVIRONMENT pinned to development; add a regression test. Claude-Session: https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
| if key in os.environ or key in manifest_env: | ||
| continue | ||
| env[key] = value |
There was a problem hiding this comment.
Dotenv overrides manifest settings
A .env entry can now overwrite manifest-derived runtime settings such as AGENT_NAME, ACP_PORT, WORKFLOW_TASK_QUEUE, and HEALTH_CHECK_PORT. These values are added through env_vars, but manifest_env contains only the explicit agent.env mapping. A conflicting dotenv value therefore replaces the manifest-derived value and can start the ACP or worker with the wrong identity, port, task queue, or health-check configuration. Preserve all manifest-derived keys while still allowing .env to replace built-in local defaults.
Knowledge Base Used: Command-line workflows
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agentex/lib/cli/handlers/run_handlers.py
Line: 476-478
Comment:
**Dotenv overrides manifest settings**
A `.env` entry can now overwrite manifest-derived runtime settings such as `AGENT_NAME`, `ACP_PORT`, `WORKFLOW_TASK_QUEUE`, and `HEALTH_CHECK_PORT`. These values are added through `env_vars`, but `manifest_env` contains only the explicit `agent.env` mapping. A conflicting dotenv value therefore replaces the manifest-derived value and can start the ACP or worker with the wrong identity, port, task queue, or health-check configuration. Preserve all manifest-derived keys while still allowing `.env` to replace built-in local defaults.
**Knowledge Base Used:** [Command-line workflows](https://app.greptile.com/scale-ai/-/custom-context/knowledge-base/scaleapi/scale-agentex-python/-/docs/command-line-workflows.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Problem
getting_started/project_structure.mdsays a.envnext tomanifest.yaml"is automatically loaded when placed alongside your manifest.yaml file, but only for local development". Nothing does that today:agentex agents runbuilds the child environment fromos.environplus the manifest (create_agent_environment).EnvironmentVariables.refresh()loads.envfromPath(__file__).parents[2], which issite-packagesfor an installed SDK, never the agent folder, and.env.localfromcwd.parent.ProjectConfigLoader._load_envonly feeds config templating.Values from
.envreach a process only when some import happens to callload_dotenv()first.litellmdoes, on import (litellm/__init__.py), which is why the Temporal + OpenAI Agents template appears to work (its model client is built lazily inside the activity, after imports) while Temporal + Pydantic AI fails at import time ofproject/agent.pywithopenai.OpenAIError: Missing credentials. Verified with a print at the top of both workers: OpenAI Agents worker seesLITELLM_API_KEYonly after its imports; the Pydantic AI worker never does.Fix
create_agent_environment(manifest, manifest_dir)merges<manifest dir>/.env(python-dotenvdotenv_values, already a dependency) into the environment handed to both the ACP and worker subprocesses, without overriding variables already set in the shell (python-dotenv semantics).run_agentpassesmanifest_file.parent. 16-line diff plus three tests (merge, shell precedence, no file / no manifest_dir) that render a real manifest via theinithelpers.Verification
tests/lib/cli/test_run_handlers_env.py: 3 passed; streaming handler tests still pass; ruff clean.LITELLM_API_KEYin.env, patched SDK installed into its venv: before, no reply and Missing credentials; after, reply in 4.7 s, zero worker errors.Pairs with #514 ("fix(templates): map LITELLM_API_KEY to OPENAI_API_KEY in Temporal workers"): once
.envis in the process environment from the start, that mapping at the top ofrun_worker.pybecomes deterministic instead of depending on import order.https://claude.ai/code/session_01HCVKnA7LeJZ44nxZz1uzF3
The PR is not yet safe to merge because
.envcan override runtime identity, port, or workflow settings derived from the manifest.Fix with agent prompt
Summary
agent.enventries.ENVIRONMENTfixed todevelopment.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD S[Shell environment] --> M[Apply manifest-derived settings] M --> D[Apply eligible .env values] D --> E[Child process environment] E --> A[ACP process] E --> W[Temporal worker]Reviews (2) · Last reviewed commit: "fix(cli): apply .env after the built-in ..."