Skip to content

feat: Add medical-assistant AgentKit#69

Open
SandipM03 wants to merge 7 commits intoLamatic:mainfrom
SandipM03:feat/medical-assistant
Open

feat: Add medical-assistant AgentKit#69
SandipM03 wants to merge 7 commits intoLamatic:mainfrom
SandipM03:feat/medical-assistant

Conversation

@SandipM03
Copy link
Copy Markdown

@SandipM03 SandipM03 commented Mar 1, 2026

What This Kit Does

The Medical Assistant AgentKit is an AI-powered chatbot that provides general medical information, symptom checks, and health guidance through a conversational interface built with Lamatic.ai. It solves the need for accessible, on-demand health information with proper safety guardrails:

  • Conversational Interface — Chat-style Q&A with message history and session management
  • Symptom Guidance — Describe symptoms to get relevant medical information
  • Suggested Prompts — Quick-start chips for common health questions
  • Markdown Rendering — Rich formatted responses with headers, lists, and emphasis
  • Medical Disclaimers — Persistent disclaimer banner + per-response reminders
  • Copy to Clipboard — Easy sharing of responses
  • Emergency Detection — Advises calling emergency services when appropriate

Providers & Prerequisites

  • Lamatic.ai: Core orchestration and workflow execution engine
  • Lamatic GraphQL Endpoint: Project-specific endpoint for flow execution
  • Project IDs & API Keys: Required for secure authentication

How to Run Locally

  1. Navigate to kits/assistant/medical-assistant
  2. Install with npm install
  3. Create a .env file using .env.example as a template
  4. Run development server: npm run dev
  5. Open http://localhost:3000

Issue

Issue: #25

Lamatic Flow

Flow configurations and schemas are maintained in the flows/medical-assistant-chat/ directory of the kit.

PR Checklist [Kit]

Kit runs locally with npm run dev
.env.example has no secrets, only placeholders
README.mddocuments setup, environment variables, and usageFolder structure: kits/assistant/medical-assistant/
config.json and orchestrate.js are present and valid
All flows exported in flows/ folder

Demo

Screen.Recording.2026-03-01.165915.mp4

Privacy & Data Handling

  • No user data is stored persistently — chat history exists only in the browser session
  • No personal health information (PHI) is collected or stored

Summary

New Features

  • Medical Assistant kit with chat UI for health queries and AI-generated, evidence-based responses
  • Session management with sidebar for multiple conversations
  • Medical disclaimer components (banner + per-response)
  • Suggested prompt chips for quick-start interactions

Configuration

  • Environment template, README, and project config added to simplify setup
  • Flow exported with config, inputs, meta, and README

Chores

  • .gitignore and build tooling configs included
  • Added kit: kits/assistant/medical-assistant/
    • README.md — kit overview, Lamatic setup steps, local run & deploy instructions, demo link, prominent medical disclaimer, feature list, required env vars.
    • .env.example — placeholders: MEDICAL_ASSISTANT_CHAT, LAMATIC_API_URL, LAMATIC_PROJECT_ID, LAMATIC_API_KEY.
    • .gitignore — ignores node_modules, Next.js build outputs, env files, Vercel, TS build info, logs.
    • package.json — Next.js/React project manifest and dependencies for the medical assistant app.
    • tsconfig.json — TypeScript config with path alias @/* → ./* and Next.js includes.
    • next.config.mjs — Next.js config (images.unoptimized: true).
    • postcss.config.cjs — PostCSS config enabling Tailwind plugin.
    • tailwind.config.ts — Tailwind content globs and export.
    • .stylelintrc.json — Stylelint allowing Tailwind at-rules.
    • biome.json — Biome config disabling a CSS linter rule.
    • globals.css — Tailwind imports, theme tokens, dark variant, chat UI styles, markdown (.prose) adjustments, scrollbar styling.
    • app/layout.tsx — RootLayout, site metadata, fonts, Analytics wrapper.
    • app/page.tsx — MedicalAssistantPage: client-side multi-session chat UI, session sidebar, message/session types, send flow, markdown rendering, copy-to-clipboard, loading/analysis states, auto-scroll, disclaimer UI, keyboard handling.
    • components.json — shadcn UI scaffold, aliases, icon library config.
    • components/disclaimer.tsx — Disclaimer and MiniDisclaimer React components (exports Disclaimer, MiniDisclaimer).
    • lib/lamatic-client.ts — lamaticClient export; verifies MEDICAL_ASSISTANT_CHAT env and config API credentials on module load.
    • lib/utils.ts — cn(...) helper (clsx + twMerge).
    • orchestrate.js — exported config object wiring a single medical flow (MEDICAL_ASSISTANT_CHAT) and API credentials (LAMATIC_* env vars).
    • actions/orchestrate.ts — exported async sendMedicalQuery(query): selects configured workflow, validates workflowId, maps inputs from flow.inputSchema, executes flow via lamaticClient, polls for async results, normalizes multiple response shapes to an answer string, and returns { success, data } or { success: false, error } with mapped network/auth messages.
    • flows/medical-assistant-chat/
      • config.json — flow definition:
        • Nodes:
          • APITrigger (id: APITrigger_1) — inputSchema { query: string } for receiving user queries via API trigger.
          • LLMNode (id: LLMNode_1) — "Medical Assistant LLM" with:
            • systemPrompt enforcing: identify as AI (not a doctor), do not diagnose, recommend professional consultation, provide evidence-based info when possible, detect potential emergencies and advise calling emergency services, be empathetic, structure responses with headers/bullets, include general tips.
            • userPrompt bound to {{query}}
            • outputSchema { answer: string }
        • Edges: APITrigger_1 → LLMNode_1
      • meta.json — flow metadata, tags, and testInput { "query": "What are the common symptoms of the flu?" }.
      • inputs.json — LLM node input config (generativeModelName) describing selectable generator/chat model (required, private, loadOptionsMethod: listModels).
      • README.md — flow overview, node responsibilities, input/output schemas, test input, and the informational disclaimer.
    • Additional tooling/config files: next, PostCSS, Tailwind, Stylelint, Biome, and TypeScript configs to support building/linting the kit.

Flow high-level behavior

  • An external API trigger supplies a "query" (user medical question/symptom).
  • The flow routes the query to a single LLM node configured with a strict medical-aware system prompt that: provides general, evidence-informed information; forbids diagnosis; prompts escalation to healthcare providers; detects emergencies and instructs calling emergency services; and structures replies for readability.
  • Expected output from the flow is a single string field "answer".
  • Orchestration layers (orchestrate.js + lib/lamatic-client.ts + actions/orchestrate.ts) map env-provided workflow IDs and API credentials, execute the flow (sync or async with polling), normalize varied response shapes into an answer string, and return structured success/error responses to the frontend.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 1, 2026

Walkthrough

Adds a new Medical Assistant kit: a Next.js + Tailwind frontend chat UI, Lamatic flow definitions and orchestration, Lamatic client and server action to execute queries (with polling/error handling), configuration and tooling files, UI components (disclaimer), and documentation/metadata.

Changes

Cohort / File(s) Summary
Env & Git
kits/assistant/medical-assistant/.env.example, kits/assistant/medical-assistant/.gitignore
Adds .env example with MEDICAL_ASSISTANT_CHAT and Lamatic API placeholders; new .gitignore for Node/Next/Tailwind artifacts and env files.
Kit Metadata & Docs
kits/assistant/medical-assistant/config.json, kits/assistant/medical-assistant/components.json, kits/assistant/medical-assistant/README.md
Adds kit manifest, shadcn components config, and README with setup, required env vars, disclaimer, and usage/deploy instructions.
Flow Definitions
kits/assistant/medical-assistant/flows/medical-assistant-chat/...
Adds flow folder: flow config, inputs, meta, and README describing API trigger → LLM node, system prompt constraints, IO schemas, and test input.
Orchestration & Runtime
kits/assistant/medical-assistant/orchestrate.js, kits/assistant/medical-assistant/actions/orchestrate.ts
Adds orchestrator config (env-sourced workflow and Lamatic API settings) and server action sendMedicalQuery to execute flows, handle async polling, normalize responses, and map common errors.
Lamatic Client
kits/assistant/medical-assistant/lib/lamatic-client.ts
Exports lamaticClient initialized from config and validates presence of MEDICAL_ASSISTANT_CHAT and API config on module load.
Frontend App & Pages
kits/assistant/medical-assistant/app/layout.tsx, kits/assistant/medical-assistant/app/page.tsx
Adds RootLayout with metadata/fonts and a client-side multi-session chat page implementing sessions, message handling, markdown rendering, copy-to-clipboard, loading states, and disclaimer UI.
Styling & Tooling
kits/assistant/medical-assistant/app/globals.css, kits/assistant/medical-assistant/tailwind.config.ts, kits/assistant/medical-assistant/postcss.config.cjs, kits/assistant/medical-assistant/.stylelintrc.json, kits/assistant/medical-assistant/biome.json
Adds global CSS with theme tokens, dark mode, chat animation, prose rules; Tailwind/PostCSS and linter configs.
Utilities & Components
kits/assistant/medical-assistant/lib/utils.ts, kits/assistant/medical-assistant/components/disclaimer.tsx
Adds cn className util and Disclaimer / MiniDisclaimer React components.
Build & Types
kits/assistant/medical-assistant/package.json, kits/assistant/medical-assistant/tsconfig.json, kits/assistant/medical-assistant/next.config.mjs
New package.json with dependencies/scripts, TypeScript config, and Next.js config (images.unoptimized).

Suggested reviewers

  • amanintech
  • d-pamneja
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat: Add medical-assistant AgentKit' clearly and concisely summarizes the main change: adding a new Medical Assistant AgentKit to the repository.
Description check ✅ Passed The PR description is comprehensive and covers all required sections including what the kit does, prerequisites, local setup instructions, privacy handling, and a completed kit checklist with feature summaries.

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

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

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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (5)
kits/assistant/medical-assistant/package.json (1)

16-16: Consider moving autoprefixer to devDependencies.

autoprefixer is a build-time tool for PostCSS and doesn't need to be in production dependencies. Moving it to devDependencies reduces the production bundle footprint.

♻️ Proposed fix
   "dependencies": {
     "@radix-ui/react-scroll-area": "^1.2.3",
     "@radix-ui/react-slot": "^1.1.1",
     "@tailwindcss/typography": "^0.5.19",
     "@vercel/analytics": "^1.5.0",
-    "autoprefixer": "^10.4.27",
     "class-variance-authority": "^0.7.1",
   "devDependencies": {
     "@tailwindcss/postcss": "^4.0.6",
     "@types/node": "^20",
     "@types/react": "^19",
     "@types/react-dom": "^19",
+    "autoprefixer": "^10.4.27",
     "postcss": "^8.5.6",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/package.json` at line 16, The package.json
currently lists "autoprefixer" in dependencies; move it to devDependencies by
removing the "autoprefixer" entry from the top-level "dependencies" object and
adding the same version string under "devDependencies" so it is installed only
in development/build environments; update any package-lock or yarn.lock by
reinstalling deps if needed to reflect the change.
kits/assistant/medical-assistant/.env.example (1)

1-4: Remove spaces around equal signs in .env.example.

Some .env parsers don't handle spaces around the = sign correctly, which could lead to configuration issues. The standard convention is KEY=value without spaces.

♻️ Proposed fix
-MEDICAL_ASSISTANT_CHAT = "MEDICAL_ASSISTANT_CHAT Flow ID"
-LAMATIC_API_URL = "LAMATIC_API_URL"
-LAMATIC_PROJECT_ID = "LAMATIC_PROJECT_ID"
-LAMATIC_API_KEY = "LAMATIC_API_KEY"
+MEDICAL_ASSISTANT_CHAT="your_flow_id_here"
+LAMATIC_API_URL="https://api.lamatic.ai"
+LAMATIC_PROJECT_ID="your_project_id_here"
+LAMATIC_API_KEY="your_api_key_here"

Note: The proposed fix also aligns placeholder values with the README documentation format for consistency.

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

In `@kits/assistant/medical-assistant/.env.example` around lines 1 - 4, Remove the
spaces around the equals signs in the environment variable declarations for
MEDICAL_ASSISTANT_CHAT, LAMATIC_API_URL, LAMATIC_PROJECT_ID, and LAMATIC_API_KEY
so each line follows KEY=value format (no surrounding spaces) and update the
placeholder values to match the README's placeholder style for consistency.
kits/assistant/medical-assistant/tsconfig.json (1)

11-13: Consider enabling full strict mode for better type safety.

The current configuration sets strict: false while manually enabling strictNullChecks and noImplicitAny. This is an unusual pattern. Using strict: true would enable all strict options (including strictBindCallApply, strictFunctionTypes, strictPropertyInitialization, etc.) for more comprehensive type checking.

♻️ Proposed change
-    "strict": false,
-    "strictNullChecks": true,
-    "noImplicitAny": true,
+    "strict": true,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/tsconfig.json` around lines 11 - 13, The
tsconfig currently has "strict": false while individually enabling
"strictNullChecks" and "noImplicitAny"; change to enable full strict mode by
setting "strict": true and remove or keep the individual flags for clarity (they
become redundant) so that all strict checks (e.g., strictBindCallApply,
strictFunctionTypes, strictPropertyInitialization) are enforced; update the JSON
entry for the "strict" compiler option and ensure the "strictNullChecks" and
"noImplicitAny" lines are consistent with that change.
kits/assistant/medical-assistant/actions/orchestrate.ts (1)

6-14: Add server-side query guardrails (empty/oversized).

Relying only on client checks is fragile. A lightweight server boundary check will reduce avoidable provider calls and failure noise.

✅ Suggested guardrails
 export async function sendMedicalQuery(
   query: string,
 ): Promise<{
@@
 }> {
   try {
+    const trimmedQuery = query?.trim()
+    if (!trimmedQuery) {
+      return { success: false, error: "Query cannot be empty." }
+    }
+    if (trimmedQuery.length > 2000) {
+      return { success: false, error: "Query is too long. Please shorten and try again." }
+    }
-    console.log("[medical-assistant] Processing query, length:", query.length)
+    console.log("[medical-assistant] Processing query, length:", trimmedQuery.length)
@@
-      query,
+      query: trimmedQuery,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/actions/orchestrate.ts` around lines 6 - 14,
In sendMedicalQuery add server-side guardrails: trim the incoming query and if
it's empty return { success: false, error: "empty query" } without calling
downstream providers; if query.length exceeds a defined MAX_QUERY_LENGTH
constant (e.g., MAX_QUERY_LENGTH = 2000) log the event and return { success:
false, error: "query too long" }; use the existing console/logging pattern
(console.log or processLogger) to record rejected queries and ensure all early
returns match the function's Promise<{success:boolean, data?:any,
error?:string}> shape so no provider/client calls happen for invalid input.
kits/assistant/medical-assistant/app/page.tsx (1)

416-420: Copy action should be keyboard-visible, not hover-only.

The button is visually hidden unless hovered; add focus-visible styles so keyboard users can discover it.

⌨️ Accessibility tweak
-                                                            className="absolute top-2 opacity-0 group-hover:opacity-100 transition-all duration-200 p-1.5 rounded-lg"
+                                                            className="absolute top-2 opacity-0 group-hover:opacity-100 focus-visible:opacity-100 focus-visible:outline focus-visible:outline-2 transition-all duration-200 p-1.5 rounded-lg"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/app/page.tsx` around lines 416 - 420, The
copy control is hidden via opacity unless hovered; make it discoverable to
keyboard users by adding focus/focus-visible styles and ensuring it's focusable:
update the element using className (the element that currently has "absolute
top-2 opacity-0 group-hover:opacity-100 ...") to include
"focus-visible:opacity-100" (and/or "focus:opacity-100") and a visible focus
outline class (e.g., "focus-visible:outline" or similar), and if the element is
not already a native button ensure it has tabIndex={0} and keyboard handlers;
keep the existing aria-label logic (aria-label={copiedId === msg.id ? "Copied" :
"Copy response"}) and reference copiedId and msg.id as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@kits/assistant/medical-assistant/actions/orchestrate.ts`:
- Around line 56-60: Replace raw payload logging in orchestrate.ts by removing
verbose prints of asyncResult and error; instead log only non-sensitive metadata
(e.g., requestId, status code, duration, and a redacted/summary message).
Specifically update the console.log calls around lamaticClient.checkStatus
(where requestId and asyncResult are logged) and the catch/log that prints error
to redact or stringify only safe fields (avoid user medical content or provider
internals) and add a correlation id if available; keep the detailed payloads
available only for secure debug endpoints or structured logs behind a privacy
guard.
- Around line 8-11: The returned payload currently types data as any and can
propagate non-string values; change the return type to data?: string and ensure
every assignment to data (in the orchestrate function and the parsing/return
branches around the 75-91 range) converts values to a string using a small
helper like ensureString(value) that returns '' for null/undefined, returns the
value if typeof value === 'string', otherwise returns JSON.stringify(value);
update the Promise signature from data?: any to data?: string and replace direct
data assignments with ensureString(...) to guarantee downstream UI always
receives text.

In `@kits/assistant/medical-assistant/app/globals.css`:
- Around line 3-5: Linting fails because Tailwind v4 at-rules like `@plugin` and
`@custom-variant` (and others: `@theme`, `@apply`, `@layer`, `@import`, `@tailwind`) are not
allowed by current CSS linters; update .stylelintrc.json to add these directives
to the "ignoreAtRules" list for the "at-rule-no-unknown" rule, and update
biome.json to enable Tailwind CSS parsing or disable conflicting CSS rules so
Biome's CSS linter accepts Tailwind directives; also rename the animation
identifier `@keyframes` chatMessageEnter to kebab-case `@keyframes`
chat-message-enter (and update any references to that animation) to satisfy
naming conventions.

In `@kits/assistant/medical-assistant/app/page.tsx`:
- Around line 169-247: The sidebar remains mounted and keyboard-focusable when
collapsed; change the rendering so the <aside> is only mounted when sidebarOpen
is true (e.g., wrap the aside JSX with a conditional check on the sidebarOpen
state) to remove hidden focus targets, and ensure any handlers that reference
sessions, createNewSession, setActiveSessionId, or activeSessionId still work
when the sidebar mounts/unmounts.

In `@kits/assistant/medical-assistant/flows/medical-assistant-chat/README.md`:
- Around line 23-28: The Output Schema table is malformed: the row with `query`
has four cells while the header defines three and it incorrectly documents the
input instead of the LLM response; update the table so header and all rows have
the same three columns (Field, Type, Description) and replace the `query` row
with the actual output field name from the Lamatic flow (e.g., `response` or
whatever the flow uses), its type (e.g., `string`), and a concise description of
the model's reply; verify the exact output field name in the
medical-assistant-chat flow configuration and use that identifier in the `Field`
column.

In `@kits/assistant/medical-assistant/lib/lamatic-client.ts`:
- Around line 10-19: The validation currently requires config.api.endpoint,
config.api.projectId and config.api.apiKey but lamaticClient instantiation uses
a nullable fallback for projectId; pick one behavior and make them consistent:
if projectId is required, remove the "?? null" fallback in Lamatic construction
and pass config.api.projectId (non-null) directly to new Lamatic, ensuring types
match; alternatively, if projectId should be optional, remove projectId from the
initial throw check and document/handle its absence before creating
lamaticClient (adjust the validation block and the instantiation of
lamaticClient accordingly). Reference: the validation block checking
config.api?.endpoint/config.api?.projectId/config.api?.apiKey and the exported
lamaticClient = new Lamatic({...}) lines.

In `@kits/assistant/medical-assistant/package.json`:
- Line 19: The package.json currently lists an unavailable dependency version
"lamatic": "^0.3.2"; update the dependency entry for "lamatic" to a published
version such as "lamatic": "^0.3.1" (or "0.3.1") so the dependency resolves
correctly when installing.

---

Nitpick comments:
In `@kits/assistant/medical-assistant/.env.example`:
- Around line 1-4: Remove the spaces around the equals signs in the environment
variable declarations for MEDICAL_ASSISTANT_CHAT, LAMATIC_API_URL,
LAMATIC_PROJECT_ID, and LAMATIC_API_KEY so each line follows KEY=value format
(no surrounding spaces) and update the placeholder values to match the README's
placeholder style for consistency.

In `@kits/assistant/medical-assistant/actions/orchestrate.ts`:
- Around line 6-14: In sendMedicalQuery add server-side guardrails: trim the
incoming query and if it's empty return { success: false, error: "empty query" }
without calling downstream providers; if query.length exceeds a defined
MAX_QUERY_LENGTH constant (e.g., MAX_QUERY_LENGTH = 2000) log the event and
return { success: false, error: "query too long" }; use the existing
console/logging pattern (console.log or processLogger) to record rejected
queries and ensure all early returns match the function's
Promise<{success:boolean, data?:any, error?:string}> shape so no provider/client
calls happen for invalid input.

In `@kits/assistant/medical-assistant/app/page.tsx`:
- Around line 416-420: The copy control is hidden via opacity unless hovered;
make it discoverable to keyboard users by adding focus/focus-visible styles and
ensuring it's focusable: update the element using className (the element that
currently has "absolute top-2 opacity-0 group-hover:opacity-100 ...") to include
"focus-visible:opacity-100" (and/or "focus:opacity-100") and a visible focus
outline class (e.g., "focus-visible:outline" or similar), and if the element is
not already a native button ensure it has tabIndex={0} and keyboard handlers;
keep the existing aria-label logic (aria-label={copiedId === msg.id ? "Copied" :
"Copy response"}) and reference copiedId and msg.id as-is.

In `@kits/assistant/medical-assistant/package.json`:
- Line 16: The package.json currently lists "autoprefixer" in dependencies; move
it to devDependencies by removing the "autoprefixer" entry from the top-level
"dependencies" object and adding the same version string under "devDependencies"
so it is installed only in development/build environments; update any
package-lock or yarn.lock by reinstalling deps if needed to reflect the change.

In `@kits/assistant/medical-assistant/tsconfig.json`:
- Around line 11-13: The tsconfig currently has "strict": false while
individually enabling "strictNullChecks" and "noImplicitAny"; change to enable
full strict mode by setting "strict": true and remove or keep the individual
flags for clarity (they become redundant) so that all strict checks (e.g.,
strictBindCallApply, strictFunctionTypes, strictPropertyInitialization) are
enforced; update the JSON entry for the "strict" compiler option and ensure the
"strictNullChecks" and "noImplicitAny" lines are consistent with that change.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 994954e and c3e4f3a.

⛔ Files ignored due to path filters (1)
  • kits/assistant/medical-assistant/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (22)
  • kits/assistant/medical-assistant/.env.example
  • kits/assistant/medical-assistant/.gitignore
  • kits/assistant/medical-assistant/README.md
  • kits/assistant/medical-assistant/actions/orchestrate.ts
  • kits/assistant/medical-assistant/app/globals.css
  • kits/assistant/medical-assistant/app/layout.tsx
  • kits/assistant/medical-assistant/app/page.tsx
  • kits/assistant/medical-assistant/components.json
  • kits/assistant/medical-assistant/components/disclaimer.tsx
  • kits/assistant/medical-assistant/config.json
  • kits/assistant/medical-assistant/flows/medical-assistant-chat/README.md
  • kits/assistant/medical-assistant/flows/medical-assistant-chat/config.json
  • kits/assistant/medical-assistant/flows/medical-assistant-chat/inputs.json
  • kits/assistant/medical-assistant/flows/medical-assistant-chat/meta.json
  • kits/assistant/medical-assistant/lib/lamatic-client.ts
  • kits/assistant/medical-assistant/lib/utils.ts
  • kits/assistant/medical-assistant/next.config.mjs
  • kits/assistant/medical-assistant/orchestrate.js
  • kits/assistant/medical-assistant/package.json
  • kits/assistant/medical-assistant/postcss.config.cjs
  • kits/assistant/medical-assistant/tailwind.config.ts
  • kits/assistant/medical-assistant/tsconfig.json

Comment on lines +56 to +60
console.log("[medical-assistant] Async response, polling with requestId:", requestId)

const asyncResult = await lamaticClient.checkStatus(requestId, 2, 60)
console.log("[medical-assistant] Async poll result:", asyncResult)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid logging raw workflow payloads/errors in a medical context.

Line [59] logs full asyncResult and Line [93] logs raw error. These can include user medical content or provider internals and should be sanitized.

🔒 Suggested logging hardening
-      console.log("[medical-assistant] Async poll result:", asyncResult)
+      console.log("[medical-assistant] Async poll status:", asyncResult?.status)

@@
-    console.error("[medical-assistant] Query error:", error)
+    const safeError =
+      error instanceof Error ? { name: error.name, message: error.message } : { message: "Unknown error" }
+    console.error("[medical-assistant] Query error:", safeError)

Also applies to: 93-93

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

In `@kits/assistant/medical-assistant/actions/orchestrate.ts` around lines 56 -
60, Replace raw payload logging in orchestrate.ts by removing verbose prints of
asyncResult and error; instead log only non-sensitive metadata (e.g., requestId,
status code, duration, and a redacted/summary message). Specifically update the
console.log calls around lamaticClient.checkStatus (where requestId and
asyncResult are logged) and the catch/log that prints error to redact or
stringify only safe fields (avoid user medical content or provider internals)
and add a correlation id if available; keep the detailed payloads available only
for secure debug endpoints or structured logs behind a privacy guard.

Comment on lines +3 to +5
@plugin "@tailwindcss/typography";

@custom-variant dark (&:is(.dark *));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Tailwind directives used in globals.css"
rg -n '@plugin|@custom-variant|@theme|@apply' kits/assistant/medical-assistant/app/globals.css

echo
echo "2) Lint config files"
fd -HI '(^|/)(\.stylelintrc(\..+)?|stylelint\.config\.(js|cjs|mjs|json|yaml|yml)|biome\.jsonc?|biome\.json)$' .

CONFIGS="$(fd -HI '(^|/)(\.stylelintrc(\..+)?|stylelint\.config\.(js|cjs|mjs|json|yaml|yml)|biome\.jsonc?|biome\.json)$' .)"
if [ -n "$CONFIGS" ]; then
  echo
  echo "3) Relevant parser/rule entries"
  rg -n 'at-rule-no-unknown|ignoreAtRules|keyframes-name-pattern|tailwind|css' $CONFIGS
fi

Repository: Lamatic/AgentKit

Length of output: 567


🏁 Script executed:

# Also check the full globals.css file to see the extent of the issues
wc -l kits/assistant/medical-assistant/app/globals.css

Repository: Lamatic/AgentKit

Length of output: 112


🏁 Script executed:

# Read the globals.css file to understand the full context
cat -n kits/assistant/medical-assistant/app/globals.css

Repository: Lamatic/AgentKit

Length of output: 6935


🏁 Script executed:

# Check the actual stylelint and biome configuration content
cat -n .stylelintrc.json

Repository: Lamatic/AgentKit

Length of output: 1276


🏁 Script executed:

cat -n biome.json

Repository: Lamatic/AgentKit

Length of output: 2345


Configure linting tools to support Tailwind v4 syntax.

Stylelint and Biome are configured but neither supports Tailwind v4 at-rules (@plugin, @custom-variant, @theme, @apply). This will cause CI failures.

Update .stylelintrc.json to allow these directives:

{
  "extends": ["stylelint-config-standard-scss"],
  "rules": {
    "at-rule-no-unknown": [
      true,
      {
        "ignoreAtRules": [
          "plugin",
          "custom-variant",
          "theme",
          "layer",
          "apply",
          "import",
          "tailwind"
        ]
      }
    ]
    // ... existing rules
  }
}

Configure Biome's CSS linter for Tailwind in biome.json (lines 60-67) by adding Tailwind parser support or disabling conflicting CSS rules.

Also, rename @keyframes chatMessageEnter (line 129) to @keyframes chat-message-enter to follow kebab-case convention.

🧰 Tools
🪛 Biome (2.4.4)

[error] 3-3: Tailwind-specific syntax is disabled.

(parse)


[error] 5-5: Tailwind-specific syntax is disabled.

(parse)

🪛 Stylelint (17.3.0)

[error] 3-3: Unexpected unknown at-rule "@plugin" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)


[error] 5-5: Unexpected unknown at-rule "@custom-variant" (scss/at-rule-no-unknown)

(scss/at-rule-no-unknown)

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

In `@kits/assistant/medical-assistant/app/globals.css` around lines 3 - 5, Linting
fails because Tailwind v4 at-rules like `@plugin` and `@custom-variant` (and others:
`@theme`, `@apply`, `@layer`, `@import`, `@tailwind`) are not allowed by current CSS
linters; update .stylelintrc.json to add these directives to the "ignoreAtRules"
list for the "at-rule-no-unknown" rule, and update biome.json to enable Tailwind
CSS parsing or disable conflicting CSS rules so Biome's CSS linter accepts
Tailwind directives; also rename the animation identifier `@keyframes`
chatMessageEnter to kebab-case `@keyframes` chat-message-enter (and update any
references to that animation) to satisfy naming conventions.

Comment on lines +169 to +247
<aside
className={`${sidebarOpen ? "w-72" : "w-0"
} transition-all duration-300 flex flex-col overflow-hidden flex-shrink-0`}
style={{ background: '#fff', borderRight: sidebarOpen ? '1px solid #e2e8f0' : 'none' }}
>
{/* Brand */}
<div className="h-14 flex items-center gap-2 px-5 flex-shrink-0" style={{ borderBottom: '1px solid #f1f5f9' }}>
<Stethoscope className="w-5 h-5" style={{ color: '#f43f5e' }} />
<span className="text-lg font-bold tracking-tight whitespace-nowrap">
<span style={{ color: '#0f172a' }}>Medical</span>{" "}
<span style={{ color: '#f43f5e' }}>Assistant</span>
</span>
</div>

{/* New Session */}
<div className="p-3 flex-shrink-0">
<button
onClick={createNewSession}
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium transition-colors shadow-sm"
style={{ background: '#f43f5e', color: '#fff' }}
onMouseEnter={(e) => (e.currentTarget.style.background = '#e11d48')}
onMouseLeave={(e) => (e.currentTarget.style.background = '#f43f5e')}
>
<Plus className="w-4 h-4" />
New Session
</button>
</div>

{/* Session List */}
<div className="flex-1 overflow-y-auto px-3 pb-3">
<div className="flex flex-col gap-1">
{sessions.length === 0 ? (
<p className="text-center py-8 text-sm" style={{ color: '#94a3b8' }}>No sessions yet</p>
) : (
sessions.map((session) => (
<button
key={session.id}
onClick={() => setActiveSessionId(session.id)}
className="w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2.5"
style={{
background: session.id === activeSessionId ? '#f1f5f9' : 'transparent',
color: session.id === activeSessionId ? '#0f172a' : '#475569',
fontWeight: session.id === activeSessionId ? 500 : 400,
}}
>
<MessageSquare className="w-4 h-4 flex-shrink-0" />
<span className="truncate">{session.title}</span>
</button>
))
)}
</div>
</div>

{/* Sidebar Footer Links */}
<div className="p-3 flex-shrink-0" style={{ borderTop: '1px solid #f1f5f9' }}>
<div className="flex flex-col gap-1">
<Link
href="https://lamatic.ai/docs"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors"
style={{ color: '#475569' }}
>
<FileText className="w-4 h-4" style={{ color: '#94a3b8' }} />
Documentation
</Link>
<Link
href="https://github.com/Lamatic/AgentKit"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors"
style={{ color: '#475569' }}
>
<Github className="w-4 h-4" style={{ color: '#94a3b8' }} />
GitHub
</Link>
</div>
</div>
</aside>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Collapsed sidebar stays in tab order while visually hidden.

When sidebarOpen is false, the sidebar content is still mounted and can remain keyboard-focusable, creating hidden focus targets.

♿ Suggested fix (render sidebar only when open)
-            <aside
-                className={`${sidebarOpen ? "w-72" : "w-0"
-                    } transition-all duration-300 flex flex-col overflow-hidden flex-shrink-0`}
-                style={{ background: '#fff', borderRight: sidebarOpen ? '1px solid `#e2e8f0`' : 'none' }}
-            >
+            {sidebarOpen && (
+            <aside
+                className="w-72 transition-all duration-300 flex flex-col overflow-hidden flex-shrink-0"
+                style={{ background: '#fff', borderRight: '1px solid `#e2e8f0`' }}
+            >
@@
-            </aside>
+            </aside>
+            )}
📝 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
<aside
className={`${sidebarOpen ? "w-72" : "w-0"
} transition-all duration-300 flex flex-col overflow-hidden flex-shrink-0`}
style={{ background: '#fff', borderRight: sidebarOpen ? '1px solid #e2e8f0' : 'none' }}
>
{/* Brand */}
<div className="h-14 flex items-center gap-2 px-5 flex-shrink-0" style={{ borderBottom: '1px solid #f1f5f9' }}>
<Stethoscope className="w-5 h-5" style={{ color: '#f43f5e' }} />
<span className="text-lg font-bold tracking-tight whitespace-nowrap">
<span style={{ color: '#0f172a' }}>Medical</span>{" "}
<span style={{ color: '#f43f5e' }}>Assistant</span>
</span>
</div>
{/* New Session */}
<div className="p-3 flex-shrink-0">
<button
onClick={createNewSession}
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium transition-colors shadow-sm"
style={{ background: '#f43f5e', color: '#fff' }}
onMouseEnter={(e) => (e.currentTarget.style.background = '#e11d48')}
onMouseLeave={(e) => (e.currentTarget.style.background = '#f43f5e')}
>
<Plus className="w-4 h-4" />
New Session
</button>
</div>
{/* Session List */}
<div className="flex-1 overflow-y-auto px-3 pb-3">
<div className="flex flex-col gap-1">
{sessions.length === 0 ? (
<p className="text-center py-8 text-sm" style={{ color: '#94a3b8' }}>No sessions yet</p>
) : (
sessions.map((session) => (
<button
key={session.id}
onClick={() => setActiveSessionId(session.id)}
className="w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2.5"
style={{
background: session.id === activeSessionId ? '#f1f5f9' : 'transparent',
color: session.id === activeSessionId ? '#0f172a' : '#475569',
fontWeight: session.id === activeSessionId ? 500 : 400,
}}
>
<MessageSquare className="w-4 h-4 flex-shrink-0" />
<span className="truncate">{session.title}</span>
</button>
))
)}
</div>
</div>
{/* Sidebar Footer Links */}
<div className="p-3 flex-shrink-0" style={{ borderTop: '1px solid #f1f5f9' }}>
<div className="flex flex-col gap-1">
<Link
href="https://lamatic.ai/docs"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors"
style={{ color: '#475569' }}
>
<FileText className="w-4 h-4" style={{ color: '#94a3b8' }} />
Documentation
</Link>
<Link
href="https://github.com/Lamatic/AgentKit"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors"
style={{ color: '#475569' }}
>
<Github className="w-4 h-4" style={{ color: '#94a3b8' }} />
GitHub
</Link>
</div>
</div>
</aside>
{sidebarOpen && (
<aside
className="w-72 transition-all duration-300 flex flex-col overflow-hidden flex-shrink-0"
style={{ background: '#fff', borderRight: '1px solid `#e2e8f0`' }}
>
{/* Brand */}
<div className="h-14 flex items-center gap-2 px-5 flex-shrink-0" style={{ borderBottom: '1px solid `#f1f5f9`' }}>
<Stethoscope className="w-5 h-5" style={{ color: '#f43f5e' }} />
<span className="text-lg font-bold tracking-tight whitespace-nowrap">
<span style={{ color: '#0f172a' }}>Medical</span>{" "}
<span style={{ color: '#f43f5e' }}>Assistant</span>
</span>
</div>
{/* New Session */}
<div className="p-3 flex-shrink-0">
<button
onClick={createNewSession}
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl text-sm font-medium transition-colors shadow-sm"
style={{ background: '#f43f5e', color: '#fff' }}
onMouseEnter={(e) => (e.currentTarget.style.background = '#e11d48')}
onMouseLeave={(e) => (e.currentTarget.style.background = '#f43f5e')}
>
<Plus className="w-4 h-4" />
New Session
</button>
</div>
{/* Session List */}
<div className="flex-1 overflow-y-auto px-3 pb-3">
<div className="flex flex-col gap-1">
{sessions.length === 0 ? (
<p className="text-center py-8 text-sm" style={{ color: '#94a3b8' }}>No sessions yet</p>
) : (
sessions.map((session) => (
<button
key={session.id}
onClick={() => setActiveSessionId(session.id)}
className="w-full text-left px-3 py-2.5 rounded-lg text-sm transition-colors flex items-center gap-2.5"
style={{
background: session.id === activeSessionId ? '#f1f5f9' : 'transparent',
color: session.id === activeSessionId ? '#0f172a' : '#475569',
fontWeight: session.id === activeSessionId ? 500 : 400,
}}
>
<MessageSquare className="w-4 h-4 flex-shrink-0" />
<span className="truncate">{session.title}</span>
</button>
))
)}
</div>
</div>
{/* Sidebar Footer Links */}
<div className="p-3 flex-shrink-0" style={{ borderTop: '1px solid `#f1f5f9`' }}>
<div className="flex flex-col gap-1">
<Link
href="https://lamatic.ai/docs"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors"
style={{ color: '#475569' }}
>
<FileText className="w-4 h-4" style={{ color: '#94a3b8' }} />
Documentation
</Link>
<Link
href="https://github.com/Lamatic/AgentKit"
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-2 px-3 py-2 rounded-lg text-sm transition-colors"
style={{ color: '#475569' }}
>
<Github className="w-4 h-4" style={{ color: '#94a3b8' }} />
GitHub
</Link>
</div>
</div>
</aside>
)}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/app/page.tsx` around lines 169 - 247, The
sidebar remains mounted and keyboard-focusable when collapsed; change the
rendering so the <aside> is only mounted when sidebarOpen is true (e.g., wrap
the aside JSX with a conditional check on the sidebarOpen state) to remove
hidden focus targets, and ensure any handlers that reference sessions,
createNewSession, setActiveSessionId, or activeSessionId still work when the
sidebar mounts/unmounts.

Comment on lines +23 to +28
## Output Schema

| Field | Type | Description |
| -------- | -------- | ----------------------------------------------------- |
| `query` | `string` | Max 1000 chars, sanitized for safety | The user's medical question or symptom description |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix malformed table in Output Schema section.

Line 27 has 4 cells but the table header defines only 3 columns, causing rendering issues. Additionally, the output schema appears to duplicate the input field (query) rather than documenting the actual LLM response output.

📝 Proposed fix
 ## Output Schema

 | Field    | Type     | Description                                           |
 | -------- | -------- | ----------------------------------------------------- |
-| `query` | `string` | Max 1000 chars, sanitized for safety | The user's medical question or symptom description |
+| `response` | `string` | The LLM-generated medical information response |

Please verify the actual output field name from your Lamatic flow configuration.

📝 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
## Output Schema
| Field | Type | Description |
| -------- | -------- | ----------------------------------------------------- |
| `query` | `string` | Max 1000 chars, sanitized for safety | The user's medical question or symptom description |
## Output Schema
| Field | Type | Description |
| -------- | -------- | ----------------------------------------------------- |
| `response` | `string` | The LLM-generated medical information response |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/flows/medical-assistant-chat/README.md`
around lines 23 - 28, The Output Schema table is malformed: the row with `query`
has four cells while the header defines three and it incorrectly documents the
input instead of the LLM response; update the table so header and all rows have
the same three columns (Field, Type, Description) and replace the `query` row
with the actual output field name from the Lamatic flow (e.g., `response` or
whatever the flow uses), its type (e.g., `string`), and a concise description of
the model's reply; verify the exact output field name in the
medical-assistant-chat flow configuration and use that identifier in the `Field`
column.

@github-actions
Copy link
Copy Markdown

Hi @SandipM03! 👋

CodeRabbit has posted actionable review comments on this PR. Please review and address them before requesting a maintainer review.

Once you've addressed the CodeRabbit feedback, please push your changes and we'll take another look. Thank you! 🙏

Copy link
Copy Markdown
Contributor

@d-pamneja d-pamneja Mar 30, 2026

Choose a reason for hiding this comment

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

Could you add a live demo link to this file? would allow us to view the functionality better, and allow users to see the kit before forking it. otherwise, LGTM. Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also, if you could add the entry in the README.md of the main readme as well?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Hi, I’ve added the live demo link to the main README as well. Please let me know if anything else is needed.

@coderabbitai coderabbitai bot requested a review from amanintech March 31, 2026 13:36
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (3)
kits/assistant/medical-assistant/README.md (1)

4-6: ⚠️ Potential issue | 🟡 Minor

Mission note: the Live Demo badge still dead-ends.

href="#" leaves users with a dead preview entry point. Replace it with the real demo URL or remove the badge until one exists.

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

In `@kits/assistant/medical-assistant/README.md` around lines 4 - 6, The Live Demo
badge anchor uses href="#" which creates a dead link; update the anchor in
README.md by replacing href="#" with the actual demo URL (the working public
demo endpoint) or remove the entire <a> anchor element (or the badge image)
until a demo exists, ensuring the badge no longer dead-ends and the alt/title
reflect the correct destination.
kits/assistant/medical-assistant/.stylelintrc.json (1)

2-17: ⚠️ Potential issue | 🟠 Major

Mission-critical: CI is still tripping over @plugin.

Static analysis still reports @plugin as an unknown at-rule in kits/assistant/medical-assistant/app/globals.css Line 3, so this override is not reaching the rule Stylelint is actually enforcing. Please verify whether the active config comes from a root file or from scss/at-rule-no-unknown, and mirror the Tailwind ignore list there.

#!/bin/bash
set -euo pipefail

echo "Stylelint configs discovered in the repo:"
fd -HI '(^|/)(\.stylelintrc(\..+)?|stylelint\.config\.(js|cjs|mjs|json|yaml|yml))$' .

echo
echo "Rules that can still reject Tailwind v4 at-rules:"
rg -n --hidden --glob '!**/node_modules/**' '(scss/at-rule-no-unknown|at-rule-no-unknown|ignoreAtRules)' .

echo
echo "Medical assistant local override:"
cat kits/assistant/medical-assistant/.stylelintrc.json

Expected result: the active rule set for this path should ignore plugin, custom-variant, theme, layer, apply, import, and tailwind.

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

In `@kits/assistant/medical-assistant/.stylelintrc.json` around lines 2 - 17, The
CI is still flagging `@plugin` because the active Stylelint rule is coming from
the scss plugin or a root config that doesn't include Tailwind at-rules; update
the active rule (either the "scss/at-rule-no-unknown" entry or the root
"at-rule-no-unknown" in the active config) to include ignoreAtRules with
["apply","custom-variant","import","layer","plugin","tailwind","theme"], or make
the medical-assistant .stylelintrc.json extend/override the same rule so the
ignore list is mirrored; specifically target the rule name
"scss/at-rule-no-unknown" (and/or "at-rule-no-unknown") in your configs and
ensure the ignoreAtRules list contains the eight Tailwind entries so `@plugin` is
no longer treated as unknown.
kits/assistant/medical-assistant/actions/orchestrate.ts (1)

21-24: ⚠️ Potential issue | 🟠 Major

Mission-critical: close the any escape hatch at the server boundary.

data?: any plus the object branch at Lines 99-100 can still return non-string payloads. The UI consumes this as chat text, so the server action should normalize to string before it crosses the boundary.

🎯 One safe way to normalize the payload
 ): Promise<{
   success: boolean
-  data?: any
+  data?: string
   error?: string
 }> {
+  const ensureString = (value: unknown): string => {
+    if (value == null) return ""
+    return typeof value === "string" ? value : JSON.stringify(value)
+  }
@@
-    if (typeof rawAnswer === "object" && rawAnswer !== null) {
-      answer = rawAnswer.generatedResponse || rawAnswer.text || rawAnswer.content || JSON.stringify(rawAnswer)
+    if (typeof rawAnswer === "object" && rawAnswer !== null) {
+      const candidate =
+        (rawAnswer as any).generatedResponse ??
+        (rawAnswer as any).text ??
+        (rawAnswer as any).content ??
+        rawAnswer
+      answer = ensureString(candidate)
     } else if (typeof rawAnswer === "string" && rawAnswer.length > 0) {
       answer = rawAnswer
     }

Also applies to: 97-103

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

In `@kits/assistant/medical-assistant/actions/orchestrate.ts` around lines 21 -
24, The server return type currently exposes data?: any; change the Promise
generic to use data?: string and ensure every place that sets the data field
(notably the object branch around the current lines ~97-103 in orchestrate.ts)
normalizes the payload to a string before returning; implement normalization
like: if typeof payload === 'string' return it as-is, otherwise return
JSON.stringify(payload) (handle null/undefined explicitly as 'null' or empty
string per app convention) so the UI always receives a string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@kits/assistant/medical-assistant/app/page.tsx`:
- Around line 303-317: The textarea composer lacks an accessible name and the
icon-only send button and sticky composer are unlabeled for screen readers; add
an id to the textarea (used by inputRef/handleKeyDown) and connect the visible
label via htmlFor or change the label to a <label> that wraps the textarea so it
is programmatically bound, add an aria-label or aria-labelledby to the sticky
composer container, and give the icon-only send button a clear accessible name
(aria-label or include visually-hidden text) so screen-reader users can identify
and operate the main composer and send action.

In `@kits/assistant/medical-assistant/lib/lamatic-client.ts`:
- Around line 4-8: Remove the MEDICAL_ASSISTANT_CHAT presence check from
lib/lamatic-client.ts so the SDK client initialization is only scoped to SDK
credentials (LAMATIC_API_URL, LAMATIC_PROJECT_ID, LAMATIC_API_KEY); ensure the
module only constructs/exports the Lamatic client (e.g., exported lamaticClient
or createLamaticClient) and does not throw for flow selection, and instead move
or add the MEDICAL_ASSISTANT_CHAT validation into the orchestrator action
(actions/orchestrate.ts) where flows are invoked.

In `@kits/assistant/medical-assistant/README.md`:
- Around line 77-96: Update the unlabeled fenced block that shows the repo tree
in the README.md to use a text language label (i.e., change the opening
backticks to ```text) so markdownlint no longer flags it; locate the repo tree
fenced block (the block starting with "/actions" and listing /app, /components,
/lib, /flows) and add the text label to the fence.

---

Duplicate comments:
In `@kits/assistant/medical-assistant/.stylelintrc.json`:
- Around line 2-17: The CI is still flagging `@plugin` because the active
Stylelint rule is coming from the scss plugin or a root config that doesn't
include Tailwind at-rules; update the active rule (either the
"scss/at-rule-no-unknown" entry or the root "at-rule-no-unknown" in the active
config) to include ignoreAtRules with
["apply","custom-variant","import","layer","plugin","tailwind","theme"], or make
the medical-assistant .stylelintrc.json extend/override the same rule so the
ignore list is mirrored; specifically target the rule name
"scss/at-rule-no-unknown" (and/or "at-rule-no-unknown") in your configs and
ensure the ignoreAtRules list contains the eight Tailwind entries so `@plugin` is
no longer treated as unknown.

In `@kits/assistant/medical-assistant/actions/orchestrate.ts`:
- Around line 21-24: The server return type currently exposes data?: any; change
the Promise generic to use data?: string and ensure every place that sets the
data field (notably the object branch around the current lines ~97-103 in
orchestrate.ts) normalizes the payload to a string before returning; implement
normalization like: if typeof payload === 'string' return it as-is, otherwise
return JSON.stringify(payload) (handle null/undefined explicitly as 'null' or
empty string per app convention) so the UI always receives a string.

In `@kits/assistant/medical-assistant/README.md`:
- Around line 4-6: The Live Demo badge anchor uses href="#" which creates a dead
link; update the anchor in README.md by replacing href="#" with the actual demo
URL (the working public demo endpoint) or remove the entire <a> anchor element
(or the badge image) until a demo exists, ensuring the badge no longer dead-ends
and the alt/title reflect the correct destination.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9236b580-cb70-45f5-bd2a-3ffacc4b8d5a

📥 Commits

Reviewing files that changed from the base of the PR and between c3e4f3a and e4fe5e8.

📒 Files selected for processing (8)
  • kits/assistant/medical-assistant/.stylelintrc.json
  • kits/assistant/medical-assistant/README.md
  • kits/assistant/medical-assistant/actions/orchestrate.ts
  • kits/assistant/medical-assistant/app/globals.css
  • kits/assistant/medical-assistant/app/page.tsx
  • kits/assistant/medical-assistant/biome.json
  • kits/assistant/medical-assistant/flows/medical-assistant-chat/README.md
  • kits/assistant/medical-assistant/lib/lamatic-client.ts

Comment on lines +303 to +317
<label className="flex items-center gap-2 text-[13px] font-semibold mb-2.5" style={{ color: '#334155' }}>
<Stethoscope className="w-4 h-4" style={{ color: '#f43f5e' }} />
Medical Query or Symptom
</label>
<textarea
ref={inputRef}
placeholder="e.g. What are the common symptoms of the flu?"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={handleKeyDown}
disabled={isLoading}
rows={3}
className="w-full resize-none rounded-xl px-4 py-3 text-sm focus:outline-none transition-colors"
style={{ border: '2px solid #e2e8f0', color: '#1e293b', background: '#fff' }}
/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Mission-critical: the main composer is missing accessible names.

The welcome label is not bound to its <textarea>, the sticky composer has no programmatic label, and the icon-only send button has no accessible name. That blocks the primary chat flow for screen-reader users.

🛰️ Minimal fix
-<label className="flex items-center gap-2 text-[13px] font-semibold mb-2.5" style={{ color: '#334155' }}>
+<label
+  htmlFor="medical-query"
+  className="flex items-center gap-2 text-[13px] font-semibold mb-2.5"
+  style={{ color: '#334155' }}
+>
@@
 <textarea
+  id="medical-query"
   ref={inputRef}
@@
 <textarea
+  aria-label="Describe your symptoms or ask a medical question"
   ref={inputRef}
@@
 <button
+  aria-label={isLoading ? "Sending medical query" : "Send medical query"}
   onClick={handleSend}

Also applies to: 478-505

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

In `@kits/assistant/medical-assistant/app/page.tsx` around lines 303 - 317, The
textarea composer lacks an accessible name and the icon-only send button and
sticky composer are unlabeled for screen readers; add an id to the textarea
(used by inputRef/handleKeyDown) and connect the visible label via htmlFor or
change the label to a <label> that wraps the textarea so it is programmatically
bound, add an aria-label or aria-labelledby to the sticky composer container,
and give the icon-only send button a clear accessible name (aria-label or
include visually-hidden text) so screen-reader users can identify and operate
the main composer and send action.

Comment on lines +4 to +8
if (!process.env.MEDICAL_ASSISTANT_CHAT) {
throw new Error(
"MEDICAL_ASSISTANT_CHAT environment variable is not set. Please add it to your .env.local file."
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Keep the SDK client scoped to SDK credentials.

MEDICAL_ASSISTANT_CHAT is a flow selection concern, not client initialization. Failing on it here couples every lamaticClient import to one specific workflow instead of leaving flow-env validation in actions/orchestrate.ts.

As per coding guidelines, "Use the lib/lamatic-client.ts pattern to initialize the Lamatic SDK with LAMATIC_API_URL, LAMATIC_PROJECT_ID, and LAMATIC_API_KEY" and "Kit server action files (e.g., actions/orchestrate.ts) must call Lamatic flows via the SDK and read flow IDs from environment variables".

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

In `@kits/assistant/medical-assistant/lib/lamatic-client.ts` around lines 4 - 8,
Remove the MEDICAL_ASSISTANT_CHAT presence check from lib/lamatic-client.ts so
the SDK client initialization is only scoped to SDK credentials
(LAMATIC_API_URL, LAMATIC_PROJECT_ID, LAMATIC_API_KEY); ensure the module only
constructs/exports the Lamatic client (e.g., exported lamaticClient or
createLamaticClient) and does not throw for flow selection, and instead move or
add the MEDICAL_ASSISTANT_CHAT validation into the orchestrator action
(actions/orchestrate.ts) where flows are invoked.

Comment on lines +77 to +96
```
/actions
└── orchestrate.ts # Lamatic workflow orchestration for medical queries
/app
├── globals.css # Teal-themed design system
├── layout.tsx # Root layout with SEO metadata
└── page.tsx # Chat-style medical assistant UI
/components
├── header.tsx # Header with medical branding
└── disclaimer.tsx # Medical disclaimer components
/lib
├── lamatic-client.ts # Lamatic SDK client
└── utils.ts # Tailwind class merge utility
/flows
└── medical-assistant-chat/
├── config.json # Flow configuration
├── inputs.json # Input schema
├── meta.json # Flow metadata
└── README.md # Flow documentation
```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Mark the repo tree fence as text.

Line 77 starts an unlabeled fenced block, which is already flagged by markdownlint. text is enough here.

🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 77-77: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

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

In `@kits/assistant/medical-assistant/README.md` around lines 77 - 96, Update the
unlabeled fenced block that shows the repo tree in the README.md to use a text
language label (i.e., change the opening backticks to ```text) so markdownlint
no longer flags it; locate the repo tree fenced block (the block starting with
"/actions" and listing /app, /components, /lib, /flows) and add the text label
to the fence.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
kits/assistant/medical-assistant/README.md (1)

77-96: ⚠️ Potential issue | 🟡 Minor

Mission update: label the repo-structure code fence to clear markdownlint.

Line 77 uses an unlabeled fenced block; change it to ```text to resolve MD040.

🎯 Proposed patch
-```
+```text
 /actions
  └── orchestrate.ts        # Lamatic workflow orchestration for medical queries
 /app
 ...
-```
+```
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kits/assistant/medical-assistant/README.md` around lines 77 - 96, The
markdown README.md has an unlabeled fenced code block showing the repo tree
(around the block starting with "/actions ... /flows"); change the opening fence
from ``` to ```text so the block is labeled and satisfies MD040; update the
block surrounding the tree in README.md (the repo-structure code fence) to use
```text as the opening fence and keep the closing ``` unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@kits/assistant/medical-assistant/README.md`:
- Around line 77-96: The markdown README.md has an unlabeled fenced code block
showing the repo tree (around the block starting with "/actions ... /flows");
change the opening fence from ``` to ```text so the block is labeled and
satisfies MD040; update the block surrounding the tree in README.md (the
repo-structure code fence) to use ```text as the opening fence and keep the
closing ``` unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: c537fa64-84e8-41df-8b48-743b9b187ad4

📥 Commits

Reviewing files that changed from the base of the PR and between e4fe5e8 and a478edb.

📒 Files selected for processing (1)
  • kits/assistant/medical-assistant/README.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants