Querying Child Agent Workflows ๐Ÿ”

๐Ÿ”„ Advanced Feature

Monitor and interact with ADK agent workflows that are spawned as child workflows from your main orchestration workflows. Get real-time insights into agent conversations, execution state, and decision-making processes.

Overview ๐ŸŽฏ

When you include ADK agent nodes in your Graph Compose workflows, they execute as child workflows with their own lifecycle, state, and query capabilities. This architecture provides:

  • Isolation: Each agent runs independently with its own session and conversation history
  • Monitoring: Full visibility into agent decision-making and tool usage
  • Control: Ability to send signals and confirmations to running agents
  • Durability: Agent state persists across workflow restarts and replays
graph TD A["Parent Workflow<br/>httpWorkflow"] --> B["ADK Child Workflow<br/>adk-workflow-parentId-nodeId"] A --> C["Iterator Child Workflow<br/>parentId-row-index"] B --> D["ADK Queries Available:<br/>โ€ข get_latest_orchestration_result<br/>โ€ข get_session_events<br/>โ€ข get_pending_confirmation_details<br/>โ€ข is_waiting_for_confirmation<br/>โ€ข get_latest_invocation_trace"] B --> E["ADK Signals Available:<br/>โ€ข confirm_action<br/>โ€ข end_conversation<br/>โ€ข receive_message"] F["API Routes"] --> G["Direct Child Query<br/>/workflows/:parentId/children/:childWorkflowId/queries/:queryName"] F --> H["ADK Convenience Query<br/>/workflows/:parentId/adk/:nodeId/queries/:queryName"] G --> I["ChildWorkflowService.queryChildWorkflow"] H --> J["ChildWorkflowService.queryAdkChildWorkflow"] I --> K["Temporal Client<br/>handle.query(queryName)"] J --> K K --> L["ADK Agent Workflow<br/>Python Implementation"] style A fill:#e1f5fe style B fill:#f3e5f5 style C fill:#f3e5f5 style D fill:#e8f5e8 style E fill:#fff3e0 style L fill:#fce4ec

Child Workflow Architecture ๐Ÿ—๏ธ

Workflow ID Generation

Child ADK workflows follow a predictable naming pattern:

  • ADK Child Workflow: adk-workflow-{parentWorkflowId}-{nodeId}
  • Iterator Child Workflow: {parentWorkflowId}-row-{index}

This systematic approach allows for easy identification and querying of child workflows.

Available Queries ๐Ÿ“Š

ADK child workflows expose five key queries for monitoring:

Query NameDescriptionReturns
get_latest_orchestration_resultLatest agent turn result with final response and execution metadataFinal response text, session state, exit flow status
get_session_eventsComplete conversation history between user and agentAll messages, tool calls, timestamps, and authors
get_pending_confirmation_detailsDetails about pending Human-in-the-Loop confirmation requestsConfirmation details, request ID, action context
is_waiting_for_confirmationBoolean status indicating if agent is paused for human confirmationtrue/false boolean value
get_latest_invocation_traceDetailed execution trace with workflow metadata and statusWorkflow metadata, iteration counts, termination status

API Routes ๐Ÿ›ฃ๏ธ

Graph Compose provides two approaches for querying child workflows:

1. Direct Child Workflow Queries

Use when you know the exact child workflow ID:

# Query any child workflow directly
GET /api/v1/workflows/{parentId}/children/{childWorkflowId}/queries/{queryName}

# Example: Get conversation history
curl -X GET \
  "https://api.graphcompose.io/api/v1/workflows/parent-123/children/adk-workflow-parent-123-agent-node/queries/get_session_events" \
  -H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"

2. ADK Convenience Queries

Use when you know the parent workflow ID and node ID (recommended):

# Query ADK child workflow by node ID
GET /api/v1/workflows/{parentId}/adk/{nodeId}/queries/{queryName}

# Example: Get latest orchestration result
curl -X GET \
  "https://api.graphcompose.io/api/v1/workflows/parent-123/adk/weather-agent/queries/get_latest_orchestration_result" \
  -H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"

Complete ADK State Query ๐Ÿ“‹

For comprehensive monitoring, use the dedicated ADK state endpoint:

# Get all ADK workflow state at once
GET /api/v1/workflows/{parentId}/adk/{nodeId}/state

curl -X GET \
  "https://api.graphcompose.io/api/v1/workflows/parent-123/adk/weather-agent/state" \
  -H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"

Query Examples by Use Case ๐ŸŽฏ

Monitoring Agent Progress

# Check if agent is still processing
curl -X GET \
  "https://api.graphcompose.io/api/v1/workflows/parent-123/adk/research-agent/queries/get_latest_invocation_trace" \
  -H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"

# Look for workflow_metadata.conversation_end_requested: false

Human-in-the-Loop Monitoring

# See if agent needs human approval
curl -X GET \
  "https://api.graphcompose.io/api/v1/workflows/parent-123/adk/approval-agent/queries/is_waiting_for_confirmation" \
  -H "Authorization: Bearer $GRAPH_COMPOSE_TOKEN"

Error Handling ๐Ÿšจ

Child workflow queries can fail for several reasons:

// Child workflow not found
{
  "success": false,
  "message": "Failed to query child workflow: Workflow not found",
  "data": null
}

// Invalid query name
{
  "success": false,
  "message": "Invalid ADK query name: invalid_query. Must be one of: get_latest_orchestration_result, get_session_events, get_pending_confirmation_details, is_waiting_for_confirmation, get_latest_invocation_trace",
  "data": null
}

// Workflow access denied
{
  "success": false,
  "message": "Workflow access denied",
  "data": null
}

Integration Patterns ๐Ÿ”„

Polling for Agent Completion

async function waitForAdkWorkflowCompletion(workflowId: string) {
  const maxAttempts = 30;
  const pollInterval = 2000; // 2 seconds - matches Chat UI default
  
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    try {
      // Use the ADK-specific state endpoint (matches Chat UI implementation)
      const response = await fetch(
        `/api/v1/workflows/agent/${workflowId}/state`,
        {
          headers: {
            'Authorization': `Bearer ${process.env.GRAPH_COMPOSE_TOKEN}`
          }
        }
      );
      
      const data = await response.json();
      
      if (data.success) {
        const state = data.data;
        
        // Check if workflow is stopped or agent completed
        if (state.isStopped || state.latestOrchestrationResult?.exit_flow) {
          console.log('ADK workflow completed');
          return {
            finalResponse: state.latestOrchestrationResult?.final_response_text,
            sessionState: state.latestOrchestrationResult?.session_state,
            conversationHistory: state.conversationHistory
          };
        }
        
        // Check if waiting for HITL confirmation
        if (state.pendingConfirmation?.isWaiting) {
          console.log('Workflow paused for human confirmation');
          return {
            status: 'pending_confirmation',
            confirmationDetails: state.pendingConfirmation.details
          };
        }
      }
      
      await new Promise(resolve => setTimeout(resolve, pollInterval));
    } catch (error) {
      console.log(`Polling attempt ${attempt + 1} failed, retrying...`);
      await new Promise(resolve => setTimeout(resolve, pollInterval));
    }
  }
  
  throw new Error('ADK workflow did not complete within timeout period');
}

Real-time Conversation Monitoring

Here's how to monitor agent conversations in real-time:

async function monitorAdkConversation(workflowId: string) {
  let lastEventCount = 0;
  
  const checkForNewEvents = async () => {
    try {
      const response = await fetch(
        `/api/v1/workflows/agent/${workflowId}/conversation`,
        {
          headers: {
            'Authorization': `Bearer ${process.env.GRAPH_COMPOSE_TOKEN}`
          }
        }
      );
      
      if (!response.ok) {
        throw new Error(`Failed to fetch conversation: ${response.statusText}`);
      }
      
      const data = await response.json();
      const events = data.conversation_history || [];
      
      // Check for new events
      if (events.length > lastEventCount) {
        const newEvents = events.slice(lastEventCount);
        newEvents.forEach(event => {
          console.log(`[${event.role}]: ${event.content?.parts?.[0]?.text || 'No text content'}`);
        });
        lastEventCount = events.length;
      }
      
      // Check if agent is waiting for input or confirmation
      if (data.has_pending_confirmation) {
        console.log('๐Ÿคš Agent is waiting for human confirmation');
      }
      
    } catch (error) {
      console.error('Failed to check for new events:', error);
    }
  };
  
  // Poll every 2 seconds for new conversation events
  const intervalId = setInterval(checkForNewEvents, 2000);
  
  // Return cleanup function
  return () => clearInterval(intervalId);
}

// Usage
const stopMonitoring = monitorAdkConversation('your-workflow-id');

// Stop monitoring when done
// stopMonitoring();

Security & Authentication ๐Ÿ”’

All child workflow queries require proper authentication and respect the same access controls as parent workflows:

  • Bearer Token: Use your Graph Compose API token
  • Ownership Verification: Only users who own the parent workflow can query its children
  • Organization Isolation: Child workflows are isolated by organization

Next Steps ๐Ÿš€