Skip to content

[FE chore] Move secrets and tools to monorepo packages#4338

Merged
ardaerzin merged 23 commits into
release/v0.100.0from
frontend-chore/move-secrets-and-tools-to-entities
May 19, 2026
Merged

[FE chore] Move secrets and tools to monorepo packages#4338
ardaerzin merged 23 commits into
release/v0.100.0from
frontend-chore/move-secrets-and-tools-to-entities

Conversation

@ardaerzin
Copy link
Copy Markdown
Contributor

Summary

tba...

Testing

Verified locally

secrets & tools are working as expected

QA follow-up

vault related features in FE and tools integrations in playground

Checklist

  • I have included a video or screen recording for UI changes, or marked Demo as N/A
  • Relevant tests pass locally
  • Relevant linting and formatting pass locally
  • I have signed the CLA, or I will sign it when the bot prompts me

Contributor Resources

ardaerzin added 10 commits May 8, 2026 14:10
…shared

- Move User, LlmProvider, llmAvailableProviders, removeEmptyFromObjects
  to @agenta/shared so package code can consume them without reaching
  back into @/oss/*.
- Add a primitive userAtom + setUserAtom in @agenta/shared/state, matching
  the projectIdAtom / sessionAtom pattern: package-readable primitive,
  populated by app code.
- Add OSS UserListener mirroring SessionListener to keep the shared atom
  synced with the rich profile state. Mounted in Providers.tsx alongside
  the existing listeners.
- Sweep OSS consumers to import directly from @agenta/shared/types
  (no thin re-exports through @/oss/lib/Types or @/oss/lib/helpers/*),
  consistent with the no-restricted-syntax lint rule for tree-shaking.
Vault-backed secret storage for LLM provider keys, scoped per project and
gated by user authentication.

Reference implementation of the entities/molecule pattern at its smallest
viable shape — query and mutation only:
  - No draft semantics
  - No imperative get/set surface
  - No isDirty tracking

Vault has no artifact-revision concept, so adding those slots would only
contribute dead methods.

The hook name (useVaultSecret) and return shape are preserved verbatim
from the legacy OSS implementation so consumer migration is an
import-path refactor rather than a rewrite. The query key
(["vault", "secrets", user?.id, projectId]) and migration atom
semantics (idempotency, logout-reset) are byte-identical with the legacy
source.

Includes a README documenting the folder shape, the explicit "no full
molecule API" decision, and the canonical homes for cross-cutting types
and atoms the package depends on.
Sweep the 9 OSS consumer files (ModelRegistry modals/drawer,
settings/Secrets, app management, custom workflow modal, evaluations,
prompts) to import useVaultSecret from @agenta/entities/secret. Same
hook name, same return shape — purely an import-path refactor.

Update ConfigureProviderDrawer to import SecretDTOProvider,
PROVIDER_KINDS, and PROVIDER_LABELS from the new secret package directly,
consistent with the no-restricted-syntax rule.

Drop the legacy barrel re-exports (./atoms/vault, ./hooks/useVaultSecret)
from web/oss/src/state/app/index.ts and update the SelectLLMProvider
example to point at the new path.

Remove the legacy OSS source:
  - web/oss/src/services/vault/
  - web/oss/src/state/app/atoms/vault.ts
  - web/oss/src/state/app/hooks/useVaultSecret.ts
  - web/oss/src/hooks/useVaultSecret.ts
  - web/oss/src/lib/helpers/llmProviders.ts
…end-chore/move-secrets-and-tools-to-entities
…gatewayTool and @agenta/entity-ui/gatewayTool
@vercel
Copy link
Copy Markdown

vercel Bot commented May 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment May 19, 2026 7:28pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a8a61a1-815c-4ff1-a83d-d94612caefd9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Extracts gateway tools and vault secrets into shared packages with Fern-backed APIs, updates OSS and entity-UI components to new types/hooks, adds shared user/types/utils, and removes legacy OSS-specific types/hooks.

Changes

Gateway Tool entity extraction and OSS/UI rewiring

Layer / File(s) Summary
GatewayTool core types and API wrappers
web/packages/agenta-entities/src/gatewayTool/*
Adds Fern-backed API functions and consolidated core types/helpers for tools, connections, and results.
GatewayTool hooks, state atoms, and prompt bridge
web/packages/agenta-entities/src/gatewayTool/{hooks,state,prompt}/*
Exports query/mutation hooks/atoms and refactors prompt tool-removal atom; adds barrel exports.
Entity-UI drawers/components converted to gatewayTool types
web/packages/agenta-entity-ui/src/gatewayTool/*
Updates drawers/components to Tool* types and helpers, normalizing optional props and flags.
OSS components/hooks switched to gatewayTool entities
web/oss/src/components/..., web/oss/src/components/pages/settings/Tools/*
Rewires OSS screens and hooks to new gatewayTool APIs/types with guarded IDs and updated generics.
Package export entries for gatewayTool/UI
web/packages/agenta-entities/package.json, web/packages/agenta-entity-ui/package.json
Adds subpath exports for gatewayTool in entities and entity-UI packages.

Secret/Vault entity extraction and OSS migration

Layer / File(s) Summary
Secret core types, transforms, and index
web/packages/agenta-entities/src/secret/{core,README}.md
Defines secret DTO/type aliases, provider catalogs, transforms, and barrel exports.
Secret API client and wrappers
web/packages/agenta-entities/src/secret/api/*
Adds Fern secrets client, project scoping, and CRUD wrappers.
Secret state atoms and useVaultSecret hook
web/packages/agenta-entities/src/secret/state/*
Implements secrets query/mutation atoms, migration atom, and refactored useVaultSecret.
OSS provider UI/hooks switched to @entities/secret and cleanup
web/oss/src/components/**/ConfigureProvider*, .../Secrets/*, .../hooks/*, web/oss/src/lib/*
Replaces local secret types/hooks with shared ones and updates helper/utils and legacy types.

Shared types/state/utils and OSS user sync

Layer / File(s) Summary
Shared API env and index re-exports
web/packages/agenta-shared/src/api/*
Adds getAgentaWebUrl and re-exports.
Shared hooks: debounced atom search
web/packages/agenta-shared/src/hooks/*
Exports useDebouncedAtomSearch with nullable timer ref.
Shared user/type definitions and state atoms
web/packages/agenta-shared/src/types/*, .../state/*
Adds User/LlmProvider types and userAtom/setUserAtom.
Shared utils and provider catalogs
web/packages/agenta-shared/src/utils/*
Exports schema builders, provider catalogs, and removeEmptyFromObjects.
OSS user listener and selector type updates
web/oss/src/state/*, web/oss/src/components/Sidebar/...
Adds UserListener syncing to shared userAtom and updates type imports.

Sequence Diagram(s)

sequenceDiagram
  participant OSS_UI as OSS UI
  participant Entities_Hooks as Entities Hooks
  participant Entities_API as Entities API
  participant SDK as Agenta SDK
  OSS_UI->>Entities_Hooks: useConnectionsQuery/useCatalogActions
  Entities_Hooks->>Entities_API: queryConnections/fetchActions
  Entities_API->>SDK: tools client (projectScopedRequest)
  SDK-->>Entities_API: responses
  Entities_API-->>Entities_Hooks: Tool* typed data
  Entities_Hooks-->>OSS_UI: connections/actions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Agenta-AI/agenta#4274: Overlapping validation-helper refactor affecting provider validation and related UI components.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch frontend-chore/move-secrets-and-tools-to-entities

@ardaerzin ardaerzin marked this pull request as ready for review May 18, 2026 19:48
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label May 18, 2026
@ardaerzin ardaerzin requested a review from ashrafchowdury May 18, 2026 19:48
@dosubot dosubot Bot added Frontend refactoring A code change that neither fixes a bug nor adds a feature labels May 18, 2026
Copy link
Copy Markdown

@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: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
web/packages/agenta-entity-ui/src/gatewayTool/drawers/ConnectDrawer.tsx (1)

92-104: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard redirect_url type before opening or assigning.

At Line 94, truthiness alone is not enough; Lines 97 and 104 cast unknown data to string. If backend payload drifts, this can navigate to an invalid URL stringification.

Suggested fix
-            const redirectUrl = (result.connection?.data as Record<string, unknown> | undefined)
-                ?.redirect_url
-            if (redirectUrl) {
+            const redirectUrl = (result.connection?.data as Record<string, unknown> | undefined)
+                ?.redirect_url
+            if (typeof redirectUrl === "string" && redirectUrl) {
                 // Composio handles all auth (OAuth and API key) via their redirect UI
                 const popup = window.open(
-                    redirectUrl as string,
+                    redirectUrl,
                     "tools_oauth",
                     "width=600,height=700,popup=yes",
                 )
                 if (!popup) {
                     setLoading(false)
                     message.warning("Popup blocked. Redirecting in this tab.")
-                    window.location.assign(redirectUrl as string)
+                    window.location.assign(redirectUrl)
                     return
                 }
web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx (1)

74-121: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard popup-blocked flow and make refresh finalization single-shot.

Line 74 can return null when popups are blocked; the current flow still registers long-lived listeners/timers. Also, cleanup can run twice (message + polling), causing duplicate invalidation/toasts.

Suggested fix
-                    const popup = window.open(
+                    const popup = window.open(
                         redirectUrl,
                         "tools_oauth",
                         "width=600,height=700,popup=yes",
                     )
+                    if (!popup) {
+                        message.warning("Popup was blocked. Please allow popups and try again.")
+                        return
+                    }

                     const cleanup = async () => {
                         window.focus()
                         // Poll the individual connection endpoint which checks
                         // Composio for status and updates is_valid in the DB.
@@
-                    const handler = (event: MessageEvent) => {
+                    let finalized = false
+                    let pollTimer: ReturnType<typeof setInterval> | undefined
+                    const finalize = () => {
+                        if (finalized) return
+                        finalized = true
+                        if (pollTimer) clearInterval(pollTimer)
+                        window.removeEventListener("message", handler)
+                        void cleanup()
+                    }
+
+                    const handler = (event: MessageEvent) => {
                         if (
                             event.data?.type === "tools:oauth:complete" &&
                             trustedOrigins.has(event.origin)
                         ) {
-                            window.removeEventListener("message", handler)
-                            void cleanup()
+                            finalize()
                         }
                     }
                     window.addEventListener("message", handler)

                     // Fallback: detect popup closed
-                    const pollTimer = setInterval(() => {
-                        if (popup && popup.closed) {
-                            clearInterval(pollTimer)
-                            window.removeEventListener("message", handler)
-                            void cleanup()
-                        }
-                    }, 1000)
+                    pollTimer = setInterval(() => {
+                        if (popup.closed) finalize()
+                    }, 1000)
web/packages/agenta-entities/src/secret/state/atoms.ts (1)

210-215: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the existing secret id when deciding update vs create.

Line 212 currently requires provider.id to update. If findSecret exists but provider.id is missing, this falls into create and can duplicate/fail instead of updating the existing vault record.

💡 Suggested fix
-        if (findSecret && provider.id) {
-            await updateMutation.mutateAsync({secret_id: provider.id, payload})
+        const secretId = findSecret?.id ?? provider.id
+        if (secretId) {
+            await updateMutation.mutateAsync({secret_id: secretId, payload})
         } else {
             await createMutation.mutateAsync(payload)
         }
🧹 Nitpick comments (4)
web/packages/agenta-shared/src/utils/llmProviders.ts (1)

20-34: ⚡ Quick win

Remove the empty key field from llmAvailableProviders entries.

The key: "" field is defined in every provider entry but is never used. Search shows no code accesses this field from the array; only the name field is used for provider matching. Either remove it to reduce clutter or document its intended purpose if it's reserved for future use.

web/packages/agenta-entities/src/gatewayTool/api/api.ts (1)

31-34: ⚡ Quick win

Prefer named interface declarations for exported parameter object shapes.

These inline object types work, but using named interfaces here improves reuse/readability and aligns with repo standards.

As per coding guidelines, "Prefer interface for defining object shapes in TypeScript".

Also applies to: 60-66, 98-101

web/packages/agenta-entities/src/gatewayTool/hooks/useActionDetail.ts (1)

11-12: ⚡ Quick win

Use a named interface for the atom-family argument shape.

Inline object-shape typing here can be replaced with a small interface to match project conventions and improve reuse.

As per coding guidelines, "Prefer interface for defining object shapes in TypeScript".

web/packages/agenta-entities/src/gatewayTool/prompt/atoms.ts (1)

34-43: ⚡ Quick win

Use interface for these local object-shape declarations.

EnhancedPrompt and EnhancedTool are object-shape definitions; convert them to interface to match repo TypeScript conventions.

♻️ Suggested change
-        type EnhancedPrompt = {
+        interface EnhancedPrompt extends Record<string, unknown> {
             __id?: string
             __name?: string
             llm_config?: Record<string, unknown>
             llmConfig?: Record<string, unknown>
-        } & Record<string, unknown>
-        type EnhancedTool = {
+        }
+        interface EnhancedTool extends Record<string, unknown> {
             value?: {function?: {name?: string}}
             __tool?: string
-        } & Record<string, unknown>
+        }

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 254519d3-15de-484b-839d-49640463d9c4

📥 Commits

Reviewing files that changed from the base of the PR and between 1684a52 and 35555c9.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (98)
  • web/oss/src/components/DrillInView/OSSdrillInUIProvider.tsx
  • web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/ConfigureProviderDrawerContent.tsx
  • web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/constants.ts
  • web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/types.d.ts
  • web/oss/src/components/ModelRegistry/Modals/ConfigureProviderModal/assets/types.d.ts
  • web/oss/src/components/ModelRegistry/Modals/ConfigureProviderModal/index.tsx
  • web/oss/src/components/ModelRegistry/Modals/DeleteProviderModal/assets/types.d.ts
  • web/oss/src/components/ModelRegistry/Modals/DeleteProviderModal/index.tsx
  • web/oss/src/components/Playground/Components/PlaygroundGenerations/assets/GatewayToolExecuteButton.tsx
  • web/oss/src/components/Playground/Components/PlaygroundVariantConfigPrompt/assets/GatewayToolsPanel.tsx
  • web/oss/src/components/Playground/Playground.tsx
  • web/oss/src/components/Sidebar/hooks/useDropdownItems/types.d.ts
  • web/oss/src/components/pages/app-management/modals/CustomWorkflowModal/hooks/useCustomWorkflowConfig.tsx
  • web/oss/src/components/pages/evaluations/NewEvaluation/Components/NewEvaluationModalInner.tsx
  • web/oss/src/components/pages/settings/Secrets/SecretProviderTable/index.tsx
  • web/oss/src/components/pages/settings/Tools/components/ActionsList.tsx
  • web/oss/src/components/pages/settings/Tools/components/ConnectionsList.tsx
  • web/oss/src/components/pages/settings/Tools/components/GatewayToolsSection.tsx
  • web/oss/src/components/pages/settings/Tools/components/IntegrationGrid.tsx
  • web/oss/src/components/pages/settings/Tools/hooks/useIntegrationDetail.ts
  • web/oss/src/components/pages/settings/Tools/hooks/useToolsConnections.ts
  • web/oss/src/components/pages/settings/Tools/hooks/useToolsIntegrations.ts
  • web/oss/src/components/pages/settings/WorkspaceManage/cellRenderers.tsx
  • web/oss/src/features/gateway-tools/components/ScrollSentinel.tsx
  • web/oss/src/features/gateway-tools/components/ScrollToTopButton.tsx
  • web/oss/src/features/gateway-tools/index.ts
  • web/oss/src/features/gateway-tools/utils/slugify.ts
  • web/oss/src/hooks/useLLMProviderConfig.tsx
  • web/oss/src/hooks/useVaultSecret.ts
  • web/oss/src/lib/Types.ts
  • web/oss/src/lib/helpers/llmProviders.ts
  • web/oss/src/lib/helpers/utils.ts
  • web/oss/src/services/app-selector/api/index.ts
  • web/oss/src/services/tools/api/index.ts
  • web/oss/src/services/tools/api/types.ts
  • web/oss/src/services/vault/api/index.ts
  • web/oss/src/state/Providers.tsx
  • web/oss/src/state/app/index.ts
  • web/oss/src/state/org/selectors/org.ts
  • web/oss/src/state/profile/UserListener.tsx
  • web/oss/src/state/profile/selectors/user.ts
  • web/oss/src/state/project/selectors/project.ts
  • web/packages/agenta-entities/package.json
  • web/packages/agenta-entities/src/gatewayTool/api/api.ts
  • web/packages/agenta-entities/src/gatewayTool/api/client.ts
  • web/packages/agenta-entities/src/gatewayTool/api/index.ts
  • web/packages/agenta-entities/src/gatewayTool/core/index.ts
  • web/packages/agenta-entities/src/gatewayTool/core/types.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/index.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useActionDetail.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useCatalogActions.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useCatalogIntegrations.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useConnectionActions.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useConnectionQuery.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useConnectionsQuery.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useIntegrationConnections.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useIntegrationDetail.ts
  • web/packages/agenta-entities/src/gatewayTool/hooks/useToolExecution.ts
  • web/packages/agenta-entities/src/gatewayTool/index.ts
  • web/packages/agenta-entities/src/gatewayTool/prompt/atoms.ts
  • web/packages/agenta-entities/src/gatewayTool/prompt/index.ts
  • web/packages/agenta-entities/src/gatewayTool/state/atoms.ts
  • web/packages/agenta-entities/src/gatewayTool/state/index.ts
  • web/packages/agenta-entities/src/index.ts
  • web/packages/agenta-entities/src/secret/README.md
  • web/packages/agenta-entities/src/secret/api/api.ts
  • web/packages/agenta-entities/src/secret/api/client.ts
  • web/packages/agenta-entities/src/secret/api/index.ts
  • web/packages/agenta-entities/src/secret/core/index.ts
  • web/packages/agenta-entities/src/secret/core/transforms.ts
  • web/packages/agenta-entities/src/secret/core/types.ts
  • web/packages/agenta-entities/src/secret/index.ts
  • web/packages/agenta-entities/src/secret/state/atoms.ts
  • web/packages/agenta-entities/src/secret/state/index.ts
  • web/packages/agenta-entities/src/secret/state/useVaultSecret.ts
  • web/packages/agenta-entity-ui/package.json
  • web/packages/agenta-entity-ui/src/gatewayTool/components/ConnectionStatusBadge.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/components/ResultViewer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/components/SchemaForm.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/CatalogDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/ConnectDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/ConnectionManagerDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/drawers/ToolExecutionDrawer.tsx
  • web/packages/agenta-entity-ui/src/gatewayTool/index.ts
  • web/packages/agenta-shared/src/api/env.ts
  • web/packages/agenta-shared/src/api/index.ts
  • web/packages/agenta-shared/src/hooks/index.ts
  • web/packages/agenta-shared/src/hooks/useDebouncedAtomSearch.ts
  • web/packages/agenta-shared/src/state/index.ts
  • web/packages/agenta-shared/src/state/user.ts
  • web/packages/agenta-shared/src/types/index.ts
  • web/packages/agenta-shared/src/types/llmProvider.ts
  • web/packages/agenta-shared/src/types/user.ts
  • web/packages/agenta-shared/src/utils/gatewayToolSchema.ts
  • web/packages/agenta-shared/src/utils/index.ts
  • web/packages/agenta-shared/src/utils/llmProviders.ts
  • web/packages/agenta-shared/src/utils/objectUtils.ts
  • web/packages/agenta-ui/src/SelectLLMProvider/README.md
💤 Files with no reviewable changes (10)
  • web/oss/src/services/tools/api/types.ts
  • web/oss/src/hooks/useVaultSecret.ts
  • web/oss/src/lib/helpers/llmProviders.ts
  • web/oss/src/features/gateway-tools/utils/slugify.ts
  • web/oss/src/features/gateway-tools/components/ScrollToTopButton.tsx
  • web/oss/src/features/gateway-tools/components/ScrollSentinel.tsx
  • web/oss/src/state/app/index.ts
  • web/oss/src/services/tools/api/index.ts
  • web/oss/src/services/vault/api/index.ts
  • web/oss/src/features/gateway-tools/index.ts

Comment thread web/oss/src/lib/Types.ts
Comment on lines +113 to +117
// Secret-domain types (HeaderDTO, StandardSecretDTO, CustomSecretDTO,
// VaultData, SecretDTOKind, SecretDTOProvider, PROVIDER_KINDS,
// PROVIDER_LABELS, etc.) live in @agenta/entities/secret. Import from
// there directly — re-exporting from @agenta packages is disallowed
// (see eslint no-restricted-syntax rule for tree-shaking).
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for any imports of the removed types from `@/oss/lib/Types`

echo "=== Checking for imports of removed secret types from Types.ts ==="
rg -n --type=ts --type=tsx "from ['\"]`@/oss/lib/Types`['\"]" -A5 | rg -i "(HeaderDTO|StandardSecret|SecretDTO|SecretDTOKind|SecretDTOProvider|PROVIDER_LABELS|PROVIDER_KINDS|CustomSecretDTO)" || echo "No secret type imports found"

echo ""
echo "=== Checking for User imports from Types.ts ==="
rg -n --type-add 'ts:*.{ts,tsx}' --type=ts "import.*User.*from ['\"]`@/oss/lib/Types`['\"]" || echo "No User imports from Types.ts found"

echo ""
echo "=== Checking for any remaining usage of removed constants ==="
rg -n --type-add 'ts:*.{ts,tsx}' --type=ts "\b(PROVIDER_LABELS|PROVIDER_KINDS)\b" web/oss/src/ || echo "No PROVIDER_LABELS/PROVIDER_KINDS usage found"

Repository: Agenta-AI/agenta

Length of output: 1424


🏁 Script executed:

#!/bin/bash

# Get the actual import line from the billing atoms file
echo "=== Actual import statement in billing atoms.ts ==="
sed -n '1,20p' web/ee/src/state/billing/atoms.ts | cat -n

echo ""
echo "=== Check if User exists in `@agenta/shared/types` ==="
# Find all files in shared/types
find . -path "./web/*/node_modules" -prune -o -type f -name "*types*" -path "*/shared/*" -print | head -20

echo ""
echo "=== Search for User export in shared package ==="
rg "export.*User" --type=ts --type=tsx | grep -i "shared\|types" | head -20

echo ""
echo "=== Check actual imports in ConfigureProviderDrawerContent.tsx ==="
head -20 web/oss/src/components/ModelRegistry/Drawers/ConfigureProviderDrawer/assets/ConfigureProviderDrawerContent.tsx | cat -n

Repository: Agenta-AI/agenta

Length of output: 2388


🏁 Script executed:

#!/bin/bash

echo "=== Search for all User type definitions/exports ==="
rg "export.*type.*User\b|export.*interface.*User\b" --type=ts --type=tsx | head -30

echo ""
echo "=== Check `@agenta/shared/types` exports ==="
find . -path "*/node_modules" -prune -o -path "*/web/packages/agenta-shared/*" -type f -name "*.ts" -print | xargs grep -l "export.*User" 2>/dev/null | head -10

echo ""
echo "=== Check the exact file at `@agenta/shared/types` path ==="
ls -la web/packages/agenta-shared/src/types/ 2>/dev/null || ls -la web/packages/agenta-shared/src/ 2>/dev/null || find web/packages/agenta-shared -name "types.ts" -o -name "types" -type d

echo ""
echo "=== Full content search for User type in agenta-shared ==="
rg "User" web/packages/agenta-shared --type=ts --type=tsx -A2 -B2 | head -50

Repository: Agenta-AI/agenta

Length of output: 895


🏁 Script executed:

#!/bin/bash

echo "=== Check User type in agenta-shared/src/types/user.ts ==="
cat -n web/packages/agenta-shared/src/types/user.ts

echo ""
echo "=== Check index exports in agenta-shared/src/types/index.ts ==="
cat -n web/packages/agenta-shared/src/types/index.ts

echo ""
echo "=== Check what's exported from agenta-shared/src/state/user.ts ==="
cat -n web/packages/agenta-shared/src/state/user.ts

echo ""
echo "=== Check current Types.ts to see what User was exported ==="
grep -n "User" web/oss/src/lib/Types.ts | head -20

Repository: Agenta-AI/agenta

Length of output: 3028


Migrate remaining User import from removed location in web/ee/src/state/billing/atoms.ts.

The User type has been removed from this file. One consumer was missed during migration: web/ee/src/state/billing/atoms.ts line 6 still imports from @/oss/lib/Types. Update it to import from @agenta/shared/types instead (the User type is properly exported there). The secret-domain types have been correctly migrated by consumers.

Comment on lines +57 to +76
export const fetchActions = async (
providerKey: string,
integrationKey: string,
params?: {
query?: string
categories?: string[]
limit?: number
cursor?: string
important?: boolean
},
): Promise<ToolCatalogActionsResponse> => {
return getToolsClient().listToolActions(
{
provider_key: providerKey,
integration_key: integrationKey,
query: params?.query,
categories: params?.categories,
limit: params?.limit,
cursor: params?.cursor,
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

important filter is accepted but never sent to the backend.

fetchActions exposes important (Line 65) but the request payload omits it, so callers cannot actually filter by importance.

Proposed fix
 export const fetchActions = async (
@@
     return getToolsClient().listToolActions(
         {
             provider_key: providerKey,
             integration_key: integrationKey,
             query: params?.query,
             categories: params?.categories,
+            important: params?.important,
             limit: params?.limit,
             cursor: params?.cursor,
         },
         projectScopedRequest(),
     )
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const fetchActions = async (
providerKey: string,
integrationKey: string,
params?: {
query?: string
categories?: string[]
limit?: number
cursor?: string
important?: boolean
},
): Promise<ToolCatalogActionsResponse> => {
return getToolsClient().listToolActions(
{
provider_key: providerKey,
integration_key: integrationKey,
query: params?.query,
categories: params?.categories,
limit: params?.limit,
cursor: params?.cursor,
},
export const fetchActions = async (
providerKey: string,
integrationKey: string,
params?: {
query?: string
categories?: string[]
limit?: number
cursor?: string
important?: boolean
},
): Promise<ToolCatalogActionsResponse> => {
return getToolsClient().listToolActions(
{
provider_key: providerKey,
integration_key: integrationKey,
query: params?.query,
categories: params?.categories,
important: params?.important,
limit: params?.limit,
cursor: params?.cursor,
},
projectScopedRequest(),
)
}

Comment thread web/packages/agenta-entities/src/secret/api/api.ts Outdated
Comment thread web/packages/agenta-entities/src/secret/core/transforms.ts Outdated
Comment thread web/packages/agenta-entities/src/secret/README.md Outdated
Comment thread web/packages/agenta-entities/src/secret/state/atoms.ts Outdated
Comment thread web/packages/agenta-shared/src/api/env.ts Outdated
Comment on lines +13 to +36
export const removeEmptyFromObjects = <T = unknown>(obj: T): T => {
if (Array.isArray(obj)) {
return obj
.map((item) => removeEmptyFromObjects(item))
.filter(
(item) =>
item != null &&
(typeof item !== "object" || Object.keys(item as object).length > 0),
) as unknown as T
}
if (obj && typeof obj === "object") {
return Object.entries(obj as Record<string, unknown>).reduce(
(acc, [key, value]) => {
const cleaned = removeEmptyFromObjects(value)
if (cleaned !== null && cleaned !== undefined && cleaned !== "") {
acc[key] = cleaned
}
return acc
},
{} as Record<string, unknown>,
) as unknown as T
}
return obj
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Implementation doesn't match documentation for empty arrays and objects in object values.

The documentation claims to remove "empty objects ({})" and "empty arrays after recursive cleanup," but the implementation is inconsistent:

Array items (lines 17-21): Empty arrays and objects ARE filtered via Object.keys(item).length > 0.

Object values (line 27): Only checks !== null, !== undefined, and !== "", so empty arrays and objects are KEPT.

Example demonstrating the bug:

removeEmptyFromObjects({outer: [{inner: []}, {}]})
// Returns: {outer: []} — array items filtered correctly

removeEmptyFromObjects({a: [], b: {}})
// Returns: {a: [], b: {}} — object values NOT filtered
🛡️ Proposed fix to align implementation with documentation
 export const removeEmptyFromObjects = <T = unknown>(obj: T): T => {
     if (Array.isArray(obj)) {
         return obj
             .map((item) => removeEmptyFromObjects(item))
             .filter(
                 (item) =>
                     item != null &&
                     (typeof item !== "object" || Object.keys(item as object).length > 0),
             ) as unknown as T
     }
     if (obj && typeof obj === "object") {
         return Object.entries(obj as Record<string, unknown>).reduce(
             (acc, [key, value]) => {
                 const cleaned = removeEmptyFromObjects(value)
-                if (cleaned !== null && cleaned !== undefined && cleaned !== "") {
+                if (
+                    cleaned !== null &&
+                    cleaned !== undefined &&
+                    cleaned !== "" &&
+                    !(Array.isArray(cleaned) && cleaned.length === 0) &&
+                    !(typeof cleaned === "object" && Object.keys(cleaned as object).length === 0)
+                ) {
                     acc[key] = cleaned
                 }
                 return acc
             },
             {} as Record<string, unknown>,
         ) as unknown as T
     }
     return obj
 }

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

Railway Preview Environment

Status Destroyed (PR closed)

Updated at 2026-05-19T19:27:42.448Z

…OSS _app

Without this the @agenta/sdk singleton falls back to its built-in default
host (https://cloud.agenta.ai) because AGENTA_HOST is only set server-side,
so staging/preview deployments would issue tools/secrets requests against
the production origin and trip CORS.
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels May 19, 2026
Copy link
Copy Markdown

@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 (1)
web/oss/src/components/pages/_app/index.tsx (1)

27-32: 💤 Low value

Consider adding error handling for SDK initialization.

If getAgentaApiUrl() or getAgentaSdkClient() throws during module load, the entire app will fail to initialize. Consider wrapping this in a try-catch to handle potential initialization failures gracefully.

🛡️ Proposed defensive initialization
-// Pin the workspace Fern-client singleton to the host this deployment
-// actually talks to. Without this the SDK defaults to `https://cloud.agenta.ai`
-// (its built-in fallback) because `AGENTA_HOST` is only set server-side —
-// staging/preview deployments would otherwise issue tools/secrets requests
-// against the production origin.
-getAgentaSdkClient({host: getAgentaApiUrl()})
+// Pin the workspace Fern-client singleton to the host this deployment
+// actually talks to. Without this the SDK defaults to `https://cloud.agenta.ai`
+// (its built-in fallback) because `AGENTA_HOST` is only set server-side —
+// staging/preview deployments would otherwise issue tools/secrets requests
+// against the production origin.
+try {
+    getAgentaSdkClient({host: getAgentaApiUrl()})
+} catch (error) {
+    console.error("Failed to initialize Agenta SDK:", error)
+    // SDK will fall back to default host
+}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 285261e9-638a-4b48-9c06-df4357735f88

📥 Commits

Reviewing files that changed from the base of the PR and between 35555c9 and 3088aad.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • web/oss/package.json
  • web/oss/src/components/pages/_app/index.tsx

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label May 19, 2026
@junaway junaway changed the base branch from main to release/v0.100.0 May 19, 2026 17:32
ardaerzin added 2 commits May 19, 2026 20:14
…ation

- Forward `important` filter through queryParams in fetchActions (Fern's
  ListToolActionsRequest doesn't model it, but the backend honours it).
- Include port in origin fallback so getAgentaApiUrl/getAgentaWebUrl return
  the right URL on non-default ports (was dropping :3000 in local dev).
- Switch EE billing atoms to import User from @agenta/shared/types (the
  type was removed from @/oss/lib/Types when secrets were lifted).
- Prefer the matched server-side secret id when deciding update vs create
  so the update path is reached when callers seed LlmProvider without id.
- Make removeEmptyFromObjects actually strip empty objects/arrays from
  object values (the docstring already advertised this, the object branch
  didn't enforce it).
- Use a stable per-row key fallback for connections in GatewayToolsPanel
  (`integrationKey-index`) so missing id+slug doesn't collide on "".
- Guard redirect_url with typeof === "string" in ConnectDrawer instead of
  casting unknown to string.
- Skip opening the execution drawer when a connection lacks id or slug
  rather than passing empty strings.
Addresses remaining CodeRabbit threads on the secrets migration:

- createVaultSecret/updateVaultSecret/deleteVaultSecret now take/return the
  typed Fern request/response shapes derived from getSecretsClient(). The
  fake <T> generics + `as unknown as` casts are gone; callers get real
  compile-time checks on payload shape.
- transformSecret and getEnvNameMap now share a single
  STANDARD_PROVIDER_ENV_BY_KIND source of truth (kind → env) — getEnvNameMap
  derives the reverse via Object.entries. Unmapped standard provider kinds
  are now logged + dropped instead of surfacing as nameless rows.
- Secret mutation atoms no longer reach for getDefaultStore() to read
  projectId. Callers (createStandardSecretAtom / createCustomSecretAtom /
  deleteSecretAtom) read it via the atom's own `get` and pass it explicitly
  via mutateAsync — the mutation atoms themselves are now pure forwarders.
- README: added `text` language tag to the folder-shape fenced block, and
  refreshed the api.ts comment now that it's Fern-backed.
@ardaerzin ardaerzin merged commit 5f09a5c into release/v0.100.0 May 19, 2026
9 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Frontend lgtm This PR has been approved by a maintainer refactoring A code change that neither fixes a bug nor adds a feature size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants