Changelog¶
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[0.2.10] - 2026-05-27¶
Added¶
- Frontend
PageHerocomponent — sharedcomponents/dashboard/page-hero.tsx(151 lines) used by admin, billing, settings, KB, organizations, and dashboard pages so headers share a single typographic rhythm and breadcrumb pattern instead of each page hand-rolling its own - Chat controls panel — new
components/chat/chat-controls.tsx(586 lines) consolidates model picker, knowledge-base toggles, and conversation settings into one panel. Replaces the splitchat-settings.tsx(deleted) andkb-selector.tsx(deleted) — fewer UI surfaces, no more duplicate KB lookups - Auth screens redesigned — login, register, reset-password, and forgot-password forms now use a split-screen layout (product pitch on the right, form on the left), proper OAuth divider, and consistent form spacing. Generated
(auth)/layout.tsx+magic-link-sent/page.tsxupdated to match
Changed¶
- Marketing site refreshed — hero, pricing teaser, final CTA, marketing footer rebuilt with cleaner typography, monthly/annual toggle on pricing, and configurable footer columns (
footer-config.ts) - Knowledge bases page redesigned —
kb/kb-list.tsxrewritten (266-line refactor) with card layout, per-base actions, and clearer empty-state copy - Dashboard / admin / settings / billing pages — every page header migrated to the new
PageHero; layout, sidebar, and command palette tightened. Globals CSS adjusted for the new spacing scale - README — banner image at the top replaced with the live chat demo video so the first thing a visitor sees is the product running; merged the separate "web search" and "chart generation" demos into one (the new demo covers both); refreshed every product screenshot from
assets/new2/; pruned ~40 unused assets (assets/new/,assets/chat/, old marketing PNGs, button SVGs)
Fixed¶
- No-AI projects (
use_ai=False) failed to build — generator now removes every AI-only surface that previously leaked through and broke imports:conversation/conversation_share/message_rating/user_slash_commandmodels + repos + services, theagent,admin_conversations,admin_ratings, andme_slash_commandsroutes, and the corresponding frontend pages (chat/,admin/conversations,admin/ratings,settings/slash-commands), API proxies, and data hooks. RAG-off projects also drop the KB UI (components/kb,app/api/kb,(dashboard)/kb,use-knowledge-bases.ts,types/knowledge-base.ts) sonext buildno longer fails on orphaned imports - Backend modules unconditionally pulled in chat code —
api/deps.py,api/routes/v1/__init__.py,db/models/__init__.py,repositories/__init__.py,schemas/__init__.py,services/admin.py,repositories/user.py, andadmin.py(SQLAdmin) haduse_database-gated imports ofConversation/Message/MessageRating/etc. that crashed in no-AI projects. Re-gated touse_aiand added literal-zero fallbacks for conversation counts in admin stats / user listings (PG, SQLite, MongoDB) - CLI: Slack/Telegram channels silently accepted without an AI framework —
ProjectConfigvalidation now rejects--slack/--telegramwhenuse_aiis off (the channel adapters only exist to relay messages toAgentInvocationService), with a quick-fix message temperatureforwarded to reasoning models (gpt-5.5, o1) — those models reject the parameter entirely, soAssistantAgentno longer falls back tosettings.AI_TEMPERATURE; it staysNoneand is only forwarded toModelSettingswhen the caller explicitly sets itreranker.pyCohere init imported the SDK only to discard it — replaced thefrom cohere import AsyncClientprobe withimportlib.util.find_spec("cohere")so we check availability without polluting imports- Auth components barrel exported password forms in OAuth-only builds —
components/auth/index.tsnow gates the local-auth form exports behinduse_local_auth, so OAuth-only projects don't ship dead code that references missing endpoints - README demo videos invisible on GitHub —
<video>tags fromraw.githubusercontent.comdon't render in the GitHub README viewer (only<img>autoplays from raw URLs). Converted both chat and RAG demo.mp4s to optimized.gifs (960px, 10fps, palette-quantized — 5.8 MB and 3.0 MB respectively, ~80% smaller than source) and switched the README to<img>tags. Removed the unused.mp4sources - Renovate scanned the generated
ai_agent_test/snapshot — opened useless PRs against the snapshot'spackage.json/docker-compose.ymlinstead of the actualtemplate/source, so every accepted bump would silently revert on the next regeneration. AddedignorePaths: ["ai_agent_test/**", "**/node_modules/**"]so future bumps target the template files
Dependencies¶
- Generator CI Python pinned to 3.14 (was 3.12) —
.github/workflows/{ci,docs,release}.yml(#75) aquasecurity/trivy-action→ v0.36.0 in generated projects' CI (#74)milvusdb/milvusDocker tag → v2.6.17 in generateddocker-compose.{dev,prod,}.yml(#77)qdrant/qdrantDocker tag → v1.18.1 in generateddocker-compose.{dev,prod,}.yml(#78)quay.io/coreos/etcdDocker tag → v3.6.11 (Milvus dependency) in generateddocker-compose.{dev,prod,}.yml(#80)prettier-plugin-tailwindcss→ ^0.8.0 in template frontendpackage.json(#81 bumped only the snapshot; the template source is the durable fix)
[0.2.9] - 2026-05-17¶
Added¶
- Chart generation tool (
enable_charts) — optionalcreate_charttool letting the agent produce line/bar/pie/area/scatter charts. Returns a validatedChartSpec(data, series, custom style/palette/legend/axis) as JSON, so the same payload flows to every surface. Registered in all 6 agent frameworks (PydanticAI, LangChain, LangGraph, CrewAI, DeepAgents, PydanticDeep). Web chat renders it interactively with Recharts; Slack/Telegram get a server-side PNG via matplotlib (charts_channel_png, gated dep, with a markdown-table fallback). Wizard prompt +--chartsCLI flag +enable_chartscookiecutter var - Portable
fetch_urltool (web_fetch_tool) — SSRF-safe "read this web page" tool for LangChain/LangGraph/CrewAI/DeepAgents (which had no model-native web-fetch). Reusesapp.core.sanitize.validate_webhook_url, re-validates every redirect hop, caps size/timeout, extracts readable text (BeautifulSoup). PydanticAI/PydanticDeep keep their nativeWebFetch. Closes the gap whereenable_web_fetchwas a silent no-op for those frameworks - Web Search & Fetch offered for every agent framework in the interactive wizard (was PydanticAI-only); CrewAI now actually attaches
search_web/fetch_urlto the research agent (they were registered but never used) - Gated test suites:
test_chart_tool.py,test_fetch_url.py,test_web_search.py
Changed¶
- Refreshed default AI models — OpenAI →
gpt-5.5, Anthropic →claude-opus-4-7, OpenRouter →anthropic/claude-opus-4-7, multi-provider →openai/gpt-5.5(Google staysgemini-2.5-flash). UpdatedAI_AVAILABLE_MODELS(GPT-5.x frontier line; full Claude Opus/Sonnet/Haiku line) and Claude pricing in billingMODEL_COSTS; synced.env/.env.example/docs - Rewrote the default agent system prompt (outcome-first style) — real personality + answering policy + formatting. The RAG variant is no longer a straitjacket: the agent answers general-knowledge questions directly instead of replying "not in the knowledge base", and treats
search_documentsas a tool to use when relevant with a retrieval budget and citations web_searchtool returns structured JSON (WebSearchResults) instead of ad-hoc text, so the chat UI renders clickable titles, domains and snippets (addedparse_web_search). Fixed stale frontend detection that meant the rich card never showed for LangChain/LangGraph/DeepAgents- Removed the
.env.prod/.env.prod.exampleabstraction — production now uses the samebackend/.envas dev (it already contained every variable.env.prod.exampledefined).docker-compose.prod.ymlreadsenv_file: ./backend/.env;make prodchecks forbackend/.envand passes--env-file backend/.envto Compose..env.prodremoved from.gitignore. Migration: move any values from your old.env.prodintobackend/.env(gitignored) on the server - Chat UI: ordered message timeline — a streamed assistant turn now renders as an ordered sequence of parts (thinking → tools → text → …) in true chronological order instead of three fixed slots, so multi-step turns display correctly. Provider-agnostic; CrewAI keeps its multi-message layout
- Tool-call cards redesigned — collapsed by default to a clickable bar (tool name + input hint, e.g. the query/URL), expand to the formatted view,
</>toggle for arguments + raw output. Chart cards auto-expand (they're only useful when visible). New generic fallback renderer displays any newly added backend tool sensibly with no frontend changes; removed the per-tool status icon
Fixed¶
- LangChain/LangGraph/DeepAgents streaming: tool-call arguments were empty in the web UI — the token-chunk path emitted a premature
tool_callwithargs: {}and poisoned the shared dedup set, suppressing the complete event. Theupdatesstream is now the single source of truth (full args), with no duplicate/empty card - Reasoning ("thinking") now streams reliably — extracted via a shared helper, with a fallback that emits reasoning from the final message for providers that don't stream it as chunks
AIMessageChunkmerge crash —Additional kwargs key created_at … unsupported type <class 'float'>on the OpenAI Responses API. Usage is now summed viaadd_usageinstead of merging whole chunks- DeepAgents tool calls never fired —
_stream_update_eventchecked the graph node"agent", butcreate_deep_agent(deepagents 0.6.1 → LangChaincreate_agent) names it"model". Tool calls, args and reasoning are now emitted for DeepAgents KBSelectorinfiniteGET /api/kbrequest loop when a workspace has no knowledge bases — a length-based effect re-fired after every empty fetch; replaced with a one-shot ref guardtest_agents.pywas not provider-gated — it patched OpenAI-only symbols, breaking generation/tests for Anthropic/Google/OpenRouter (and the LangChain branch). PydanticAI now patches the single_build_modelseam with a realTestModel; LangChain patches the provider-correct chat class
[0.2.8] - 2026-05-11¶
Added¶
- Email module (
enable_email) — Transactional email system with three providers: Resend (async), SMTP (aiosmtplib), and Log (dev/test). Pre-rendered HTML/text templates stored inemails/compiled/using[[variable]]substitution.EmailServicefacade with convenience wrappers for all email types: welcome, password reset, invitation, payment succeeded/failed, trial ending/expired, subscription canceled/changed, low credits, newsletter welcome - Email triggers wired —
UserService.register()firessend_welcome;InvitationService.invite()firessend_invitation; billing webhook handlers fire payment/subscription lifecycle emails using Stripe customer data (fail-open — email errors never break webhook processing) - Stripe billing — rate limiting per plan (
enable_rate_limiting) — Sliding window rate limiter backed by Redis sorted sets (ZADD/ZREMRANGEBYSCORE/ZCARD pipeline) with in-memory fallback.RateLimitRulefrozen dataclass (per_user, per_org, per_ip, configurable periods);RateLimitCategoryconstants; data-driven plan features overrideDEFAULT_RATE_LIMITS;make_rate_limit_dep(category)factory for FastAPIDepends(); admin bypass; fail-open on Redis error; HTTP 429 withRetry-Afterheader - Extended frontend billing dashboard —
SubscriptionPanelwith 4 states (free/trial/active/canceled), cancel/reactivate dialogs, plan details;CreditsPanelwith balance display, low-credit alert, top-up button, transaction history with type badges;/billing/subscriptionpage with live plan cards;/billing/creditspage.useSubscription,useCredits,usePlanshooks added touse-billing.ts - Admin user management —
GET/PATCH/DELETE /admin/users/{id}endpoints (requiresis_app_adminflag).POST /admin/users/{id}/impersonateissues a short-lived (1h) JWT token to act as any user — token is returned in the API response. Frontend:/admin/userspage with search, role toggle, delete, and impersonation-token-to-clipboard button;/admin/page.tsxoverview with navigation cards;useAdminUsershook - UsageService —
app/services/usage.py— recordsUsageEventin DB, computes credits viausage_to_credits(), debits org credits viaCreditService.debit(). All 3 DB variants (PG/SQLite/MongoDB). Wiring point for agent invocations - Usage dashboard —
/billing/usagefrontend page: total credits/tokens/calls KPI cards, recharts bar chart of credits by model, per-model breakdown table, CSV export of credit transaction history - Anomaly detection service (
enable_usage_anomaly_detection) —anomaly_detection.py— spike detection: current-hour credits vs rolling 24h average; alert if ratio > 3×; optional Slack webhook notification (enable_slack_alerts,SLACK_ANOMALY_WEBHOOK_URLsetting) - Newsletter signup (
enable_newsletter_signup) —POST /newsletter/signupendpoint;NewsletterSignupReact component; sends welcome email via email service - Changelog page (
enable_changelog) —/changelogroute with release history, change type badges (feat/fix/improvement/chore) - Pricing comparison page (
enable_comparison_pages) —/pricingroute fetches live plans from API; monthly/annual toggle; plan feature list; trial days display; "Get Started" CTA
Fixed¶
- Email templates excluded by
.gitignore— Renamedemails/dist/→emails/compiled/to avoid the genericdist/gitignore rule silently stripping all compiled templates from generated projects billing/facade.pyimportsusage_event_repounconditionally —app.repositories.usage_eventwas imported in both PostgreSQL and SQLite branches regardless ofenable_credits_system; projects generated withenable_billing=True+enable_credits_system=Falsecrashed on startup withImportErrorfunc.case()SQLAlchemy 2.x crash inmessage_rating_repo—func.case((condition, value), else_=0)raisedTypeError: Function.__init__() got an unexpected keyword argument 'else_'; replaced withcase(...)imported directly fromsqlalchemy- Credits/usage dashboard widgets shown when
enable_credits_system=False—UsageTimelineandTopModelscomponents were gated onenable_billinginstead ofenable_credits_system; they fetch from/billing/me/credits/usage/...endpoints that don't exist without the credits system, producing silent 404s and empty charts - MongoDB projects:
admin.pyused SQLAlchemyfunc.count—AdminServicenow has separate{%- if use_postgresql or use_sqlite %}/{%- elif use_mongodb %}branches; the MongoDB branch uses BeanieDocument.find().count()and returns[], 0for Stripe events (not applicable to MongoDB projects) - Admin
GET /conversations/{id}returned 404 for other users' conversations —get_conversationandlist_messagesroute handlers now resolveuid = None if current_user.role == "admin" else current_user.id;user_id=Nonein the service layer bypasses the ownership check, allowing admins to read any conversation - Frontend
?id=URL param blocked by ownership guard —fetchConversationsremoved theresponse.items.some(c => c.id === urlId)check before loading messages; any?id=value is now attempted unconditionally and a 404/403 from the server clears the ID silently (non-admins are still protected server-side) - Admin conversations page "View" opened an in-page read-only preview — Replaced the custom preview panel with a
Linkto/chat?id=<conversation_id>; admins now land on the full chat UI with the real message history - Admin ratings page "Export" returned 404 —
window.openwas targeting/api/v1/admin/ratings/export(direct backend path) instead of/api/admin/ratings/export(the Next.js proxy route that attaches the auth cookie) - CI integration test failures —
generated_project_fullfixture now setsfrontend=FrontendType.NEXTJS(required whenoauth_provider=GOOGLE); MongoDB repository__init__.pyimport guard split so only SQL-only repos (chat_file_repo) are excluded from MongoDB projects; SQLite auth test fixed a mock type mismatch (MagicMock→AsyncMock)
[0.2.7] - 2026-04-26¶
Fixed¶
- Disabled features no longer leak generated files —
post_gen_project.pynow removes channel adapters/routes/services/repos/schemas/models/commands/migrations whenuse_telegramanduse_slackare both off, RAG sync infrastructure (sync_log,sync_source,rag_documentfiles) when RAG is off, DeepAgents project scaffolding when not selected, leftover test stubs for disabled modules, and emptydocker-composeplaceholders when Docker is disabled agent.py(DeepAgents): undefinedfile_ids— WebSocket payload parsing now extractsfile_ids = raw_data.get("file_ids", [])before use (previously raisedNameErrorat runtime)agent.py(CrewAI): missingConversationUpdateimport — Added to imports so title-update path no longer crashesrag.py:complete_synccalled on wrong service — Was invoked onSyncSourceService; now correctly routed toRAGSyncServiceIngestionService()instantiated without required args — AddedIngestionService.from_settings()classmethod factory; routes/commands/workers now use itmessage_rating_reponot exported — Added toapp/repositories/__init__.py; admin ratings flow no longer fails on importConversationService.get_conversation_with_messagesmissing on SQL backends — Previously only existed on MongoDB; added to PostgreSQL + SQLite variantsProjectService.list/ChannelBotService.listshadowed builtinlist— Renamed tolist_for_user()/list_all()(withfind_active()andlist_by_platform()helpers added)ModuleNotFoundError: No module named 'app.rag.connectors'—post_gen_project.pywas deleting the entirerag/connectors/directory when neither Google Drive nor S3 ingestion was enabled, butsync_source.pyalways importsCONNECTOR_REGISTRYfrom that package. Directory is now preserved; only the individual connector files are removed- Empty
tasks/channel.pygenerated for projects without Telegram or Slack — Added removal to thenot use_telegram and not use_slackpost-gen hook block - Frontend TypeScript strict mode errors — Fixed 26
noUncheckedIndexedAccessandundefined-assignability violations across 7 files:rag/page.tsx(array index + file loop guard),chat-container.tsx(model selectoruseStatetype + fallback),chat-input.tsx(speech recognition result guard),tool-approval-dialog.tsx(editedArgsindex fallback),tool-call-card.tsx(regex capture group fallbacks),breadcrumb.tsx(route segment index),theme-toggle.tsx(persisted zustand state hydration)
Changed¶
- Strict layered architecture enforced across the template — Routes call services only (via FastAPI
Depends); services call repositories only; repositories are the sole layer permitted to talk to the database. Worker tasks, channel adapters, CLI commands, and webhook handlers no longer perform raw DB operations admin_conversations.pyrewritten to useConversationSvc.admin_list_with_users()andUserSvc.admin_list_with_counts()telegram_webhook.py/slack_webhook.pyuseChannelBotSvcviaDependsinstead of opening their own DB sessions (bot_service.find_active(bot_id))agent.pyusesconv_service.list_attached_files(file_ids)instead of rawselect(ChatFile)queries- Worker tasks (
rag_tasks._run_ingestion,_run_sync,_update_status,_update_sync_log) refactored onto the service layer - CLI commands (
commands/channel.py,seed.py,rag.py) refactored with a_channel_service()context-manager helper - All
self.db.execute/commit/addremoved from services; sessions auto-commit viaget_db_session/get_db_context/get_worker_db_context - Repositories expanded with the queries services now need —
conversation.admin_list_with_users()+export_chunk()(3 backends);user.list_query()+admin_list_with_counts()+delete_non_admins()+has_any()(3 backends);chat_file.get_many()+link_to_message();message_rating.get_user_ratings_for_messages()+get_rating_counts_for_messages()+get_ratings_with_users_for_messages();webhook.create_delivery()+save_delivery();sync_log.create(sync_source_id=...);rag_document.delete_by_collection() - Routes thinned to HTTP-only layer — All response-object construction moved from route handlers into services:
admin_ratings.py: CSV/JSON export helpers (_csv_escape,_csv_row_values,_serialize_csv_row,_validate_export_format,_export_disposition,_json_export_response,_stream_csv_sync/async) andexport_ratings()moved toMessageRatingService. Route reduced to a singlereturn await rating_service.export_ratings(...)callsessions.py:SessionReadconstruction inlist_sessionsmoved toSessionService.list_sessions()which now returnsSessionListResponsedirectlyrag.py:SyncSourceRead(...)construction moved toSyncSourceService._to_read()(used bylist_sources,create_source,update_source);RAGSyncLogItem(...)moved toRAGSyncService.list_sync_logs()→ returnsRAGSyncLogList;RAGTrackedDocumentItem(...)moved toRAGDocumentService.list_documents()→ returnsRAGTrackedDocumentList;RAGDocumentItem(...)moved toBaseVectorStore.get_document_list();ConnectorInfo/ConnectorListconstruction moved toSyncSourceService.list_connectors()oauth.py: Three-step find/link/create OAuth flow extracted toUserService.get_or_create_oauth_user()(all 3 DB variants);google_callbackreduced to a single service callusers.py: RawAnnotated[User, Depends(RoleChecker(UserRole.ADMIN))]replaced withCurrentAdminalias throughout;Depends(get_current_user)replaced withCurrentUser- Unused
current_user/admin_userroute parameters that only provided auth enforcement renamed to_: CurrentAdmin/_: CurrentUseracross all affected routers agent.py: inline imports moved to module level —from datetime import datetime, UTC,import json,from pydantic_ai.messages import BinaryContent,from app.services.file_storage import get_file_storage, and pydantic_deep session/project service imports were scattered across WebSocket handler bodies; all moved to the top of their respective framework blocksconversations.py: Direct field mutationdata.user_id = current_user.idreplaced withdata = data.model_copy(update={"user_id": current_user.id})(Pydantic v2 safe update); inlineConversationShareSvcimport moved to module level; section-divider comments (# Message Rating Endpoints,# Sharing endpoints) removed
Security¶
- Generator dependency floors raised —
pyproject.tomlruntime/dev/docs floors bumped to currently-used versions:click>=8.3.0,cookiecutter>=2.7.0,rich>=15.0.0,questionary>=2.1.0,pydantic>=2.13.0,pydantic-settings>=2.13.0,email-validator>=2.3.0,pytest>=9.0.0,pytest-cov>=7.0.0,ruff>=0.14.0,ty>=0.0.31,pre-commit>=4.0.0,mkdocs>=1.6.1,mkdocs-material>=9.7.0,pymdown-extensions>=10.20. Brings in upstream security/bug fixes pip-auditCI: CVE-2026-3219 (pip 26.0.1) added to ignore list — Vulnerability inpipitself with no fix version published yet; documented in the workflow alongside the other ignored CVEs
Added¶
- Config validator: CrewAI + Logfire combination rejected — Raises
ValueErrorat config time; documents an upstream OpenTelemetry/logfire ≥ 4.30 conflict with CrewAI - Conditional pydantic pin for CrewAI — Generated
pyproject.tomlpinspydantic[email]>=2.11.0,<2.12when CrewAI is selected (CrewAI is incompatible with pydantic 2.12) - Stricter
tyrules in generatedpyproject.toml—unknown-argument,invalid-await,invalid-context-manager,missing-argument,not-iterable,invalid-return-type,invalid-type-formpromoted towarn - Integration test matrix —
TestGeneratedTemplateMatrixnow exercises 14 framework/database/RAG/channel combinations (project names prefixed withmatrix_to avoid package-name collisions). Suite: 405 passed, 3 skipped services/health.py— Newbuild_health_response(status, checks, details)helper extracted fromhealth.pyroute;health.pynow imports and calls it instead of defining it inlineservices/agent.py— NewAgentConnectionManagerclass extracted from all 5 AI framework blocks inagent.py. Single canonical implementation shared viafrom app.services.agent import AgentConnectionManagerUserService.get_or_create_oauth_user(provider, provider_id, email, full_name)— Encapsulates the find-by-oauth-id → find-by-email → link-or-create orchestration that was previously duplicated inline in all threegoogle_callbackroute handlersSyncSourceService._to_read(source)/list_connectors()—_to_readconverts aSyncSourceORM model toSyncSourceRead(includingjson.loadsfor SQLite config);list_connectors()is a@staticmethodthat iteratesCONNECTOR_REGISTRYand returnsConnectorListwithout requiring a DB sessionBaseVectorStore.get_document_list(collection_name)— Concrete (non-abstract) method on the base class; callsget_documents()and maps toRAGDocumentList. All vector store implementations (Milvus, Qdrant, ChromaDB, pgvector) inherit it automatically
[0.2.6] - 2026-04-18¶
Added¶
- Message rating feature — Users can rate AI assistant messages with thumbs up/down and optional feedback comments. Toggle behavior: clicking same button removes rating, clicking opposite button changes it. Only assistant messages are rateable
- Backend:
MessageRatingmodel (PostgreSQL/SQLite/MongoDB, SQLAlchemy/SQLModel), repository + service + schema layers,POST /conversations/{id}/messages/{messageId}/rateendpoint. Ratings persisted tomessage_ratingstable with unique constraint per user/message andCHECKconstraint on rating values (1/-1). Optional comment field (up to 2000 chars). Supports all 3 database variants - Admin API:
GET /admin/ratings(paginated list with filters),GET /admin/ratings/summary(aggregate stats),GET /admin/ratings/export(CSV/JSON download).GET /admin/conversations(paginated listing). All admin routes require admin role - WebSocket integration: Ratings data (user's rating, like/dislike counts) included in streaming message events and conversation history loading
- Frontend:
RatingButtonscomponent with like/dislike icons, comment dialog on dislike, optimistic count updates. Integrated intomessage-item.tsxfor assistant messages. Admin pages for ratings management and conversations listing - Frontend proxy routes:
POST/DELETE /api/conversations/{id}/messages/{messageId}/rateproxies,GET /api/v1/admin/ratings,/summary,/exportroutes,lib/admin-auth.tsutility for admin API calls - Documentation:
docs/howto/use-ratings.mduser guide, updateddocs/architecture.mdanddocs/permissions.md - Tests: 660+ lines of tests covering config validation, model generation, repository/service/route layers, all database variants
Security¶
- Removed JWT from WebSocket URL query string — WS auth now uses
Sec-WebSocket-Protocol(access_token.<JWT>) instead of?token=..., so tokens no longer leak into access logs orRefererheaders. Backend echoes the chosen application subprotocol back onaccept() - Removed
/api/auth/tokenhttpOnly downgrade endpoint —access_tokenis now returned in the body of/auth/login,/auth/me, and/auth/refreshproxy responses and kept in memory only (never persisted) - CSV export injection hardening — Admin ratings CSV export now prefixes cells starting with
= + - @(or tab/CR) with a single quote, preventing formula execution when opened in Excel/Sheets - Rating comments stored raw — Dropped
html.escapefrom comment sanitization; comments are rendered via React (auto-escaped) and CSV-escaped separately, so the DB stores original text
Changed¶
- Streaming admin ratings CSV export —
/admin/ratings/export?export_format=csvnow streams row-by-row via an async/sync generator instead of buffering the whole dataset in memory
[0.2.5] - 2026-04-12¶
Added¶
Conversation Sharing + Admin Conversation Browser¶
- Conversation sharing — Share conversations with other users (direct share by user ID) or generate public share links (UUID4 token). Permission levels:
view(read-only) andedit(can add messages). Owner can share, list shares, and revoke access. Recipients can also leave shared conversations ConversationSharemodel — New DB model across all 5 variants (PG+SQLModel, PG+SQLAlchemy, SQLite+SQLModel, SQLite+SQLAlchemy, MongoDB). Fields: conversation_id, shared_by, shared_with, share_token, permission. Unique constraint on (conversation_id, shared_with)- Share endpoints —
POST /conversations/{id}/shares(share or generate link),GET /conversations/{id}/shares(list shares, owner only),DELETE /conversations/{id}/shares/{share_id}(revoke),GET /conversations/shared-with-me(list shared with current user),GET /conversations/shared/{token}(public access, no auth) - Admin conversation browser — Admin-only endpoints:
GET /admin/conversations(paginated, searchable by title, filterable by user_id, includes message_count and user_email),GET /admin/conversations/{id}(full conversation with messages),GET /admin/conversations/users(user list with conversation counts, searchable) - Share dialog component — Frontend dialog to share conversations: user search input, permission dropdown (view/edit), generate share link with copy button, list current shares with revoke
- Admin conversations page —
/admin/conversationspage with tabs (Conversations/Users), table views, search, click-to-preview (read-only), user → conversations drill-down - Public shared page —
/shared/[token]SSR page renders conversation transcript without sidebar or input. Clean read-only view using server-side fetch - Frontend hooks —
useConversationShares(share, fetch, revoke, shared-with-me) anduseAdminConversations(admin list, users, detail preview)
Slack Multi-Bot Channel Integration¶
- Slack adapter —
SlackAdapter(ChannelAdapter)supporting both Events API (production webhook) and Socket Mode (development polling). Thread-aware: Slack thread replies foldthread_tsintoplatform_chat_id({channel}:{thread_ts}) so each thread gets its ownChannelSessionandConversation - Events API webhook —
POST /slack/{bot_id}/eventsendpoint handles Slack URL verification challenge and event dispatch. Signature verified via HMAC-SHA256 (v0={timestamp}:{body}) with 5-minute replay-protection window. Fire-and-forget background dispatch meets Slack's 3s response requirement - Socket Mode (dev) — Supervised polling loop with
slack-sdk'sSocketModeClient. Bot-scoped tasks with 5s back-off restart on crash. Lifecycle managed in app lifespan alongside Telegram polling use_slackcookiecutter variable — Gates all Slack infrastructure. CLI interactive prompt for "Enable Slack integration" added alongside Telegram. Enables:slack-sdk>=3.35.0, Slack-specific config vars (SLACK_SIGNING_SECRET,SLACK_BOT_TOKEN,SLACK_APP_TOKEN),POST /slack/{bot_id}/eventsroute- Shared channel infrastructure expanded — All 14 shared files (
ChannelAdapterbase, models, repos, services, router, commands) gated fromuse_telegram→use_telegram or use_slackso both platforms share the same session/identity/bot management layer - Group chat concurrency control — Per-chat
asyncio.Lock(keyed on{bot_id}:{platform_chat_id}) inChannelMessageRouter.route(). Serializes concurrent messages from the same group/channel to prevent: duplicateChannelSessioncreation (DB constraint violation), interleaved agent invocations on the sameConversation, and rate-limit counter races. Affects both Telegram groups and Slack channels
Telegram Multi-Bot Channel Integration¶
- Full Telegram bot integration — Multi-bot support with polling and webhook delivery modes, encrypted token storage (Fernet), in-memory rate limiting (token-bucket per user per bot), and role-based access policies (open, whitelist, jwt_linked, group_only)
- Channel adapter architecture — Abstract
ChannelAdapterbase class with concreteTelegramAdapter(aiogram v3). Adapter registry pattern for future platform extensions (Discord, Slack, etc.) - Channel message router — 8-step processing pipeline: load bot, check access, handle commands (/start, /new, /help, /link, /unlink, /project), resolve identity, resolve session, rate-limit, invoke agent, send reply
- 3 new DB models —
ChannelBot(encrypted token, access policy, webhook config),ChannelIdentity(platform user ↔ app user linking with link codes),ChannelSession(bot+chat → conversation mapping) - Admin API routes — Full CRUD for bot management (
/channels/bots), activate/deactivate, webhook register/delete, session listing. All endpoints require admin role with properChannelBotCreate/ChannelBotUpdate/ChannelBotReadschemas - Webhook endpoint —
POST /telegram/{bot_id}/webhookwith signature verification, fire-and-forget async processing to stay within Telegram's 5s timeout - Supervised polling — Per-bot polling loop with 5s back-off restart on crash, managed via lifespan startup/shutdown
- CLI commands —
channel-list-bots,channel-add-bot,channel-webhook-register,channel-webhook-delete,channel-test-message AgentInvocationService— Framework-agnostic non-streaming agent invocation for all 6 AI frameworks, used by Telegram channel routeruse_telegramcookiecutter variable — Gates all Telegram code via Jinja2 conditionals. CLI interactive prompt added
PydanticDeep Framework (6th AI Framework)¶
- PydanticDeep integration — Deep agentic coding assistant built on pydantic-ai with filesystem tools (ls, read_file, write_file, edit_file, glob, grep), task management, subagent delegation, skills system, memory persistence, and context discovery
- Sandbox environment selection in CLI — New interactive prompt when selecting DeepAgents or PydanticDeep:
- PydanticDeep: Docker sandbox (default), Daytona workspace, State (in-memory)
- DeepAgents: Docker sandbox (default), State (in-memory)
sandbox_backendcookiecutter variable — ConfiguresPYDANTIC_DEEP_BACKEND_TYPE/DEEPAGENTS_BACKEND_TYPEin generated Settings- File upload to sandbox workspace — When users attach files in chat, files are written to the Docker/Daytona sandbox via
docker cp(or backend API) so the agent can access them withread_file. File paths are automatically included in the user message. Falls back to inline content for StateBackend - Project-scoped WebSocket endpoint —
ws/projects/{project_id}/chats/{conversation_id}for shared Docker containers per project
PydanticAI Capabilities¶
- WebSearch and WebFetch as default capabilities — All PydanticAI agents now include
WebSearch()andWebFetch()capabilities. Provider-adaptive: uses builtin when the model supports it natively, falls back to DuckDuckGo (search) and markdownify (fetch) - pydantic-ai bumped to >=1.80.0 with
duckduckgoandweb-fetchextras for local fallback support
Changed¶
- Removed LocalBackend from PydanticDeep — Server-side filesystem backends are not appropriate for web apps. Only Docker/Daytona sandbox and StateBackend are supported
- Removed
PYDANTIC_DEEP_WORKSPACE_DIRsetting — No longer needed without LocalBackend
Fixed¶
- pgvector
vectorstore.pyf-string SyntaxError —metadata JSONB DEFAULT '{}'::jsonbwas rendered inside a Python f-string, causingSyntaxError: f-string: empty expression not allowedin generated projects using pgvector. Escaped the braces so the f-string renders{}literally. (#65)
Telegram Channel Code Review Fixes¶
channels/router.py— Maderoute()alwaysasync def(was sync for SQLite, causingasyncio.get_event_loop().run_until_complete()crash). Removed broken_handle_command_sync,_resolve_identity_sync,_resolve_session_syncmethods. Added SQLite branches to all async methodschannels/router.py— Fixed/linkcommand: replaced non-existentchannel_link_repo.redeem_code()withchannel_identity_repo.get_by_link_code(). Code is invalidated after usechannels/router.py— Fixedbot.encrypted_token→bot.token_encryptedin_send_reply(). Fixedbot.system_prompt→bot.system_prompt_overrideandbot.model_override→bot.ai_model_overridechannels/router.py— Fixed MongoDB import paths:from app.db.models.channel import→from app.db.models.channel_identity import/from app.db.models.channel_session importchannels/router.py— Added_parse_policy()helper to normalizeaccess_policyfrom JSON string (SQLite) or dict (PostgreSQL/MongoDB)channels/telegram.py— Removed module-level singleton that conflicted with lifespan-managed adapter inmain.py. Fixed SQLite_handle_updatetoawait router.route()api/routes/v1/channels.py— Fixed all service method names (service.list_bots()→service.list(), etc.). Replaceddata: Anywith properChannelBotCreate/ChannelBotUpdateschemas. Addedresponse_modelto all endpoints. Made SQLite webhook routesasync(was usingasyncio.run()inside running loop)api/routes/v1/telegram_webhook.py— Fixed SQLite branch toawait router.route()(route is now always async)services/channel_bot.py— Generatewebhook_secretviasecrets.token_urlsafe(32)whenwebhook_mode=True(was alwaysNone). Addedlist_sessions()method to all 3 backendsrepositories/channel_session.py— Addedlist_by_bot()andcount_by_bot()functions to all 3 backendscommands/channel.py— Fixedbot.encrypted_token→bot.token_encrypted. Fixedchannel_bot_repo.list_all(platform=...)(no such parameter) → conditionalget_by_platform(). Fixedencrypted_token=→token_encrypted=in create
Tooling¶
- CI: MongoDB job — Added missing
ty checkstep (was present in minimal and PostgreSQL jobs but absent from MongoDB) - Template pre-commit — Bumped ruff-pre-commit from
v0.8.0tov0.15.0(consistent withpyproject.toml >=0.15.0)
Dependencies¶
- pydantic-ai
>=1.77.0→>=1.80.0(all providers + pydantic-deep) - pydantic-ai extras: Added
duckduckgoandweb-fetchextras for WebSearch/WebFetch local fallback - aiogram
>=3.17,<4.0(new — Telegram adapter) - slack-sdk
>=3.35.0(new — Slack Web API, Socket Mode, Events API) - cryptography
>=44.0.0(new — Fernet token encryption, gated underuse_telegram or use_slack)
[0.2.4] - 2026-04-09¶
Security¶
- SSRF protection for webhook URLs (CWE-918) — Added
validate_webhook_url()inapp/core/sanitize.pythat blocks private/reserved/loopback/link-local/multicast/CGNAT IPs, validates DNS resolution against internal networks, rejects non-http(s) schemes and URLs with credentials. Validation enforced at webhook create, update, and delivery time across all three database variants (PostgreSQL, SQLite, MongoDB). IncludesSSRFBlockedErrorexception with proper 422 responses and 39 unit tests. (PR #62)
[0.2.3] - 2026-04-05¶
Added¶
.claude/directory in generated projects — Full Claude Code project structure so generated projects work as AI-native codebases out of the boxsettings.json— Auto-allow permissions for safe operations (Read, Glob, Grep, git, pytest, ruff, ty, alembic)rules/architecture.md— Layered architecture patterns (Routes → Services → Repositories), DI withAnnotatedaliases,db.flush()convention, domain exceptionsrules/code-style.md— Type hints (str | None), naming conventions table, import ordering (stdlib → third-party → local), ruff configrules/schemas-models.md— Pydantic v2*Create/*Update/*Read/*Listpattern,BaseSchemawithConfigDict, SQLAlchemyMapped[]columns,TimestampMixinrules/exceptions-security.md— Domain exception hierarchy (AppException→NotFoundError, etc.), JWT/bcrypt patterns,RoleChecker, API key verificationrules/api-conventions.md— REST design, pagination (Query(ge=0, le=100)), auth deps (CurrentUser/CurrentAdmin/ValidAPIKey), response format, file uploadrules/testing.md— Async test patterns,httpx.AsyncClient, fixtures, exception testing withpytest.raisesrules/frontend.md— Next.js 15 App Router, Server Components, Tailwind conventions (auto-removed when frontend disabled)commands/review.md—/project:reviewslash command: checks changes against architecture, types, security, and runs lintingcommands/add-endpoint.md—/project:add-endpointslash command: scaffolds full CRUD (schema → model → repo → service → deps → route → migration → test)commands/fix-issue.md—/project:fix-issueslash command: traces through layers, fixes, tests, lints- Enhanced
CLAUDE.md— Rewritten with precise patterns from the actual codebase: architecture layers, DI pattern, schema conventions, exception table, response format examples, key conventions
Changed¶
- Replaced mypy with ty — Astral's Rust-based type checker (from the makers of ruff/uv). Updated across:
pyproject.toml, Makefile, CI (GitHub Actions + GitLab CI), pre-commit config,.gitignore - Dependency version bumps — All generated project dependencies updated to latest stable versions:
- Core: FastAPI 0.135.3, uvicorn 0.43.0, Pydantic 2.12.0, pydantic-settings 2.13.0
- Database: SQLAlchemy 2.0.40, asyncpg 0.31.0, alembic 1.18.0, sqlmodel 0.0.38, motor 3.7.0, beanie 1.29.0
- AI Frameworks: pydantic-ai 1.77.0, langchain 1.2.0, langchain-openai 1.1.0, langgraph 0.4.0, langgraph-checkpoint 4.0.0, crewai 1.13.0
- Vector Stores: pymilvus 2.6.0, qdrant-client 1.14.0, chromadb 1.5.0
- Infra: redis 7.3.0, celery 5.6.0, sentry-sdk 2.53.0, logfire 4.30.0, sqladmin 0.24.0, boto3 1.42.0
- Dev: pytest 9.0.0, ruff 0.15.0, ty 0.0.29
[0.2.2] - 2026-03-20¶
Changed — CLI Simplification (Breaking)¶
The interactive wizard and CLI have been significantly simplified. Many options that were previously user-configurable are now always enabled or have sensible defaults. This reduces decision fatigue and eliminates invalid configuration combinations.
- AI Agent always enabled — Removed
enable_ai_agentoption. AI agent with WebSocket streaming is always included. Stripped{%- if cookiecutter.enable_ai_agent %}conditionals from 53 template files. - Auth always JWT + API Key — Removed
AuthTypeenum and--authCLI option. JWT (user management, login, roles) + API Key (utility for programmatic access) are always included. StrippedWebSocketAuthType— WebSocket always uses JWT. - Database always required — Removed
DatabaseType.NONEand--database none. JWT needs user storage. Minimal preset now uses SQLite. - Conversation persistence always on — Removed
enable_conversation_persistenceoption. Chat history always saved to database. Stripped 139 template conditionals. - i18n always enabled — Removed
enable_i18noption.next-intlalways included with[locale]routing. Stripped 50 template conditionals. - Example CRUD removed — Removed
include_example_crudoption. Item model/routes/tests no longer generated. Post-gen hook always cleans up CRUD files. - Session management defaults to enabled — Changed default from
FalsetoTrue. - Admin panel simplified — Removed
AdminEnvironmentTypeenum and auth config prompts. Admin panel always usesdev_stagingenvironment restriction and always requires auth. Checkbox label clarified: "SQL Admin Panel (SQLAdmin) — web UI for browsing/editing database tables". - Background tasks default Celery — Changed default from
NonetoCelery. Celery is first option in wizard (was last).Noneoption kept for projects without Redis.
Added¶
CLI¶
--s3-ragflag — Enable S3/MinIO document ingestion from CLI (previously only available in interactive mode)- S3 ingestion prompt — Interactive wizard now asks "Enable S3/MinIO document ingestion?"
- Image description prompt — Interactive wizard now asks "Enable image description in documents?" for RAG
- Reranker type selection — Replaced boolean
--rerankerwith properRerankerTypeenum. User's choice (Cohere vs Cross-Encoder) is now preserved instead of being auto-determined by LLM provider - PDF Parser "All" option — New option installs all 3 parsers (PyMuPDF, LiteParse, LlamaParse). Runtime selection via
PDF_PARSERandCHAT_PDF_PARSERenv vars.PdfParserFactorycreates parser on demand - RAG without Celery — RAG now works with
BackgroundTasks(no Celery/Taskiq/ARQ required). Ingestion and sync run in-process via FastAPIBackgroundTasks. Removed validation that blocked RAG without a task queue - Retry, sync logs, cancel endpoints always available — Previously gated behind Celery/Taskiq/ARQ, now work with any background task backend
Backend¶
CHAT_PDF_PARSERenv var — Separate parser config for chat file attachments (independent from RAG ingestion). Defaults topymupdffor speedPdfParserFactory— Factory class for runtime PDF parser selection when "All" parsers installed- Conversation IDOR protection —
get_conversation()now validatesuser_idownership. Users can only access their own conversations - OAuth null password guard —
authenticate()checksuser.hashed_password is not Nonebeforeverify_password(). Prevents crash for OAuth-only users - ChatFile cascade delete — Added
ondelete="CASCADE"touser_idandmessage_idforeign keys in all 4 DB variants - SQLite ToolCall args deserialization — Added
field_validatoronToolCallBase.argsthat deserializes JSON strings for SQLite compatibility - Embedding dimension validation — Runtime check in
EmbeddingServicethat embedding output matches configureddim. RaisesValueErroron mismatch - Collection name validation — Regex check
^[a-zA-Z][a-zA-Z0-9_]{0,63}$on collection creation. Prevents SQL injection in pgvector and invalid names - Vector store connection cleanup — Qdrant
client.close()and PgVectorengine.dispose()in lifespan shutdown
RAG¶
- ChromaDB async compliance — All ChromaDB operations wrapped in
asyncio.to_thread()to avoid blocking the event loop - ChromaDB
_ensure_collection()— Added missing method.POST /collections/{name}now works with ChromaDB - ChromaDB filter support —
search()now parsesparent_doc_idfilter and passes as ChromaDBwhereclause - ChromaDB consistent metadata — Now uses
_build_chunk_metadata()(same as Milvus/Qdrant/pgvector) - Qdrant filter support —
search()now parses filter string and passes asquery_filterwithFieldCondition - RRF fusion key fix — Changed merge key from
content[:100](collision-prone) toparent_doc_id:chunk_num
Frontend¶
- Refresh token rotation —
/api/auth/refreshnow updatesrefresh_tokencookie when backend returns a new one - WebSocket connection guard — Prevents orphaned WebSocket instances by checking
CONNECTINGstate - Scroll pagination guard — Conversation sidebar scroll handler checks
isLoading+ fetch mutex prevents concurrent requests - Message deduplication — Chat messages cleared before loading conversation history, preventing duplicates on switch
Fixed¶
- Port validator — Returns descriptive error messages ("Port must be between 1024 and 65535") instead of generic
False - Reverse proxy default —
ReverseProxyType.NONEwhen Docker disabled (wasTRAEFIK_INCLUDED) - OpenRouter validation — Consolidated 4 separate checks into single message: "OpenRouter is only supported with PydanticAI, not {framework}"
- RAG prompt cancellation — All questionary calls in
prompt_rag_config()now wrapped with_check_cancelled(). Ctrl+C during RAG config shows "Cancelled." instead of crashing - Stale docstring — Removed bogus
Args: llm_providerfromprompt_rag_config()(function has no parameters) - Hardcoded
lang="en"— Root layout now uses locale from i18n config - Milvus version pinned — Dev compose files use
v2.5.10(waslatest), matching production - Frontend CI — Added
bun run lintandbun run type-checksteps to CI pipeline - Tailwind CSS — Updated from
^4.0.0-beta.8to^4.0.0(stable) - SQLite WebSocket auth —
contextmanager(get_db_session)()pattern verified working with mypy TYPE_CHECKINGimport for ChatFile — Added to SQLAlchemy PG and SQLite conversation model variants- Duplicate import — Removed duplicate
import Image from "next/image"inmessage-item.tsx - RAG search result off-by-one — Fixed array indexing in expanded view, uses
.find()by index value - Login loading state —
setLoading(false)now infinallyblock (was only incatch) - Refresh cookie clearing — Cookie options (
httpOnly,secure,sameSite) now consistent with logout route - Tool call status fallback —
statusConfig[status]falls back topendingfor unknown statuses
Added¶
Frontend — Landing Page¶
- Floating navbar with animated beam border — Pill-shaped navbar with rotating conic-gradient border in brand color, glass morphism background, adaptive dark/light mode
- Tech stack marquee — Infinite scrolling carousel with all project technologies (30+ items), edge fade mask, 60s animation loop
- Grid background — 64px grid pattern on hero section with radial gradient mask fade
- Glass cards — Frosted glass feature cards with backdrop-blur, hover lift animation, dark/light mode variants
- Brand color system — Global
--color-brandCSS variable (oklch), configurable hue presets (blue, green, red, violet, orange). Changes one value to retheme entire app - Footer — Two-column footer with product links, resources, API docs link, copyright
Frontend — Auth¶
- Split layout login/register — Left panel: dark bg with grid, gradient glow, heading, feature pills (AI Chat, KB, Auth, Real-time), quote. Right panel: form with contrasting background. Mobile: form only
- Auth guard — Client-side
AuthGuardcomponent wraps dashboard layout, redirects unauthenticated users to/loginwith loading spinner
Frontend — Dashboard¶
- Personalized greeting — "Good morning/afternoon/evening, {name}" based on time of day
- Stats row — Compact 4-column cards (API status, Conversations, Knowledge Base, AI Agent)
- Recent conversations — Last 5 chats with relative timestamps, skeleton loading
- Collections overview — Clickable RAG collection list with vector counts and status badges
- Quick actions grid — 2x2 icon grid (New Chat, Upload Docs, API Docs, Profile)
- Account card — Avatar with initials, email, role, registration date
- Environment card — Status, version, framework, LLM, vector store info
Frontend — Chat¶
- "Thinking..." indicator — Animated bounce dots before first content arrives from LLM
- Copy buttons — Appear on hover under both user and assistant messages (moved from inside bubble)
- Message timestamps — HH:MM format under each message, hidden during streaming
- File upload system — Upload images, text, PDF, DOCX via backend API. Thumbnail preview for images, badge for files. Files parsed on backend (PyMuPDF for PDF, python-docx for DOCX)
- Image support (LLM Vision) — Images sent as
BinaryContentto PydanticAI agent for vision analysis. Stored inmedia/directory, linked to messages viaChatFilemodel - Microphone (Speech-to-Text) — Web Speech API voice input button, always visible, toast fallback for unsupported browsers
- Message queue — Input not disabled during processing. Messages queued on frontend, auto-sent when bot finishes responding
- Model selector — Dropdown in chat status bar (Claude Sonnet 4, Claude 3.5 Sonnet, GPT-4o, GPT-4o Mini, Gemini 2.5 Flash). Backend
get_agent(model_name=...)accepts override - Tool call persistence — Tool calls (name, args, result, status) saved to database during WebSocket streaming. Visible when loading conversation history
Frontend — Knowledge Base (RAG Dashboard)¶
- Sidebar layout — Collections in left sidebar (collapsible), documents/search in main area
- Create collection — Inline input in sidebar with "+" button
- Upload & ingest — File upload → backend ingestion (parse, chunk, embed, store). Supports PDF, DOCX, TXT, MD. Max 50MB
- Document tracking —
RAGDocumentmodel in database: status (processing/done/error), error message, timestamps, storage path - Document list — Per-collection with filename, type badge, size, date, status icon (spinner/check/error)
- View original — Eye icon opens original uploaded file (stored in local storage / S3)
- Delete document — AlertDialog confirmation, removes from vector store + file storage + SQL
- Search — Full-text vector search with score badges, source document linking ("View source")
Frontend — UI Components (shadcn/ui + Radix)¶
- Dialog —
@radix-ui/react-dialogbased modal with overlay, close button, fade+zoom animations - AlertDialog —
@radix-ui/react-alert-dialogfor destructive action confirmations (delete collection, delete document) - Avatar —
@radix-ui/react-avatarwith image support and initial fallback - Skeleton — Pulse animation placeholder for loading states
- Separator —
@radix-ui/react-separatorfor visual dividers - Tooltip —
@radix-ui/react-tooltipwith TooltipProvider - Button
asChildfix —@radix-ui/react-slotenables properasChildprop on Button component
Frontend — Navigation & Layout¶
- Nav links in header — Dashboard, Chat, Knowledge Base, Profile tabs with icons and active state (moved from sidebar)
- Sidebar → mobile only — Desktop sidebar removed, kept as Sheet drawer for mobile
- Language switcher — Segmented control buttons (EN | PL) with
router.pushlocale switching - Softer dark theme — Zinc-inspired tones (14.5% lightness, subtle blue-purple hue 285) replacing pure black (12%)
BACKEND_URLconstant — API docs links point to backend (http://localhost:8000/docs), not frontend- Page transition animations — Fade-in + 6px slide-up animation (250ms ease-out) on dashboard page navigation via
PageTransitioncomponent withkey={pathname}re-mount - Breadcrumbs — Auto-generated breadcrumb navigation on Profile and Settings pages with
aria-label="Breadcrumb", chevron separators, clickable parent links
Frontend — Error Handling¶
- 404 page —
not-found.tsxwith "Page not found" message, "Go home" and "Dashboard" buttons, brand-colored styling - 500 error boundary —
global-error.tsxwith inline styles (no CSS dependency), "Try again" reset button, error digest ID display - Page error boundary —
[locale]/error.tsxcatches errors within layout, preserves header/sidebar, "Try again" + "Go home" buttons
Frontend — Accessibility¶
aria-current="page"— Active nav items in header marked for screen readersaria-live="polite"— Loading/status changes announced: auth guard, chat "Thinking..." indicator, RAG upload progress, RAG document status iconsaria-hidden="true"— Decorative bounce dots and spinner icons hidden from screen readersrole="status"— RAGStatusIconcomponent with descriptivearia-label(Completed/Failed/Processing)
Backend — File System¶
ChatFilemodel — Tracks files uploaded in chat (user_id, message_id, filename, mime_type, storage_path, file_type, parsed_content)LocalFileStorageservice — Save/load/delete files inmedia/{user_id}/directory. ExtensibleBaseFileStorageABC for S3/MinIOPOST /files/upload— Multipart upload with MIME validation, 10MB limit, auto-parsing (text/PDF/DOCX)GET /files/{id}— Download with owner-only access check- File linking — Files linked to messages via
message_idFK, loaded with conversation history
Backend — RAG Improvements¶
- Async Celery ingestion —
POST /rag/collections/{name}/ingestreturns202 Acceptedand dispatchesingest_document_taskto Celery worker. Falls back to synchronous ingestion when Celery is not enabled - WebSocket status updates —
WS /rag/ws/statusendpoint subscribes to Redis pub/sub channelrag_status, forwards real-time ingestion status (processing → done/error) to frontend - RAG is global — Removed
user_idfromRAGDocumentmodel. All documents, collections, and vectors are shared across users (no per-user isolation) - CLI DB tracking —
rag-ingestCLI command now createsRAGDocumentrecords in SQL for each file. Documents ingested via CLI appear in the Knowledge Base dashboard with status tracking - Retry endpoint —
POST /rag/documents/{id}/retryresets failed document status toprocessingfor re-ingestion RAGDocumentmodel — Tracks ingestion status (processing/done/error), error_message, vector_document_id, storage_path, timestampsGET /rag/documents— List tracked documents with collection filterGET /rag/documents/{id}/download— Download original ingested fileDELETE /rag/documents/{id}— Removes from vector store + file storage + SQL (3-way cleanup)- Configurable upload size —
MAX_UPLOAD_SIZE_MBsetting (default 50MB) used in file upload, RAG ingest, and health endpoint. Frontend reads fromNEXT_PUBLIC_MAX_UPLOAD_SIZE_MBenv var - Batch upload — Frontend RAG page supports multi-file upload with progress bar (X/Y files, filename indicator)
- Filename fix in ingestion —
document.metadata.filenameset fromsource_pathinstead of temp file name EmbeddingsConfigmodel validator — Auto-derives vector dimensions from model name viaEMBEDDING_DIMENSIONSlookup tableEMBEDDING_MODELenv var wired — Settings → RAGSettings → EmbeddingsConfig flow complete
Backend — Agent Improvements¶
- Tool call persistence — WebSocket handler collects tool calls during streaming, saves to DB after assistant message
- Conversation title auto-set — Backend updates conversation title from first user message when title is empty
- Model selection — WebSocket handler accepts
modelfield, passes toget_agent(model_name=...) - File handling in WS — Parses
file_idsfrom WebSocket message, loads files, images →BinaryContentfor LLM vision, text/PDF/DOCX → parsed content appended to prompt
Backend — Security & Compliance¶
- PII redaction in logs —
PiiRedactionFilterlogging filter scrubs emails, JWT tokens, API keys (OpenAI/Anthropic), Bearer tokens, and password-like values from all log output. Prevents PII leaks to log aggregators (Datadog, CloudWatch, Logfire). Activated viasetup_logging()at app startup - Dependency vulnerability scanning — CI pipeline includes
securityjob withpip-auditfor supply chain risk detection - Docker image scanning — Trivy vulnerability scanner (
aquasecurity/trivy-action@0.28.0) runs after Docker build in CI, reports CRITICAL and HIGH severity issues
Backend — Database & Infrastructure¶
- Missing indexes added —
users.oauth_provider,users.oauth_id,sessions.user_id,webhooks.user_id,webhook_deliveries.webhook_id,webhook_deliveries.created_at(all SQL variants) MEDIA_DIRconfig — New setting for file storage directoryimport sqlmodelin migrations — Added toscript.py.makotemplate for SQLModel projects- Graceful RAG startup — Embedding, reranker, vector store warmup wrapped in try/except, app doesn't crash on failure
Changed¶
- Auth layout theme-aware — Left hero panel now adapts to light/dark mode (
bg-zinc-100 dark:bg-zinc-950) instead of hardcodedbg-zinc-950 next/imagemigration — Chat file thumbnails and attached images usenext/imagewithunoptimizedfor lazy loading and layout stability- Consistent loading states — All
"..."placeholder text and"Loading..."messages replaced withSkeletoncomponents (dashboard stats, conversation sidebar, OAuth callback) - RAG sidebar responsive — Sidebar width
w-52 lg:w-64(narrower on tablets, full width on desktop) - Empty search state — RAG search shows in-UI "No results found" with icon instead of toast-only
- Profile inline update —
window.location.reload()replaced with ZustandsetUser()for instant state update without page reload - Real-time form validation — Register: email format on blur, password strength bar (Weak/Fair/Good/Strong), confirm password match indicator. Login: email format on blur
TimestampMixinusessa_column_kwargs— Fixed SQLModel shared Column object bug (Column 'created_at' already assigned to Table)MessageListschema — Changed fromMessageReadSimple(no tool_calls) toMessageRead(with tool_calls + files)list_messagesendpoint — Now passesinclude_tool_calls=Trueto eagerly load tool call relationships- RAG proxy routes — Removed
NEXT_PUBLIC_AUTH_ENABLEDgate, always forward auth cookie if present - Removed unused code —
pipelines/directory,repositories/base.py,worker/tasks/rag_ingestion.py(reindex task),test_pipelines.py,docs/howto/add-data-pipeline.md - Removed section dividers —
# =========comments removed fromservices/conversation.py,repositories/conversation.py,schemas/conversation.py itsdangerousdependency — Added when OAuth enabled (required by StarletteSessionMiddleware)loggeradded tomain.py—import logging+logger = logging.getLogger(__name__)for RAG startup error logging- Document ingestion is CLI-only - Removed upload API endpoints. Ingestion exclusively via CLI commands (later re-added as
POST /rag/collections/{name}/ingest) RetrievalServicerenamed -MilvusRetrievalService→RetrievalService(now backend-agnostic)- Docker validation relaxed - Docker only required for Milvus and Qdrant vector stores
.env.examplerestructured - RAG section moved fromuse_milvustoenable_ragguard- README.md rewritten - Updated for 5 frameworks, 4 providers, RAG section with vector store/embedding tables
- CLAUDE.md / AGENTS.md updated - Both project-level and template versions updated with RAG, Gemini, vector stores
Fixed¶
- Language switching —
usePathname()with next-intl returns path with locale prefix, originalsegments[1] = newLocale+router.pushlogic restored - Conversation "20531d ago" —
updated_atnull fallback tocreated_atin dashboard - RAG stats "..." — Set
{collections: [], totalVectors: 0}on error instead of null callable | NoneTypeError — Changed toCallable | Nonewith proper import iningestion.py- Tool call card TS error —
Type 'unknown' not assignable to ReactNodefixed with ternary - Empty args crash —
json.loads("")in tool call persistence fixed with.strip()check user_promptserialization —BinaryContentnot JSON serializable, now sends text-only prompt in WS event- File linking FK violation — ChatFile
message_idupdate moved to same DB session as message insert
RAG (Retrieval-Augmented Generation) — Pipeline¶
- RAG integration - Full RAG pipeline: document parsing → chunking → embedding → vector store → retrieval. Integrated with all 5 AI frameworks as
search_knowledge_basetool - 4 vector store backends - Milvus (Docker), Qdrant (Docker), ChromaDB (embedded), pgvector (PostgreSQL extension). Selected via
vector_storeconfig option - 4 embedding providers - OpenAI (
text-embedding-3-small), Voyage (voyage-3), Google Gemini (gemini-embedding-exp-03-07, multimodal), SentenceTransformers (all-MiniLM-L6-v2) - Document parsers - PyMuPDF (PDF text + tables + headers/footers + images + OCR), LlamaParse (130+ formats via cloud API, configurable tier), python-docx (DOCX), native (TXT/MD)
- Image description - Optional extraction of images from documents via PyMuPDF + LLM vision API description (OpenAI GPT-4o / Anthropic Claude / Gemini / OpenRouter). Opt-in via
enable_rag_image_description - Chunking strategies - 3 strategies:
recursive(default),markdown(split by headers),fixed(simple fixed-size). Configurable viaRAG_CHUNKING_STRATEGYenv var - Hybrid search - BM25 keyword search + vector similarity search with Reciprocal Rank Fusion (RRF). Enable via
RAG_HYBRID_SEARCH=true - Reranking - Cohere API or local CrossEncoder for improved search quality
- Citation/source tracking - Agent tool returns
[1] Source: filename, page X, chunk Yformat. Agent prompt instructs citation with[1],[2]references and source list - Document versioning -
source_path(local path /gdrive://id/s3://bucket/key) andcontent_hash(SHA256) in metadata. Automatic deduplication: re-ingest replaces old chunks. CLI:--replace/--no-replace - Multi-collection search -
RetrievalService.retrieve_multi()searches across multiple collections. API:collection_names: list[str]. Frontend: "All collections" option - Document sources - Local files (CLI
rag-ingest), Google Drive (service account, CLIrag-sync-gdrive), S3/MinIO (CLIrag-sync-s3). ExtensibleBaseDocumentSourceABC - Ingestion progress -
tqdmprogress bar in CLIrag-ingestwith per-file status and replaced count - RAG management page - Frontend
/ragpage: collection list with stats, search preview with results, metadata filters (filetype, min score), multi-collection support, delete collection - RAG API endpoints -
GET/POST/DELETE /rag/collections,GET /rag/collections/{name}/info,GET /rag/collections/{name}/documents,POST /rag/search,DELETE /rag/collections/{name}/documents/{id} - RAG CLI commands -
rag-collections,rag-ingest,rag-search,rag-drop,rag-stats,rag-sync-gdrive,rag-sync-s3
AI / LLM¶
- Google Gemini LLM provider - New
--llm-provider googleoption. PydanticAI:GoogleModel+GoogleProvider. LangChain/LangGraph/CrewAI/DeepAgents:ChatGoogleGenerativeAI. Dependencies:pydantic-ai-slim[google],langchain-google-genai - Gemini multimodal embeddings -
GeminiEmbeddingProviderwithembed_image()for native multimodal (text + images in same vector space). Model:gemini-embedding-exp-03-07(3072 dim)
Frontend¶
- Toast notification system -
sonnerlibrary with<Toaster />in providers. Toast feedback on: login, register, logout, profile save, RAG operations - Profile save wired - "Save Changes" button now calls
PATCH /users/me. Editable email field, loading state, toast feedback - Dashboard redesigned - Stats cards (API status, account, AI framework, RAG vector count), quick action links (Chat, Knowledge Base, Profile)
- Settings page - New
/settingspage with sections: Appearance (theme toggle), Application (project info, AI framework, vector store), Stack (technology badges), Security (auth type, rate limiting) - Metadata filtering UI - RAG search page: filetype dropdown, min score dropdown, "Clear filters" link
- Specialized tool call cards - DateTime tool: Calendar/Clock icons with formatted date/time. RAG search: horizontal card carousel with filename, page, score badges, expandable content. Toggle between formatted and raw JSON view
- Sidebar "Knowledge Base" link - Navigation item with Database icon, conditional on
enable_rag
DevOps¶
make quickstart- One command to install deps, start Docker services, run migrations, create admin user- Vercel deployment -
frontend/vercel.jsonconfig +make vercel-deploytarget with env var instructions - Qdrant Docker service - Added to
docker-compose.dev.ymlwith health check, volume, and backend env vars
PR #50 RAG Bug Fixes (28 issues found and fixed)¶
schedules.pyregression - Outer conditional broke Taskiq scheduling for all non-RAG projects. Fixed: restoreduse_taskiqguard, RAG schedule inside nested conditional- Duplicate Milvus settings -
core/config.pyhad Milvus settings twice. Fixed: removed duplicate, nested underuse_milvusinsideenable_rag - Env vars not wired to RAGSettings -
RAG_CHUNK_SIZE,RAG_DEFAULT_COLLECTIONignored at runtime. Fixed: wired throughSettings.ragcomputed property - Copy-paste etcd command in prod MinIO -
docker-compose.prod.ymlminio had etcd command. Fixed: removed - Frontend type mismatch -
RAGSearchResult.textvs backendcontent. Fixed: renamed tocontent, addedparent_doc_id - Milvus filter injection -
document_idinterpolated unsanitized. Fixed: strip"and\before interpolation - File upload security - No filename sanitization, no size limit. Fixed:
_safe_filename(),MAX_UPLOAD_SIZE=50MB, HTTP 413 - Hardcoded MinIO credentials in prod - Fixed: env var substitution
${MINIO_ROOT_USER}/${MINIO_ROOT_PASSWORD} milvusdb/milvus:latestin prod - Fixed: pinned tov2.5.10processor.parser.allowedAttributeError - Fixed: useDocumentExtensionsenum directly- Inconsistent default collection - sync wrapper
"default"vs async"documents". Fixed: both"documents" RerankServiceNameError when disabled - Fixed:from __future__ import annotationsprint()in reranker.py - Fixed: all 13print()→logger.info()console.login rag-api.ts - Fixed: removed debug statements- Legacy typing imports in schemas - Fixed:
List→list,Dict→dict,Optional→| None - Hardcoded
/tmp/rag_uploads- Fixed:tempfile.gettempdir() - Inconsistent frontend auth - Fixed: all RAG routes use
NEXT_PUBLIC_AUTH_ENABLEDpattern - Inline
import loggingin routes - Fixed: moved to module level - Unconditional PDF parser import - Fixed: conditional on
not use_llamaparse - Chat page not removed when i18n disabled - Fixed: remove both
[locale]/and direct paths stores/index.tsunconditional chat exports - Fixed: previously gated behindenable_ai_agent(now always enabled)types/index.tsunconditional chat export - Fixed: previously gated behindenable_ai_agent(now always enabled)chat-sidebar-store.tsnot cleaned up - Fixed: added to post-gen hookrag/config.pygated byuse_milvus- Fixed: changed toenable_rag- Worker tasks gated by
use_milvus- Fixed:rag_ingestion.py,celery_app.py,arq_app.pychanged toenable_rag - pgvector SQL injection - Fixed:
_validate_collection_name()regex +_table()helper in all methods - pgvector IVFFlat on empty table - Fixed: changed to HNSW index
- Duplicate
loggerin reranker.py - Fixed: removed duplicate, reordered imports
[0.2.1] - 2026-03-05¶
Added¶
- LangSmith observability integration - New
enable_langsmithoption for LangChain, LangGraph, and DeepAgents frameworks. AddsLANGCHAIN_TRACING_V2,LANGCHAIN_API_KEY,LANGCHAIN_PROJECT,LANGCHAIN_ENDPOINTsettings andlangsmithdependency when enabled. Includes interactive prompt,--langsmithCLI flag, and auto-enable inai-agentpreset. Previously LangSmith env vars were hardcoded to appear with LangChain — now requires explicit opt-in and works with all 3 LangChain-ecosystem frameworks. - CLI:
--conversation-persistenceflag - Enable conversation persistence from the command line (previously only available interactively) - CLI:
--websocket-authoption - Set WebSocket authentication method (none,jwt,api_key) from the command line
Changed¶
- CLI runs interactive wizard by default -
fastapi-fullstacknow launches the configurator directly without requiringnewsubcommand - CLI branding updated - Banner, descriptions, and prog name updated from "fastapi-gen / FastAPI Project Generator with Logfire" to "Full-Stack AI Agent Template Generator"
templatescommand expanded - Now lists all 5 AI frameworks, LangSmith, ORM options, WebSocket auth, conversation persistence, and port options
Fixed¶
CLI Fixes¶
--ai-frameworkmissing 3 frameworks - Addedlanggraph,crewai,deepagentsto choices (previously onlypydantic_aiandlangchain)
Backend Template Fixes¶
- Unconditional
import logfireinversioning.py- Replaced withloggingmodule to preventImportErrorwhen Logfire is disabled - Unconditional
import logfireinwebhook.py- Replacedlogfire.error()/logfire.info()withlogger.error()/logger.info()in all 3 database sections (PostgreSQL, SQLite, MongoDB) to preventImportErrorwhen Logfire is disabled but webhooks are enabled backend/.envLangSmith conditional wrong - Was gated byuse_langchaininstead ofenable_langsmith(only.env.examplewas updated,.envwas missed)backend/.envmissing sections - Added OAuth Google, ARQ, and Prometheus sections that were present in.env.examplebut absent from generated.env
Frontend Template Fixes¶
- Sidebar "Chat" link visible without AI agent - Chat navigation item now always visible (AI agent is always enabled)
- Frontend chat files not cleaned up - No longer applicable (AI agent is always enabled, chat files are always present)
- Chat component exports unconditional - Chat exports are now always included (AI agent is always enabled)
- Chat hook exports unconditional - Hook exports for
useWebSocket,useChat,useLocalChatare now always included (AI agent is always enabled) WS_URLandROUTES.CHATalways defined -constants.tsnow conditionally defines WebSocket URL and chat route only when AI agent is enabled
[0.2.0] - 2026-02-27¶
Changed¶
- Repository renamed from
full-stack-fastapi-nextjs-llm-templatetofull-stack-ai-agent-template— all internal links, badges, raw.githubusercontent URLs, mkdocs config, and template files updated. Old GitHub URLs redirect automatically. - Repository marked as GitHub Template — users can now click "Use this template" to create a new repo directly from GitHub
- README CTA section — replaced "Made with" footer with Vstorm consultancy call-to-action
[0.1.18] - 2026-02-01¶
Fixed¶
- Removed macOS
.DS_Storeartifacts and added.DS_Storeto.gitignore(contributed by @vladdoster in #42)
[0.1.17] - 2026-01-24¶
Added¶
- MkDocs Material documentation site with pink theme, Inter/JetBrains Mono fonts
- New documentation pages:
docs/index.md- Landing page with quick start and features overviewdocs/installation.md- Installation guide with uv/pip/pipx optionsdocs/getting-help.md- FAQ and support resourcesdocs/concepts/index.md- Architecture overview with Mermaid diagramsdocs/guides/quick-start.md- Step-by-step first project guidedocs/guides/configuration.md- All configuration options- GitHub Actions workflow for automatic docs deployment (
docs.yml) - Custom styling (
docs/stylesheets/extra.css) matching pydantic-deep theme - GitHub announcement bar in docs header
Changed¶
- README.md redesign:
- New centered header with "Full-Stack AI Agent Template" title
- Reorganized badges: AI frameworks (PydanticAI, LangChain, LangGraph, CrewAI, OpenAI, Anthropic, OpenRouter) moved to Features section
- Added infrastructure badges: FastAPI, Next.js 15, React 19, TypeScript, Tailwind v4, SQLAlchemy, PostgreSQL, MongoDB, Redis, Celery, Logfire, Sentry, Prometheus, Docker, Kubernetes, GitHub Actions, S3
- New highlights: "🤖 PydanticAI • 🦜 LangChain, LangGraph & DeepAgents • 👥 CrewAI • 🎯 Fully Type-Safe"
- Moved
CHANGELOG.mdfromdocs/to project root (symlinked in docs) - Added
docsoptional dependency group with mkdocs packages
[0.1.16] - 2026-01-20¶
Fixed¶
- Logfire Celery instrumentation prompt - Celery instrumentation option now only appears when Celery is selected as background task system (previously caused validation error when selecting the option with Taskiq/ARQ)
Changed¶
- Prompt order - Background tasks prompt now appears before Logfire prompt to enable dynamic feature filtering
Tests Added¶
- Test for Celery instrumentation option visibility based on background task selection
[0.1.15] - 2026-01-18¶
Added¶
DeepAgents Framework Support¶
- DeepAgents as fifth AI framework option alongside PydanticAI, LangChain, LangGraph, and CrewAI
- New
--ai-framework deepagentsCLI option for project creation - Interactive prompt includes "DeepAgents" choice
- Built-in tools for file operations, code execution, and task management:
ls,read_file,write_file,edit_file,glob,grepexecute(disabled by default for safety)write_todos,task(sub-agents)- StateBackend for in-memory file state management
- Skills support via
DEEPAGENTS_SKILLS_PATHSenvironment variable - New template files:
app/agents/deepagents_assistant.py- DeepAgentsAssistant class with run() and stream()- WebSocket route implementation with interrupt handling
- New cookiecutter variable:
use_deepagents - Dependencies:
deepagents>=0.1.0
Human-in-the-Loop (HITL) Support¶
- Tool approval workflow for DeepAgents allowing users to approve, edit, or reject tool calls
- Configurable via
DEEPAGENTS_INTERRUPT_TOOLSenvironment variable: - Comma-separated tool names (e.g.,
write_file,edit_file,execute) - Or
allto require approval for all tools - Frontend tool approval dialog (
tool-approval-dialog.tsx): - Shows pending tool calls with JSON args in editable textarea
- Cancel/Save buttons for editing args
- Submit button to send decisions
- Auto-detects changes and sends appropriate decision (approve/edit/reject)
- WebSocket protocol for interrupt handling:
- Backend sends
tool_approval_requiredevent with action requests - Frontend sends
resumemessage with user decisions - Thread ID management for state persistence across interrupts
- New types in
chat.ts:ActionRequest,ReviewConfig,PendingApproval,Decision - Updated hooks (
use-chat.ts,use-local-chat.ts) with: pendingApprovalstatesendResumeDecisions()function- Environment variables:
DEEPAGENTS_INTERRUPT_TOOLS- tools requiring approvalDEEPAGENTS_ALLOWED_DECISIONS- allowed decision types (approve, edit, reject)
Fixed¶
- OAuth requires JWT authentication - Added validation that OAuth providers (Google) require JWT auth to be enabled, preventing invalid configuration combinations
Changed¶
AIFrameworkTypeenum extended withDEEPAGENTSvalue- AI framework prompt now shows five options: PydanticAI, LangChain, LangGraph, CrewAI, DeepAgents
- LLM provider validation - OpenRouter not supported with DeepAgents (uses LangChain providers directly)
VARIABLES.mdupdated withuse_deepagentsdocumentation- Template
CLAUDE.mdincludes DeepAgents in stack section CONTRIBUTING.mdupdated with correct repository URL
Tests Added¶
- Tests for
DEEPAGENTSenum value - Tests for DeepAgents + OpenRouter validation (combination is rejected)
- Tests for
use_deepagentscomputed field - Tests for cookiecutter context generation with DeepAgents
[0.1.14] - 2026-01-16¶
Fixed¶
- Dynamic version reading -
fastapi-fullstack --versionnow correctly displays the version frompyproject.tomlusingimportlib.metadatainstead of hardcoded value
Security¶
- CVE-2026-22701 - Updated
filelockto 3.20.3 - CVE-2026-21441 - Updated
urllib3to 2.6.3 - CVE-2026-22702 - Updated
virtualenvto 20.36.1
[0.1.13] - 2026-01-06¶
Added¶
Comprehensive Configuration Validation¶
- New validation rules to prevent invalid option combinations at config time:
- WebSocket JWT auth requires main JWT auth to be enabled
- WebSocket API key auth requires main API key auth to be enabled
- Admin panel authentication requires JWT auth (for User model)
- Conversation persistence requires AI agent to be enabled
- Admin panel requires SQLAlchemy ORM (SQLModel not fully supported by SQLAdmin)
- Session management requires JWT auth
- Webhooks require a database to store subscriptions and delivery history
- Background task queues (Celery/Taskiq/ARQ) require Redis as broker
- Logfire database instrumentation requires a database
- Logfire Redis instrumentation requires Redis
- Logfire Celery instrumentation requires Celery as background task system
Improved Post-Generation Instructions¶
- Clearer database setup instructions with warning message:
- README.md updated with prominent warning about required migration steps
- Commands displayed with aligned descriptions for better readability
Dynamic Integration Prompts¶
- Context-aware integration options in interactive wizard:
- Admin Panel option only shown when SQLAlchemy is selected (not SQLModel)
- Webhooks option only shown when a database is enabled
- WebSocket auth options filtered based on main auth type selected
- Clearer ORM selection labels: "SQLAlchemy — full control, supports admin panel" vs "SQLModel — less boilerplate, no admin panel support"
- Auto-enable Redis when caching is selected (with info message)
- Better descriptions for all integration options explaining dependencies
Template Improvements¶
- ARQ worker service added to
docker-compose.prod.yml - Prometheus labels added to backend service in
docker-compose.dev.yml - OAuth environment variable
NEXT_PUBLIC_API_URLadded to frontend.env.example - Frontend WS_URL now uses
backend_portcookiecutter variable instead of hardcoded 8000
Changed¶
Post-Generation Hook Improvements¶
- Stub file cleanup - removes files containing only docstrings with no actual code
- Auth file cleanup - removes auth/user files when JWT is disabled:
auth.py,users.pyroutesuser.pymodel, repository, service, schematoken.pyschema- Logfire cleanup - removes
logfire_setup.pywhen Logfire is disabled - Security cleanup - removes
security.pywhen no auth is configured at all - LangGraph/CrewAI cleanup - properly removes unused AI framework files
Fixed¶
Template Fixes¶
- LangChain assistant
stream()method - changed from sync generator to async generator usingastream()for proper async streaming - OAuth callback - made fully async, removed sync
asyncio.new_event_loop()hack - Deprecated
datetime.utcnow()- replaced withdatetime.now(UTC)across all services: cleanup.pycommandsession.pyrepository and serviceconversation.pyservicewebhook.pyservice- Session model - added missing
default_factory=datetime.utcnowforcreated_atandlast_used_atfields - Webhook model - moved
import jsonto module level instead of inside properties - Admin panel template condition - now correctly checks for SQLAlchemy ORM requirement
- Caching setup - only runs when both caching AND Redis are enabled
- Config imports - fixed conditional imports for Redis-only projects (no database)
Tests Added¶
- 290+ new test lines covering all new validation rules
- Tests for WebSocket auth requiring main auth
- Tests for admin panel requiring SQLAlchemy
- Tests for admin authentication requiring JWT
- Tests for conversation persistence requiring AI agent
- Tests for webhooks requiring database
- Tests for Logfire feature dependencies (database, Redis, Celery)
- Tests for background task queues requiring Redis
- Updated CLI tests to include
--redisflag with task queue options
[0.1.12] - 2026-01-02¶
Added¶
CrewAI Multi-Agent Framework Improvements¶
- Full type annotations for all CrewAI event handlers in
crewai_assistant.py - Comprehensive event queue listener with handlers for:
crew_started,crew_completed,crew_failedagent_started,agent_completedtask_started,task_completedtool_started,tool_finishedllm_started,llm_completed- Improved stream method with proper thread and queue handling:
- Natural completion path when receiving None sentinel
- Race condition handling for thread death scenarios
- Defensive code with
# pragma: no coverfor edge cases - 100% test coverage for CrewAI assistant module
Fixed¶
Backend Fixes¶
- Type annotations - All mypy errors fixed across the codebase:
- Added
Anytypes where needed inlogfire_setup.py - Fixed
Callabletypes incommands/__init__.py - Added proper types to versioning middleware
- Full type coverage for CrewAI event handlers
- WebSocket disconnect handling - Proper logging and cleanup when client disconnects during agent processing (lines 241-242 in
agent.py) - Health endpoint edge cases - Added
# pragma: no coverfor unreachable 503 response path (checks dict is always empty) - Abstract method coverage - Added
# pragma: no coverfor abstractrun()method inBasePipeline
Frontend Fixes¶
- Timeline connector lines for grouped messages now display correctly
- Message grouping visual indicators properly connect related messages
Tests Added¶
- 100% code coverage achieved (720 statements, 0 missing)
- Tests for all 11 CrewAI event handlers:
test_crew_started_handler,test_crew_completed_handler,test_crew_failed_handlertest_agent_started_handler,test_agent_completed_handlertest_task_started_handler,test_task_completed_handlertest_tool_started_handler,test_tool_finished_handlertest_llm_started_handler,test_llm_completed_handler- Tests for CrewAI stream method edge cases:
test_stream_complete_flow- natural completion pathtest_stream_empty_queue_break- queue empty handlingtest_stream_with_error- error event handling- Tests for WebSocket disconnect during processing:
test_websocket_disconnect_during_streamtest_websocket_disconnect_during_processing- Tests for health endpoint edge cases:
test_readiness_probe_503_unit- 503 response logic
[0.1.11] - 2026-01-02¶
Added¶
LangGraph ReAct Agent Support¶
- LangGraph as third AI framework option alongside PydanticAI and LangChain
- New
--ai-framework langgraphCLI option for project creation - Interactive prompt includes "LangGraph (ReAct agent)" choice
- ReAct (Reasoning + Acting) agent pattern with graph-based architecture:
- Agent node for LLM reasoning and tool decision
- Tools node for executing tool calls
- Conditional edges for tool execution loop
- Memory-based checkpointing for conversation continuity
- Full WebSocket streaming support using
astream()with dual modes: messagesmode for token-level LLM streamingupdatesmode for node state changes (tool calls/results)- Tool result correlation - proper
tool_call_idmatching between calls and results - New template files:
app/agents/langgraph_assistant.py- LangGraphAssistant class with run() and stream()- WebSocket route implementation in
app/api/routes/v1/agent.py - New cookiecutter variable:
use_langgraph - Dependencies for LangGraph projects:
langchain-core>=0.3.0langchain-openai>=0.3.0orlangchain-anthropic>=0.3.0langgraph>=0.2.0langgraph-checkpoint>=2.0.0
Changed¶
AIFrameworkTypeenum extended withLANGGRAPHvalue- AI framework prompt now shows three options: PydanticAI, LangChain, LangGraph
- LLM provider validation - OpenRouter not supported with LangGraph (same as LangChain)
VARIABLES.mdupdated withuse_langgraphdocumentation- Template
CLAUDE.mdincludes LangGraph in stack section
[0.1.10] - 2025-12-27¶
Added¶
Nginx Reverse Proxy Support¶
- Nginx as alternative to Traefik with two configuration modes:
nginx_included: Full Nginx setup in docker-compose.prod.ymlnginx_external: Nginx config template only, for external Nginx- Nginx configuration template (
nginx/nginx.conf) with: - Reverse proxy for backend API (api.DOMAIN)
- Reverse proxy for frontend (DOMAIN) - conditional
- Reverse proxy for Flower dashboard (flower.DOMAIN) - conditional
- WebSocket support for
/wsendpoint - Security headers (X-Frame-Options, X-Content-Type-Options, HSTS, etc.)
- HTTP to HTTPS redirect
- SSL/TLS configuration with modern cipher suites
- Let's Encrypt ACME challenge support
- SSL certificate directory (
nginx/ssl/) with setup instructions - New cookiecutter variables:
include_nginx_service: Include Nginx container in docker-composeinclude_nginx_config: Generate nginx configuration filesuse_nginx: Using Nginx (included or external)use_traefik: Using Traefik (included or external)
Changed¶
- Reverse proxy prompt now offers 5 options:
- Traefik (included in docker-compose) - default
- Traefik (external, shared between projects)
- Nginx (included in docker-compose)
- Nginx (external, config template only)
- None (expose ports directly)
ReverseProxyTypeenum extended withNGINX_INCLUDEDandNGINX_EXTERNAL- docker-compose.prod.yml updated:
- Added nginx service definition
- Services use backend-internal network when nginx is selected
- No ports exposed on backend/frontend when nginx handles traffic
.env.prod.exampleincludes DOMAIN variable for nginx configurationpost_gen_project.pyremoves nginx/ folder when nginx is not selected
Tests Added¶
- Tests for
NGINX_INCLUDEDandNGINX_EXTERNALenum values - Tests for cookiecutter context generation with all reverse proxy options
- Tests for
prompt_reverse_proxy()with nginx choices
[0.1.9] - 2025-12-26¶
Added¶
SQLModel Support¶
- Optional SQLModel ORM as alternative to SQLAlchemy for PostgreSQL and SQLite
- New
--ormCLI option:--orm sqlalchemy(default) or--orm sqlmodel - Interactive prompt for ORM library selection when using
fastapi-fullstack new - SQLModel provides simplified syntax combining SQLAlchemy and Pydantic:
- Full Alembic compatibility maintained with SQLModel
- SQLAdmin works seamlessly with SQLModel models
- All database models updated with SQLModel variants:
User,Item,Conversation,Message,Session,Webhook,WebhookDeliveryVARIABLES.mdupdated with new ORM variables:orm_type,use_sqlalchemy,use_sqlmodel
Changed¶
- Database model templates now support conditional SQLModel/SQLAlchemy syntax
alembic/env.pyusesSQLModel.metadatawhen SQLModel is selected- Repositories remain unchanged (SQLModel uses same AsyncSession and methods)
Tests Added¶
- Tests for
OrmTypeenum values - Tests for
use_sqlalchemyanduse_sqlmodelcomputed fields - Tests for SQLModel validation (requires PostgreSQL or SQLite)
- Tests for
prompt_orm_type()function - Updated
run_interactive_prompts()tests withprompt_orm_typemocks
[0.1.7] - 2025-12-23¶
Added¶
Docker & Production¶
- Optional Traefik reverse proxy with three configuration modes:
traefik_included: Full Traefik setup in docker-compose.prod.yml (default)traefik_external: Traefik labels only, for shared Traefik instancesnone: No reverse proxy, ports exposed directly.env.prod.exampletemplate for production secrets management:- Conditional sections for PostgreSQL, Redis, JWT, Traefik, Flower
- Required variable validation using
${VAR:?error}syntax - Setup instructions in docker-compose.prod.yml header
- Unique Traefik router names using
project_slugprefix for multi-tenant support: {project_slug}-api,{project_slug}-frontend,{project_slug}-flower- Prevents conflicts when running multiple projects on same server
AI Agent Support¶
AGENTS.mdfile for non-Claude AI agents (Codex, Copilot, Cursor, Zed, OpenCode)- Progressive disclosure documentation in generated projects:
docs/architecture.md- layered architecture detailsdocs/adding_features.md- how to add endpoints, commands, toolsdocs/testing.md- testing guide and examplesdocs/patterns.md- DI, service, repository patterns- README.md updated with "AI-Agent Friendly" section
Changed¶
- Template
CLAUDE.mdrefactored from 384 to ~80 lines following progressive disclosure best practices - Main project
CLAUDE.mdupdated with "Where to Find More Info" section - docker-compose.prod.yml now uses
env_file: .env.prodinstead of inline defaults - Removed hardcoded credentials (
changeme) from docker-compose.prod.yml
Security¶
- Production credentials no longer have insecure defaults
.env.prodadded to.gitignoreto prevent committing secrets- Required environment variables fail fast with descriptive error messages
[0.1.6] - 2025-12-22¶
Added¶
Multi-LLM Provider Support¶
- Multiple LLM providers for AI agents: OpenAI, Anthropic, and OpenRouter
- PydanticAI supports all three providers (OpenAI, Anthropic, OpenRouter)
- LangChain supports OpenAI and Anthropic
- New
--llm-providerCLI option and interactive prompt - Provider-specific API key configuration in
.envandconfig.py
CLI Enhancements¶
make create-admincommand for quick admin user creation- Comprehensive CLI options for
fastapi-fullstack createcommand: --redis,--caching,--rate-limiting--admin-panel,--websockets--task-queue(none/celery/taskiq/arq)--oauth-google,--session-management--kubernetes,--ci(github/gitlab/none)--sentry,--prometheus--file-storage,--webhooks--python-version(3.11/3.12/3.13)--i18n- Configuration presets for common use cases:
--preset production: Full production setup with Redis, Sentry, K8s, Prometheus--preset ai-agent: AI agent with WebSocket streaming and conversation persistence- Interactive rate limit configuration when rate limiting is enabled:
- Requests per period (default: 100)
- Period in seconds (default: 60)
- Storage backend (memory or Redis)
Documentation¶
- Improved CLI documentation in README explaining project CLI naming convention (
uv run <project_slug>) - Makefile shortcuts documented with
make helpcommand
Template Improvements¶
- Generator version metadata in generated projects (
pyproject.toml): - Centralized agent prompts module (
app/agents/prompts.py) for easier maintenance - Template variables documentation (
template/VARIABLES.md) with 88+ variables documented
Validation¶
- Email validation for
author_emailfield using Pydantic'sEmailStr - Tests for OpenRouter + LangChain validation (combination is rejected)
- Tests for agents folder conditional creation
Changed¶
Configuration Validation¶
- Improved option combination validation in
ProjectConfig: - Admin panel requires PostgreSQL or SQLite (not MongoDB)
- Caching requires Redis to be enabled
- Session management requires a database
- Conversation persistence requires a database
- Rate limiting with Redis storage requires Redis enabled
- OpenRouter is only available with PydanticAI (not LangChain)
Database Support¶
- Admin panel prompt now appears for both PostgreSQL and SQLite (previously only PostgreSQL)
- Database-specific post-generation messages:
- PostgreSQL:
make docker-db+ migration commands - SQLite: Auto-creation note + migration commands (no Docker)
- MongoDB:
make docker-mongo(no migrations) - Added
close_db()function for SQLite database consistency
Project Name Handling¶
- Unified project name validation between
prompts.pyandconfig.py - Extracted validation into
_validate_project_name()function with clear error messages - Shows converted project name to user when it differs from input
Fixed¶
Backend Fixes¶
- Conversation list API response format: Changed
/conversationsand/conversations/{id}/messagesendpoints to return paginated response{ items: [...], total: N }instead of raw array, fixing frontend conversation list not loading after page refresh - Database session handling: Split
get_db_sessioninto async generator for FastAPIDepends()and@asynccontextmanagerfor manual use (WebSocket handlers) - WebSocket authentication:
- Update
deps.pyto useget_db_contextfor WebSocket auth - Add cookie-based authentication support for WebSocket (
access_tokencookie) - Now accepts token via query parameter OR cookie for flexibility
- WebSocket exception handling: Fix
AttributeErrorwhen exception occurs on WebSocket connection (request.methoddoesn't exist for WebSocket) - WebSocket conversation persistence:
- Fix
get_db_sessionvsget_db_contextusage (async generator vs async context manager) - Fix event name mismatch: backend now sends
conversation_createdto match frontend expectation - Docker Compose: Fix
env_filepath from.envto./backend/.env - ValidationInfo typing: Add proper type hints to all field validators in
config.py
Frontend Fixes¶
- ThemeToggle hydration mismatch: Add mounted state to prevent SSR/client mismatch
- Button component: Extract
asChildprop to prevent DOM warning - ConversationList: Add default value for conversations to prevent undefined error
- New Chat button:
- Create conversation in database immediately (eager creation)
- Clear messages properly when switching conversations
- Fix message appending issue when switching between conversations
- Conversation store: Add defensive checks for undefined state
CLI Fixes¶
- Consistent package name: Changed from
fastapi-gentofastapi-fullstackin version option - Makefile: Always generated now (removed from optional dev tools)
Template/Generator Fixes¶
- Ruff dependency in hooks: Graceful handling when ruff is not installed:
- Check PATH for ruff binary
- Fall back to
uvx ruffif uv is available - Fall back to
python -m ruffif available as module - Show friendly warning if ruff is not available
- Dynamic generator version: Replaced hardcoded version with
DYNAMICplaceholder - Unused files cleanup: Improved post-generation hook to remove:
- AI agent files based on framework selection
- Example CRUD files when disabled
- Conversation, webhook, session files when features disabled
- Worker directory when no background tasks selected
- Empty directories automatically
.envfile location: Move.env.examplefrom root tobackend/
Tests Added¶
- Tests for all configuration validation combinations
- Tests for project name validation edge cases
- Tests for
newcommand--outputoption - Tests for OpenRouter + LangChain validation
- Tests for admin panel prompt with SQLite
- Tests for agents folder conditional creation
- Tests for email validation (config and prompts)
- Tests for rate limit configuration prompts