feat(projects): add star, unstar and get_starred for starred projects - #801
prasad-albert wants to merge 9 commits into
Conversation
Lets callers (including Ask Albert) pin projects for the current user, matching the web app's Starred Projects. get_starred yields fully populated Projects and unstar on a project that is not starred is a no-op. Refs AI-2153.
|
Code Review Issues Found
Verify against live API
Summary 2 issues found, plus one contract to verify. The |
…ed args Address review on #801: fall back to the id key when matching starred records and add @validate_call to get_starred for consistency with sibling methods.
Code ReviewIssues Found
Summary1 issue found. Correctness of star/get_starred/unstar hinges on the personalization GET response matching the standard |
Code ReviewIssues Found
Summary1 issue found. Contingent correctness risk: the feature works only if the personalization GET envelope uses the standard |
…ion model Covers create, get_by_id, get_all (category/sub_category/saved_id/user_id filters, current user by default), and delete over /api/v3/personalization. PATCH is intentionally deferred: its ops are category-specific and require exact old-value matching. Refs AI-2153.
…onCollection Same public API and wire behavior; the one-off personalization calls in ProjectCollection now go through client.personalization. Refs AI-2153.
|
Looks good - no bugs or correctness issues found. |
CircleCI Integration Tests failedBranch: |
CircleCI Integration Tests failedBranch: |
The create call returns {id, parentId, savedId, savedName} with no
category key, so Personalization(**response) raised a validation error
in create() and projects.star(). The category just sent is authoritative;
setdefault it onto the response before validating. Refs AI-2153.
|
Looks good - no bugs or correctness issues found. |
CircleCI Integration Tests failedBranch: |
The handler supports a savedId query, but the deployed API spec (rest/api.yaml) does not declare it, so the gateway rejects the request with "Unknown query parameter 'savedId'". Remove the parameter until the backend declares it; listing is by createdBy (current user by default). Refs AI-2153.
|
Code Review Issues Found
Summary 2 issue(s) found. No confirmed logic bugs; the implementation mirrors the users.get_all pattern correctly. The main risk is the unverified pagination response key on a brand-new endpoint whose integration tests were not executed, confirm before merging. |
What
client.projectscan now star (pin) a project for the current user, remove the star, and list the user's starred projects as fully populatedProjects. It's the same "Starred Projects" feature the web app has.Why
Ask Albert couldn't pin projects for users (AI-2153). It even claimed starring was a browser-only preference. In fact stars are stored server-side by
api-personalization, and the SDK simply had no wrapper for it. Ask Albert generates its tools from SDK methods, so this change is what unblocks that request.How
api-personalizationat/api/v3/personalization, category"Starred Projects".POST [{category, savedId: PRO…, savedName}].GET ?createdBy=<me>&category=Starred Projects, key-based pagination.DELETE /personalization/{USP id}.PersonalizationCollection(client.personalization) wraps/api/v3/personalizationwith basic CRUD:create,get_by_id,get_all(category/sub_category/saved_id/user_id filters, current user by default),delete. This unlocks the other personalization categories (Hidden Rows, Saved Filters, User Configuration, Notification, Skills) for future work. PATCH is intentionally deferred: its ops are category-specific and require exact old-value matching.star/unstar/get_starredmethods live onProjectCollectionand delegate toPersonalizationCollection. There's no separate starred-project model: every method returnsProject.starfetches the project first, which checks that it exists and suppliessavedName. It returns that project.savedId already existis treated as success, and any other 400 is still raised.unstarfinds the user's starred record(s) whosesavedIdmatches and deletes them. If the project isn't starred, nothing happens.get_starredwraps the key-mode paginator in aMappedPaginatorthat hydrates each item withget_by_id, the same pattern asusers.get_all.limit=200(the API's maximum) explicitly. The handler callsparseInt(params.limit)with no fallback, so I didn't want to rely on the OpenAPI default of 100 being applied.parentIdfrom the token. So a service-credential client stars for the service user.Testing
uv run pytest tests/unit: 1249 passed. That includes new unit tests for the personalization query builder, record matching,albertId/idalias round-trips, and detecting the duplicate-star error, plus the meta tests for keyword-only arguments,max_items, docstrings and theMethodslisting.test_star_get_starred_and_unstar_projectintests/integration/collections/test_projects.py. It covers star, idempotent re-star, get_starred, unstar, and unstar on a project that isn't starred.tests/integration/collections/test_personalization.pycovering create, get_by_id, get_all (by category and by saved_id), and delete.ALBERT_*credentials. Please run:uv run pytest tests/integration/collections/test_projects.py tests/integration/collections/test_personalization.py -v -n 4[{"id":"USP17620","parentId":"USR4227","savedId":"PROMO130903","savedName":"test-worksheets"}].Linear: AI-2153
Cake session: https://agents.ai.albertinventdev.com/sessions/875eb734-655e-4d08-9489-12bba899becf