Skip to content

feat: Implement governed RAG workflows and indexing#28

Merged
ssdeanx merged 1 commit intomainfrom
develop
Dec 9, 2025
Merged

feat: Implement governed RAG workflows and indexing#28
ssdeanx merged 1 commit intomainfrom
develop

Conversation

@ssdeanx
Copy link
Copy Markdown
Owner

@ssdeanx ssdeanx commented Dec 9, 2025

  • Created governed-rag-answer.workflow.ts to handle multi-agent governed retrieval-augmented generation (RAG) process including authentication, document retrieval, answer generation, and verification.
  • Added detailed logging and error handling throughout the workflow steps to enhance observability and debugging.
  • Implemented governed-rag-index.workflow.ts for indexing documents with security tags and classifications, ensuring proper handling of document indexing results.
  • Introduced new types in types.ts for better type safety and clarity, including Principal, AccessFilter, Document, and Chunk.
  • Added utility functions in streamUtils.ts for handling server-sent events (SSE) and streaming text data, including createSSEStream, streamProgressUpdate, and handleTextStream.
  • Developed comprehensive tests for streaming utilities in streamUtils.test.ts to ensure functionality and reliability.
  • Updated tsconfig.cli.json for improved TypeScript configuration in CLI context.
  • Documented the utilities directory and its purpose in AGENTS.md for better understanding and maintenance.

- Created `governed-rag-answer.workflow.ts` to handle multi-agent governed retrieval-augmented generation (RAG) process including authentication, document retrieval, answer generation, and verification.
- Added detailed logging and error handling throughout the workflow steps to enhance observability and debugging.
- Implemented `governed-rag-index.workflow.ts` for indexing documents with security tags and classifications, ensuring proper handling of document indexing results.
- Introduced new types in `types.ts` for better type safety and clarity, including `Principal`, `AccessFilter`, `Document`, and `Chunk`.
- Added utility functions in `streamUtils.ts` for handling server-sent events (SSE) and streaming text data, including `createSSEStream`, `streamProgressUpdate`, and `handleTextStream`.
- Developed comprehensive tests for streaming utilities in `streamUtils.test.ts` to ensure functionality and reliability.
- Updated `tsconfig.cli.json` for improved TypeScript configuration in CLI context.
- Documented the utilities directory and its purpose in `AGENTS.md` for better understanding and maintenance.
Copilot AI review requested due to automatic review settings December 9, 2025 13:22
@continue
Copy link
Copy Markdown

continue Bot commented Dec 9, 2025

Keep this PR in a mergeable state →

Learn more

All Green is an AI agent that automatically:

✅ Addresses code review comments

✅ Fixes failing CI checks

✅ Resolves merge conflicts

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Sorry @ssdeanx, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Dec 9, 2025

🤖 Hi @ssdeanx, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 9, 2025

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced chat with file attachment previews and downloads for non-image files
    • Inline preview support for documents and code sandboxes in messages
    • Improved task visualization in chat conversations
    • New CLI for document indexing, knowledge retrieval, and usage management with quota tracking
  • Documentation

    • Added architecture documentation for backend services, CLI operations, and utility layer

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

Walkthrough

This change introduces a comprehensive backend infrastructure for governed RAG with multi-tenant support, role-based access control, and tier-based quota management. New CLI commands enable document indexing and querying. UI enhancements include task parsing from assistant content, file attachment previews, and code sandbox support. Streaming utilities provide SSE handling for real-time updates.

Changes

Cohort / File(s) Summary
Chat UI Enhancements
app/chat/components/chat-messages.tsx
Added task extraction from assistant content, non-image attachment previews, code sandbox rendering, inline web preview modal, and chain-of-thought display fallback logic. Refactored WebPreviewPanel to accept preview prop instead of reading from context.
Role & Tier Management
src/mastra/config/role-service.ts
src/mastra/config/tier-management-service.ts
Introduced RoleService with role hierarchy expansion, access validation, and permission checking. Added TierManagementService with quota tracking, usage validation per subscription tier, daily reset logic, and feature access control.
Workflow Orchestration
src/mastra/workflows/governed-rag-answer.workflow.ts
src/mastra/workflows/governed-rag-index.workflow.ts
Created governedRagAnswer workflow with authentication, document retrieval/reranking, answer generation, and verification steps. Added governedRagIndex workflow for batch document indexing with pgVector integration.
CLI Tooling
src/cli/index.ts
src/cli/AGENTS.md
src/AGENTS.md
src/utils/AGENTS.md
Implemented CLI entrypoint with index, query, usage, demo, and help commands for document management and RAG operations. Added architectural documentation defining persona, scope, and workflow patterns for backend, CLI, and utilities layers.
Streaming Utilities
src/utils/streamUtils.ts
src/utils/streamUtils.test.ts
Introduced SSE stream creation, progress updates, JSON event encoding, and text stream handling. Added comprehensive test suite covering streaming behavior, encoding formats, error handling, and integration flows.
Type Definitions & Package API
src/types.ts
src/index.ts
Added public interfaces for Principal, AccessFilter, Document, and Chunk. Re-exported mastra module and types at package root.
Configuration & Utilities
lib/a2a.ts
package.json
tsconfig.cli.json
Introduced A2A agent demonstration script. Added build-cli, cli, and generate-index npm scripts. Created TypeScript configuration for CLI compilation.

Sequence Diagram

sequenceDiagram
    participant Client
    participant AuthService as Authentication<br/>Service
    participant Retriever as Document<br/>Retriever
    participant AnswerAgent as Answer<br/>Generator Agent
    participant VerifierAgent as Verifier<br/>Agent
    participant Response

    Client->>AuthService: Authentication (JWT)
    activate AuthService
    AuthService-->>Client: Access Filter + Question
    deactivate AuthService

    Client->>Retriever: Retrieve Documents<br/>(with Access Filter)
    activate Retriever
    Retriever-->>Client: Contexts
    deactivate Retriever

    Client->>AnswerAgent: Generate Answer<br/>(Contexts + Question)
    activate AnswerAgent
    AnswerAgent-->>Client: Answer + Citations
    deactivate AnswerAgent

    Client->>VerifierAgent: Verify Answer<br/>(Security Policies)
    activate VerifierAgent
    alt Verification Success
        VerifierAgent-->>Response: Return Answer + Citations
    else Insufficient Evidence
        VerifierAgent-->>Response: Return Fallback Answer
    end
    deactivate VerifierAgent
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Areas requiring extra attention:

  • Role and Tier Management Services: Complex authorization logic with role hierarchy expansion and quota validation across multiple operation types; verify correctness of role inheritance and quota enforcement
  • Governed RAG Workflows: Multi-step orchestration with error handling and fallback logic; review authentication validation, context filtering, and verification steps for security implications
  • Streaming Utilities: SSE encoding and AsyncIterable handling; verify proper encoding, error propagation, and resource cleanup in streaming paths
  • CLI Integration: Environment variable handling, service initialization, and workflow invocation; ensure proper error reporting and exit codes
  • Type/Interface Usage: Verify Principal, AccessFilter, Document, and Chunk types are consistently used throughout services and workflows

Possibly related PRs

  • Develop #14: Modifies same chat-messages component and adjusts WebPreviewPanel signature and MessageItem-related type exports; coordinates with this PR's UI component changes.

Suggested reviewers

  • Copilot

Poem

🐰 Through roles and tiers the rabbits bound,

Workflows orchestrated, safety found!

Tasks parse like clover, SSE streams flow,

Governed RAG now has the best show,

With sandbox code and previews so keen—

The fluffiest system you've ever seen! 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat: Implement governed RAG workflows and indexing' accurately summarizes the main changes, which center on implementing governed RAG workflows and document indexing capabilities.
Description check ✅ Passed The pull request description is directly related to the changeset, detailing the new workflows, types, utilities, tests, and documentation introduced across multiple files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

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

❤️ Share

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

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ssdeanx, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's Retrieval-Augmented Generation (RAG) capabilities by introducing governed, multi-agent workflows for both answering queries and indexing documents. It integrates robust role-based access control and subscription tier management to ensure data security and resource allocation. Furthermore, it provides a command-line interface for streamlined RAG operations and improves the chat UI with new features for displaying agent-generated tasks, file previews, and code snippets.

Highlights

  • Governed RAG Workflows: Implemented 'governed-rag-answer.workflow.ts' for a multi-agent RAG process, covering authentication, document retrieval, answer generation, and verification. Additionally, 'governed-rag-index.workflow.ts' was added for indexing documents with security tags and classifications.
  • Role-Based Access Control and Tier Management: Introduced 'RoleService' to manage role hierarchies, expand user roles, and enforce document access based on permissions. A 'TierManagementService' was also added to validate quotas, features, and classification access according to subscription tiers.
  • CLI for RAG Operations: A new command-line interface ('src/cli/index.ts') was developed to streamline operational tasks such as indexing documents, querying governed RAG workflows, and displaying usage statistics.
  • Enhanced UI for Agent Interactions: The 'chat-messages.tsx' component was updated to support displaying parsed agent tasks, inline file previews, and interactive code sandbox previews directly within chat messages.
  • Streaming Utilities: New utility functions in 'streamUtils.ts' were created for handling Server-Sent Events (SSE) and streaming text data, complete with comprehensive tests in 'streamUtils.test.ts'.
  • New Type Definitions: Core interfaces such as 'Principal', 'AccessFilter', 'Document', and 'Chunk' were defined in 'types.ts' to improve type safety and clarity across the application.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Dec 9, 2025

🤖 I'm sorry @ssdeanx, but I was unable to process your request. Please see the logs for more details.

@ssdeanx ssdeanx merged commit a1185e1 into main Dec 9, 2025
19 of 21 checks passed
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Dec 9, 2025

Greptile Overview

Greptile Summary

This PR implements a comprehensive governed RAG (Retrieval-Augmented Generation) system with multi-agent workflows, role-based access control, and subscription tier management.

Key Changes:

  • Implemented governed-rag-answer.workflow.ts with 4-step process: authentication → retrieval+rerank → answer generation → verification
  • Added governed-rag-index.workflow.ts for document indexing with security tags and classifications
  • Created RoleService and TierManagementService for access control and quota enforcement
  • Added streaming utilities (streamUtils.ts) with comprehensive test coverage for SSE streaming
  • Introduced type definitions for Principal, AccessFilter, Document, and Chunk
  • Added CLI interface for operational tasks (indexing, querying)
  • Enhanced chat UI components and A2A protocol examples

Architecture Integration:
The implementation follows Mastra's workflow patterns with proper use of createStep and createWorkflow, integrates with existing pg-storage vector configuration, and maintains consistency with the project's agent-driven architecture. The workflows leverage multiple specialized agents (retrieve, rerank, answerer, verifier) to implement a secure, governed RAG pipeline.

Issues Found:

  • Unused import ChunkType in governed-rag-answer.workflow.ts
  • Environment variable mismatch: QDRANT_COLLECTION used instead of PG_INDEX_NAME in indexing workflow
  • Hardcoded validation strings in retrieval step that create brittle checks
  • TierManagementService has TODO items for database persistence that need implementation before production

Confidence Score: 3/5

  • Safe to merge with minor fixes needed for production readiness
  • The implementation is well-structured with comprehensive error handling and follows established patterns. However, unused imports, environment variable naming inconsistencies, and TODO items for database persistence in TierManagementService need attention. The core logic is sound but these issues should be addressed before production deployment.
  • Focus on src/mastra/workflows/governed-rag-index.workflow.ts (env var fix) and src/mastra/config/tier-management-service.ts (implement persistence)

Important Files Changed

File Analysis

Filename Score Overview
src/mastra/workflows/governed-rag-answer.workflow.ts 3/5 Implemented 4-step governed RAG workflow with auth, retrieval+rerank, answer generation, and verification - includes comprehensive logging and security validation with some unused imports and hardcoded validation strings
src/mastra/workflows/governed-rag-index.workflow.ts 3/5 Document indexing workflow with security tags and classifications - has environment variable naming inconsistency (QDRANT_COLLECTION used for PgVector)
src/utils/streamUtils.ts 5/5 Clean SSE streaming utilities for progress updates and text streaming with proper event formatting - well-structured with clear separation of concerns
src/types.ts 5/5 Added clean type definitions for Principal, AccessFilter, Document, and Chunk to support governed RAG implementation - types are well-documented and structured
src/mastra/config/role-service.ts 5/5 Robust role service implementing role hierarchy expansion, access validation, and document-level permissions - comprehensive with good error handling
src/mastra/config/tier-management-service.ts 4/5 Subscription tier management with quota validation and usage tracking - TODO items for database persistence need implementation before production use

Sequence Diagram

sequenceDiagram
    participant Client
    participant Workflow as governedRagAnswer
    participant AuthService as AuthenticationService
    participant RetrieveAgent
    participant VectorStore as PgVector
    participant RerankAgent
    participant AnswererAgent
    participant VerifierAgent

    Client->>Workflow: execute({jwt, question})
    
    Note over Workflow: Step 1: Authentication
    Workflow->>AuthService: authenticateAndAuthorize(jwt)
    AuthService-->>Workflow: {accessFilter, principal}
    
    Note over Workflow: Step 2: Retrieval & Rerank
    Workflow->>RetrieveAgent: generate(question, accessFilter)
    RetrieveAgent->>VectorStore: query with security filters
    VectorStore-->>RetrieveAgent: contexts with securityTags
    RetrieveAgent-->>Workflow: retrieved contexts
    
    Workflow->>RerankAgent: generate(question, contexts)
    RerankAgent-->>Workflow: reranked contexts
    
    Note over Workflow: Step 3: Answer Generation
    Workflow->>AnswererAgent: generate(question, contexts)
    AnswererAgent-->>Workflow: {answer, citations}
    
    Note over Workflow: Step 4: Verification
    Workflow->>VerifierAgent: generate(answer, question, contexts)
    VerifierAgent-->>Workflow: {ok, reason}
    
    alt Verification Failed
        Workflow-->>Client: Error: Security violation
    else Verification Passed
        Workflow-->>Client: {answer, citations}
    end
Loading

Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

16 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

}),
execute: async ({ inputData, mastra }) => {
const startTime = Date.now()
const requestId = `REQ-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

style: use crypto module's randomBytes instead of Math.random() for better uniqueness

Suggested change
const requestId = `REQ-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`
const requestId = `REQ-${Date.now()}-${crypto.randomBytes(3).toString('hex')}`
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/workflows/governed-rag-answer.workflow.ts
Line: 94:94

Comment:
**style:** use crypto module's `randomBytes` instead of `Math.random()` for better uniqueness

```suggestion
        const requestId = `REQ-${Date.now()}-${crypto.randomBytes(3).toString('hex')}`
```

How can I resolve this? If you propose a fix, please make it concise.

} from '../schemas/agent-schemas'
import { AuthenticationService } from '../services/AuthenticationService'
import { log } from '../config/logger'
import { ChunkType } from '@mastra/core/stream';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

syntax: unused import - ChunkType is imported but never used in this file

Suggested change
import { ChunkType } from '@mastra/core/stream';
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/workflows/governed-rag-answer.workflow.ts
Line: 23:23

Comment:
**syntax:** unused import - `ChunkType` is imported but never used in this file

```suggestion
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +310 to +319
(typeof ctx.text === 'string' &&
!ctx.text.includes(
'The Termination Procedures are as follows'
)) &&
(typeof ctx.text === 'string' &&
!ctx.text.includes(
'# Git Workflow at ACME'
)) &&
// Score must be realistic (0-1 range)
ctx.score >= 0 &&
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

style: hardcoded strings like "The Termination Procedures" and "# Git Workflow at ACME" create brittle validation that breaks if these specific examples change - consider validating based on structural properties only (docId, score range, etc) without content-specific checks

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/workflows/governed-rag-answer.workflow.ts
Line: 310:319

Comment:
**style:** hardcoded strings like "The Termination Procedures" and "# Git Workflow at ACME" create brittle validation that breaks if these specific examples change - consider validating based on structural properties only (docId, score range, etc) without content-specific checks

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +50 to +51
const indexName: string =
process.env.QDRANT_COLLECTION ?? 'governed_rag'
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

syntax: mismatch between environment variable name and comment - reads QDRANT_COLLECTION but comment says "PgVector"

Suggested change
const indexName: string =
process.env.QDRANT_COLLECTION ?? 'governed_rag'
const indexName: string =
process.env.PG_INDEX_NAME ?? 'governed_rag'
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/workflows/governed-rag-index.workflow.ts
Line: 50:51

Comment:
**syntax:** mismatch between environment variable name and comment - reads `QDRANT_COLLECTION` but comment says "PgVector"

```suggestion
            const indexName: string =
                process.env.PG_INDEX_NAME ?? 'governed_rag'
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces governed RAG workflows, including indexing and answering processes. It adds new agents, services for authentication and tier management, and CLI commands to interact with these workflows. The changes also include significant updates to the chat UI to support new features like inline previews, code sandboxes, and task lists. My review focuses on improving type safety, fixing potential runtime errors, ensuring consistency, and addressing brittle implementation details. I've identified a critical issue with inconsistent embedding dimensions, several high-severity issues related to type safety and unsafe data handling, and medium-severity issues concerning code maintainability and correctness in streaming logic.

try {
await vectorStore.createIndex({
indexName,
dimension: 1568, // gemini-embedding-001 dimension (1568)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

There is a critical inconsistency in the embedding dimension used. Here, it's hardcoded to 1568 for gemini-embedding-001. However, in src/mastra/config/pg-storage.ts, the dimension for the same model is specified as 3072. This mismatch will cause vector storage and query operations to fail. This value should be consistent across the codebase, ideally defined as a shared constant.

Comment thread lib/a2a.ts

const researchResult =
researchResponse.result.status.message?.parts?.[0]?.kind === 'text'
? researchResponse.result.status.message.parts?.[0]?.text
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

There's a potential null pointer exception here. researchResponse.result.status.message can be undefined due to the optional chaining on line 111. However, on line 112, you are accessing message.parts without optional chaining (?). If message is undefined, this will throw a runtime error. You should use optional chaining here as well.

Suggested change
? researchResponse.result.status.message.parts?.[0]?.text
? researchResponse.result.status.message?.parts?.[0]?.text

Comment thread src/cli/index.ts
log.info(`Current usage: ${usage.documentsIndexed} documents indexed`)
}

const sampleDocs: any[] = [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Using any[] for sampleDocs and later for validDocs bypasses TypeScript's type safety. This can lead to hard-to-debug issues if the object structure is incorrect. It's highly recommended to define a specific interface or type for the document objects and use it here to ensure type safety and improve code clarity.

Suggested change
const sampleDocs: any[] = [
interface SampleDoc {
filePath: string;
docId: string;
classification: 'public' | 'internal' | 'confidential';
allowedRoles: string[];
tenant: string;
source: string;
}
const sampleDocs: SampleDoc[] = [

Comment thread src/cli/index.ts
Date.now() - startTime
)
// Log document results
const resultData = (result as any).result ?? result
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Casting result to any and then accessing properties ((result as any).result) is not type-safe. The workflow's output schema is defined, so you should use a proper type assertion or, even better, ensure the workflow execution function returns a strongly-typed result. This will prevent potential runtime errors and improve maintainability.

Comment on lines +229 to +248
} catch (validationError) {
const validationErrorInfo =
validationError instanceof Error
? {
message: validationError.message,
stack: validationError.stack,
}
: (() => {
try {
return { error: JSON.parse(JSON.stringify(validationError)) }
} catch {
return { error: String(validationError) }
}
})()
log.warn(
`[${requestId}] ⚠️ Schema validation failed, using raw contexts`,
validationErrorInfo
)
contexts = toolResultData.contexts
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

In the catch block for Zod validation, the code falls back to using the unvalidated toolResultData.contexts. This is risky as it bypasses the schema validation and could pass malformed data to subsequent steps, potentially causing runtime errors or unexpected behavior. If validation fails, it should ideally throw an error or the data should be sanitized, not used as is.

className="h-6 px-2 text-xs"
onClick={() =>
setInlinePreview({
id: (file as { id?: string }).id ?? `file-${idx}`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The type assertion (file as { id?: string }) is not type-safe and might lead to runtime errors if the file object shape changes. The FileUIPart type does not guarantee an id property. A safer approach would be to use a type guard or optional chaining with a check to ensure the property exists before accessing it.

                            id: 'id' in file && typeof (file as any).id === 'string' ? (file as any).id : `file-${idx}`,

Comment thread lib/a2a.ts
Comment on lines +49 to +54
if ('error' in response) {
throw new Error(response.error.message);
} else if ('messageId' in response.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
return;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The pattern for checking for an error and then for a messageId in the response is repeated multiple times in this file (lines 49-54, 103-108, 130-135). This duplicated logic increases maintenance overhead. Consider extracting this into a reusable helper function to handle the A2A response, which would make the main logic cleaner and more robust.

Comment on lines +231 to +253
private async loadUsageStats(
tenant: string,
tier: SubscriptionTier
): Promise<UsageStats> {
// Mock implementation - replace with database query
return {
tenant,
tier,
documentsIndexed: 0,
apiRequestsToday: 0,
totalUsers: 1,
lastReset: new Date(),
}
}

/**
* Persist usage stats to storage
* TODO: Implement database integration
*/
private async persistUsageStats(usage: UsageStats): Promise<void> {
// Mock implementation - replace with database update
log.debug('Persisting usage stats', { usage })
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The loadUsageStats and persistUsageStats methods have mock implementations and TODO comments indicating they are not yet integrated with a database. While this is acceptable for development, it's a critical missing piece for production functionality. This should be addressed before this feature is considered complete.

Comment on lines +50 to +51
const indexName: string =
process.env.QDRANT_COLLECTION ?? 'governed_rag'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The variable indexName is being initialized using an environment variable named QDRANT_COLLECTION, but the code is using pgVector. This is misleading and could cause configuration issues. The environment variable should be renamed to reflect its use with PostgreSQL/PgVector, for example, PG_VECTOR_INDEX_NAME.

Comment thread src/utils/streamUtils.ts
Comment on lines +112 to +116
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n\n'))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The way SSE events are terminated here is inconsistent with streamJSONEvent and technically incorrect. This implementation sends data: ...\n followed by \n\n, resulting in an extra newline (...\n\n\n). While many clients might tolerate this, it creates an extra empty comment line after each event. To be correct and consistent, you should send data: ...\n for each line and then a single \n to terminate the event, resulting in the standard ...\n\n terminator.

        const lines = chunk.split('\n')
        for (const line of lines) {
            streamController.enqueue(encoder.encode(`data: ${line}\n`))
        }
        // Terminate the event with a single extra newline to form a blank line.
        streamController.enqueue(encoder.encode(`\n`))

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 36

Caution

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

⚠️ Outside diff range comments (3)
app/chat/components/chat-messages.tsx (3)

36-106: Task import and extractTasksFromText helper look correct and robust

The new AgentTask/TaskStep imports and extractTasksFromText implementation correctly parse checklist-style sections, infer status from [x]/[-] markers, and generate stable IDs per section/step. The regex and sanitation steps are reasonable for expected assistant output.

If you expect very large responses, you might gate extractTasksFromText behind isAssistant at the call site (or add a cheap early check for keywords) to avoid unnecessary parsing on user messages. Otherwise this is good as-is.


202-271: Message-level content parsing, previews, sandbox, and parsed tasks wiring are sound

  • Using rawContent = textPart?.text ?? "" as a single source for artifact extraction, plan extraction, and task extraction simplifies downstream logic and keeps the toolbar CopyButton behavior consistent.
  • Inline preview (inlinePreview) and sandbox (sandboxPreview) state are kept local to MessageItem, and all usages are guarded (inlinePreview && …, sandboxPreview && …), so there are no hook order issues here.
  • Non-image attachment UI with “Preview” (using AgentWebPreview) and “Download” (via window.open) is straightforward and respects the existing file-part model.
  • The mutually exclusive reasoning/chain-of-thought display (hasChainOfThoughtSteps vs shouldShowReasoningFallback) is clear and matches the intended behavior.
  • Sandbox integration for the first code block and subsequent AgentCodeSandbox rendering are correctly guarded by codeBlocks.length > 0 and sandboxPreview.

You could slightly optimize by memoizing extractedTasks only when isAssistant && rawContent (e.g., useMemo(() => isAssistant ? extractTasksFromText(rawContent) : [], [isAssistant, rawContent])) since tasks are only rendered for assistant messages, but this is a minor perf nit.

Also applies to: 318-370, 373-379, 411-440, 451-458


515-575: Move hooks above the early return to fix rules-of-hooks violation in WebPreviewPanel

WebPreviewPanel calls useChatContext() at the top level, then has an early return before calling useCallback hooks. This means the hooks only execute on some renders (when preview is non-null), violating React's rules-of-hooks: the number and order of hooks changes between renders.

Move the early return to after all hooks, and move the preview check inside the handleCodeChange callback:

function WebPreviewPanel({ preview }: { preview: WebPreviewData | null }) {
  const { setWebPreview, agentConfig } = useChatContext()
-
-  if (!preview || !agentConfig?.features.webPreview) {return null}
-
   const handleCodeChange = useCallback(
     (newCode: string) => {
-      if (preview) {
+      if (!preview) { return }
       setWebPreview({
         ...preview,
         code: newCode,
       })
-      }
     },
     [preview, setWebPreview],
   )

   const handleClose = useCallback(() => {
     setWebPreview(null)
   }, [setWebPreview])
+
+  if (!preview || !agentConfig?.features.webPreview) {
+    return null
+  }

This keeps all hooks executing unconditionally in the same order on every render while preserving the existing behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd16286 and 8486bdc.

📒 Files selected for processing (16)
  • app/chat/components/chat-messages.tsx (14 hunks)
  • lib/a2a.ts (1 hunks)
  • package.json (1 hunks)
  • src/AGENTS.md (1 hunks)
  • src/cli/AGENTS.md (1 hunks)
  • src/cli/index.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/mastra/config/role-service.ts (1 hunks)
  • src/mastra/config/tier-management-service.ts (1 hunks)
  • src/mastra/workflows/governed-rag-answer.workflow.ts (1 hunks)
  • src/mastra/workflows/governed-rag-index.workflow.ts (1 hunks)
  • src/types.ts (1 hunks)
  • src/utils/AGENTS.md (1 hunks)
  • src/utils/streamUtils.test.ts (1 hunks)
  • src/utils/streamUtils.ts (1 hunks)
  • tsconfig.cli.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/instructions/next-js.instructions.md)

**/*.{js,jsx,ts,tsx}: Use next/dynamic for dynamic imports to load components only when needed, improving initial load time.
Use next/image component for automatic image optimization, including lazy loading and responsive images.
Use React.memo to prevent unnecessary re-renders of components.
Use the <Link prefetch> tag to prefetch pages that are likely to be visited.
Use getServerSideProps, getStaticProps, or server components for fetching data on the server-side.
Use SWR or React Query for client-side data fetching and caching.
Use CSS Modules, Styled Components, or Tailwind CSS for component-level styling. Prefer Tailwind CSS for rapid development.
Use React Context, Zustand, Jotai, or Recoil for managing global state. Avoid Redux unless necessary.
Use react-hook-form for managing forms and validation.
Only fetch the data that is needed by the component to avoid over-fetching.
Avoid long-running synchronous operations in the main thread to prevent blocking.
Always use setState or hooks to update state instead of mutating state directly.
Include a complete dependency array in useEffect hooks to prevent unexpected behavior.
Avoid writing server-side code in client components to prevent exposing secrets or causing unexpected behavior.
Use try...catch blocks for handling errors in asynchronous operations.
Implement error boundary components using getDerivedStateFromError or componentDidCatch lifecycle methods.
Sanitize user input to prevent Cross-Site Scripting (XSS) attacks. Be especially careful when rendering HTML directly from user input.
Store authentication tokens in HTTP-only cookies or local storage securely.
Implement role-based access control to restrict access to sensitive resources.
Clean up event listeners and timers in useEffect hooks to avoid memory leaks.
Only update state when necessary to reduce the number of re-renders and improve performance.
Use immutable data structures and avoid mutating data directly to prevent unexpected...

Files:

  • src/cli/index.ts
  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/config/role-service.ts
  • src/utils/streamUtils.ts
  • lib/a2a.ts
  • src/index.ts
  • src/types.ts
  • src/utils/streamUtils.test.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
  • src/mastra/config/tier-management-service.ts
  • app/chat/components/chat-messages.tsx
**/*.{js,ts}

📄 CodeRabbit inference engine (.github/instructions/next-js.instructions.md)

Use parameterized queries or an ORM to prevent SQL injection attacks.

Files:

  • src/cli/index.ts
  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/config/role-service.ts
  • src/utils/streamUtils.ts
  • lib/a2a.ts
  • src/index.ts
  • src/types.ts
  • src/utils/streamUtils.test.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
  • src/mastra/config/tier-management-service.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Never commit API keys or secrets to the repository; use maskSensitiveMessageData() helper from src/mastra/config/pg-storage.ts when logging

**/*.{ts,tsx}: Document interface and type definitions with TSDoc comments explaining their purpose and usage context
Document interface properties with /** */ comments explaining each field's purpose and constraints
Document generic type parameters with @template tags explaining what each type parameter represents
Use type guards with comments explaining the runtime validation logic being performed
Document advanced/complex TypeScript types with explanatory comments about their purpose and use cases

Files:

  • src/cli/index.ts
  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/config/role-service.ts
  • src/utils/streamUtils.ts
  • lib/a2a.ts
  • src/index.ts
  • src/types.ts
  • src/utils/streamUtils.test.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
  • src/mastra/config/tier-management-service.ts
  • app/chat/components/chat-messages.tsx
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Run eslint with --max-warnings=0 on src/**/*.{ts,tsx} to enforce linting standards

Files:

  • src/cli/index.ts
  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/config/role-service.ts
  • src/utils/streamUtils.ts
  • src/index.ts
  • src/types.ts
  • src/utils/streamUtils.test.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
  • src/mastra/config/tier-management-service.ts
**/*.{ts,tsx,js,jsx,py,java,cs,rb,go,rs,cpp,c,h,hpp,swift,kotlin,php,scala,clj,groovy,lua,sh,bash}

📄 CodeRabbit inference engine (.github/instructions/self-explanatory-code-commenting.instructions.md)

**/*.{ts,tsx,js,jsx,py,java,cs,rb,go,rs,cpp,c,h,hpp,swift,kotlin,php,scala,clj,groovy,lua,sh,bash}: Write code that speaks for itself. Comment only when necessary to explain WHY, not WHAT. Avoid obvious comments that state what the code literally does.
Avoid redundant comments that simply repeat what the code is doing
Keep comments accurate and up-to-date with code changes. Remove or update outdated comments that no longer match the implementation.
Write comments for complex business logic that explain the WHY behind specific calculations or business rules
Document non-obvious algorithms with comments explaining the algorithm choice and its reasoning
Add comments explaining what regex patterns match, especially for complex patterns
Document API constraints, rate limits, gotchas, and external dependencies with explanatory comments
Avoid commenting out dead code. Use version control instead of maintaining commented code blocks.
Do not maintain code change history or modification logs as comments. Rely on git history and commit messages instead.
Avoid decorative divider comments (e.g., lines of equals signs or asterisks) for section separation
Ensure comments are placed appropriately above or adjacent to the code they describe
Write comments using proper grammar, spelling, and professional language
Prefer self-documenting code with clear variable/function names over adding comments to explain unclear code

Files:

  • src/cli/index.ts
  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/config/role-service.ts
  • src/utils/streamUtils.ts
  • lib/a2a.ts
  • src/index.ts
  • src/types.ts
  • src/utils/streamUtils.test.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
  • src/mastra/config/tier-management-service.ts
  • app/chat/components/chat-messages.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/instructions/self-explanatory-code-commenting.instructions.md)

**/*.{ts,tsx,js,jsx}: Document public APIs with TSDoc/JSDoc comments including parameter descriptions, return types, examples, and thrown exceptions
Add TSDoc comments to configuration constants and environment variables explaining their source, reasoning, or constraints
Use TSDoc annotation tags (TODO, FIXME, HACK, NOTE, WARNING, PERF, SECURITY, BUG, REFACTOR, DEPRECATED) to mark special comments
Include file headers with @fileoverview, @author, @copyright, and @license tags to document file purpose and ownership
Document function parameters with @param tags, return values with @returns tags, and exceptions with @throws tags in TSDoc comments
Use @see tags in TSDoc comments to reference related functions, methods, or documentation
Include @example tags in public API documentation with code examples showing typical usage

Files:

  • src/cli/index.ts
  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/config/role-service.ts
  • src/utils/streamUtils.ts
  • lib/a2a.ts
  • src/index.ts
  • src/types.ts
  • src/utils/streamUtils.test.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
  • src/mastra/config/tier-management-service.ts
  • app/chat/components/chat-messages.tsx
**/*.md

📄 CodeRabbit inference engine (.github/instructions/markdown.instructions.md)

**/*.md: Use appropriate heading levels (H2, H3, etc.) to structure markdown content. Do not use H1 headings, as these will be generated from the title. Use ## for H2 and ### for H3 in a hierarchical manner. Recommend restructuring if content includes H4 or higher levels.
Use bullet points (with -) or numbered lists (with 1.) for lists in markdown. Indent nested lists with two spaces and ensure proper indentation and spacing.
Use fenced code blocks (triple backticks) for code snippets in markdown. Specify the language after the opening backticks for syntax highlighting (e.g., csharp).
Use proper markdown syntax for links: [link text](URL). Ensure that link text is descriptive and URLs are valid and accessible.
Use proper markdown syntax for images: ![alt text](image URL). Include a brief description of the image in the alt text for accessibility.
Use markdown tables (with | delimiters) for tabular data. Ensure proper formatting, alignment, and inclusion of headers.
Limit line length to 80 characters in markdown for readability. Use soft line breaks for long paragraphs.
Use appropriate whitespace in markdown to separate sections and improve readability. Use blank lines between sections and avoid excessive whitespace.
Include YAML front matter at the beginning of markdown files with required metadata fields: post_title, author1, post_slug, microsoft_alias, featured_image, categories (from /categories.txt), tags, ai_note, summary, and post_date.

Files:

  • src/AGENTS.md
  • src/cli/AGENTS.md
  • src/utils/AGENTS.md
src/mastra/{tools,workflows}/**/*.ts

📄 CodeRabbit inference engine (src/mastra/AGENTS.md)

Use RuntimeContext to enforce access control in tools and workflows

Files:

  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
src/mastra/workflows/**/*.ts

📄 CodeRabbit inference engine (src/mastra/AGENTS.md)

Add new workflow definitions under src/mastra/workflows to orchestrate multi-step flows

Use Mastra DSL for multi-step workflow definitions in src/mastra/workflows

Files:

  • src/mastra/workflows/governed-rag-index.workflow.ts
  • src/mastra/workflows/governed-rag-answer.workflow.ts
src/mastra/config/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/mastra/config/**/*.ts: Centralize provider clients (Google, OpenAI, Anthropic, OpenRouter) and storage configuration in src/mastra/config
Use pg-storage with PgVector for vector store functionality in the configuration
Use src/mastra/config for role hierarchy and provider client configuration

Files:

  • src/mastra/config/role-service.ts
  • src/mastra/config/tier-management-service.ts
**/types.{ts,tsx}

📄 CodeRabbit inference engine (.github/instructions/next-js.instructions.md)

Organize TypeScript type definitions and interfaces in types.ts or interfaces.ts files.

Files:

  • src/types.ts
**/*.test.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/instructions/next-js.instructions.md)

**/*.test.{js,jsx,ts,tsx}: Write unit tests for individual components to ensure they are working correctly.
Use React Testing Library for component testing to encourage testing from a user perspective.
Mock external dependencies to isolate components during testing.
Use Jest or Mocha as a testing framework for unit and integration tests.
Use Mock Service Worker (msw) to intercept and mock API calls during testing.
Co-locate test files with components using a consistent naming convention (e.g., ComponentName.test.js).
Test edge cases and error conditions to ensure components are robust.

Files:

  • src/utils/streamUtils.test.ts
**/*.test.ts?(x)

📄 CodeRabbit inference engine (AGENTS.md)

Use Vitest for all unit testing in the Mastra project

Files:

  • src/utils/streamUtils.test.ts
**/app/**

📄 CodeRabbit inference engine (.github/instructions/next-js.instructions.md)

Use the app/ directory structure for route handlers, server components, and client components (Next.js 13+). Prefer this over the pages/ directory for new projects.

Files:

  • app/chat/components/chat-messages.tsx
**/components/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.github/instructions/next-js.instructions.md)

Use PascalCase for component file names (e.g., ComponentName.jsx or ComponentName.tsx).

Files:

  • app/chat/components/chat-messages.tsx
app/**/*.{tsx,ts}

📄 CodeRabbit inference engine (app/AGENTS.md)

app/**/*.{tsx,ts}: Use Tailwind CSS 4 with oklch color variables for styling in Next.js App Router pages and layouts
Use React 19 latest features in component implementations within the app directory

Files:

  • app/chat/components/chat-messages.tsx
app/chat/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (app/chat/AGENTS.md)

app/chat/components/**/*.{ts,tsx}: Use AI SDK v5 types and patterns in chat components: import types like UIMessage, DynamicToolUIPart, TextUIPart, ReasoningUIPart from 'ai' and use type guard functions like isTextUIPart, isReasoningUIPart, isToolOrDynamicToolUIPart to filter message parts
Access message content through message.parts array using type guards rather than message.content, extracting specific parts like text using const textPart = message.parts?.find(isTextUIPart)
Handle Mastra stream chunk types correctly: use 'text-delta' for streaming text, 'reasoning-delta' for streaming reasoning (NOT 'reasoning'), 'tool-call' for tool invocation, 'tool-result' for tool completion, 'source' for research sources, and 'finish' for completion with usage data
Use AI Elements components (Conversation, Message, PromptInput, ModelSelector, Reasoning, Tool, Sources, Artifact) from the AI Elements library in their respective chat component files as specified in the architecture

Files:

  • app/chat/components/chat-messages.tsx
app/chat/components/chat-messages.tsx

📄 CodeRabbit inference engine (app/chat/AGENTS.md)

Implement ChatMessages component to display message list with streaming support, using Conversation and Message AI Elements components with proper handling of different message types

Files:

  • app/chat/components/chat-messages.tsx
app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Next.js 16 App Router with React 19 for frontend development in the app/ directory

Files:

  • app/chat/components/chat-messages.tsx
{app,ui,src/components}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Tailwind CSS 4 with oklch color variables for styling in UI components

Files:

  • app/chat/components/chat-messages.tsx
{app,src/components}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

{app,src/components}/**/*.{ts,tsx}: Use shadcn/ui base components (34 components) located in ui/ directory for common UI elements
Use AI Elements library (30 components) from src/components/ai-elements/ for chat, reasoning, and canvas UIs

Files:

  • app/chat/components/chat-messages.tsx
🧬 Code graph analysis (5)
src/mastra/workflows/governed-rag-index.workflow.ts (2)
src/mastra/config/logger.ts (4)
  • logStepStart (72-88)
  • logProgress (176-197)
  • logStepEnd (90-109)
  • logError (153-174)
src/mastra/config/pg-storage.ts (1)
  • pgVector (81-87)
src/mastra/config/role-service.ts (2)
src/mastra/config/role-hierarchy.ts (4)
  • isValidRole (80-82)
  • ROLE_HIERARCHY (16-36)
  • getRoleLevel (73-75)
  • getInheritorRoles (103-113)
src/mastra/config/logger.ts (1)
  • log (14-18)
src/utils/streamUtils.test.ts (1)
src/utils/streamUtils.ts (4)
  • createSSEStream (13-48)
  • streamProgressUpdate (57-69)
  • streamJSONEvent (78-84)
  • handleTextStream (100-120)
src/mastra/workflows/governed-rag-answer.workflow.ts (1)
src/mastra/config/logger.ts (5)
  • logStepStart (72-88)
  • logStepEnd (90-109)
  • logError (153-174)
  • log (14-18)
  • logAgentActivity (132-151)
src/mastra/config/tier-management-service.ts (2)
src/mastra/config/role-hierarchy.ts (1)
  • SubscriptionTier (8-8)
src/mastra/config/logger.ts (1)
  • log (14-18)
🪛 Biome (2.1.2)
app/chat/components/chat-messages.tsx

[error] 520-520: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 529-529: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

Hooks should not be called after an early return.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

⏰ 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). (2)
  • GitHub Check: Agent
  • GitHub Check: Codacy Security Scan
🔇 Additional comments (23)
src/AGENTS.md (1)

1-59: Documentation structure looks good.

The AGENTS.md file provides clear architectural guidance with well-organized sections covering persona, scope, key files, data flow, and dependency rules. The dependency rules table (lines 48-53) effectively documents module boundaries.

package.json (1)

22-22: LGTM on the format script update.

Adding dotenvx run prefix to the format script aligns with other scripts that use environment variables.

lib/a2a.ts (1)

1-152: Overall structure is good for a demo file.

The A2A example demonstrates a clear multi-step workflow with proper error handling via try/catch. The eslint-disable for console is appropriate for this demonstration code.

src/mastra/config/role-service.ts (3)

9-44: Well-implemented role expansion with proper fallback handling.

The expandRoles method correctly handles the role hierarchy lookup with nullish coalescing (line 29), preserves unknown roles for backward compatibility, and sorts by privilege level. The warning log for unknown roles is appropriate.


103-112: Good defensive handling of tenant parameter.

The explicit check for string type and trimmed empty string handling with a warning log is thorough and prevents edge cases from creating invalid tags.


1-197: RoleService implementation is well-structured.

The service provides a comprehensive API for role-based access control with proper TSDoc documentation, logging for edge cases, and consistent return types. The static method pattern is appropriate for stateless utility operations.

src/mastra/config/tier-management-service.ts (4)

1-16: LGTM!

The file header documentation clearly describes the module's purpose. Imports are correctly sourced from the local config modules.


17-33: LGTM!

The UsageStats and TierValidationResult interfaces are well-defined with clear property names and appropriate optional fields.


215-225: Edge case: lastReset in the future causes immediate reset.

If lastReset is accidentally set to a future date, needsDailyReset returns true immediately (since lastReset > resetTime is false but the comparison lastReset < resetTime will be true). This is likely correct behavior, but consider adding a guard or logging for anomalous dates.


258-280: LGTM!

The percentage calculation correctly handles unlimited quotas (-1) by returning 0.

src/index.ts (1)

1-2: LGTM!

Clean barrel exports for the package entry point, properly exposing the Mastra module and types.

src/mastra/workflows/governed-rag-index.workflow.ts (1)

1-14: LGTM!

Imports are well-organized and correctly sourced from local config and services.

src/cli/index.ts (1)

281-286: LGTM!

Entry point correctly guards with require.main === module and handles fatal errors with process.exit(1).

src/mastra/workflows/governed-rag-answer.workflow.ts (5)

31-77: LGTM!

The authentication step is well-structured with proper schema validation, logging, and error handling.


359-407: Good fallback behavior on rerank failure.

The reranking step properly falls back to original contexts if reranking fails, with appropriate logging. This is a robust pattern.


420-492: LGTM!

The answer generation step has proper schema validation, sensible defaults for empty contexts, and comprehensive error handling.


543-567: Good handling of "insufficient evidence" edge case.

The verification step correctly identifies and passes through answers that indicate no authorized documents were found, rather than failing verification.


601-624: LGTM!

The workflow composition is clean and follows the expected pattern with proper chaining of steps.

src/utils/streamUtils.test.ts (1)

1-371: Comprehensive test coverage for streaming utilities.

The test suite is well-structured and covers all exported functions with good edge case handling (empty streams, special characters, multi-line content). The use of Vitest aligns with the coding guidelines, and the integration test validates a realistic end-to-end workflow.

src/utils/streamUtils.ts (3)

13-48: LGTM!

The SSE stream creation is well-implemented with proper error handling, completion signaling, and correct headers. The try-catch-finally pattern ensures the controller is always closed.


57-69: LGTM!

The progress update event is correctly formatted as SSE data with proper JSON payload structure.


78-84: LGTM!

Generic typing provides good flexibility. Note that JSON.stringify could throw on circular references, but this would be caught by createSSEStream's error handler.

app/chat/components/chat-messages.tsx (1)

619-630: Streaming reasoning / chain-of-thought and WebPreviewPanel wiring look correct

  • streamingReasoningSteps is memoized from streamingReasoning and reuses parseReasoningToSteps, mirroring the per-message behavior.
  • hasStreamingChainOfThought and shouldShowStreamingReasoningFallback are correctly derived and ensure only one of AgentChainOfThought or AgentReasoning is shown during streaming, aligned with the static rendering logic.
  • Passing webPreview down as a preview prop into WebPreviewPanel centralizes web preview handling cleanly in one place.

Also applies to: 661-661, 687-693

Comment thread lib/a2a.ts
Comment on lines +51 to +54
} else if ('messageId' in response.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Silent early return may confuse users.

When the A2A implementation returns a task instead of a message, the script exits silently without any indication of what happened. Consider adding a log message before returning to improve debugging experience.

     } else if ('messageId' in response.result) {
       // Mastra's current A2A implementation will always return a task, rather than a message
+      console.log('ℹ️  Received task response (not a message). A2A task-based flow not demonstrated in this example.');
       return;
     }
📝 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
} else if ('messageId' in response.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
return;
}
} else if ('messageId' in response.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
console.log('ℹ️ Received task response (not a message). A2A task-based flow not demonstrated in this example.');
return;
}
🤖 Prompt for AI Agents
In lib/a2a.ts around lines 51–54, the function silently returns when
response.result contains messageId (Mastra returns a task not a message); add a
log statement right before the return (e.g., processLogger.warn or console.warn
depending on existing logger) that clearly states we received a task instead of
a message and include relevant details from response.result (like messageId and
any task metadata) to aid debugging, then keep the early return behavior.

Comment thread lib/a2a.ts
Comment on lines +105 to +108
} else if ('messageId' in researchResponse.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add logging for silent early return.

Same issue as above - the silent return provides no feedback to the user.

     } else if ('messageId' in researchResponse.result) {
       // Mastra's current A2A implementation will always return a task, rather than a message
+      console.log('ℹ️  Research step returned task response. Exiting example.');
       return;
     }
🤖 Prompt for AI Agents
In lib/a2a.ts around lines 105-108, the branch that returns early when
'messageId' exists in researchResponse.result is silent; add a log statement
before the return to surface this condition (e.g., use the module's logger or
console.warn/info) including relevant context such as messageId and any request
or task identifiers so callers can see why processing stopped; keep the log
level appropriate (warn/info) and include enough details to correlate to the
originating request.

Comment thread lib/a2a.ts
Comment on lines +132 to +135
} else if ('messageId' in contentResponse.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add logging for silent early return.

Same issue - add user feedback before exiting.

     } else if ('messageId' in contentResponse.result) {
       // Mastra's current A2A implementation will always return a task, rather than a message
+      console.log('ℹ️  Content step returned task response. Exiting example.');
       return;
     }
📝 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
} else if ('messageId' in contentResponse.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
return;
}
} else if ('messageId' in contentResponse.result) {
// Mastra's current A2A implementation will always return a task, rather than a message
console.log('ℹ️ Content step returned task response. Exiting example.');
return;
}
🤖 Prompt for AI Agents
In lib/a2a.ts around lines 132–135 the function returns silently when
contentResponse.result contains a messageId; add a log statement immediately
before the return to surface this early-exit (include the fact of an A2A
messageId-based response and any non-sensitive identifiers such as messageId,
taskId or requestId available on contentResponse/result), using the module's
existing logger (or console.warn if none) and avoid printing full sensitive
payloads so callers get feedback instead of a silent no-op.

Comment thread package.json
Comment on lines +23 to +25
"build-cli": "tsc -p tsconfig.cli.json",
"cli": "node dist/index.js",
"generate-index": "node dist/cli/index.js"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the actual CLI entrypoint structure

# Find all index.ts files
echo "=== All index.ts files ==="
find . -name "index.ts" -type f 2>/dev/null | sort

# Check src/cli/index.ts if it exists
echo -e "\n=== src/cli/index.ts (first 40 lines) ==="
if [ -f "src/cli/index.ts" ]; then
  cat -n src/cli/index.ts | head -40
else
  echo "File not found"
fi

# Check src/index.ts
echo -e "\n=== src/index.ts (first 40 lines) ==="
if [ -f "src/index.ts" ]; then
  cat -n src/index.ts | head -40
else
  echo "File not found"
fi

# Check if dist/cli/index.js exists
echo -e "\n=== Checking dist structure (relevant to runtime) ==="
if [ -d "dist/cli" ]; then
  echo "dist/cli/ exists"
  ls -la dist/cli/ 2>/dev/null | head -10
fi

if [ -f "dist/index.js" ]; then
  echo "dist/index.js exists"
fi

Repository: ssdeanx/AgentStack

Length of output: 2234


Fix the cli script to point to the correct CLI entry point.

The cli script points to dist/index.js, which is the library export file containing only re-exports. The actual CLI entry point is src/cli/index.ts with CLI-specific logic (document indexing, logging, tier validation). Change cli to "node dist/cli/index.js" to match the generate-index script and execute the correct entry point.

🤖 Prompt for AI Agents
In package.json around lines 23 to 25, the "cli" npm script incorrectly points
to "dist/index.js" (the library re-exports) instead of the actual CLI bundle;
update the "cli" script to use "node dist/cli/index.js" so it executes the CLI
entry point (matching the "generate-index" script) and runs the CLI-specific
logic.

Comment thread src/AGENTS.md
@@ -0,0 +1,60 @@
<!-- AGENTS-META {"title":"Backend Source Root","version":"1.1.0","last_updated":"2025-10-08T08:00:26Z","applies_to":"/src","tags":["layer:backend","domain:rag","type:source","status:stable"],"status":"stable"} -->

# Source Root (`/src`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use H2 instead of H1 heading.

Per coding guidelines, H1 headings should not be used as they will be generated from the title. Change this to an H2 heading.

-# Source Root (`/src`)
+## Source Root (`/src`)
📝 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
# Source Root (`/src`)
## Source Root (`/src`)
🤖 Prompt for AI Agents
In src/AGENTS.md around line 3, the document uses an H1 heading ("# Source Root
(`/src`)") but coding guidelines require H2 headings; change the leading '#' to
'##' so the heading becomes H2 ("## Source Root (`/src`)") and ensure no other
H1 headings are present in this file.

Comment thread src/utils/AGENTS.md
@@ -0,0 +1,35 @@
<!-- AGENTS-META {"title":"Backend Utility Layer","version":"1.1.0","last_updated":"2025-10-08T08:00:26Z","applies_to":"/src/utils","tags":["layer:backend","domain:shared","type:utilities","status":"stable"],"status":"stable"} -->

# Utilities Directory (`/src/utils`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Use H2 instead of H1 heading.

Per coding guidelines, H1 headings should not be used. Change to H2.

-# Utilities Directory (`/src/utils`)
+## Utilities Directory (`/src/utils`)
📝 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
# Utilities Directory (`/src/utils`)
## Utilities Directory (`/src/utils`)
🤖 Prompt for AI Agents
In src/utils/AGENTS.md around line 3, the top-level H1 heading "# Utilities
Directory (`/src/utils`)" should be changed to an H2 per project guidelines;
edit the heading to use "## Utilities Directory (`/src/utils`)" (or equivalent
H2 syntax) and save the file so no H1 headings remain.

Comment thread src/utils/AGENTS.md
Comment on lines +7 to +8
**Name:** `{utils_persona_name}` = "Core Library Developer"
**Role:** "I create pure, dependency-light building blocks that any backend or API module can import without triggering circular references or side-effects."
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider replacing the template placeholder.

The {utils_persona_name} appears to be an unreplaced template variable. If this is intentional documentation of a pattern, consider adding a note clarifying this; otherwise, replace it with an actual value like the other AGENTS.md files.

🤖 Prompt for AI Agents
In src/utils/AGENTS.md around lines 7 to 8, the Name field uses an unreplaced
template variable `{utils_persona_name}`; replace the placeholder with the
actual persona name (e.g., Name: "Core Library Developer") so it matches the
Role line, or if the template is intentional add a short clarifying note
immediately below explaining this is a template variable and how to replace it
in derived files; ensure the final text uses plain literal names (no braces)
unless documenting the templating pattern.

Comment thread src/utils/streamUtils.ts
Comment on lines +71 to +84
/**
* Emit any JSON object as a data event.
* Used for actions, tool responses, custom events, etc.
*
* @param controller - The stream controller to enqueue the event to
* @param eventData - The event data to serialize and send
*/
export function streamJSONEvent<T>(
controller: ReadableStreamDefaultController<Uint8Array>,
eventData: T
): void {
const encoder = new TextEncoder()
controller.enqueue(encoder.encode(`data: ${JSON.stringify(eventData)}\n\n`))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding @template tag for the generic type parameter.

Per coding guidelines, generic type parameters should be documented with @template tags explaining what each type parameter represents.

 /**
  * Emit any JSON object as a data event.
  * Used for actions, tool responses, custom events, etc.
  *
  * @param controller - The stream controller to enqueue the event to
  * @param eventData - The event data to serialize and send
+ * @template T - The type of event data to serialize (must be JSON-serializable)
  */
 export function streamJSONEvent<T>(
📝 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
/**
* Emit any JSON object as a data event.
* Used for actions, tool responses, custom events, etc.
*
* @param controller - The stream controller to enqueue the event to
* @param eventData - The event data to serialize and send
*/
export function streamJSONEvent<T>(
controller: ReadableStreamDefaultController<Uint8Array>,
eventData: T
): void {
const encoder = new TextEncoder()
controller.enqueue(encoder.encode(`data: ${JSON.stringify(eventData)}\n\n`))
}
/**
* Emit any JSON object as a data event.
* Used for actions, tool responses, custom events, etc.
*
* @param controller - The stream controller to enqueue the event to
* @param eventData - The event data to serialize and send
* @template T - The type of event data to serialize (must be JSON-serializable)
*/
export function streamJSONEvent<T>(
controller: ReadableStreamDefaultController<Uint8Array>,
eventData: T
): void {
const encoder = new TextEncoder()
controller.enqueue(encoder.encode(`data: ${JSON.stringify(eventData)}\n\n`))
}
🤖 Prompt for AI Agents
In src/utils/streamUtils.ts around lines 71 to 84, the JSDoc for streamJSONEvent
is missing a @template tag for the generic type parameter T; add a @template T
line to the comment describing what T represents (e.g., "T - type of the event
data to be serialized and sent"), so the generic is documented per guidelines
and tools that consume JSDoc will show the generic's meaning.

Comment thread src/utils/streamUtils.ts
Comment on lines +109 to +117
// Stream raw text chunks through data field
for await (const chunk of streamResult.textStream) {
chunks.push(chunk)
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n\n'))
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Extra newline in SSE event termination.

The current implementation produces an extra newline in the SSE output. Each data: line already ends with \n, so only one additional \n is needed to terminate the event (creating the required blank line), not two.

For a chunk like 'Hello':

  • Current output: data: Hello\n\n\n (3 newlines)
  • Correct SSE format: data: Hello\n\n (2 newlines)

Most SSE parsers tolerate this, but it's technically non-compliant with the SSE specification.

     for await (const chunk of streamResult.textStream) {
         chunks.push(chunk)
         const lines = chunk.split('\n')
         for (const line of lines) {
             streamController.enqueue(encoder.encode(`data: ${line}\n`))
         }
-        streamController.enqueue(encoder.encode('\n\n'))
+        streamController.enqueue(encoder.encode('\n'))
     }
📝 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
// Stream raw text chunks through data field
for await (const chunk of streamResult.textStream) {
chunks.push(chunk)
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n\n'))
}
// Stream raw text chunks through data field
for await (const chunk of streamResult.textStream) {
chunks.push(chunk)
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n'))
}
🤖 Prompt for AI Agents
In src/utils/streamUtils.ts around lines 109 to 117, the SSE event termination
writes an extra newline: each `data:` line already ends with `\n`, but the code
enqueues an additional `\n\n` after lines producing a total of three newlines
per event; change the final enqueue to a single `\n` (so the event ends with one
blank line total) by removing one of the newlines when enqueueing the event
terminator to produce `data: ...\n\n` instead of `data: ...\n\n\n`.

Comment thread tsconfig.cli.json
Comment on lines +1 to +12
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "dist",
"jsx": "react",
"module": "commonjs",
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "app/**/*", "components/**/*", ".next/**/*"]
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider removing unnecessary jsx setting for CLI builds.

The CLI code in src/cli/index.ts doesn't appear to use JSX. Setting "jsx": "react" is harmless but adds unnecessary configuration. If the CLI will never use JSX, consider removing this option.

     "compilerOptions": {
         "noEmit": false,
         "outDir": "dist",
-        "jsx": "react",
         "module": "commonjs",
         "moduleResolution": "node"
     },
📝 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
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "dist",
"jsx": "react",
"module": "commonjs",
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "app/**/*", "components/**/*", ".next/**/*"]
}
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"outDir": "dist",
"module": "commonjs",
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "app/**/*", "components/**/*", ".next/**/*"]
}
🤖 Prompt for AI Agents
In tsconfig.cli.json lines 1-12, the "jsx": "react" compilerOption is
unnecessary for a CLI build; remove the "jsx" entry from the "compilerOptions"
object (or omit it entirely) so the CLI tsconfig uses the default non-JSX
behavior, then run the CLI TypeScript build to verify no breakages.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a comprehensive governed RAG (Retrieval-Augmented Generation) system with multi-agent workflows, role-based access control, subscription tier management, and document indexing capabilities. The implementation includes server-sent event streaming utilities, CLI tooling for operations, and comprehensive test coverage for streaming functionality.

Key Changes

  • Multi-agent RAG workflows: Implements authentication → retrieval+rerank → answer generation → verification pipeline with security-first design
  • Document indexing system: Adds workflow for indexing documents with security tags, classifications, and role-based access controls using PgVector
  • Streaming utilities: Provides reusable SSE streaming helpers for progress updates, JSON events, and text streaming with comprehensive test coverage

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 24 comments.

Show a summary per file
File Description
tsconfig.cli.json New TypeScript configuration for CLI builds with CommonJS output
package.json Added CLI build and execution scripts
src/types.ts Defines core type interfaces for Principal, AccessFilter, Document, and Chunk
src/index.ts Exports public API for mastra instance and types
src/utils/streamUtils.ts SSE streaming utilities for data-only format with progress updates and JSON events
src/utils/streamUtils.test.ts Comprehensive test suite covering SSE stream creation, progress updates, JSON events, and text streaming
src/utils/AGENTS.md Documentation for utilities directory structure and streaming patterns
src/mastra/workflows/governed-rag-index.workflow.ts Document indexing workflow with security tags and PgVector integration
src/mastra/workflows/governed-rag-answer.workflow.ts Multi-step RAG answer workflow with authentication, retrieval, reranking, answer generation, and verification
src/mastra/config/tier-management-service.ts Subscription tier validation, quota enforcement, and usage tracking service
src/mastra/config/role-service.ts Role hierarchy management with role expansion and access control logic
src/cli/index.ts CLI entry point with commands for indexing, querying, and usage monitoring
src/cli/AGENTS.md CLI documentation describing command surface and execution flow
src/AGENTS.md Source root documentation outlining modular boundaries and dependency rules
lib/a2a.ts Example implementation of agent-to-agent communication protocol
app/chat/components/chat-messages.tsx UI enhancements for task parsing, file previews, and reasoning display
Comments suppressed due to low confidence (9)

src/cli/index.ts:47

  • Unexpected any. Specify a different type.
    const sampleDocs: any[] = [

src/cli/index.ts:77

  • Unexpected any. Specify a different type.
    const validDocs: any[] = []

src/cli/index.ts:108

  • Unexpected any. Specify a different type.
            result as any,

src/cli/index.ts:112

  • Unexpected any. Specify a different type.
        const resultData = (result as any).result ?? result

src/cli/index.ts:115

  • Unexpected any. Specify a different type.
            resultData.documents.forEach((doc: any) => {

src/cli/index.ts:176

  • Unexpected any. Specify a different type.
            const resultData = (result as any).result ?? result

src/cli/index.ts:196

  • Unexpected any. Specify a different type.
                resultData.citations.forEach((citation: any) => {

src/mastra/workflows/governed-rag-answer.workflow.ts:20

  • Unused imports jwtClaimsSchema, verificationResultSchema.
import {
    jwtClaimsSchema,
    accessFilterSchema,
    documentContextSchema,
    ragAnswerSchema,
    verificationResultSchema,
} from '../schemas/agent-schemas'

src/mastra/workflows/governed-rag-answer.workflow.ts:23

  • Unused import ChunkType.
import { ChunkType } from '@mastra/core/stream';

Comment thread src/utils/streamUtils.ts
Comment on lines +109 to +116
// Stream raw text chunks through data field
for await (const chunk of streamResult.textStream) {
chunks.push(chunk)
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n\n'))
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The code splits chunks by newlines and sends each line as a separate SSE data event without any sanitization. If the chunk contains content that could be interpreted as SSE control sequences (e.g., lines starting with "event:", "data:", or "id:"), this could cause protocol confusion or injection issues. Consider sanitizing or escaping the content before sending it through the SSE stream, or use a more robust encoding method.

Suggested change
// Stream raw text chunks through data field
for await (const chunk of streamResult.textStream) {
chunks.push(chunk)
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n\n'))
// Stream raw text chunks through data field, JSON-encoded to prevent SSE injection
for await (const chunk of streamResult.textStream) {
chunks.push(chunk)
streamController.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`))

Copilot uses AI. Check for mistakes.
Comment thread src/utils/streamUtils.ts
Comment on lines +112 to +116
const lines = chunk.split('\n')
for (const line of lines) {
streamController.enqueue(encoder.encode(`data: ${line}\n`))
}
streamController.enqueue(encoder.encode('\n\n'))
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The comment "Stream raw text chunks through data field" doesn't fully explain the unusual behavior of splitting chunks by newlines and sending each line separately, followed by an empty line. This non-standard approach to streaming text could be confusing to maintainers. Consider adding more detailed documentation explaining why this split-by-newline approach is used and how clients should reassemble the text.

Copilot uses AI. Check for mistakes.
Comment on lines +165 to +179
const possibleToolNames = [
'pgQuery',
'pgQueryTool',
'vectorQueryTool',
'vector-query',
'vectorQuery',
'pgQueryTool',
'pg-query',
'graphQueryTool',
'graph-query',
'graphQuery',
'textQueryTool',
'text-query',
'textQuery',
]
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The list of possible tool names (lines 165-179) contains duplicate entries: 'pgQueryTool' appears twice (lines 167 and 171). This duplication is unnecessary and should be removed to improve code clarity and maintainability.

Copilot uses AI. Check for mistakes.
title: preview.title,
}}
onClose={handleClose}
// onCodeChange={handleCodeChange}
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Another instance of commented-out code (// onCodeChange={handleCodeChange}). This should be removed to keep the codebase clean and maintainable.

Suggested change
// onCodeChange={handleCodeChange}

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +28
// Use nullish coalescing to avoid treating empty arrays as falsy
// and to satisfy linters that warn about object values in boolean conditionals.
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

The comment explaining the use of nullish coalescing (lines 27-28) is overly detailed for a straightforward operation. While it's good to document why you're using ?? instead of ||, this level of explanation is excessive for standard TypeScript patterns. Consider simplifying to just "// Get inherited roles, defaulting to empty array" or remove the comment entirely as the code is self-explanatory.

Suggested change
// Use nullish coalescing to avoid treating empty arrays as falsy
// and to satisfy linters that warn about object values in boolean conditionals.

Copilot uses AI. Check for mistakes.
} from '../schemas/agent-schemas'
import { AuthenticationService } from '../services/AuthenticationService'
import { log } from '../config/logger'
import { ChunkType } from '@mastra/core/stream';
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

'ChunkType' is defined but never used.

Suggested change
import { ChunkType } from '@mastra/core/stream';

Copilot uses AI. Check for mistakes.
tenant: string,
tier: SubscriptionTier,
operationType: 'document' | 'api_request' | 'user'
): Promise<TierValidationResult> {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Callee is not a function: it has type undefined.

Suggested change
): Promise<TierValidationResult> {
): Promise<TierValidationResult> {
if (typeof getTierQuota !== 'function') {
throw new Error('getTierQuota is not a function. Check the import from ../config/role-hierarchy.');
}

Copilot uses AI. Check for mistakes.
tier: SubscriptionTier,
feature: string
): TierValidationResult {
const allowed = isTierFeatureEnabled(tier, feature)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Callee is not a function: it has type undefined.

Suggested change
const allowed = isTierFeatureEnabled(tier, feature)
let allowed: boolean
if (typeof isTierFeatureEnabled === 'function') {
allowed = isTierFeatureEnabled(tier, feature)
} else {
log.error?.(
"isTierFeatureEnabled is not a function (got: %s). Feature access validation failed for tier: %s, feature: %s",
typeof isTierFeatureEnabled,
tier,
feature
)
return {
allowed: false,
tier,
reason: "Feature access validation is not available due to a configuration error.",
upgradeRequired: false,
}
}

Copilot uses AI. Check for mistakes.
tier: SubscriptionTier,
classification: 'public' | 'internal' | 'confidential'
): TierValidationResult {
const minimumTier = getMinimumTierForClassification(classification)
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Callee is not a function: it has type undefined.

Copilot uses AI. Check for mistakes.
documents: number
apiRequests: number
users: number
} {
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

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

Callee is not a function: it has type undefined.

Suggested change
} {
} {
if (typeof getTierQuota !== 'function') {
throw new Error('getTierQuota is not a function. Check the import from ../config/role-hierarchy.');
}

Copilot uses AI. Check for mistakes.
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