staging#613
Conversation
…nly PyPI publish Versioning & packaging cleanup ahead of the first public PyPI release. - Single-source the version in queryweaver/__init__.py via hatch dynamic version (pyproject `dynamic = ["version"]`); bump to 0.3.0. Backend reads it at runtime via importlib.metadata. app/package.json bumped for tidiness. - Add a public, unauthenticated GET /version endpoint (api/routes/meta.py, registered in app_factory) and surface it in the Settings UI footer via a new MetaService. - Prune the published wheel/sdist to the SDK + the api/ code it actually imports; exclude the server layer (routes/auth/analyzers/entities/ app_factory/index/extensions). Drop the api.index:main console script. Move python-dotenv + pydantic into core deps (imported at SDK import time); add optional [memory] extra. - Add .github/workflows/publish-pypi.yml: build with uv and publish via PyPI Trusted Publishing (OIDC) on release, TestPyPI dry-run gate then PyPI. - Fix chat "Error: undefined": error events carry text in `message`, so the handler now falls back message -> content (matches other handlers). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sioning-pypi # Conflicts: # uv.lock
- Keep api/extensions.py in the wheel/sdist: api/core/db_resolver.py lazily imports it as the default FalkorDB handle when callers pass db=None, so excluding it would break SDK consumers using core APIs directly. - meta.py: add `-> dict[str, str]` return type on get_version; correct the module docstring (the route is tagged "Meta", excluded from MCP because that tag isn't mapped to an MCP type, not because it's untagged). - publish-pypi.yml: pin Python via actions/setup-python (>=3.12 build) and set enable-cache: false on setup-uv for deterministic release builds. - Add tests/test_meta_route.py covering /version (200, name+version, unauth). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aligns with the documented tests/ marker convention (CodeRabbit PR #584). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(packaging): version single-source, /version endpoint + UI, SDK-only PyPI publish
Python (uv): - falkordb ~=1.6.1 (#568) - pymysql ~=1.2.0 (#586) - graphiti-core >=0.29.1 (#589) - python-multipart ~=0.0.29 (#588) - pytest-playwright ~=0.8.0 (#585) - urllib3 2.7.0 transitive (#573) GitHub Actions (SHA pins): - docker/login-action v4 (#579) - docker/metadata-action v6 (#577) - docker/build-push-action v7 (#578) - astral-sh/setup-uv v8.1.0 (#565) - actions/dependency-review-action v4 (#564) npm (app): - @vitejs/plugin-react-swc ^4.3.1, postcss ^8.5.15 (#587) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
chore(deps): combine compatible Dependabot bumps
- react/react-dom ^18.3.1 → ^19.0.0 (#489) - @types/react ^18.3.23 → ^19.0.0 - @types/react-dom ^18.3.7 → ^19.0.0 - next-themes ^0.3.0 → ^0.4.0 (React 19 peer compat) - react-day-picker → ^8.10.2 (adds React 19 to peer range) - vaul ^0.9.9 → ^1.1.2 (React 19 peer compat) - vite ^7.3.2 → ^8.0.0 (#555) - tailwindcss ^3.4.17 → ^4.0.0 (#556) - add @tailwindcss/vite Vite plugin - replace tailwindcss-animate with tw-animate-css - replace @tailwind directives with @import "tailwindcss" - add @custom-variant dark for selector-based dark mode - add @config bridge to preserve tailwind.config.ts theme - remove tailwindcss from postcss (handled by Vite plugin)
The root package.json links the frontend via `queryweaver-app: file:app`, so its lock file must be regenerated when app deps change. The major bumps (React 19, Vite 8, Tailwind 4) left the root lock stale, breaking the Playwright `test` job's `npm ci` step. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaced by tw-animate-css in app/ during the Tailwind v4 migration; the root package only needs Playwright tooling. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
chore(deps): combine 3 remaining major Dependabot PRs (React 19, Vite 8, Tailwind 4)
Completed Working on "Code Review"✅ Review submitted successfully: COMMENT. Total comments: 2 across 2 files. ✅ Workflow completed successfully. |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add a dedicated, provider-agnostic usage-tracking layer that records every query onto the central Organizations graph, independent of the optional LLM conversational-memory feature. Background: the only pre-existing per-query record was a side effect of the opt-in `use_memory` feature, which is also gated to OpenAI/Azure providers and lazily created. As a result the vast majority of users had no recorded query activity, and every recorded query was against the demo DB — usage counts were unusable for measuring adoption. This change: - Adds api/core/usage_tracking.py with record_query_usage_background(), a fire-and-forget recorder mirroring save_memory_background (background task, task-sink support for the SDK, errors logged-not-raised). - Maintains denormalized counters on the User node (query_count/success_count/ error_count/last_active/first_query_at) plus a per-query (:UsageEvent) node linked (User)-[:PERFORMED]-> for time-series/per-DB/success-rate analytics. - Hooks the recorder into run_query and run_confirmed at the completion point, OUTSIDE the use_memory/provider gate, so it runs on every query. - Uses MATCH (not MERGE) on User so an unknown email is a silent no-op rather than creating a phantom user from the query path. Forward-only: historical usage cannot be backfilled. Tests: tests/test_usage_tracking.py (write content, demo flag, ungated design, invalid user_id no-op, swallowed write failure). Cypher validated against a live FalkorDB engine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dependency ReviewThe following issues were found:
|
There was a problem hiding this comment.
Review Summary
Found 2 MAJOR issues across 2 files (no BLOCKER/CRITICAL findings).
Counts by importance
- BLOCKER: 0
- CRITICAL: 0
- MAJOR: 2
- MINOR: 0
- SUGGESTION: 0
- PRAISE: 0
Key themes
- Release gating robustness: PyPI publish flow may allow bypassing intended TestPyPI promotion checks in certain rerun paths.
- Environment parity / integration reliability: Frontend dev proxy is missing the new
/versionbackend route, causing local behavior drift and hidden integration failures.
Actionable next steps
- Harden the publish workflow: enforce successful TestPyPI stage and artifact promotion guarantees before PyPI publish.
- Add
/versionto Vite dev proxy rules so local development mirrors production routing behavior. - Re-run CI/dev verification after these fixes to confirm release gating and frontend metadata display behavior.
|
|
||
| publish-pypi: | ||
| name: Publish to PyPI | ||
| needs: publish-testpypi |
There was a problem hiding this comment.
[major]: publish-pypi relies only on needs: publish-testpypi, but there is no explicit guard that the current run actually executed and succeeded in publishing to TestPyPI artifacts. In GitHub Actions, selective reruns can execute downstream jobs in ways that bypass intended release gates, weakening the two-stage promotion safety model.
Suggested fix: Build once in a dedicated build job, upload artifacts, and require both publish jobs to consume those exact artifacts; add an if: condition on publish-pypi that checks needs.publish-testpypi.result == 'success' and ensure environment protection rules require manual approval for pypi.
| }, | ||
| }, | ||
| plugins: [react()], | ||
| plugins: [react(), tailwindcss()], |
There was a problem hiding this comment.
[major]: The frontend now calls the unauthenticated /version endpoint, but Vite dev server proxy rules only forward /api, /login, and /logout. In local development this request will hit the Vite origin and return 404, so version display silently fails and masks integration issues.
Suggested fix: Add a proxy entry for /version (and any other non-/api backend routes) to http://127.0.0.1:5000, similar to /login and /logout.
There was a problem hiding this comment.
Pull request overview
This PR updates QueryWeaver’s release/packaging setup and frontend build pipeline while adding a new unauthenticated /version metadata endpoint that the UI can display (plus accompanying dependency bumps across Python and the frontend).
Changes:
- Added a public
/versionFastAPI route (and unit tests) and surfaced the backend version in the Settings UI. - Switched Python packaging to dynamic versioning from
queryweaver/__init__.pyand introduced a PyPI publishing workflow (Trusted Publishing via OIDC). - Upgraded and reshaped dependencies/build tooling (Python deps bumps; frontend upgrades incl. Tailwind v4 + Vite v8 + React v19).
Reviewed changes
Copilot reviewed 19 out of 22 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Updates locked Python dependencies and extras metadata to match new versions/extras. |
pyproject.toml |
Switches to dynamic versioning; adjusts core/optional deps; configures hatch version path; excludes server-only modules from wheel/sdist. |
queryweaver/__init__.py |
Bumps SDK __version__ to 0.3.0 (source of truth for hatch dynamic version). |
api/routes/meta.py |
Adds new unauthenticated metadata router with /version. |
api/app_factory.py |
Wires in the meta router and sets FastAPI app version from app_version(). |
tests/test_meta_route.py |
Adds unit tests validating /version behavior. |
app/src/config/api.ts |
Adds VERSION endpoint constant. |
app/src/services/meta.ts |
Adds a small client-side service to fetch /version. |
app/src/pages/Settings.tsx |
Fetches and displays backend version in the Settings footer. |
app/src/components/chat/ChatInterface.tsx |
Improves error message fallback handling for toast + chat output. |
app/vite.config.ts |
Adds Tailwind’s Vite plugin to the build pipeline. |
app/postcss.config.js |
Removes tailwindcss PostCSS plugin (Tailwind v4/Vite plugin flow). |
app/tailwind.config.ts |
Removes darkMode config and drops tailwindcss-animate plugin usage. |
app/src/index.css |
Migrates Tailwind directives to Tailwind v4-style imports/config and adds a custom dark variant. |
app/package.json |
Bumps app version to 0.3.0 and upgrades frontend deps (Tailwind v4, Vite v8, React v19, etc.). |
app/package-lock.json |
Locks updated frontend dependency graph after upgrades. |
package.json |
Removes unused tailwindcss-animate from root devDependencies. |
.github/workflows/tests.yml |
Updates the pinned setup-uv GitHub Action version. |
.github/workflows/publish-pypi.yml |
Adds a new workflow to publish to TestPyPI then PyPI via OIDC Trusted Publishing. |
.github/workflows/publish-docker.yml |
Updates pinned Docker GitHub Actions versions. |
.github/workflows/dependency-review.yml |
Updates dependency-review GitHub Action to v5.0.0. |
| @@ -0,0 +1,32 @@ | |||
| """Public metadata routes (version/health) for the QueryWeaver API. | |||
| server = [ | ||
| "fastapi~=0.136.1", | ||
| "uvicorn~=0.46.0", | ||
| "authlib~=1.7.0", | ||
| "itsdangerous~=2.2.0", | ||
| "python-multipart~=0.0.27", | ||
| "python-multipart~=0.0.29", | ||
| "jinja2~=3.1.4", | ||
| "fastmcp>=3.2.4", | ||
| "graphiti-core>=0.28.1", | ||
| "graphiti-core>=0.29.1", | ||
| "snowflake-connector-python~=4.4.0", | ||
| "python-dotenv~=1.2.2", | ||
| "aiohttp>=3.13.5", | ||
| ] |
Aligns QueryWeaver's release process with FalkorDB/GraphRAG-SDK while keeping QueryWeaver's single-sourced dynamic version and TestPyPI gate. - publish-pypi.yml: add a verify-version job that refuses to publish unless the GitHub Release tag (vX.Y.Z) matches __version__. - CHANGELOG.md: Keep a Changelog format, seeded with the 0.2.0 manual publish and an [Unreleased] section. - RELEASING.md: runbook covering the one-time OIDC/env setup and the per-release cut process (SemVer, vX.Y.Z tags, Release-triggered publish). - Makefile: `make release VERSION=X.Y.Z` bumps queryweaver/__init__.py and app/package.json together so the two version files never drift. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
🚅 Deployed to the QueryWeaver-pr-613 environment in queryweaver
|
Make queryweaver/__init__.py the one place the version is authored, and have everything else derive from or be stamped from it so PyPI, the UI, the Docker image, and the MCP manifest never disagree. - scripts/version.py: current / check / set commands over the single source plus the static manifests that must embed a literal copy (app/package.json, server.json). - make release VERSION=X.Y.Z now stamps all manifests via the script; make check-version verifies they agree. - tests.yml: version-consistency job fails any PR where a manifest drifts. - publish-pypi.yml verify-version: check all manifests + tag match before publishing. - server.json: realign 0.0.11 -> 0.3.0 so the MCP/Docker lineage matches the SDK version. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rsion checks) Remove scripts/version.py, CHANGELOG.md, RELEASING.md, the make release/ check-version targets, and the verify-version / version-consistency CI jobs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a dedicated build job that produces the wheel/sdist once and uploads it as an artifact; the TestPyPI gate and PyPI publish now download and ship that exact build instead of each rebuilding from scratch. Drop the redundant setup-python and checkout steps from the publish jobs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
server.json's packages[].version must reference a real published Docker image; 0.3.0 does not exist on Docker Hub (tags stop at 0.0.14). Leave it at 0.0.11 until a matching image is released. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Copilot review: the build-once job ran uv build without an explicit interpreter, depending on whatever ubuntu-latest ships. Pin 3.12 to match the rest of CI and the package's requires-python. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- text2sql: record usage on every terminal path of run_query/run_confirmed (off-topic, not-translatable, demo-blocked, cancelled, no-loader), via a local _track_usage helper. The destructive-confirmation prompt is the deliberate exception — run_confirmed records that query's outcome, so tracking it twice would double-count. - usage_tracking: omit email (PII) from the per-query log line and strip CR/LF from the user-influenced graph_id (CodeQL log-injection). - usage_tracking: base64 decode with validate=True + email-shape check so a malformed user_id is skipped instead of triggering a phantom write. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ci(pypi): build-once publish workflow + PyPI README badge
Two design fixes raised in review: 1. Single source of truth for the central graph name. Add config.ORGANIZATIONS_GRAPH (env var ORGANIZATIONS_GRAPH, default "Organizations") and use it everywhere the graph was hardcoded — auth/user_management, routes/auth, routes/tokens, and usage tracking. 2. Don't ship hosted-app telemetry in the PyPI SDK. Move usage_tracking from api/core (shipped) to api/routes (excluded from the wheel) and invoke it from the route layer (_serialize_pipeline) instead of inside run_query/run_confirmed in api/core/text2sql.py. The route records exactly once from the final QueryResult and skips the destructive- confirmation prompt (the /confirm call records that query). text2sql.py is back to its pristine, tracking-free state. Verified: SDK wheel no longer contains usage_tracking and text2sql has no tracking refs; unit suite 138 passed, pylint 10/10. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ack crashes
- usage_tracking: the per-query log line logged the namespaced graph_id
({base64(email)}_{db}); base64 email is reversible, so log a short SHA-256
hash instead — keeps identity out of logs and neutralizes log-injection.
- config: ORGANIZATIONS_GRAPH falls back to "Organizations" when the env var
is empty (not just unset), so a blank value can't target an empty graph.
- routes/graphs: record success=False when run_query/run_confirmed raise
before the _Final sentinel (e.g. get_db_description), so pipeline crashes
are still counted instead of silently bypassing tracking.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address the latest review pass: - routes/graphs: success = is_valid AND no error. error_message-None alone counted off-topic / not-SQL-translatable results (is_valid=False, no error) as successes, inflating success_count. - tests: assert against usage_tracking.ORGANIZATIONS_GRAPH instead of the hardcoded "Organizations" so the suite passes when the env var is set. - usage_tracking: reword the task_sink docstring — it no longer ships in the SDK, so drop the QueryWeaver.close() reference for a generic description. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(usage): always-on per-query usage tracking
| EMAIL = "gal.shubeli@falkordb.com" | ||
| USER_ID = base64.b64encode(EMAIL.encode()).decode() |
| """Public metadata routes (version/health) for the QueryWeaver API. | ||
|
|
||
| These endpoints are intentionally unauthenticated so the frontend can read | ||
| them before login. Their tag is not mapped to any MCP type, so FastMCP's | ||
| default EXCLUDE route map keeps them out of the MCP tool surface. | ||
| """ |
No description provided.