Added tool calling support (#731)

Co-authored-by: krut_ni <nils.kruthoff@dlr.de>
Co-authored-by: Thorsten Sommer <SommerEngineering@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-09-04 15:48:07 +02:00
1 parent b00c3f9ab3
commit 4d8d30e15e
266 files changed
+11186 -740

No files matched your search

@@ -11,9 +11,27 @@
</MudAvatar>
</CardHeaderAvatar>
<CardHeaderContent>
<MudText Typo="Typo.body1">
@this.Role.ToName() (@this.Time.LocalDateTime)
</MudText>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudText Typo="Typo.body1">
@this.Role.ToName() (@this.Time.LocalDateTime)
</MudText>
@if (this.HasToolTrace)
{
<MudTooltip Text="@this.GetToolTraceTooltip()" Placement="Placement.Bottom">
<MudButton Variant="Variant.Outlined"
Color="Color.Default"
Size="Size.Small"
Class="px-2 py-1 rounded-pill"
Style="min-width:auto; border-width:1px; text-transform:none;"
OnClick="@this.ToggleToolTrace">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
<MudIcon Icon="@Icons.Material.Filled.Build" Color="Color.Default" Size="Size.Small" />
<MudIcon Icon="@(this.showToolTrace ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)" Size="Size.Small" />
</MudStack>
</MudButton>
</MudTooltip>
}
</MudStack>
</CardHeaderContent>
<CardHeaderActions>
<div class="d-flex align-center">
@@ -100,42 +118,121 @@
case ContentType.TEXT:
if (this.Content is ContentText textContent)
{
@*
The tool trace and the running-tool status stand outside the waiting and
streaming branches on purpose. While the model works through its tool
calls, nothing has been streamed yet, so those branches show a skeleton
or nothing at all — and that is exactly when the user wants to watch
what the tools are doing.
*@
@if (this.HasToolTrace && this.showToolTrace)
{
<MudPaper Class="pa-3 mb-3 border rounded-lg" Style="border-width:1px;">
<MudText Typo="Typo.subtitle2" Class="mb-2">
@string.Format(T("Tool Calls ({0})"), textContent.ToolInvocations.Count)
</MudText>
@foreach (var invocation in textContent.ToolInvocations.OrderBy(x => x.Order))
{
<MudPaper Class="pa-3 mb-3 border rounded-lg" Style="border-width:1px;">
<MudButton Variant="Variant.Text"
Color="Color.Default"
FullWidth="@true"
Class="px-0 py-0 justify-space-between"
Style="min-width:auto; text-transform:none;"
OnClick="@(() => this.ToggleToolInvocation(invocation.Order))">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Class="w-100">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudIcon Icon="@invocation.ToolIcon" Color="Color.Info" />
<MudText Typo="Typo.subtitle1">@($"{invocation.Order}. {invocation.ToolName}")</MudText>
<MudChip T="string" Color="@ContentBlockComponent.GetTraceColor(invocation.Status)" Size="Size.Small" Variant="Variant.Outlined">
@this.GetTraceStatusText(invocation)
</MudChip>
</MudStack>
<MudIcon Icon="@(this.IsToolInvocationExpanded(invocation.Order) ? Icons.Material.Filled.ExpandLess : Icons.Material.Filled.ExpandMore)" Size="Size.Small" />
</MudStack>
</MudButton>
@if (this.IsToolInvocationExpanded(invocation.Order))
{
@if (!string.IsNullOrWhiteSpace(invocation.StatusMessage))
{
<MudText Typo="Typo.body2" Color="Color.Warning" Class="mt-3 mb-3">@invocation.StatusMessage</MudText>
}
<MudText Typo="Typo.subtitle2">@T("Arguments")</MudText>
@if (invocation.Arguments.Count == 0)
{
<MudText Typo="Typo.body2" Class="mb-3">@T("No arguments")</MudText>
}
else
{
<MudList T="string" Dense="@true" Class="mb-0">
@foreach (var argument in invocation.Arguments)
{
<MudListItem T="string">
<MudText Typo="Typo.body2"><strong>@argument.Key:</strong> @argument.Value</MudText>
</MudListItem>
}
</MudList>
}
<MudText Typo="Typo.subtitle2" Class="mt-3">@T("Result")</MudText>
<MudPaper Class="pa-3 mt-2 mb-3">
@if (invocation.JsonResult is not null)
{
<JsonTreeView Value="@invocation.JsonResult" />
}
else
{
<MudText Typo="Typo.body2" Style="white-space: pre-wrap; overflow-wrap: anywhere;">@this.GetToolInvocationResult(invocation)</MudText>
}
</MudPaper>
}
</MudPaper>
}
</MudPaper>
}
if (textContent.InitialRemoteWait)
{
<MudSkeleton Width="30%" Height="42px;"/>
<MudSkeleton Width="80%"/>
<MudSkeleton Width="100%"/>
}
else if (this.Content.IsStreaming)
{
<MudText Typo="Typo.body1" Style="white-space: pre-wrap;">
@textContent.Text.RemoveThinkTags()
</MudText>
}
else
{
@if (this.Content.IsStreaming)
{
<MudText Typo="Typo.body1" Style="white-space: pre-wrap;">
@textContent.Text.RemoveThinkTags()
</MudText>
}
else
{
var renderPlan = this.GetMarkdownRenderPlan(textContent.Text);
<div @ref="this.mathContentContainer" class="chat-math-container">
@foreach (var segment in renderPlan.Segments)
var renderPlan = this.GetMarkdownRenderPlan(textContent.Text);
<div @ref="this.mathContentContainer" class="chat-math-container">
@foreach (var segment in renderPlan.Segments)
{
var segmentContent = segment.GetContent(renderPlan.Source);
if (segment.Type is MarkdownRenderSegmentType.MARKDOWN)
{
var segmentContent = segment.GetContent(renderPlan.Source);
if (segment.Type is MarkdownRenderSegmentType.MARKDOWN)
{
<MudMarkdown @key="@segment.RenderKey" Value="@segmentContent" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.CHAT_MARKDOWN_PIPELINE" />
}
else
{
<MathJaxBlock @key="@segment.RenderKey" Value="@segmentContent" Class="mb-5" />
}
<MudMarkdown @key="@segment.RenderKey" Value="@segmentContent" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.CHAT_MARKDOWN_PIPELINE" />
}
@if (textContent.Sources.Count > 0)
else
{
<MudMarkdown Value="@textContent.Sources.ToMarkdown()" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE" />
<MathJaxBlock @key="@segment.RenderKey" Value="@segmentContent" Class="mb-5" />
}
</div>
}
}
@if (textContent.Sources.Count > 0)
{
<MudMarkdown Value="@textContent.Sources.ToMarkdown()" Props="Markdown.DefaultConfig" Styling="@this.MarkdownStyling" MarkdownPipeline="Markdown.SAFE_MARKDOWN_PIPELINE" />
}
</div>
}
@if (this.Role is ChatRole.AI && !string.IsNullOrWhiteSpace(textContent.ToolRuntimeStatus.Message))
{
<MudAlert Dense="@true" Severity="Severity.Info" Variant="Variant.Outlined" Class="mt-4">
@textContent.ToolRuntimeStatus.Message
</MudAlert>
}
}