Conversation
📝 WalkthroughWalkthroughThis PR introduces a complete medical assistant kit featuring a Next.js frontend application with multi-session chat UI, Lamatic workflow integration for LLM-powered medical queries, comprehensive configuration files, styling system, and backend orchestration logic. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant Browser as Browser/Client
participant NextApp as Next.js App
participant LamaticAPI as Lamatic API
participant LLM as LLM (Medical AI)
User->>Browser: Enters medical query
Browser->>NextApp: sendMedicalQuery(query)
activate NextApp
NextApp->>LamaticAPI: executeFlow(workflowId, inputs)
activate LamaticAPI
LamaticAPI->>LLM: Process with medical system prompt
activate LLM
LLM-->>LamaticAPI: Generated medical response
deactivate LLM
LamaticAPI-->>NextApp: Execute result (immediate or requestId)
deactivate LamaticAPI
alt Async Response
NextApp->>LamaticAPI: checkStatus(requestId)
LamaticAPI-->>NextApp: Status & answer
end
NextApp->>NextApp: Parse answer from response
deactivate NextApp
NextApp-->>Browser: { success: true, data: answer }
Browser->>Browser: Update session, render markdown
Browser-->>User: Display medical response with disclaimer
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (5)
kits/assistant/medical-assistant/package.json (1)
16-16: Consider movingautoprefixertodevDependencies.
autoprefixeris a build-time tool for PostCSS and doesn't need to be in production dependencies. Moving it todevDependenciesreduces 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
.envparsers don't handle spaces around the=sign correctly, which could lead to configuration issues. The standard convention isKEY=valuewithout 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: falsewhile manually enablingstrictNullChecksandnoImplicitAny. This is an unusual pattern. Usingstrict: truewould enable all strict options (includingstrictBindCallApply,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.
⛔ Files ignored due to path filters (1)
kits/assistant/medical-assistant/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (22)
kits/assistant/medical-assistant/.env.examplekits/assistant/medical-assistant/.gitignorekits/assistant/medical-assistant/README.mdkits/assistant/medical-assistant/actions/orchestrate.tskits/assistant/medical-assistant/app/globals.csskits/assistant/medical-assistant/app/layout.tsxkits/assistant/medical-assistant/app/page.tsxkits/assistant/medical-assistant/components.jsonkits/assistant/medical-assistant/components/disclaimer.tsxkits/assistant/medical-assistant/config.jsonkits/assistant/medical-assistant/flows/medical-assistant-chat/README.mdkits/assistant/medical-assistant/flows/medical-assistant-chat/config.jsonkits/assistant/medical-assistant/flows/medical-assistant-chat/inputs.jsonkits/assistant/medical-assistant/flows/medical-assistant-chat/meta.jsonkits/assistant/medical-assistant/lib/lamatic-client.tskits/assistant/medical-assistant/lib/utils.tskits/assistant/medical-assistant/next.config.mjskits/assistant/medical-assistant/orchestrate.jskits/assistant/medical-assistant/package.jsonkits/assistant/medical-assistant/postcss.config.cjskits/assistant/medical-assistant/tailwind.config.tskits/assistant/medical-assistant/tsconfig.json
| 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) | ||
|
|
There was a problem hiding this comment.
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.
| @plugin "@tailwindcss/typography"; | ||
|
|
||
| @custom-variant dark (&:is(.dark *)); |
There was a problem hiding this comment.
🧩 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
fiRepository: 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.cssRepository: 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.cssRepository: Lamatic/AgentKit
Length of output: 6935
🏁 Script executed:
# Check the actual stylelint and biome configuration content
cat -n .stylelintrc.jsonRepository: Lamatic/AgentKit
Length of output: 1276
🏁 Script executed:
cat -n biome.jsonRepository: 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.
| <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> |
There was a problem hiding this comment.
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.
| <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.
| ## Output Schema | ||
|
|
||
| | Field | Type | Description | | ||
| | -------- | -------- | ----------------------------------------------------- | | ||
| | `query` | `string` | Max 1000 chars, sanitized for safety | The user's medical question or symptom description | | ||
|
|
There was a problem hiding this comment.
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.
| ## 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.
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:
Providers & Prerequisites
How to Run Locally
kits/assistant/medical-assistantnpm install.envfile using.env.exampleas a templatenpm run devIssue
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.examplehas no secrets, only placeholdersREADME.md
documents setup, environment variables, and usageFolder structure:kits/assistant/medical-assistant/config.jsonandorchestrate.jsare present and validAll flows exported in
flows/folderDemo
Screen.Recording.2026-03-01.165915.mp4
Privacy & Data Handling
Summary
New Features
Configuration
Chores
.gitignoreand build tooling configs includedSummary by CodeRabbit
Release Notes
New Features
Documentation