Skip to content

feat: Update role hierarchy and subscription tier configurations#23

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

feat: Update role hierarchy and subscription tier configurations#23
ssdeanx merged 1 commit intomainfrom
develop

Conversation

@ssdeanx
Copy link
Copy Markdown
Owner

@ssdeanx ssdeanx commented Dec 8, 2025

  • Refactored role hierarchy to align with Supabase Auth and RLS, simplifying role definitions and inheritance.
  • Introduced new roles: 'service_role', 'moderator', and updated existing roles to streamline access control.
  • Revised subscription tiers to include 'free', 'pro', and 'enterprise' with clear inheritance and access levels.
  • Added RLS policy helpers for better role-based access control.

refactor: Enhance tracing configuration

  • Removed unused imports and cleaned up code formatting for better readability.
  • Improved error handling and logging in the LangfuseExporter class.

feat: Implement AI Gateway configuration

  • Created a new AI Gateway configuration file to manage API interactions with various AI models.
  • Added support for multiple AI models from different providers, including OpenAI, Anthropic, Google, and others.
  • Implemented dynamic model discovery and credit retrieval functions.

feat: Add Claude Code provider integration

  • Introduced a new configuration for Claude Code provider, allowing interaction with Claude models.
  • Defined model selection functions for easy access to different Claude Code models.

feat: Integrate GitHub Copilot provider

  • Developed a configuration for GitHub Copilot integration, supporting various models.
  • Added environment variable management for flexible configuration.
  • Created model selection function for easy access to GitHub Copilot models.

- Refactored role hierarchy to align with Supabase Auth and RLS, simplifying role definitions and inheritance.
- Introduced new roles: 'service_role', 'moderator', and updated existing roles to streamline access control.
- Revised subscription tiers to include 'free', 'pro', and 'enterprise' with clear inheritance and access levels.
- Added RLS policy helpers for better role-based access control.

refactor: Enhance tracing configuration
- Removed unused imports and cleaned up code formatting for better readability.
- Improved error handling and logging in the LangfuseExporter class.

feat: Implement AI Gateway configuration
- Created a new AI Gateway configuration file to manage API interactions with various AI models.
- Added support for multiple AI models from different providers, including OpenAI, Anthropic, Google, and others.
- Implemented dynamic model discovery and credit retrieval functions.

feat: Add Claude Code provider integration
- Introduced a new configuration for Claude Code provider, allowing interaction with Claude models.
- Defined model selection functions for easy access to different Claude Code models.

feat: Integrate GitHub Copilot provider
- Developed a configuration for GitHub Copilot integration, supporting various models.
- Added environment variable management for flexible configuration.
- Created model selection function for easy access to GitHub Copilot models.
Copilot AI review requested due to automatic review settings December 8, 2025 16:48
@continue
Copy link
Copy Markdown

continue Bot commented Dec 8, 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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 8, 2025

Summary by CodeRabbit

  • New Features

    • GitHub Copilot integration now available as an AI provider option
    • Claude Code integration added for code generation tasks
    • AI Gateway integration for multi-model access and unified API consumption
    • Extended model support across Google, OpenAI, and Anthropic providers
    • Added GPT OSS 20B free model via OpenRouter
  • Documentation

    • Comprehensive configuration guide with detailed setup instructions
    • Enhanced environment variable documentation and examples
  • Chores

    • Added new dependencies for provider integrations
    • Updated .env.example with new API key configuration

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

Walkthrough

This PR adds three new AI provider integrations (GitHub Copilot, AI Gateway, Claude Code), refactors existing model configurations into centralized registries with accessor functions, expands documentation with new providers, removes a processors module, updates role hierarchy for Supabase RLS, and adjusts tracing imports with enhanced logging.

Changes

Cohort / File(s) Summary
Configuration & Dependencies
.env.example, .agent/rules/conventions.md, package.json
Added AI_GATEWAY_API_KEY environment variable; removed duplicate RuntimeContext import; added @opeoginni/github-copilot-openai-compatible and ai-sdk-provider-claude-code dependencies.
New Provider Integrations
src/mastra/config/github-copilot.ts, src/mastra/config/ai-gateway.ts, src/mastra/config/claude-code.ts
Introduced three new provider modules with centralized config, model registries, and accessor functions (getGitHubCopilotModel, getAIGatewayModel, getClaudeCodeChatModel). Each exports models and backward-compatible aliases.
Model Registry Refactoring
src/mastra/config/openai.ts, src/mastra/config/google.ts, src/mastra/config/anthropic.ts, src/mastra/config/gemini-cli.ts, src/mastra/config/openrouter.ts
Reorganized individual model exports into centralized collections (openAIChatModels, googleChatModels, anthropicChatModels, geminiCliModels, openRouterModels) with corresponding getter functions; added backward-compatible exports mapping old names to new registry entries.
Public API
src/mastra/config/index.ts
Added four new barrel exports: github-copilot, gemini-cli, ai-gateway, claude-code modules.
Model Configuration
app/chat/config/openrouter-models.ts
Added new OpenRouter model: openrouter/openai/gpt-oss-20b:free with 8000 token context window and chat/code capabilities.
Documentation & Configuration
src/mastra/config/README.md, src/mastra/config/AGENTS.md
Expanded README from brief model-registry overview to comprehensive configuration handbook with examples and tooling guidance; updated AGENTS.md with new provider listings, vector storage details, environment variables, and changelog.
Authorization & RBAC
src/mastra/config/role-hierarchy.ts
Replaced generic role hierarchy with Supabase/RLS-oriented model (service_role, anon, authenticated, admin, moderator, subscription tiers). Introduced TierConfig, RLS_POLICIES mapping, and new helpers: hasFeature, getRLSPolicyForRole, canAccessResource, hasRoleAccess.
Observability
src/mastra/config/tracing.ts
Changed BaseAISpan from value import to type-only import; expanded logging payloads in LangfuseExporter with additional attributes (maxSteps, availableTools, usage, finishReason, success, waitDurationMs, etc.).
Removal
src/mastra/config/processors.ts
Deleted entire processor module including base classes (BaseInputProcessor, BaseOutputProcessor), concrete implementations (MessageLengthValidator, ResponseTimeTracker, ConversationSummarizer, SensitiveContentFilter, ContentLogger), and factory functions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Areas requiring extra attention:

  • Backward compatibility verification — Ensure all model registry refactoring (openai, google, anthropic, gemini-cli, openrouter) maintains existing export names and behavior via aliases; test that old import paths still work.
  • Provider configuration correctness — Validate GitHub Copilot, AI Gateway, and Claude Code module configurations (API keys, base URLs, headers, defaults) match documented integration patterns.
  • Processor deletion impact — Confirm src/mastra/config/processors.ts removal has no external dependencies; check if any agents or workflows reference the deleted classes or factory functions.
  • Role hierarchy and RLS logic — Review new Supabase-oriented role hierarchy, TierConfig structure, and RLS policy mappings (getRLSPolicyForRole, canAccessResource, hasRoleAccess) for correctness; verify inheritance chains and tier-to-role assignments.
  • Tracing logging payload expansion — Ensure new logging fields (maxSteps, availableTools, usage, finishReason, etc.) are compatible with LangfuseExporter expectations and don't introduce type mismatches.

Possibly related PRs

Poem

🐰 whiskers twitch with delight

Three new friends hop into place,
Copilot, Gateway, Claude—what grace!
Registries organized, so neat and tidy,
Roles align with Supabase RLS friendly.
Processors gone, tracing logs shine bright,
Config refactored—what a sight! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title focuses on role hierarchy and subscription tier configurations, but the changeset includes much broader changes: AI Gateway, Claude Code, GitHub Copilot integrations, gemini-cli restructuring, google.ts reorganization, tracing improvements, and more. Update the title to reflect the full scope of changes, such as: 'feat: Add AI provider integrations and refactor model configurations' or provide multiple descriptive headings.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description is well-organized and addresses multiple major features and refactorings in the changeset, covering role hierarchy, tracing, AI Gateway, Claude Code, and GitHub Copilot integrations.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% which is sufficient. The required threshold is 80.00%.
✨ 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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Dec 8, 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.

@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 introduces a substantial expansion of AI model integrations, allowing for a wider array of AI capabilities and providers to be utilized. Concurrently, it overhauls the application's access control system by refactoring the role hierarchy to be Supabase-compatible and defining clear subscription tiers. These changes are supported by comprehensive updates to the configuration documentation and minor improvements to the tracing system, ensuring a more robust, flexible, and well-documented foundation for AI-driven features and user management.

Highlights

  • Expanded AI Model Integrations: Significantly broadened the range of supported AI models and providers, including new configurations for AI Gateway, Claude Code, and GitHub Copilot. Existing providers like Anthropic, Google, OpenAI, and OpenRouter have been updated with new model series and capabilities.
  • Refactored Role Hierarchy and Subscription Tiers: The role hierarchy has been completely revamped to align with Supabase Auth and Row Level Security (RLS), introducing new roles like 'service_role' and 'moderator', and streamlining subscription tiers ('free', 'pro', 'enterprise') with clear inheritance and RLS policy helpers.
  • Enhanced Configuration Documentation: The AGENTS.md and README.md files within the src/mastra/config directory have been extensively updated to provide comprehensive documentation on the architecture, quick start guides, supported providers, storage systems, authentication, and environment variables.
  • Improved Tracing Configuration: The LangfuseExporter class in the tracing configuration has been refined with minor refactoring, removal of unused imports, and improved error handling for better observability and debugging.
  • New Environment Variables: Added new environment variables in .env.example for AI Gateway (AI_GATEWAY_API_KEY) and GitHub Copilot (COPILOT_TOKEN), along with various database, memory, RAG, and embedding configuration options.
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 8, 2025

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

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Dec 8, 2025

Greptile Overview

Greptile Summary

This PR refactors role hierarchy to align with Supabase Auth/RLS patterns and adds three new AI provider integrations (AI Gateway, Claude Code, GitHub Copilot), significantly expanding model access options.

Key Changes

  • Simplified role hierarchy from complex department-based roles to Supabase-native roles (service_role, admin, moderator, authenticated, anon)
  • Revised subscription tiers (free, pro, enterprise) with clearer inheritance and RLS policy mappings
  • Added AI Gateway provider with 20+ models from multiple providers (OpenAI, Anthropic, Google, xAI, Meta, Mistral, DeepSeek)
  • Integrated Claude Code provider with CLI-based authentication
  • Added GitHub Copilot provider with extensive model catalog (GPT, Claude, Gemini, Grok, o-series)
  • Cleaned up tracing configuration formatting

Issues Found

  • Critical: role-hierarchy.ts has logic errors in getTierForRole() function - doesn't map non-subscription roles like admin or moderator to appropriate tiers
  • Critical: Free tier incorrectly uses anon RLS policy instead of authenticated policy
  • Critical: claude-code.ts has incorrect default value for cwd parameter ('claude' string instead of process.cwd())
  • Minor: Several files missing newlines at EOF and have unused imports

Confidence Score: 2/5

  • This PR has critical logic bugs that will cause runtime errors in role-based access control
  • Score reflects three critical logic errors in core access control functions (getTierForRole, RLS policy mapping, and Claude Code cwd parameter) that would break RBAC functionality and Claude Code integration. While the provider integrations are well-structured, the role hierarchy bugs must be fixed before merging.
  • Pay close attention to src/mastra/config/role-hierarchy.ts and src/mastra/config/claude-code.ts - both contain critical bugs that need immediate fixes

Important Files Changed

File Analysis

Filename Score Overview
src/mastra/config/role-hierarchy.ts 2/5 Refactored role hierarchy with Supabase alignment, but contains 2 critical logic errors in tier mapping and RLS policy assignments
src/mastra/config/ai-gateway.ts 4/5 New AI Gateway integration with comprehensive model support, minor issues with unused import and missing newline
src/mastra/config/claude-code.ts 2/5 New Claude Code provider integration, but critical bug with cwd default value and unused import
src/mastra/config/github-copilot.ts 4/5 New GitHub Copilot provider with extensive model support, minor unused import issue
.env.example 3/5 Added AI Gateway API key, but comment is incomplete

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant Auth as Supabase Auth
    participant RH as Role Hierarchy
    participant TC as Tier Config
    participant Provider as AI Provider
    participant Gateway as AI Gateway

    App->>Auth: User authenticates
    Auth-->>App: JWT with role metadata
    
    App->>RH: hasRoleAccess(userRole, requiredRole)
    RH->>RH: Check ROLE_HIERARCHY inheritance
    RH-->>App: Access decision (true/false)
    
    App->>TC: getTierForRole(role)
    TC-->>App: SubscriptionTier (free/pro/enterprise)
    
    App->>TC: getTierConfig(tier)
    TC->>TC: Lookup TIER_CONFIGS
    TC-->>App: TierConfig with features & limits
    
    App->>RH: getRLSPolicyForRole(role)
    RH->>TC: getTierForRole(role)
    TC-->>RH: tier
    RH->>TC: TIER_CONFIGS[tier].rlsPolicy
    TC-->>RH: RLS policy string
    RH-->>App: Policy for database queries
    
    App->>Provider: Select AI model (OpenAI/Anthropic/Copilot/Claude Code)
    Provider-->>App: Model instance
    
    alt Using AI Gateway
        App->>Gateway: aiGateway(modelId)
        Gateway->>Gateway: Route to provider (OpenAI/Anthropic/Google/xAI/etc)
        Gateway-->>App: Unified model interface
    end
    
    App->>Provider: Generate response
    Provider-->>App: AI response
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.

18 files reviewed, 10 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 125 to +128
free: {
maxDocuments: 500,
maxApiRequestsPerDay: 50,
maxUsersPerTenant: 1,
features: ['basic-rag', 'basic-search', 'public-docs'],
supportLevel: 'community',
customIntegrations: false,
advancedAnalytics: false,
whiteLabel: false,
onPremise: false,
maxRequests: 100,
features: ['basic-chat', 'public-docs'],
rlsPolicy: RLS_POLICIES.publicRead,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

logic: free tier pointing to RLS_POLICIES.publicRead ('anon') is incorrect - free users are authenticated, not anonymous

Suggested change
free: {
maxDocuments: 500,
maxApiRequestsPerDay: 50,
maxUsersPerTenant: 1,
features: ['basic-rag', 'basic-search', 'public-docs'],
supportLevel: 'community',
customIntegrations: false,
advancedAnalytics: false,
whiteLabel: false,
onPremise: false,
maxRequests: 100,
features: ['basic-chat', 'public-docs'],
rlsPolicy: RLS_POLICIES.publicRead,
free: {
maxRequests: 100,
features: ['basic-chat', 'public-docs'],
rlsPolicy: RLS_POLICIES.userAccess,
},
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/role-hierarchy.ts
Line: 125:128

Comment:
**logic:** `free` tier pointing to `RLS_POLICIES.publicRead` ('anon') is incorrect - free users are authenticated, not anonymous

```suggestion
    free: {
        maxRequests: 100,
        features: ['basic-chat', 'public-docs'],
        rlsPolicy: RLS_POLICIES.userAccess,
    },
```

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

Comment on lines +176 to +179
export function getRLSPolicyForRole(role: string): string {
const tier = getTierForRole(role)
return TIER_CONFIGS[tier].rlsPolicy
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

logic: getTierForRole only handles exact matches for 'enterprise', 'pro', 'free' but doesn't handle other roles like 'admin', 'moderator', 'authenticated'

Suggested change
export function getRLSPolicyForRole(role: string): string {
const tier = getTierForRole(role)
return TIER_CONFIGS[tier].rlsPolicy
}
export function getTierForRole(role: string): SubscriptionTier {
if (role === 'enterprise' || role === 'admin' || role === 'service_role') {
return 'enterprise'
}
if (role === 'pro' || role === 'moderator') {
return 'pro'
}
return 'free'
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/role-hierarchy.ts
Line: 176:179

Comment:
**logic:** `getTierForRole` only handles exact matches for 'enterprise', 'pro', 'free' but doesn't handle other roles like 'admin', 'moderator', 'authenticated'

```suggestion
export function getTierForRole(role: string): SubscriptionTier {
    if (role === 'enterprise' || role === 'admin' || role === 'service_role') {
        return 'enterprise'
    }
    if (role === 'pro' || role === 'moderator') {
        return 'pro'
    }
    return 'free'
}
```

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

continue: true,
maxThinkingTokens: 1000,
additionalDirectories: [],
cwd: process.env.CLAUDE_CODE_CLI_CWD ?? 'claude',
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

logic: default value 'claude' doesn't make sense for cwd parameter - should be process.cwd()

Suggested change
cwd: process.env.CLAUDE_CODE_CLI_CWD ?? 'claude',
cwd: process.env.CLAUDE_CODE_CLI_CWD ?? process.cwd(),
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/claude-code.ts
Line: 13:13

Comment:
**logic:** default value 'claude' doesn't make sense for `cwd` parameter - should be `process.cwd()`

```suggestion
    cwd: process.env.CLAUDE_CODE_CLI_CWD ?? process.cwd(),
```

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

@@ -0,0 +1,70 @@
import { createGitHubCopilotOpenAICompatible } from '@opeoginni/github-copilot-openai-compatible';
import { logError } from './logger';
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: logError imported but never used in this file

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/github-copilot.ts
Line: 2:2

Comment:
**syntax:** `logError` imported but never used in this file

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

@@ -0,0 +1,82 @@
import { createGateway } from '@ai-sdk/gateway'
import { logError } from './logger'
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: logError imported but never used in this file

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/ai-gateway.ts
Line: 2:2

Comment:
**syntax:** `logError` imported but never used in this file

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

// Default model
export const aiGatewayModel = aiGatewayModels.openaiGpt5

export default aiGateway No newline at end of file
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: missing newline at end of file

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/ai-gateway.ts
Line: 82:82

Comment:
**style:** missing newline at end of file

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

export const claudeCodeSonnet = claudeCodeChatModels.claudeSonnet;
export const claudeCodeHaiku = claudeCodeChatModels.claudeHaiku;

export default claudeCodeProvider;
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: missing newline at end of file

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/claude-code.ts
Line: 39:39

Comment:
**style:** missing newline at end of file

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

}

// Default model
export const githubCopilotModel = githubCopilotModels.gpt5;
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: missing newline at end of file

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/github-copilot.ts
Line: 70:70

Comment:
**style:** missing newline at end of file

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

Comment thread .env.example
# OpenRouter Configuration
OPENROUTER_API_KEY='your_openrouter_api_key_here'

# AI Ga
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: incomplete comment "# AI Ga" should be "# AI Gateway Configuration"

Suggested change
# AI Ga
# AI Gateway Configuration
Prompt To Fix With AI
This is a comment left during a code review.
Path: .env.example
Line: 23:23

Comment:
**syntax:** incomplete comment "# AI Ga" should be "# AI Gateway Configuration"

```suggestion
# AI Gateway Configuration
```

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

@@ -0,0 +1,39 @@
import { createClaudeCode } from 'ai-sdk-provider-claude-code'
import { logError } from './logger'
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: logError imported but never used

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/mastra/config/claude-code.ts
Line: 2:2

Comment:
**syntax:** `logError` imported but never used

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 significantly expands and refactors the configuration system, primarily focusing on AI model providers, storage, and authentication. Key changes include the introduction of new AI model providers such as AI Gateway, GitHub Copilot, and Claude Code, along with a comprehensive restructuring of existing Anthropic, Gemini CLI, Google, OpenAI, and OpenRouter model configurations into organized objects with selector functions and backward compatibility. The .env.example file was updated to include the AI_GATEWAY_API_KEY. Documentation files (AGENTS.md and README.md) were extensively updated to reflect these new providers, detail the architecture, directory structure, quick start guides, storage systems, and authentication/authorization using a Supabase-compatible RBAC system. The role-hierarchy.ts file was refactored to simplify role definitions, introduce RLS policies, and update tier configurations. The processors.ts file was removed. Review comments highlighted several areas for improvement: the hasRoleAccess function in role-hierarchy.ts was identified as non-recursive and a corrected BFS-based implementation was suggested; the dotenv.config() call in github-copilot.ts was flagged as an anti-pattern and recommended for removal; the getTierForRole function in role-hierarchy.ts was deemed too simplistic and a more robust implementation based on ROLE_LEVELS was provided; minor issues like a typo in .env.example, trailing whitespace in AGENTS.md, an undefined userRole in a README.md example, a missing newline in ai-gateway.ts, and a suggestion to add braces to a single-line if statement in tracing.ts were also noted.

Comment on lines +87 to +98
export function hasRoleAccess(userRole: string, requiredRole: string): boolean {
if (userRole === requiredRole) {
return true
}

if (!(userRole in ROLE_HIERARCHY)) {
return false
}

const inheritedRoles = ROLE_HIERARCHY[userRole]
return inheritedRoles.includes(requiredRole)
}
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

The hasRoleAccess function is not recursive and will fail to check inherited permissions correctly. For example, hasRoleAccess('service_role', 'moderator') would incorrectly return false because 'moderator' is inherited by 'admin', which is in turn inherited by 'service_role'. The check needs to traverse the entire inheritance chain.

The suggested implementation uses a breadth-first search to correctly and safely traverse the role hierarchy, preventing potential infinite loops if cycles were ever introduced.

export function hasRoleAccess(userRole: string, requiredRole: string): boolean {
    if (userRole === requiredRole) {
        return true;
    }

    const queue: string[] = [userRole];
    const visited = new Set<string>([userRole]);

    while (queue.length > 0) {
        const currentRole = queue.shift()!;
        const inheritedRoles = ROLE_HIERARCHY[currentRole] || [];

        for (const inheritedRole of inheritedRoles) {
            if (inheritedRole === requiredRole) {
                return true;
            }
            if (!visited.has(inheritedRole)) {
                visited.add(inheritedRole);
                queue.push(inheritedRole);
            }
        }
    }

    return false;
}

Comment on lines +5 to +6
// Load environment variables
dotenv.config();
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

Calling dotenv.config() inside a library module is an anti-pattern. It creates side effects, making the module less reusable and harder to test. Environment variables should be loaded once at the application's entry point, not within individual modules. Please remove these lines and the corresponding dotenv import on line 3.

Comment on lines 159 to 170
export function getTierForRole(role: string): SubscriptionTier {
if (role === 'public') {
return 'free'
}
if (role === 'free_user') {
return 'free'
if (role === 'enterprise') {
return 'enterprise'
}
if (role.startsWith('pro_') || role === 'employee' || role === 'reader') {
if (role === 'pro') {
return 'pro'
}
if (role.startsWith('enterprise_') || role === 'admin' || role.endsWith('.admin') || role.endsWith('.viewer')) {
return 'enterprise'
if (role === 'free') {
return 'free'
}
return 'free'
}
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

The getTierForRole function is too simplistic. It only handles the exact roles 'enterprise', 'pro', and 'free', incorrectly defaulting all other roles like 'admin' or 'moderator' to the 'free' tier. This is likely incorrect, as higher-privilege roles should map to higher subscription tiers. A more robust implementation should consider the role's privilege level defined in ROLE_LEVELS.

export function getTierForRole(role: string): SubscriptionTier {
    const level = getRoleLevel(role);

    // Check from highest tier to lowest
    if (level >= ROLE_LEVELS.enterprise) {
        return 'enterprise';
    }
    if (level >= ROLE_LEVELS.pro) {
        return 'pro';
    }
    // Default to free for any other valid role
    return 'free';
}

Comment thread .env.example
# OpenRouter Configuration
OPENROUTER_API_KEY='your_openrouter_api_key_here'

# AI Ga
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

There's a minor typo in the comment for the AI Gateway configuration. It appears to be incomplete.

# AI Gateway Configuration

| `upstash.ts` | Upstash Redis configuration | Caching and session storage |
| `upstashMemory.ts` | Upstash Redis memory configuration | Alternative memory provider |
| `logger.ts` | Structured logging (Pino) | Standard log helpers & transports |
| `tracing.ts` | Distributed tracing configuration | Performance monitoring and debugging |
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

This line, and several others in the markdown tables, have trailing whitespace. This can affect the readability of the raw markdown and create noisy diffs in the future. Please remove the trailing spaces from all affected lines in this file (e.g., lines 31, 33, 48, 49, 51, 52, and throughout the 'Model Providers' table).


// Role-based access control
import { hasRoleAccess } from './role-hierarchy'
if (hasRoleAccess(userRole, 'admin')) {
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 example code here references userRole, but it's not defined in the snippet. This could be confusing for users trying to copy and paste the example. Please define it to make the example self-contained and runnable.

Suggested change
if (hasRoleAccess(userRole, 'admin')) {
const userRole = 'admin'; // Example user role
if (hasRoleAccess(userRole, 'admin')) {

// Default model
export const aiGatewayModel = aiGatewayModels.openaiGpt5

export default aiGateway No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

This file is missing a final newline character. It's a common convention to end files with a newline to prevent issues with file concatenation and to ensure consistent git diffs.

Suggested change
export default aiGateway
export default aiGateway

// @ts-expect-error - traceMap is protected in base class but we need to check it
const traceMap = this.traceMap as Map<string, unknown> | undefined
if (!traceMap || !span.traceId) return
if (!traceMap || !span.traceId) {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

While functionally correct, adding braces to a single-line if statement can improve readability and prevent potential issues if more logic is added to the block later. It's a good practice for consistency and maintainability.

Suggested change
if (!traceMap || !span.traceId) {return}
if (!traceMap || !span.traceId) return

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: 27

Caution

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

⚠️ Outside diff range comments (4)
src/mastra/config/openrouter.ts (2)

2-2: Unused import: logError is imported but never used.

Remove the unused import to keep the code clean.

 import { createOpenRouter } from '@openrouter/ai-sdk-provider'
-import { logError } from './logger'

319-344: Duplicate model definitions detected.

openQwenAI, openGLMAI, and openAIFree are duplicates of entries in openRouterModels (lines 109, 280, 190). Consider aliasing from the registry instead.

-export const openQwenAI = openrouter('qwen/qwen3-coder:free', {
-    includeReasoning: true,
-    extraBody: {
-        reasoning: { max_tokens: 20000 },
-        stream: true,
-    },
-    usage: { include: true },
-})
-
-export const openGLMAI = openrouter('z-ai/glm-4.5-air:free', {
-    includeReasoning: true,
-    extraBody: {
-        reasoning: { max_tokens: 20000 },
-        stream: true,
-    },
-    usage: { include: true },
-})
-
-export const openAIFree = openrouter('openai/gpt-oss-20b:free', {
-    includeReasoning: true,
-    extraBody: {
-        reasoning: { max_tokens: 20000 },
-        stream: true,
-    },
-    usage: { include: true },
-})
+// Backward compatibility exports
+export const openQwenAI = openRouterModels.qwenQwen3CoderFree;
+export const openGLMAI = openRouterModels.zAiGlm45AirFree;
+export const openAIFree = openRouterModels.openaiGptOss20bFree;
src/mastra/config/tracing.ts (1)

341-356: Mask sensitive span data before logging input, output, and errorInfo fields.

The SensitiveDataFilter doesn't protect these fields at the exporter level. Use maskSensitiveMessageData() from src/mastra/config/pg-storage.ts to mask span.input, span.output, and span.errorInfo before logging them at lines 352-355, since these may contain PII, API keys, or other secrets depending on the span's contents.

src/mastra/config/gemini-cli.ts (1)

6-13: Avoid using API‑key auth in production when GOOGLE_GENERATIVE_AI_API_KEY is missing

useApiKey becomes true in production even if GOOGLE_GENERATIVE_AI_API_KEY is unset, which results in:

apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY ?? ''

An empty string here will likely cause confusing runtime errors from the provider.

Consider tightening this logic so that in production you either:

  • Require the env var and throw/log a clear error if it’s missing, or
  • Fall back to OAuth only when you explicitly allow that in prod.

For example:

const hasApiKey = !!process.env.GOOGLE_GENERATIVE_AI_API_KEY;
const isProd = process.env.NODE_ENV === 'production';

if (isProd && !hasApiKey) {
  // logError('GOOGLE_GENERATIVE_AI_API_KEY is required in production');
  throw new Error('GOOGLE_GENERATIVE_AI_API_KEY is required in production');
}

const useApiKey = hasApiKey || isProd;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbd1b0d and f944655.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (18)
  • .agent/rules/conventions.md (0 hunks)
  • .env.example (1 hunks)
  • app/chat/config/openrouter-models.ts (1 hunks)
  • package.json (2 hunks)
  • src/mastra/config/AGENTS.md (3 hunks)
  • src/mastra/config/README.md (1 hunks)
  • src/mastra/config/ai-gateway.ts (1 hunks)
  • src/mastra/config/anthropic.ts (1 hunks)
  • src/mastra/config/claude-code.ts (1 hunks)
  • src/mastra/config/gemini-cli.ts (5 hunks)
  • src/mastra/config/github-copilot.ts (1 hunks)
  • src/mastra/config/google.ts (1 hunks)
  • src/mastra/config/index.ts (1 hunks)
  • src/mastra/config/openai.ts (2 hunks)
  • src/mastra/config/openrouter.ts (1 hunks)
  • src/mastra/config/processors.ts (0 hunks)
  • src/mastra/config/role-hierarchy.ts (3 hunks)
  • src/mastra/config/tracing.ts (16 hunks)
💤 Files with no reviewable changes (2)
  • .agent/rules/conventions.md
  • src/mastra/config/processors.ts
🧰 Additional context used
📓 Path-based instructions (23)
**/*.{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/mastra/config/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • app/chat/config/openrouter-models.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.ts
**/*.{js,ts}

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

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

Files:

  • src/mastra/config/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • app/chat/config/openrouter-models.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.ts
src/mastra/config/**/*.ts

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

All external service initialization in the config directory must be environment-driven, with sensitive credentials loaded from environment variables and never hardcoded

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/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.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/mastra/config/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • app/chat/config/openrouter-models.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/mastra/config/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.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/mastra/config/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • app/chat/config/openrouter-models.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.ts
**/*.{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/mastra/config/github-copilot.ts
  • src/mastra/config/ai-gateway.ts
  • app/chat/config/openrouter-models.ts
  • src/mastra/config/anthropic.ts
  • src/mastra/config/index.ts
  • src/mastra/config/openai.ts
  • src/mastra/config/claude-code.ts
  • src/mastra/config/openrouter.ts
  • src/mastra/config/gemini-cli.ts
  • src/mastra/config/tracing.ts
  • src/mastra/config/role-hierarchy.ts
  • src/mastra/config/google.ts
**/.env*

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

Use environment variables to store configuration values in the application.

Files:

  • .env.example
.env*

📄 CodeRabbit inference engine (AGENTS.md)

.env*: Use .env file locally for environment variables and secure env variables in CI/CD systems like GitHub Actions Secrets
Configure minimum required environment variables: SUPABASE/DATABASE_URL, GOOGLE_GENERATIVE_AI_API_KEY, and optional provider keys (OPENAI_API_KEY, ANTHROPIC_API_KEY, OPENROUTER_API_KEY) for local development

Files:

  • .env.example
**/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/config/openrouter-models.ts
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/config/openrouter-models.ts
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/config/openrouter-models.ts
{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/config/openrouter-models.ts
{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/config/openrouter-models.ts
**/*.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/mastra/config/README.md
  • src/mastra/config/AGENTS.md
src/mastra/config/anthropic.ts

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

Anthropic model provider configuration in anthropic.ts should support Claude 3.5 Sonnet, Opus, and Haiku models with API key from ANTHROPIC_API_KEY environment variable

Files:

  • src/mastra/config/anthropic.ts
src/mastra/config/index.ts

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

Index file (index.ts) in /src/mastra/config should aggregate and export all provider configuration modules

Files:

  • src/mastra/config/index.ts
src/mastra/config/AGENTS.md

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

When adding new tools or providers, add env var placeholders to .env and document them in src/mastra/config/AGENTS.md

Files:

  • src/mastra/config/AGENTS.md
src/mastra/config/openai.ts

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

OpenAI model provider configuration in openai.ts should support GPT-4, GPT-4o, and GPT-3.5 models with API key from OPENAI_API_KEY environment variable

Files:

  • src/mastra/config/openai.ts
src/mastra/config/openrouter.ts

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

OpenRouter model provider configuration in openrouter.ts should enable routing to multiple models via OPENROUTER_API_KEY environment variable

Files:

  • src/mastra/config/openrouter.ts
src/mastra/config/gemini-cli.ts

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

Gemini CLI provider configuration in gemini-cli.ts should support local development and testing scenarios

Files:

  • src/mastra/config/gemini-cli.ts
src/mastra/config/role-hierarchy.ts

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

Role-based access control (RBAC) inheritance model in role-hierarchy.ts should drive policy decisions and access filters

Files:

  • src/mastra/config/role-hierarchy.ts
src/mastra/config/google.ts

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

Google AI model provider configuration in google.ts should support Gemini 2.5 Flash, Pro, and Flash Lite models with API key from GOOGLE_GENERATIVE_AI_API_KEY environment variable

Files:

  • src/mastra/config/google.ts
🧬 Code graph analysis (2)
src/mastra/config/ai-gateway.ts (1)
src/mastra/config/logger.ts (1)
  • logError (153-174)
src/mastra/config/tracing.ts (1)
lib/types/mastra-api.ts (1)
  • AISpanType (177-184)
🪛 dotenv-linter (4.0.0)
.env.example

[warning] 24-24: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

⏰ 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 (12)
src/mastra/config/README.md (2)

1-370: Documentation is comprehensive and well-structured.

The README provides thorough coverage of the configuration system including architecture, usage examples, environment variables, and development guidelines. The modular organization with clear sections for providers, storage, and auth aligns well with the codebase structure.


41-44: Remove non-existent processors.ts reference from Infrastructure section.

The directory structure at line 44 references processors.ts, but this file does not exist in the codebase. Either remove this line or replace it with an actual file that exists in the Infrastructure module.

Likely an incorrect or invalid review comment.

src/mastra/config/index.ts (1)

13-16: LGTM!

The new barrel exports for github-copilot, gemini-cli, ai-gateway, and claude-code follow the established pattern and align with the coding guidelines for aggregating provider configuration modules in the index file.

src/mastra/config/anthropic.ts (2)

25-28: LGTM!

The selector function follows the established pattern for model access, providing type-safe model selection via keyof typeof anthropicChatModels.


30-33: Backward compatibility exports are well-documented.

The comments clarify the mapping for each alias, which helps maintainability.

src/mastra/config/openai.ts (2)

59-62: LGTM!

The selector function provides type-safe model selection consistent with the pattern used across other provider configurations.


36-57: > Likely an incorrect or invalid review comment.

package.json (2)

79-79: @opeoginni/github-copilot-openai-compatible is in early development stage (v0.1.21) — verify production readiness.

The package exists on npm and was recently updated (November 2025), but the pre-release version number (0.1.x) indicates early-stage software. Confirm this dependency is suitable for production use and consider the maintenance risk of a single-maintainer package.


97-97: No action needed on ai-sdk-provider-claude-code package.

The package is actively maintained with the latest update on 2025-12-05. Version 2.2.4 specified in package.json is the current latest release, and the package has a dedicated maintainer.

src/mastra/config/tracing.ts (2)

62-63: LGTM: Import formatting improvement.

Moving BaseAISpan to the type import block is a minor formatting cleanup with no functional impact.


370-512: LGTM: Expanded span attribute logging for observability.

The enhanced logging for different AISpanType cases (AgentRun, ModelGeneration, ToolCall, WorkflowRun, etc.) improves debugging and aligns with the broader observability patterns in the PR.

src/mastra/config/google.ts (1)

42-102: Google provider registry + selectors look consistent and env‑driven

The new googleChatModels / googleImageModels / googleEmbeddingModels registries, along with getGoogle*Model helpers and default model aliases, form a coherent, centralized config surface. Initialization via createGoogleGenerativeAI({ apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY }) satisfies the env-driven requirement and avoids hardcoded credentials.

No issues from a correctness or configuration perspective in this section.

Comment thread .env.example
Comment on lines +23 to +24
# AI Ga
AI_GATEWAY_API_KEY='your_api_key_here'
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

Fix truncated comment.

The comment on line 23 is incomplete (# AI Ga). This should likely read # AI Gateway or similar to describe the environment variable.

-# AI Ga
+# AI Gateway Configuration
 AI_GATEWAY_API_KEY='your_api_key_here'
📝 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
# AI Ga
AI_GATEWAY_API_KEY='your_api_key_here'
# AI Gateway Configuration
AI_GATEWAY_API_KEY='your_api_key_here'
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 24-24: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🤖 Prompt for AI Agents
In .env.example around lines 23 to 24, the inline comment for the AI gateway API
key is truncated ("# AI Ga"); replace it with a complete descriptive comment
such as "# AI Gateway" (or "# AI Gateway API key") so the environment variable
is clearly documented, ensuring punctuation and capitalization are consistent
with other comments in the file.

Comment on lines +296 to +303
{
id: "openrouter/openai/gpt-oss-20b:free",
name: "GPT OSS 20B (Free)",
provider: "openrouter",
contextWindow: 8000,
capabilities: ["chat", "code"],
description: "Open-source GPT via OR",
},
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

🧩 Analysis chain

🌐 Web query:

OpenRouter gpt-oss-20b free model

💡 Result:

Yes — gpt-oss-20b is an OpenAI open‑weight model (Apache‑2.0) and is available to run locally or via third‑party hosts (including OpenRouter). Key facts and how to access:

  • What it is: gpt-oss-20b is a 21B‑parameter, Mixture‑of‑Experts model released by OpenAI (Apache‑2.0, full chain‑of‑thought, 131k context). [1][2]
  • Official downloads / repo: weights, reference code, and instructions are on OpenAI's repo and Hugging Face. [2][3]
  • Third‑party hosting (OpenRouter and others): many providers (including OpenRouter/third‑party APIs) offer hosted endpoints for gpt-oss-20b; some expose a “free” model variant or low‑cost access keys (model IDs you’ll see include names like openrouter/gpt-oss-20b or openai/gpt-oss-20b:free depending on provider). Check the provider’s docs for exact model ID, rate limits, and pricing. [4][5]
  • Quick next steps: (1) pick a host (OpenRouter, Hugging Face Inference, Ollama, etc.), (2) read their model listing for the exact model ID and quota, (3) call the host’s API with that model ID (or download weights to run locally if you have suitable hardware). [1][3][4]

Sources: OpenAI introducing gpt‑oss (model details & availability) [1]; OpenAI GitHub model repo (README + download instructions) [2]; examples of third‑party hosted/free listings (provider docs / libraries) [4][5].


Fix incorrect context window for gpt-oss-20b model.

The context window is set to 8000 tokens, but gpt-oss-20b is a 21B-parameter open-weight model with a 131k context window. Update line 299 to reflect the correct context window value.

🤖 Prompt for AI Agents
In app/chat/config/openrouter-models.ts around lines 296 to 303, the gpt-oss-20b
model's contextWindow is incorrectly set to 8000; change the contextWindow value
on line 299 to the correct 131000 (131k) to reflect the model's actual
~131k-token context window.

@@ -1,4 +1,4 @@
<!-- AGENTS-META {"title":"Mastra Config","version":"2.0.0","last_updated":"2025-11-26T00:00:00Z","applies_to":"/src/mastra/config","tags":["layer:backend","domain:infra","type:config","status":"stable"],"status":"stable"} -->
<!-- AGENTS-META {"title":"Mastra Config","version":"2.2.1","last_updated":"2025-12-08T00:00:00Z","applies_to":"/src/mastra/config","tags":["layer:backend","domain:infra","type:config","status":"stable"],"status":"stable"} -->
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

Align AGENTS-META version with Change Log entries

The metadata header declares version 2.2.1, but the Change Log introduces 2.3.0 as the latest entry. Consider bumping the AGENTS-META version field to 2.3.0 (or whatever is intended as the current doc version) to avoid confusion about which version the page represents.

Also applies to: 145-150

🤖 Prompt for AI Agents
In src/mastra/config/AGENTS.md lines 1-1 and 145-150, the AGENTS-META header
still lists version "2.2.1" while the Change Log shows "2.3.0"; update the
metadata version field (and any other AGENTS-META occurrences at lines 145-150)
to "2.3.0" (or the intended current doc version) so the header matches the
Change Log and avoids confusion.

Comment on lines +76 to 83
### Supported Supabase Roles

- `anon` - Public/unauthenticated access
- `authenticated` - Logged-in users
- `admin` - Administrative access
- `service_role` - Backend service operations
- Subscription tiers: `free`, `pro`, `enterprise`

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

Keep documented Supabase roles in sync with role-hierarchy.ts

The “Supported Supabase Roles” list documents anon, authenticated, admin, and service_role, plus subscription tiers. The RBAC config in role-hierarchy.ts also introduces a moderator role and treats free, pro, and enterprise as role-like entries.

It would be helpful to either:

  • Add moderator to this list (and clarify it’s app-level but RLS-relevant), or
  • Explicitly distinguish Supabase core roles from app roles and subscription tiers.

This keeps RLS policy docs aligned with the actual hierarchy.

🤖 Prompt for AI Agents
In src/mastra/config/AGENTS.md around lines 76 to 83, the documented “Supported
Supabase Roles” list is out of sync with role-hierarchy.ts which includes a
moderator role and treats subscription tiers as role-like entries; update this
section to either add `moderator` (noting it is an app-level role that impacts
RLS) or split the list into two clearly labeled groups — “Supabase core roles”
(`anon`, `authenticated`, `service_role`, `admin`) and “App-level roles /
subscription tiers” (`moderator`, `free`, `pro`, `enterprise`) — so the docs
match the RBAC config and clarify intent.

Comment on lines +5 to +9
export const aiGatewayConfig = {
apiKey: process.env.AI_GATEWAY_API_KEY ?? '',
baseURL: process.env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh/v1/ai',
metadataCacheRefreshMillis: parseInt(process.env.AI_GATEWAY_CACHE_REFRESH ?? '300000'), // 5 minutes
}
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 validation or warning for missing API key.

An empty apiKey will silently pass initialization but cause runtime API failures. Consider logging a warning when the key is missing. As per coding guidelines, add TSDoc documenting the environment variables.

+/**
+ * AI Gateway configuration loaded from environment variables.
+ * @property apiKey - AI_GATEWAY_API_KEY environment variable (required for API calls)
+ * @property baseURL - AI_GATEWAY_BASE_URL environment variable
+ * @property metadataCacheRefreshMillis - AI_GATEWAY_CACHE_REFRESH parsed as integer (default: 5 minutes)
+ */
 export const aiGatewayConfig = {
   apiKey: process.env.AI_GATEWAY_API_KEY ?? '',
   baseURL: process.env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh/v1/ai',
   metadataCacheRefreshMillis: parseInt(process.env.AI_GATEWAY_CACHE_REFRESH ?? '300000'), // 5 minutes
 }
+
+if (!aiGatewayConfig.apiKey) {
+  console.warn('[ai-gateway] AI_GATEWAY_API_KEY is not set. API calls will fail.');
+}
📝 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 const aiGatewayConfig = {
apiKey: process.env.AI_GATEWAY_API_KEY ?? '',
baseURL: process.env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh/v1/ai',
metadataCacheRefreshMillis: parseInt(process.env.AI_GATEWAY_CACHE_REFRESH ?? '300000'), // 5 minutes
}
/**
* AI Gateway configuration loaded from environment variables.
* @property apiKey - AI_GATEWAY_API_KEY environment variable (required for API calls)
* @property baseURL - AI_GATEWAY_BASE_URL environment variable
* @property metadataCacheRefreshMillis - AI_GATEWAY_CACHE_REFRESH parsed as integer (default: 5 minutes)
*/
export const aiGatewayConfig = {
apiKey: process.env.AI_GATEWAY_API_KEY ?? '',
baseURL: process.env.AI_GATEWAY_BASE_URL ?? 'https://ai-gateway.vercel.sh/v1/ai',
metadataCacheRefreshMillis: parseInt(process.env.AI_GATEWAY_CACHE_REFRESH ?? '300000'), // 5 minutes
}
if (!aiGatewayConfig.apiKey) {
console.warn('[ai-gateway] AI_GATEWAY_API_KEY is not set. API calls will fail.');
}
🤖 Prompt for AI Agents
In src/mastra/config/ai-gateway.ts around lines 5 to 9, the aiGatewayConfig
allows an empty apiKey which will cause runtime failures; add a runtime check
that logs a warning (using the app logger or console.warn if no logger) when
process.env.AI_GATEWAY_API_KEY is missing or empty, and keep the existing
default for baseURL and parsed cache refresh; also add TSDoc above the exported
aiGatewayConfig describing the expected environment variables
(AI_GATEWAY_API_KEY, AI_GATEWAY_BASE_URL, AI_GATEWAY_CACHE_REFRESH) and their
defaults/types so callers and maintainers understand required configuration.

Comment on lines +314 to +317
// Model selector function
export function getOpenRouterModel(modelId: keyof typeof openRouterModels) {
return openRouterModels[modelId];
}
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 TSDoc comment documenting the function.

As per coding guidelines, public API functions should include TSDoc with @param and @returns tags.

-// Model selector function
+/**
+ * Retrieves an OpenRouter model instance by its identifier.
+ * @param modelId - The key of the model in the openRouterModels registry
+ * @returns The configured OpenRouter model instance
+ * @example
+ * const model = getOpenRouterModel('anthropicClaudeSonnet45');
+ */
 export function getOpenRouterModel(modelId: keyof typeof openRouterModels) {
   return openRouterModels[modelId];
 }
📝 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
// Model selector function
export function getOpenRouterModel(modelId: keyof typeof openRouterModels) {
return openRouterModels[modelId];
}
/**
* Retrieves an OpenRouter model instance by its identifier.
* @param modelId - The key of the model in the openRouterModels registry
* @returns The configured OpenRouter model instance
* @example
* const model = getOpenRouterModel('anthropicClaudeSonnet45');
*/
export function getOpenRouterModel(modelId: keyof typeof openRouterModels) {
return openRouterModels[modelId];
}
🤖 Prompt for AI Agents
In src/mastra/config/openrouter.ts around lines 314 to 317, the
getOpenRouterModel function is missing a TSDoc comment; add a TSDoc block above
the function that documents the function purpose, includes a @param tag
describing the modelId parameter (that it is a key of openRouterModels) and a
@returns tag describing the returned model (the corresponding entry from
openRouterModels or undefined if not found), and ensure the description is
concise and follows existing project TSDoc style.

Comment on lines +8 to +11
export type SubscriptionTier = 'free' | 'pro' | 'enterprise'

export type SupabaseRole = 'anon' | 'authenticated' | 'admin' | 'moderator' | 'user'

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

Align SupabaseRole and role levels with the actual hierarchy

SupabaseRole is declared as:

export type SupabaseRole = 'anon' | 'authenticated' | 'admin' | 'moderator' | 'user'

but:

  • ROLE_HIERARCHY and ROLE_LEVELS include service_role, enterprise, pro, and free.
  • There is no user entry anywhere in the hierarchy or RLS helpers.
  • Docs in AGENTS.md call out service_role explicitly as a supported role.

To avoid type drift and confusion, consider either:

  • Expanding SupabaseRole to include all actual Supabase / app roles used here (e.g. 'service_role' | 'anon' | 'authenticated' | 'admin' | 'moderator'), and introducing a separate type for subscription tiers, or
  • Removing/renaming SupabaseRole if it’s not actually used, and replacing it with more precise types for “auth roles” vs “subscription tiers”.

Right now the exported type does not accurately describe the role set this module models.

Also applies to: 16-36, 41-50

Comment on lines 84 to +98
/**
* Get all roles that inherit from a specific role
* @param targetRole The role to find inheritors for
* @returns Array of roles that can access the target role
* Check if a user role has access to a required role
*/
export function hasRoleAccess(userRole: string, requiredRole: string): boolean {
if (userRole === requiredRole) {
return true
}

if (!(userRole in ROLE_HIERARCHY)) {
return false
}

const inheritedRoles = ROLE_HIERARCHY[userRole]
return inheritedRoles.includes(requiredRole)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

hasRoleAccess only checks direct inheritance; confirm if transitive access is required

hasRoleAccess currently returns true only when:

  • userRole === requiredRole, or
  • requiredRole is directly listed in ROLE_HIERARCHY[userRole].

It does not traverse multiple inheritance levels. For example, with the current hierarchy:

  • service_roleadmin, authenticated, anon
  • adminmoderator, authenticated, anon

hasRoleAccess('service_role', 'moderator') will return false, even though service_role > admin > moderator in the conceptual hierarchy.

If you intend roles to inherit transitively (which is typical for RBAC), this function should walk the hierarchy (e.g., via BFS/DFS) until it finds requiredRole or exhausts ancestors. If one-step inheritance is intentional, consider documenting that explicitly to avoid surprises when the helper is used for access checks.

🤖 Prompt for AI Agents
In src/mastra/config/role-hierarchy.ts around lines 84 to 98, hasRoleAccess only
checks direct inheritance and must be updated to support transitive role
inheritance: implement a traversal (BFS or DFS) starting from userRole that
walks ROLE_HIERARCHY until requiredRole is found, keeping a visited set to avoid
cycles, returning true if requiredRole is encountered and false when traversal
completes; also keep the current direct-equality and missing-userRole checks,
and add a small comment noting transitive lookup behavior.

Comment on lines +118 to 140
export interface TierConfig {
maxRequests: number
features: string[]
supportLevel: 'community' | 'email' | 'priority' | 'phone_24x7'
customIntegrations: boolean
advancedAnalytics: boolean
whiteLabel: boolean
onPremise: boolean
rlsPolicy: string
}

export const TIER_QUOTAS: Record<SubscriptionTier, TierQuota> = {
export const TIER_CONFIGS: Record<SubscriptionTier, TierConfig> = {
free: {
maxDocuments: 500,
maxApiRequestsPerDay: 50,
maxUsersPerTenant: 1,
features: ['basic-rag', 'basic-search', 'public-docs'],
supportLevel: 'community',
customIntegrations: false,
advancedAnalytics: false,
whiteLabel: false,
onPremise: false,
maxRequests: 100,
features: ['basic-chat', 'public-docs'],
rlsPolicy: RLS_POLICIES.publicRead,
},
pro: {
maxDocuments: 50000,
maxApiRequestsPerDay: 10000,
maxUsersPerTenant: -1, // unlimited
features: [
'basic-rag',
'basic-search',
'advanced-search',
'public-docs',
'internal-docs',
'ai-insights',
'advanced-analytics',
'custom-integrations',
'api-access',
'priority-support',
],
supportLevel: 'priority',
customIntegrations: true,
advancedAnalytics: true,
whiteLabel: false,
onPremise: false,
maxRequests: 10000,
features: ['advanced-chat', 'private-docs', 'api-access'],
rlsPolicy: RLS_POLICIES.proFeatures,
},
enterprise: {
maxDocuments: -1, // unlimited
maxApiRequestsPerDay: -1, // unlimited
maxUsersPerTenant: -1, // unlimited
features: [
'basic-rag',
'basic-search',
'advanced-search',
'public-docs',
'internal-docs',
'confidential-docs',
'ai-insights',
'advanced-analytics',
'custom-workflows',
'custom-integrations',
'api-access',
'white-label',
'on-premise',
'phone-support',
'dedicated-account-manager',
],
supportLevel: 'phone_24x7',
customIntegrations: true,
advancedAnalytics: true,
whiteLabel: true,
onPremise: true,
maxRequests: -1, // unlimited
features: ['unlimited-chat', 'all-docs', 'custom-models', 'admin-panel'],
rlsPolicy: RLS_POLICIES.enterpriseFeatures,
},
}
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 | 🟠 Major

Clarify tier–role mapping in getTierForRole / getRLSPolicyForRole to avoid misconfigured RLS

getTierForRole only distinguishes 'enterprise', 'pro', and 'free'; all other roles (including service_role, admin, moderator, authenticated, anon) fall through to 'free':

export function getTierForRole(role: string): SubscriptionTier {
  if (role === 'enterprise') return 'enterprise'
  if (role === 'pro') return 'pro'
  if (role === 'free') return 'free'
  return 'free'
}

getRLSPolicyForRole then derives the policy solely from this tier:

export function getRLSPolicyForRole(role: string): string {
  const tier = getTierForRole(role)
  return TIER_CONFIGS[tier].rlsPolicy
}

This means:

  • getRLSPolicyForRole('service_role') and getRLSPolicyForRole('admin') both currently resolve to the free tier’s rlsPolicy (backed by RLS_POLICIES.publicRead/'anon'), even though RLS_POLICIES defines stronger policies like serviceOnly and adminOnly.

If these helpers are used to drive RLS policy selection, that behavior is likely unintended and could lead to confusing or incorrect policy mapping.

Consider either:

  • Making getRLSPolicyForRole explicitly handle privileged roles (e.g., service_roleRLS_POLICIES.serviceOnly, adminRLS_POLICIES.adminOnly), or
  • Narrowing the function to only accept SubscriptionTier (or a dedicated “tier role” type), leaving Supabase/auth roles to be mapped via a different helper.

Right now, the generic role: string signature combined with a tier-only switch makes it easy to misuse this in RLS configuration.

Also applies to: 159-179

🤖 Prompt for AI Agents
In src/mastra/config/role-hierarchy.ts around lines 118-140 (and apply same
change to lines 159-179), getTierForRole/getRLSPolicyForRole currently treat all
unknown roles as 'free', causing privileged roles (service_role, admin,
moderator, authenticated, anon) to inherit the free-tier RLS policy; explicitly
map those privileged roles to the correct RLS policies (e.g., service_role →
RLS_POLICIES.serviceOnly, admin → RLS_POLICIES.adminOnly, moderator →
appropriate policy, authenticated/anon → publicRead or their intended policies)
in getRLSPolicyForRole, or change the API so getRLSPolicyForRole accepts a
SubscriptionTier only and create a separate helper that maps auth role strings
to tiers/policies; update both functions so privileged roles never fall through
to 'free' and add a small unit test or comment documenting the intended mapping.

Comment on lines +181 to 189
/**
* Check if a user can access a resource based on their role
*/
export function canAccessResource(userRole: string, resourcePolicy: string): boolean {
const userLevel = getRoleLevel(userRole)
const requiredLevel = getRoleLevel(resourcePolicy)

// Check based on role level
switch (tier) {
case 'free':
return roleLevel >= 10
case 'pro':
return roleLevel >= 50
case 'enterprise':
return roleLevel >= 75
default:
return false
}
return userLevel >= requiredLevel
}
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

Clarify what resourcePolicy represents in canAccessResource

canAccessResource compares numeric levels:

const userLevel = getRoleLevel(userRole)
const requiredLevel = getRoleLevel(resourcePolicy)
return userLevel >= requiredLevel

This assumes resourcePolicy is itself a role key from ROLE_LEVELS (e.g., 'pro', 'enterprise', 'service_role'), but the name reads more like a Supabase policy identifier (e.g., 'proFeatures' from RLS_POLICIES).

To avoid misuse:

  • Either tighten the type/signature (e.g., resourceRole: keyof typeof ROLE_LEVELS) and/or
  • Add a small doc comment noting that callers should pass the underlying role (RLS_POLICIES.proFeatures'pro'), not the policy key ('proFeatures').

This makes it clearer how to combine RLS_POLICIES and canAccessResource correctly.

🤖 Prompt for AI Agents
In src/mastra/config/role-hierarchy.ts around lines 181 to 189, the parameter
resourcePolicy is misleadingly named and typed — callers may pass an RLS policy
key (e.g., 'proFeatures') instead of a role key from ROLE_LEVELS, causing silent
misuse; change the parameter name to resourceRole and tighten its type to keyof
typeof ROLE_LEVELS (or otherwise document it) and add a short doc comment
stating callers must pass the underlying role key (e.g.,
RLS_POLICIES.proFeatures -> 'pro'), and also add a runtime guard that throws or
returns false if getRoleLevel returns undefined to fail loudly on invalid
inputs.

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 pull request implements a comprehensive refactoring and expansion of the Mastra configuration system, including:

Purpose: Modernize the configuration architecture to support multiple AI providers with a unified interface, align with Supabase authentication patterns, and prepare for future model expansions.

Key Changes:

  1. Role hierarchy refactor: Simplified RBAC system with Supabase-compatible roles (anon, authenticated, admin, service_role) and subscription tiers (free, pro, enterprise)
  2. Provider consolidation: Refactored all AI provider configs (Google, OpenAI, Anthropic, etc.) to use consistent patterns with model collections and selector functions
  3. New integrations: Added GitHub Copilot, Claude Code, and AI Gateway providers with comprehensive model support

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/mastra/config/tracing.ts Minor formatting cleanup - moved BaseAISpan import, removed trailing whitespace
src/mastra/config/role-hierarchy.ts Major refactor to Supabase-compatible RBAC with simplified role hierarchy and subscription tiers
src/mastra/config/processors.ts Deleted entire file (584 lines removed) - processor implementations removed
src/mastra/config/openrouter.ts Added 300+ lines of model configurations with reasoning support for 50+ models across providers
src/mastra/config/openai.ts Refactored to use model collections pattern with GPT-4/5 series models
src/mastra/config/google.ts Reorganized into separate collections for chat, image, and embedding models
src/mastra/config/github-copilot.ts New file - GitHub Copilot integration with 20+ model configurations
src/mastra/config/gemini-cli.ts Refactored into organized model collections with audio/video support
src/mastra/config/claude-code.ts New file - Claude Code CLI provider integration
src/mastra/config/anthropic.ts Refactored to model collections pattern with Claude 3.5/4.x series
src/mastra/config/ai-gateway.ts New file - Unified AI Gateway integration with dynamic model discovery
src/mastra/config/index.ts Added exports for new providers (github-copilot, gemini-cli, ai-gateway, claude-code)
src/mastra/config/README.md Comprehensive documentation rewrite with architecture overview and usage examples
src/mastra/config/AGENTS.md Updated to reflect new providers, roles, and environment variables
package.json Added dependencies for github-copilot and claude-code providers
package-lock.json Dependency lock updates including @anthropic-ai/claude-agent-sdk
app/chat/config/openrouter-models.ts Added GPT OSS 20B free model configuration
.env.example Added AI_GATEWAY_API_KEY (incomplete comment)
.agent/rules/conventions.md Removed duplicate RuntimeContext import
Comments suppressed due to low confidence (3)

src/mastra/config/AGENTS.md:153

  • The changelog shows dates of 2025-12-08, 2025-11-26, 2025-10-15, 2025-10-08, and 2025-09-24, which are all in the future (current date is December 8, 2024, and the knowledge cutoff is January 2025). These should be corrected to use 2024 instead of 2025 for the year.
| 2.3.0   | 2025-12-08 | Added AI Gateway provider for unified multi-provider access |
| 2.2.1   | 2025-12-08 | Fixed database environment variables (SUPABASE instead of PG_CONNECTION) |
| 2.1.0   | 2025-12-08 | Added GitHub Copilot, updated all providers, comprehensive model coverage |
| 2.0.0   | 2025-11-26 | Major update: added all providers, env vars documented  |
| 1.2.0   | 2025-10-15 | Enhanced pg-storage.ts description                      |
| 1.1.0   | 2025-10-08 | Verified content accuracy and updated metadata.         |
| 1.0.0   | 2025-09-24 | Standardized template applied                           |

src/mastra/config/claude-code.ts:2

  • Unused import logError.
import { logError } from './logger'

src/mastra/config/github-copilot.ts:2

  • Unused import logError.
import { logError } from './logger';

import { AISpanType, InternalSpans } from "@mastra/core/ai-tracing";
import type { RuntimeContext } from "@mastra/core/runtime-context";
import { log } from "../config/logger";
import type { RuntimeContext } from '@mastra/core/runtime-context'
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Duplicate import statement. The line import type { RuntimeContext } from '@mastra/core/runtime-context' appears at both line 22 and line 23. One of these should be removed to avoid confusion and maintain clean code.

Suggested change
import type { RuntimeContext } from '@mastra/core/runtime-context'
import type { RuntimeContext } from '@mastra/core/runtime-context';

Copilot uses AI. Check for mistakes.
// @ts-expect-error - traceMap is protected in base class but we need to check it
const traceMap = this.traceMap as Map<string, unknown> | undefined
if (!traceMap || !span.traceId) return
if (!traceMap || !span.traceId) {return}
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

Unnecessary braces around the return statement. The code if (!traceMap || !span.traceId) {return} should be if (!traceMap || !span.traceId) return to maintain consistency with the rest of the codebase and avoid unnecessary syntax.

Suggested change
if (!traceMap || !span.traceId) {return}
if (!traceMap || !span.traceId) return

Copilot uses AI. Check for mistakes.
Comment on lines +186 to 187
const requiredLevel = getRoleLevel(resourcePolicy)

Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The canAccessResource function has flawed logic. It compares userLevel >= requiredLevel, which means users with higher numeric levels can access resources requiring lower levels. However, looking at ROLE_LEVELS, service_role: 1000 is the highest level and anon: 0 is the lowest. This is correct. But the function uses resourcePolicy as input, which would be a string like 'publicRead' from RLS_POLICIES, not a role name. The function should map the policy to a role first:

export function canAccessResource(userRole: string, resourcePolicy: string): boolean {
    const userLevel = getRoleLevel(userRole)
    const policyRole = Object.entries(RLS_POLICIES).find(([, policy]) => policy === resourcePolicy)?.[1] ?? resourcePolicy
    const requiredLevel = getRoleLevel(policyRole)
    
    return userLevel >= requiredLevel
}
Suggested change
const requiredLevel = getRoleLevel(resourcePolicy)
// Map resourcePolicy to the required role by searching TIER_CONFIGS
const policyRole = Object.entries(TIER_CONFIGS).find(([, config]) => config.rlsPolicy === resourcePolicy)?.[0] ?? resourcePolicy
const requiredLevel = getRoleLevel(policyRole)

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +7
// Load environment variables
dotenv.config();

Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The dotenv.config() call on line 6 is unnecessary in config files. Environment variables should be loaded once at the application entry point, not in individual configuration modules. This could lead to redundant file reads and potential conflicts.

Suggested change
// Load environment variables
dotenv.config();

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +25
// Claude 4.1 Opus (most capable)
claudeOpus: claudeCodeProvider('opus'),
// Claude 4.5 Sonnet (balanced performance)
claudeSonnet: claudeCodeProvider('sonnet'),
// Claude 4.5 Haiku (fastest, most cost-effective)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The comments describe the models using version numbers that don't match the actual model IDs. For example, line 21 says "Claude 4.1 Opus" but the model ID is just 'opus', and line 23 says "Claude 4.5 Sonnet" but the model ID is 'sonnet'. These comments are misleading. Consider either updating the comments to match the actual Claude Code CLI naming convention, or clarifying that these are shorthand identifiers that map to specific versions.

Suggested change
// Claude 4.1 Opus (most capable)
claudeOpus: claudeCodeProvider('opus'),
// Claude 4.5 Sonnet (balanced performance)
claudeSonnet: claudeCodeProvider('sonnet'),
// Claude 4.5 Haiku (fastest, most cost-effective)
// 'opus' model ID (Claude Code CLI). Currently maps to Claude Opus (most capable).
claudeOpus: claudeCodeProvider('opus'),
// 'sonnet' model ID (Claude Code CLI). Currently maps to Claude Sonnet (balanced performance).
claudeSonnet: claudeCodeProvider('sonnet'),
// 'haiku' model ID (Claude Code CLI). Currently maps to Claude Haiku (fastest, most cost-effective).

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +3
import { logError } from './logger'

Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The logError import is unused in this file. It should be removed to keep imports clean.

Suggested change
import { logError } from './logger'

Copilot uses AI. Check for mistakes.

```env
# Database
SUPABASE=postgres://user:password@localhost:5432/mastra
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The environment variable name SUPABASE is misleading. Based on the AGENTS.md file showing PG_CONNECTION was used previously, and the fact that this appears to be a PostgreSQL connection string (not Supabase-specific), a more accurate name would be DATABASE_URL or PG_CONNECTION_STRING. If the codebase actually uses SUPABASE as the variable name, this should be clarified in the documentation to explain why a generic PostgreSQL connection uses this name.

Suggested change
SUPABASE=postgres://user:password@localhost:5432/mastra
DATABASE_URL=postgres://user:password@localhost:5432/mastra

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +63

BaseAISpan} from '@mastra/core/ai-tracing'
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The import statement formatting is inconsistent. BaseAISpan should be moved to line 62 with a trailing comma to maintain consistency with the rest of the import block.

Suggested change
BaseAISpan} from '@mastra/core/ai-tracing'
BaseAISpan,
} from '@mastra/core/ai-tracing'

Copilot uses AI. Check for mistakes.
}

const inheritedRoles = ROLE_HIERARCHY[userRole]
return inheritedRoles.includes(requiredRole)
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The hasRoleAccess function only checks direct inheritance (one level deep). It does not recursively check transitive role inheritance. For example, if 'admin' inherits 'moderator', and 'moderator' inherits 'authenticated', then hasRoleAccess('admin', 'authenticated') would return false even though admin should have authenticated access through the hierarchy. Consider implementing recursive checking to properly handle multi-level inheritance:

export function hasRoleAccess(userRole: string, requiredRole: string): boolean {
    if (userRole === requiredRole) {
        return true
    }
    
    if (!(userRole in ROLE_HIERARCHY)) {
        return false
    }
    
    const inheritedRoles = ROLE_HIERARCHY[userRole]
    if (inheritedRoles.includes(requiredRole)) {
        return true
    }
    
    // Check transitive inheritance
    return inheritedRoles.some(role => hasRoleAccess(role, requiredRole))
}
Suggested change
return inheritedRoles.includes(requiredRole)
if (inheritedRoles.includes(requiredRole)) {
return true
}
// Recursively check transitive inheritance
return inheritedRoles.some(role => hasRoleAccess(role, requiredRole))

Copilot uses AI. Check for mistakes.
return 'enterprise'
if (role === 'free') {
return 'free'
}
Copy link

Copilot AI Dec 8, 2025

Choose a reason for hiding this comment

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

The getTierForRole function only handles subscription tier roles ('enterprise', 'pro', 'free'), but not other roles like 'admin', 'moderator', 'authenticated', or 'anon'. When called with any of these roles, it will always return 'free' as the default. This could lead to incorrect tier assignments. Consider either:

  1. Documenting that this function only works with subscription tier roles, or
  2. Adding logic to handle all role types:
export function getTierForRole(role: string): SubscriptionTier {
    // Subscription tier roles
    if (role === 'enterprise') return 'enterprise'
    if (role === 'pro') return 'pro'
    if (role === 'free') return 'free'
    
    // Non-subscription roles - map to appropriate tier
    if (role === 'admin' || role === 'service_role') return 'enterprise'
    if (role === 'moderator') return 'pro'
    
    // Default for authenticated/anon
    return 'free'
}
Suggested change
}
}
// Non-subscription roles - map to appropriate tier
if (role === 'admin' || role === 'service_role') {
return 'enterprise'
}
if (role === 'moderator') {
return 'pro'
}
// Default for authenticated/anon and any unknown role

Copilot uses AI. Check for mistakes.
@ssdeanx ssdeanx merged commit 2fc0302 into main Dec 8, 2025
321 of 323 checks passed
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