From 61a18aa427ce87d33db61344ea1a57fdf9281903 Mon Sep 17 00:00:00 2001 From: zhaohaha <406123980@qq.com> Date: Tue, 7 Jul 2026 21:39:28 +0800 Subject: [PATCH] feat(agui): propagate userId from forwardedProps to RuntimeContext --- .../core/agui/adapter/AguiAgentAdapter.java | 3 + .../agui/adapter/AguiAgentAdapterTest.java | 107 ++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java b/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java index ba3aa2b2cc..26d4430215 100644 --- a/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java +++ b/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/main/java/io/agentscope/core/agui/adapter/AguiAgentAdapter.java @@ -79,6 +79,7 @@ public class AguiAgentAdapter { public static final String RUNTIME_CONTEXT_CONTEXT_KEY = "agui.context"; public static final String RUNTIME_CONTEXT_STATE_KEY = "agui.state"; public static final String RUNTIME_CONTEXT_FORWARDED_PROPS_KEY = "agui.forwardedProps"; + public static final String FORWARDED_PROP_USER_ID_KEY = "userId"; private final Agent agent; private final AguiAdapterConfig config; @@ -160,8 +161,10 @@ public Flux run(RunAgentInput input) { } private RuntimeContext buildRuntimeContext(RunAgentInput input) { + Object userId = input.getForwardedProp(FORWARDED_PROP_USER_ID_KEY); return RuntimeContext.builder() .sessionId(input.getThreadId()) + .userId(userId == null ? null : userId.toString()) .put(RunAgentInput.class, input) .put(RUNTIME_CONTEXT_THREAD_ID_KEY, input.getThreadId()) .put(RUNTIME_CONTEXT_RUN_ID_KEY, input.getRunId()) diff --git a/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java b/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java index 2d96f21ffb..387891bdc8 100644 --- a/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java +++ b/agentscope-extensions/agentscope-extensions-protocol/agentscope-extensions-agui/src/test/java/io/agentscope/core/agui/adapter/AguiAgentAdapterTest.java @@ -70,6 +70,113 @@ void setUp() { adapter = new AguiAgentAdapter(mockAgent, AguiAdapterConfig.defaultConfig()); } + @Test + void testRunSetsUserIdFromForwardedPropsIntoRuntimeContext() { + ArgumentCaptor contextCaptor = + ArgumentCaptor.forClass(RuntimeContext.class); + when(mockAgent.stream(anyList(), any(StreamOptions.class), contextCaptor.capture())) + .thenReturn(Flux.empty()); + + RunAgentInput input = + RunAgentInput.builder() + .threadId("thread-user") + .runId("run-user") + .messages(List.of(AguiMessage.userMessage("msg-1", "Hello"))) + .forwardedProps( + Map.of(AguiAgentAdapter.FORWARDED_PROP_USER_ID_KEY, "user-123")) + .build(); + + adapter.run(input).collectList().block(); + + RuntimeContext context = contextCaptor.getValue(); + assertEquals("user-123", context.getUserId()); + assertSame(input.getForwardedProps(), context.get("agui.forwardedProps")); + } + + @Test + void testRunConvertsNonStringUserIdFromForwardedProps() { + ArgumentCaptor contextCaptor = + ArgumentCaptor.forClass(RuntimeContext.class); + when(mockAgent.stream(anyList(), any(StreamOptions.class), contextCaptor.capture())) + .thenReturn(Flux.empty()); + + RunAgentInput input = + RunAgentInput.builder() + .threadId("thread-user-long") + .runId("run-user-long") + .messages(List.of(AguiMessage.userMessage("msg-1", "Hello"))) + .forwardedProps(Map.of(AguiAgentAdapter.FORWARDED_PROP_USER_ID_KEY, 12345L)) + .build(); + + adapter.run(input).collectList().block(); + + RuntimeContext context = contextCaptor.getValue(); + assertEquals("12345", context.getUserId()); + } + + @Test + void testRunKeepsUserIdNullWhenForwardedPropsMissingUserId() { + ArgumentCaptor contextCaptor = + ArgumentCaptor.forClass(RuntimeContext.class); + when(mockAgent.stream(anyList(), any(StreamOptions.class), contextCaptor.capture())) + .thenReturn(Flux.empty()); + + RunAgentInput input = + RunAgentInput.builder() + .threadId("thread-no-user") + .runId("run-no-user") + .messages(List.of(AguiMessage.userMessage("msg-1", "Hello"))) + .forwardedProps(Map.of("tenant", "demo")) + .build(); + + adapter.run(input).collectList().block(); + + RuntimeContext context = contextCaptor.getValue(); + assertNull(context.getUserId()); + } + + @Test + void testRunKeepsBlankUserIdFromForwardedProps() { + ArgumentCaptor contextCaptor = + ArgumentCaptor.forClass(RuntimeContext.class); + when(mockAgent.stream(anyList(), any(StreamOptions.class), contextCaptor.capture())) + .thenReturn(Flux.empty()); + + RunAgentInput input = + RunAgentInput.builder() + .threadId("thread-blank-user") + .runId("run-blank-user") + .messages(List.of(AguiMessage.userMessage("msg-1", "Hello"))) + .forwardedProps(Map.of(AguiAgentAdapter.FORWARDED_PROP_USER_ID_KEY, " ")) + .build(); + + adapter.run(input).collectList().block(); + + RuntimeContext context = contextCaptor.getValue(); + assertEquals(" ", context.getUserId()); + } + + @Test + void testRunKeepsEmptyUserIdFromForwardedProps() { + ArgumentCaptor contextCaptor = + ArgumentCaptor.forClass(RuntimeContext.class); + when(mockAgent.stream(anyList(), any(StreamOptions.class), contextCaptor.capture())) + .thenReturn(Flux.empty()); + + RunAgentInput input = + RunAgentInput.builder() + .threadId("thread-empty-user") + .runId("run-empty-user") + .messages(List.of(AguiMessage.userMessage("msg-1", "Hello"))) + .forwardedProps(Map.of(AguiAgentAdapter.FORWARDED_PROP_USER_ID_KEY, "")) + .build(); + + adapter.run(input).collectList().block(); + + RuntimeContext context = contextCaptor.getValue(); + assertEquals("", context.getUserId()); + } + @Test void testRunInjectsRunInputIntoRuntimeContext() { ArgumentCaptor contextCaptor =