Skip to content

Commit 2b95aa3

Browse files
committed
Add optional user location information to GrokSearchTool
This allows customizing the scope of the web search.
1 parent 95a85dc commit 2b95aa3

4 files changed

Lines changed: 105 additions & 0 deletions

File tree

src/xAI.Tests/ChatClientTests.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,32 @@ public async Task GrokInvokesHostedSearchTool()
173173
Assert.Contains(urls, x => x.PathAndQuery.Contains("/TSLA"));
174174
}
175175

176+
[SecretsFact("XAI_API_KEY")]
177+
public async Task GrokInvokesHostedSearchWithCity()
178+
{
179+
var messages = new Chat()
180+
{
181+
{ "system", "You are an assistant that uses web search to respond" },
182+
{ "user", "Que se puede hacer en el verano por la zona? Lo mas popular?" },
183+
};
184+
185+
var grok = new GrokClient(Configuration["XAI_API_KEY"]!).AsIChatClient("grok-4-fast");
186+
187+
var options = new GrokChatOptions
188+
{
189+
Include = [IncludeOption.WebSearchCallOutput],
190+
Tools = [new GrokSearchTool {
191+
Country = "AR",
192+
City = "Concepcion del Uruguay"
193+
}]
194+
};
195+
196+
var response = await grok.GetResponseAsync(messages, options);
197+
var text = response.Text;
198+
199+
Assert.Contains("termas", text, StringComparison.OrdinalIgnoreCase);
200+
}
201+
176202
[SecretsFact("XAI_API_KEY")]
177203
public async Task GrokInvokesGrokSearchToolIncludesDomain()
178204
{

src/xAI.Tests/GrokConversionTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,57 @@ public void AsTool_WithWebSearch_ImageUnderstanding()
7474
Assert.True(tool.WebSearch.EnableImageUnderstanding);
7575
}
7676

77+
[Fact]
78+
public void AsTool_WithWebSearch_UserLocation()
79+
{
80+
var webSearch = new GrokSearchTool
81+
{
82+
Country = "US",
83+
Region = "California",
84+
City = "San Francisco",
85+
Timezone = "America/Los_Angeles"
86+
};
87+
88+
var tool = webSearch.AsProtocolTool();
89+
90+
Assert.NotNull(tool?.WebSearch);
91+
Assert.NotNull(tool.WebSearch.UserLocation);
92+
Assert.Equal("US", tool.WebSearch.UserLocation.Country);
93+
Assert.Equal("California", tool.WebSearch.UserLocation.Region);
94+
Assert.Equal("San Francisco", tool.WebSearch.UserLocation.City);
95+
Assert.Equal("America/Los_Angeles", tool.WebSearch.UserLocation.Timezone);
96+
}
97+
98+
[Fact]
99+
public void AsTool_WithWebSearch_UserLocation_PartialFields()
100+
{
101+
var webSearch = new GrokSearchTool
102+
{
103+
Country = "DE",
104+
City = "Berlin"
105+
};
106+
107+
var tool = webSearch.AsProtocolTool();
108+
109+
Assert.NotNull(tool?.WebSearch);
110+
Assert.NotNull(tool.WebSearch.UserLocation);
111+
Assert.Equal("DE", tool.WebSearch.UserLocation.Country);
112+
Assert.Equal("Berlin", tool.WebSearch.UserLocation.City);
113+
Assert.Empty(tool.WebSearch.UserLocation.Region);
114+
Assert.Empty(tool.WebSearch.UserLocation.Timezone);
115+
}
116+
117+
[Fact]
118+
public void AsTool_WithWebSearch_NoUserLocation()
119+
{
120+
var webSearch = new GrokSearchTool();
121+
122+
var tool = webSearch.AsProtocolTool();
123+
124+
Assert.NotNull(tool?.WebSearch);
125+
Assert.Null(tool.WebSearch.UserLocation);
126+
}
127+
77128
[Fact]
78129
public void AsTool_WithXSearch_ThrowsIfAllowedAndExcluded()
79130
{

src/xAI/GrokProtocolExtensions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,22 @@ public static partial class GrokProtocolExtensions
7575
EnableImageUnderstanding = grokSearch.EnableImageUnderstanding,
7676
};
7777

78+
if (grokSearch.Country is not null ||
79+
grokSearch.Region is not null ||
80+
grokSearch.City is not null ||
81+
grokSearch.Timezone is not null)
82+
{
83+
websearch.UserLocation = new WebSearchUserLocation();
84+
if (grokSearch.Country is not null)
85+
websearch.UserLocation.Country = grokSearch.Country;
86+
if (grokSearch.Region is not null)
87+
websearch.UserLocation.Region = grokSearch.Region;
88+
if (grokSearch.City is not null)
89+
websearch.UserLocation.City = grokSearch.City;
90+
if (grokSearch.Timezone is not null)
91+
websearch.UserLocation.Timezone = grokSearch.Timezone;
92+
}
93+
7894
if (grokSearch.AllowedDomains is { Count: > 0 } &&
7995
grokSearch.ExcludedDomains is { Count: > 0 })
8096
throw new NotSupportedException($"Cannot use {nameof(GrokSearchTool.AllowedDomains)} and {nameof(GrokSearchTool.ExcludedDomains)} together in the same request.");

src/xAI/GrokSearchTool.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,16 @@ public class GrokSearchTool : HostedWebSearchTool
2020

2121
/// <summary>See https://docs.x.ai/docs/guides/tools/search-tools#enable-image-understanding</summary>
2222
public bool EnableImageUnderstanding { get; set; }
23+
24+
/// <summary>Sets the user's country for web search results, using the ISO alpha-2 code.</summary>
25+
public string? Country { get; set; }
26+
27+
/// <summary>Additional free text information about the region to be used in the search.</summary>
28+
public string? Region { get; set; }
29+
30+
/// <summary>Additional free text information about the city to be used in the search.</summary>
31+
public string? City { get; set; }
32+
33+
/// <summary>IANA timezone name to be used in the search.</summary>
34+
public string? Timezone { get; set; }
2335
}

0 commit comments

Comments
 (0)