Skip to content

feat: add tag management for Agents with filtering and sorting (#14774)#14799

Merged
yingfeng merged 5 commits into
infiniflow:mainfrom
plind-junior:feat/agent-tag-management
May 13, 2026
Merged

feat: add tag management for Agents with filtering and sorting (#14774)#14799
yingfeng merged 5 commits into
infiniflow:mainfrom
plind-junior:feat/agent-tag-management

Conversation

@plind-junior
Copy link
Copy Markdown

Summary

Closes #14774.

Adds free-form tags on agents (UserCanvas) with full UI + API:

  • Stored as comma-separated tags column on UserCanvas with online migration.
  • New endpoints: GET /v1/agents/tags (aggregate counts) and PUT /v1/agent/<id>/tags (write). GET /v1/agents accepts a tags= query.
  • "Edit tags" item in agent dropdown opens a chip-style editor dialog; tags render as badges on each agent card.
  • New "Tags" facet in the agents filter bar, with counts.

Implementation notes

  • Tag matching is exact-token: the SQL filter wraps stored tags as ,…, and matches ,ml, so ml doesn't match ml-ops.
  • Server-side normalization in 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.
  • Tenant authorization: PUT /v1/agent/<id>/tags gates on UserCanvasService.accessible(canvas_id, tenant_id).
  • Tag listing scope: UserCanvasService.list_tags follows the same own + team-shared rule as get_by_tenant_ids.
  • i18n: keys added to en.ts and zh.ts only (per project convention; other locales fall back).
  • HomeCard gets a non-breaking extra?: ReactNode slot for the chip row; no src/components/ui/ files modified.

Test plan

  • Backend boot runs migrate_db → confirm user_canvas.tags column exists (DESCRIBE user_canvas).
  • Agents page renders cards normally (no console error from missing field).
  • ⋯ → Edit tags opens a dialog that stays open (regression: dialog was unmounting with the dropdown).
  • Typing a tag without pressing Enter and clicking Save persists it (regression: last typed tag was being dropped).
  • Chip input supports Enter/comma to commit, Backspace on empty to remove, × to remove individual chip.
  • Tag containing a comma sent via API is stored with the comma replaced by a space.
  • 20 long tags sent via API does not error (length cap silently truncates).
  • "Tags" filter in the filter bar shows counts and narrows the list.
  • Filtering by ml does not return agents tagged ml-ops.
  • UI in Chinese shows 编辑标签 / 添加标签以整理和筛选你的智能体 etc.
  • PUT /v1/agent/<other-tenant-id>/tags returns Agent not found or no permission.

…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.
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label May 11, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 490afc2e-58db-4b86-8c48-5ee7ccbb1749

📥 Commits

Reviewing files that changed from the base of the PR and between 9a89c89 and d74bcac.

📒 Files selected for processing (1)
  • test/testcases/test_web_api/test_agent_app/test_agents_webhook_unit.py

📝 Walkthrough

Walkthrough

Adds full-stack agent tag management: DB tags column and migration, service filtering/aggregation and update, REST endpoints to list/update tags and filter agents, frontend display/editor components and hooks, filter integration, and translations.

Changes

Agent Tag Management Feature

Layer / File(s) Summary
Database Schema
api/db/db_models.py
UserCanvas gains indexed tags (CharField, 512, non-null, default "") and migrate_db() updated to add the column.
Backend Query Imports
api/db/services/canvas_service.py
Adds reduce and or_ imports used for OR-combined tag predicates.
Backend Service: Canvas Query & Filtering
api/db/services/canvas_service.py
get_by_tenant_ids(..., tags?) now returns tags and applies OR-combined substring matching for tokenized tags.
Backend Service: Tag Aggregation & Update
api/db/services/canvas_service.py
Adds list_tags() to aggregate per-tag counts and update_tags() to normalize/dedupe/truncate and persist tags; defines TAGS limits.
REST API: Agent List with Tag Filtering
api/apps/restful_apis/agent_api.py
list_agents parses tags query param and forwards tags to the canvas service for filtered results.
REST API: Tag Management Endpoints
api/apps/restful_apis/agent_api.py
Adds GET /agents/tags to return tag counts and PUT /agents/<canvas_id>/tags to update tags (with access check and normalized input).
Frontend Data Types
web/src/interfaces/database/agent.ts
IFlow interface gains optional tags?: string.
Frontend API Config
web/src/utils/api.ts
Adds listAgentTags and updateAgentTags(agentId) endpoint entries.
Frontend Service Layer
web/src/services/agent-service.ts
Registers listAgentTags method and exports updateAgentTags(agentId, tags) that PUTs comma-joined tags.
Frontend Hooks: Actions & Params
web/src/hooks/use-agent-request.ts
Extends AgentApiAction; buildAgentListParams accepts tags?: string[] and serializes to CSV; useFetchAgentListByPage forwards tag filters.
Frontend Hooks: Tag Query & Mutation
web/src/hooks/use-agent-request.ts
Adds IAgentTagCount, useFetchAgentTags(canvasCategory?) to fetch counts, and useUpdateAgentTags() mutation with error handling and cache invalidation.
Component Foundation: HomeCard Extension
web/src/components/home-card.tsx
HomeCard accepts an optional extra ReactNode and renders it in the card content.
UI: Agent Tag Display
web/src/pages/agents/agent-card.tsx
Adds AgentTags helper and renders tags as Badges via HomeCard.extra.
UI: Dropdown Integration
web/src/pages/agents/agent-dropdown.tsx
Adds "edit tags" menu item, tagEditorOpen state, and embeds AgentTagEditor.
UI: Tag Editor Dialog
web/src/pages/agents/agent-tag-editor.tsx
Adds AgentTagEditor with tag parsing, suggestions, draft input, keyboard commits, removable badges, and save flow calling updateAgentTags.
Frontend Filter Integration
web/src/pages/agents/hooks/use-selelct-filters.ts
useSelectFilters fetches tag counts and appends a tags filter to the filters collection.
Localization
web/src/locales/en.ts, web/src/locales/zh.ts
Adds English and Chinese translation strings for tag editing UI text.
Tests
test/testcases/test_web_api/test_agent_app/test_agents_webhook_unit.py
Unit test monkeypatch updated to accept and capture the new tags argument for get_by_tenant_ids.

Sequence Diagram

sequenceDiagram
  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}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • infiniflow/ragflow#14157: Modifies the same list_agents REST endpoint; this PR extends that work with tag storage, tag-aware filtering and aggregation, and frontend support.

Suggested labels

💞 feature, 🐖api, size:M, 🧪 test

Suggested reviewers

  • yingfeng
  • yuzhichang
  • wangq8

🐰 I nibble code and hop with glee,

Tags on agents bloom like springtime tea.
From DB field to badge I bound,
Edit, save, and filters found.
Hooray — I hop, the tags are sound!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature being added: tag management for Agents with filtering and sorting support, directly matching the PR's core changes.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the problem statement, implementation details, design decisions, and a detailed test plan checklist.
Linked Issues check ✅ Passed The PR fully addresses all coding requirements from issue #14774: tagging system with editable/removable tags, filterable agent list with tag facet and counts, exact-token matching semantics, tenant authorization, and tag normalization constraints.
Out of Scope Changes check ✅ Passed All changes are directly related to the tag management feature: database schema, service layer filtering/updating, API endpoints, UI components for tag display/editing, localization strings, and test updates. No extraneous modifications were detected.

✏️ 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.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
api/apps/restful_apis/agent_api.py (1)

357-367: ⚡ Quick win

Add request-level logging for the new tag endpoints.

GET /agents/tags and PUT /agent/<canvas_id>/tags are 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 win

Add lightweight logging for new tag read/write flows.

list_tags and update_tags introduce 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

📥 Commits

Reviewing files that changed from the base of the PR and between 2f2d156 and 5de2689.

📒 Files selected for processing (14)
  • api/apps/restful_apis/agent_api.py
  • api/db/db_models.py
  • api/db/services/canvas_service.py
  • web/src/components/home-card.tsx
  • web/src/hooks/use-agent-request.ts
  • web/src/interfaces/database/agent.ts
  • web/src/locales/en.ts
  • web/src/locales/zh.ts
  • web/src/pages/agents/agent-card.tsx
  • web/src/pages/agents/agent-dropdown.tsx
  • web/src/pages/agents/agent-tag-editor.tsx
  • web/src/pages/agents/hooks/use-selelct-filters.ts
  • web/src/services/agent-service.ts
  • web/src/utils/api.ts

Comment thread api/apps/restful_apis/agent_api.py Outdated
Comment thread web/src/pages/agents/agent-tag-editor.tsx
- 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.
Comment thread api/apps/restful_apis/agent_api.py Outdated
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manager.route("/agents/<canvas_id>/tags", methods=["PUT"])

I found a bug in my testing. We need to add an s here.

@caesergattuso
Copy link
Copy Markdown

Could you add a list of existing tags in the tag input area for quick selection? This will make tag usage much more convenient.

@plind-junior
Copy link
Copy Markdown
Author

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.
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels May 12, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4e0bda6 and 754e34e.

📒 Files selected for processing (4)
  • api/apps/restful_apis/agent_api.py
  • web/src/locales/en.ts
  • web/src/locales/zh.ts
  • web/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

Comment thread web/src/pages/agents/agent-tag-editor.tsx
Comment thread web/src/pages/agents/agent-tag-editor.tsx
Comment thread web/src/pages/agents/agent-tag-editor.tsx Outdated
@wangq8 wangq8 requested a review from Magicbook1108 May 12, 2026 09:10
Copy link
Copy Markdown
Contributor

@Magicbook1108 Magicbook1108 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

- 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.
@Magicbook1108 Magicbook1108 added the ci Continue Integration label May 13, 2026
@yingfeng yingfeng marked this pull request as draft May 13, 2026 12:40
@yingfeng yingfeng marked this pull request as ready for review May 13, 2026 12:40
@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.16%. Comparing base (daf8a58) to head (d74bcac).
⚠️ Report is 52 commits behind head on main.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yingfeng
Copy link
Copy Markdown
Member

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.
@yingfeng yingfeng merged commit dd76653 into infiniflow:main May 13, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continue Integration size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Add tag management for Agents with filtering and sorting support

4 participants