Skip to content

Conversation

@vishnurk6247
Copy link
Member

@vishnurk6247 vishnurk6247 commented Dec 11, 2025

Summary by CodeRabbit

  • New Features

    • Wavefront web console: apps for agents, APIs, datasources, workflows/pipelines, knowledge bases, models, and voice agents.
    • Chat UI with file/image attachments, model selection, variables, and real-time event streaming.
    • Model inference, knowledge-base augmentation (RAG), pipeline/job submission, and voice/telephony integrations.
    • New UI components, icons, and consistent theming.
  • Infrastructure

    • CI workflow and Docker build/publish for the web console.
  • Documentation

    • Client README and runtime config examples added.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 11, 2025

Walkthrough

Adds a new Wavefront web client: project scaffold, Docker builds, CI workflow, Express runtime server, global styles, extensive React UI primitives and components, typed Axios API services, React Query hooks/mutations, provider configs, and numerous asset/icon files.

Changes

Cohort / File(s) Change Summary
Build & Ignore
\.dockerignore`, `.gitignore`, .vscode/launch.json`
Added/updated ignore rules and a minimal VSCode launch config.
CI / Deployment
.github/workflows/build-wavefront-web-develop.yaml
New GitHub Actions workflow to build and push client Docker image to Google Artifact Registry.
Dockerfiles
docker/floware.Dockerfile, wavefront/client/Dockerfile
New multi-stage Dockerfiles: backend UV runtime image and PNPM-based client build/runtime image.
Client root & runtime
wavefront/client/{index.html,package.json,README.md,components.json,postcss.config.js,pnpm-workspace.yaml,.env}, wavefront/client/public/config.js, wavefront/client/server.cjs
New project manifest, HTML entry, runtime config, PostCSS, pnpm workspace, README, env, and an Express server serving dist with /config.js endpoint, CSP nonce, compression and caching.
Global styles & icons
wavefront/client/src/index.css, wavefront/client/src/assets/icons/*, wavefront/client/src/assets/icons/index.ts
Added Tailwind-based global CSS, theme tokens, fonts, many SVG icon components and an icons barrel.
UI primitives (Radix/Tailwind)
wavefront/client/src/components/ui/* (alert, dialog, button, select, form, field, table, popover, dropdown-menu, tabs, input, textarea, spinner, skeleton, slider, switch, tooltip, breadcrumb, etc.)
Large accessible UI library with forwardRef wrappers, variants, and composable primitives.
Domain components
wavefront/client/src/components/* (Topbar, DashboardLayout, ProtectedLayout, ResourceCard, cards, ChatBot, Stream, InferencePopup, DeleteConfirmationDialog, EmptyCard, etc.)
New layout, navigation, resource cards, chat/inference UI, streaming events panel, modals and utility components.
API services
wavefront/client/src/api/*-service.ts (agent, app, api-service, datasources, workflows, knowledge-base, llm-inference, model-inference, message-processor, telephony/tts/stt, user, voice-agent, tool, etc.)
Many typed Axios-based service clients implementing CRUD and action endpoints for backend APIs.
API service index & HTTP client
wavefront/client/src/api/index.ts, wavefront/client/src/lib/axios.ts, wavefront/client/src/lib/constants.ts
FloConsoleService singleton exposing per-domain services; configured Axios instance with baseURL, token injection, :appId replacement, response error handling/401 logic; exported token/path constants.
Config modules
wavefront/client/src/config/{env,authenticators,llm-providers,telephony-providers,voice-providers}.ts
Provider metadata, parameter schemas, defaults, helpers, and runtime env detection/feature flags.
Hooks & data layer
wavefront/client/src/hooks/data/{query-keys,query-functions,fetch-hooks,mutation-functions,mutation-hooks}.ts, wavefront/client/src/hooks/data/index.ts, wavefront/client/src/hooks/index.ts
React Query integration: key generators, query functions, ~40+ fetch hooks, mutation helpers/hooks, and consolidated re-exports.
App entry & utils
wavefront/client/src/App.tsx, various new utility modules
App root component reads token and sets authentication state; multiple new utility helpers and glue code.
Misc & tooling
other added files under wavefront/client/ and workspace configs
Additional project files, README, and workspace/tooling updates.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

  • Areas requiring extra attention:
    • wavefront/client/src/lib/axios.ts — interceptors, :appId replacement, notification/redirect side-effects.
    • wavefront/client/server.cjs — CSP nonce injection, config endpoint, caching and security headers.
    • DashboardLayout.tsx — inactivity timer, BroadcastChannel cross-tab sync and cleanup.
    • InferencePopup.tsx and ChatBot.tsx — file validations, base64 conversions, form validation, submission flow and error handling.
    • hooks/data (query-functions, fetch-hooks, mutation-hooks) — query keys, enablement conditions, cache invalidation correctness.
    • api service implementations and api/index.ts — consistent base paths, content-type handling (text/plain cases), and shared Axios usage.
    • dropdown-menu, command palette, and other complex UI primitives — accessibility and focus/portal behavior.

Poem

🐇 I nibbled code and stitched a tiny stream,

Icons, hooks, and servers in a dream.
Docker hums, CI sings a gentle rhyme,
I hopped through files and saved you build-time.
— From the rabbit, with a joyful chime.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The PR title 'chore: import wavefront client and server' is vague and does not clearly describe the substantial changes in this changeset. Revise the title to be more specific about the primary changes, such as 'feat: add wavefront web client with React+TypeScript setup and Docker support' or 'feat: add wavefront web client application' to accurately reflect the main additions.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch wavefront

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.

Comment on lines +17 to +69
runs-on: ubuntu-latest

steps:
- name: "Checkout"
uses: "actions/checkout@v3"

- name: Get commit hash
id: get-commit-hash
run: echo "::set-output name=commit-hash::$(git rev-parse --short HEAD)"

- name: Get timestamp
id: get-timestamp
run: echo "::set-output name=timestamp::$(date +'%Y-%m-%d-%H-%M')"

- name: Cache Docker layers
id: cache-docker-layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-docker-${{ github.sha }}
restore-keys: |
${{ runner.os }}-docker-

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build Docker Image
id: build-image
run: |
docker build -f wavefront/client/Dockerfile -t rootflo:${{ steps.get-commit-hash.outputs.commit-hash }}-${{ steps.get-timestamp.outputs.timestamp }} .
echo "IMAGE_TAG=${{ steps.get-commit-hash.outputs.commit-hash }}-${{ steps.get-timestamp.outputs.timestamp }}" >> $GITHUB_ENV

- id: "Auth-to-GCP"
uses: "google-github-actions/auth@v1"
with:
credentials_json: "${{ secrets.GCP_SERVICE_ACCOUNT_KEY }}"

- name: "Set up Cloud SDK"
uses: "google-github-actions/setup-gcloud@v1"

- name: "Docker auth for GCP"
run: |-
gcloud auth configure-docker ${{ env.GCP_REGION }}-docker.pkg.dev --quiet

- name: Tag and push image to GCP Artifact Registry
run: |
docker tag rootflo:${{ env.IMAGE_TAG }} ${{ env.GAR_LOCATION }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
docker push ${{ env.GAR_LOCATION }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}

- name: Cleanup Docker images
run: |
docker rmi rootflo:${{ env.IMAGE_TAG }} || true
docker rmi ${{ env.GAR_LOCATION }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} || true

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

Copilot Autofix

AI about 1 month ago

To fix the problem, you should add a permissions block following the principle of least privilege. This allows the workflow or job to run only with the minimal GitHub token permissions required, preventing unauthorized or accidental write operations to the repository. As none of the jobs in the provided workflow require write access to repository contents or metadata, the minimal setting is appropriate: at the workflow or job level, add permissions: contents: read. The block can be added after the name: line at the top (root-level, affecting all jobs), or directly in the build-push-artifact job block if more granular control is desired. The recommendation is to add it at the root for maximum coverage and clarity. No imports or special methods are needed.


Suggested changeset 1
.github/workflows/build-wavefront-web-develop.yaml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/build-wavefront-web-develop.yaml b/.github/workflows/build-wavefront-web-develop.yaml
--- a/.github/workflows/build-wavefront-web-develop.yaml
+++ b/.github/workflows/build-wavefront-web-develop.yaml
@@ -1,4 +1,6 @@
 name: (Develop) Build and Push Wavefront Web app to AWS and GCP
+permissions:
+  contents: read
 
 on:
   workflow_dispatch:
EOF
@@ -1,4 +1,6 @@
name: (Develop) Build and Push Wavefront Web app to AWS and GCP
permissions:
contents: read

on:
workflow_dispatch:
Copilot is powered by AI and may make mistakes. Always verify output.
logger.error(f'{error_msg} with error as {str(error)}')
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=ResponseFormatter.buildErrorResponse(str(error)),
logger.error(f'{error_msg} with error as {str(error)}')
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=ResponseFormatter.buildErrorResponse(str(error)),
logger.error(f'{error_msg} with error as {str(error)}')
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content=ResponseFormatter.buildErrorResponse(str(error)),
Copy link

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

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

♻️ Duplicate comments (4)
wavefront/client/src/assets/icons/datasources.tsx (1)

1-14: Same React import verification needed.

This component has the same TypeScript type reference without React import as noted in ai-agent-icon.tsx.

wavefront/client/src/assets/icons/model-repository-icon.tsx (1)

1-13: Same React import verification needed.

This component has the same TypeScript type reference without React import as noted in ai-agent-icon.tsx.

wavefront/client/src/assets/icons/workflow-icon.tsx (1)

1-18: Same React import verification needed.

This component has the same TypeScript type reference without React import as noted in ai-agent-icon.tsx.

wavefront/client/src/assets/icons/rag-icon.tsx (1)

1-12: Same React import verification needed.

This component has the same TypeScript type reference without React import as noted in ai-agent-icon.tsx.

🟠 Major comments (16)
wavefront/client/src/assets/icons/api-icon.tsx-13-23 (1)

13-23: Add props parameter for consistency and reusability.

ApiActiveIcon should also accept props for consistency with other icons in this set.

Apply this diff:

-const ApiActiveIcon = () => (
-  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14">
+const ApiActiveIcon = ({ ...props }: React.SVGProps<SVGSVGElement>) => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14" {...props}>
wavefront/client/src/assets/icons/api-icon.tsx-1-11 (1)

1-11: Add props parameter for consistency and reusability.

ApiIcon doesn't accept props, unlike other icons in this set (e.g., AiAgentIcon, DatasourcesIcon). This limits reusability.

Apply this diff:

-const ApiIcon = () => (
-  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14">
+const ApiIcon = ({ ...props }: React.SVGProps<SVGSVGElement>) => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14" {...props}>
wavefront/client/src/assets/icons/permission-icon.tsx-1-22 (1)

1-22: Add props parameter and use implicit return for consistency.

PermissionIcon doesn't accept props, unlike other icons in this set. This limits reusability and is inconsistent with icons like AiAgentIcon, DatasourcesIcon, etc.

Apply this diff:

-const PermissionIcon = () => {
-  return (
-    <svg xmlns="http://www.w3.org/2000/svg" width="13" height="14" fill="none" viewBox="0 0 13 14">
+const PermissionIcon = ({ ...props }: React.SVGProps<SVGSVGElement>) => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="13" height="14" fill="none" viewBox="0 0 13 14" {...props}>
     <g id="vuesax/linear/shield-security">
       <g id="shield-security" stroke="#22A622" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.1">
         <path
           id="Vector"
           d="M5.682 1.708 2.98 2.726c-.623.233-1.132.97-1.132 1.63v4.025c0 .64.423 1.479.937 1.864l2.33 1.738c.763.575 2.02.575 2.783 0l2.33-1.738c.514-.385.937-1.225.937-1.864V4.357c0-.667-.51-1.403-1.132-1.636L7.329 1.708c-.46-.168-1.197-.168-1.647 0"
         ></path>
         <path
           id="Vector_2"
           strokeMiterlimit="10"
           d="M6.5 7.271a1.083 1.083 0 1 0 0-2.167 1.083 1.083 0 0 0 0 2.167"
         ></path>
         <path id="Vector_3" strokeMiterlimit="10" d="M6.5 7.27v1.626"></path>
       </g>
     </g>
   </svg>
-  );
-};
+);
wavefront/client/src/assets/icons/phone-icon.tsx-10-19 (1)

10-19: Refactor for consistency: accept props and use implicit return.

PhoneActiveIcon should accept props for consistency with other icons and can use implicit return for cleaner code.

Apply this diff:

-const PhoneActiveIcon = () => {
-  return (
-    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14">
+const PhoneActiveIcon = ({ ...props }: React.SVGProps<SVGSVGElement>) => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14" {...props}>
     <path
       fill="#0080E2"
       d="M6.446 8.72 5.366 9.8a.586.586 0 0 1-.822.006c-.064-.064-.128-.123-.192-.187a16.6 16.6 0 0 1-1.628-1.907 10.4 10.4 0 0 1-1.143-1.99q-.413-.996-.414-1.907c0-.397.07-.776.21-1.126q.208-.535.67-.974c.374-.367.782-.548 1.214-.548.163 0 .327.035.472.105a.95.95 0 0 1 .391.326l1.354 1.908c.105.146.18.28.233.408a.9.9 0 0 1 .082.356q0 .211-.123.414a2 2 0 0 1-.327.414L4.9 5.56a.31.31 0 0 0-.093.234.5.5 0 0 0 .017.134c.018.046.035.081.047.116q.158.291.542.747.393.456.846.922c.059.058.123.116.181.175.233.227.24.6.006.834M12.816 10.693c0 .163-.03.332-.088.495q-.024.07-.058.14c-.1.21-.227.409-.397.595a2.6 2.6 0 0 1-.956.689c-.006 0-.012.005-.018.005-.344.14-.717.216-1.12.216q-.894.001-1.901-.425-1.008-.429-2.007-1.155c-.228-.17-.455-.339-.67-.52l1.907-1.907q.246.183.431.28c.03.011.064.029.105.046a.4.4 0 0 0 .146.024.32.32 0 0 0 .24-.1l.443-.437a1.8 1.8 0 0 1 .42-.326.8.8 0 0 1 .414-.123q.164-.002.356.076.19.078.408.227l1.93 1.371a.9.9 0 0 1 .322.373c.058.146.093.292.093.456"
     ></path>
   </svg>
-  );
-};
+);
wavefront/client/src/assets/icons/phone-icon.tsx-1-9 (1)

1-9: Add props parameter for consistency and reusability.

PhoneIcon doesn't accept props, unlike other icons in this set (e.g., AiAgentIcon, DatasourcesIcon). This limits the ability to pass common SVG attributes like className, onClick, aria-label, etc.

Apply this diff to accept and spread props:

-const PhoneIcon = () => (
-  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14">
+const PhoneIcon = ({ ...props }: React.SVGProps<SVGSVGElement>) => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14" {...props}>
wavefront/client/server.cjs-50-68 (1)

50-68: CSP missing connect-src directive — API requests may be blocked.

The Content-Security-Policy lacks a connect-src directive. This will default to default-src 'self', which may block API calls to BASE_URL if it's on a different origin.

Add connect-src to allow API requests:

   const imgSrc = `'self' https://storage.googleapis.com data:`;
+  const connectSrc = `'self' ${BASE_URL}`;

   res.set({
     // ...
-    'Content-Security-Policy': `default-src ${defaultSrc}; script-src ${scriptSrc}; style-src ${styleSrc}; frame-ancestors ${frameAncestors}; img-src ${imgSrc}; media-src ${mediaSrc}`,
+    'Content-Security-Policy': `default-src ${defaultSrc}; script-src ${scriptSrc}; style-src ${styleSrc}; frame-ancestors ${frameAncestors}; img-src ${imgSrc}; media-src ${mediaSrc}; connect-src ${connectSrc}`,

Committable suggestion skipped: line range outside the PR's diff.

wavefront/client/server.cjs-23-36 (1)

23-36: Potential XSS via JSON injection and missing cache headers.

Two concerns with this endpoint:

  1. XSS risk: If any config value contains </script>, it could break out of the script context. Use proper escaping.
  2. Missing cache headers: Config may change between deployments; add Cache-Control: no-store to prevent stale config.
 app.get('/config.js', (req, res) => {
   const config = {
     BASE_URL,
     APP_ENV,
     FEATURE_API_SERVICES,
   };

   res.setHeader('Content-Type', 'application/javascript');
   res.set({
+    'Cache-Control': 'no-store',
     'X-Content-Type-Options': 'nosniff',
     'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
   });
-  res.send(`window.__APP_CONFIG__ = ${JSON.stringify(config)};`);
+  // Escape </script> to prevent XSS
+  const safeJson = JSON.stringify(config).replace(/</g, '\\u003c');
+  res.send(`window.__APP_CONFIG__ = ${safeJson};`);
 });
wavefront/client/server.cjs-70-77 (1)

70-77: Synchronous file read blocks the event loop on every request.

fs.readFileSync is called on every request to the catch-all route, which blocks the Node.js event loop and degrades performance under load.

Consider caching the file content at startup and only re-reading in development:

+const fs = require('fs');
+
+// Cache index.html content at startup
+let indexContent;
+function getIndexContent() {
+  if (!indexContent || process.env.NODE_ENV === 'development') {
+    indexContent = fs.readFileSync(path.join(__dirname, 'dist', 'index.html'), 'utf8');
+  }
+  return indexContent;
+}
+
 app.get('*', (req, res) => {
   // Generate nonce for CSP
   const nonce = crypto.randomBytes(16).toString('base64');
   // ... headers setup ...
 
-  // Read the index.html file
-  const indexPath = path.join(__dirname, 'dist', 'index.html');
-  const indexContent = require('fs').readFileSync(indexPath, 'utf8');
+  const content = getIndexContent();
 
   // Add nonce to script tags
-  const modifiedContent = indexContent.replace(/<script/g, `<script nonce="${nonce}"`);
+  const modifiedContent = content.replace(/<script/g, `<script nonce="${nonce}"`);
 
   res.send(modifiedContent);
 });

Committable suggestion skipped: line range outside the PR's diff.

wavefront/client/.env-1-5 (1)

1-5: Add .env to .gitignore and use .env.example instead.

The .env file is currently tracked in git, which violates security best practices. Committed .env files can expose secrets if added in the future. Recommended approach:

  1. Create .env.example with placeholder values for this configuration
  2. Add .env to a .gitignore file (none currently exists)
  3. Developers can then copy .env.example to .env locally

Additionally, verify whether VITE_APP_ENV=production is intentional for local development. If you're testing production behavior locally, this is fine; otherwise, consider changing it to development or local to match the actual environment.

wavefront/client/src/components/ResourceCard.tsx-38-44 (1)

38-44: Missing stopPropagation on delete button click.

The delete button is nested inside the clickable card container. Without stopPropagation(), clicking the delete button will also trigger the card's onClick handler, causing unintended navigation alongside the delete action.

         <button
-            onClick={onDeleteClick}
+            onClick={(e) => {
+              e.stopPropagation();
+              onDeleteClick(e);
+            }}
             className="cursor-pointer rounded p-1 text-red-500 opacity-0 transition-opacity hover:bg-red-50 hover:text-red-700 group-hover:opacity-100"
             title={deleteTitle}
           >
wavefront/client/src/index.css-40-47 (1)

40-47: Fix scrollbar visibility selector.

The selector :hover::-webkit-scrollbar-thumb won't work as intended. Pseudo-elements like ::webkit-scrollbar-thumb cannot have hover states directly. The typical pattern is to apply this on the scrollable container.

Consider this approach instead:

 ::-webkit-scrollbar-thumb {
   background: rgb(168, 168, 168);
-  visibility: hidden;
   border-radius: 16px;
 }
-:hover::-webkit-scrollbar-thumb {
-  visibility: visible;
-}

Or if you want to show on container hover:

/* Apply to specific scrollable containers */
.scrollable-container::-webkit-scrollbar-thumb {
  background: rgb(168, 168, 168);
  opacity: 0;
  border-radius: 16px;
  transition: opacity 0.2s;
}
.scrollable-container:hover::-webkit-scrollbar-thumb {
  opacity: 1;
}
wavefront/client/src/config/env.ts-1-3 (1)

1-3: Add type definitions for runtime configuration.

The window.__APP_CONFIG__ global lacks type safety, and getConfig() returns any. This defeats TypeScript's type checking and could lead to runtime errors.

Add a type declaration:

declare global {
  interface Window {
    __APP_CONFIG__?: {
      BASE_URL?: string;
      APP_ENV?: string;
      FEATURE_API_SERVICES?: string;
    };
  }
}

export const getConfig = (): Window['__APP_CONFIG__'] => {
  return window.__APP_CONFIG__ || {};
};
.github/workflows/build-wavefront-web-develop.yaml-3-18 (1)

3-18: Add an explicit permissions block for least-privilege GITHUB_TOKEN

The workflow currently lacks a permissions block, which is a security best practice and flagged by CodeQL. Define minimal permissions required for the workflow to operate.

permissions:
  contents: read
  id-token: write # required for google-github-actions/auth if you migrate to OIDC

You can set this either at the workflow root (line 2) or per-job. Currently, the workflow authenticates to GCP using a service account key via credentials_json; if you transition to OIDC authentication, the id-token: write permission will be necessary.

wavefront/client/src/lib/axios.ts-51-57 (1)

51-57: Handle network errors where err.response is undefined.

When a network error occurs (e.g., server unreachable, CORS failure), err.response is undefined, causing errorData.data?.meta?.error to throw.

   function (err: IAxiosError) {
-    const errorData = err.response as IApiResponse;
-    useNotifyStore.setState({
-      visible: true,
-      type: "error",
-      message: errorData.data?.meta?.error || "Something went wrong",
-    });
+    const errorData = err.response as IApiResponse | undefined;
+    const errorMessage = errorData?.data?.meta?.error || err.message || "Something went wrong";
+    useNotifyStore.setState({
+      visible: true,
+      type: "error",
+      message: errorMessage,
+    });
wavefront/client/src/api/voice-agent-service.ts-59-68 (1)

59-68: Add proper typing for initiateCall response.

The initiateCall method returns Promise<any>, which eliminates type safety. Define a proper response type (e.g., CallInitiationResponse) that describes the structure of the response from the /initiate endpoint.

Create a type definition and apply this diff:

+import { 
+  // ... existing imports
+  CallInitiationResponse,
+} from "@app/types/voice-agent";

 async initiateCall(
   agentId: string,
   data: { to_number: string; from_number?: string }
-): Promise<any> {
+): Promise<CallInitiationResponse> {
-  const response = await this.http.post(
+  const response: IApiResponse</* call data type */> = await this.http.post(
     `/v1/:appId/floware/v1/voice-agents/${agentId}/initiate`,
     data
   );
   return response;
 }

Committable suggestion skipped: line range outside the PR's diff.

wavefront/client/src/api/knowledge-base-service.ts-152-184 (1)

152-184: URL query string built via concatenation lacks proper encoding.

The ragQuery method builds the URL by string concatenation (lines 162-175), which doesn't URL-encode the query parameter. This could cause issues with special characters.

Use axios params for proper encoding:

 async ragQuery(
   kbId: string,
   inferenceId: string,
   query: string,
   threshold?: number,
   topK?: number,
   vectorWeight?: number,
   keywordWeight?: number,
   imageData?: string
 ): Promise<RagInferenceResponse> {
-  let url = `/v1/:appId/floware/v1/knowledge-base/${kbId}/augment/${inferenceId}?query=${query}`;
-
-  if (threshold) {
-    url += `&threshold=${threshold}`;
-  }
-  if (topK) {
-    url += `&top_k=${topK}`;
-  }
-  if (vectorWeight) {
-    url += `&vector_weight=${vectorWeight}`;
-  }
-  if (keywordWeight) {
-    url += `&keyword_weight=${keywordWeight}`;
-  }
+  const params: Record<string, string | number> = { query };
+  if (threshold) params.threshold = threshold;
+  if (topK) params.top_k = topK;
+  if (vectorWeight) params.vector_weight = vectorWeight;
+  if (keywordWeight) params.keyword_weight = keywordWeight;

   const data: { image_data?: string } = {};
   if (imageData) {
     data.image_data = imageData;
   }

-  const response: RagInferenceResponse = await this.http.post(url, data);
+  const response: RagInferenceResponse = await this.http.post(
+    `/v1/:appId/floware/v1/knowledge-base/${kbId}/augment/${inferenceId}`,
+    data,
+    { params }
+  );
   return response;
 }
🟡 Minor comments (18)
wavefront/client/src/components/ui/table.tsx-26-31 (1)

26-31: Fix incorrect Tailwind arbitrary variant syntax.

The className [&>tr]:last:border-b-0 mixes arbitrary variant syntax with Tailwind's modifier syntax incorrectly. This will prevent the style from being applied.

Apply this diff to correct the CSS selector:

-    <tfoot ref={ref} className={cn('bg-muted/50 border-t font-medium [&>tr]:last:border-b-0', className)} {...props} />
+    <tfoot ref={ref} className={cn('bg-muted/50 border-t font-medium [&>tr:last-child]:border-b-0', className)} {...props} />
wavefront/client/src/assets/icons/rootflo-icon.tsx-12-12 (1)

12-12: Fix the escaped newline characters in the style template.

The template literal contains escaped \n characters which appear to be unintentional. These should either be removed or converted to actual newlines for cleaner formatting.

Apply this diff to clean up the formatting:

-        <style>{`\n      .cls-1 {\n        fill: ${color ? color : '#231f20'};\n      }\n    `}</style>
+        <style>{`.cls-1 { fill: ${color ? color : '#231f20'}; }`}</style>
wavefront/client/server.cjs-70-77 (1)

70-77: Missing error handling for missing dist/index.html.

If dist/index.html doesn't exist (e.g., before build), the server will crash with an unhandled exception.

+  const indexPath = path.join(__dirname, 'dist', 'index.html');
+  
+  if (!require('fs').existsSync(indexPath)) {
+    return res.status(500).send('Application not built. Run build first.');
+  }
+  
-  const indexPath = path.join(__dirname, 'dist', 'index.html');
   const indexContent = require('fs').readFileSync(indexPath, 'utf8');
wavefront/client/src/components/ui/empty.tsx-62-73 (1)

62-73: Type and element mismatch in EmptyDescription.

The component is typed with React.ComponentProps<'p'> but renders a <div>. This could cause issues if consumers pass <p>-specific props or if semantic HTML is important for accessibility.

-function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
+function EmptyDescription({ className, ...props }: React.ComponentProps<'div'>) {
   return (
     <div
       data-slot="empty-description"

Alternatively, if paragraph semantics are desired, change the element to <p>:

 function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
   return (
-    <div
+    <p
       data-slot="empty-description"
       className={cn(
         'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
         className
       )}
       {...props}
-    />
+    />
   );
 }
wavefront/client/src/components/ui/separator.tsx-1-1 (1)

1-1: Remove unnecessary 'use client' directive.

The 'use client' directive is specific to Next.js App Router, but the PR summary indicates this project uses Vite. While it may be ignored by Vite, it's unnecessary and could cause confusion.

-'use client';
-
 import * as React from 'react';
wavefront/client/src/config/env.ts-7-9 (1)

7-9: Feature flag parsing is fragile.

The strict string comparison === "true" will only match the exact lowercase string "true". Values like "True", "TRUE", "1", or boolean true will be treated as disabled.

Consider more robust parsing:

 const isApiServicesEnabled =
-  import.meta.env.VITE_FEATURE_API_SERVICES === "true" ||
-  getConfig().FEATURE_API_SERVICES === "true";
+  String(import.meta.env.VITE_FEATURE_API_SERVICES).toLowerCase() === "true" ||
+  String(getConfig().FEATURE_API_SERVICES).toLowerCase() === "true";
wavefront/client/src/api/user-service.ts-19-25 (1)

19-25: Add return type annotation for consistency.

The method is missing a return type annotation, unlike whoAmI() which declares Promise<IApiResponse<{ user: IUser }>>. Add the return type for consistency and better type safety.

Also, consider whether the null body with email as a query parameter is the intended API contract. If the backend can accept the email in the POST body instead, that would be more conventional:

-async resetPasswordEmailSend(email: string) {
-  return this.http.post("/v1/user/send-reset-password-email", null, {
-    params: {
-      email: email,
-    },
-  });
+async resetPasswordEmailSend(email: string): Promise<IApiResponse<unknown>> {
+  return this.http.post("/v1/user/send-reset-password-email", { email });
 }

If the API requires query parameters, keep the current pattern and just add the return type.

Committable suggestion skipped: line range outside the PR's diff.

wavefront/client/src/api/tool-service.ts-20-32 (1)

20-32: Change getToolNamesAndDetails() return type to ToolDetailsResponse

The method calls /v1/:appId/floware/v1/tools/tool-details, which the backend confirms returns ToolDetailsData, not ToolNamesData. Update the method signature and internal type annotation:

-  async getToolNamesAndDetails(): Promise<ToolNamesResponse> {
-    const response: IApiResponse<ToolNamesData> = await this.http.get(
+  async getToolNamesAndDetails(): Promise<ToolDetailsResponse> {
+    const response: IApiResponse<ToolDetailsData> = await this.http.get(
       `/v1/:appId/floware/v1/tools/tool-details`
     );
     return response;
   }

The server-side endpoint /tool-details is registered with ToolDetailsData response model, not ToolNamesData.

wavefront/client/src/lib/axios.ts-34-38 (1)

34-38: Fragile appId extraction from URL path.

The extraction assumes the URL structure is always /xxx/{appId}/.... If the URL structure changes or differs across routes, this will silently produce incorrect values or empty strings.

Consider a more robust approach or centralized route parameter management.

wavefront/client/src/components/DashboardLayout.tsx-28-39 (1)

28-39: Missing navigate in useCallback dependency array.

The resetTimer callback uses navigate but doesn't include it in the dependency array. This could lead to stale closure issues if navigate changes. Also, the @ts-ignore can be replaced with window.setTimeout to get the correct browser return type.

 const resetTimer = useCallback(() => {
   if (timeoutRef.current) {
     clearTimeout(timeoutRef.current);
   }
-  // @ts-ignore
-  timeoutRef.current = setTimeout(
+  timeoutRef.current = window.setTimeout(
     () => {
       navigate("/logout");
     },
     30 * 60 * 1000 // 30 minutes
   );
-}, []);
+}, [navigate]);
wavefront/client/src/components/ui/breadcrumb.tsx-80-80 (1)

80-80: Fix typo in displayName.

The displayName is misspelled as "BreadcrumbElipssis" (missing "i"). This will appear incorrectly in React DevTools.

Apply this diff:

-BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis';
+BreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis';
wavefront/client/src/components/ui/breadcrumb.tsx-48-59 (1)

48-59: Reconsider role="link" on BreadcrumbPage.

The BreadcrumbPage component uses role="link" on a span element representing the current page. According to ARIA practices, the current page in a breadcrumb should not be a link and typically doesn't need role="link". The combination of role="link" with aria-disabled="true" is non-standard.

Consider removing role="link" and relying solely on aria-current="page" to indicate the current location, which is the standard pattern for breadcrumbs.

Apply this diff:

   <span
     ref={ref}
-    role="link"
-    aria-disabled="true"
     aria-current="page"
     className={cn('text-foreground font-normal', className)}
     {...props}
   />
wavefront/client/src/components/InferencePopup.tsx-421-429 (1)

421-429: Add type="button" to document remove button.

Same issue as the image remove button - this could trigger form submission.

                     <button
+                      type="button"
                       onClick={() => handleRemoveDocument(index)}
                       className="rounded-full p-1 text-red-500 hover:bg-red-50"
                       title="Remove document"
                     >
wavefront/client/src/components/InferencePopup.tsx-346-354 (1)

346-354: Add type="button" to prevent accidental form submission.

The remove image button is inside the form but lacks type="button". In HTML, buttons default to type="submit", so clicking this could accidentally submit the form.

                 <button
+                  type="button"
                   onClick={handleRemoveImage}
                   className="rounded-full p-1 text-red-500 hover:bg-red-50"
                   title="Remove image"
                 >
wavefront/client/src/components/InferencePopup.tsx-498-505 (1)

498-505: Add type="button" to modal close button.

The close button in the modal wrapper should explicitly have type="button" to prevent form interaction issues.

           <button
+            type="button"
             onClick={() => onClose()}
             className="rounded-full p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
           >
wavefront/client/src/components/ChatBot.tsx-161-166 (1)

161-166: Alignment logic may not match role-based styling.

The alignment in lines 162-165 uses index % 2 === 0 to determine items-end vs items-start, but line 157-159 uses chat.role to determine justify-end vs justify-start. These could become inconsistent if messages don't strictly alternate between user and assistant.

Use role-based alignment consistently:

 <div
   className={clsx(
     "flex max-w-[70%] flex-col",
-    index % 2 === 0 ? "items-end" : "items-start"
+    chat.role === "user" ? "items-end" : "items-start"
   )}
 >
wavefront/client/src/hooks/data/query-functions.ts-51-73 (1)

51-73: Guard JSON.parse in getDatasourceQueryFn against malformed config payloads

getDatasourceQueryFn calls JSON.parse(responseData.config) on line 65 when config is a string. If the backend sends invalid JSON, this will throw and violate the function's return type contract (Datasource | null), causing the query to error instead of returning null.

Wrap the parse in a try/catch and fall back to an empty object:

let config: unknown = responseData.config ?? {};
if (typeof responseData.config === "string") {
  try {
    config = JSON.parse(responseData.config);
  } catch {
    config = {};
  }
}

Alternatively, if failing hard on malformed config is intentional, add a comment explaining why.

wavefront/client/src/hooks/data/fetch-hooks.ts-339-350 (1)

339-350: useGetWorkflowRuns: backend failures return empty result instead of error state

The hook correctly wires to getWorkflowRunsKey and getWorkflowRunsQueryFn. However, getWorkflowRunsQueryFn converts non-success responses into an empty page object, preventing the hook from exposing isError/error for backend failures. The consuming component in workflowPipelineId.tsx explicitly checks for runsError to display error feedback and a retry button, but this will never trigger since backend errors are swallowed. If the UI needs to distinguish "no runs" from "failed to fetch", change the query function to throw on error meta instead of returning empty data.

Comment on lines 12 to 26
useEffect(() => {
const token = localStorage.getItem(TOKEN_KEY);
const currentPath = localStorage.getItem(CURRENT_PATH_KEY);

if (!token) {
setAuthenticatedState(false);
navigate("/login");
} else {
setAuthenticatedState(true);
}

if (currentPath) {
navigate(currentPath);
}
}, []);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix authentication flow issues.

The current implementation has several problems:

  1. Missing dependencies: The useEffect has an empty dependency array but uses navigate and setAuthenticatedState. While these are typically stable, it's better to include them or explicitly acknowledge they're stable.

  2. Navigation logic issue: Lines 23-25 navigate to currentPath regardless of authentication status. If there's no token, the user is sent to /login (line 18), but then immediately redirected to currentPath (line 24), which could cause unexpected behavior.

  3. No cleanup of currentPath: After navigating to the stored path, it should be removed from localStorage to prevent repeated navigation on subsequent renders.

Apply this diff:

   useEffect(() => {
     const token = localStorage.getItem(TOKEN_KEY);
     const currentPath = localStorage.getItem(CURRENT_PATH_KEY);
 
     if (!token) {
       setAuthenticatedState(false);
       navigate("/login");
-    } else {
+      return;
+    }
+    
+    setAuthenticatedState(true);
+    
+    if (currentPath) {
+      localStorage.removeItem(CURRENT_PATH_KEY);
       navigate(currentPath);
     }
-
-    if (currentPath) {
-      navigate(currentPath);
-    }
-  }, []);
+  }, [navigate, setAuthenticatedState]);

Comment on lines +270 to +290
const getWorkflowRunsQueryFn = async (
workflowPipelineId: string,
offset: number = 0,
limit: number = 10
): Promise<WorkflowRunListData> => {
const response = await floConsoleService.workflowService.getWorkflowRuns(
workflowPipelineId,
offset,
limit
);
if (response.data?.meta?.status === "success" && response.data.data) {
return response.data.data;
}
return {
workflow_runs: [],
total_count: 0,
page_size: limit,
page_number: Math.floor(offset / limit),
total_pages: 0,
};
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "query-functions.ts" | head -20

Repository: rootflo/wavefront

Length of output: 113


🏁 Script executed:

# Read the specific file and location
cat -n wavefront/client/src/hooks/data/query-functions.ts | sed -n '260,300p'

Repository: rootflo/wavefront

Length of output: 1427


🏁 Script executed:

# Search for usages of getWorkflowRunsQueryFn
rg "getWorkflowRunsQueryFn" -A 3 -B 3

Repository: rootflo/wavefront

Length of output: 2163


🏁 Script executed:

# Look at similar functions in the file to understand the pattern
rg "Promise<.*ListData>" wavefront/client/src/hooks/data/query-functions.ts -B 5 -A 10

Repository: rootflo/wavefront

Length of output: 479


🏁 Script executed:

# Check the useQueryInit implementation and error handling
rg "useQueryInit" -A 10 wavefront/client/src/hooks/data/fetch-hooks.ts | head -40

Repository: rootflo/wavefront

Length of output: 1347


🏁 Script executed:

# Check if there's error handling or logging in the service layer
rg "workflowService" wavefront/client/src -l | head -5

Repository: rootflo/wavefront

Length of output: 409


🏁 Script executed:

# Look at how other similar query functions handle errors
rg "return \[\]" wavefront/client/src/hooks/data/query-functions.ts -B 5

Repository: rootflo/wavefront

Length of output: 3629


🏁 Script executed:

# Check how results are consumed in components
rg "useWorkflowRunsQuery" -A 5 -B 2 wavefront/client/src

Repository: rootflo/wavefront

Length of output: 43


🏁 Script executed:

# Search for workflow runs usage in components more broadly
rg "workflow.*run" -i wavefront/client/src/pages -A 2 -B 2 | head -60

Repository: rootflo/wavefront

Length of output: 6578


🏁 Script executed:

# Check if there's any global error handling or monitoring
rg "try.*catch" wavefront/client/src/hooks/data/query-functions.ts

Repository: rootflo/wavefront

Length of output: 43


🏁 Script executed:

# Look for useQueryInit definition to understand error handling
find . -type f -name "*.ts" -o -name "*.tsx" | xargs rg "export.*useQueryInit" | head -5

Repository: rootflo/wavefront

Length of output: 127


🏁 Script executed:

# Read the component file to see full error handling
cat -n wavefront/client/src/pages/apps/[appId]/workflows/pipelines/[workflowPipelineId].tsx | grep -A 30 "runsError" | head -40

Repository: rootflo/wavefront

Length of output: 1703


🏁 Script executed:

# Check the useQueryInit implementation
cat -n ./wavefront/client/src/lib/react-query.ts | head -100

Repository: rootflo/wavefront

Length of output: 731


getWorkflowRunsQueryFn silently converts backend failures into empty results, preventing error UI from surfacing

When meta.status !== "success" or response.data.data is missing, the function returns an empty WorkflowRunListData instead of throwing. This causes React Query to treat the response as successful (no error state), making the component's error handling at line 432–438 unreachable. Users see "no workflow runs" instead of the "Error loading workflow runs" message when the backend fails or returns unexpected responses.

To surface errors correctly, throw when meta.status !== "success" or the response structure is invalid:

if (response.data?.meta?.status !== "success" || !response.data.data) {
  throw new Error(`Failed to fetch workflow runs: ${response.data?.meta?.message || 'Unknown error'}`);
}
return response.data.data;

Note: This pattern affects multiple query functions in the file. Consider a consistent error-handling strategy across all query functions.

🤖 Prompt for AI Agents
In wavefront/client/src/hooks/data/query-functions.ts around lines 270 to 290,
the getWorkflowRunsQueryFn currently returns an empty WorkflowRunListData when
response.data?.meta?.status !== "success" or response.data.data is missing;
change it to throw an Error instead so React Query surfaces the failure: check
the response for meta.status === "success" and presence of data, and if not
throw a new Error that includes response.data?.meta?.message or a fallback
message like "Unknown error" (this will allow the consuming component to enter
its error state); apply the same standardized throw-on-invalid-response pattern
to the other query functions in this file for consistency.

Copy link

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

🧹 Nitpick comments (1)
wavefront/client/src/components/AppCard.tsx (1)

20-49: Consider minor refinements to event handling and button semantics.

Two optional improvements:

  1. Remove unnecessary preventDefault (line 24): Since the onClick is on a div element, not a form or link, preventDefault() has no effect and can be removed.

  2. Add explicit type="button" to buttons (lines 29, 39): While not critical, adding type="button" prevents these buttons from accidentally acting as submit buttons if the component is ever nested in a form.

Apply this diff to refine the implementation:

     <div
       className="group relative flex  w-full cursor-pointer flex-col gap-8 rounded-xl border border-[#FFF] bg-white/60 p-5"
       onClick={(e) => {
-        e.preventDefault();
         onClick(app);
       }}
     >
       <div className="absolute right-5 top-5 flex items-center gap-2">
         <button
+          type="button"
           onClick={(e) => {
             e.stopPropagation();
             handleEditApp(app);
           }}
           className="cursor-pointer rounded p-1 text-gray-600 opacity-0 transition-opacity hover:bg-gray-100 hover:text-gray-900 group-hover:opacity-100"
           title="Edit"
         >
           <Pencil className="h-4 w-4" />
         </button>
         <button
+          type="button"
           onClick={(e) => {
             e.stopPropagation();
             onDeleteClick(app);
           }}
           className="cursor-pointer rounded p-1 text-red-500 opacity-0 transition-opacity hover:bg-red-50 hover:text-red-700 group-hover:opacity-100"
           title="Delete"
         >
           <Trash2 className="h-4 w-4" />
         </button>
       </div>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6d626b and 1d6c03b.

📒 Files selected for processing (1)
  • wavefront/client/src/components/AppCard.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-push-artifact
🔇 Additional comments (3)
wavefront/client/src/components/AppCard.tsx (3)

7-11: LGTM!

The interface definition is clear, type-safe, and appropriately structured for the component's requirements.


13-18: LGTM!

The navigation setup is clean and follows a clear RESTful pattern for editing resources.


50-58: Implementation is correct.

The component properly uses the defined App type fields: app_name (line 51), public_url (line 53), and updated_at (line 57), all of which are correctly typed in the App interface.

@vishnurk6247 vishnurk6247 merged commit 7b3012c into develop Dec 12, 2025
6 of 7 checks passed
@vishnurk6247 vishnurk6247 deleted the wavefront branch December 12, 2025 07:35
Copy link

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

🧹 Nitpick comments (1)
wavefront/client/src/api/knowledge-base-service.ts (1)

206-214: Consider defining empty response types for delete operations.

While IApiResponse<any> is common for delete operations, consider defining an explicit empty response type or status response for better type clarity and consistency.

+export interface DeleteResponse {
+  success: boolean;
+  message?: string;
+}
+
-async deleteSystemPrompt(kbId: string, inferenceId: string): Promise<IApiResponse<any>> {
+async deleteSystemPrompt(kbId: string, inferenceId: string): Promise<IApiResponse<DeleteResponse>> {
-  const response: IApiResponse<any> = await this.http.delete(
+  const response: IApiResponse<DeleteResponse> = await this.http.delete(
     `/v1/:appId/floware/v1/knowledge-base/${kbId}/inference/${inferenceId}`
   );
   return response;
 }

Apply similar changes to deleteKnowledgeBase and deleteDocument methods.

Also applies to: 225-230, 232-240

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d6c03b and 7013ec5.

📒 Files selected for processing (2)
  • wavefront/client/src/api/knowledge-base-service.ts (1 hunks)
  • wavefront/client/src/components/ProtectedLayout.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • wavefront/client/src/components/ProtectedLayout.tsx
🔇 Additional comments (1)
wavefront/client/src/api/knowledge-base-service.ts (1)

96-96: The :appId placeholder is properly handled by the axios request interceptor.

The axios instance in wavefront/client/src/lib/axios.ts (lines 33–38) includes logic that replaces the :appId placeholder with the actual application ID extracted from the current page URL pathname before sending requests. No changes needed.

Comment on lines +20 to +27
export interface KnowledgeBaseData {
data: KbData;
}

export type KnowledgeBaseDetail = IApiResponse<KbData>;

// Interface for a single knowledge base response
export type KnowledgeBaseDetailResponse = IApiResponse<KnowledgeBaseData>;
Copy link

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:

find . -name "knowledge-base-service.ts" -type f | head -5

Repository: rootflo/wavefront

Length of output: 113


🏁 Script executed:

# View the type definitions section of the file (lines 1-40)
cat -n wavefront/client/src/api/knowledge-base-service.ts | head -40

Repository: rootflo/wavefront

Length of output: 1304


🏁 Script executed:

# Check the actual usage of both types in the service methods
echo "=== KnowledgeBaseDetail usage ==="
rg -nP --type=ts 'KnowledgeBaseDetail[^R]' wavefront/client/src/api/knowledge-base-service.ts -C 2

echo -e "\n=== KnowledgeBaseDetailResponse usage ==="
rg -nP --type=ts 'KnowledgeBaseDetailResponse' wavefront/client/src/api/knowledge-base-service.ts -C 2

Repository: rootflo/wavefront

Length of output: 936


🏁 Script executed:

# Check usage in the broader codebase
echo "=== KnowledgeBaseDetail usage in codebase ==="
rg -nP --type=ts 'KnowledgeBaseDetail[^R]' wavefront/client/src --include-dir=. | head -20

echo -e "\n=== KnowledgeBaseDetailResponse usage in codebase ==="
rg -nP --type=ts 'KnowledgeBaseDetailResponse' wavefront/client/src | head -20

Repository: rootflo/wavefront

Length of output: 977


🏁 Script executed:

# Check for any comments or documentation about why different types are used
echo "=== Checking for backend API references ==="
grep -r "knowledge-bases" wavefront/client/src --include="*.ts" -B 2 -A 2 | head -40

Repository: rootflo/wavefront

Length of output: 3247


🏁 Script executed:

# Find and view IApiResponse definition
rg -nP 'export.*IApiResponse' wavefront/client/src -A 3

Repository: rootflo/wavefront

Length of output: 11139


🏁 Script executed:

# View the complete knowledge-base-service.ts to understand method patterns better
wc -l wavefront/client/src/api/knowledge-base-service.ts

Repository: rootflo/wavefront

Length of output: 115


🏁 Script executed:

# Get all method signatures and their return types
sed -n '89,248p' wavefront/client/src/api/knowledge-base-service.ts | rg -nP 'async|Promise'

Repository: rootflo/wavefront

Length of output: 1030


Consolidate inconsistent response types for knowledge base operations.

KnowledgeBaseDetail (line 24) wraps KbData directly via IApiResponse<KbData>, while KnowledgeBaseDetailResponse (line 27) wraps KnowledgeBaseData, which itself contains data: KbData. This creates unnecessary double-wrapping and inconsistent shapes between getKnowledgeBase() (returns KnowledgeBaseDetail) and createKnowledgeBase() (returns KnowledgeBaseDetailResponse).

Verify that the backend API actually returns different response structures for GET vs. POST, or align these types to use a consistent structure.

🤖 Prompt for AI Agents
In wavefront/client/src/api/knowledge-base-service.ts around lines 20 to 27, the
response types are inconsistent: KnowledgeBaseDetail is IApiResponse<KbData>
while KnowledgeBaseDetailResponse is IApiResponse<KnowledgeBaseData> (which
wraps data: KbData), causing double-wrapping and mismatched shapes between GET
and POST; inspect the actual backend JSON for GET and POST and then choose a
single canonical shape (either IApiResponse<KbData> if the API returns the
object directly, or IApiResponse<KnowledgeBaseData> if it nests under data),
update both type aliases to the chosen shape, update any callers
(getKnowledgeBase/createKnowledgeBase) and tests to match the unified type, and
remove the unused or redundant type alias.

Comment on lines +54 to +56
export interface RagInferenceResultData {
response: string;
sources: any[]; // Assuming sources can be any array for now
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace any[] with a typed interface for sources.

The sources array is typed as any[], which eliminates type safety for this field. Define a proper interface that describes the source structure returned by RAG queries.

+export interface RagSource {
+  // Define the actual source structure based on your backend response
+  // Example fields:
+  document_id: string;
+  content: string;
+  score?: number;
+}
+
 export interface RagInferenceResultData {
   response: string;
-  sources: any[];
+  sources: RagSource[];
 }
📝 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 interface RagInferenceResultData {
response: string;
sources: any[]; // Assuming sources can be any array for now
export interface RagSource {
// Define the actual source structure based on your backend response
// Example fields:
document_id: string;
content: string;
score?: number;
}
export interface RagInferenceResultData {
response: string;
sources: RagSource[];
}
🤖 Prompt for AI Agents
In wavefront/client/src/api/knowledge-base-service.ts around lines 54 to 56,
replace the untyped sources: any[] with a proper exported interface describing
the RAG source structure. Add an exported RagSource (or similar) interface that
includes likely fields such as id (string), title? (string), url? (string),
excerpt? (string), score? (number) and a metadata?: Record<string, unknown> (or
specific typed fields if known), then change RagInferenceResultData.sources to
RagSource[] and update any usages/imports accordingly.

Comment on lines +72 to +82
export interface AllConfigsData {
id: string;
llm_model: string;
display_name: string;
type: string;
base_url: string;
parameters: any;
is_deleted: boolean;
created_at: string;
updated_at: string;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace any with a typed interface for parameters.

The parameters field is typed as any, reducing type safety. Define a proper interface or use a more specific type like Record<string, unknown>.

 export interface AllConfigsData {
   id: string;
   llm_model: string;
   display_name: string;
   type: string;
   base_url: string;
-  parameters: any;
+  parameters: Record<string, unknown>;
   is_deleted: boolean;
   created_at: string;
   updated_at: string;
 }
📝 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 interface AllConfigsData {
id: string;
llm_model: string;
display_name: string;
type: string;
base_url: string;
parameters: any;
is_deleted: boolean;
created_at: string;
updated_at: string;
}
export interface AllConfigsData {
id: string;
llm_model: string;
display_name: string;
type: string;
base_url: string;
parameters: Record<string, unknown>;
is_deleted: boolean;
created_at: string;
updated_at: string;
}
🤖 Prompt for AI Agents
In wavefront/client/src/api/knowledge-base-service.ts around lines 72 to 82, the
AllConfigsData.parameters field is typed as any which reduces type safety;
replace it with a concrete type (either define and export a Parameters interface
that models expected keys or use Record<string, unknown> if structure is
dynamic), update the AllConfigsData.parameters declaration to that type, update
any code that reads parameters to use the typed fields or narrow with type
guards/validation (or cast after validation), and add/adjust unit types or
parsing checks where configs are deserialized to ensure runtime shape matches
the new type.

Comment on lines +122 to +136
async uploadDocument(kbId: string, file: File): Promise<IApiResponse<any>> {
const formData = new FormData();
formData.append("file", file);

const response: IApiResponse<any> = await this.http.post(
`/v1/:appId/floware/v1/knowledge-bases/${kbId}/documents`,
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
return response;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Define a proper response type for document upload.

The uploadDocument method returns IApiResponse<any>, which provides no type safety for the upload response. Define an interface that describes the document metadata returned after upload.

+export interface DocumentUploadResponse {
+  id: string;
+  file_name: string;
+  file_type: string;
+  file_size: number;
+  created_at: string;
+}
+
-async uploadDocument(kbId: string, file: File): Promise<IApiResponse<any>> {
+async uploadDocument(kbId: string, file: File): Promise<IApiResponse<DocumentUploadResponse>> {
   const formData = new FormData();
   formData.append("file", file);

-  const response: IApiResponse<any> = await this.http.post(
+  const response: IApiResponse<DocumentUploadResponse> = await this.http.post(
     `/v1/:appId/floware/v1/knowledge-bases/${kbId}/documents`,
     formData,
     {
       headers: {
         "Content-Type": "multipart/form-data",
       },
     }
   );
   return response;
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In wavefront/client/src/api/knowledge-base-service.ts around lines 122 to 136,
the uploadDocument method currently returns IApiResponse<any); define a concrete
interface (e.g. IDocumentUploadResponse) that models the returned document
metadata (id, name, size, mimeType, uploadedAt, status, any urls or tags your
API returns) and replace the any with IApiResponse<IDocumentUploadResponse>; add
the interface to this file or a shared types/models file and update
imports/exports accordingly so the method signature enforces the correct shape
for callers.

Comment on lines +164 to +167
if (threshold) params.threshold = threshold;
if (topK) params.top_k = topK;
if (vectorWeight) params.vector_weight = vectorWeight;
if (keywordWeight) params.keyword_weight = keywordWeight;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix parameter validation to handle valid zero values.

The truthy checks (if (threshold), if (topK), etc.) will exclude valid zero values. Use explicit !== undefined checks instead to allow 0 as a valid parameter.

-  if (threshold) params.threshold = threshold;
-  if (topK) params.top_k = topK;
-  if (vectorWeight) params.vector_weight = vectorWeight;
-  if (keywordWeight) params.keyword_weight = keywordWeight;
+  if (threshold !== undefined) params.threshold = threshold;
+  if (topK !== undefined) params.top_k = topK;
+  if (vectorWeight !== undefined) params.vector_weight = vectorWeight;
+  if (keywordWeight !== undefined) params.keyword_weight = keywordWeight;
📝 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
if (threshold) params.threshold = threshold;
if (topK) params.top_k = topK;
if (vectorWeight) params.vector_weight = vectorWeight;
if (keywordWeight) params.keyword_weight = keywordWeight;
if (threshold !== undefined) params.threshold = threshold;
if (topK !== undefined) params.top_k = topK;
if (vectorWeight !== undefined) params.vector_weight = vectorWeight;
if (keywordWeight !== undefined) params.keyword_weight = keywordWeight;
🤖 Prompt for AI Agents
In wavefront/client/src/api/knowledge-base-service.ts around lines 164 to 167,
the current truthy checks (if (threshold), if (topK), if (vectorWeight), if
(keywordWeight)) incorrectly omit valid zero values; change each conditional to
an explicit undefined check (e.g., if (threshold !== undefined)) so 0 is
accepted, and assign to params as before; apply the same !== undefined pattern
to threshold, topK, vectorWeight, and keywordWeight.

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.

3 participants