Skip to content

Releases: vstorm-co/full-stack-ai-agent-template

0.2.12

17 Jun 17:00
d97d291

Choose a tag to compare

[0.2.12] - 2026-06-17

Added

  • Deep Research mode (enable_deep_research, --deep-research, PydanticAI only) — turns the assistant into a deep-research agent: a TODO planner (pydantic-ai-todo), parallel researcher/analyst/writer subagents (subagents-pydantic-ai), and an automatic context manager (summarization-pydantic-ai). The planner clarifies scope, plans the work, delegates web research to subagents, and composes a cited report; progress streams to a dedicated live research panel (plan checklist, subagent status cards, context-usage meter) while the final report streams back as a normal message. TODO state persists in PostgreSQL when available, else in memory. Activated at runtime with ENABLE_DEEP_RESEARCH=true; a client can opt a single turn out with deep_research=false. Gated behind the new flag and PydanticAI-only by a config validator — when off, the template generates exactly as before. Ships with a stop control and a per-turn research store in the web chat (#90)

Fixed

  • make install failed with Failed to spawn: pre-commit — dev tools (pytest, ruff, ty, pre-commit, …) lived under [project.optional-dependencies].dev, which uv only installs via its deprecated dev-extra special-casing; on uv versions where uv sync --dev targets the PEP 735 group instead, they were skipped entirely. Moved them to [dependency-groups] so uv sync / uv sync --dev install them deterministically and --no-dev (prod Dockerfile) still excludes them (#95, #101)
  • make docker-db (and the other docker-* / docker-prod-* / docker-redis targets) errored docker-compose: No such file or directory — those recipes shelled out to the legacy Compose v1 binary while the dev/quickstart targets already used Compose v2. Every recipe now invokes docker compose; the docker-compose.*.yml filenames are unchanged (#96, #100)
  • Frontend Docker build (make dev-frontend) failed to build the image — the Dockerfile copied a bun.lockb* glob that never matched the current text bun.lock (so bun install --frozen-lockfile had no lockfile and errored), the healthcheck shelled out to a curl the oven/bun image doesn't ship, and the NEXT_PUBLIC_* client vars were never passed as build args. Copies bun.lock*, passes the public env vars as build args (Dockerfile + compose), probes the healthcheck with bun's fetch, chowns the copied public/, and guards parseLoadSkillResult so bun run build type-checks (#97, #99)
  • PydanticDeep OpenAI models are now routed to the OpenAI Responses API (#93)
  • Taskiq worker and scheduler containers stay healthy; the taskiq-only worker regression test is removed from celery/arq/none projects so it doesn't linger as an empty file (#94)
  • ty check on generated projects — the admin/user routes for SQLite were sync defs that never awaited the always-async UserService, so they returned un-awaited coroutines (real bug); they are now async. The service's id parameters are typed per database (UUID for Postgres, str for SQLite/MongoDB) via a UserId alias, the agent's capability list is typed list[Any], the admin-stats best-effort model imports are feature-gated instead of importing absent modules, and the AdminService session is typed Any so one implementation serves async/sync. A minimal SQLite project now type-checks clean (0 diagnostics)

Dependencies

  • Pinned fastapi>=0.135.3,<0.137 in generated backends — FastAPI 0.137 made prefix-less include_router reject the documented @router.get("") empty-path idiom, breaking every generated project at import (#90)
  • Added pydantic-ai-todo, subagents-pydantic-ai, and summarization-pydantic-ai to generated backends when enable_deep_research is on (#90)
  • Bumped codecov/codecov-action 6 → 7 in the CI actions group (#89)

0.2.11

12 Jun 17:56

Choose a tag to compare

[0.2.11] - 2026-06-12

Added

  • AntV advanced-diagram tools + interactive maps (enable_antv_charts, --antv-charts) — adds an mcp-server-chart Docker sidecar exposing AntV diagram tools (flowchart, mind-map, org-chart, sankey, waterfall, funnel, treemap, radar, histogram, boxplot, dual-axes) and a native create_map tool (Leaflet/OpenStreetMap) with a typed MapMarker schema that prevents empty-marker validation errors from weaker models. create_map is wired into all 6 agent frameworks; the AntV diagrams render server-side via the sidecar. Web chat renders maps with react-leaflet (MapMessage/MapLeaflet) and AntV diagrams as images in the tool-call card. Opt-in and profile-gated — ENABLE_ANTV_CHARTS=false by default, sidecar started with docker compose --profile antv up -d; for prod self-host GPT-Vis-SSR via ANTV_VIS_REQUEST_SERVER instead of AntV's public render backend (#83)
  • ask_user tool (PydanticAI) — the agent can pause a run to put one or more questions to the user and resume with their answers, for intake/setup flows and mid-run clarifications. Backed by a WebSocket pause/resume in AgentSession and an interactive multi-step QuestionPrompt card in the frontend (numbered options, free-form answers, skip). System-prompt guidance steers the model to use it only when a missing detail would genuinely change what it does next (#88)
  • run_python code execution (enable_code_execution, --code-execution, PydanticAI only) — a run_python tool backed by the pydantic-monty sandboxed interpreter. In one tool turn the model can compute projections/aggregations and call create_chart/create_map/current_datetime directly from inside the sandbox; visualizations created in-code stream to the session as live, persisted interactive cards (the same tool_call/tool_result pair as a direct call). Restricted stdlib (math, asyncio, json, datetime, re); activated at runtime with ENABLE_CODE_EXECUTION=true. Temporary shim until PydanticAI's official CodeExecutionToolset ships (#88)
  • Skills system (enable_skills, --skills, PydanticAI only) — a pydantic-ai-skills SkillsToolset that loads SKILL.md files from backend/skills/ as agent tools (the model picks a skill, then follows its instructions). Ships the loader only — drop your own skills in; the toolset no-ops when the directory is empty. Frontend renders load_skill/list_skills tool calls as clean skill cards. Pairs with code execution for skills that compute (#88)

Fixed

  • MCP connection leak in CrewAIget_antv_crewai_tools now memoizes the started MCP adapter so it's started once per process, not once per request (#83)
  • Per-request event-loop blocking in LangChain/LangGraph/DeepAgents — AntV tool discovery is memoized so _run_sync only blocks on the first request (#83)
  • antvis-chart Docker healthcheck — plain wget was rejected by the streamable-HTTP endpoint; replaced with a node one-liner. Added coordinate-bounds validation to MapSpec._validate_center (matching per-marker validation) and removed the dead parse_map_spec export (#83)
  • Streamed tool-call args could be a raw stringagent_session now uses args_as_dict(raise_if_invalid=False) so tool-call cards always receive a dict; a stray/duplicate ask_user_response frame (e.g. after a reconnect) is dropped instead of surfacing a spurious "Empty message" error (#88)

Changed

  • Generated-project ruff tests run via uvxtest_template_integration.py / test_message_ratings.py invoke uvx ruff from the project's backend/ dir (matching the post-gen hook) instead of uv run ruff, avoiding a stray VIRTUAL_ENV breaking local runs. New matrix configs pydantic_ai_code_execution and pydantic_ai_skills so both new paths are linted + type-checked in CI (#88)

Removed

  • ai_agent_test/ generated snapshot — removed the 710-file generated project that was committed to the repo root; it only served to confuse Renovate and tooling (the template/ source is the durable artifact). Added to .gitignore

Dependencies

  • pydantic-monty>=0.0.18 and pydantic-ai-skills>=0.11.0 added to generated backends when enable_code_execution / enable_skills are on; react-leaflet added to the template frontend and an mcp-server-chart sidecar to the compose files when enable_antv_charts is on

0.2.10

27 May 12:40

Choose a tag to compare

[0.2.10] - 2026-05-27

Added

  • Frontend PageHero component — shared components/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 split chat-settings.tsx (deleted) and kb-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.tsx updated 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 redesignedkb/kb-list.tsx rewritten (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_command models + repos + services, the agent, admin_conversations, admin_ratings, and me_slash_commands routes, 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) so next build no longer fails on orphaned imports
  • Backend modules unconditionally pulled in chat codeapi/deps.py, api/routes/v1/__init__.py, db/models/__init__.py, repositories/__init__.py, schemas/__init__.py, services/admin.py, repositories/user.py, and admin.py (SQLAdmin) had use_database-gated imports of Conversation/Message/MessageRating/etc. that crashed in no-AI projects. Re-gated to use_ai and added literal-zero fallbacks for conversation counts in admin stats / user listings (PG, SQLite, MongoDB)
  • CLI: Slack/Telegram channels silently accepted without an AI frameworkProjectConfig validation now rejects --slack/--telegram when use_ai is off (the channel adapters only exist to relay messages to AgentInvocationService), with a quick-fix message
  • temperature forwarded to reasoning models (gpt-5.5, o1) — those models reject the parameter entirely, so AssistantAgent no longer falls back to settings.AI_TEMPERATURE; it stays None and is only forwarded to ModelSettings when the caller explicitly sets it
  • reranker.py Cohere init imported the SDK only to discard it — replaced the from cohere import AsyncClient probe with importlib.util.find_spec("cohere") so we check availability without polluting imports
  • Auth components barrel exported password forms in OAuth-only buildscomponents/auth/index.ts now gates the local-auth form exports behind use_local_auth, so OAuth-only projects don't ship dead code that references missing endpoints
  • README demo videos invisible on GitHub<video> tags from raw.githubusercontent.com don'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 .mp4 sources
  • Renovate scanned the generated ai_agent_test/ snapshot — opened useless PRs against the snapshot's package.json / docker-compose.yml instead of the actual template/ source, so every accepted bump would silently revert on the next regeneration. Added ignorePaths: ["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-actionv0.36.0 in generated projects' CI (#74)
  • milvusdb/milvus Docker tag → v2.6.17 in generated docker-compose.{dev,prod,}.yml (#77)
  • qdrant/qdrant Docker tag → v1.18.1 in generated docker-compose.{dev,prod,}.yml (#78)
  • quay.io/coreos/etcd Docker tag → v3.6.11 (Milvus dependency) in generated docker-compose.{dev,prod,}.yml (#80)
  • prettier-plugin-tailwindcss^0.8.0 in template frontend package.json (#81 bumped only the snapshot; the template source is the durable fix)

0.2.9

16 May 23:36
7354cbe

Choose a tag to compare

[0.2.9] - 2026-05-17

Added

  • Chart generation tool (enable_charts) — optional create_chart tool letting the agent produce line/bar/pie/area/scatter charts. Returns a validated ChartSpec (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 + --charts CLI flag + enable_charts cookiecutter var
  • Portable fetch_url tool (web_fetch_tool) — SSRF-safe "read this web page" tool for LangChain/LangGraph/CrewAI/DeepAgents (which had no model-native web-fetch). Reuses app.core.sanitize.validate_webhook_url, re-validates every redirect hop, caps size/timeout, extracts readable text (BeautifulSoup). PydanticAI/PydanticDeep keep their native WebFetch. Closes the gap where enable_web_fetch was 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_url to 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 stays gemini-2.5-flash). Updated AI_AVAILABLE_MODELS (GPT-5.x frontier line; full Claude Opus/Sonnet/Haiku line) and Claude pricing in billing MODEL_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_documents as a tool to use when relevant with a retrieval budget and citations
  • web_search tool returns structured JSON (WebSearchResults) instead of ad-hoc text, so the chat UI renders clickable titles, domains and snippets (added parse_web_search). Fixed stale frontend detection that meant the rich card never showed for LangChain/LangGraph/DeepAgents
  • Removed the .env.prod / .env.prod.example abstraction — production now uses the same backend/.env as dev (it already contained every variable .env.prod.example defined). docker-compose.prod.yml reads env_file: ./backend/.env; make prod checks for backend/.env and passes --env-file backend/.env to Compose. .env.prod removed from .gitignore. Migration: move any values from your old .env.prod into backend/.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_call with args: {} and poisoned the shared dedup set, suppressing the complete event. The updates stream 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
  • AIMessageChunk merge crashAdditional kwargs key created_at … unsupported type <class 'float'> on the OpenAI Responses API. Usage is now summed via add_usage instead of merging whole chunks
  • DeepAgents tool calls never fired_stream_update_event checked the graph node "agent", but create_deep_agent (deepagents 0.6.1 → LangChain create_agent) names it "model". Tool calls, args and reasoning are now emitted for DeepAgents
  • KBSelector infinite GET /api/kb request loop when a workspace has no knowledge bases — a length-based effect re-fired after every empty fetch; replaced with a one-shot ref guard
  • test_agents.py was 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_model seam with a real TestModel; LangChain patches the provider-correct chat class

0.2.8

14 May 01:18
26f7d70

Choose a tag to compare

[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 in emails/compiled/ using [[variable]] substitution. EmailService facade 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 wiredUserService.register() fires send_welcome; InvitationService.invite() fires send_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. RateLimitRule frozen dataclass (per_user, per_org, per_ip, configurable periods); RateLimitCategory constants; data-driven plan features override DEFAULT_RATE_LIMITS; make_rate_limit_dep(category) factory for FastAPI Depends(); admin bypass; fail-open on Redis error; HTTP 429 with Retry-After header
  • Extended frontend billing dashboardSubscriptionPanel with 4 states (free/trial/active/canceled), cancel/reactivate dialogs, plan details; CreditsPanel with balance display, low-credit alert, top-up button, transaction history with type badges; /billing/subscription page with live plan cards; /billing/credits page. useSubscription, useCredits, usePlans hooks added to use-billing.ts
  • Admin user managementGET/PATCH/DELETE /admin/users/{id} endpoints (requires is_app_admin flag). POST /admin/users/{id}/impersonate issues a short-lived (1h) JWT token to act as any user — token is returned in the API response. Frontend: /admin/users page with search, role toggle, delete, and impersonation-token-to-clipboard button; /admin/page.tsx overview with navigation cards; useAdminUsers hook
  • UsageServiceapp/services/usage.py — records UsageEvent in DB, computes credits via usage_to_credits(), debits org credits via CreditService.debit(). All 3 DB variants (PG/SQLite/MongoDB). Wiring point for agent invocations
  • Usage dashboard/billing/usage frontend 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_URL setting)
  • Newsletter signup (enable_newsletter_signup) — POST /newsletter/signup endpoint; NewsletterSignup React component; sends welcome email via email service
  • Changelog page (enable_changelog) — /changelog route with release history, change type badges (feat/fix/improvement/chore)
  • Pricing comparison page (enable_comparison_pages) — /pricing route fetches live plans from API; monthly/annual toggle; plan feature list; trial days display; "Get Started" CTA

Fixed

  • Email templates excluded by .gitignore — Renamed emails/dist/emails/compiled/ to avoid the generic dist/ gitignore rule silently stripping all compiled templates from generated projects
  • billing/facade.py imports usage_event_repo unconditionallyapp.repositories.usage_event was imported in both PostgreSQL and SQLite branches regardless of enable_credits_system; projects generated with enable_billing=True + enable_credits_system=False crashed on startup with ImportError
  • func.case() SQLAlchemy 2.x crash in message_rating_repofunc.case((condition, value), else_=0) raised TypeError: Function.__init__() got an unexpected keyword argument 'else_'; replaced with case(...) imported directly from sqlalchemy
  • Credits/usage dashboard widgets shown when enable_credits_system=FalseUsageTimeline and TopModels components were gated on enable_billing instead of enable_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.py used SQLAlchemy func.countAdminService now has separate {%- if use_postgresql or use_sqlite %} / {%- elif use_mongodb %} branches; the MongoDB branch uses Beanie Document.find().count() and returns [], 0 for Stripe events (not applicable to MongoDB projects)
  • Admin GET /conversations/{id} returned 404 for other users' conversationsget_conversation and list_messages route handlers now resolve uid = None if current_user.role == "admin" else current_user.id; user_id=None in the service layer bypasses the ownership check, allowing admins to read any conversation
  • Frontend ?id= URL param blocked by ownership guardfetchConversations removed the response.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 Link to /chat?id=<conversation_id>; admins now land on the full chat UI with the real message history
  • Admin ratings page "Export" returned 404window.open was 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 failuresgenerated_project_full fixture now sets frontend=FrontendType.NEXTJS (required when oauth_provider=GOOGLE); MongoDB repository __init__.py import guard split so only SQL-only repos (chat_file_repo) are excluded from MongoDB projects; SQLite auth test fixed a mock type mismatch (MagicMockAsyncMock)

0.2.7

26 Apr 10:25
488f6d8

Choose a tag to compare

[0.2.7] - 2026-04-26

Fixed

  • Disabled features no longer leak generated filespost_gen_project.py now removes channel adapters/routes/services/repos/schemas/models/commands/migrations when use_telegram and use_slack are both off, RAG sync infrastructure (sync_log, sync_source, rag_document files) when RAG is off, DeepAgents project scaffolding when not selected, leftover test stubs for disabled modules, and empty docker-compose placeholders when Docker is disabled
  • agent.py (DeepAgents): undefined file_ids — WebSocket payload parsing now extracts file_ids = raw_data.get("file_ids", []) before use (previously raised NameError at runtime)
  • agent.py (CrewAI): missing ConversationUpdate import — Added to imports so title-update path no longer crashes
  • rag.py: complete_sync called on wrong service — Was invoked on SyncSourceService; now correctly routed to RAGSyncService
  • IngestionService() instantiated without required args — Added IngestionService.from_settings() classmethod factory; routes/commands/workers now use it
  • message_rating_repo not exported — Added to app/repositories/__init__.py; admin ratings flow no longer fails on import
  • ConversationService.get_conversation_with_messages missing on SQL backends — Previously only existed on MongoDB; added to PostgreSQL + SQLite variants
  • ProjectService.list / ChannelBotService.list shadowed builtin list — Renamed to list_for_user() / list_all() (with find_active() and list_by_platform() helpers added)
  • ModuleNotFoundError: No module named 'app.rag.connectors'post_gen_project.py was deleting the entire rag/connectors/ directory when neither Google Drive nor S3 ingestion was enabled, but sync_source.py always imports CONNECTOR_REGISTRY from that package. Directory is now preserved; only the individual connector files are removed
  • Empty tasks/channel.py generated for projects without Telegram or Slack — Added removal to the not use_telegram and not use_slack post-gen hook block
  • Frontend TypeScript strict mode errors — Fixed 26 noUncheckedIndexedAccess and undefined-assignability violations across 7 files: rag/page.tsx (array index + file loop guard), chat-container.tsx (model selector useState type + fallback), chat-input.tsx (speech recognition result guard), tool-approval-dialog.tsx (editedArgs index 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.py rewritten to use ConversationSvc.admin_list_with_users() and UserSvc.admin_list_with_counts()
    • telegram_webhook.py / slack_webhook.py use ChannelBotSvc via Depends instead of opening their own DB sessions (bot_service.find_active(bot_id))
    • agent.py uses conv_service.list_attached_files(file_ids) instead of raw select(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/add removed from services; sessions auto-commit via get_db_session/get_db_context/get_worker_db_context
  • Repositories expanded with the queries services now needconversation.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) and export_ratings() moved to MessageRatingService. Route reduced to a single return await rating_service.export_ratings(...) call
    • sessions.py: SessionRead construction in list_sessions moved to SessionService.list_sessions() which now returns SessionListResponse directly
    • rag.py: SyncSourceRead(...) construction moved to SyncSourceService._to_read() (used by list_sources, create_source, update_source); RAGSyncLogItem(...) moved to RAGSyncService.list_sync_logs() → returns RAGSyncLogList; RAGTrackedDocumentItem(...) moved to RAGDocumentService.list_documents() → returns RAGTrackedDocumentList; RAGDocumentItem(...) moved to BaseVectorStore.get_document_list(); ConnectorInfo/ConnectorList construction moved to SyncSourceService.list_connectors()
    • oauth.py: Three-step find/link/create OAuth flow extracted to UserService.get_or_create_oauth_user() (all 3 DB variants); google_callback reduced to a single service call
    • users.py: Raw Annotated[User, Depends(RoleChecker(UserRole.ADMIN))] replaced with CurrentAdmin alias throughout; Depends(get_current_user) replaced with CurrentUser
    • Unused current_user/admin_user route parameters that only provided auth enforcement renamed to _: CurrentAdmin / _: CurrentUser across all affected routers
  • agent.py: inline imports moved to module levelfrom 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 blocks
  • conversations.py: Direct field mutation data.user_id = current_user.id replaced with data = data.model_copy(update={"user_id": current_user.id}) (Pydantic v2 safe update); inline ConversationShareSvc import moved to module level; section-divider comments (# Message Rating Endpoints, # Sharing endpoints) removed

Security

  • Generator dependency floors raisedpyproject.toml runtime/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-audit CI: CVE-2026-3219 (pip 26.0.1) added to ignore list — Vulnerability in pip itself with no fix version published yet; documented in the workflow alongside the other ignored CVEs

Added

  • Config validator: CrewAI + Logfire combination rejected — Raises ValueError at config time; documents an upstream OpenTelemetry/logfire ≥ 4.30 conflict with CrewAI
  • Conditional pydantic pin for CrewAI — Generated pyproject.toml pins pydantic[email]>=2.11.0,<2.12 when CrewAI is selected (CrewAI is incompatible with pydantic 2.12)
  • Stricter ty rules in generated pyproject.tomlunknown-argument, invalid-await, invalid-context-manager, missing-argument, not-iterable, invalid-return-type, invalid-type-form promoted to warn
  • Integration test matrixTestGeneratedTemplateMatrix now exercises 14 framework/database/RAG/channel combinations (project names prefixed with matrix_ to avoid package-name collisions). Suite: 405 passed, 3 skipped
  • services/health.py — New build_health_response(status, checks, details) helper extracted from health.py route; health.py now imports and calls it instead of defining it inline
  • services/agent.py — New AgentConnectionManager class extracted from all 5 AI framework blocks in agent.py. Single canonical implementation shared via from app.services.agent import AgentConnectionManager
  • UserService.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 three google_callback route handlers
  • SyncSourceService._to_read(source) / list_connectors()_to_read converts a SyncSource ORM model to SyncSourceRead (including json.loads for SQLite config); list_connectors() is a @staticmethod that iterates CONNECTOR_REGISTRY and returns ConnectorList without requiring a DB session
  • BaseVectorStore.get_document_list(collection_name) — Concrete (non-abstract) method on the base class; calls get_documents() and maps to RAGDocumentList. All vector store implementations (Milvus, Qdrant, ChromaDB, pgvector) inherit it automatically

0.2.6

18 Apr 11:48

Choose a tag to compare

[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: MessageRating model (PostgreSQL/SQLite/MongoDB, SQLAlchemy/SQLModel), repository + service + schema layers, POST /conversations/{id}/messages/{messageId}/rate endpoint. Ratings persisted to message_ratings table with unique constraint per user/message and CHECK constraint 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: RatingButtons component with like/dislike icons, comment dialog on dislike, optimistic count updates. Integrated into message-item.tsx for assistant messages. Admin pages for ratings management and conversations listing
    • Frontend proxy routes: POST/DELETE /api/conversations/{id}/messages/{messageId}/rate proxies, GET /api/v1/admin/ratings, /summary, /export routes, lib/admin-auth.ts utility for admin API calls
    • Documentation: docs/howto/use-ratings.md user guide, updated docs/architecture.md and docs/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 or Referer headers. Backend echoes the chosen application subprotocol back on accept()
  • Removed /api/auth/token httpOnly downgrade endpointaccess_token is now returned in the body of /auth/login, /auth/me, and /auth/refresh proxy 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.escape from 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=csv now streams row-by-row via an async/sync generator instead of buffering the whole dataset in memory

0.2.5

18 Apr 09:26
3ea3517

Choose a tag to compare

[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) and edit (can add messages). Owner can share, list shares, and revoke access. Recipients can also leave shared conversations
  • ConversationShare model — 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 endpointsPOST /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/conversations page 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 hooksuseConversationShares (share, fetch, revoke, shared-with-me) and useAdminConversations (admin list, users, detail preview)

Slack Multi-Bot Channel Integration

  • Slack adapterSlackAdapter(ChannelAdapter) supporting both Events API (production webhook) and Socket Mode (development polling). Thread-aware: Slack thread replies fold thread_ts into platform_chat_id ({channel}:{thread_ts}) so each thread gets its own ChannelSession and Conversation
  • Events API webhookPOST /slack/{bot_id}/events endpoint 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's SocketModeClient. Bot-scoped tasks with 5s back-off restart on crash. Lifecycle managed in app lifespan alongside Telegram polling
  • use_slack cookiecutter 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}/events route
  • Shared channel infrastructure expanded — All 14 shared files (ChannelAdapter base, models, repos, services, router, commands) gated from use_telegramuse_telegram or use_slack so 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}) in ChannelMessageRouter.route(). Serializes concurrent messages from the same group/channel to prevent: duplicate ChannelSession creation (DB constraint violation), interleaved agent invocations on the same Conversation, 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 ChannelAdapter base class with concrete TelegramAdapter (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 modelsChannelBot (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 proper ChannelBotCreate/ChannelBotUpdate/ChannelBotRead schemas
  • Webhook endpointPOST /telegram/{bot_id}/webhook with 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 commandschannel-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 router
  • use_telegram cookiecutter 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_backend cookiecutter variable — Configures PYDANTIC_DEEP_BACKEND_TYPE / DEEPAGENTS_BACKEND_TYPE in 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 with read_file. File paths are automatically included in the user message. Falls back to inline content for StateBackend
  • Project-scoped WebSocket endpointws/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() and WebFetch() 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 duckduckgo and web-fetch extras 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_DIR setting — No longer needed without LocalBackend

Fixed

Telegram Channel Code Review Fixes

  • channels/router.py — Made route() always async def (was sync for SQLite, causing asyncio.get_event_loop().run_until_complete() crash). Removed broken _handle_command_sync, _resolve_identity_sync, _resolve_session_sync methods. Added SQLite branches to all async methods
  • channels/router.py — Fixed /link command: replaced non-existent channel_link_repo.redeem_code() with channel_identity_repo.get_by_link_code(). Code is invalidated after use
  • channels/router.py — Fixed bot.encrypted_tokenbot.token_encrypted in _send_reply(). Fixed bot.system_promptbot.system_prompt_override and bot.model_overridebot.ai_model_override
  • channels/router.py — Fixed MongoDB import paths: from app.db.models.channel importfrom app.db.models.channel_identity import / from app.db.models.channel_session import
  • channels/router.py — Added _parse_policy() helper to normalize access_policy from JSON string (SQLite) or dict (PostgreSQL/MongoDB)
  • channels/telegram.py — Removed module-level singleton that conflicted with lifespan-managed adapter in main.py. Fixed SQLite _handle_update to await router.route()
  • api/routes/v1/channels.py — Fixed all service method names (service.list_bots()service.list(), etc.). Replaced data: Any with proper ChannelBotCreate/ChannelBotUpdate schemas. Added response_model to all endpoints. Made SQLite webhook routes async (was using asyncio.run() inside running loop)
  • api/routes/v1/telegram_webhook.py — Fixed SQLite branch to await router.route() (route is now always async)
  • services/channel_bot.py — Generate webhook_secret via secrets.token_urlsafe(32) when webhook_mode=True (was always None). Added list_sessions() method to all 3 backends
  • repositories/channel_session.py — Added list_by_bot() and count_by_bot() functions to all 3 backends
  • commands/channel.py — Fixed bot.encrypted_tokenbot.token_encrypted. Fixed channel_bot_repo.list_all(platform=...) (no such parameter) → conditional get_by_platform(). Fixed encrypted_token=token_encrypted= in create

Tooling

  • CI: MongoDB job — Added missing ty check step (was present in minimal and PostgreSQL jobs but absent from MongoDB)
  • Template pre-commit — Bumped ruff-pre-c...
Read more

0.2.4

09 Apr 11:21

Choose a tag to compare

[0.2.4] - 2026-04-09

Security

  • SSRF protection for webhook URLs (CWE-918) — Added validate_webhook_url() in app/core/sanitize.py that 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). Includes SSRFBlockedError exception with proper 422 responses and 39 unit tests. (PR #62)

0.2.3

05 Apr 22:12
58a1871

Choose a tag to compare

[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 box
    • settings.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 with Annotated aliases, db.flush() convention, domain exceptions
    • rules/code-style.md — Type hints (str | None), naming conventions table, import ordering (stdlib → third-party → local), ruff config
    • rules/schemas-models.md — Pydantic v2 *Create/*Update/*Read/*List pattern, BaseSchema with ConfigDict, SQLAlchemy Mapped[] columns, TimestampMixin
    • rules/exceptions-security.md — Domain exception hierarchy (AppExceptionNotFoundError, etc.), JWT/bcrypt patterns, RoleChecker, API key verification
    • rules/api-conventions.md — REST design, pagination (Query(ge=0, le=100)), auth deps (CurrentUser/CurrentAdmin/ValidAPIKey), response format, file upload
    • rules/testing.md — Async test patterns, httpx.AsyncClient, fixtures, exception testing with pytest.raises
    • rules/frontend.md — Next.js 15 App Router, Server Components, Tailwind conventions (auto-removed when frontend disabled)
    • commands/review.md/project:review slash command: checks changes against architecture, types, security, and runs linting
    • commands/add-endpoint.md/project:add-endpoint slash command: scaffolds full CRUD (schema → model → repo → service → deps → route → migration → test)
    • commands/fix-issue.md/project:fix-issue slash 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