-
Notifications
You must be signed in to change notification settings - Fork 8
Link insertion #118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Link insertion #118
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughConsolidates blog-post validation into a new AI-driven validator, adds an internal-links insertion agent, updates agent imports and model defaults, adjusts system prompts, updates schemas and models to track validation state, and applies a database migration to replace legacy validation fields. Changes
Sequence Diagram(s)sequenceDiagram
participant Flow as BlogPostFlow
participant Content as ContentGenAgent
participant Validator as ValidateAgent
participant Inserter as InsertLinksAgent
participant DB as Database
Flow->>Content: Request generated content (no internal links injected)
Content-->>Flow: Raw content
Flow->>Validator: Validate content (completeness, length, placeholders, structure)
alt Validation passes
Validator-->>Flow: is_valid=true, issues=[]
Flow->>Inserter: Insert internal links (must-use & optional pages)
Inserter-->>Flow: Content with links
Flow->>DB: Save post (is_content_valid=true)
DB-->>Flow: Saved
else Validation fails
Validator-->>Flow: is_valid=false, issues=[...]
Flow->>DB: Save validation_issues & increment validation_attempts
DB-->>Flow: Saved
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50–70 minutes Areas requiring extra attention:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some food for thought. View full project report here.
| logger.info( | ||
| "[Generate Content] Attempt %s/%s", | ||
| attempt, | ||
| MAX_ATTEMPTS, | ||
| project_id=self.project.id, | ||
| title=self.title, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| logger.info( | |
| "[Generate Content] Attempt %s/%s", | |
| attempt, | |
| MAX_ATTEMPTS, | |
| project_id=self.project.id, | |
| title=self.title, | |
| ) | |
| logger.info( | |
| "[Generate Content] Attempt %s/%s", | |
| attempt, | |
| MAX_ATTEMPTS, | |
| project_id=self.project_id, | |
| title=self.title, | |
| ) |
| "[Generate Content] Attempt %s/%s", | ||
| attempt, | ||
| MAX_ATTEMPTS, | ||
| project_id=self.project.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.project.id performs a database read when id is evaluated. You could take advantage of Django's caching of related fields by using self.project_id, which does not do a database read. More info.
Greptile OverviewGreptile SummaryThis PR implements a two-phase approach to blog post generation: first generating content without links, then inserting internal links in a separate step using semantic search. Key changes:
Technical improvements:
Confidence Score: 4/5
Important Files ChangedFile Analysis
Sequence DiagramsequenceDiagram
participant User
participant BlogPostTitleSuggestion
participant GenerateContentAgent
participant GeneratedBlogPost
participant ValidationAgent
participant InsertLinksAgent
participant ProjectPage
User->>BlogPostTitleSuggestion: generate_content()
loop MAX_ATTEMPTS=2
BlogPostTitleSuggestion->>GenerateContentAgent: Create agent & generate content
Note over GenerateContentAgent: No project_pages in context<br/>Temperature: 0.6
GenerateContentAgent-->>BlogPostTitleSuggestion: Blog post content (no links)
alt First attempt
BlogPostTitleSuggestion->>GeneratedBlogPost: create_and_validate()
else Retry
BlogPostTitleSuggestion->>GeneratedBlogPost: Update content & save
end
GeneratedBlogPost->>ValidationAgent: run_validation()
ValidationAgent->>ValidationAgent: Check completeness, length,<br/>placeholders, structure, quality
ValidationAgent-->>GeneratedBlogPost: is_valid, validation_issues
alt Content is valid
GeneratedBlogPost->>InsertLinksAgent: insert_internal_links()
GeneratedBlogPost->>ProjectPage: Get must_use_pages (always_use=True)
ProjectPage-->>GeneratedBlogPost: Must-use pages
GeneratedBlogPost->>ProjectPage: Vector similarity search<br/>(top 5 similar pages)
ProjectPage-->>GeneratedBlogPost: Optional pages
GeneratedBlogPost->>InsertLinksAgent: Pass content + page contexts
InsertLinksAgent->>InsertLinksAgent: Insert links with<br/>contextual relevance
InsertLinksAgent-->>GeneratedBlogPost: Content with internal links
GeneratedBlogPost->>GeneratedBlogPost: save(update_fields=['content'])
GeneratedBlogPost-->>BlogPostTitleSuggestion: Return valid blog post
else Content invalid & attempts < MAX_ATTEMPTS
Note over BlogPostTitleSuggestion: Retry generation
else Content invalid & attempts == MAX_ATTEMPTS
GeneratedBlogPost-->>BlogPostTitleSuggestion: Return invalid blog post
end
end
BlogPostTitleSuggestion-->>User: Generated blog post
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
11 files reviewed, 2 comments
|
|
||
| return ending_is_valid | ||
|
|
||
| except Exception as error: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Catching bare Exception violates the backend error handling style guide
| except Exception as error: | |
| except (PydanticAIError, ValueError) as error: |
Context Used: Context from dashboard - .cursor/rules/backend-error-handling.mdc (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: core/models.py
Line: 984:984
Comment:
**style:** Catching bare `Exception` violates the backend error handling style guide
```suggestion
except (PydanticAIError, ValueError) as error:
```
**Context Used:** Context from `dashboard` - .cursor/rules/backend-error-handling.mdc ([source](https://app.greptile.com/review/custom-context?memory=9343d853-8bca-46ca-b37d-fd4327d3e3d2))
How can I resolve this? If you propose a fix, please make it concise.| self.fix_header_start() | ||
| return True | ||
|
|
||
| except Exception as error: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Catching bare Exception violates the backend error handling style guide
| except Exception as error: | |
| except (PydanticAIError, ValueError) as error: |
Context Used: Context from dashboard - .cursor/rules/backend-error-handling.mdc (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: core/models.py
Line: 1216:1216
Comment:
**style:** Catching bare `Exception` violates the backend error handling style guide
```suggestion
except (PydanticAIError, ValueError) as error:
```
**Context Used:** Context from `dashboard` - .cursor/rules/backend-error-handling.mdc ([source](https://app.greptile.com/review/custom-context?memory=9343d853-8bca-46ca-b37d-fd4327d3e3d2))
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
core/agents/system_prompts.py (1)
110-119: Fix invalid multi-line f-string expressions.The new f-string inserts newline characters inside the
{…}expression, which Python rejects (SyntaxError: f-string expression part cannot include a newline). Module import will fail until this is corrected. Refactor to compute the values first (or keep the expression on a single line) before interpolating them.- return f""" + target_keywords = ( + ", ".join(title.target_keywords) if title.target_keywords else "None specified" + ) + suggested_meta_description = ( + title.suggested_meta_description or "None specified" + ) + return f""" This is the title suggestion generated by AI using project information: - Title: {title.title} - Description: {title.description} - Category: {title.category} - - Target Keywords: { - ", ".join(title.target_keywords) if title.target_keywords else "None specified" - } - - Suggested Meta Description: { - title.suggested_meta_description if title.suggested_meta_description else "None specified" - } + - Target Keywords: {target_keywords} + - Suggested Meta Description: {suggested_meta_description} """
🧹 Nitpick comments (3)
core/agents/validate_blog_post_agent.py (1)
1-9: UseField(default_factory=list)for mutable default.Avoid sharing the same list instance across models by switching to
Field(default_factory=list)and importingField. Keeps the schema safer and aligns with our Pydantic patterns.-from pydantic import BaseModel +from pydantic import BaseModel, Field @@ -class BlogPostValidationResult(BaseModel): - is_valid: bool - issues: list[str] = [] +class BlogPostValidationResult(BaseModel): + is_valid: bool + issues: list[str] = Field(default_factory=list)core/agents/insert_internal_links_agent.py (1)
51-51: Remove unused# noqa: E501.Ruff reports this suppression as unused; please drop it to keep lint clean.
core/models.py (1)
1197-1197: Remove unused# noqa: E501.This suppression is redundant under the current lint config; please drop it for cleanliness.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
core/agents/__init__.py(2 hunks)core/agents/generate_blog_post_content_agent.py(2 hunks)core/agents/insert_internal_links_agent.py(1 hunks)core/agents/schemas.py(1 hunks)core/agents/system_prompts.py(3 hunks)core/agents/validate_blog_post_agent.py(1 hunks)core/agents/validate_blog_post_ending_agent.py(0 hunks)core/migrations/0043_remove_generatedblogpost_content_too_short_and_more.py(1 hunks)core/models.py(6 hunks)frontend/templates/components/blog_post_validation_warning.html(1 hunks)tuxseo/settings.py(0 hunks)
💤 Files with no reviewable changes (2)
- tuxseo/settings.py
- core/agents/validate_blog_post_ending_agent.py
🧰 Additional context used
📓 Path-based instructions (8)
**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
**/*.py: Prioritize readability and maintainability; follow PEP 8
Use descriptive variable/function names with underscoresIn Python, use try-except blocks that catch specific exception types; do not catch broad Exception.
**/*.py: Follow PEP 8 for Python code style
Use descriptive variable names with underscores (snake_case) in Python
Prefer Django's built-in features over external libraries
**/*.py: Use structlog for logging in Python code (avoid print and the standard logging module)
Include contextual key-value fields in log messages (e.g., error=str(e), exc_info=True, profile_id=profile.id)
**/*.py: Use descriptive, full-word variable names; avoid abbreviations and single-letter variables in Python
Provide context in variable names when format or type matters (e.g., include_iso_format,date)
Extract unchanging values into UPPER_CASE constants
Use intermediary variables to name parsed groups instead of using index access directly
Naming conventions: use is_/has_/can_ for booleans; include 'date' for dates; snake_case for variables/functions; PascalCase for classes
Define variables close to where they are used to keep lifespan short
Name things after what they do, not how they're used; ensure names make sense without extra context
Avoid generic names like data, info, manager; use specific, intention-revealing names
Function names should include necessary context without being verbose
If naming is hard, split functions into smaller focused parts
Maintain consistency: reuse the same verbs and nouns for the same concepts; name variables after the functions that create them
Use more descriptive names for longer-lived variables
Avoid else statements by using guard clauses for early returns
Replace simple conditionals with direct assignment when both branches call the same function with different values
Use dictionaries as dispatch tables instead of multiple equal-probability elif chains
Validate input before processing to prevent errors propagating in...
Files:
core/agents/__init__.pycore/agents/insert_internal_links_agent.pycore/agents/schemas.pycore/agents/validate_blog_post_agent.pycore/agents/generate_blog_post_content_agent.pycore/models.pycore/migrations/0043_remove_generatedblogpost_content_too_short_and_more.pycore/agents/system_prompts.py
core/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
Leverage Django's ORM; avoid raw SQL when possible
Files:
core/agents/__init__.pycore/agents/insert_internal_links_agent.pycore/agents/schemas.pycore/agents/validate_blog_post_agent.pycore/agents/generate_blog_post_content_agent.pycore/models.pycore/migrations/0043_remove_generatedblogpost_content_too_short_and_more.pycore/agents/system_prompts.py
core/agents/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Implement AI agents using pydantic-ai under core/agents/
Files:
core/agents/__init__.pycore/agents/insert_internal_links_agent.pycore/agents/schemas.pycore/agents/validate_blog_post_agent.pycore/agents/generate_blog_post_content_agent.pycore/agents/system_prompts.py
**/*.html
📄 CodeRabbit inference engine (.cursor/rules/frontend.mdc)
**/*.html: Prefer Stimulus JS for adding interactivity to Django templates instead of raw script elements
Leverage Stimulus data attributes to connect HTML elements with JavaScript functionality
Utilize Stimulus targets to reference specific elements within a controller
Employ Stimulus actions to handle user interactions and events
Files:
frontend/templates/components/blog_post_validation_warning.html
**/*.{html,htm}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always generate semantic HTML
Files:
frontend/templates/components/blog_post_validation_warning.html
{**/*.{html,htm,css,scss},**/*_controller.@(js|ts)}
📄 CodeRabbit inference engine (.cursor/rules/ui-ux-design-guidelines.mdc)
Always favor the utility-first Tailwind approach; avoid creating reusable style classes and prefer reuse via template components
Files:
frontend/templates/components/blog_post_validation_warning.html
frontend/templates/**/*.html
📄 CodeRabbit inference engine (.cursor/rules/stimulus-events.mdc)
Avoid data-*-outlet links for sibling controller communication when using the event-based approach; keep controllers self-contained
Use semantic HTML elements (e.g., dialog, details/summary) in templates
Files:
frontend/templates/components/blog_post_validation_warning.html
core/models.py
📄 CodeRabbit inference engine (CLAUDE.md)
core/models.py: Place business logic in Django models (fat models pattern)
Validate simple constraints in the database and place complex domain logic in Django models
Files:
core/models.py
🧠 Learnings (2)
📚 Learning: 2025-10-04T08:52:37.437Z
Learnt from: CR
Repo: rasulkireev/TuxSEO PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T08:52:37.437Z
Learning: Always add AGENTS.md into AI context
Applied to files:
core/agents/__init__.pycore/agents/insert_internal_links_agent.py
📚 Learning: 2025-10-04T08:52:37.437Z
Learnt from: CR
Repo: rasulkireev/TuxSEO PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T08:52:37.437Z
Learning: Applies to core/agents/**/*.py : Implement AI agents using pydantic-ai under core/agents/
Applied to files:
core/agents/validate_blog_post_agent.py
🧬 Code graph analysis (4)
core/agents/__init__.py (2)
core/agents/insert_internal_links_agent.py (1)
create_insert_internal_links_agent(7-85)core/agents/validate_blog_post_agent.py (1)
create_validate_blog_post_agent(12-43)
core/agents/insert_internal_links_agent.py (2)
core/agents/schemas.py (2)
InsertedLinksOutput(293-298)InsertInternalLinksContext(279-290)core/choices.py (1)
get_default_ai_model(136-138)
core/agents/validate_blog_post_agent.py (1)
core/choices.py (1)
get_default_ai_model(136-138)
core/models.py (7)
core/agents/insert_internal_links_agent.py (2)
create_insert_internal_links_agent(7-85)output(82-83)core/agents/schemas.py (4)
BlogPostGenerationContext(182-188)GeneratedBlogPostSchema(191-201)InsertInternalLinksContext(279-290)ProjectPageContext(171-179)core/agents/generate_blog_post_content_agent.py (1)
create_generate_blog_post_content_agent(19-54)core/utils.py (2)
run_agent_synchronously(194-251)get_jina_embedding(144-186)core/agents/validate_blog_post_agent.py (1)
create_validate_blog_post_agent(12-43)core/api/views.py (1)
fix_generated_blog_post(1081-1111)core/agents/content_editor_agent.py (1)
create_content_editor_agent(14-49)
🪛 Ruff (0.14.4)
core/agents/insert_internal_links_agent.py
51-51: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
core/agents/validate_blog_post_agent.py
38-38: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
core/models.py
992-992: Use explicit conversion flag
Replace with conversion flag
(RUF010)
1197-1197: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
1214-1214: Consider moving this statement to an else block
(TRY300)
core/migrations/0043_remove_generatedblogpost_content_too_short_and_more.py
8-10: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
12-44: Mutable class attributes should be annotated with typing.ClassVar
(RUF012)
core/agents/system_prompts.py
22-22: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
| base_logger_info = { | ||
| "blog_post_id": self.id, | ||
| "project_id": self.project_id, | ||
| "project_name": self.project.name, | ||
| "profile_id": self.project.profile.id, | ||
| "profile_email": self.project.profile.user.email, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard validation logging against missing relations.
GeneratedBlogPost.project and Project.profile are nullable, so building base_logger_info this way raises AttributeError when either relation is absent, aborting validation. Please derive these IDs/emails defensively (falling back to None) before logging so the validation run can proceed even when data is partially missing.
- base_logger_info = {
- "blog_post_id": self.id,
- "project_id": self.project_id,
- "project_name": self.project.name,
- "profile_id": self.project.profile.id,
- "profile_email": self.project.profile.user.email,
- }
+ project = self.project
+ profile = project.profile if project else None
+ base_logger_info = {
+ "blog_post_id": self.id,
+ "project_id": project.id if project else None,
+ "project_name": project.name if project else None,
+ "profile_id": profile.id if profile else None,
+ "profile_email": profile.user.email if profile else None,
+ }🤖 Prompt for AI Agents
In core/models.py around lines 936 to 942, building base_logger_info accesses
project, project.name, project.profile and project.profile.user.email directly
which raises AttributeError when those relations are null; change the
construction to derive values defensively (e.g., use local variables with
conditional access or getattr/defaults) so project_id = self.project_id,
project_name = self.project.name if self.project else None, profile_id =
self.project.profile.id if self.project and self.project.profile else None,
profile_email = self.project.profile.user.email if self.project and
self.project.profile and getattr(self.project.profile, "user", None) else None,
and then use those vars in base_logger_info so validation continues when
relations are missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
♻️ Duplicate comments (4)
core/models.py (4)
758-758: Optimize database access by usingself.project_id.Line 758 accesses
self.project.id, which triggers a database read. Useself.project_idinstead to leverage Django's cached foreign key ID.As per coding guidelines.
940-946: Guard validation logging against missing relations.The code directly accesses
self.project.name,self.project.profile.id, andself.project.profile.user.emailwithout checking if these relations exist. This will raiseAttributeErrorifprojectorproject.profileisNone, preventing validation from running.
988-988: Catch specific exception types instead of bareException.Catching bare
Exceptionviolates the error handling guidelines. Use specific exception types likePydanticAIErrororValueError.As per coding guidelines.
1220-1220: Catch specific exception types instead of bareException.Catching bare
Exceptionviolates the error handling guidelines. Consider catching specific exceptions likePydanticAIErrororValueError.As per coding guidelines.
🧹 Nitpick comments (2)
core/models.py (2)
996-996: Use explicit conversion flag in f-string.The static analysis tool correctly identifies that
validation_issuesshould use an explicit conversion flag.Apply this diff:
- self.validation_issues = [f"Validation error: {str(error)}"] + self.validation_issues = [f"Validation error: {error!s}"]
1201-1201: Remove unusednoqadirective.The
# noqa: E501comment is unnecessary as the line length is acceptable or the rule is not enabled.Apply this diff:
- "Please insert internal links into the blog post content where contextually relevant.", # noqa: E501 + "Please insert internal links into the blog post content where contextually relevant.",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
CHANGELOG.md(1 hunks)core/agents/analyze_competitor_agent.py(2 hunks)core/agents/analyze_project_agent.py(2 hunks)core/agents/competitor_vs_blog_post_agent.py(2 hunks)core/agents/content_editor_agent.py(2 hunks)core/agents/extract_competitors_data_agent.py(2 hunks)core/agents/extract_links_agent.py(2 hunks)core/agents/find_competitors_agent.py(2 hunks)core/agents/generate_blog_post_content_agent.py(3 hunks)core/agents/insert_internal_links_agent.py(1 hunks)core/agents/models.py(1 hunks)core/agents/populate_competitor_details_agent.py(2 hunks)core/agents/schemas.py(2 hunks)core/agents/summarize_page_agent.py(2 hunks)core/agents/system_prompts.py(4 hunks)core/agents/title_suggestions_agent.py(3 hunks)core/agents/validate_blog_post_agent.py(1 hunks)core/choices.py(0 hunks)core/models.py(6 hunks)
💤 Files with no reviewable changes (1)
- core/choices.py
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
🧰 Additional context used
📓 Path-based instructions (4)
**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
**/*.py: Prioritize readability and maintainability; follow PEP 8
Use descriptive variable/function names with underscoresIn Python, use try-except blocks that catch specific exception types; do not catch broad Exception.
**/*.py: Follow PEP 8 for Python code style
Use descriptive variable names with underscores (snake_case) in Python
Prefer Django's built-in features over external libraries
**/*.py: Use structlog for logging in Python code (avoid print and the standard logging module)
Include contextual key-value fields in log messages (e.g., error=str(e), exc_info=True, profile_id=profile.id)
**/*.py: Use descriptive, full-word variable names; avoid abbreviations and single-letter variables in Python
Provide context in variable names when format or type matters (e.g., include_iso_format,date)
Extract unchanging values into UPPER_CASE constants
Use intermediary variables to name parsed groups instead of using index access directly
Naming conventions: use is_/has_/can_ for booleans; include 'date' for dates; snake_case for variables/functions; PascalCase for classes
Define variables close to where they are used to keep lifespan short
Name things after what they do, not how they're used; ensure names make sense without extra context
Avoid generic names like data, info, manager; use specific, intention-revealing names
Function names should include necessary context without being verbose
If naming is hard, split functions into smaller focused parts
Maintain consistency: reuse the same verbs and nouns for the same concepts; name variables after the functions that create them
Use more descriptive names for longer-lived variables
Avoid else statements by using guard clauses for early returns
Replace simple conditionals with direct assignment when both branches call the same function with different values
Use dictionaries as dispatch tables instead of multiple equal-probability elif chains
Validate input before processing to prevent errors propagating in...
Files:
core/agents/summarize_page_agent.pycore/agents/analyze_project_agent.pycore/agents/models.pycore/agents/populate_competitor_details_agent.pycore/agents/content_editor_agent.pycore/agents/find_competitors_agent.pycore/agents/analyze_competitor_agent.pycore/models.pycore/agents/validate_blog_post_agent.pycore/agents/schemas.pycore/agents/title_suggestions_agent.pycore/agents/extract_competitors_data_agent.pycore/agents/generate_blog_post_content_agent.pycore/agents/competitor_vs_blog_post_agent.pycore/agents/system_prompts.pycore/agents/extract_links_agent.pycore/agents/insert_internal_links_agent.py
core/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend.mdc)
Leverage Django's ORM; avoid raw SQL when possible
Files:
core/agents/summarize_page_agent.pycore/agents/analyze_project_agent.pycore/agents/models.pycore/agents/populate_competitor_details_agent.pycore/agents/content_editor_agent.pycore/agents/find_competitors_agent.pycore/agents/analyze_competitor_agent.pycore/models.pycore/agents/validate_blog_post_agent.pycore/agents/schemas.pycore/agents/title_suggestions_agent.pycore/agents/extract_competitors_data_agent.pycore/agents/generate_blog_post_content_agent.pycore/agents/competitor_vs_blog_post_agent.pycore/agents/system_prompts.pycore/agents/extract_links_agent.pycore/agents/insert_internal_links_agent.py
core/agents/**/*.py
📄 CodeRabbit inference engine (CLAUDE.md)
Implement AI agents using pydantic-ai under core/agents/
Files:
core/agents/summarize_page_agent.pycore/agents/analyze_project_agent.pycore/agents/models.pycore/agents/populate_competitor_details_agent.pycore/agents/content_editor_agent.pycore/agents/find_competitors_agent.pycore/agents/analyze_competitor_agent.pycore/agents/validate_blog_post_agent.pycore/agents/schemas.pycore/agents/title_suggestions_agent.pycore/agents/extract_competitors_data_agent.pycore/agents/generate_blog_post_content_agent.pycore/agents/competitor_vs_blog_post_agent.pycore/agents/system_prompts.pycore/agents/extract_links_agent.pycore/agents/insert_internal_links_agent.py
core/models.py
📄 CodeRabbit inference engine (CLAUDE.md)
core/models.py: Place business logic in Django models (fat models pattern)
Validate simple constraints in the database and place complex domain logic in Django models
Files:
core/models.py
🧠 Learnings (3)
📚 Learning: 2025-10-04T08:52:58.590Z
Learnt from: CR
Repo: rasulkireev/TuxSEO PR: 0
File: .cursor/rules/agent-rules.mdc:0-0
Timestamp: 2025-10-04T08:52:58.590Z
Learning: Always add AGENTS.md into AI context
Applied to files:
core/agents/summarize_page_agent.pycore/agents/analyze_project_agent.pycore/agents/models.pycore/agents/content_editor_agent.pycore/agents/find_competitors_agent.pycore/agents/title_suggestions_agent.pycore/agents/generate_blog_post_content_agent.pycore/agents/competitor_vs_blog_post_agent.pycore/agents/extract_links_agent.py
📚 Learning: 2025-10-04T08:52:37.437Z
Learnt from: CR
Repo: rasulkireev/TuxSEO PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T08:52:37.437Z
Learning: Applies to core/agents/**/*.py : Implement AI agents using pydantic-ai under core/agents/
Applied to files:
core/agents/summarize_page_agent.pycore/agents/analyze_project_agent.pycore/agents/models.pycore/agents/populate_competitor_details_agent.pycore/agents/content_editor_agent.pycore/agents/find_competitors_agent.pycore/agents/analyze_competitor_agent.pycore/agents/validate_blog_post_agent.pycore/agents/title_suggestions_agent.pycore/agents/extract_competitors_data_agent.pycore/agents/generate_blog_post_content_agent.pycore/agents/competitor_vs_blog_post_agent.pycore/agents/extract_links_agent.py
📚 Learning: 2025-10-05T01:51:48.411Z
Learnt from: CR
Repo: rasulkireev/TuxSEO PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-05T01:51:48.411Z
Learning: Applies to **/*.py : Handle errors at the source and return safe defaults instead of propagating exceptions
Applied to files:
core/models.py
🧬 Code graph analysis (15)
core/agents/summarize_page_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/analyze_project_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/populate_competitor_details_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/content_editor_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/find_competitors_agent.py (2)
core/agents/models.py (1)
AIModel(4-6)core/agents/schemas.py (1)
ProjectDetails(17-99)
core/agents/analyze_competitor_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/models.py (7)
core/agents/insert_internal_links_agent.py (2)
create_insert_internal_links_agent(7-85)output(82-83)core/agents/schemas.py (4)
BlogPostGenerationContext(182-192)GeneratedBlogPostSchema(195-205)InsertInternalLinksContext(283-294)ProjectPageContext(171-179)core/agents/generate_blog_post_content_agent.py (1)
create_generate_blog_post_content_agent(21-57)core/utils.py (2)
run_agent_synchronously(194-251)get_jina_embedding(144-186)core/agents/validate_blog_post_agent.py (1)
create_validate_blog_post_agent(12-41)core/api/views.py (1)
fix_generated_blog_post(1081-1111)core/agents/content_editor_agent.py (1)
create_content_editor_agent(14-49)
core/agents/validate_blog_post_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/title_suggestions_agent.py (4)
core/agents/models.py (1)
get_default_ai_model(12-14)core/agents/schemas.py (1)
TitleSuggestionContext(132-148)core/agents/system_prompts.py (2)
add_todays_date(7-8)add_language_specification(123-128)core/choices.py (1)
ContentType(4-6)
core/agents/extract_competitors_data_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/generate_blog_post_content_agent.py (4)
core/agents/models.py (1)
get_default_ai_model(12-14)core/agents/schemas.py (2)
BlogPostGenerationContext(182-192)GeneratedBlogPostSchema(195-205)core/agents/system_prompts.py (10)
add_language_specification(123-128)add_project_details(40-53)add_target_keywords(131-144)add_title_details(107-120)add_todays_date(7-8)add_validation_feedback(156-173)filler_content(27-37)markdown_lists(23-24)post_structure(15-20)valid_markdown_format(11-12)core/choices.py (1)
ContentType(4-6)
core/agents/competitor_vs_blog_post_agent.py (1)
core/agents/models.py (1)
AIModel(4-6)
core/agents/system_prompts.py (2)
core/models.py (1)
project_details(433-448)core/agents/schemas.py (1)
BlogPostGenerationContext(182-192)
core/agents/extract_links_agent.py (1)
core/agents/models.py (1)
get_default_ai_model(12-14)
core/agents/insert_internal_links_agent.py (2)
core/agents/models.py (1)
get_default_ai_model(12-14)core/agents/schemas.py (2)
InsertedLinksOutput(297-302)InsertInternalLinksContext(283-294)
🪛 Ruff (0.14.4)
core/agents/find_competitors_agent.py
73-73: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
79-79: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
core/models.py
996-996: Use explicit conversion flag
Replace with conversion flag
(RUF010)
1201-1201: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
1218-1218: Consider moving this statement to an else block
(TRY300)
core/agents/validate_blog_post_agent.py
22-22: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
core/agents/system_prompts.py
20-20: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
core/agents/insert_internal_links_agent.py
51-51: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
🔇 Additional comments (35)
core/agents/content_editor_agent.py (2)
3-3: LGTM: Import path updated to centralized location.The import consolidation to
core.agents.modelsimproves maintainability by centralizing AI model selection logic.
40-40: LGTM: Prompt text simplified.Removing the "IMPORTANT:" prefix simplifies the prompt while maintaining clarity. This change is consistent with similar updates across other agent files.
core/agents/summarize_page_agent.py (1)
3-3: LGTM: Consistent with centralized AI model configuration.The import path update and model_settings changes align with the broader refactor to centralize AI model configuration. The
thinking_budgetparameter verification requested in content_editor_agent.py applies here as well.Also applies to: 28-28
core/agents/analyze_project_agent.py (1)
3-3: LGTM: Consistent configuration updates.The import consolidation and model_settings configuration are consistent with the broader refactor. The temperature of 0.8 is appropriate for creative analysis tasks.
Also applies to: 28-28
core/agents/analyze_competitor_agent.py (1)
4-4: LGTM: Import path updated to centralized location.The import consolidation improves code organization.
core/agents/extract_links_agent.py (1)
3-3: LGTM: Appropriate configuration for link extraction.The import consolidation is consistent with the broader refactor. The low temperature (0.2) is well-suited for deterministic link extraction tasks.
Also applies to: 27-27
core/agents/title_suggestions_agent.py (1)
3-6: LGTM: Consistent refactoring and prompt simplification.The import consolidation for AI model configuration while maintaining ContentType in core.choices shows appropriate separation of concerns. The removal of "IMPORTANT:" prefixes simplifies the prompts without losing clarity.
Also applies to: 18-18, 41-41, 47-47
core/agents/competitor_vs_blog_post_agent.py (1)
6-6: LGTM: Consistent with centralized configuration.The import update to use
AIModelfromcore.agents.modelsaligns with the broader refactor, and the prompt text simplification is consistent with changes across other agent files.Also applies to: 67-67
core/agents/find_competitors_agent.py (1)
6-6: LGTM: Import path updated correctly.The import has been correctly updated to use the new centralized location for AI model definitions.
core/agents/generate_blog_post_content_agent.py (4)
3-3: LGTM: Imports updated correctly.The imports have been properly updated to use the new centralized locations for AI model utilities and the new validation feedback helper.
Also applies to: 11-11
27-29: Good documentation of the two-step process.This clarification helps developers understand that content generation and internal linking are now separate concerns, which is a sound architectural decision.
51-51: LGTM: Validation feedback integration.The addition of
add_validation_feedbackenables the agent to learn from previous validation failures, which should improve content quality on retries.
43-43: Confirm that the temperature reduction to 0.3 aligns with project quality requirements.This temperature setting is consistent with other content generation agents in the codebase (insert_internal_links_agent and content_editor_agent both use 0.3), while analysis agents intentionally use 0.8. The lower temperature makes output more deterministic, which appears intentional for structured content generation. The agent includes validation feedback mechanisms (retries=2, validation system prompt) to handle this behavior.
However, verify that:
- This change was intentional for this PR and not accidental
- Quality expectations are still met with reduced creativity/diversity
- The validation loop effectively handles deterministic output
core/agents/extract_competitors_data_agent.py (2)
3-3: LGTM: Import path updated correctly.The import has been correctly updated to use the new centralized location for AI model utilities.
25-25: LGTM: Appropriate model settings for data extraction.The temperature of 0.2 is well-suited for structured data extraction tasks where deterministic, accurate output is more important than creativity.
core/agents/populate_competitor_details_agent.py (2)
3-3: LGTM: Import path updated correctly.The import has been correctly updated to use the new centralized location for AI model utilities.
30-30: LGTM: Appropriate model settings for inference tasks.The temperature of 0.5 strikes a good balance between creativity and consistency for inferring competitor details from webpage content.
core/agents/schemas.py (4)
189-192: LGTM: Well-designed validation feedback mechanism.The
previous_validation_issuesfield enables the agent to learn from previous failures and improve content quality on retries. The field has a clear description and appropriate default value.
278-280: LGTM: Project pages added for internal linking.Adding
project_pagestoCompetitorVsPostContextenables internal linking in competitor comparison posts, maintaining consistency with the broader linking workflow.
283-295: LGTM: Well-structured context for link insertion.The
InsertInternalLinksContextmodel clearly separates must-use pages from optional pages, enabling intelligent link insertion based on priority and contextual relevance.
297-302: LGTM: Clean output schema.The
InsertedLinksOutputmodel provides a simple, focused contract for the link insertion agent's output.core/agents/insert_internal_links_agent.py (3)
7-19: LGTM: Clear function signature and documentation.The docstring clearly explains the agent's purpose and behavior, making it easy for developers to understand how to use it.
20-51: Excellent system prompt design.The system prompt provides comprehensive, actionable guidelines for link insertion:
- Clear quality standards (natural integration, contextual relevance)
- Specific instructions for anchor text and placement
- Distinction between must-use and optional pages
- Preservation of existing content
This should result in high-quality, contextually relevant internal linking.
53-60: LGTM: Appropriate agent configuration.The temperature of 0.3 and
thinking_budget: 0strike a good balance for link insertion, providing consistency while allowing some flexibility in anchor text selection and placement decisions.core/agents/system_prompts.py (4)
12-12: LGTM: Simplified prompt functions.The simplification of
valid_markdown_formatandmarkdown_liststo single-line returns improves readability without losing clarity.Also applies to: 24-24
27-37: LGTM: Clearer filler content guidance.The explicit examples ("No link placeholders", "No image placeholders") make the instructions more concrete and easier for the AI to follow.
110-110: Good catch: Typo fixed.Fixed "gnerate" → "generated".
156-173: LGTM: Well-implemented validation feedback mechanism.The
add_validation_feedbackfunction is well-designed:
- Uses
hasattrto safely check for optional field- Clearly formats validation issues for AI consumption
- Provides strong directive to avoid repeating mistakes
- Returns empty string when no issues exist
This should effectively improve content quality on retries.
core/agents/validate_blog_post_agent.py (3)
7-9: LGTM: Clean validation result model.The
BlogPostValidationResultmodel provides a simple, focused contract with a boolean validity flag and a list of specific issues.
12-25: LGTM: Appropriate agent configuration for validation.The extremely low temperature (0.1) and single retry are well-suited for validation tasks where consistency and determinism are critical.
27-39: LGTM: Comprehensive validation checks.The validation criteria cover the most critical quality issues:
- Completeness: Ensures content isn't truncated
- Length: Enforces minimum content threshold (2500-3000 chars)
- Placeholders: Catches common content generation failures
- Structure: Ensures proper formatting
These checks should catch the majority of publication-blocking issues.
core/models.py (4)
909-911: Well-designed validation state tracking.The new validation fields provide a clean, extensible approach to tracking content quality. Using a JSONField for issues allows detailed feedback accumulation.
1077-1117: Well-structured fix workflow.The method correctly checks validation state before attempting fixes, uses the content editor agent appropriately, and re-validates after fixing. The integration with link insertion when content becomes valid is a logical flow.
1144-1163: Excellent semantic search implementation.The use of pgvector's CosineDistance for finding semantically similar pages is well-designed. Separating must-use pages from optional pages based on similarity provides good control over link insertion strategy.
805-820: Clean integration of validation, link insertion, and OG image generation.The flow properly gates link insertion on successful validation, passes through the optional model parameter, and respects project settings for OG image generation. The separation of concerns is well-maintained.
| You are an expert marketer. | ||
| Based on the competitor details and homepage content provided, | ||
| extract and infer the requested information. Make reasonable inferences based | ||
| extract and infer the requested information. Make reasonable inferences based |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix extra whitespace in system prompt.
Line 26 contains multiple consecutive spaces: "Make reasonable inferences based". This appears to be a formatting error.
Apply this diff to fix the spacing:
- extract and infer the requested information. Make reasonable inferences based
+ extract and infer the requested information. Make reasonable inferences based📝 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.
| extract and infer the requested information. Make reasonable inferences based | |
| extract and infer the requested information. Make reasonable inferences based |
🤖 Prompt for AI Agents
In core/agents/analyze_competitor_agent.py around line 26, the system prompt
string contains extra consecutive spaces ("Make reasonable inferences
based"); remove the extra spaces so the sentence uses single spacing ("Make
reasonable inferences based") and ensure surrounding punctuation/indentation
remains unchanged.
| """, | ||
| retries=2, | ||
| model_settings={"temperature": 0.3}, | ||
| model_settings={"temperature": 0.3, "thinking_budget": 0}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the thinking_budget parameter is supported.
The thinking_budget: 0 parameter has been added to model_settings. Please confirm this is a valid parameter for the version of pydantic-ai in use.
🌐 Web query:
Does pydantic-ai Agent support a thinking_budget parameter in model_settings?
💡 Result:
Yes. Agent accepts model_settings and you can set a thinking_budget via a model-specific settings class — e.g., GoogleModelSettings supports google_thinking_config={'thinking_budget': ...} which can be passed to Agent (or at run time). [1][2]
Sources:
[1] Pydantic AI — Agents (model_settings description).
[2] Pydantic AI — Google model docs (example showing google_thinking_config with thinking_budget).
🏁 Script executed:
#!/bin/bash
# View the content_editor_agent.py file to see full context
cat core/agents/content_editor_agent.py | head -60Length of output: 1381
🏁 Script executed:
#!/bin/bash
# Search for model initialization patterns in agents directory
rg -nP --type=py -C5 'model_settings.*thinking_budget' core/agents/Length of output: 8860
🏁 Script executed:
#!/bin/bash
# Check what model is being used in this agent
rg -nP --type=py -C10 'class.*Agent|ClientModel|model=' core/agents/content_editor_agent.pyLength of output: 575
🏁 Script executed:
#!/bin/bash
# Find all Agent instantiations in the agents directory
rg -nP --type=py 'Agent\(' core/agents/ -C3Length of output: 6583
🏁 Script executed:
#!/bin/bash
# Check what get_default_ai_model returns
cat core/agents/models.pyLength of output: 362
🏁 Script executed:
#!/bin/bash
# Check if there's requirements or setup to see pydantic-ai version
fd -e 'txt' -e 'toml' -e 'cfg' --type f | grep -E '(requirements|setup|pyproject|poetry)' | head -5Length of output: 43
🏁 Script executed:
#!/bin/bash
# Search for any imports or usage of model settings structures
rg -nP --type=py 'ModelSettings|model_settings' core/agents/ -B2 -A2 | head -50Length of output: 3016
🏁 Script executed:
#!/bin/bash
# Check pydantic-ai version
grep -A5 -B5 'pydantic.ai\|pydantic-ai' pyproject.toml requirements.txt 2>/dev/null | head -20Length of output: 1182
🌐 Web query:
pydantic-ai Agent model_settings thinking_budget parameter syntax
💡 Result:
Short answer — use the model-specific settings field (GoogleModelSettings.google_thinking_config) and pass a dict with key "thinking_budget". Example:
-
Enable / set budget:
from pydantic_ai import Agent
from pydantic_ai.models.google import GoogleModel, GoogleModelSettingssettings = GoogleModelSettings(google_thinking_config={'thinking_budget': 2048})
model = GoogleModel('gemini-2.5-flash')
agent = Agent(model, model_settings=settings) -
Disable thinking (budget 0):
settings = GoogleModelSettings(google_thinking_config={'thinking_budget': 0})
Agent-level model_settings are merged with model-level and run-time settings (run-time has highest precedence). [1][2][3]
Sources:
[1] Pydantic AI — Google model docs (shows google_thinking_config & thinking_budget examples).
[2] Pydantic AI — Agents / ModelSettings docs (explains model_settings merging & usage).
[3] Pydantic AI — Thinking page (other model-specific thinking examples).
Incorrect parameter format for thinking_budget in model_settings.
For pydantic-ai 1.9.1 with Google Gemini models, thinking_budget must be passed via GoogleModelSettings(google_thinking_config={'thinking_budget': ...}), not as a flat dictionary key in model_settings.
The current code at line 34:
model_settings={"temperature": 0.3, "thinking_budget": 0}Should be corrected to use the model-specific settings structure. This issue affects multiple agents in core/agents/: validate_blog_post_agent.py, title_suggestions_agent.py, summarize_page_agent.py, populate_competitor_details_agent.py, generate_blog_post_content_agent.py, extract_competitors_data_agent.py, extract_links_agent.py, insert_internal_links_agent.py, and analyze_project_agent.py.
🤖 Prompt for AI Agents
In core/agents/content_editor_agent.py around line 34, model_settings uses an
incorrect flat key for thinking_budget; for pydantic-ai 1.9.1 with Google Gemini
you must supply thinking_budget via GoogleModelSettings using the
google_thinking_config dict. Replace the current model_settings={"temperature":
0.3, "thinking_budget": 0} with a model-specific settings object that sets
temperature and uses
GoogleModelSettings(google_thinking_config={"thinking_budget": 0}) (or
equivalent in your codebase) so thinking_budget is passed under
google_thinking_config; apply the same pattern to the other listed agent files.
| IMPORTANT: Be mindful that competitors are likely to speak in | ||
| {project.language} language. | ||
| """ | ||
| return f"Be mindful that competitors are likely to speak in {project.language} language." # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused noqa directives.
The static analysis tool correctly identified that the # noqa: E501 comments are unnecessary since the E501 rule (line too long) is not enabled in your linter configuration.
Apply this diff to remove the unused directives:
- return f"Be mindful that competitors are likely to speak in {project.language} language." # noqa: E501
+ return f"Be mindful that competitors are likely to speak in {project.language} language."- return f"Only return competitors whose target audience is in {project.location}." # noqa: E501
+ return f"Only return competitors whose target audience is in {project.location}."Also applies to: 79-79
🧰 Tools
🪛 Ruff (0.14.4)
73-73: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In core/agents/find_competitors_agent.py lines 73 and 79, remove the unnecessary
"# noqa: E501" comments trailing the return statements; simply delete the "#
noqa: E501" tokens so the lines read normally without the unused noqa
directives, ensuring no other changes are made.
| ## Output Requirements: | ||
| Return the complete blog post content with internal links inserted. The content should be in Markdown format with proper link syntax. | ||
| """ # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused noqa directive.
The static analysis tool correctly identified that the # noqa: E501 comment is unnecessary since the E501 rule is not enabled in your linter configuration.
Apply this diff:
## Output Requirements:
Return the complete blog post content with internal links inserted. The content should be in Markdown format with proper link syntax.
-""" # noqa: E501
+"""📝 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.
| """ # noqa: E501 | |
| ## Output Requirements: | |
| Return the complete blog post content with internal links inserted. The content should be in Markdown format with proper link syntax. | |
| """ |
🧰 Tools
🪛 Ruff (0.14.4)
51-51: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In core/agents/insert_internal_links_agent.py around line 51, the trailing "#
noqa: E501" on the docstring is unnecessary; remove the unused noqa directive by
deleting " # noqa: E501" from the line (leave the docstring content intact) and
run linting to confirm no other violations remain.
| from django.db import models | ||
|
|
||
|
|
||
| class AIModel(models.TextChoices): | ||
| GEMINI_FLASH = "google-gla:gemini-2.5-flash", "Gemini 2.5 Flash" | ||
| PERPLEXITY_SONAR = "sonar", "Perplexity Sonar" | ||
|
|
||
|
|
||
| DEFAULT_AI_MODEL = AIModel.GEMINI_FLASH | ||
|
|
||
|
|
||
| def get_default_ai_model() -> str: | ||
| """Returns the default AI model to use across the application.""" | ||
| return DEFAULT_AI_MODEL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
LGTM: Clean centralization of AI model configuration.
The new module provides a clean, centralized location for AI model definitions. The structure follows Django conventions with TextChoices and provides a clear default model selection mechanism.
However, please verify the model identifier "google-gla:gemini-2.5-flash" is correct. The "google-gla" prefix appears unusual for Gemini models.
🌐 Web query:
What is the correct model identifier for Google Gemini 2.5 Flash in pydantic-ai?
💡 Result:
The correct model identifier is "gemini-2.5-flash". [1][2]
Sources:
[1] Pydantic AI — Google models list (LatestGoogleModelNames includes "gemini-2.5-flash").
[2] Google Gemini models documentation (model code "gemini-2.5-flash").
Fix incorrect model identifier for Google Gemini 2.5 Flash.
The correct model identifier for Google Gemini 2.5 Flash in pydantic-ai is "gemini-2.5-flash", not "google-gla:gemini-2.5-flash". Update line 5 in core/agents/models.py:
GEMINI_FLASH = "gemini-2.5-flash", "Gemini 2.5 Flash"The incorrect prefix will cause runtime failures when pydantic-ai attempts to load the model.
🤖 Prompt for AI Agents
In core/agents/models.py lines 1-14, the AIModel.GEMINI_FLASH enum value is
incorrect and will fail at runtime; change the enum member's stored string to
"gemini-2.5-flash" (i.e., GEMINI_FLASH = "gemini-2.5-flash", "Gemini 2.5 Flash")
and also ensure the default/exported value matches the hinted str type by
setting DEFAULT_AI_MODEL to AIModel.GEMINI_FLASH.value or by returning
DEFAULT_AI_MODEL.value from get_default_ai_model().
| - Use '##' (h2 headers) for sections of the post where necessary. | ||
| - Don't use 3rd levle subheaders (###) or deeper. That should not be necessary for the post. | ||
| - Don't use 3rd level subheaders (###) or deeper. That should not be necessary for the post. | ||
| """ # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused noqa directive.
The static analysis tool correctly identified that the # noqa: E501 comment is unnecessary since the E501 rule is not enabled.
Apply this diff:
- Use '##' (h2 headers) for sections of the post where necessary.
- Don't use 3rd level subheaders (###) or deeper. That should not be necessary for the post.
- """ # noqa: E501
+ """📝 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.
| """ # noqa: E501 | |
| """ |
🧰 Tools
🪛 Ruff (0.14.4)
20-20: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In core/agents/system_prompts.py around line 20, remove the unnecessary "# noqa:
E501" directive at the end of the triple-quoted string closing line; simply
delete the comment so the line ends with the closing triple quotes, and ensure
no other unused noqa comments remain in the file.
| Analyze the provided blog post content and determine if it meets publication quality standards. | ||
| Be thorough but fair. Minor imperfections are okay if the content is publishable. | ||
| """, # noqa: E501 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused noqa directive.
The static analysis tool correctly identified that the # noqa: E501 comment is unnecessary since the E501 rule is not enabled.
Apply this diff:
Be thorough but fair. Minor imperfections are okay if the content is publishable.
- """, # noqa: E501
+ """,📝 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.
| """, # noqa: E501 | |
| """, |
🧰 Tools
🪛 Ruff (0.14.4)
22-22: Unused noqa directive (non-enabled: E501)
Remove unused noqa directive
(RUF100)
🤖 Prompt for AI Agents
In core/agents/validate_blog_post_agent.py around line 22, the trailing "# noqa:
E501" on the triple-quoted string is unnecessary (E501 not enabled); remove the
"# noqa: E501" directive so the line ends with the string delimiter only, and
run linters to confirm no other noqa directives are required.
Summary by CodeRabbit
New Features
Bug Fixes
Refactor