feat(agent): support structured output in streamEvents - #2919
Open
Letter2025 wants to merge 1 commit into
Open
Conversation
Add fine-grained structured-output overloads to the v2 streaming API so callers can stream validated structured JSON without depending on the deprecated coarse-grained stream(...) methods. - ReActAgent.streamEvents(List, Class, RuntimeContext) - ReActAgent.streamEvents(List, JsonNode, RuntimeContext) - HarnessAgent mirrors both overloads with sandbox-lifecycle semantics Both reuse the existing buildAgentStream core with doCall(m, schema/class), so the native response_format path and the synthetic generate_response fallback behave identically to call(msgs, schema/class, ctx). The final AgentResultEvent carries the validated structured Msg (hasStructuredData() == true) plus aggregated token usage. Closes agentscope-ai#1717
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The fine-grained streaming API (
ReActAgent#streamEvents(...)) — the recommended replacement for the deprecated coarse-grainedstream(...)— has no structured-output overloads. Onlycall(msgs, schema/class, ctx)(non-streaming) and the deprecatedstream(msgs, options, schema/class, ctx)supportoutputSchema.buildAgentStream(...)is private, so downstream code cannot inject a schema variant ofstreamEventswithout forking the framework or relying on the deprecated API (which returns the legacyio.agentscope.core.agent.Eventinstead of the fine-grainedio.agentscope.core.event.AgentEvent).Closes #1717.
Change
Add the missing fine-grained overloads, reusing the existing
buildAgentStreamcore so streaming and blocking calls share identical lifecycle / middleware / hook semantics:ReActAgent#streamEvents(List<Msg>, Class<?>, RuntimeContext)ReActAgent#streamEvents(List<Msg>, JsonNode, RuntimeContext)HarnessAgent#streamEvents(List<Msg>, Class<?>, RuntimeContext)HarnessAgent#streamEvents(List<Msg>, JsonNode, RuntimeContext)Each overload simply routes
m -> doCall(m, schema/class)throughbuildAgentStream, exactly mirroringcall(msgs, schema/class, ctx)→callInternal(msgs, ctx, m -> doCall(m, schema/class)). This means:response_format(strictjson_schema) is preferred whensupportsNativeStructuredOutput()is true; the JSON text surfaces asTextBlockDeltaEvents.generate_responsetool is injected and itsToolCallStartEvent/ToolCallDeltaEvent/ tool-result events surface in the stream.AgentResultEventcarries aMsgwithhasStructuredData() == trueplus aggregated tokenusage, semantically identical to the blockingcall(...)result.Tests
ReActAgentStreamEventsStructuredOutputTest(core): class/JsonNode overloads, fallback tool events + final structured result + usage, nativeTextBlockDeltaEventJSON deltas, and semantic equivalence withcall(...).HarnessAgentStructuredOutputStreamEventsTest(harness): both overloads delegate structured output through the harness sandbox-lifecycle wrapper.Notes
stream(...)API; those overloads remain as-is.streamEventsis intentionally left for a follow-up (see HarnessAgent和ReActAgent 中streamEvent 为什么不放在Agent接口层 #1894); this PR only adds the concreteReActAgent/HarnessAgentoverloads requested in 2.0版本streamEvents增加结构化输出参数 #1717.