Skip to content

Create agent llm-provider configuration when creating the agent#605

Open
menakaj wants to merge 7 commits intowso2:mainfrom
menakaj:agent-llm-config-create
Open

Create agent llm-provider configuration when creating the agent#605
menakaj wants to merge 7 commits intowso2:mainfrom
menakaj:agent-llm-config-create

Conversation

@menakaj
Copy link
Copy Markdown
Contributor

@menakaj menakaj commented Mar 20, 2026

Purpose

Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.

Fixes #575

Screenshot 2026-03-20 at 12 50 54

Env variable uniqueness validation
Screenshot 2026-03-20 at 14 21 04

Goals

Describe the solutions that this feature/fix will introduce to resolve the problems described above

Approach

Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.

User stories

Summary of user stories addressed by this change>

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter �N/A� plus brief explanation of why there�s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type �Sent� when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type �N/A� and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

  • New Features

    • Agent creation now supports per-environment LLM model configurations and environment-specific variables; new UI to add/manage LLM providers and guardrails.
  • Improvements

    • Stronger validation (reserved-name and duplicate detection), create/submit disabled on LLM variable conflicts, name helper text changed to “Validating name...”.
    • Backend flow now creates LLM config records during agent creation and performs cleanup/rollback on failure.
  • Documentation/Types

    • API schema and client types updated to include modelConfig; payload builder and console types adjusted.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds optional per-environment LLM model configuration to agent creation: OpenAPI/schema and generated Go models added, agent manager creates LLM configs with rollback on failure, DI wiring adjusted, and frontend UI, form state, and payload builder updated to select and submit provider/guardrail/env-variable mappings.

Changes

Cohort / File(s) Summary
OpenAPI Schema & Generated Go Models
agent-manager-service/docs/api_v1_openapi.yaml, agent-manager-service/spec/model_create_agent_request.go, agent-manager-service/spec/model_model_config_request.go
Added modelConfig: ModelConfigRequest[] to CreateAgentRequest; introduced ModelConfigRequest schema and generated Go model, JSON (un)marshallers, nullable helper, and accessor/mutator methods.
Backend Service Logic
agent-manager-service/services/agent_manager.go
Injected agentConfigurationService; added createAgentLLMConfigs, conversion helpers, and conditional creation of LLM configs during CreateAgent with best-effort secret and component rollback on errors.
Dependency Injection / Wiring
agent-manager-service/wiring/wire_gen.go
Rewired to construct agentConfigurationService and dependent LLM/proxy/deployment services earlier and inject it into agentManagerService.
TypeScript Types
console/workspaces/libs/types/src/api/agents.ts
Added ModelConfigRequest interface and extended AgentRequestBase/CreateAgentRequest with optional modelConfig?: ModelConfigRequest[].
Frontend — LLM Provider UI & Form Integration
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx, .../forms/InternalAgentForm.tsx, .../form/schema.ts, .../components/EnvironmentVariable.tsx, .../components/CreateButtons.tsx
Added new LLMProviderSection and LLMProviderFormEntry type; threaded llmProviders state through InternalAgentForm; pass reserved names to env editor; detect variable name conflicts and disable submit when conflicts exist.
Frontend — Payload Builder
console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts
Added buildOneModelConfig and buildModelConfig; updated buildAgentCreationPayload signature to accept llmProviders and include modelConfig when present, mapping guardrails→policies and env var names.
Minor Frontend & Dependency Edits
console/workspaces/pages/add-new-agent/package.json, .../ExternalAgentFlow.tsx, .../ExternalAgentForm.tsx, .../ProjectForm.tsx, .../components/EnvironmentVariable.tsx
Added workspace dependency @agent-management-platform/llm-providers; small UI text change (“Generating name...” → “Validating name...”); minor formatting and Add button size tweak; EnvironmentVariable accepts llmReservedNames.

Sequence Diagram

sequenceDiagram
    participant UI as Client/UI
    participant Form as InternalAgentForm
    participant Builder as buildAgentPayload
    participant AMS as AgentManagerService
    participant ACS as AgentConfigurationService
    participant OC as OpenChoreo

    UI->>Form: submit(formData + llmProviders)
    Form->>Builder: buildAgentCreationPayload(...)
    Builder-->>UI: CreateAgentRequest (includes modelConfig)
    UI->>AMS: POST CreateAgent(req)
    AMS->>AMS: create base agent
    alt modelConfig present
        AMS->>ACS: createAgentLLMConfigs(ModelConfig[])
        ACS-->>AMS: success
    else LLM config error
        ACS-->>AMS: error
        AMS->>AMS: best-effort cleanup secrets
        AMS->>OC: DeleteComponent(agent)
        OC-->>AMS: deleted
        AMS-->>UI: error
    end
    AMS->>OC: publish agent
    OC-->>AMS: result
    AMS-->>UI: response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A little rabbit hops through code and log,
Adds providers, guardrails, and envs in a jog.
One form, one deploy, configs stitched in line,
Rollbacks ready if errors opine.
Hop—agents and LLMs now deploy fine!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete. While it references issue #575 with supporting screenshots, all substantive template sections (Goals, Approach, User stories, Release note, Documentation, etc.) are left blank/unfilled. Complete the PR description by filling in Goals, Approach, User stories, Release note, Documentation, Training, Certification, Marketing, Automation tests, Security checks, Samples, Related PRs, Migrations, Test environment, and Learning sections.
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding LLM provider configuration during agent creation, which directly addresses the PR's primary objective.
Linked Issues check ✅ Passed The code changes comprehensively implement the objective from #575: enabling LLM provider configuration during agent creation through backend model config generation, frontend UI components, payload building, and dependency injection.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to implementing LLM provider configuration during agent creation. Minor UI text updates ('Generating name' to 'Validating name') and formatting adjustments are reasonable refactoring within scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@menakaj menakaj force-pushed the agent-llm-config-create branch from 01ac35c to 5f1dedc Compare March 20, 2026 07:24
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

do we need this?

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
console/workspaces/Untitled (1)

1-1: Remove accidental workspace artifact from the PR.

console/workspaces/Untitled appears to be a stray file unrelated to the feature and should not be committed.

Suggested cleanup
-API Key Generated
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/Untitled` at line 1, Remove the accidental workspace
artifact named "Untitled" from the PR: delete the file from the branch (unstage
and remove from git), amend or create a new commit without it, and push the
updated commit to the PR; also check for any other stray console workspace files
and, if these files are generated regularly, add an appropriate rule to
.gitignore to prevent future accidental commits.
console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx (1)

24-24: Unused import: LLMProviderFormEntry.

The LLMProviderFormEntry type is imported but not used anywhere in this file. External agent flow doesn't include LLM provider configuration based on the PR design.

🧹 Proposed fix to remove unused import
-import { ConnectAgentFormValues, LLMProviderFormEntry } from "../form/schema";
+import { ConnectAgentFormValues } from "../form/schema";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx` at
line 24, Remove the unused type import LLMProviderFormEntry from the import
statement that currently imports ConnectAgentFormValues and LLMProviderFormEntry
(the line importing from "../form/schema"); keep ConnectAgentFormValues only so
the file no longer imports unused symbols.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@agent-manager-service/docs/api_v1_openapi.yaml`:
- Around line 6401-6406: The environmentVariables array schema lacks the same
duplicate-key validation note as
CreateAgentModelConfigRequest.environmentVariables; update the OpenAPI docs for
the environmentVariables property (the array under environmentVariables and its
items referencing EnvironmentVariableConfig) to document that duplicate keys are
rejected with a 400 error (in addition to uniqueItems: true), e.g., add a
description sentence or validation note stating "Duplicate environment variable
keys are rejected with 400" so the contract matches the standalone model-config
API.

In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 332-349: The default env-var values for new provider entries are
not unique and not validated: update the logic that sets entry.urlVarName and
entry.apikeyVarName (the places that render TextField with
value={entry.urlVarName ?? `${agentNameUpper}_URL`} and
value={entry.apikeyVarName ?? `${agentNameUpper}_API_KEY`} as well as the
similar occurrences at the other noted locations) to generate unique,
provider-scoped defaults (e.g., include a unique provider index or provider id)
instead of reusing `${agentNameUpper}_URL`/`_API_KEY`, and add validation in the
onChange handlers (handleUrlVarChange and handleApikeyVarChange) to reject empty
or invalid names using the same env-var regex used for configurations.env;
ensure buildAgentCreationPayload receives sanitized, validated values only.
- Around line 419-425: The drawer currently hardcodes drawerEnvName =
environments[0]?.name which causes edits to always target the first env and
overwrites selectedProviderByEnv for every env; change the drawer to accept or
derive the actual active environment name (e.g., prop activeEnvName or from the
active tab) and use that value instead of environments[0] when computing
currentDrawerProviderUuid and when writing updates to
llmProviders[x].selectedProviderByEnv and modelConfig.envMappings; update the
other similar block (the logic around lines handling 463-470) so updates only
set the single key for the active env (e.g.,
selectedProviderByEnv[activeEnvName] = {...} or
modelConfig.envMappings[activeEnvName] = ...), not replace the entire mapping
object, preserving other environments' mappings.

---

Nitpick comments:
In `@console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx`:
- Line 24: Remove the unused type import LLMProviderFormEntry from the import
statement that currently imports ConnectAgentFormValues and LLMProviderFormEntry
(the line importing from "../form/schema"); keep ConnectAgentFormValues only so
the file no longer imports unused symbols.

In `@console/workspaces/Untitled`:
- Line 1: Remove the accidental workspace artifact named "Untitled" from the PR:
delete the file from the branch (unstage and remove from git), amend or create a
new commit without it, and push the updated commit to the PR; also check for any
other stray console workspace files and, if these files are generated regularly,
add an appropriate rule to .gitignore to prevent future accidental commits.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5f88de9a-8766-4d77-b69c-01c996ba42dc

📥 Commits

Reviewing files that changed from the base of the PR and between 503f007 and 01ac35c.

📒 Files selected for processing (16)
  • agent-manager-service/docs/api_v1_openapi.yaml
  • agent-manager-service/services/agent_manager.go
  • agent-manager-service/spec/model_create_agent_request.go
  • agent-manager-service/spec/model_model_config_request.go
  • agent-manager-service/wiring/wire_gen.go
  • console/workspaces/Untitled
  • console/workspaces/libs/types/src/api/agents.ts
  • console/workspaces/pages/add-new-agent/package.json
  • console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx
  • console/workspaces/pages/add-new-agent/src/components/ExternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx
  • console/workspaces/pages/add-new-agent/src/form/schema.ts
  • console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/forms/InternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts

Comment on lines +6401 to +6406
environmentVariables:
type: array
description: Optional custom environment variable names exposed to the agent
uniqueItems: true
items:
$ref: "#/components/schemas/EnvironmentVariableConfig"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep environmentVariables validation docs consistent with the standalone model-config API.

uniqueItems: true only rejects identical {key, name} objects. The existing CreateAgentModelConfigRequest.environmentVariables docs already say duplicate keys are rejected with 400, but that rule is omitted here, so the same field shape now has two different documented contracts.

📝 Suggested doc fix
         environmentVariables:
           type: array
-          description: Optional custom environment variable names exposed to the agent
+          description: Optional custom environment variable names exposed to the agent. Duplicate keys are rejected with 400.
           uniqueItems: true
           items:
             $ref: "#/components/schemas/EnvironmentVariableConfig"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/docs/api_v1_openapi.yaml` around lines 6401 - 6406, The
environmentVariables array schema lacks the same duplicate-key validation note
as CreateAgentModelConfigRequest.environmentVariables; update the OpenAPI docs
for the environmentVariables property (the array under environmentVariables and
its items referencing EnvironmentVariableConfig) to document that duplicate keys
are rejected with a 400 error (in addition to uniqueItems: true), e.g., add a
description sentence or validation note stating "Duplicate environment variable
keys are rejected with 400" so the contract matches the standalone model-config
API.

Comment on lines +636 to +647
// Create LLM configurations (applies to both internal and external agents)
if len(req.ModelConfig) > 0 {
if err := s.createAgentLLMConfigs(ctx, orgName, projectName, req); err != nil {
s.logger.Error("Failed to create LLM configurations for agent", "agentName", req.Name, "error", err)
if hasSecrets {
s.cleanupSecretsOnRollback(ctx, secretLocation)
}
if errDeletion := s.ocClient.DeleteComponent(ctx, orgName, projectName, req.Name); errDeletion != nil {
s.logger.Error("Failed to rollback agent after LLM config failure", "agentName", req.Name, "error", errDeletion)
}
return err
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Roll back created LLM configs on every failure path.

Once createAgentLLMConfigs has created the first config, any later error here only removes the component and secrets. That leaves orphaned ${agent}-llm-config* records behind, so a retry can fail even though the component was rolled back. Please track the created config IDs and delete them in each rollback branch so create-agent stays atomic.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx (2)

246-257: ⚠️ Potential issue | 🟠 Major

Make the env-var names unique and valid by default.

This still initializes every entry with the same ${agentNameUpper}_URL / ${agentNameUpper}_API_KEY pair, and the change handlers store whatever the user types. Multiple entries collide immediately, and display names like 123 Bot can produce defaults that violate the env-var regex already enforced for env.

Also applies to: 332-349, 455-457

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 246 - 257, The default env-var names are not unique/validated and
handlers accept arbitrary input; update the initialization logic that sets
urlVarName/apikeyVarName (and the similar blocks around the other occurrences)
to generate unique, regex-safe defaults per entry (e.g., based on a sanitized
agent name plus the entry index or a counter) and ensure handleUrlVarChange and
handleApikeyVarChange sanitize and/or validate user input against the same
env-var regex before calling onUpdateEntry (reject/normalize invalid characters
and avoid collisions by appending index if needed), so look for the functions
handleUrlVarChange and handleApikeyVarChange and the places initializing
urlVarName/apikeyVarName and apply the uniqueness + validation logic
consistently.

244-245: ⚠️ Potential issue | 🟠 Major

Keep provider edits scoped to the active environment.

onOpenDrawer only carries the entry index, drawerEnvName is fixed to the first environment, and handleProviderSelect rewrites the whole selectedProviderByEnv record. With multiple environments, opening the drawer from another tab still edits the first env and wipes any per-env selection differences.

Also applies to: 419-425, 443-470

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 244 - 245, The drawer open flow is using a fixed drawerEnvName and
onOpenDrawer(index) so opening the drawer from a non-first environment edits the
first env and handleProviderSelect replaces the entire selectedProviderByEnv
record; update the flow so the active environment is passed and used: change
onOpenDrawer to accept (index, envName) or capture the current env in
handleOpenDrawer (reference handleOpenDrawer, onOpenDrawer, drawerEnvName),
ensure handleProviderSelect updates only selectedProviderByEnv[envName] (merge
into the existing object rather than replacing it) so per-environment selections
are preserved, and update any other callsites (see usages around the other
mentions) to pass the correct envName and include envName in useCallback
dependency lists.
🧹 Nitpick comments (2)
agent-manager-service/wiring/wire_gen.go (1)

70-70: Consider clarifying the dual repository/service access pattern.

The agentManagerService now holds both agentConfigRepository (direct repo access) and agentConfigurationService (service layer). Per the PR objective of atomic creation with rollback, ensure that agent configuration operations during creation flow through agentConfigurationService rather than the direct repository, to maintain transactional guarantees and avoid bypassing business logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/wiring/wire_gen.go` at line 70, The wiring currently
injects both agentConfigRepository and agentConfigurationService into
NewAgentManagerService, which risks bypassing service-layer transactional logic;
update the constructor call and AgentManagerService so creation/rollback use
agentConfigurationService exclusively: remove the direct agentConfigRepository
dependency from the NewAgentManagerService injection (or stop using it inside
AgentManagerService), change any AgentManagerService methods that call
agentConfigRepository to call the corresponding agentConfigurationService
methods (e.g., CreateAgentConfig, DeleteAgentConfig/Rollback methods), and
ensure NewAgentManagerService signature and AgentManagerService implementation
only rely on agentConfigurationService for agent configuration operations to
preserve atomic creation and rollback guarantees.
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx (1)

103-109: Prefer theme-derived sizing in the new card UI.

The avatar/logo dimensions here are hardcoded pixels in sx. Using theme tokens keeps this section aligned with the console’s spacing scale.

As per coding guidelines, "Use theme tokens via the sx prop instead of hardcoded colors and spacing values".

Also applies to: 124-128

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 103 - 109, The Avatar in LLMProviderSection.tsx uses hardcoded
pixel values for sizing and also has other hardcoded spacing/colors nearby;
update the Avatar's sx to use theme tokens instead of numeric literals (e.g.,
replace height: 32 and width: 32 with theme.spacing(...) via the sx callback
such as (theme) => theme.spacing(4)) and ensure any nearby color/spacing uses
theme.palette and theme.spacing tokens (refer to the Avatar component, its sx
prop and the isSelected logic, and the similar block around lines 124-128) so
spacing and colors align with the console theme.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 386-388: The add flow is enabled before the backing queries settle
(useListEnvironments, useListCatalogLLMProviders, useListLLMProviderTemplates),
causing creation with missing env mappings and empty-state UI; fix by gating the
Add button and drawer behavior on the queries' loading/completed state (use
isLoading/isFetching or data === undefined) — disable the Add control until
environments and catalog finish loading, prevent creating a provider if
environments is undefined (check environments before creating env mappings in
the create handler used by the drawer), and swap the empty-state copy for a
loading spinner in the drawer while catalog/template queries are loading; apply
the same guards to the other affected sections that call those hooks (the blocks
around the other Add flows).
- Around line 437-441: handleDrawerClose resets search state but does not clear
a pending debounce timer, so a queued timeout can later restore stale
debouncedSearch and reopen the drawer; update handleDrawerClose to clear the
pending timer (e.g., clearTimeout on the timer id stored in a ref or state)
before resetting setProviderDrawerOpen, setProviderSearchQuery, and
setDebouncedSearch, and apply the same change to the other drawer-close handler
referenced at lines 499-504 (the other provider/drawer close function) so any
outstanding setTimeout is canceled on close.

---

Duplicate comments:
In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 246-257: The default env-var names are not unique/validated and
handlers accept arbitrary input; update the initialization logic that sets
urlVarName/apikeyVarName (and the similar blocks around the other occurrences)
to generate unique, regex-safe defaults per entry (e.g., based on a sanitized
agent name plus the entry index or a counter) and ensure handleUrlVarChange and
handleApikeyVarChange sanitize and/or validate user input against the same
env-var regex before calling onUpdateEntry (reject/normalize invalid characters
and avoid collisions by appending index if needed), so look for the functions
handleUrlVarChange and handleApikeyVarChange and the places initializing
urlVarName/apikeyVarName and apply the uniqueness + validation logic
consistently.
- Around line 244-245: The drawer open flow is using a fixed drawerEnvName and
onOpenDrawer(index) so opening the drawer from a non-first environment edits the
first env and handleProviderSelect replaces the entire selectedProviderByEnv
record; update the flow so the active environment is passed and used: change
onOpenDrawer to accept (index, envName) or capture the current env in
handleOpenDrawer (reference handleOpenDrawer, onOpenDrawer, drawerEnvName),
ensure handleProviderSelect updates only selectedProviderByEnv[envName] (merge
into the existing object rather than replacing it) so per-environment selections
are preserved, and update any other callsites (see usages around the other
mentions) to pass the correct envName and include envName in useCallback
dependency lists.

---

Nitpick comments:
In `@agent-manager-service/wiring/wire_gen.go`:
- Line 70: The wiring currently injects both agentConfigRepository and
agentConfigurationService into NewAgentManagerService, which risks bypassing
service-layer transactional logic; update the constructor call and
AgentManagerService so creation/rollback use agentConfigurationService
exclusively: remove the direct agentConfigRepository dependency from the
NewAgentManagerService injection (or stop using it inside AgentManagerService),
change any AgentManagerService methods that call agentConfigRepository to call
the corresponding agentConfigurationService methods (e.g., CreateAgentConfig,
DeleteAgentConfig/Rollback methods), and ensure NewAgentManagerService signature
and AgentManagerService implementation only rely on agentConfigurationService
for agent configuration operations to preserve atomic creation and rollback
guarantees.

In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 103-109: The Avatar in LLMProviderSection.tsx uses hardcoded pixel
values for sizing and also has other hardcoded spacing/colors nearby; update the
Avatar's sx to use theme tokens instead of numeric literals (e.g., replace
height: 32 and width: 32 with theme.spacing(...) via the sx callback such as
(theme) => theme.spacing(4)) and ensure any nearby color/spacing uses
theme.palette and theme.spacing tokens (refer to the Avatar component, its sx
prop and the isSelected logic, and the similar block around lines 124-128) so
spacing and colors align with the console theme.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d369e565-d046-4fbc-a3b6-32c77cc46184

📥 Commits

Reviewing files that changed from the base of the PR and between 01ac35c and 6540d85.

⛔ Files ignored due to path filters (1)
  • console/common/config/rush/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • agent-manager-service/wiring/wire_gen.go
  • console/workspaces/Untitled
  • console/workspaces/libs/types/src/api/agents.ts
  • console/workspaces/pages/add-new-agent/package.json
  • console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx
  • console/workspaces/pages/add-new-agent/src/components/ExternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx
  • console/workspaces/pages/add-new-agent/src/form/schema.ts
  • console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/forms/InternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts
✅ Files skipped from review due to trivial changes (5)
  • console/workspaces/Untitled
  • console/workspaces/pages/add-new-agent/src/components/ExternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/package.json
  • console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • console/workspaces/libs/types/src/api/agents.ts
  • console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts

@menakaj menakaj force-pushed the agent-llm-config-create branch 3 times, most recently from a9afca9 to e765179 Compare March 20, 2026 08:05
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx (2)

342-353: ⚠️ Potential issue | 🟠 Major

Use unique env-var defaults per entry and validate env-var names before storing.

All entries default to the same ${agentNameUpper}_URL / ${agentNameUpper}_API_KEY names, and input handlers on Lines 249-259 accept arbitrary values. Since payload building forwards these names directly, collisions/invalid env var names are only caught downstream.

Proposed patch
+const ENV_VAR_NAME_REGEX = /^[A-Z_][A-Z0-9_]*$/;

@@
-  const handleUrlVarChange = useCallback(
+  const handleUrlVarChange = useCallback(
     (e: React.ChangeEvent<HTMLInputElement>) => {
-      onUpdateEntry(index, { ...entry, urlVarName: e.target.value });
+      const next = e.target.value.trim().toUpperCase();
+      if (next !== "" && !ENV_VAR_NAME_REGEX.test(next)) return;
+      onUpdateEntry(index, { ...entry, urlVarName: next || undefined });
     },

@@
-  const handleApikeyVarChange = useCallback(
+  const handleApikeyVarChange = useCallback(
     (e: React.ChangeEvent<HTMLInputElement>) => {
-      onUpdateEntry(index, { ...entry, apikeyVarName: e.target.value });
+      const next = e.target.value.trim().toUpperCase();
+      if (next !== "" && !ENV_VAR_NAME_REGEX.test(next)) return;
+      onUpdateEntry(index, { ...entry, apikeyVarName: next || undefined });
     },

@@
-              urlVarName: `${agentNameUpper}_URL`,
-              apikeyVarName: `${agentNameUpper}_API_KEY`,
+              urlVarName: `${agentNameUpper}_${prev.length + 1}_URL`,
+              apikeyVarName: `${agentNameUpper}_${prev.length + 1}_API_KEY`,

Also applies to: 465-466

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 342 - 353, Default env-var names for each LLM entry currently all
use `${agentNameUpper}_URL` and `${agentNameUpper}_API_KEY` and the handlers
(handleUrlVarChange, handleApikeyVarChange) accept arbitrary values; change this
so each entry gets a unique default (e.g., derive from entry.id or index when
rendering the TextField value for urlVarName/apikeyVarName) and add validation
in handleUrlVarChange and handleApikeyVarChange to reject/normalize invalid
env-var names (allow only A-Z0-9 and underscores, start with a letter, no
collisions among entries) before updating entry state so only valid,
collision-free names are stored and forwarded.

393-395: ⚠️ Potential issue | 🟠 Major

Block add/select until required queries settle, and prevent empty env-mappings creation.

environments can still be unresolved when the add flow is usable. On Line 458, creating a new entry with an empty environments array produces selectedProviderByEnv = {}, which breaks per-environment intent and can emit invalid modelConfig.envMappings.

[suggested fix: gate Add + guard creation path]

Proposed patch
-  const { data: environments = [] } = useListEnvironments({ orgName: orgId });
-  const { data: catalogData } = useListCatalogLLMProviders({ orgName: orgId }, { limit: 50 });
+  const { data: environments = [], isLoading: isEnvironmentsLoading } = useListEnvironments({ orgName: orgId });
+  const { data: catalogData, isLoading: isCatalogLoading } = useListCatalogLLMProviders({ orgName: orgId }, { limit: 50 });

@@
         if (editingIndex === null) {
+          if (isEnvironmentsLoading || environments.length === 0) {
+            return prev;
+          }
           const selectedProviderByEnv: LLMProviderFormEntry["selectedProviderByEnv"] = {};
           for (const env of environments) {
             selectedProviderByEnv[env.name] = { uuid: providerUuid, handle: providerHandle };
           }

@@
           <Button
@@
-            disabled={providers.length === 0 && !!catalogData}
+            disabled={isEnvironmentsLoading || isCatalogLoading || providers.length === 0}
           >
             Add
           </Button>

Also applies to: 437-470, 547-553, 597-606

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 393 - 395, Gate the Add/select flow until useListEnvironments (and
related queries) are settled by checking the hook loading/error state and that
environments is a non-empty array before enabling the Add button and before
computing selectedProviderByEnv; in the onAdd/createNewEntry path, add a
defensive guard that returns early (or shows validation) if environments is
undefined/empty to avoid initializing selectedProviderByEnv = {} and emitting
invalid modelConfig.envMappings. Ensure selectedProviderByEnv and any
envMappings are constructed only after environments is available (derive them
from environments.map(...) not from an empty default) so per-environment intent
remains correct.
🧹 Nitpick comments (1)
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx (1)

526-530: Prefer a stable key instead of index for stateful entry cards.

EntryCard has local state (selectedEnvIndex). Using key={index} can rebind state to the wrong entry after deletion/reorder.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 526 - 530, The map over llmProviders uses key={index} which can
cause EntryCard (which holds local state selectedEnvIndex) to lose or swap state
after reorder/delete; change the key to a stable unique identifier from the
entry object (e.g., entry.id or another immutable field like entry.providerKey
or entry.name) in the llmProviders.map that renders EntryCard; if entries
currently lack a stable id, add one when items are created (persisted or
generated once) and use that property as the key so EntryCard instances keep
stable identity.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 342-353: Default env-var names for each LLM entry currently all
use `${agentNameUpper}_URL` and `${agentNameUpper}_API_KEY` and the handlers
(handleUrlVarChange, handleApikeyVarChange) accept arbitrary values; change this
so each entry gets a unique default (e.g., derive from entry.id or index when
rendering the TextField value for urlVarName/apikeyVarName) and add validation
in handleUrlVarChange and handleApikeyVarChange to reject/normalize invalid
env-var names (allow only A-Z0-9 and underscores, start with a letter, no
collisions among entries) before updating entry state so only valid,
collision-free names are stored and forwarded.
- Around line 393-395: Gate the Add/select flow until useListEnvironments (and
related queries) are settled by checking the hook loading/error state and that
environments is a non-empty array before enabling the Add button and before
computing selectedProviderByEnv; in the onAdd/createNewEntry path, add a
defensive guard that returns early (or shows validation) if environments is
undefined/empty to avoid initializing selectedProviderByEnv = {} and emitting
invalid modelConfig.envMappings. Ensure selectedProviderByEnv and any
envMappings are constructed only after environments is available (derive them
from environments.map(...) not from an empty default) so per-environment intent
remains correct.

---

Nitpick comments:
In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 526-530: The map over llmProviders uses key={index} which can
cause EntryCard (which holds local state selectedEnvIndex) to lose or swap state
after reorder/delete; change the key to a stable unique identifier from the
entry object (e.g., entry.id or another immutable field like entry.providerKey
or entry.name) in the llmProviders.map that renders EntryCard; if entries
currently lack a stable id, add one when items are created (persisted or
generated once) and use that property as the key so EntryCard instances keep
stable identity.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a2faf873-6e0a-4530-8d2b-c2b414ff22e1

📥 Commits

Reviewing files that changed from the base of the PR and between 6540d85 and e765179.

📒 Files selected for processing (4)
  • console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx
  • console/workspaces/pages/add-new-agent/src/forms/InternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts
  • console/workspaces/pages/add-new-project/src/components/ProjectForm.tsx
✅ Files skipped from review due to trivial changes (1)
  • console/workspaces/pages/add-new-project/src/components/ProjectForm.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts
  • console/workspaces/pages/add-new-agent/src/forms/InternalAgentForm.tsx

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx (3)

556-561: Consider adding cleanup on unmount.

The debounce timer is cleared on drawer close and provider select, but if the component unmounts while the drawer is open with a pending timer, it could fire after unmount. Adding a cleanup effect would be more robust.

🧹 Suggested cleanup effect
+import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
-import React, { useCallback, useMemo, useRef, useState } from "react";
@@
  const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const val = e.target.value;
    setProviderSearchQuery(val);
    if (searchTimerRef.current) clearTimeout(searchTimerRef.current);
    searchTimerRef.current = setTimeout(() => setDebouncedSearch(val), 250);
  }, []);

+  useEffect(() => {
+    return () => {
+      if (searchTimerRef.current) {
+        clearTimeout(searchTimerRef.current);
+      }
+    };
+  }, []);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 556 - 561, The debounce timer started in handleSearchChange (uses
searchTimerRef and setDebouncedSearch) needs a cleanup on unmount to avoid
firing after the component is destroyed; add a useEffect that returns a cleanup
function which checks searchTimerRef.current and calls clearTimeout on it (and
sets it to null) so any pending timer is cleared when the component unmounts.

272-281: Misleading variable name guardrails for a boolean check.

The variable guardrails is assigned the boolean result of .some(), but the name suggests it's an array. While the logic is correct (returning early if a duplicate exists), the naming is confusing.

✏️ Suggested rename for clarity
  const handleAddGuardrail = useCallback(
    (guardrail: GuardrailSelection) => {
-     const guardrails = entry.guardrails.some(
+     const isDuplicate = entry.guardrails.some(
        (g) => g.name === guardrail.name && g.version === guardrail.version)
-     if (guardrails) return;
+     if (isDuplicate) return;

      onUpdateEntry(index, { ...entry, guardrails: [...entry.guardrails, guardrail] });
    },
    [index, entry, onUpdateEntry],
  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 272 - 281, The boolean result of entry.guardrails.some(...) in
handleAddGuardrail is named guardrails which is misleading; rename it to a
clearer identifier like isDuplicate or alreadyExists (used in the
duplicate-check and early return) and update the subsequent if check accordingly
in the handleAddGuardrail callback so entry.guardrails, GuardrailSelection,
onUpdateEntry, and index usages remain unchanged.

578-592: Consider using stable keys instead of array index.

Using index as the React key can cause unexpected behavior when entries are removed, as React may incorrectly preserve state for shifted items. If LLMProviderFormEntry doesn't have a unique ID, consider generating one (e.g., crypto.randomUUID()) when creating new entries in handleProviderSelect.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 578 - 592, The EntryCard list is using the array index as key which
can lead to UI/state bugs; update the list to use a stable unique identifier
(e.g., entry.id) as the key and ensure every LLMProviderFormEntry has that id:
modify the provider creation flow in handleProviderSelect to assign a UUID
(crypto.randomUUID()) to new entries, update any initialization code that
constructs entries to also populate id for legacy/seeded entries, and keep
EntryCard key={entry.id} so handleRemoveEntry/handleUpdateEntry and rendering
remain stable when items are added/removed.
console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx (1)

154-170: Consider extracting the conflict detection logic to avoid duplication.

The logic for computing agentNameUpper and deriving LLM variable names is duplicated here and in InternalAgentForm.tsx (lines 418-428). If these implementations drift apart, conflict detection could become inconsistent between the submit button state and the visual error indicators.

♻️ Suggested extraction

Create a utility function in the form/ or utils/ directory:

// e.g., in utils/llmVarNames.ts
export function deriveLLMVarNames(
  llmProviders: LLMProviderFormEntry[],
  displayName: string
): string[] {
  const agentNameUpper = displayName
    ? displayName.toUpperCase().replace(/[^A-Z0-9]/g, "_")
    : "AGENT";
  return llmProviders.flatMap((e, i) => [
    e.urlVarName ?? `${agentNameUpper}_${i + 1}_URL`,
    e.apikeyVarName ?? `${agentNameUpper}_${i + 1}_API_KEY`,
  ]);
}

export function hasLLMVarConflicts(
  llmProviders: LLMProviderFormEntry[],
  displayName: string,
  envKeys: string[]
): boolean {
  const llmNames = deriveLLMVarNames(llmProviders, displayName);
  const llmNameSet = new Set(llmNames);
  if (llmNames.length !== llmNameSet.size) return true;
  if (envKeys.length !== new Set(envKeys).size) return true;
  return envKeys.some((k) => llmNameSet.has(k));
}

Then use it in both InternalAgentFlow.tsx and InternalAgentForm.tsx.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx`
around lines 154 - 170, Extract the duplicated LLM variable name and
conflict-detection logic into a shared utility (e.g., export deriveLLMVarNames
and hasLLMVarConflicts) and replace the inline computation in InternalAgentFlow
(the IIFE that reads llmProviders and formData.displayName, builds
llmNames/llmNameSet and checks env keys) and the matching block in
InternalAgentForm with calls to the new helpers; deriveLLMVarNames should accept
(llmProviders, displayName) and return the flat list of var names, and
hasLLMVarConflicts should accept (llmProviders, displayName, envKeys) and return
the boolean used for hasLLMVarConflicts.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx`:
- Around line 154-170: Extract the duplicated LLM variable name and
conflict-detection logic into a shared utility (e.g., export deriveLLMVarNames
and hasLLMVarConflicts) and replace the inline computation in InternalAgentFlow
(the IIFE that reads llmProviders and formData.displayName, builds
llmNames/llmNameSet and checks env keys) and the matching block in
InternalAgentForm with calls to the new helpers; deriveLLMVarNames should accept
(llmProviders, displayName) and return the flat list of var names, and
hasLLMVarConflicts should accept (llmProviders, displayName, envKeys) and return
the boolean used for hasLLMVarConflicts.

In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 556-561: The debounce timer started in handleSearchChange (uses
searchTimerRef and setDebouncedSearch) needs a cleanup on unmount to avoid
firing after the component is destroyed; add a useEffect that returns a cleanup
function which checks searchTimerRef.current and calls clearTimeout on it (and
sets it to null) so any pending timer is cleared when the component unmounts.
- Around line 272-281: The boolean result of entry.guardrails.some(...) in
handleAddGuardrail is named guardrails which is misleading; rename it to a
clearer identifier like isDuplicate or alreadyExists (used in the
duplicate-check and early return) and update the subsequent if check accordingly
in the handleAddGuardrail callback so entry.guardrails, GuardrailSelection,
onUpdateEntry, and index usages remain unchanged.
- Around line 578-592: The EntryCard list is using the array index as key which
can lead to UI/state bugs; update the list to use a stable unique identifier
(e.g., entry.id) as the key and ensure every LLMProviderFormEntry has that id:
modify the provider creation flow in handleProviderSelect to assign a UUID
(crypto.randomUUID()) to new entries, update any initialization code that
constructs entries to also populate id for legacy/seeded entries, and keep
EntryCard key={entry.id} so handleRemoveEntry/handleUpdateEntry and rendering
remain stable when items are added/removed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 471a8c6e-4a11-41f3-8cfc-af36bbacb982

📥 Commits

Reviewing files that changed from the base of the PR and between e765179 and 33af71f.

📒 Files selected for processing (5)
  • console/workspaces/pages/add-new-agent/src/components/CreateButtons.tsx
  • console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx
  • console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx
  • console/workspaces/pages/add-new-agent/src/forms/InternalAgentForm.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx

@menakaj menakaj force-pushed the agent-llm-config-create branch 2 times, most recently from eadf7e1 to b171e93 Compare March 26, 2026 20:47
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
agent-manager-service/docs/api_v1_openapi.yaml (1)

6529-6534: ⚠️ Potential issue | 🟡 Minor

Document duplicate-key rejection for environmentVariables to match existing API contract.

Line 6531 still omits the duplicate-key behavior (400) that is documented on CreateAgentModelConfigRequest.environmentVariables; uniqueItems: true alone does not communicate key-level uniqueness.

📝 Suggested doc fix
         environmentVariables:
           type: array
-          description: Optional custom environment variable names exposed to the agent
+          description: Optional custom environment variable names exposed to the agent. Duplicate keys are rejected with 400.
           uniqueItems: true
           items:
             $ref: "#/components/schemas/EnvironmentVariableConfig"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/docs/api_v1_openapi.yaml` around lines 6529 - 6534, Add
documentation that environmentVariables enforces key-level uniqueness and
duplicate keys will be rejected with a 400 error to match the existing API
contract for CreateAgentModelConfigRequest.environmentVariables; update the
schema block for environmentVariables (and/or its description) to explicitly
state "duplicate keys are rejected (HTTP 400)" and ensure any relevant response
examples or the CreateAgentModelConfigRequest schema mention the same behavior
so the contract is consistent.
agent-manager-service/services/agent_manager.go (1)

759-775: ⚠️ Potential issue | 🟠 Major

Give these LLM configs a full rollback/delete lifecycle.

After the first Create succeeds, any later failure leaves the earlier ${agent}-llm-config* rows behind because this helper only returns error; the later rollback paths in CreateAgent and DeleteAgent still only clean up the component, secrets, and agentConfigRepo data. Please either delete partial creations here or return the created config IDs so the caller can clean them up too.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@agent-manager-service/services/agent_manager.go` around lines 759 - 775,
createAgentLLMConfigs currently creates multiple agent LLM configs via
agentConfigurationService.Create but on a later error leaves previously created
`${agent}-llm-config*` rows orphaned; update createAgentLLMConfigs to either (A)
track created config identifiers returned from agentConfigurationService.Create
and return them to the caller (so CreateAgent/DeleteAgent can perform full
rollback), or (B) perform immediate cleanup on failure by calling
agentConfigurationService.Delete (or the appropriate delete method) for each
successfully created config before returning the error; reference
createAgentLLMConfigs, agentConfigurationService.Create, and the higher-level
CreateAgent/DeleteAgent flows when making the change.
console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx (1)

502-509: ⚠️ Potential issue | 🟡 Minor

Give provider rows a stable id.

The add path derives urlVarName / apikeyVarName from prev.length + 1, so deleting an earlier row and adding another can recreate an existing suffix. The render path also uses key={index}, which lets EntryCard's local selectedEnvIndex state jump to the wrong provider after a delete. A stable per-entry id fixes both problems.

Also applies to: 579-580

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`
around lines 502 - 509, The provider entries need a stable unique id to avoid
colliding suffixes and key/index-related state jumps: when adding in the reducer
where you build the new entry (the object containing selectedProviderByEnv,
urlVarName, apikeyVarName, guardrails), generate and include a stable id field
(e.g., id: uuid() or a monotonic counter) and use that id to derive
urlVarName/apikeyVarName instead of using prev.length + 1; then change the
render so EntryCard uses key={entry.id} (and anywhere relying on index for
keeping selectedEnvIndex) to prevent selectedEnvIndex from jumping after
deletes. Apply the same id usage where new entries are created in the other add
path referenced around the 579-580 area.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx`:
- Around line 95-103: Normalize env variable keys the same way
buildAgentCreationPayload does before running duplicate and reserved-name
checks: inside the envVariables.map block (where keyError is computed) compute a
normalizedKey by collapsing whitespace to underscores (matching
buildAgentCreationPayload) and use normalizedKey for checking against
llmReservedNames and sibling keys (build siblingNormalizedKeys from envVariables
excluding current index). Update the Duplicate key and LLM-provider conflict
checks to reference normalizedKey instead of the raw item.key so collisions like
"FOO BAR" vs "FOO_BAR" are caught early.

---

Duplicate comments:
In `@agent-manager-service/docs/api_v1_openapi.yaml`:
- Around line 6529-6534: Add documentation that environmentVariables enforces
key-level uniqueness and duplicate keys will be rejected with a 400 error to
match the existing API contract for
CreateAgentModelConfigRequest.environmentVariables; update the schema block for
environmentVariables (and/or its description) to explicitly state "duplicate
keys are rejected (HTTP 400)" and ensure any relevant response examples or the
CreateAgentModelConfigRequest schema mention the same behavior so the contract
is consistent.

In `@agent-manager-service/services/agent_manager.go`:
- Around line 759-775: createAgentLLMConfigs currently creates multiple agent
LLM configs via agentConfigurationService.Create but on a later error leaves
previously created `${agent}-llm-config*` rows orphaned; update
createAgentLLMConfigs to either (A) track created config identifiers returned
from agentConfigurationService.Create and return them to the caller (so
CreateAgent/DeleteAgent can perform full rollback), or (B) perform immediate
cleanup on failure by calling agentConfigurationService.Delete (or the
appropriate delete method) for each successfully created config before returning
the error; reference createAgentLLMConfigs, agentConfigurationService.Create,
and the higher-level CreateAgent/DeleteAgent flows when making the change.

In
`@console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx`:
- Around line 502-509: The provider entries need a stable unique id to avoid
colliding suffixes and key/index-related state jumps: when adding in the reducer
where you build the new entry (the object containing selectedProviderByEnv,
urlVarName, apikeyVarName, guardrails), generate and include a stable id field
(e.g., id: uuid() or a monotonic counter) and use that id to derive
urlVarName/apikeyVarName instead of using prev.length + 1; then change the
render so EntryCard uses key={entry.id} (and anywhere relying on index for
keeping selectedEnvIndex) to prevent selectedEnvIndex from jumping after
deletes. Apply the same id usage where new entries are created in the other add
path referenced around the 579-580 area.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 07a880eb-f132-4501-ba54-703ab89f6a5a

📥 Commits

Reviewing files that changed from the base of the PR and between 33af71f and b171e93.

⛔ Files ignored due to path filters (1)
  • console/common/config/rush/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • agent-manager-service/docs/api_v1_openapi.yaml
  • agent-manager-service/services/agent_manager.go
  • agent-manager-service/spec/model_create_agent_request.go
  • agent-manager-service/spec/model_model_config_request.go
  • agent-manager-service/wiring/wire_gen.go
  • console/workspaces/libs/types/src/api/agents.ts
  • console/workspaces/pages/add-new-agent/package.json
  • console/workspaces/pages/add-new-agent/src/components/CreateButtons.tsx
  • console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx
  • console/workspaces/pages/add-new-agent/src/components/ExternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/src/components/LLMProviderSection.tsx
  • console/workspaces/pages/add-new-agent/src/form/schema.ts
  • console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/forms/InternalAgentForm.tsx
  • console/workspaces/pages/add-new-agent/src/utils/buildAgentPayload.ts
  • console/workspaces/pages/add-new-project/src/components/ProjectForm.tsx
✅ Files skipped from review due to trivial changes (4)
  • console/workspaces/pages/add-new-agent/src/components/ExternalAgentFlow.tsx
  • console/workspaces/pages/add-new-agent/package.json
  • console/workspaces/pages/add-new-project/src/components/ProjectForm.tsx
  • console/workspaces/pages/add-new-agent/src/forms/ExternalAgentForm.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • console/workspaces/pages/add-new-agent/src/components/CreateButtons.tsx
  • console/workspaces/libs/types/src/api/agents.ts
  • console/workspaces/pages/add-new-agent/src/components/InternalAgentFlow.tsx
  • agent-manager-service/spec/model_model_config_request.go

Comment on lines +95 to +103
{envVariables.length ? envVariables.map((item, index) => {
const siblingKeys = new Set(
envVariables.flatMap((e, i) => (i !== index && e.key ? [e.key] : [])),
);
const keyError = item.key && llmReservedNames.has(item.key)
? "Already used as an LLM provider variable"
: item.key && siblingKeys.has(item.key)
? "Duplicate key"
: undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Normalize env keys before running duplicate/reserved-name checks.

buildAgentCreationPayload later serializes data.env[*].key with whitespace collapsed to _, but keyError compares the raw input here. FOO BAR and FOO_BAR therefore pass validation in this component and only collide in the submitted payload, including the LLM-provider conflict check.

Suggested fix
+const normalizeEnvKey = (key?: string) => key?.replace(/\s+/g, "_");
+
         <Box display="flex" flexDirection="column" py={2} gap={2}>
           {envVariables.length ? envVariables.map((item, index) => {
+            const normalizedKey = normalizeEnvKey(item.key);
             const siblingKeys = new Set(
-              envVariables.flatMap((e, i) => (i !== index && e.key ? [e.key] : [])),
+              envVariables.flatMap((e, i) =>
+                i !== index && e.key ? [normalizeEnvKey(e.key)!] : [],
+              ),
             );
-            const keyError = item.key && llmReservedNames.has(item.key)
+            const keyError = normalizedKey && llmReservedNames.has(normalizedKey)
               ? "Already used as an LLM provider variable"
-              : item.key && siblingKeys.has(item.key)
+              : normalizedKey && siblingKeys.has(normalizedKey)
                 ? "Duplicate key"
                 : undefined;
             return (
               <EnvVariableEditor
@@
               onKeyChange={(value) => handleInitialEdit('key', value)}
               onValueChange={(value) => handleInitialEdit('value', value)}
               onSensitiveChange={(value: boolean) => handleInitialEdit('isSensitive', value)}
               onRemove={() => handleRemove(0)}
-              keyError={envVariables?.[0]?.key && llmReservedNames.has(envVariables[0].key!) ? "Already used as an LLM provider variable" : undefined}
+              keyError={(() => {
+                const normalizedKey = normalizeEnvKey(envVariables?.[0]?.key);
+                return normalizedKey && llmReservedNames.has(normalizedKey)
+                  ? "Already used as an LLM provider variable"
+                  : undefined;
+              })()}
             />
           }

Also applies to: 129-129

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@console/workspaces/pages/add-new-agent/src/components/EnvironmentVariable.tsx`
around lines 95 - 103, Normalize env variable keys the same way
buildAgentCreationPayload does before running duplicate and reserved-name
checks: inside the envVariables.map block (where keyError is computed) compute a
normalizedKey by collapsing whitespace to underscores (matching
buildAgentCreationPayload) and use normalizedKey for checking against
llmReservedNames and sibling keys (build siblingNormalizedKeys from envVariables
excluding current index). Update the Duplicate key and LLM-provider conflict
checks to reference normalizedKey instead of the raw item.key so collisions like
"FOO BAR" vs "FOO_BAR" are caught early.

@menakaj menakaj force-pushed the agent-llm-config-create branch from b171e93 to 527d4e5 Compare March 30, 2026 14:45
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.

Able to configure an LLM Provider while creating an agent

2 participants