-
Notifications
You must be signed in to change notification settings - Fork 56
Add workspaces #272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add workspaces #272
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
9de614d
feat: Make disk file saving more robust
paultranvan 9c93fe3
tests: Add unit test for disk file saving
paultranvan bb966fc
refactor: Move file serialization in common module
paultranvan 7adf225
feat: Add tools endpoint
paultranvan b17bf1d
new release 1.1.7
Ahmath-Gadji 04ef5ed
feat(workspace)!: add workspace models with CRUD methods
paultranvan bcdfb1e
feat(workspace): add alembic migration for workspaces tables
paultranvan 76c8ac4
feat(workspace): expose workspace methods on MilvusDB Ray actor
paultranvan 6d3b665
feat(workspace): add workspace CRUD and file management router
paultranvan 1ab2d08
feat(workspace): add workspace filtering to search and chat pipelines
paultranvan 1e2620d
feat(workspace): add workspace_ids parameter to file upload
paultranvan 42c06cd
test(workspace): add API integration tests
paultranvan a95bd04
docs(workspace): add workspace documentation and update data model
paultranvan 21d5466
chore: Exlude superpowers plans
paultranvan 7b089e2
docs: add alternative migration methods to sql_migration guide
paultranvan b40f37d
fix(workspace): return 201 on creation, use named user dependency
EnjoyBacon7 81f0ee4
fix(workspace): align list_workspaces response shape with get_workspace
EnjoyBacon7 38207de
fix(workspace): return 404 when removing a file not in the workspace
EnjoyBacon7 70d5da5
fix(workspace): prevent partial deletion from crashing delete_workspace
EnjoyBacon7 9731c96
fix(docs): correct workspace endpoint base path from /indexer to /par…
EnjoyBacon7 db041be
fix(docs): correct workspace_files.file_id description — no FK constr…
EnjoyBacon7 45c0dc5
fix(workspace): make workspace actor methods async def for consistenc…
EnjoyBacon7 ea78003
fix(security): validate workspace belongs to target partition before …
EnjoyBacon7 5100e19
fix(workspace): return 409 on duplicate workspace_id instead of unhan…
EnjoyBacon7 131e143
fix(workspace): make add_files_to_workspace idempotent with ON CONFLI…
EnjoyBacon7 030bae0
fix(workspace): scope remove_file_from_all_workspaces to the file's p…
EnjoyBacon7 a8ed1ad
fix: defer workspace association until after file indexing completes
EnjoyBacon7 f531dcc
fix(workspace): route all workspace Ray actor calls through call_ray_…
EnjoyBacon7 060a910
fix(workspace): allow vendor-specific extra fields on request models
EnjoyBacon7 fe36e19
fix(workspace): pin workspace search to workspace's partition in asyn…
EnjoyBacon7 24d05fb
fix: guard workspace association in add_file against DB errors
EnjoyBacon7 a9f8c05
fix: preserve workspace filter when partition==["all"]
EnjoyBacon7 66bbf7a
fix: report accurate orphaned file counts on workspace delete
EnjoyBacon7 1f18e54
fix(lint): fix ruff errors in files.py, test_files.py, indexer.py, se…
EnjoyBacon7 66232a2
fix(lint): fix ruff formatting in test_files.py
EnjoyBacon7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,7 +80,7 @@ node_modules/ | |
| # AI | ||
| .claude | ||
| .planning | ||
| docs/plans | ||
| docs/plans/ | ||
|
|
||
| # Build artifacts | ||
| *.egg-info/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,213 @@ | ||
| --- | ||
| title: Workspaces | ||
| description: Group files into workspaces for scoped search and chat | ||
| --- | ||
|
|
||
| Workspaces let you organize files within a partition into named subsets. When searching or chatting, you can target a specific workspace so that only its files are considered — without affecting the underlying partition structure. | ||
|
|
||
| --- | ||
|
|
||
| ## Concepts | ||
|
|
||
| - A **workspace** belongs to exactly one partition | ||
| - A file can belong to **multiple workspaces** (or none) | ||
| - Workspaces do not duplicate files — they reference existing partition files | ||
| - Deleting a workspace deletes **orphaned files** (files not in any other workspace) from the partition automatically | ||
|
EnjoyBacon7 marked this conversation as resolved.
|
||
| - Deleting a file removes it from all workspaces it belongs to | ||
|
|
||
| --- | ||
|
|
||
| ## Data Model | ||
|
|
||
| ```mermaid | ||
| erDiagram | ||
| partitions ||--o{ workspaces : contains | ||
| workspaces ||--o{ workspace_files : has | ||
| files ||--o{ workspace_files : referenced_by | ||
|
|
||
| workspaces { | ||
| int id PK | ||
| varchar workspace_id UK | ||
| varchar partition_name FK | ||
| varchar display_name | ||
| int created_by FK | ||
| datetime created_at | ||
| } | ||
|
|
||
| workspace_files { | ||
| int id PK | ||
| varchar workspace_id FK | ||
| varchar file_id FK | ||
| } | ||
| ``` | ||
|
|
||
| **Constraints:** | ||
| - `UniqueConstraint(workspace_id)` — workspace IDs are globally unique | ||
| - `UniqueConstraint(workspace_id, file_id)` on `workspace_files` — a file appears at most once per workspace | ||
| - Cascade delete: dropping a workspace removes its `workspace_files` rows | ||
|
|
||
| --- | ||
|
|
||
| ## API Endpoints | ||
|
|
||
| All workspace endpoints live under `/partition/{partition}/workspaces`. | ||
|
|
||
| ### Workspace CRUD | ||
|
|
||
| | Method | Endpoint | Auth | Description | | ||
| |--------|----------|------|-------------| | ||
| | POST | `/partition/{partition}/workspaces` | Editor | Create a workspace | | ||
| | GET | `/partition/{partition}/workspaces` | Viewer | List all workspaces in partition | | ||
| | GET | `/partition/{partition}/workspaces/{workspace_id}` | Viewer | Get workspace details | | ||
| | DELETE | `/partition/{partition}/workspaces/{workspace_id}` | Owner | Delete workspace and orphaned files | | ||
|
|
||
| ### Workspace File Management | ||
|
|
||
| | Method | Endpoint | Auth | Description | | ||
| |--------|----------|------|-------------| | ||
| | POST | `/partition/{partition}/workspaces/{workspace_id}/files` | Editor | Add files to workspace | | ||
| | GET | `/partition/{partition}/workspaces/{workspace_id}/files` | Viewer | List files in workspace | | ||
| | DELETE | `/partition/{partition}/workspaces/{workspace_id}/files/{file_id}` | Editor | Remove file from workspace | | ||
|
|
||
| --- | ||
|
|
||
| ### Create a Workspace | ||
|
|
||
| ```bash | ||
| curl -X POST "$BASE_URL/partition/my-partition/workspaces" \ | ||
| -H "Authorization: Bearer $TOKEN" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"workspace_id": "project-alpha", "display_name": "Project Alpha"}' | ||
| ``` | ||
|
|
||
| ```json | ||
| {"status": "created", "workspace_id": "project-alpha"} | ||
| ``` | ||
|
|
||
| ### List Workspaces | ||
|
|
||
| ```bash | ||
| curl "$BASE_URL/partition/my-partition/workspaces" \ | ||
| -H "Authorization: Bearer $TOKEN" | ||
| ``` | ||
|
|
||
| ```json | ||
| { | ||
| "workspaces": [ | ||
| { | ||
| "workspace_id": "project-alpha", | ||
| "partition_name": "my-partition", | ||
| "display_name": "Project Alpha", | ||
| "created_by": 1, | ||
| "created_at": "2026-03-06T10:00:00" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ### Add Files to a Workspace | ||
|
|
||
| ```bash | ||
| curl -X POST "$BASE_URL/partition/my-partition/workspaces/project-alpha/files" \ | ||
| -H "Authorization: Bearer $TOKEN" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"file_ids": ["report.pdf", "notes.md"]}' | ||
| ``` | ||
|
|
||
| ```json | ||
| {"status": "added", "file_ids": ["report.pdf", "notes.md"]} | ||
| ``` | ||
|
|
||
| ### Delete a Workspace | ||
|
|
||
| ```bash | ||
| curl -X DELETE "$BASE_URL/partition/my-partition/workspaces/project-alpha" \ | ||
| -H "Authorization: Bearer $TOKEN" | ||
| ``` | ||
|
|
||
| ```json | ||
| {"status": "deleted", "orphaned_files_deleted": 1} | ||
| ``` | ||
|
|
||
| Files that belonged **only** to the deleted workspace are automatically removed from the partition. Files shared with other workspaces are preserved. | ||
|
|
||
| --- | ||
|
|
||
| ## Upload with Workspace Assignment | ||
|
|
||
| Files can be added to one or more workspaces at upload time using the `workspace_ids` form parameter: | ||
|
|
||
| ```bash | ||
| curl -X POST "$BASE_URL/indexer/partition/my-partition/file/my-file-id" \ | ||
| -H "Authorization: Bearer $TOKEN" \ | ||
| -F "file=@document.pdf" \ | ||
| -F 'metadata={"mimetype": "application/pdf"}' \ | ||
| -F 'workspace_ids=["project-alpha", "project-beta"]' | ||
| ``` | ||
|
|
||
| The `workspace_ids` field accepts a JSON array of workspace IDs. Each workspace must exist in the target partition, otherwise the request is rejected with a 404. | ||
|
|
||
| --- | ||
|
|
||
| ## Workspace-Scoped Search | ||
|
|
||
| Pass the `workspace` query parameter to restrict search results to files in that workspace: | ||
|
|
||
| ```bash | ||
| curl "$BASE_URL/search/partition/my-partition?text=quarterly+results&workspace=project-alpha" \ | ||
| -H "Authorization: Bearer $TOKEN" | ||
| ``` | ||
|
|
||
| Only chunks from files belonging to the `project-alpha` workspace are returned. | ||
|
|
||
| ### Multi-Partition Search | ||
|
|
||
| The `workspace` parameter also works with multi-partition search: | ||
|
|
||
| ```bash | ||
| curl "$BASE_URL/search?partitions=my-partition&text=quarterly+results&workspace=project-alpha" \ | ||
| -H "Authorization: Bearer $TOKEN" | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Workspace-Scoped Chat | ||
|
|
||
| To scope a chat completion to a workspace, include the `workspace` field in the request metadata: | ||
|
|
||
| ```bash | ||
| curl -X POST "$BASE_URL/v1/chat/completions" \ | ||
| -H "Authorization: Bearer $TOKEN" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "model": "openrag-my-partition", | ||
| "messages": [{"role": "user", "content": "Summarize the Q1 results"}], | ||
| "metadata": {"workspace": "project-alpha"} | ||
| }' | ||
| ``` | ||
|
|
||
| The RAG pipeline resolves the workspace to its file list and filters the vector search accordingly. | ||
|
|
||
| --- | ||
|
|
||
| ## Deletion Behavior | ||
|
|
||
| ### Deleting a Workspace | ||
|
|
||
| ```mermaid | ||
| flowchart LR | ||
| A[Delete workspace] --> B[Find workspace files] | ||
| B --> C{File in other workspaces?} | ||
| C -->|Yes| D[Keep file] | ||
| C -->|No| E[Delete orphaned file from partition] | ||
| D --> F[Done] | ||
| E --> F | ||
| ``` | ||
|
|
||
| ### Deleting a File | ||
|
|
||
| When a file is deleted from a partition (via `DELETE /partition/{partition}/file/{file_id}`), it is automatically removed from all workspaces that reference it. | ||
|
|
||
| ### Deleting a Partition | ||
|
|
||
| When a partition is deleted, all its workspaces and workspace-file associations are cascade-deleted along with the files. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.