feat: add tag management for Agents with filtering and sorting (#14774)#14799
Conversation
…iflow#14774) Adds free-form tags on UserCanvas with API + UI for editing, filtering, and aggregate counts. Tag matching uses comma-wrapped LIKE so "ml" does not match "ml-ops". Tenant authorization, length caps, and comma stripping enforced server-side.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds full-stack agent tag management: DB ChangesAgent Tag Management Feature
Sequence DiagramsequenceDiagram
participant Client
participant agent_api as agent_api (REST)
participant UserCanvasService
participant DB as user_canvas.tags
Client->>agent_api: GET /agents?tags=a,b
agent_api->>UserCanvasService: get_by_tenant_ids(..., tags=['a','b'])
UserCanvasService->>DB: read rows including `tags` column
DB-->>UserCanvasService: canvas rows
UserCanvasService-->>agent_api: filtered canvases
agent_api-->>Client: HTTP 200 [canvases...]
Client->>agent_api: GET /agents/tags
agent_api->>UserCanvasService: list_tags(joined_tenant_ids, user_id, canvas_category?)
UserCanvasService->>DB: read tags across canvases
DB-->>UserCanvasService: tag strings
UserCanvasService-->>agent_api: aggregated {tag:count}
agent_api-->>Client: HTTP 200 [{tag,count},...]
Client->>agent_api: PUT /agents/{id}/tags {tags: "x,y"}
agent_api->>UserCanvasService: update_tags(canvas_id, ['x','y'])
UserCanvasService->>DB: write normalized `tags` value
DB-->>UserCanvasService: affected rows
UserCanvasService-->>agent_api: update result
agent_api-->>Client: HTTP 200 {data: True}
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
api/apps/restful_apis/agent_api.py (1)
357-367: ⚡ Quick winAdd request-level logging for the new tag endpoints.
GET /agents/tagsandPUT /agent/<canvas_id>/tagsare new flows and should log key metadata (tenant_id, canvas_id, tags_count, status) for observability and incident triage.As per coding guidelines, "**/*.py: Add logging for new flows".
Also applies to: 369-383
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@api/apps/restful_apis/agent_api.py` around lines 357 - 367, Add request-level logging in the new tag endpoints: inside list_agent_tags (route "/agents/tags") log tenant_id, canvas_category, number of tags returned (tags_count), and response status (success/failure) before returning; likewise update the PUT handler (update_agent_tags / route "/agent/<canvas_id>/tags") to log tenant_id, canvas_id, incoming tags_count, and final status. Use the existing logger (processLogger or request-scoped logger used elsewhere) and log at INFO level with clear keys so logs can be parsed for observability and incident triage.api/db/services/canvas_service.py (1)
213-229: ⚡ Quick winAdd lightweight logging for new tag read/write flows.
list_tagsandupdate_tagsintroduce new behavior but currently emit no operational logs (e.g., caller, canvas_id, tag count, update result), which makes troubleshooting and audit tracing harder.As per coding guidelines, "**/*.py: Add logging for new flows".
Also applies to: 236-262
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@api/db/services/canvas_service.py` around lines 213 - 229, The new tag read/write flows lack operational logs; add lightweight INFO-level logging to CanvasService.list_tags and CanvasService.update_tags (or methods with those exact names) that records the caller/user_id, canvas_id (or canvas_category for list_tags), the number of tags returned/updated, and the update result/outcome; use the module logger (logger = logging.getLogger(__name__)) or the existing project logger, place a log entry at the start of each method noting inputs and one after the DB operation noting counts/results, and ensure logs include unique identifiers (user_id, canvas_id/canvas_category) for traceability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@api/apps/restful_apis/agent_api.py`:
- Around line 381-382: The current call to
UserCanvasService.update_tags(canvas_id, tags) ignores the return value so the
endpoint may return success even when no rows were updated; capture the update
result (e.g., rows_affected = UserCanvasService.update_tags(...)), check if
rows_affected == 0 and in that case return an error JSON (or appropriate HTTP
error) instead of get_json_result(data=True), otherwise return success; update
the endpoint around the UserCanvasService.update_tags and get_json_result calls
to implement this check.
In `@web/src/pages/agents/agent-tag-editor.tsx`:
- Around line 65-73: handleSave currently updates local state and closes the
dialog before awaiting updateAgentTags; change it to await updateAgentTags first
and only update state and call onOpenChange(false) on success. Concretely, move
setTags(finalTags) and setDraft('') to after a successful await
updateAgentTags({ agentId: agent.id, tags: finalTags }), wrap the await in a
try/catch, and in the catch do not close the dialog (let the existing error
toast from updateAgentTags surface); this keeps the dialog open for retry if the
backend call fails.
---
Nitpick comments:
In `@api/apps/restful_apis/agent_api.py`:
- Around line 357-367: Add request-level logging in the new tag endpoints:
inside list_agent_tags (route "/agents/tags") log tenant_id, canvas_category,
number of tags returned (tags_count), and response status (success/failure)
before returning; likewise update the PUT handler (update_agent_tags / route
"/agent/<canvas_id>/tags") to log tenant_id, canvas_id, incoming tags_count, and
final status. Use the existing logger (processLogger or request-scoped logger
used elsewhere) and log at INFO level with clear keys so logs can be parsed for
observability and incident triage.
In `@api/db/services/canvas_service.py`:
- Around line 213-229: The new tag read/write flows lack operational logs; add
lightweight INFO-level logging to CanvasService.list_tags and
CanvasService.update_tags (or methods with those exact names) that records the
caller/user_id, canvas_id (or canvas_category for list_tags), the number of tags
returned/updated, and the update result/outcome; use the module logger (logger =
logging.getLogger(__name__)) or the existing project logger, place a log entry
at the start of each method noting inputs and one after the DB operation noting
counts/results, and ensure logs include unique identifiers (user_id,
canvas_id/canvas_category) for traceability.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6a1651b8-dd67-48aa-96e1-9eba59925db1
📒 Files selected for processing (14)
api/apps/restful_apis/agent_api.pyapi/db/db_models.pyapi/db/services/canvas_service.pyweb/src/components/home-card.tsxweb/src/hooks/use-agent-request.tsweb/src/interfaces/database/agent.tsweb/src/locales/en.tsweb/src/locales/zh.tsweb/src/pages/agents/agent-card.tsxweb/src/pages/agents/agent-dropdown.tsxweb/src/pages/agents/agent-tag-editor.tsxweb/src/pages/agents/hooks/use-selelct-filters.tsweb/src/services/agent-service.tsweb/src/utils/api.ts
- update_agent_tags: return error when update affects zero rows (concurrent delete race). - AgentTagEditor: only close dialog when updateAgentTags resolves true; keeps form state so the user can retry after a backend error. - Add INFO logging to GET /agents/tags, PUT /agent/<id>/tags, UserCanvasService.list_tags, and UserCanvasService.update_tags (tenant_id, canvas_id, tags_count, rows_affected) per the project logging rule.
| return get_json_result(data=[{"tag": k, "count": v} for k, v in sorted(counts.items(), key=lambda x: (-x[1], x[0]))]) | ||
|
|
||
|
|
||
| @manager.route("/agent/<canvas_id>/tags", methods=["PUT"]) # noqa: F821 |
There was a problem hiding this comment.
@manager.route("/agents/<canvas_id>/tags", methods=["PUT"])
I found a bug in my testing. We need to add an s here.
|
Could you add a list of existing tags in the tag input area for quick selection? This will make tag usage much more convenient. |
|
Will do it, thanks |
…uggestions - Route fix: PUT was /agent/<canvas_id>/tags (singular) while the frontend calls /agents/<canvas_id>/tags. Every other endpoint in agent_api.py also uses plural /agents/...; the singular form was the only outlier and caused a 404 on save. Now plural. - AgentTagEditor: show an "Existing tags" suggestion row that lists tags already used elsewhere (via useFetchAgentTags), excluding tags already on the agent and filtered by the typed prefix. Click a chip to add it.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/src/pages/agents/agent-tag-editor.tsx`:
- Around line 50-55: The suggestion list currently performs substring matching;
locate the tag filtering chain around the variables draft/needle and replace the
substring check that uses tag.toLowerCase().includes(needle) with a prefix check
using startsWith so suggestions follow documented prefix behavior; ensure you
keep the existing lowercasing (tag.toLowerCase() and needle) and preserve the
other filters for taken and slicing to 20 results (references: draft, needle,
allTags, taken).
- Around line 82-85: The current append logic in handleSave uses a
case-sensitive check (!tags.includes(pending)) which can allow logical
duplicates (e.g., "ML" vs "ml"); change it to perform a case-insensitive dedupe
by comparing pending.toLowerCase() against tags.map(t => t.toLowerCase()) before
adding, keeping the original pending casing when appending; ensure you still
trim draft into pending and only add when pending is non-empty, then call
setTags(finalTags) as before.
- Line 117: The remove button's aria-label in AgentTagEditor is hardcoded in
English; replace it with the localized string (e.g. use the i18n/locale lookup
for flow.removeTagAriaLabel and interpolate the tag) so the aria-label is
translated, and add the flow.removeTagAriaLabel entry to all locale files with
the appropriate placeholder (e.g. "{tag}" or similar) so assistive tech receives
a localized label.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ec133c90-1946-4f92-a0f2-8dadea534788
📒 Files selected for processing (4)
api/apps/restful_apis/agent_api.pyweb/src/locales/en.tsweb/src/locales/zh.tsweb/src/pages/agents/agent-tag-editor.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- web/src/locales/zh.ts
- web/src/locales/en.ts
- api/apps/restful_apis/agent_api.py
- Suggestion list filtering switched to prefix match (startsWith) so it matches the documented "prefix suggestion" UX. - handleSave now compares the pending draft case-insensitively against existing tags, matching the addTag dedupe rule and preventing chips like "ML" and "ml" from co-existing. - Remove-tag aria-label is now localized via flow.removeTagAriaLabel in en/zh locales instead of being hardcoded in English.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #14799 +/- ##
=======================================
Coverage 94.16% 94.16%
=======================================
Files 10 10
Lines 703 703
Branches 112 112
=======================================
Hits 662 662
Misses 25 25
Partials 16 16 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Please fix the CI failure, thanks~ |
list_agents now passes the tags filter through to UserCanvasService.get_by_tenant_ids, so the fake replacement in test_agents_crud_unit_branches needs to accept that 9th positional argument. Without this the test raises: TypeError: fake_get_by_tenant_ids() takes 8 positional arguments but 9 were given Fixes CI failure on infiniflow#14799.
Summary
Closes #14774.
Adds free-form tags on agents (UserCanvas) with full UI + API:
tagscolumn onUserCanvaswith online migration.GET /v1/agents/tags(aggregate counts) andPUT /v1/agent/<id>/tags(write).GET /v1/agentsaccepts atags=query.Implementation notes
,…,and matches,ml,somldoesn't matchml-ops.UserCanvasService.update_tags: dedup (case-insensitive), per-tag cap of 64 chars, total length capped at 512 chars to fit the column, commas inside tag values are replaced with spaces.PUT /v1/agent/<id>/tagsgates onUserCanvasService.accessible(canvas_id, tenant_id).UserCanvasService.list_tagsfollows the same own + team-shared rule asget_by_tenant_ids.en.tsandzh.tsonly (per project convention; other locales fall back).HomeCardgets a non-breakingextra?: ReactNodeslot for the chip row; nosrc/components/ui/files modified.Test plan
migrate_db→ confirmuser_canvas.tagscolumn exists (DESCRIBE user_canvas).⋯ → Edit tagsopens a dialog that stays open (regression: dialog was unmounting with the dropdown).×to remove individual chip.mldoes not return agents taggedml-ops.PUT /v1/agent/<other-tenant-id>/tagsreturnsAgent not found or no permission.