Repository: google/adk-go
File: agent/remoteagent/utils.go (Go)

Code before:
		return nil
	}
	candidate := events.At(index)
	if candidate.Author != "user" {
		return nil
	}
	fnCallID, ok := getFunctionResponseCallID(candidate)
	if !ok {
		return nil
	}
	for i := index - 1; i >= 0; i-- {
		event := events.At(i)
		if !isFunctionCallEvent(event, fnCallID) {
			continue
		}
		result := &userFunctionCall{event: candidate}
		tid, ctxID := adka2a.GetA2ATaskInfo(event)
		result.taskID = tid
		result.contextID = ctxID
		return result
	}
	return nil
}

func isFunctionCallEvent(event *session.Event, callID string) bool {
	if event.Content == nil {
		return false
	}
	return slices.ContainsFunc(event.Content.Parts, func(part *genai.Part) bool {
		return part.FunctionCall != nil && part.FunctionCall.ID == callID
	})
}

// getFunctionResponseCallID finds the first part with non-nil FunctionResponse and returns the call ID.
func getFunctionResponseCallID(event *session.Event) (string, bool) {
	if event.Content == nil {
		return "", false
	}
	responsePartIndex := slices.IndexFunc(event.Content.Parts, func(part *genai.Part) bool {
		return part.FunctionResponse != nil
	})
	if responsePartIndex < 0 {
		return "", false
	}
	return event.Content.Parts[responsePartIndex].FunctionResponse.ID, true
}

// toMissingRemoteSessionParts returns content parts for all events we think are not present in the remote session
// and a2a contextID if it was found in a remote agent event metadata.
// We iterate session events backward until all events are processed or an event authored by a remote agent is found.
// Parts from all events we processed are returned as a single list.

Review comment (suggestion):
Does it make sense to handle event == nil?

I don't expect the external code would return nil event for any reason, still this may make code more robust.

Code after:
		return nil
	}
	candidate := events.At(index)
	if candidate.Author != "user" {
		return nil
	}
	fnCallID, ok := getFunctionResponseCallID(candidate)
	if !ok {
		return nil
	}
	for i := index - 1; i >= 0; i-- {
		event := events.At(i)
		if !isFunctionCallEvent(event, fnCallID) {
			continue
		}
		result := &userFunctionCall{event: candidate}
		tid, ctxID := adka2a.GetA2ATaskInfo(event)
		result.taskID = tid
		result.contextID = ctxID
		return result
	}
	return nil
}

func isFunctionCallEvent(event *session.Event, callID string) bool {
	if event == nil || event.Content == nil {
		return false
	}
	return slices.ContainsFunc(event.Content.Parts, func(part *genai.Part) bool {
		return part.FunctionCall != nil && part.FunctionCall.ID == callID
	})
}

// getFunctionResponseCallID finds the first part with non-nil FunctionResponse and returns the call ID.
func getFunctionResponseCallID(event *session.Event) (string, bool) {
	if event.Content == nil {
		return "", false
	}
	responsePartIndex := slices.IndexFunc(event.Content.Parts, func(part *genai.Part) bool {
		return part.FunctionResponse != nil
	})
	if responsePartIndex < 0 {
		return "", false
	}
	return event.Content.Parts[responsePartIndex].FunctionResponse.ID, true
}

// toMissingRemoteSessionParts returns content parts for all events we think are not present in the remote session
// and a2a contextID if it was found in a remote agent event metadata.
// We iterate session events backward until all events are processed or an event authored by a remote agent is found.
// Parts from all events we processed are returned as a single list.