Skip to content

feat(conversation): add client message context#4110

Closed
simonrosenberg wants to merge 2 commits into
mainfrom
client-message-context
Closed

feat(conversation): add client message context#4110
simonrosenberg wants to merge 2 commits into
mainfrom
client-message-context

Conversation

@simonrosenberg

@simonrosenberg simonrosenberg commented Jul 14, 2026

Copy link
Copy Markdown
Member

HUMAN:


AGENT:

Why

Runtime and UI context is owned by the client, can change independently of the agent profile, and should retain user-role semantics. Encoding it as a trusted launch-time system-message augmentation conflates ownership and lifecycle. This replaces the generic launch augmentation proposed in #4030 with context attached to a user message.

Summary

  • Add optional client_context to local and remote send_message, initial conversation messages, and the REST event endpoint.
  • Persist client context as MessageEvent.extended_content: it is included in LLM input without changing the visible message content.
  • Cover serialization, routing, persistence, visualization, and a real RemoteConversation → agent-server round trip.

REST API contract changes

Compared with base OpenAPI 56ac31719f91 for public /api/** paths.

--- base public OpenAPI
+++ head public OpenAPI
@@ -2012,0 +2013 @@
+schema SendMessageRequest property client_context optional schema=type="array" items=TextContent

Issue Number

Supersedes #4030. Canvas consumer: OpenHands/agent-canvas#1782. Documentation: OpenHands/docs#622. Related transport work: #4078.

How to Test

Focused behavior and live-server coverage:

.venv-client-context/bin/pytest -q \
  tests/sdk/conversation/local/test_conversation_send_message.py \
  tests/sdk/conversation/remote/test_remote_conversation.py \
  tests/agent_server/test_event_router.py \
  tests/sdk/conversation/test_visualizer.py \
  tests/agent_server/test_conversation_service.py::test_start_conversation_forwards_initial_message_client_context \
  tests/cross/test_remote_conversation_live_server.py::test_remote_conversation_over_real_server

Result: 116 passed. The live-server test starts the actual agent server, sends client_context through RemoteConversation, and verifies it is persisted on the user MessageEvent.

.venv-client-context/bin/pytest -q tests/agent_server/test_event_service.py::TestEventServiceSendMessage

Result: 18 passed.

Direct isolated-environment checks on all changed Python files:

.venv-client-context/bin/ruff format --check <changed Python files>
.venv-client-context/bin/ruff check <changed Python files>
.venv-client-context/bin/pyright <changed production Python files>

Results: 14 files already formatted, All checks passed, and 0 errors, 0 warnings, 0 informations.

Video/Screenshots

Not applicable; this is an SDK and API change with real-server test coverage.

Type

  • Bug fix
  • Feature
  • Refactor
  • Breaking change
  • Docs / chore

Notes

This is additive. client_context is persisted with the conversation and is not a security boundary; clients must not put secrets in it. The Canvas consumer should land after an agent-server release containing this API.


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-slim 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:2b0b4b2-python

Run

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

All tags pushed for this build

ghcr.io/openhands/agent-server:2b0b4b2-golang-amd64
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-golang-amd64
ghcr.io/openhands/agent-server:client-message-context-golang-amd64
ghcr.io/openhands/agent-server:2b0b4b2-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:2b0b4b2-golang-arm64
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-golang-arm64
ghcr.io/openhands/agent-server:client-message-context-golang-arm64
ghcr.io/openhands/agent-server:2b0b4b2-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:2b0b4b2-java-amd64
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-java-amd64
ghcr.io/openhands/agent-server:client-message-context-java-amd64
ghcr.io/openhands/agent-server:2b0b4b2-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:2b0b4b2-java-arm64
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-java-arm64
ghcr.io/openhands/agent-server:client-message-context-java-arm64
ghcr.io/openhands/agent-server:2b0b4b2-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:2b0b4b2-python-amd64
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-python-amd64
ghcr.io/openhands/agent-server:client-message-context-python-amd64
ghcr.io/openhands/agent-server:2b0b4b2-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-amd64
ghcr.io/openhands/agent-server:2b0b4b2-python-arm64
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-python-arm64
ghcr.io/openhands/agent-server:client-message-context-python-arm64
ghcr.io/openhands/agent-server:2b0b4b2-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim-arm64
ghcr.io/openhands/agent-server:2b0b4b2-golang
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-golang
ghcr.io/openhands/agent-server:client-message-context-golang
ghcr.io/openhands/agent-server:2b0b4b2-golang_tag_1.21-bookworm
ghcr.io/openhands/agent-server:2b0b4b2-java
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-java
ghcr.io/openhands/agent-server:client-message-context-java
ghcr.io/openhands/agent-server:2b0b4b2-eclipse-temurin_tag_17-jdk
ghcr.io/openhands/agent-server:2b0b4b2-python
ghcr.io/openhands/agent-server:2b0b4b26207a0cad21e29a1b39f40fa691d02b04-python
ghcr.io/openhands/agent-server:client-message-context-python
ghcr.io/openhands/agent-server:2b0b4b2-nikolaik_s_python-nodejs_tag_python3.13-nodejs22-slim

About Multi-Architecture Support

  • Each variant tag (e.g., 2b0b4b2-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., 2b0b4b2-python-amd64) are also available if needed

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

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Python API breakage checks — ✅ PASSED

Result:PASSED

Action log

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

REST API breakage checks (OpenAPI) — ✅ PASSED

Result:PASSED

Action log

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

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Coverage

Coverage Report •
FileStmtsMissCoverMissing
openhands-agent-server/openhands/agent_server
   conversation_service.py67710584%154–155, 164, 190–191, 195–196, 201, 286–287, 290–291, 303–304, 318, 470–471, 504, 507, 514–520, 547, 553, 649, 655, 660, 666, 674–675, 684–687, 696, 708, 716, 761–762, 823, 866–870, 872–873, 876–877, 887, 899–904, 1002, 1009–1013, 1016–1017, 1021–1025, 1028–1029, 1033–1037, 1040–1041, 1070, 1075, 1079, 1119, 1126–1128, 1147, 1168, 1178, 1182, 1184–1185, 1190–1191, 1197–1198, 1208, 1257, 1272, 1310, 1624, 1627
   event_router.py55885%185–188, 198–199, 223–224
   event_service.py71911684%123–124, 154, 157–158, 162–163, 174, 180, 190–194, 197–200, 271, 292–293, 367, 421, 441, 448, 472–473, 477, 485, 488, 521, 553, 564, 571, 577, 642–643, 721, 751, 754, 813, 834, 949, 1061–1064, 1068, 1097, 1101, 1108, 1122, 1137, 1184–1186, 1257, 1282, 1288, 1290, 1300, 1302, 1309, 1319, 1321–1322, 1326, 1340–1345, 1347, 1374, 1379–1382, 1386–1389, 1397–1400, 1446–1448, 1501–1502, 1504–1511, 1513–1514, 1523–1524, 1526–1527, 1534–1535, 1537–1538, 1549, 1574, 1580, 1586, 1595–1596
openhands-sdk/openhands/sdk/conversation
   base.py111397%235, 243, 297
   request.py881089%78, 273, 279, 285, 287–288, 291–292, 303, 312
openhands-sdk/openhands/sdk/conversation/impl
   local_conversation.py10199491%133, 584–585, 618, 635, 942, 966–967, 972, 987, 989, 1071, 1087, 1135, 1161, 1192, 1213, 1217–1223, 1282, 1302–1304, 1353, 1372–1374, 1703–1704, 1719, 1807–1808, 1811, 1944, 1947–1948, 1973, 2006–2007, 2010, 2016, 2097, 2104, 2107, 2110, 2114–2115, 2119–2120, 2123, 2130, 2155, 2159, 2162, 2181, 2233, 2236, 2275, 2282–2283, 2291, 2295–2297, 2304, 2341–2347, 2350, 2353, 2360, 2423, 2428, 2538, 2540, 2544–2545, 2556–2557, 2582, 2782, 2786, 2856, 2863–2864
   remote_conversation.py7518888%89, 164, 191, 204, 206–209, 230, 248–249, 260–263, 270–271, 276–279, 363, 373–375, 381, 459, 606–609, 611, 637–641, 646–649, 652, 668, 806, 864–865, 869–870, 884, 898–901, 942, 955–956, 980–981, 1021–1022, 1058, 1068, 1072, 1081–1082, 1127, 1281–1282, 1376–1377, 1381, 1386–1390, 1396–1402, 1415, 1420, 1470, 1714–1715
openhands-sdk/openhands/sdk/event/llm_convertible
   message.py67790%67, 89, 111, 129–130, 135, 151
TOTAL36307732880% 

@simonrosenberg

Copy link
Copy Markdown
Member Author

Closed, superseded by #4030

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.

1 participant