fix(host-service): honor agent config env in ACP chat sessions

RE
3h ago
+993-29

What & why

Fixes #9505.

ACP chat sessions ignored the agent config they were launched with: only harness reached the chat runtime, so every chat ran on the default account's env, and custom configs that run claude/codex were rejected for chat. Two Claude accounts (separated by CLAUDE_CONFIG_DIR per agent config) could run as terminals side by side but not as chats.

Changes:

  • protocol (packages/chat): optional agentConfigId on createSessionInputSchema (additive).
  • chat-runtime: nullable agent_config_id column (0004_session_agent_config, generated with drizzle-kit), stored on the session row and passed in HarnessFactoryOptions. Resume without an explicit id inherits it from the replaced session / latest row for that harness session; fork and rewind copy it.
  • host-service: buildChatAgentEnv layers agentLaunchEnv(config) over the default-account env (same precedence as terminal launches; ambient ANTHROPIC_* keys are still stripped, a key set in the config survives). captureSessionAccount now sees the right config dir. chatLaunchTarget returns the config id and lets custom* configs whose command is claude/codex chat as that preset (local helper; shared resolveAgentLaunchPresetId and terminal launches untouched). sessions.resume reopens on the stored config when it still exists.

Not in this PR: the desktop chat pane's agent picker still identifies agents by preset id, so chats created from the pane UI keep using the default account (resumed ones keep their stored config). Wiring the config id through the renderer is a follow-up: #9507.

Behavior note: a CLI/host chat with --agent claude now resolves the first claude config and applies its env, matching terminal launches.

How I tested it

  • New unit tests: agentEnv.test.ts (default only / config wins incl. own key / deleted config falls back), agents.test.ts (custom claude & codex chat, custom aider doesn't), resumeSession.test.ts (persisted, inherited on harness-only resume, null when absent).
  • bun run lint clean, bun run typecheck 42/42.
  • bun run test: all touched suites pass. Two unrelated failures in the full run: @superset/shared "recurrence timezone math > walks a BYHOUR list that wraps past midnight" (fails identically on unmodified main), and a PullRequestRuntimeManager test that passes 48/48 in isolation (flaky).
  • End-to-end, on a local build of 2.0.6 + this patch (macOS arm64). There were two agent configs, each with its own CLAUDE_CONFIG_DIR: a claude-preset config (work account, ~/.claude-a) and a custom-preset config that runs claude (personal account, ~/.claude-b). I made one chat per config with superset sessions create --local --workspace <ws> --agent <config id> --prompt 'Run: echo $CLAUDE_CONFIG_DIR and reply with only the output.':
    • Work account chat replied ~/.claude-a. Personal account chat replied ~/.claude-b. Before the patch, the work chat printed the default account's dir, and creating the personal chat failed with "cannot be used with ACP chat".
    • Resume: sessions close then sessions resume on the personal chat. The new session kept the same agentConfigId and harness session id, its ACP process had CLAUDE_CONFIG_DIR=~/.claude-b, and the same prompt again replied ~/.claude-b.
    • Both chats were also checked side by side in the app with the same outputs; a redacted screenshot is available on request.
    • Not related to this change: the resumed chat came back in "Ask for approval" mode, so its echo needed approval, while the first turn ran without a prompt.

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass (CI fails on lint warnings too)
  • "Allow edits from maintainers" is checked on fork PRs
  • I have signed the CLA (the bot asks on your first PR)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Chats retain their selected agent configuration when resumed, forked, or rewound, including when multiple chats share an agent session.
    • Supported custom Claude and Codex agents can launch chats with their configured environment and credentials.
    • Session history discovery can use a selected agent configuration.
  • Bug Fixes
    • Chats without a saved configuration continue to use the default environment when reopened.
    • If a saved configuration is deleted or no longer matches the session’s CLI, reopening falls back to the default and displays a notice.
    • Other custom agents remain unavailable as chat launch targets.