Skip to content

feat: add max tokens param for ai generation#44

Open
elliot14A wants to merge 1 commit intomainfrom
feat/max-tokens-param
Open

feat: add max tokens param for ai generation#44
elliot14A wants to merge 1 commit intomainfrom
feat/max-tokens-param

Conversation

@elliot14A
Copy link
Copy Markdown
Contributor

@elliot14A elliot14A commented Dec 31, 2025

Summary by CodeRabbit

Release Notes

  • New Features
    • Added optional maximum token limit parameter to all AI-powered features, allowing users to constrain response length for SQL generation, chat interactions, and data descriptions.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 31, 2025

📝 Walkthrough

Walkthrough

This pull request adds an optional maxTokens *int parameter to AI service methods across the repository, service, and infrastructure layers, then threads it through HTTP request handlers to enable token-limited API responses.

Changes

Cohort / File(s) Summary
Repository Layer
server/application/repositories/ai.go
Added maxTokens *int parameter to 5 methods: GenerateSql, GenerateColumnDescriptions, GenerateDatasetDescription, GenerateChatResponse, GenerateTitle.
Service Layer (AI Driver)
server/application/services/ai.go
Updated 3 public methods to accept maxTokens *int: GenerateSql, GenerateColumnDescriptions, GenerateDatasetDescription. Parameter propagated to repository calls.
Service Layer (Chat)
server/application/services/chat.go
Added maxTokens *int parameter to D_ChatWithAi and CreateChat methods; parameter passed to GenerateChatResponse and GenerateTitle calls.
Infrastructure (OpenAI Client)
server/infrastructure/openai/openai.go
Added maxTokens *int parameter to 8 methods: GenerateResponseJSON, GenerateResponseString, GenerateChatResponseFunc, GenerateSql, GenerateTitle, GenerateColumnDescriptions, GenerateDatasetDescription, GenerateChatResponse. Sets MaxTokens field on openai.ChatCompletionRequest when provided.
HTTP Routes (AI Endpoints)
server/interfaces/http/routes/api/ai/columns.go, server/interfaces/http/routes/api/nl2sql.go
Added MaxTokens *int field to request bodies (genColumnsDescBody, genDatasetDescBody, nl2SqlRequest). Updated service calls to pass body.MaxTokens.
HTTP Routes (Chat Endpoints)
server/interfaces/http/routes/api/chats/create.go, server/interfaces/http/routes/api/chats/create_chat.go
Added MaxTokens *int field to createChatRequestBody. Updated CreateChat call to pass maxTokens parameter in new-chat branch.
HTTP Routes (Database Source)
server/interfaces/http/routes/source/database/create.go
Added MaxTokens *int field to createRequestBody. Updated calls to GenerateColumnDescriptions and GenerateDatasetDescription to include maxTokens parameter.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A token limit now adorns our flow,
Through layers deep, the maxTokens go,
From HTTP's request to OpenAI's door,
We bound our words like never before!
✨ Control at last, the rabbit says with cheer!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add max tokens param for ai generation' accurately describes the main change: adding a maxTokens parameter throughout the AI-related methods across repositories, services, and HTTP handlers.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@claude
Copy link
Copy Markdown

claude Bot commented Dec 31, 2025

Claude finished @elliot14A's task —— View job


Pull Request Review: Max Tokens Parameter for AI Generation

I've completed my comprehensive review of this PR that adds max tokens parameter support across the AI generation system. Here's my detailed feedback:

Review Checklist:

  • Read repository guidelines (CLAUDE.md)
  • Analyze changed files and implementation approach
  • Check code quality and best practices
  • Identify potential bugs or issues
  • Evaluate performance considerations
  • Assess security concerns
  • Review test coverage
  • Provide constructive feedback

Summary

This PR successfully adds maxTokens parameter support across the AI generation pipeline, from HTTP endpoints to the OpenAI client. The implementation is well-structured and follows consistent patterns throughout the codebase.

Code Quality & Best Practices ✅

Strengths:

  • Consistent API design: All endpoints properly accept optional maxTokens parameter
  • Type safety: Uses *int for optional parameter, allowing nil values for default behavior
  • Proper layering: Changes flow correctly through all architectural layers (HTTP → Services → Repositories → Infrastructure)
  • Good documentation: OpenAPI/Swagger docs updated with examples
  • Logging: Appropriate debug logging in OpenAI client methods

Suggestions:

  • Consider adding validation for maxTokens ranges (e.g., minimum 1, reasonable maximum)
  • The hardcoded character limits in GenerateDatasetDescription (950 chars) should be configurable

Potential Issues 🔍

  1. Missing Input Validation (server/interfaces/http/routes/api/ai/columns.go:43):

    // Should add validation
    if body.MaxTokens != nil && *body.MaxTokens <= 0 {
        return fiber.NewError(fiber.StatusBadRequest, "maxTokens must be positive")
    }
  2. Inconsistent Parameter Handling (server/interfaces/http/routes/api/chats/create.go:345-348):

    var maxTokens *int
    if body.MaxTokens > 0 {  // This should check for nil first
        maxTokens = &body.MaxTokens
    }

    Should be:

    var maxTokens *int
    if body.MaxTokens != nil && *body.MaxTokens > 0 {
        maxTokens = body.MaxTokens
    }
  3. Type Mismatch (server/interfaces/http/routes/api/chats/create_chat.go:18):

    MaxTokens *int `json:"maxTokens,omitempty" example:"1000"`

    vs (server/interfaces/http/routes/api/chats/create.go:29):

    MaxTokens int `json:"max_tokens" validate:"omitempty"`

    Should use consistent field names and types across endpoints.

Performance Considerations 📈

  • Positive Impact: Token limits will help control OpenAI API costs and response times
  • Consideration: No caching layer for AI responses - consider implementing for frequently requested content
  • Recommendation: Add metrics/logging for token usage to monitor API costs

Security Concerns 🔒

Good practices:

  • No hardcoded API keys or sensitive information
  • Proper input validation and error handling
  • Uses pointer types to distinguish between zero values and nil

Recommendations:

  • Add rate limiting considerations for AI endpoints
  • Consider implementing maximum token limits per user/organization level
  • Log token usage for audit trails

Test Coverage 📋

Missing Coverage:

  • No unit tests found for the new maxTokens parameter functionality
  • Integration tests needed for end-to-end token limiting behavior
  • Edge case testing (negative values, extremely large values)

Recommendations:

# Should add tests for:
go test ./server/infrastructure/openai/... -v
go test ./server/application/services/... -v  
go test ./server/interfaces/http/routes/... -v

Technical Debt & Improvements 🔧

  1. Magic Numbers: The 950-character limit in GenerateDatasetDescription should be configurable
  2. Error Handling: Consider more specific error messages for token-related failures
  3. Documentation: Add inline comments explaining token limit behavior
  4. Consistency: Standardize field naming (maxTokens vs max_tokens) across all endpoints

Architecture Assessment ⭐

Excellent architectural decisions:

  • Clean separation of concerns across layers
  • Consistent parameter threading through all tiers
  • Proper use of Go's optional parameter patterns with pointers
  • Good OpenAPI documentation

Final Verdict

This is a solid implementation that adds valuable functionality for controlling AI response length and costs. The code quality is good, follows existing patterns, and maintains the clean architecture.

Required Before Merge:

  1. Fix the type inconsistency in create.go:345-348
  2. Add input validation for maxTokens parameters
  3. Standardize field naming across endpoints
  4. Add basic unit tests for the new parameter

Recommended Improvements:

  1. Add integration tests
  2. Implement token usage logging/metrics
  3. Make character limits configurable
  4. Add rate limiting considerations

Overall Rating: 8/10 - Well-implemented feature with minor issues that should be addressed before merging.


Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
server/infrastructure/openai/openai.go (2)

89-91: Consider validating maxTokens value.

The code correctly checks for nil, but doesn't validate whether the value is positive. Passing zero or negative values to the OpenAI API may cause unexpected behavior or API errors.

🔎 Proposed validation
 	if maxTokens != nil {
+		if *maxTokens <= 0 {
+			return nil, fmt.Errorf("maxTokens must be a positive integer")
+		}
 		req.MaxTokens = *maxTokens
 	}

211-212: Context parameter is ignored.

The ctx parameter is accepted but GenerateChatResponseFunc internally uses context.Background() (line 178). This prevents cancellation and timeout propagation from the caller.

🔎 Proposed fix to propagate context

Update GenerateChatResponseFunc to accept and use a context parameter:

-func (c *OpenAIClient) GenerateChatResponseFunc(userMsg string, prevMsgs []*models.D_ChatMessage, maxTokens *int) (string, error) {
+func (c *OpenAIClient) GenerateChatResponseFunc(ctx context.Context, userMsg string, prevMsgs []*models.D_ChatMessage, maxTokens *int) (string, error) {
     // ... existing code ...
-    ctx := context.Background()
     req := openai.ChatCompletionRequest{

Then update the call site:

 func (c *OpenAIClient) GenerateChatResponse(ctx context.Context, userMessage string, prevMessages []*models.D_ChatMessage, maxTokens *int) (*models.D_AiChatResponse, error) {
-	resp, err := c.GenerateChatResponseFunc(userMessage, prevMessages, maxTokens)
+	resp, err := c.GenerateChatResponseFunc(ctx, userMessage, prevMessages, maxTokens)
server/interfaces/http/routes/api/chats/create.go (1)

25-30: Inconsistent field type and JSON tag.

The MaxTokens field in chatWithAgentRequestBody uses int with "max_tokens" JSON tag, while all other request bodies in this PR use *int with "maxTokens" tag. This creates API inconsistency.

Consider aligning with the pattern used elsewhere in this PR for consistency:

 type chatWithAgentRequestBody struct {
 	Messages    []models.AIChatMessage `json:"messages" validate:"required,dive"`
 	Stream      bool                   `json:"stream" validate:"omitempty" default:"true"`
 	Temperature float64                `json:"temperature" validate:"omitempty"`
-	MaxTokens   int                    `json:"max_tokens" validate:"omitempty"`
+	MaxTokens   *int                   `json:"maxTokens,omitempty" example:"1000"`
 }

Note: This would be a breaking change if clients already use max_tokens. If backward compatibility is needed, consider accepting both.

server/application/repositories/ai.go (1)

9-13: Good use of pointer type for optional parameter.

The addition of maxTokens *int as an optional parameter is idiomatic Go. The pointer type correctly allows nil to represent "use default behavior," and the consistent placement as the last parameter across all methods maintains good API ergonomics.

Consider adding documentation comments to clarify the behavior when maxTokens is nil vs. when a specific value is provided:

// AiRepository defines AI operations for data analysis and SQL generation.
type AiRepository interface {
	// GenerateSql converts natural language to SQL.
	// If maxTokens is nil, the default token limit is used.
	GenerateSql(nl string, maxTokens *int) (string, error)
	// ... similar comments for other methods
}
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbf7dfd and 242682c.

📒 Files selected for processing (9)
  • server/application/repositories/ai.go
  • server/application/services/ai.go
  • server/application/services/chat.go
  • server/infrastructure/openai/openai.go
  • server/interfaces/http/routes/api/ai/columns.go
  • server/interfaces/http/routes/api/chats/create.go
  • server/interfaces/http/routes/api/chats/create_chat.go
  • server/interfaces/http/routes/api/nl2sql.go
  • server/interfaces/http/routes/source/database/create.go
🧰 Additional context used
🧬 Code graph analysis (2)
server/application/services/chat.go (2)
server/infrastructure/postgres/gen/chats.sql.go (1)
  • CreateChatParams (44-49)
web/src/lib/api-client.ts (1)
  • ChatWithMessages (139-141)
server/interfaces/http/routes/api/chats/create.go (1)
server/infrastructure/postgres/gen/chats.sql.go (1)
  • CreateChatParams (44-49)
⏰ 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: claude-review
  • GitHub Check: Analyze (go)
🔇 Additional comments (18)
server/infrastructure/openai/openai.go (1)

68-117: LGTM on the generic JSON response function.

The GenerateResponseJSON function correctly handles the optional maxTokens parameter with proper nil-checking, and the implementation maintains backward compatibility when maxTokens is not provided.

server/interfaces/http/routes/api/chats/create_chat.go (2)

14-19: LGTM on the request body extension.

The MaxTokens field is correctly added as an optional pointer type with appropriate JSON tag and swagger documentation.


82-91: LGTM on propagating maxTokens to service.

The body.MaxTokens is correctly passed through to CreateChat. The nil-pointer handling is delegated to the service layer appropriately.

server/interfaces/http/routes/api/nl2sql.go (2)

17-24: LGTM on the NL2SQL request extension.

The MaxTokens field is correctly added with consistent naming and documentation.


125-133: LGTM on passing maxTokens to AI service.

The parameter is correctly threaded through to the AI service call.

server/application/services/chat.go (3)

97-110: LGTM on CreateChat signature update.

The maxTokens parameter is correctly added and handled. The empty messages case (lines 102-110) doesn't require AI generation, so not passing maxTokens there is appropriate.


128-140: LGTM on GenerateTitle call with maxTokens.

The maxTokens parameter is correctly passed to GenerateTitle for title generation, with appropriate fallback handling when AI fails.


50-57: Pre-existing issue: prevMsgs is always empty.

The prevMsgs variable is initialized as an empty PaginationView (line 52) and passed directly to GenerateChatResponse (line 54) without ever being populated. This means previous conversation history is never included in the AI context when generating responses.

This appears to be a pre-existing issue unrelated to the maxTokens changes introduced in this PR.

server/interfaces/http/routes/api/ai/columns.go (4)

10-18: LGTM on genColumnsDescBody extension.

The MaxTokens field is correctly added with consistent naming and documentation.


43-47: LGTM on GenerateColumnDescriptions call.

The body.MaxTokens is correctly passed to the service.


54-68: LGTM on genDatasetDescBody extension.

The MaxTokens field is correctly added, consistent with the other request body struct.


90-101: LGTM on GenerateDatasetDescription call.

The body.MaxTokens is correctly passed as the last parameter.

server/interfaces/http/routes/api/chats/create.go (1)

344-354: LGTM on the maxTokens handling for new chat creation.

The conversion from int to *int correctly handles the zero-value case by only setting maxTokens when body.MaxTokens > 0.

server/interfaces/http/routes/source/database/create.go (3)

64-86: LGTM on the request body extension.

The MaxTokens field is correctly added with consistent naming, type, and documentation matching other endpoints.


215-224: LGTM on GenerateColumnDescriptions call.

The body.MaxTokens is correctly passed to the service.


235-247: LGTM on GenerateDatasetDescription call.

The body.MaxTokens is correctly passed as the last parameter.

server/application/services/ai.go (1)

17-27: LGTM on AiDriver method updates.

All three methods are consistently updated to accept and pass through the maxTokens parameter. The implementation is straightforward.

Note: Using context.Background() prevents context propagation from HTTP handlers. Consider accepting context as a parameter for cancellation support in a future iteration.

server/application/repositories/ai.go (1)

15-18: Consistent design across both interfaces.

The AiChatRepository interface follows the same pattern as AiRepository, maintaining consistency throughout the file.

Comment on lines 9 to 18
type AiRepository interface {
GenerateSql(nl string) (string, error)
GenerateColumnDescriptions(ctx context.Context, rows string, summary string) (map[string]string, error)
GenerateDatasetDescription(ctx context.Context, datasetName string, columnNames []string, columnDescriptions map[string]string, rows string, summary string) (string, error)
GenerateSql(nl string, maxTokens *int) (string, error)
GenerateColumnDescriptions(ctx context.Context, rows string, summary string, maxTokens *int) (map[string]string, error)
GenerateDatasetDescription(ctx context.Context, datasetName string, columnNames []string, columnDescriptions map[string]string, rows string, summary string, maxTokens *int) (string, error)
}

type AiChatRepository interface {
GenerateChatResponse(ctx context.Context, userMessage string, prevMessage []*models.D_ChatMessage) (*models.D_AiChatResponse, error)
GenerateTitle(ctx context.Context, userMessage string) (*models.D_AiChatResponse, error)
GenerateChatResponse(ctx context.Context, userMessage string, prevMessage []*models.D_ChatMessage, maxTokens *int) (*models.D_AiChatResponse, error)
GenerateTitle(ctx context.Context, userMessage string, maxTokens *int) (*models.D_AiChatResponse, error)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find implementations of AiRepository and AiChatRepository interface methods
# Check for GenerateSql, GenerateColumnDescriptions, GenerateDatasetDescription,
# GenerateChatResponse, and GenerateTitle implementations

echo "=== Searching for GenerateSql implementations ==="
rg "func.*GenerateSql" --type go -A 2

echo -e "\n=== Searching for GenerateColumnDescriptions implementations ==="
rg "func.*GenerateColumnDescriptions" --type go -A 2

echo -e "\n=== Searching for GenerateDatasetDescription implementations ==="
rg "func.*GenerateDatasetDescription" --type go -A 2

echo -e "\n=== Searching for GenerateChatResponse implementations ==="
rg "func.*GenerateChatResponse" --type go -A 2

echo -e "\n=== Searching for GenerateTitle implementations ==="
rg "func.*GenerateTitle" --type go -A 2

Repository: factly/gopie

Length of output: 3439


🏁 Script executed:

#!/bin/bash
# Search specifically for AiDriver implementations
echo "=== All GenerateChatResponse methods ==="
rg "GenerateChatResponse" --type go -B 1 -A 3

echo -e "\n=== All GenerateTitle methods ==="
rg "GenerateTitle" --type go -B 1 -A 3

Repository: factly/gopie

Length of output: 3669


🏁 Script executed:

cat -n server/application/services/ai.go

Repository: factly/gopie

Length of output: 1139


Fix critical signature mismatches in AiDriver implementations and add missing AiChatRepository methods.

The interface definitions were updated but the AiDriver wrapper implementation in server/application/services/ai.go has not been fully updated:

  1. Signature mismatch: GenerateColumnDescriptions and GenerateDatasetDescription are missing the ctx context.Context parameter required by the AiRepository interface. These methods pass context.Background() when calling the underlying implementation, but their own signatures don't accept a context parameter.

  2. Missing implementations: GenerateChatResponse and GenerateTitle methods from the AiChatRepository interface are not implemented in AiDriver at all. These are called from server/application/services/chat.go, so the AiDriver must implement them.

Update AiDriver to match both interface signatures exactly and implement all required methods from both AiRepository and AiChatRepository interfaces.

🤖 Prompt for AI Agents
In server/application/repositories/ai.go around lines 9 to 18, the AiRepository
and AiChatRepository signatures were changed but the AiDriver wrapper in
server/application/services/ai.go was not updated: add the missing ctx
context.Context parameter to AiDriver.GenerateColumnDescriptions and
AiDriver.GenerateDatasetDescription so their signatures match the interface and
forward that ctx when calling the underlying implementation (remove hardcoded
context.Background()), and implement the two missing AiChatRepository methods
GenerateChatResponse(ctx context.Context, userMessage string, prevMessage
[]*models.D_ChatMessage, maxTokens *int) and GenerateTitle(ctx context.Context,
userMessage string, maxTokens *int) in AiDriver to delegate to the underlying ai
implementation, passing all parameters and returning its results/errors.

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.

1 participant