OpenHands / OpenHands/software-agent-sdk
[Feature]: Add per-key tag endpoints to avoid read-modify-write on PATCH /api/conversations/{id}
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 539
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
Problem or Use Case
UpdateConversationRequest.tags replaces the entire tag map when provided — this is correctly documented in openhands-agent-server/openhands/agent_server/models.py:
"Replaces all existing tags when provided."
In practice this means any client that wants to update a single tag must:
GET /api/conversations/{id}to read the current tag map- Merge the new key into the existing map in memory
PATCH /api/conversations/{id}with the full merged map
This is fragile: a race between two clients patching different keys will silently drop one client's write. It also forces unnecessary round-trips for what is semantically a one-key update.
Concrete downstream impact: In OpenHands/OpenHands (agent-canvas), AgentServerConversationService.updateConversationRepository needs to update the repository, selected_branch, and git_provider tags on an existing conversation without clobbering the acpserver and clientsource tags stamped at creation time. The read-modify-write pattern was introduced specifically to work around the full-replace behaviour (see OpenHands/OpenHands#16666).
Desired Behavior
Add per-key sub-resource endpoints so callers can set or remove a single tag atomically:
PUT /api/conversations/{id}/tags/{key} — set (or overwrite) one tag; body: {"value": "..."}
DELETE /api/conversations/{id}/tags/{key} — remove one tag
Both operations leave all other tags untouched. This eliminates the read-modify-write footgun entirely and makes single-key updates safe under concurrency.
The existing PATCH /api/conversations/{id} full-replace behaviour stays as-is for callers that genuinely need to set the whole map in one shot.
Additional Context
- Existing test coverage for tag behaviour lives in
tests/agent_server/test_conversation_tags.py— the new endpoints should extend that suite. - Once these endpoints are available,
updateConversationRepositoryin agent-canvas can be simplified to two direct calls (set or delete) with no pre-read. Tracking that simplification in OpenHands/OpenHands#16666. - Docs: the new endpoints should be reflected in the agent-server OpenAPI schema and any REST contract documentation in
openhands-agent-server/AGENTS.md. updated_atmust not be bumped by either new endpoint. Tag mutations are metadata operations, not content changes; bumpingupdated_aton a tag write breaks localStorage-to-server migrations and disrupts sort order for users sorted by last-modified. See comment for full context. The existingPATCHfull-replace can keep its current behaviour.
Acceptance Criteria
-
PUT /api/conversations/{id}/tags/{key}sets or overwrites a single tag; all other tags on the conversation are unchanged -
DELETE /api/conversations/{id}/tags/{key}removes a single tag; all other tags on the conversation are unchanged - Neither endpoint updates
updated_aton the conversation - Both endpoints return 404 when the conversation does not exist
-
DELETEon a key that does not exist returns 404 (no silent no-op) - Tests added to
tests/agent_server/test_conversation_tags.pycovering set, overwrite, delete, missing-conversation 404, and missing-key 404 - New endpoints appear in the agent-server OpenAPI schema
-
openhands-agent-server/AGENTS.mdupdated to document the new endpoints
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the conversation tag models and handlers referenced in openhands-agent-server/openhands/agent_server/models.py, then run tests/agent_server/test_conversation_tags.py. Add the PUT and DELETE endpoints, extend that test suite for the listed 404 and mutation cases, and update the agent-server OpenAPI schema and openhands-agent-server/AGENTS.md; done means other tags and updated_at remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, documentation
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100