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..ed11481c97 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; @@ -162,6 +163,7 @@ public Flux run(RunAgentInput input) { private RuntimeContext buildRuntimeContext(RunAgentInput input) { return RuntimeContext.builder() .sessionId(input.getThreadId()) + .userId(normalizeUserId(input.getForwardedProp(FORWARDED_PROP_USER_ID_KEY))) .put(RunAgentInput.class, input) .put(RUNTIME_CONTEXT_THREAD_ID_KEY, input.getThreadId()) .put(RUNTIME_CONTEXT_RUN_ID_KEY, input.getRunId()) @@ -173,6 +175,18 @@ private RuntimeContext buildRuntimeContext(RunAgentInput input) { .build(); } + private static String normalizeUserId(Object value) { + if (value == null) { + return null; + } + String userId = value.toString(); + if (userId == null) { + return null; + } + userId = userId.trim(); + return userId.isEmpty() ? null : userId; + } + private ToolInjection injectFrontendTools(RunAgentInput input) { if (!input.hasTools()) { return ToolInjection.empty(); 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..431aa1099b 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,71 @@ 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 testRunInjectsRunInputIntoRuntimeContext() { ArgumentCaptor contextCaptor =