Skip to content

Conversation

Huijiro
Copy link
Member

@Huijiro Huijiro commented Aug 25, 2025

Summary by CodeRabbit

  • New Features

    • Copy menu refactored: adds “Open in ChatGPT/Claude” and more robust copy/view Markdown actions.
    • TypingAnimation gains configurable props and optional start-on-viewport behavior.
    • Improved AI assistant behavior via updated prompts (rephrase, classification, and RAG) with clearer fallback guidance.
  • Bug Fixes

    • Minor reliability improvements in redirect/error handling and API result validation.
  • Style

    • Widespread formatting: consistent single quotes, whitespace normalization, CSS hex normalization.
  • Chores

    • Adopt Biome for formatting/linting; new npm scripts and tool updates.

Copy link
Contributor

coderabbitai bot commented Aug 25, 2025

Walkthrough

Standardizes formatting/quoting and migrates lint/format tooling to Biome across the repo; introduces several type-only imports and prompt expansions. Functional edits include a CopyPageDropdown refactor, TypingAnimation start-on-view behavior, source transformer change, and expanded doc‑QA prompts/fallbacks.

Changes

Cohort / File(s) Summary of edits
Tooling & workspace
package.json, biome.json, .eslintrc.json, tsconfig.json, postcss.config.mjs, next.config.mjs, open-next.config.ts
Add Biome config and scripts, remove ESLint deps, normalize quoting/indentation; no runtime logic changes.
Agent-docs tooling
agent-docs/package.json, agent-docs/biome.json, agent-docs/tsconfig.json
Biome bump and minimal Biome config; tsconfig formatting only.
Doc-processing (format & types)
agent-docs/src/agents/doc-processing/* (e.g., chunk-mdx.ts, docs-orchestrator.ts, docs-processor.ts, index.ts, types.ts, test/chunk-mdx.test.ts)
Quote/style updates, convert some imports to type-only, reflow signatures; mostly formatting-only.
Doc-processing — embed validation
agent-docs/src/agents/doc-processing/embed-chunks.ts
Removed explicit type annotation on param, added early validation of response.embeddings length; returns same shape.
Doc-processing — keyword prompt
agent-docs/src/agents/doc-processing/keyword-extraction.ts
Prompt now requests JSON with a keywords array; parsing/dedup logic unchanged.
Doc‑QA prompts & flow
agent-docs/src/agents/doc-qa/prompt.ts, agent-docs/src/agents/doc-qa/rag.ts
Expanded/systematized system prompts and output schema; reflowed signatures; richer fallback MDX message content.
Doc‑QA ancillary (formatting)
agent-docs/src/agents/doc-qa/* (retriever.ts, index.ts, types.ts)
Formatting-only, trailing commas, type-only imports; no logic changes.
Source transformers
source.config.ts
Replace previous transformer spread with transformerTwoslash({ throws: false }).
Copy & UI components
components/CopyPageDropdown.tsx
Major refactor: typed actionConfigs, initialization gate (persisted preferred action), consolidated handlers (copy/view/open), added ChatGPT/Claude flows, improved fallbacks.
TypingAnimation behavior
components/TypingAnimation.tsx
Add props (className,duration,delay,as,startOnView); can start typing on viewport entry via IntersectionObserver.
CustomSearchDialog subtree
components/CustomSearchDialog/* (index.tsx, MessageList.tsx, SearchInput.tsx, hooks/useMessages.tsx, types.ts, CustomSearchDialog.tsx)
Switch to type-only imports, add button type="button", lint comments, refine focus/resize effects; API unchanged.
AISearchToggle minor
components/AISearchToggle.tsx
Add type="button" to toggle; formatting adjustments.
Mermaid & other components (formatting)
components/* (e.g., Mermaid.tsx, NavButton.tsx, CodeExample.tsx, CLICommand.tsx, Community.tsx, ThemeImage.tsx, XButton.tsx, icons/*)
Quote/indent normalization, minor signature reflow; mostly cosmetic.
App pages, layout & styles
app/(docs)/*, app/layout.tsx, app/layout.config.tsx, app/global.css
Quote/format normalization; CSS hex-case normalization; no behavior changes.
API routes & middleware
app/api/*, app/llms*.txt/route.ts, middleware.ts, app/api/rag-search/route.ts
Convert NextRequest imports to type-only, minor param defaults/formatting; middleware regex/string quoting tweaks; logic preserved.
Content/meta & scripts
content/*/meta.json, scripts/generate-docs-json.js
Formatting/quote normalization; no logic changes.
Lib/env & source usage
lib/env.ts, lib/source.ts
Formatting, type refinements, and quote normalization; no behavior changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as CopyPageDropdown
  participant Store as localStorage
  participant API as /api/page-content
  participant Clipboard as navigator.clipboard
  Note over UI: Initialization reads preferred action
  User->>UI: Click primary action
  UI->>Store: Read preferredAction
  alt View Markdown
    UI->>API: fetchPageContent(path)
    API-->>UI: {content,...}
    alt open new tab OK
      UI->>User: opens blob URL
    else blocked
      UI->>User: triggers download fallback
    end
  else Copy Markdown
    UI->>API: fetchPageContent(path)
    API-->>UI: {content,...}
    UI->>Clipboard: writeText(markdown)
  end
  UI->>Store: Save preferredAction (if changed)
Loading
sequenceDiagram
  autonumber
  actor User
  participant UI as Search UI
  participant API as /api/rag-search
  participant Agent as doc‑qa service
  participant VS as Vector Store
  participant LLM as Model (gpt-4o-mini)
  User->>UI: Enter query
  UI->>API: GET ?q=...
  API->>Agent: answerQuestion(prompt)
  Agent->>Agent: rephraseVaguePrompt(prompt)
  Agent->>VS: vector search
  VS-->>Agent: relevant chunks
  Agent->>LLM: generateObject(systemPrompt + <DOCS>...)
  LLM-->>Agent: answer + docs
  Agent-->>API: {aiAnswer, documents}
  API-->>UI: results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • jhaynie
  • rblalock
  • mcongrove

Poem

A rabbit taps the keys—tik tik!—so spry,
Quotes made single, tidy lines fly by.
Dropdown learns its favorite hop and stay,
Typing waits until you come in play.
Docs hum clearer now — thump-thump, ship away! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch grodrigues/agent-547-docs

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

cloudflare-workers-and-pages bot commented Aug 25, 2025

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
docs a71da1a Commit Preview URL

Branch Preview URL
Aug 25 2025, 08:32 PM

Copy link
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: 16

Caution

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

⚠️ Outside diff range comments (4)
components/NavButton.tsx (1)

21-24: Security: default rel for target="_blank"

Opening in a new tab without rel="noopener noreferrer" can expose window.opener and enable reverse tabnabbing. Provide a safe default when target is _blank.

 export function NavButton({
   href,
   children,
   className,
   noBorder = false,
   target,
   rel,
 }: NavButtonProps) {
   return (
     <a
       href={href}
-      target={target}
-      rel={rel}
+      target={target}
+      rel={target === '_blank' ? (rel ?? 'noopener noreferrer') : rel}
       className={cn(
components/XButton.tsx (1)

14-23: Ensure accessible names and proper prop forwarding in NavButton

The X button link currently:

  • Renders an <svg> with both aria-hidden="true" and aria-label="X". When hidden, its label is ignored—so remove the aria-label (and <title>) from the SVG to keep it purely decorative.
  • When follow is false, there’s no visible text in the link, so screen readers won’t announce its purpose.

Since NavButton already accepts and forwards target and rel to the underlying <a> (as seen in components/NavButton.tsx, lines 5–13), but does not accept arbitrary aria-* props, we should:

  • Add an ariaLabel?: string (or 'aria-label'?: string) prop to NavButtonProps and forward it to the <a> element.
  • Use that prop in XButton to give the link an explicit accessible name.
  • Add target="_blank" and rel="noopener noreferrer" for safety when linking externally.

Example changes:

--- a/components/NavButton.tsx
+++ b/components/NavButton.tsx
@@ export interface NavButtonProps {
     rel?: string;
+    'aria-label'?: string;
 }
 export function NavButton({
     href,
     children,
     className,
     noBorder = false,
     target,
     rel,
+    'aria-label': ariaLabel,
 }: NavButtonProps) {
     return (
         <a
             href={href}
             target={target}
             rel={rel}
+            aria-label={ariaLabel}
             className={cn(
                 'inline-flex flex-row items-center gap-2 w-auto no-underline',
                 noBorder
                     ? 'border-none'
                     : 'hover:border-cyan-700 hover:dark:border-cyan-900 border rounded-full border-gray-200 dark:border-gray-800 px-2.5 h-9',
                 className
             )}
         >
             {children}
         </a>
     );
 }
--- a/components/XButton.tsx
+++ b/components/XButton.tsx
@@
     <NavButton
         href="https://x.com/agentuity"
         noBorder={noBorder}
-        className={cn('align-bottom', className)}
+        className={cn('align-bottom', className)}
+        aria-label={follow ? 'Follow us on X' : 'Agentuity on X'}
+        target="_blank"
+        rel="noopener noreferrer"
     >
-        {follow && <span>Follow us on</span>}
-        <svg
-            aria-hidden="true"
-            aria-label="X"
+        {follow && <span>Follow us on</span>}
+        <svg
+            aria-hidden="true"
             width="16"
             height="16"
             viewBox="0 0 24 24"
             fill="currentColor"
             className="underline"
         >
-            <title>X</title>
+            {/* decorative icon */}
             <path d="M 18.242188 2.25 L 21.554688 2.25 L 14.324219 10.507812 ... Z" />
         </svg>
     </NavButton>

Also apply the same aria-label, target, rel, and SVG cleanup at lines 29–31.

components/TypingAnimation.tsx (1)

41-51: Prevent setState on unmounted component: clear the timeout created inside IntersectionObserver

When startOnView is true, the setTimeout created in the observer callback isn’t cleared on unmount. If the component unmounts before the timeout fires, React may warn about state updates on an unmounted component. Capture and clear the timeout in the effect cleanup.

 useEffect(() => {
   if (!startOnView) {
     const startTimeout = setTimeout(() => {
       setStarted(true);
     }, delay);
     return () => clearTimeout(startTimeout);
   }

-  const observer = new IntersectionObserver(
+  let viewStartTimeout: ReturnType<typeof setTimeout> | null = null;
+  const observer = new IntersectionObserver(
     ([entry]) => {
       if (entry.isIntersecting) {
-        setTimeout(() => {
-          setStarted(true);
-        }, delay);
+        viewStartTimeout = setTimeout(() => {
+          setStarted(true);
+        }, delay);
         observer.disconnect();
       }
     },
     { threshold: 0.1 }
   );
@@
-  return () => observer.disconnect();
+  return () => {
+    if (viewStartTimeout) clearTimeout(viewStartTimeout);
+    observer.disconnect();
+  };
 }, [delay, startOnView]);

Also applies to: 57-58

agent-docs/src/agents/doc-processing/keyword-extraction.ts (1)

37-50: Harden the prompt: explicitly forbid code fences and extra text in the response.

LLMs frequently wrap JSON in ```json fences or prepend explanations, which breaks strict parsers. Make the constraint explicit to reduce parse failures.

-Return the keywords as a JSON array in the following format:
+Return the keywords as a JSON array in the following format.
+Important: Return only the JSON object, with no surrounding code fences, no leading/trailing text, and no explanations:
 {
   "keywords": ["keyword1", "keyword2", ...]
 }

Comment on lines +155 to +165
id: crypto.randomUUID(),
chunkIndex: idx,
totalChunks: chunks.length,
contentType: chunk.metadata.contentType,
heading: currentHeading,
text: chunk.pageContent,
title: frontmatter.title,
description: frontmatter.description,
createdAt: new Date().toISOString(),
};
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid relying on global crypto; import Node’s randomUUID for portability and correct typings.

crypto may not be available as a global depending on the TS lib config (no DOM) and runtime. Importing from crypto avoids compile/runtime surprises.

@@
-import type { Document } from 'langchain/document';
+import type { Document } from 'langchain/document';
+import { randomUUID } from 'crypto';
@@
-      id: crypto.randomUUID(),
+      id: randomUUID(),
📝 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
id: crypto.randomUUID(),
chunkIndex: idx,
totalChunks: chunks.length,
contentType: chunk.metadata.contentType,
heading: currentHeading,
text: chunk.pageContent,
title: frontmatter.title,
description: frontmatter.description,
createdAt: new Date().toISOString(),
};
});
// at top of agent-docs/src/agents/doc-processing/chunk-mdx.ts
import type { Document } from 'langchain/document';
import { randomUUID } from 'crypto';
// …later, in the mapping over chunks:
const processed = chunks.map((chunk, idx) => {
return {
id: randomUUID(),
chunkIndex: idx,
totalChunks: chunks.length,
contentType: chunk.metadata.contentType,
heading: currentHeading,
text: chunk.pageContent,
title: frontmatter.title,
description: frontmatter.description,
createdAt: new Date().toISOString(),
};
});
🤖 Prompt for AI Agents
In agent-docs/src/agents/doc-processing/chunk-mdx.ts around lines 155-165, the
code uses the global crypto.randomUUID(); replace this with an explicit import
from Node's crypto module: add "import { randomUUID } from 'crypto';" at the top
of the file (or combined into existing imports) and change crypto.randomUUID()
to randomUUID(); ensure TypeScript types compile by having the Node lib
available (or adjust tsconfig if necessary) so the module import is used
consistently instead of the global.

Comment on lines +12 to 18
export async function processDoc(
docContent: string
): Promise<VectorUpsertParams[]> {
const chunks = await chunkAndEnrichDoc(docContent);
const vectors = await createVectorEmbedding(chunks);
return vectors;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add structured error handling and logging per agent-docs guidelines

Wrap the top-level orchestration in a try/catch to log contextual errors before rethrowing. This aligns with the coding guidelines for agent-docs/src/agents/**.

-export async function processDoc(
-  docContent: string
-): Promise<VectorUpsertParams[]> {
-  const chunks = await chunkAndEnrichDoc(docContent);
-  const vectors = await createVectorEmbedding(chunks);
-  return vectors;
-}
+export async function processDoc(
+  docContent: string
+): Promise<VectorUpsertParams[]> {
+  try {
+    const chunks = await chunkAndEnrichDoc(docContent);
+    const vectors = await createVectorEmbedding(chunks);
+    return vectors;
+  } catch (err) {
+    // TODO: replace console with the project logger
+    // logger.error({ err }, 'processDoc failed');
+    console.error('processDoc failed:', err);
+    throw err;
+  }
+}

If you point me to the logger you use in this package, I can wire it in and open a follow-up PR.

📝 Committable suggestion

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

Suggested change
export async function processDoc(
docContent: string
): Promise<VectorUpsertParams[]> {
const chunks = await chunkAndEnrichDoc(docContent);
const vectors = await createVectorEmbedding(chunks);
return vectors;
}
export async function processDoc(
docContent: string
): Promise<VectorUpsertParams[]> {
try {
const chunks = await chunkAndEnrichDoc(docContent);
const vectors = await createVectorEmbedding(chunks);
return vectors;
} catch (err) {
// TODO: replace console with the project logger
// logger.error({ err }, 'processDoc failed');
console.error('processDoc failed:', err);
throw err;
}
}
🤖 Prompt for AI Agents
In agent-docs/src/agents/doc-processing/docs-processor.ts around lines 12 to 18,
the top-level orchestration lacks structured error handling and logging; wrap
the body of processDoc in a try/catch, import and use the package logger (or
accept the logger instance you use in this package) to log a contextual error
message including the doc metadata or a concise context string and the caught
error, then rethrow the error so callers can handle it upstream; ensure the
catch only logs and rethrows (no swallowing) and keep the function return type
unchanged.

Comment on lines +56 to +77
const result = await generateText({
model: openai(model),
prompt,
maxTokens: 150,
temperature: 0.2,
});
const raw = result.text || '';
let keywords: string[] = [];
const parsed = JSON.parse(raw);
if (Array.isArray(parsed.keywords)) {
keywords = parsed.keywords
.map((k: string) => k.trim())
.filter((k: string) => Boolean(k))
.filter((k: string, i: number, arr: string[]) => arr.indexOf(k) === i)
.slice(0, maxKeywords);
}
logger.info('Extracted keywords: %o', keywords);
return {
keywords,
source: 'llm',
chunkPreview: chunkContent.slice(0, 100),
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add robust parsing and fallbacks (code-fence stripping, array/object support, CSV fallback, safe dedupe).

Right now a non-object JSON (e.g., a raw array) or a fenced JSON payload will either throw or silently return an empty list. The JSDoc mentions a CSV fallback, but it isn’t implemented.

-  const result = await generateText({
+  const result = await generateText({
     model: openai(model),
     prompt,
     maxTokens: 150,
     temperature: 0.2,
   });
-  const raw = result.text || '';
-  let keywords: string[] = [];
-  const parsed = JSON.parse(raw);
-  if (Array.isArray(parsed.keywords)) {
-    keywords = parsed.keywords
-      .map((k: string) => k.trim())
-      .filter((k: string) => Boolean(k))
-      .filter((k: string, i: number, arr: string[]) => arr.indexOf(k) === i)
-      .slice(0, maxKeywords);
-  }
+  let raw = (result.text || '').trim();
+  // Strip common code fences if present
+  raw = raw.replace(/^\s*```(?:json)?\s*/i, '').replace(/\s*```$/i, '').trim();
+
+  let keywords: string[] = [];
+  try {
+    const parsed = JSON.parse(raw);
+    if (Array.isArray(parsed)) {
+      // Model returned a bare array: ["a","b",...]
+      keywords = parsed as string[];
+    } else if (parsed && Array.isArray((parsed as any).keywords)) {
+      keywords = (parsed as any).keywords as string[];
+    }
+  } catch {
+    // Fallback: parse comma/newline separated values
+    keywords = raw
+      .split(/[\n,]+/g)
+      .map((k) => k.trim())
+      .filter(Boolean);
+  }
+
+  // Normalize, dedupe case-insensitively, and cap
+  const seen = new Set<string>();
+  keywords = keywords
+    .map((k) => k.trim())
+    .filter(Boolean)
+    .filter((k) => {
+      const key = k.toLowerCase();
+      if (seen.has(key)) return false;
+      seen.add(key);
+      return true;
+    })
+    .slice(0, maxKeywords);
+
+  if (keywords.length === 0) {
+    throw new Error('Failed to extract keywords from LLM response');
+  }
   logger.info('Extracted keywords: %o', keywords);
   return {
     keywords,
     source: 'llm',
     chunkPreview: chunkContent.slice(0, 100),
   };
📝 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
const result = await generateText({
model: openai(model),
prompt,
maxTokens: 150,
temperature: 0.2,
});
const raw = result.text || '';
let keywords: string[] = [];
const parsed = JSON.parse(raw);
if (Array.isArray(parsed.keywords)) {
keywords = parsed.keywords
.map((k: string) => k.trim())
.filter((k: string) => Boolean(k))
.filter((k: string, i: number, arr: string[]) => arr.indexOf(k) === i)
.slice(0, maxKeywords);
}
logger.info('Extracted keywords: %o', keywords);
return {
keywords,
source: 'llm',
chunkPreview: chunkContent.slice(0, 100),
};
const result = await generateText({
model: openai(model),
prompt,
maxTokens: 150,
temperature: 0.2,
});
let raw = (result.text || '').trim();
// Strip common code fences if present
raw = raw
.replace(/^\s*
🤖 Prompt for AI Agents
In agent-docs/src/agents/doc-processing/keyword-extraction.ts around lines
56–77, the current parsing assumes a JSON object with a keywords array and will
fail or return empty for fenced JSON, bare arrays, or CSV-style responses;
implement robust parsing by first stripping Markdown code fences/backticks from
raw, then try JSON.parse inside a try/catch and accept either a bare array or an
object with a keywords property, and on parse failure fall back to splitting raw
by commas/newlines to extract tokens; afterwards normalize tokens (trim),
perform case-insensitive dedupe using a Set, limit to maxKeywords, and if the
final list is empty throw a clear error; ensure you log the resulting keywords
as before.

Comment on lines +57 to +59
const rephrasedQuery = result.text?.trim() || input;
console.log(rephrasedQuery);
// Log if we actually rephrased it
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove console.log to avoid PII leakage; use the provided logger instead.

Raw console logging can leak user input outside your structured logging pipeline. Replace or drop it.

-		console.log(rephrasedQuery);
🤖 Prompt for AI Agents
In agent-docs/src/agents/doc-qa/prompt.ts around lines 57 to 59, remove the raw
console.log(rephrasedQuery) to avoid PII leakage and instead use the module's
provided logger (e.g., logger.debug or logger.info) or drop the log entirely; if
you must record the event, log a non-sensitive message such as "query rephrased"
and only include a hashed/trimmed token or boolean flag indicating rephrasing,
ensuring no raw user input is written to stdout/stderr.

Comment on lines +57 to +66
const rephrasedQuery = result.text?.trim() || input;
console.log(rephrasedQuery);
// Log if we actually rephrased it
if (rephrasedQuery !== input) {
ctx.logger.info(
'Rephrased query from "%s" to "%s"',
input,
rephrasedQuery
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Repo-wide sanity check for stray console logging.

To prevent future leaks, scan the repo for other console.log/console.error etc., and replace them with ctx.logger equivalents where appropriate.


🏁 Script executed:

#!/bin/bash
# Find raw console logging across the repo (excluding node_modules and build artifacts)
rg -nP --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' '\bconsole\.(log|error|warn|info|debug)\s*\(' -C2

Length of output: 22566


Replace raw console statements with ctx.logger across source files

I ran a repo-wide search and identified the following non-documentation files that still use raw console.* calls. Please replace these with ctx.logger.<level> (e.g., ctx.logger.debug, ctx.logger.info, ctx.logger.warn, ctx.logger.error) to ensure consistent, configurable logging:

• scripts/generate-docs-json.js
• lib/env.ts
• components/Mermaid.tsx
• app/layout.tsx
• components/CopyPageDropdown.tsx
• components/CustomSearchDialog/hooks/useMessages.tsx
• app/api/rag-search/route.ts
• app/api/page-content/route.ts
• app/llms.txt/route.ts
• app/llms-full.txt/route.ts
• agent-docs/index.ts
• agent-docs/src/agents/doc-qa/prompt.ts

Exclude MDX guide files under content/ (these are user-facing examples). Once updated, double-check that logging levels align with intent (debug vs. info vs. warn vs. error).

🤖 Prompt for AI Agents
In agent-docs/src/agents/doc-qa/prompt.ts around lines 57 to 66, replace the raw
console.log(rephrasedQuery) with the contextual logger (e.g., ctx.logger.debug)
and use a descriptive message; keep the existing ctx.logger.info call for when
the query actually changed. Ensure ctx.logger is available in scope and that the
logging level matches intent (debug for routine values, info for meaningful
state changes). Also scan the repo for other console.* usages noted in the
review and replace them with the appropriate ctx.logger.<level> calls.

Comment on lines +14 to 16
const [currentInput, setCurrentInput] = useState('');
const inputRef = useRef<HTMLTextAreaElement>(null);

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Unwired inputRef and focus effect: either remove or forward a ref to SearchInput.

inputRef is never attached to an element, so the open-focus effect is a no-op. Since SearchInput already focuses on mount, you can drop this altogether, or forward the ref if parent-controlled focus is desired.

-  const [currentInput, setCurrentInput] = useState('');
-  const inputRef = useRef<HTMLTextAreaElement>(null);
+  const [currentInput, setCurrentInput] = useState('');
@@
-  // Focus input when dialog opens
-  useEffect(() => {
-    if (open) {
-      setTimeout(() => inputRef.current?.focus(), 100);
-    }
-  }, [open]);
+  // SearchInput focuses itself on mount; parent-level focusing not required here.

If you prefer parent-controlled focus, expose a ref from SearchInput:

// in SearchInput.tsx
export const SearchInput = forwardRef<HTMLTextAreaElement, SearchInputProps>(function SearchInput(props, ref) {
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  useImperativeHandle(ref, () => textareaRef.current as HTMLTextAreaElement | null);
  // ...use textareaRef on the <textarea />
});

Also applies to: 26-31

🤖 Prompt for AI Agents
In components/CustomSearchDialog/index.tsx around lines 14-16 (and related
effect at 26-31), the inputRef is created but never attached so the focus effect
is a no-op; either remove the unused inputRef and the open-focus effect
entirely, or forward the ref into SearchInput and attach it to the actual
<textarea>. To forward: change SearchInput to use
forwardRef<HTMLTextAreaElement,...>, keep an internal textarea ref and expose it
via useImperativeHandle, attach that internal ref to the textarea, and then pass
the inputRef down to <SearchInput ref={inputRef}/> from CustomSearchDialog;
ensure the focus effect uses the forwarded ref or is removed if SearchInput
already focuses on mount.

Comment on lines +120 to +125
// Extract string content from children
const code =
typeof codeElement?.props?.children === 'string'
? codeElement.props.children
: String(codeElement?.props?.children || '');

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix code extraction: arrays become comma-joined via String(). Join children without commas.

react-markdown often passes children as an array of strings/nodes. String([]) inserts commas, corrupting code. Join explicitly.

-                    // Extract string content from children
-                    const code =
-                      typeof codeElement?.props?.children === 'string'
-                        ? codeElement.props.children
-                        : String(codeElement?.props?.children || '');
+                    // Extract string content from children
+                    const rawChildren = codeElement?.props?.children;
+                    const code = Array.isArray(rawChildren)
+                      ? rawChildren.join('')
+                      : typeof rawChildren === 'string'
+                        ? rawChildren
+                        : String(rawChildren ?? '');
📝 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
// Extract string content from children
const code =
typeof codeElement?.props?.children === 'string'
? codeElement.props.children
: String(codeElement?.props?.children || '');
// Extract string content from children
const rawChildren = codeElement?.props?.children;
const code = Array.isArray(rawChildren)
? rawChildren.join('')
: typeof rawChildren === 'string'
? rawChildren
: String(rawChildren ?? '');
🤖 Prompt for AI Agents
In components/CustomSearchDialog/MessageList.tsx around lines 120-125, the code
uses String(codeElement?.props?.children) which will comma-join array children
and corrupt code blocks; instead detect if children is an array and join its
items without commas (e.g., map/flatMap to strings and join('') or join('')
after filtering null/undefined), otherwise keep the string branch, and fall back
to String(...) only for non-array, non-string values so code content is
preserved without extra commas.

Comment on lines +53 to +54
<div className="flex gap-2 h-10">
{/* Textarea Container */}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Auto-resize is capped by a fixed parent height (h-10) — textarea cannot grow

The wrapper’s h-10 locks the row height to 40px, negating the auto-resize effect (up to 150px). Remove the fixed height so the textarea can expand.

-    <div className="flex gap-2 h-10">
+    <div className="flex gap-2 items-end">
🤖 Prompt for AI Agents
In components/CustomSearchDialog/SearchInput.tsx around lines 53-54 the wrapper
div uses a fixed height class "h-10" which prevents the textarea from
auto-resizing; remove the "h-10" class from the container (or replace it with a
min-height if a baseline height is needed) so the textarea can expand up to its
max height (150px) and ensure any layout CSS (flex alignment or gap) still
behaves as intended.

Comment on lines +28 to 33
securityLevel: 'loose',
fontFamily: 'inherit',
themeCSS: 'margin: 1.5rem auto 0;',
theme: _theme,
darkMode: _theme === "dark",
darkMode: _theme === 'dark',
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Security: securityLevel 'loose' + dangerouslySetInnerHTML enables XSS if chart content is untrusted.

Mermaid’s “loose” mode permits raw HTML. Combined with dangerouslySetInnerHTML, this is a high-risk vector if user-supplied charts are ever rendered. Use securityLevel: 'strict' (default) and only relax if inputs are fully trusted and sanitized.

 mermaid.initialize({
   startOnLoad: false,
-  securityLevel: 'loose',
+  securityLevel: 'strict',
   fontFamily: 'inherit',
   themeCSS: 'margin: 1.5rem auto 0;',
   theme: _theme,
   darkMode: _theme === 'dark',
 });

If you truly need HTML labels, sanitize upstream and consider restricting allowed directives; document the trust boundary.

📝 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
securityLevel: 'loose',
fontFamily: 'inherit',
themeCSS: 'margin: 1.5rem auto 0;',
theme: _theme,
darkMode: _theme === "dark",
darkMode: _theme === 'dark',
});
mermaid.initialize({
startOnLoad: false,
securityLevel: 'strict',
fontFamily: 'inherit',
themeCSS: 'margin: 1.5rem auto 0;',
theme: _theme,
darkMode: _theme === 'dark',
});
🤖 Prompt for AI Agents
In components/Mermaid.tsx around lines 28 to 33, the code sets mermaid config
securityLevel: 'loose' while rendering with dangerouslySetInnerHTML which
enables raw HTML and is an XSS risk for untrusted chart content; change
securityLevel to 'strict' (the safe default) and remove or avoid passing
unsanitized HTML to dangerouslySetInnerHTML, or if HTML labels are required,
ensure upstream sanitization of chart input (whitelist allowed tags/attributes
and strip scripts) and document the trust boundary; if you must permit limited
HTML, implement and call a sanitizer here before assigning to
dangerouslySetInnerHTML and add a comment explaining why the relaxation is safe.

theme: _theme,
darkMode: _theme === "dark",
darkMode: _theme === 'dark',
});
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify darkMode option is valid for current Mermaid version.

Upstream Mermaid config has evolved; confirm that darkMode is a supported option (vs. relying solely on theme/themeVariables).


🌐 Web query:

Is `darkMode` a valid configuration option in Mermaid v11, or should we rely only on `theme` and `themeVariables`?

💡 Result:

I cannot find any documented darkMode option in Mermaid v11. Configure dark appearance with theme: 'dark' (and override colors via themeVariables or themeCSS) instead [1][2].

References:

  1. Mermaid configuration (theme & themeVariables) — https://mermaid.js.org/configuration/configuration.html
  2. mermaidAPI.initialize options (theme, themeVariables) — https://mermaid.js.org/mermaidAPI.html#initialize

Replace unsupported darkMode option with theme: 'dark'

Mermaid v11 does not recognize a darkMode setting. You should remove the darkMode entry from your configuration and instead use:

  • theme: 'dark' (or conditional logic to toggle between 'dark' and 'default')
  • themeVariables or themeCSS to customize any specific colors

Please update the call in components/Mermaid.tsx (around line 33) accordingly:

  • Remove the darkMode property.
  • Add or adjust:
    mermaid.initialize({
    -   darkMode: isDark,
        theme: isDark ? 'dark' : 'default',
        themeVariables: { /* your overrides here */ },
    });

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

🤖 Prompt for AI Agents
In components/Mermaid.tsx around line 33, the mermaid config uses an unsupported
darkMode option; remove the darkMode property and replace it with theme: 'dark'
(or add conditional logic to set theme to 'dark' or 'default' based on app
theme), and if you need custom colors move those settings into themeVariables or
themeCSS so the mermaid.initialize call uses recognized keys.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
components/Mermaid.tsx (1)

14-19: Prevent stale renders and state updates after unmount.

renderChart is async; rapid prop/theme changes can cause out-of-order updates or setState on unmounted component. You already have currentChartRef; use it and add cleanup.

   const container = containerRef.current;
   if (!container) return;
-  currentChartRef.current = chart;
+  // Snapshot the chart for this render to prevent out-of-order updates
+  currentChartRef.current = chart;
 
   async function renderChart() {
-    const { default: mermaid } = await import('mermaid');
+    const { default: mermaid } = await import('mermaid');
+    const snapshot = currentChartRef.current;
     const _theme =
       theme === 'dark' || (theme === 'system' && resolvedTheme === 'dark')
         ? 'dark'
         : 'neutral';
 
     try {
       mermaid.initialize({
         startOnLoad: false,
         securityLevel: 'strict',
         fontFamily: 'inherit',
         themeCSS: 'margin: 1.5rem auto 0;',
         theme: _theme,
       });
-      const { svg, bindFunctions } = await mermaid.render(
-        id,
-        chart.replaceAll('\\n', '\n')
-      );
+      const normalized = chart.replace(/\r\n/g, '\n').replaceAll('\\n', '\n');
+      // Optional: validate before render to fail fast on bad diagrams
+      await mermaid.parse(normalized);
+      const { svg, bindFunctions } = await mermaid.render(id, normalized);
 
       // biome-ignore lint/style/noNonNullAssertion: <explanation>
       bindFunctions?.(container!);
-      setSvg(svg);
+      // Abort if a newer render started or component unmounted
+      if (snapshot !== currentChartRef.current || canceled) return;
+      setSvg(svg);
     } catch (error) {
       console.error('Error while rendering mermaid', error);
     }
   }
 
-  void renderChart();
+  let canceled = false;
+  void renderChart();
+  return () => {
+    canceled = true;
+  };
-}, [chart, id, resolvedTheme, theme]);
+}, [chart, id, resolvedTheme, theme]);

API references for async render and bindFunctions. (github.com, fossies.org)

Also applies to: 41-48

♻️ Duplicate comments (4)
agent-docs/src/agents/doc-qa/prompt.ts (1)

57-66: Remove raw console.log and avoid logging full user text; use sanitized structured logging via ctx.logger.

Direct console logging risks PII leakage and bypasses your logging pipeline. Also, logging the entire before/after query at info level exposes raw user input. Replace with sanitized metadata (changed flag and lengths).

Apply this diff:

-		const rephrasedQuery = result.text?.trim() || input;
-		console.log(rephrasedQuery);
-		// Log if we actually rephrased it
-		if (rephrasedQuery !== input) {
-			ctx.logger.info(
-				'Rephrased query from "%s" to "%s"',
-				input,
-				rephrasedQuery
-			);
-		}
+		let rephrasedQuery = result.text?.trim() || input;
+		// Strip enclosing quotes if the model echoed them
+		if (
+			(rephrasedQuery.startsWith('"') && rephrasedQuery.endsWith('"')) ||
+			(rephrasedQuery.startsWith("'") && rephrasedQuery.endsWith("'"))
+		) {
+			rephrasedQuery = rephrasedQuery.slice(1, -1).trim();
+		}
+
+		// Structured + sanitized logging (no raw user text)
+		ctx.logger.debug(
+			'Rephrase result: changed=%s, inLen=%d, outLen=%d',
+			rephrasedQuery !== input,
+			input.length,
+			rephrasedQuery.length
+		);
+		if (rephrasedQuery !== input) {
+			ctx.logger.info(
+				'Rephrased query (sanitized): changed=%s, inLen=%d, outLen=%d',
+				true,
+				input.length,
+				rephrasedQuery.length
+			);
+		}
components/Mermaid.tsx (2)

28-33: Security: switch securityLevel to 'strict' and justify/mitigate dangerouslySetInnerHTML.

Using securityLevel: 'loose' together with dangerouslySetInnerHTML exposes you to XSS if chart content is ever untrusted. Mermaid’s default is 'strict' (encodes HTML, disables clicks). If you truly need HTML labels, sanitize upstream and document the trust boundary; otherwise prefer 'strict'. Also replace the placeholder "" in the biome-ignore with a concrete justification.

Apply this minimal hardening:

 mermaid.initialize({
   startOnLoad: false,
-  securityLevel: 'loose',
+  securityLevel: 'strict',
   fontFamily: 'inherit',
   themeCSS: 'margin: 1.5rem auto 0;',
   theme: _theme,
-  darkMode: _theme === 'dark',
 });

Optionally, add a sanitizer (e.g., DOMPurify) before setting innerHTML if you must stay in a relaxed mode.

References: Mermaid config schema (securityLevel default = "strict"; 'loose' allows HTML), and options overview. (mermaid.js.org)

Also applies to: 53-55


31-33: Replace unsupported top-level darkMode with theme or themeVariables.darkMode.

Mermaid v10/v11 does not support a top-level darkMode key in initialize(). Use theme: 'dark' or themeVariables: { darkMode: true } alongside a compatible theme. Since you already compute _theme, removing darkMode is sufficient.

 mermaid.initialize({
   startOnLoad: false,
   securityLevel: 'strict',
   fontFamily: 'inherit',
   themeCSS: 'margin: 1.5rem auto 0;',
   theme: _theme,
-  darkMode: _theme === 'dark',
 });

Docs: themes and themeVariables (darkMode lives under themeVariables). (mermaid.js.org)

components/CustomSearchDialog/MessageList.tsx (1)

109-138: Fix code extraction: String(array) comma-joins children; add guards and robust language detection

Current logic uses String(codeElement.props.children) which inserts commas when children is an array, corrupting code blocks. Also add a null-safe guard for non-element children and a more robust language extractor. Trim CLI commands to avoid trailing blank lines.

Apply this diff:

-                  pre: ({ children }) => {
-                    // Extract code content and language
-                    const codeElement = React.Children.toArray(
-                      children
-                    )[0] as React.ReactElement<{
-                      className?: string;
-                      children?: React.ReactNode;
-                    }>;
-                    const className = codeElement?.props?.className || '';
-                    const language = className.replace('language-', '');
-
-                    // Extract string content from children
-                    const code =
-                      typeof codeElement?.props?.children === 'string'
-                        ? codeElement.props.children
-                        : String(codeElement?.props?.children || '');
-
-                    // Use CLICommand for bash/shell commands
-                    if (
-                      language === 'bash' ||
-                      language === 'sh' ||
-                      language === 'shell'
-                    ) {
-                      return <CLICommand command={code} />;
-                    }
-
-                    return (
-                      <DynamicCodeBlock code={code} lang={language || 'text'} />
-                    );
-                  },
+                  pre: ({ children }) => {
+                    // Extract code content and language safely
+                    const [firstChild] = React.Children.toArray(children);
+                    const codeElement = React.isValidElement(firstChild)
+                      ? (firstChild as React.ReactElement<{
+                          className?: string;
+                          children?: React.ReactNode;
+                        }>)
+                      : undefined;
+
+                    const className = codeElement?.props?.className ?? '';
+                    const language =
+                      className.match(/\blanguage-([^\s]+)/)?.[1] ?? '';
+
+                    // Extract string content from children — avoid comma-joining arrays
+                    const rawChildren = codeElement?.props?.children;
+                    const code = Array.isArray(rawChildren)
+                      ? rawChildren
+                          .map((c) =>
+                            typeof c === 'string' || typeof c === 'number'
+                              ? String(c)
+                              : ''
+                          )
+                          .join('')
+                      : typeof rawChildren === 'string' || typeof rawChildren === 'number'
+                        ? String(rawChildren)
+                        : String(rawChildren ?? '');
+
+                    // Use CLICommand for bash/shell commands
+                    if (language === 'bash' || language === 'sh' || language === 'shell') {
+                      return <CLICommand command={code.trim()} />;
+                    }
+
+                    return (
+                      <DynamicCodeBlock code={code} lang={language || 'text'} />
+                    );
+                  },
🧹 Nitpick comments (13)
agent-docs/src/agents/doc-qa/prompt.ts (2)

57-58: Harden output normalization: strip enclosing quotes from LLM output.

The model can occasionally return the query wrapped in quotes due to the prompt formatting. Normalize by removing symmetrical leading/trailing quotes. This also enables switching from const to let for reassignment.

The change above in the prior diff already implements this normalization.


122-127: Lower verbosity of classification logs to debug (or sanitize).

Classification reasoning is useful for debugging but noisy at info level. Consider logging at debug, or remove reasoning from info to reduce log volume.

-		ctx.logger.info(
+		ctx.logger.debug(
 			'Prompt classified as %s (confidence: %f): %s',
 			result.object.type,
 			result.object.confidence,
 			result.object.reasoning
 		);
agent-docs/src/agents/doc-qa/rag.ts (2)

9-12: Annotate return type for stronger typing and API stability.

Explicitly return Promise to lock the contract and improve IDE help.

-export default async function answerQuestion(
+export default async function answerQuestion(
 	ctx: AgentContext,
 	prompt: string
-) {
+): Promise<Answer> {

19-96: Optional: route by prompt type to balance cost/latency vs. quality.

You already have getPromptType; consider using it to select model/parameters (e.g., gpt-4o-mini for Normal, gpt-4o for Thinking) and adjust maxTokens/temperature accordingly. This keeps simple queries fast and cheap without sacrificing complex ones.

Example insertion after retrieval:

+	// Optionally classify prompt complexity to choose model/params
+	// const promptType = await getPromptType(ctx, rephrasedPrompt);
+	// const isThinking = promptType === 'Thinking';
+	// const model = openai(isThinking ? 'gpt-4o' : 'gpt-4o-mini');
+	// const maxTokens = isThinking ? 2048 : 1024;
app/(docs)/[[...slug]]/page.tsx (4)

19-21: Prefer path aliases over deep relative paths for consistency

Elsewhere in this file you already use the @/* alias. Using it here improves readability and reduces churn on future file moves.

-import { CommunityButton } from '../../../components/Community';
-import CopyPageDropdown from '../../../components/CopyPageDropdown';
-import { NavButton } from '../../../components/NavButton';
+import { CommunityButton } from '@/components/Community';
+import CopyPageDropdown from '@/components/CopyPageDropdown';
+import { NavButton } from '@/components/NavButton';

23-27: Avoid Promise-wrapping params; Next.js passes route params synchronously

params is provided synchronously to App Router page components. Keeping it non-Promise aligns with Next types and removes an unnecessary await.

-export default async function Page(props: {
-  params: Promise<{ slug?: string[] }>;
-}) {
-  const params = await props.params;
+export default async function Page(props: { params: { slug?: string[] } }) {
+  const { params } = props;

77-79: Copy nit: “Sign up” (verb) vs “Signup” (noun)

Slight wording tweak for consistency with common UI copy.

-        <a href="mailto:hi@agentuity.com">hi@agentuity.com</a> if you&apos;d
+        <a href="mailto:hi@agentuity.com">hi@agentuity.com</a> if you’d

And for the CTA below (Line 86):

-        <a href="https://app.agentuity.com/sign-up">Signup</a>
+        <a href="https://app.agentuity.com/sign-up">Sign up</a>

99-103: Same as Page: remove Promise from generateMetadata params

Keep params synchronous and drop the await for type clarity.

-export async function generateMetadata(props: {
-  params: Promise<{ slug?: string[] }>;
-}) {
-  const params = await props.params;
+export async function generateMetadata(props: { params: { slug?: string[] } }) {
+  const { params } = props;
components/Mermaid.tsx (3)

21-23: Confirm theme choice 'neutral' for light mode.

neutral is intended for black-and-white/print; many UIs prefer default for light mode. If this was unintentional, switch to 'default'. Otherwise, keep as-is.

Reference: available themes include default, neutral, dark, forest, base. (mermaid.js.org, github.com)


36-36: Normalize both escaped and real Windows newlines.

If incoming chart strings sometimes contain actual CRLFs or literal "\r\n" and "\n", normalize both before render.

- chart.replaceAll('\\n', '\n')
+ chart.replace(/\r\n/g, '\n').replaceAll('\\n', '\n')

43-43: Improve error telemetry and UX fallback.

Augment the log with id and theme; optionally clear SVG or show a small fallback UI to avoid stale diagrams when a render fails.

- console.error('Error while rendering mermaid', error);
+ console.error('Error while rendering mermaid', { id, theme: _theme, error });
+ // Optionally: setSvg('<svg aria-hidden="true"></svg>');
components/CustomSearchDialog/MessageList.tsx (2)

126-133: Recognize more shell aliases for CLI command blocks

Small UX win: treat zsh/console/shell-session variants as CLI commands too.

-                    if (
-                      language === 'bash' ||
-                      language === 'sh' ||
-                      language === 'shell'
-                    ) {
-                      return <CLICommand command={code.trim()} />;
-                    }
+                    if (
+                      ['bash', 'sh', 'shell', 'zsh', 'console', 'shell-session', 'sh-session'].includes(
+                        language
+                      )
+                    ) {
+                      return <CLICommand command={code.trim()} />;
+                    }

63-65: Hide decorative avatars from screen readers

These avatar icons are purely presentational; hide them to reduce verbosity for assistive tech.

-      <div className="w-6 h-6 bg-gray-50 dark:bg-gray-800 rounded-full flex items-center justify-center flex-shrink-0">
+      <div aria-hidden="true" className="w-6 h-6 bg-gray-50 dark:bg-gray-800 rounded-full flex items-center justify-center flex-shrink-0">
         <AgentuityLogo className="w-3 h-3 text-gray-500 dark:text-gray-400" />
       </div>
-      <div className="w-6 h-6 bg-gray-50 dark:bg-gray-800 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
+      <div aria-hidden="true" className="w-6 h-6 bg-gray-50 dark:bg-gray-800 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
         <AgentuityLogo className="w-3 h-3 text-gray-500 dark:text-gray-400" />
       </div>
-      <div className="w-6 h-6 bg-gray-100 dark:bg-gray-700 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
+      <div aria-hidden="true" className="w-6 h-6 bg-gray-100 dark:bg-gray-700 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
         <User className="w-3 h-3 text-gray-500 dark:text-gray-400" />
       </div>

Also applies to: 89-92, 199-201

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira 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 100fa7d and a71da1a.

📒 Files selected for processing (24)
  • agent-docs/src/agents/doc-processing/chunk-mdx.ts (2 hunks)
  • agent-docs/src/agents/doc-processing/docs-orchestrator.ts (1 hunks)
  • agent-docs/src/agents/doc-processing/docs-processor.ts (1 hunks)
  • agent-docs/src/agents/doc-processing/embed-chunks.ts (1 hunks)
  • agent-docs/src/agents/doc-processing/test/chunk-mdx.test.ts (1 hunks)
  • agent-docs/src/agents/doc-qa/prompt.ts (4 hunks)
  • agent-docs/src/agents/doc-qa/rag.ts (3 hunks)
  • app/(docs)/[[...slug]]/page.tsx (4 hunks)
  • app/(docs)/layout.tsx (2 hunks)
  • app/api/rag-search/route.ts (1 hunks)
  • app/api/search/route.ts (1 hunks)
  • app/layout.tsx (3 hunks)
  • components/AISearchToggle.tsx (1 hunks)
  • components/CodeExample.tsx (2 hunks)
  • components/CopyPageDropdown.tsx (1 hunks)
  • components/CustomSearchDialog/MessageList.tsx (1 hunks)
  • components/CustomSearchDialog/SearchInput.tsx (1 hunks)
  • components/CustomSearchDialog/hooks/useMessages.tsx (1 hunks)
  • components/CustomSearchDialog/index.tsx (1 hunks)
  • components/Mermaid.tsx (2 hunks)
  • components/TypingAnimation.tsx (4 hunks)
  • lib/source.ts (1 hunks)
  • middleware.ts (1 hunks)
  • package.json (2 hunks)
✅ Files skipped from review due to trivial changes (3)
  • app/api/search/route.ts
  • agent-docs/src/agents/doc-processing/docs-orchestrator.ts
  • app/layout.tsx
🚧 Files skipped from review as they are similar to previous changes (16)
  • lib/source.ts
  • components/CodeExample.tsx
  • components/CopyPageDropdown.tsx
  • agent-docs/src/agents/doc-processing/chunk-mdx.ts
  • components/TypingAnimation.tsx
  • components/AISearchToggle.tsx
  • app/api/rag-search/route.ts
  • components/CustomSearchDialog/index.tsx
  • app/(docs)/layout.tsx
  • package.json
  • agent-docs/src/agents/doc-processing/embed-chunks.ts
  • components/CustomSearchDialog/hooks/useMessages.tsx
  • agent-docs/src/agents/doc-processing/docs-processor.ts
  • components/CustomSearchDialog/SearchInput.tsx
  • middleware.ts
  • agent-docs/src/agents/doc-processing/test/chunk-mdx.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
agent-docs/src/agents/**/*.ts

📄 CodeRabbit inference engine (agent-docs/.cursor/rules/sdk.mdc)

agent-docs/src/agents/**/*.ts: Use TypeScript for better type safety and IDE support
Import types from '@agentuity/sdk'
Use structured error handling with try/catch blocks
Leverage the provided logger for consistent logging
Use the storage APIs for persisting data
Consider agent communication for complex workflows

Files:

  • agent-docs/src/agents/doc-qa/prompt.ts
  • agent-docs/src/agents/doc-qa/rag.ts
🧠 Learnings (5)
📚 Learning: 2025-07-23T12:40:13.980Z
Learnt from: CR
PR: agentuity/docs#0
File: .cursor/rules/mdx.mdc:0-0
Timestamp: 2025-07-23T12:40:13.980Z
Learning: This is MDX so some react components can be used

Applied to files:

  • app/(docs)/[[...slug]]/page.tsx
📚 Learning: 2025-07-23T12:40:34.834Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-23T12:40:34.834Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Leverage the provided logger for consistent logging

Applied to files:

  • agent-docs/src/agents/doc-qa/prompt.ts
📚 Learning: 2025-07-23T12:40:22.412Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/agent.mdc:0-0
Timestamp: 2025-07-23T12:40:22.412Z
Learning: Applies to agent-docs/**/src/agents/**/index.ts : Use the provided logger from the `AgentContext` interface such as `ctx.logger.info("my message: %s", "hello")`

Applied to files:

  • agent-docs/src/agents/doc-qa/prompt.ts
📚 Learning: 2025-06-28T18:06:02.340Z
Learnt from: afterrburn
PR: agentuity/docs#208
File: agent-docs/src/agents/doc-qa/index.ts:27-28
Timestamp: 2025-06-28T18:06:02.340Z
Learning: The answerQuestion function in agent-docs/src/agents/doc-qa/rag.ts handles errors internally by logging them and returning a fallback JSON answer, so it doesn't require external try-catch blocks at the call site.

Applied to files:

  • agent-docs/src/agents/doc-qa/rag.ts
📚 Learning: 2025-07-23T12:40:34.834Z
Learnt from: CR
PR: agentuity/docs#0
File: agent-docs/.cursor/rules/sdk.mdc:0-0
Timestamp: 2025-07-23T12:40:34.834Z
Learning: Applies to agent-docs/src/agents/**/*.ts : Use structured error handling with try/catch blocks

Applied to files:

  • agent-docs/src/agents/doc-qa/rag.ts
🧬 Code graph analysis (4)
app/(docs)/[[...slug]]/page.tsx (1)
components/XButton.tsx (1)
  • XButton (4-34)
agent-docs/src/agents/doc-qa/prompt.ts (1)
agent-docs/src/agents/doc-qa/types.ts (2)
  • PromptType (27-27)
  • PromptClassificationSchema (18-22)
components/CustomSearchDialog/MessageList.tsx (3)
components/CustomSearchDialog/types.ts (2)
  • MessageListProps (26-30)
  • Message (3-14)
components/icons/AgentuityLogo.tsx (1)
  • AgentuityLogo (6-33)
components/CLICommand.tsx (1)
  • CLICommand (8-26)
agent-docs/src/agents/doc-qa/rag.ts (3)
agent-docs/src/agents/doc-qa/prompt.ts (1)
  • rephraseVaguePrompt (8-73)
agent-docs/src/agents/doc-qa/retriever.ts (1)
  • retrieveRelevantDocs (121-226)
agent-docs/src/agents/doc-qa/types.ts (2)
  • AnswerSchema (11-14)
  • Answer (26-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Workers Builds: docs
🔇 Additional comments (13)
agent-docs/src/agents/doc-qa/prompt.ts (1)

48-55: Good: fail-safe error handling returns original input on failure.

The try/catch with a safe fallback aligns with the agent guidelines for structured error handling.

Also applies to: 69-72

agent-docs/src/agents/doc-qa/rag.ts (1)

98-107: Solid fallback behavior with structured JSON and MDX guidance.

The catch block logs the error and returns a schema-compliant Answer with an MDX-formatted message. This maintains the function’s “never throw” contract for callers.

Also applies to: 110-126

app/(docs)/[[...slug]]/page.tsx (5)

1-3: LGTM on formatting/import style changes

The switch to single quotes and consistent import specifiers looks good and keeps Biome happy.

Also applies to: 10-18


41-41: Verify the content/ prefix matches page.file.path shape

If page.file.path already includes content/, this would duplicate the segment in the rendered URL.

Quick check: log one example during local dev or inspect source’s file.path contract to ensure no double content/ occurs.


52-69: Client components inside MDX mapping: ensure they’re marked correctly

Components like TypingAnimation, Popup*, and Mermaid likely run client-side logic. Ensure those files are use client (where appropriate) to avoid hydration warnings when rendered via MDX.


109-112: LGTM on title fallback logic

The conditional nicely handles the “Agentuity” root title vs. specific page titles.


37-43: Could you share the relevant FumaDocs documentation or your DocsPage/editOnGithub configuration snippet (e.g. the docs link or code example) so we can confirm whether sha must be a full commit SHA or if a branch name like "main" is supported?

components/Mermaid.tsx (2)

1-1: LGTM: client-only component directive is correct.

Mermaid rendering is browser-only; 'use client' is appropriate here.


3-4: LGTM: dynamic import + next-themes usage fit SSR constraints.

Importing mermaid inside useEffect avoids SSR issues and keeps the bundle lean.

components/CustomSearchDialog/MessageList.tsx (4)

10-16: LGTM on type-only import and props signature formatting

Type-only import reduces bundle size and clarifies intent. Multiline destructuring of MessageList props reads well and is non-breaking.


20-23: Auto-scroll dependency exception is acceptable

Ignoring exhaustive-deps here is intentional and scoped; scrolling only on message changes avoids jumpiness during transient loading updates.


139-151: Inline code rendering is sensible

Fallback class adds wrapping and preserves whitespace. Keeping language-specific classes for inline code when provided is fine.


190-195: Timestamp runtime type confirmed
All messages always carry a Date at render time:

  • components/CustomSearchDialog/types.ts declares timestamp: Date.
  • New messages are instantiated with new Date() (user, AI, error, and fallback flows).
  • Persisted history is JSON.stringify-ed (yielding ISO strings) then on load mapped back via new Date(msg.timestamp) in the useMessages hook.
  • The dialog and its hooks live in a client component ('use client'), so there’s no SSR/rehydration risk.

Calling message.timestamp.toLocaleTimeString(...) is safe—no further changes needed.

const [svg, setSvg] = useState("");
const [svg, setSvg] = useState('');
const containerRef = useRef<HTMLDivElement>(null);
const currentChartRef = useRef<string>(null);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Type correctness: fix ref nullability.

useRef(null) is a type error under strict TS. Update to include null in the ref type.

- const currentChartRef = useRef<string>(null);
+ const currentChartRef = useRef<string | null>(null);
📝 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
const currentChartRef = useRef<string>(null);
const currentChartRef = useRef<string | null>(null);
🤖 Prompt for AI Agents
In components/Mermaid.tsx around line 10, the ref is created with
useRef<string>(null) which fails under strict TypeScript because null isn’t
allowed; change the ref type to include null (e.g. useRef<string | null>(null))
so the initial null value is type-safe, and update any downstream usages to
handle the possible null value (guard or non-null assertion where appropriate).

@Huijiro Huijiro merged commit e341aff into main Aug 27, 2025
2 checks passed
@Huijiro Huijiro deleted the grodrigues/agent-547-docs branch August 27, 2025 16:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants