Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 44 additions & 17 deletions src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
let p = c.ToPart(options)
where p is not null
select p).ToArray();
if (systemParts.Length > 0)
if (systemParts.Length > 0 || !string.IsNullOrWhiteSpace(options?.Instructions))
{
request.SystemInstruction = new Content(systemParts, Roles.System);
request.SystemInstruction = new Content(systemParts.Concat([new Part { Text = options!.Instructions }]), Roles.System);
}
Comment on lines +36 to 39

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix NRE when options is null; append instructions only when present.

If systemParts.Length > 0 and options is null, options!.Instructions dereferences null. Also avoid appending an empty instruction.

Apply:

-        if (systemParts.Length > 0 || !string.IsNullOrWhiteSpace(options?.Instructions))
-        {
-            request.SystemInstruction = new Content(systemParts.Concat([new Part { Text = options!.Instructions }]), Roles.System);
-        }
+        if (systemParts.Length > 0 || !string.IsNullOrWhiteSpace(options?.Instructions))
+        {
+            IEnumerable<Part> sys = systemParts;
+            if (!string.IsNullOrWhiteSpace(options?.Instructions))
+            {
+                sys = sys.Concat(new[] { new Part { Text = options!.Instructions! } });
+            }
+            request.SystemInstruction = new Content(sys.ToArray(), Roles.System);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (systemParts.Length > 0 || !string.IsNullOrWhiteSpace(options?.Instructions))
{
request.SystemInstruction = new Content(systemParts, Roles.System);
request.SystemInstruction = new Content(systemParts.Concat([new Part { Text = options!.Instructions }]), Roles.System);
}
if (systemParts.Length > 0 || !string.IsNullOrWhiteSpace(options?.Instructions))
{
IEnumerable<Part> sys = systemParts;
if (!string.IsNullOrWhiteSpace(options?.Instructions))
{
sys = sys.Concat(new[] { new Part { Text = options!.Instructions! } });
}
request.SystemInstruction = new Content(sys.ToArray(), Roles.System);
}
🤖 Prompt for AI Agents
In src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs around lines
36–39, the current code dereferences options with options! and always appends
options.Instructions which causes a NullReferenceException when options is null
and can append empty instructions; change the conditional logic to only access
options.Instructions when options is not null and not whitespace, build the
SystemInstruction parts sequence so that you only concatenate an instruction
Part when that check passes (otherwise use systemParts alone), and avoid forcing
a null-forgiving operator.


request.Contents = (from m in chatMessages
Expand All @@ -45,24 +45,51 @@
where p is not null
select p).ToArray(), m.Role == ChatRole.Assistant ? Roles.Model : Roles.User)).ToList();

var functionDeclarations = options?.Tools?.OfType<AIFunction>().Select(f =>
new FunctionDeclaration()
if (options?.Tools is not null)
{
List<FunctionDeclaration>? functionDeclarations = null;
List<Tool>? tools = null;
foreach (var tool in options.Tools)
{
Name = f.Name,
Description = f.Description,
Parameters = ParseFunctionParameters(f.JsonSchema),
switch (tool)
{
case AIFunctionDeclaration f:
(functionDeclarations ??= []).Add(new()
{
Name = f.Name,
Description = f.Description,
Parameters = ParseFunctionParameters(f.JsonSchema),
});
break;

case HostedWebSearchTool ws:
(tools ??= []).Add(new Tool
{
GoogleSearch = new GoogleSearchTool()
});
break;

case HostedCodeInterpreterTool ci:
(tools ??= []).Add(new Tool
{
CodeExecution = new CodeExecutionTool(),
});
break;
}
}
).ToList();

if (functionDeclarations != null && functionDeclarations.Count > 0)
{
request.Tools = new List<Tool>()
if (functionDeclarations is not null)
{
new Tool
(tools ??= []).Add(new Tool
{
FunctionDeclarations = functionDeclarations.ToList()
}
};
});
}

if (tools is not null)
{
request.Tools = tools;
}
}

return request;
Expand Down Expand Up @@ -330,7 +357,7 @@
/// </summary>
/// <param name="response">The <see cref="GenerateContentResponse"/> instance to convert.</param>
/// <returns>A <see cref="ChatResponse"/> object if the transformation is successful; otherwise, null.</returns>
public static ChatResponse? ToChatResponse(this GenerateContentResponse? response, ChatOptions? options = null)

Check warning on line 360 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Parameter 'options' has no matching param tag in the XML comment for 'MicrosoftExtensions.ToChatResponse(GenerateContentResponse?, ChatOptions?)' (but other parameters do)
{
if (response is null) return null;

Expand All @@ -353,7 +380,7 @@
/// </summary>
/// <param name="response">The input <see cref="GenerateContentResponse"/> to transform into a chat response update.</param>
/// <returns>A new <see cref="ChatResponseUpdate"/> object reflecting the data in the provided <see cref="GenerateContentResponse"/>.</returns>
public static ChatResponseUpdate ToChatResponseUpdate(this GenerateContentResponse? response, ChatOptions? options = null)

Check warning on line 383 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Parameter 'options' has no matching param tag in the XML comment for 'MicrosoftExtensions.ToChatResponseUpdate(GenerateContentResponse?, ChatOptions?)' (but other parameters do)
{
#if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(response);
Expand Down Expand Up @@ -423,7 +450,7 @@
/// </summary>
/// <param name="response">The <see cref="GenerateContentResponse"/> to be transformed into a <see cref="ChatMessage"/>.</param>
/// <returns>A <see cref="ChatMessage"/> representing the data contained in the <see cref="GenerateContentResponse"/>.</returns>
private static ChatMessage ToChatMessage(GenerateContentResponse response, ChatOptions? options = null)

Check warning on line 453 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Parameter 'options' has no matching param tag in the XML comment for 'MicrosoftExtensions.ToChatMessage(GenerateContentResponse, ChatOptions?)' (but other parameters do)
{
var generatedContent = response.Candidates?.FirstOrDefault()?.Content;
var contents = generatedContent?.Parts.ToAiContents(options);
Expand All @@ -439,7 +466,7 @@
/// </summary>
/// <param name="contents">The <see cref="Content"/> to be transformed into a <see cref="ChatMessage"/>.</param>
/// <returns>A <see cref="ChatMessage"/> representing the data contained in the <see cref="GenerateContentResponse"/>.</returns>
public static IEnumerable<ChatMessage> ToChatMessages(this List<Content>? contents, ChatOptions? options = null)

Check warning on line 469 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Parameter 'options' has no matching param tag in the XML comment for 'MicrosoftExtensions.ToChatMessages(List<Content>?, ChatOptions?)' (but other parameters do)
{
return (from content in contents
let aiContents = content.Parts.ToAiContents(options)
Expand Down Expand Up @@ -564,11 +591,11 @@
if (objectSchema == null && !string.IsNullOrEmpty(parameterName) && !string.IsNullOrEmpty(functionName) && options?.Tools != null)
{
// Try to get the schema for this object parameter
var function = options.Tools.OfType<AIFunction>().FirstOrDefault(f => f.Name == functionName);
var function = options.Tools.OfType<AIFunctionDeclaration>().FirstOrDefault(f => f.Name == functionName);
if (function?.JsonSchema != null)
{
var schemaNode = JsonSerializer.SerializeToNode(function.JsonSchema);
var pathParts = parameterName.Split('.');

Check warning on line 598 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Dereference of a possibly null reference.
var currentSchema = schemaNode?["properties"];

foreach (var part in pathParts)
Expand Down Expand Up @@ -697,11 +724,11 @@
JsonNode? itemSchema = null;
if (!string.IsNullOrEmpty(parameterName) && !string.IsNullOrEmpty(functionName) && options?.Tools != null)
{
var function = options.Tools.OfType<AIFunction>().FirstOrDefault(f => f.Name == functionName);
var function = options.Tools.OfType<AIFunctionDeclaration>().FirstOrDefault(f => f.Name == functionName);
if (function?.JsonSchema != null)
{
var schemaNode = JsonSerializer.SerializeToNode(function.JsonSchema);
var pathParts = parameterName.Split('.');

Check warning on line 731 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Dereference of a possibly null reference.
var currentSchema = schemaNode?["properties"];

foreach (var part in pathParts)
Expand Down Expand Up @@ -747,7 +774,7 @@
if (!string.IsNullOrEmpty(parameterName) && !string.IsNullOrEmpty(functionName) && options?.Tools != null)
{
// Find the function in the tools
var function = options.Tools.OfType<AIFunction>().FirstOrDefault(f => f.Name == functionName);
var function = options.Tools.OfType<AIFunctionDeclaration>().FirstOrDefault(f => f.Name == functionName);
if (function?.JsonSchema != null)
{
// Parse the schema to check the parameter's format
Expand All @@ -769,7 +796,7 @@
else if (!string.IsNullOrEmpty(parameterName))
{
// For complex objects in arrays, look up the property in the item schema
var pathParts = parameterName.Split('.');

Check warning on line 799 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Dereference of a possibly null reference.
var currentSchema = arrayItemSchema["properties"];

foreach (var part in pathParts)
Expand Down Expand Up @@ -813,7 +840,7 @@
else
{
// Split the parameter name to handle nested properties like "appointment.date" or "events.schedule.startDate"
var pathParts = parameterName.Split('.');

Check warning on line 843 in src/GenerativeAI.Microsoft/Extensions/MicrosoftExtensions.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Dereference of a possibly null reference.
var currentSchema = schemaNode?["properties"];

foreach (var part in pathParts)
Expand Down
2 changes: 1 addition & 1 deletion src/GenerativeAI.Microsoft/GenerativeAI.Microsoft.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<ProjectReference Include="..\GenerativeAI\GenerativeAI.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.8.0" />
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="9.9.0" />
</ItemGroup>

</Project>
Loading