@@ -649,6 +649,7 @@ private void completeOrchestratorTaskWithChunking(OrchestratorResponse response)
649649 int chunkIndex = 0 ;
650650 boolean isPartial = true ;
651651 boolean isChunkedMode = false ;
652+ boolean hasTraceContext = response .hasOrchestrationTraceContext ();
652653
653654 while (isPartial ) {
654655 OrchestratorResponse .Builder chunk = OrchestratorResponse .newBuilder ()
@@ -657,15 +658,23 @@ private void completeOrchestratorTaskWithChunking(OrchestratorResponse response)
657658 .setCompletionToken (response .getCompletionToken ())
658659 .setRequiresHistory (response .getRequiresHistory ());
659660
660- int chunkPayloadSize = 0 ;
661661 while (actionsCompleted < allActions .size ()) {
662- int actionSize = allActions .get (actionsCompleted ).getSerializedSize ();
662+ OrchestratorAction nextAction = allActions .get (actionsCompleted );
663+
664+ chunk .addActions (nextAction );
665+
666+ int estimatedSize = estimateChunkSerializedSize (
667+ chunk ,
668+ chunkIndex ,
669+ hasTraceContext ,
670+ response .getOrchestrationTraceContext ());
671+
663672 // Always accept the first action in an empty chunk to avoid infinite loops
664- if (chunkPayloadSize + actionSize > maxChunkBytes && chunkPayloadSize > 0 ) {
673+ if (estimatedSize > maxChunkBytes && chunk .getActionsCount () > 1 ) {
674+ chunk .removeActions (chunk .getActionsCount () - 1 );
665675 break ;
666676 }
667- chunk .addActions (allActions .get (actionsCompleted ));
668- chunkPayloadSize += actionSize ;
677+
669678 actionsCompleted ++;
670679 }
671680
@@ -696,6 +705,32 @@ private void completeOrchestratorTaskWithChunking(OrchestratorResponse response)
696705 }
697706 }
698707
708+ /**
709+ * Estimates the serialized size of a candidate chunk including envelope overhead fields
710+ * that may be added later in the chunking flow.
711+ */
712+ private static int estimateChunkSerializedSize (
713+ OrchestratorResponse .Builder chunk ,
714+ int chunkIndex ,
715+ boolean hasTraceContext ,
716+ OrchestrationTraceContext traceContext ) {
717+ OrchestratorResponse .Builder estimate = chunk .clone ();
718+
719+ // Include potential overhead fields to avoid under-estimating chunk size.
720+ estimate .setIsPartial (true );
721+ estimate .setChunkIndex (Int32Value .of (chunkIndex ));
722+
723+ if (chunkIndex == 0 ) {
724+ if (hasTraceContext ) {
725+ estimate .setOrchestrationTraceContext (traceContext );
726+ }
727+ } else {
728+ estimate .setNumEventsProcessed (Int32Value .of (0 ));
729+ }
730+
731+ return estimate .build ().getSerializedSize ();
732+ }
733+
699734 static WorkItemFilters toProtoWorkItemFilters (WorkItemFilter filter ) {
700735 WorkItemFilters .Builder builder = WorkItemFilters .newBuilder ();
701736 for (WorkItemFilter .OrchestrationFilter orch : filter .getOrchestrations ()) {
0 commit comments