Skip to content

Add tags support to conversations API#2454

Open
rbren wants to merge 1 commit intomainfrom
rb/tags
Open

Add tags support to conversations API#2454
rbren wants to merge 1 commit intomainfrom
rb/tags

Conversation

@rbren
Copy link
Contributor

@rbren rbren commented Mar 15, 2026

Summary

Add key-value tag metadata to conversations. Tags can be specified when creating or updating a conversation via the SDK or REST API.

Validation rules

  • Keys: lowercase alphanumeric only (^[a-z0-9]+$)
  • Values: arbitrary strings, max 256 characters

Changes

SDK layer (openhands-sdk/)

  • ConversationTags type in conversation/types.py — Pydantic-validated dict[str, str] with a BeforeValidator enforcing key/value constraints
  • ConversationState — new persisted tags field (auto-saved to base_state.json)
  • Conversation factorytags parameter on all overloads
  • LocalConversation — accepts tags, flows to ConversationState.create
  • RemoteConversation — accepts tags, includes in server POST payload
  • ExportsConversationTags exported from conversation package

Server API layer (openhands-agent-server/)

  • StartConversationRequesttags: ConversationTags field (defaults to {})
  • UpdateConversationRequesttags: ConversationTags | None field (PATCH can now update tags only, title only, or both; title made optional)
  • StoredConversation / ConversationInfo — inherit tags from parents
  • conversation_service.update_conversation — handles tag updates, syncs to ConversationState

Tests (18 new, all passing)

  • tests/sdk/conversation/test_tags.py — validation unit tests (valid keys, invalid keys, value length limits, Pydantic model integration)
  • tests/agent_server/test_conversation_tags.py — API endpoint tests (create with/without tags, invalid keys rejected with 422, PATCH tags, GET returns tags)

Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.13-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:6606e54-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-6606e54-python \
  ghcr.io/openhands/agent-server:6606e54-python

All tags pushed for this build

ghcr.io/openhands/agent-server:6606e54-golang-amd64
ghcr.io/openhands/agent-server:6606e54-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:6606e54-golang-arm64
ghcr.io/openhands/agent-server:6606e54-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:6606e54-java-amd64
ghcr.io/openhands/agent-server:6606e54-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:6606e54-java-arm64
ghcr.io/openhands/agent-server:6606e54-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:6606e54-python-amd64
ghcr.io/openhands/agent-server:6606e54-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-amd64
ghcr.io/openhands/agent-server:6606e54-python-arm64
ghcr.io/openhands/agent-server:6606e54-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-arm64
ghcr.io/openhands/agent-server:6606e54-golang
ghcr.io/openhands/agent-server:6606e54-java
ghcr.io/openhands/agent-server:6606e54-python

About Multi-Architecture Support

  • Each variant tag (e.g., 6606e54-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., 6606e54-python-amd64) are also available if needed

Add key-value tag metadata to conversations. Tags can be specified when
creating or updating a conversation via the SDK or REST API.

Validation rules:
- Keys must be lowercase alphanumeric (regex: ^[a-z0-9]+$)
- Values are arbitrary strings, max 256 characters

Changes:
- Add ConversationTags validated type in conversation/types.py
- Add tags field to ConversationState (persisted in base_state.json)
- Add tags parameter to Conversation factory, LocalConversation, and
  RemoteConversation
- Add tags to StartConversationRequest and UpdateConversationRequest
  (PATCH can now update tags, title, or both)
- Flow tags through conversation_service start and update paths
- Export ConversationTags from conversation package

Co-authored-by: openhands <openhands@all-hands.dev>
@github-actions
Copy link
Contributor

Python API breakage checks — ✅ PASSED

Result:PASSED

Action log

@github-actions
Copy link
Contributor

REST API breakage checks (OpenAPI) — ❌ FAILED

Result:FAILED

⚠️ Breaking REST API changes or policy violations detected.

Log excerpt (first 1000 characters)
::error title=openhands-agent-server REST API::Breaking REST API change detected without MINOR version bump (1.14.0 -> 1.14.0).

Breaking REST API changes detected compared to baseline release:
- added '#/components/schemas/ACPAgent-Output, #/components/schemas/Agent-Output' to the '/items/anyOf[subschema #1: ConversationInfo]/agent' response property 'oneOf' list for the response status '200'
- the '/items/anyOf[subschema #1: ConversationInfo]/agent' response's property type/format changed from 'object'/'' to ''/'' for status '200'
- removed the required property '/items/anyOf[subschema #1: ConversationInfo]/agent/kind' from the response with the '200' status
- removed the required property '/items/anyOf[subschema #1: ConversationInfo]/agent/llm' from the response with the '200' status
- the 'agent' request property type/format changed from 'object'/'' to ''/''
- added '#/components/schemas/ACPAgent-Output, #/components/schemas/Agent-Output' to the 'agent' response property 'oneOf' li

Action log

@github-actions
Copy link
Contributor

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-agent-server/openhands/agent_server
   conversation_service.py38921444%81–82, 109, 112, 123–124, 127–130, 132, 136, 138, 141–148, 151–152, 155–159, 162–164, 166–169, 171, 178–179, 181–183, 186, 190, 192, 194, 201, 207, 215–216, 225–228, 237, 246, 251–252, 255, 268–269, 308, 311, 322–326, 328–331, 334–339, 343, 356–357, 364–365, 380, 394–398, 400–403, 405–407, 409, 412–414, 416–421, 425, 429, 436–440, 443–444, 448–452, 455–456, 460–464, 467–468, 474–479, 486–487, 491, 493–494, 499–500, 506–507, 514–515, 519–521, 539, 563, 595, 597–598, 629, 659, 661, 663–666, 671, 673–674, 678–679, 681–682, 685–687, 690, 696, 701–704, 711–712, 716–720, 722, 727, 731–733, 737–738, 740–742, 744, 746, 759–761, 764, 767, 770–774, 781–782, 786–788, 791–792, 795, 798
   models.py1281489%60–61, 227–228, 230–232, 234, 238–239, 241, 247, 250, 252
openhands-sdk/openhands/sdk/conversation
   conversation.py22195%136
   state.py188895%215, 219, 230, 372, 419–421, 548
openhands-sdk/openhands/sdk/conversation/impl
   local_conversation.py4002693%292, 297, 325, 368, 386, 402, 467, 645–646, 649, 801, 809, 811, 815–816, 827, 829–831, 856, 928, 1054, 1058, 1128, 1135–1136
   remote_conversation.py59010482%127, 154, 167, 169–172, 182, 204–205, 210–213, 289, 299–301, 307, 348, 480–483, 485, 505–509, 514–517, 520, 532–536, 678–679, 683–684, 695, 714–715, 734, 745–746, 766–769, 771–772, 796–798, 801–805, 807–808, 812, 814–822, 824, 861, 988, 1056–1057, 1061, 1066–1070, 1076–1082, 1095–1096, 1172, 1179, 1185–1186, 1241–1242, 1256–1257
TOTAL20127585370% 

@rbren
Copy link
Contributor Author

rbren commented Mar 15, 2026

@OpenHands check github actions and fix the failing tests

@rbren rbren requested a review from all-hands-bot March 15, 2026 23:57
@openhands-ai
Copy link

openhands-ai bot commented Mar 15, 2026

I'm on it! rbren can track my progress at all-hands.dev

Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

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

🟢 Good taste - Clean implementation. The dict[str, str] with Pydantic BeforeValidator is exactly the right pattern here. Validation is straightforward, backward compatible, and well-tested. LGTM! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants