UI changes and added support for i18n

This commit is contained in:
Peer Schütt 2026-04-10 10:43:13 +02:00
parent 447fe9d712
commit f474589834
15 changed files with 296 additions and 73 deletions

View File

@ -1684,12 +1684,24 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CHATROLEEXTENSIONS::T601166687"] = "AI"
-- Edit Message -- Edit Message
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1183581066"] = "Edit Message" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1183581066"] = "Edit Message"
-- Result
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1347088452"] = "Result"
-- Do you really want to remove this message? -- Do you really want to remove this message?
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1347427447"] = "Do you really want to remove this message?" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1347427447"] = "Do you really want to remove this message?"
-- Yes, remove the AI response and edit it -- Yes, remove the AI response and edit it
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1350385882"] = "Yes, remove the AI response and edit it" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1350385882"] = "Yes, remove the AI response and edit it"
-- Failed
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1434043348"] = "Failed"
-- Tool Calls ({0})
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1493057571"] = "Tool Calls ({0})"
-- Executed
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1564757972"] = "Executed"
-- Yes, regenerate it -- Yes, regenerate it
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1603883875"] = "Yes, regenerate it" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T1603883875"] = "Yes, regenerate it"
@ -1708,6 +1720,9 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2093355991"] = "Removes
-- Regenerate Message -- Regenerate Message
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2308444540"] = "Regenerate Message" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2308444540"] = "Regenerate Message"
-- Arguments
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T2738624831"] = "Arguments"
-- Number of attachments -- Number of attachments
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3018847255"] = "Number of attachments" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3018847255"] = "Number of attachments"
@ -1717,9 +1732,15 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3175548294"] = "Cannot
-- Edit -- Edit
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3267849393"] = "Edit" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3267849393"] = "Edit"
-- Unknown
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3424652889"] = "Unknown"
-- Regenerate -- Regenerate
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3587744975"] = "Regenerate" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3587744975"] = "Regenerate"
-- Blocked
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3816336467"] = "Blocked"
-- Do you really want to regenerate this message? -- Do you really want to regenerate this message?
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3878878761"] = "Do you really want to regenerate this message?" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T3878878761"] = "Do you really want to regenerate this message?"
@ -1732,6 +1753,9 @@ UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T4188329028"] = "No, kee
-- Export Chat to Microsoft Word -- Export Chat to Microsoft Word
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T861873672"] = "Export Chat to Microsoft Word" UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T861873672"] = "Export Chat to Microsoft Word"
-- No arguments
UI_TEXT_CONTENT["AISTUDIO::CHAT::CONTENTBLOCKCOMPONENT::T931993614"] = "No arguments"
-- The local image file does not exist. Skipping the image. -- The local image file does not exist. Skipping the image.
UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image." UI_TEXT_CONTENT["AISTUDIO::CHAT::IIMAGESOURCEEXTENSIONS::T255679918"] = "The local image file does not exist. Skipping the image."
@ -2590,6 +2614,27 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T900237
-- Export configuration -- Export configuration
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T975426229"] = "Export configuration" UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELPROVIDERS::T975426229"] = "Export configuration"
-- Configure global settings for each tool. Tool defaults for chat and assistants are configured in the corresponding feature settings.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T176751696"] = "Configure global settings for each tool. Tool defaults for chat and assistants are configured in the corresponding feature settings."
-- Configured
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T2463440925"] = "Configured"
-- Tools
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T2499909372"] = "Tools"
-- Tool
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3517012711"] = "Tool"
-- Actions
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T3865031940"] = "Actions"
-- State
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T502047894"] = "State"
-- Configuration required
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTOOLS::T979592518"] = "Configuration required"
-- No transcription provider configured yet. -- No transcription provider configured yet.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1079350363"] = "No transcription provider configured yet." UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1079350363"] = "No transcription provider configured yet."
@ -2659,6 +2704,48 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::THIRDPARTYCOMPONENT::T1392042694"] = "Ope
-- License: -- License:
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::THIRDPARTYCOMPONENT::T1908172666"] = "License:" UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::THIRDPARTYCOMPONENT::T1908172666"] = "License:"
-- Tool selection is hidden
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T2096103917"] = "Tool selection is hidden"
-- Choose which tools should be preselected for new runs of this assistant.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T2696618758"] = "Choose which tools should be preselected for new runs of this assistant."
-- Default tools for this assistant
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3253667950"] = "Default tools for this assistant"
-- Tool selection is visible
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3384582069"] = "Tool selection is visible"
-- Show tool selection in this assistant?
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T3494508870"] = "Show tool selection in this assistant?"
-- Default tools for chat
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T907403808"] = "Default tools for chat"
-- Choose which tools should be preselected for new chats.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLDEFAULTSCONFIGURATION::T948842182"] = "Choose which tools should be preselected for new chats."
-- Tool changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T1688023907"] = "Tool changes are locked while a response is running. Your current selection is shown below and applies again from the next message once the run is finished."
-- Required settings are missing. Configure this tool before enabling it.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3119156561"] = "Required settings are missing. Configure this tool before enabling it."
-- The selected provider or model does not support tool calling.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3364063757"] = "The selected provider or model does not support tool calling."
-- Close
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3448155331"] = "Close"
-- No tools are available in this context.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T3904490680"] = "No tools are available in this context."
-- Tool Selection
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T749664565"] = "Tool Selection"
-- Select tools
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::TOOLSELECTION::T998515990"] = "Select tools"
-- You'll interact with the AI systems using your voice. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation. -- You'll interact with the AI systems using your voice. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T1015366320"] = "You'll interact with the AI systems using your voice. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation." UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::VISION::T1015366320"] = "You'll interact with the AI systems using your voice. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation."
@ -4696,6 +4783,12 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T13933
-- Preselect aspects for the LLM to focus on when generating slides, such as bullet points or specific topics to emphasize. -- Preselect aspects for the LLM to focus on when generating slides, such as bullet points or specific topics to emphasize.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T1528169602"] = "Preselect aspects for the LLM to focus on when generating slides, such as bullet points or specific topics to emphasize." UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T1528169602"] = "Preselect aspects for the LLM to focus on when generating slides, such as bullet points or specific topics to emphasize."
-- Slide Planner Assistant options are preselected
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T1549358578"] = "Slide Planner Assistant options are preselected"
-- No Slide Planner Assistant options are preselected
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T1694374279"] = "No Slide Planner Assistant options are preselected"
-- Choose whether the assistant should use the app default profile, no profile, or a specific profile. -- Choose whether the assistant should use the app default profile, no profile, or a specific profile.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T1766361623"] = "Choose whether the assistant should use the app default profile, no profile, or a specific profile." UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T1766361623"] = "Choose whether the assistant should use the app default profile, no profile, or a specific profile."
@ -4705,9 +4798,6 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T20146
-- Which audience organizational level should be preselected? -- Which audience organizational level should be preselected?
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T216511105"] = "Which audience organizational level should be preselected?" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T216511105"] = "Which audience organizational level should be preselected?"
-- Preselect Slide Planner Assistant options?
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T227645894"] = "Preselect Slide Planner Assistant options?"
-- Preselect a profile -- Preselect a profile
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T2322771068"] = "Preselect a profile" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T2322771068"] = "Preselect a profile"
@ -4724,26 +4814,23 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T25714
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T2645589441"] = "Preselect the audience age group" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T2645589441"] = "Preselect the audience age group"
-- Assistant: Slide Planner Assistant Options -- Assistant: Slide Planner Assistant Options
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3215549988"] = "Assistant: Slide Planner Assistant Options" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3226042276"] = "Assistant: Slide Planner Assistant Options"
-- Which audience expertise should be preselected? -- Which audience expertise should be preselected?
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3228597992"] = "Which audience expertise should be preselected?" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3228597992"] = "Which audience expertise should be preselected?"
-- Preselect Slide Planner Assistant options?
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T339924858"] = "Preselect Slide Planner Assistant options?"
-- Close -- Close
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3448155331"] = "Close" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3448155331"] = "Close"
-- Preselect important aspects -- Preselect important aspects
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3705987833"] = "Preselect important aspects" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T3705987833"] = "Preselect important aspects"
-- No Slide Planner Assistant options are preselected
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T4214398691"] = "No Slide Planner Assistant options are preselected"
-- Preselect the audience profile -- Preselect the audience profile
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T861397972"] = "Preselect the audience profile" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T861397972"] = "Preselect the audience profile"
-- Slide Planner Assistant options are preselected
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T93124146"] = "Slide Planner Assistant options are preselected"
-- Which audience age group should be preselected? -- Which audience age group should be preselected?
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T956845877"] = "Which audience age group should be preselected?" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGSLIDEBUILDER::T956845877"] = "Which audience age group should be preselected?"
@ -5002,6 +5089,18 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T3547
-- Preselect e-mail options? -- Preselect e-mail options?
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T3832719342"] = "Preselect e-mail options?" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::SETTINGSDIALOGWRITINGEMAILS::T3832719342"] = "Preselect e-mail options?"
-- Save
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T1294818664"] = "Save"
-- Tool Settings
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3730473128"] = "Tool Settings"
-- The selected tool could not be loaded.
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T3907843187"] = "The selected tool could not be loaded."
-- Cancel
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SETTINGS::TOOLSETTINGSDIALOG::T900713019"] = "Cancel"
-- Save -- Save
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SHORTCUTDIALOG::T1294818664"] = "Save" UI_TEXT_CONTENT["AISTUDIO::DIALOGS::SHORTCUTDIALOG::T1294818664"] = "Save"

View File

@ -16,6 +16,18 @@
</MudText> </MudText>
</CardHeaderContent> </CardHeaderContent>
<CardHeaderActions> <CardHeaderActions>
@if (this.Role is ChatRole.AI && this.Content is ContentText toolContent && toolContent.ToolInvocations.Count > 0)
{
<MudDivider Vertical="true" Class="mx-1" />
<MudTooltip Text="@this.GetToolTraceTooltip()" Placement="Placement.Bottom">
<MudPaper Class="d-flex align-center px-2 py-1 mr-1 border rounded-lg" Style="gap: 6px; cursor: pointer;" @onclick="@this.ToggleToolTrace">
@foreach (var toolIcon in this.GetDistinctToolIcons())
{
<MudIcon Icon="@toolIcon" Color="Color.Info" />
}
</MudPaper>
</MudTooltip>
}
@if (this.Content.FileAttachments.Count > 0) @if (this.Content.FileAttachments.Count > 0)
{ {
<MudTooltip Text="@T("Number of attachments")" Placement="Placement.Bottom"> <MudTooltip Text="@T("Number of attachments")" Placement="Placement.Bottom">
@ -123,50 +135,50 @@
</MudAlert> </MudAlert>
} }
@if (this.Role is ChatRole.AI && textContent.ToolInvocations.Count > 0) @if (this.Role is ChatRole.AI && textContent.ToolInvocations.Count > 0 && this.showToolTrace)
{ {
<MudText Typo="Typo.subtitle2" Class="mt-4 mb-2"> <MudText Typo="Typo.subtitle2" Class="mt-4 mb-2">
@string.Format(T("Tool Calls ({0})"), textContent.ToolInvocations.Count) @string.Format(T("Tool Calls ({0})"), textContent.ToolInvocations.Count)
</MudText> </MudText>
<MudExpansionPanels MultiExpansion="@true" Class="mt-4"> @foreach (var invocation in textContent.ToolInvocations.OrderBy(x => x.Order))
@foreach (var invocation in textContent.ToolInvocations.OrderBy(x => x.Order)) {
{ <MudPaper Class="pa-3 mb-3 border rounded-lg">
<ExpansionPanel HeaderIcon="@invocation.ToolIcon" HeaderText="@($"{invocation.Order}. {invocation.ToolName}")"> <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-3">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2" Class="mb-3"> <MudIcon Icon="@invocation.ToolIcon" Color="Color.Info" />
<MudChip T="string" Color="@ContentBlockComponent.GetTraceColor(invocation.Status)" Size="Size.Small" Variant="Variant.Outlined"> <MudText Typo="Typo.subtitle1">@($"{invocation.Order}. {invocation.ToolName}")</MudText>
@this.GetTraceStatusText(invocation) <MudChip T="string" Color="@ContentBlockComponent.GetTraceColor(invocation.Status)" Size="Size.Small" Variant="Variant.Outlined">
</MudChip> @this.GetTraceStatusText(invocation)
</MudStack> </MudChip>
</MudStack>
@if (!string.IsNullOrWhiteSpace(invocation.StatusMessage)) @if (!string.IsNullOrWhiteSpace(invocation.StatusMessage))
{ {
<MudText Typo="Typo.body2" Color="Color.Warning" Class="mb-3">@invocation.StatusMessage</MudText> <MudText Typo="Typo.body2" Color="Color.Warning" Class="mb-3">@invocation.StatusMessage</MudText>
} }
<MudText Typo="Typo.subtitle2">@T("Arguments")</MudText> <MudText Typo="Typo.subtitle2">@T("Arguments")</MudText>
@if (invocation.Arguments.Count == 0) @if (invocation.Arguments.Count == 0)
{ {
<MudText Typo="Typo.body2" Class="mb-3">@T("No arguments")</MudText> <MudText Typo="Typo.body2" Class="mb-3">@T("No arguments")</MudText>
} }
else else
{ {
<MudList T="string" Dense="@true" Class="mb-3"> <MudList T="string" Dense="@true" Class="mb-3">
@foreach (var argument in invocation.Arguments) @foreach (var argument in invocation.Arguments)
{ {
<MudListItem T="string"> <MudListItem T="string">
<MudText Typo="Typo.body2"><strong>@argument.Key:</strong> @argument.Value</MudText> <MudText Typo="Typo.body2"><strong>@argument.Key:</strong> @argument.Value</MudText>
</MudListItem> </MudListItem>
} }
</MudList> </MudList>
} }
<MudText Typo="Typo.subtitle2">@T("Result")</MudText> <MudText Typo="Typo.subtitle2">@T("Result")</MudText>
<MudPaper Class="pa-3 mt-2"> <MudPaper Class="pa-3 mt-2">
<MudText Typo="Typo.body2" Style="white-space: pre-wrap;">@invocation.Result</MudText> <MudText Typo="Typo.body2" Style="white-space: pre-wrap;">@invocation.Result</MudText>
</MudPaper> </MudPaper>
</ExpansionPanel> </MudPaper>
} }
</MudExpansionPanels>
} }
} }
} }

View File

@ -104,6 +104,7 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
private string lastMathRenderSignature = string.Empty; private string lastMathRenderSignature = string.Empty;
private bool hasActiveMathContainer; private bool hasActiveMathContainer;
private bool isDisposed; private bool isDisposed;
private bool showToolTrace;
#region Overrides of ComponentBase #region Overrides of ComponentBase
@ -203,6 +204,7 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
hash.Add(text.ToolInvocations.Count); hash.Add(text.ToolInvocations.Count);
hash.Add(text.ToolRuntimeStatus.IsRunning); hash.Add(text.ToolRuntimeStatus.IsRunning);
hash.Add(text.ToolRuntimeStatus.Message); hash.Add(text.ToolRuntimeStatus.Message);
hash.Add(this.showToolTrace);
foreach (var invocation in text.ToolInvocations) foreach (var invocation in text.ToolInvocations)
{ {
hash.Add(invocation.Order); hash.Add(invocation.Order);
@ -250,6 +252,28 @@ public partial class ContentBlockComponent : MSGComponentBase, IAsyncDisposable
_ => this.T("Unknown"), _ => this.T("Unknown"),
}; };
private IReadOnlyList<ToolInvocationTrace> GetToolInvocations() => this.Content is ContentText textContent
? textContent.ToolInvocations.OrderBy(x => x.Order).ToList()
: [];
private IReadOnlyList<string> GetDistinctToolIcons() => this.GetToolInvocations()
.Select(x => x.ToolIcon)
.Distinct(StringComparer.Ordinal)
.ToList();
private string GetToolTraceTooltip()
{
var invocations = this.GetToolInvocations();
return invocations.Count switch
{
0 => this.T("No tool calls"),
1 => string.Format(this.T("Show tool call for {0}"), invocations[0].ToolName),
_ => string.Format(this.T("Show {0} tool calls"), invocations.Count),
};
}
private void ToggleToolTrace() => this.showToolTrace = !this.showToolTrace;
private MudMarkdownStyling MarkdownStyling => new() private MudMarkdownStyling MarkdownStyling => new()
{ {
CodeBlock = { Theme = this.CodeColorPalette }, CodeBlock = { Theme = this.CodeColorPalette },

View File

@ -8,19 +8,33 @@
<MudTable Items="@this.items" Hover="@true" Dense="@true"> <MudTable Items="@this.items" Hover="@true" Dense="@true">
<HeaderContent> <HeaderContent>
<MudTh>@T("Tool")</MudTh> <MudTh>@T("Icon")</MudTh>
<MudTh>@T("Name")</MudTh>
<MudTh>@T("Description")</MudTh>
<MudTh>@T("State")</MudTh> <MudTh>@T("State")</MudTh>
<MudTh>@T("Actions")</MudTh> <MudTh>@T("Settings")</MudTh>
</HeaderContent> </HeaderContent>
<RowTemplate> <RowTemplate>
<MudTd> <MudTd>
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2"> <MudIcon Icon="@context.Implementation.Icon" Color="Color.Info" />
<MudIcon Icon="@context.Definition.Icon" />
<MudText Typo="Typo.body1">@context.Definition.DisplayName</MudText>
</MudStack>
</MudTd> </MudTd>
<MudTd> <MudTd>
@(context.ConfigurationState.IsConfigured ? T("Configured") : T("Configuration required")) <MudText Typo="Typo.body1">@context.Implementation.GetDisplayName()</MudText>
</MudTd>
<MudTd>
<MudText Typo="Typo.body2">@context.Implementation.GetDescription()</MudText>
</MudTd>
<MudTd>
@if (context.ConfigurationState.IsConfigured)
{
<MudIcon Icon="@Icons.Material.Filled.CheckCircle" Color="Color.Success" />
}
else
{
<MudTooltip Text="@this.GetConfigurationTooltip(context)">
<MudIcon Icon="@Icons.Material.Filled.Warning" Color="Color.Warning" />
</MudTooltip>
}
</MudTd> </MudTd>
<MudTd> <MudTd>
<MudIconButton Icon="@Icons.Material.Filled.Settings" OnClick="@(async () => await this.OpenSettings(context.Definition.Id))" /> <MudIconButton Icon="@Icons.Material.Filled.Settings" OnClick="@(async () => await this.OpenSettings(context.Definition.Id))" />

View File

@ -31,4 +31,19 @@ public partial class SettingsPanelTools : SettingsPanelBase
this.items = await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetAllDefinitions()); this.items = await this.ToolRegistry.GetCatalogAsync(this.ToolRegistry.GetAllDefinitions());
this.StateHasChanged(); this.StateHasChanged();
} }
private string GetConfigurationTooltip(ToolCatalogItem item) => item.ConfigurationState.MissingRequiredFields.Count switch
{
0 => this.T("This tool still needs to be configured."),
_ => string.Format(this.T("Missing required settings: {0}"), string.Join(", ", item.ConfigurationState.MissingRequiredFields.Select(fieldName => this.GetFieldDisplayName(item, fieldName))))
};
private string GetFieldDisplayName(ToolCatalogItem item, string fieldName)
{
var fieldDefinition = item.Definition.SettingsSchema.Properties.GetValueOrDefault(fieldName);
if (fieldDefinition is null)
return fieldName;
return item.Implementation.GetSettingsFieldLabel(fieldName, fieldDefinition);
}
} }

View File

@ -25,13 +25,12 @@ public partial class ToolDefaultsConfiguration : MSGComponentBase
? this.T("Choose which tools should be preselected for new chats.") ? this.T("Choose which tools should be preselected for new chats.")
: this.T("Choose which tools should be preselected for new runs of this assistant."); : this.T("Choose which tools should be preselected for new runs of this assistant.");
protected override void OnInitialized() protected override async Task OnInitializedAsync()
{ {
this.availableTools = this.ToolRegistry this.availableTools = (await this.ToolRegistry.GetCatalogAsync(this.Component))
.GetDefinitionsForComponent(this.Component) .Select(x => new ConfigurationSelectData<string>(x.Implementation.GetDisplayName(), x.Definition.Id))
.Select(x => new ConfigurationSelectData<string>(x.DisplayName, x.Id))
.ToList(); .ToList();
base.OnInitialized(); await base.OnInitializedAsync();
} }
private HashSet<string> GetSelectedValues() => this.SettingsManager.GetDefaultToolIds(this.Component); private HashSet<string> GetSelectedValues() => this.SettingsManager.GetDefaultToolIds(this.Component);

View File

@ -42,12 +42,13 @@
<MudPaper Class="pa-2 mb-2 border rounded-lg"> <MudPaper Class="pa-2 mb-2 border rounded-lg">
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween"> <MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2"> <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
<MudSwitch T="bool" Value="@isSelected" ValueChanged="@(value => this.ChangeSelection(item.Definition.Id, value))" Disabled="@(!isConfigured || this.Disabled || !this.SupportsTools)" /> <MudSwitch T="bool" Color="Color.Primary" Value="@isSelected" ValueChanged="@(value => this.ChangeSelection(item.Definition.Id, value))" Disabled="@(!isConfigured || this.Disabled || !this.SupportsTools)" />
<MudIcon Icon="@item.Definition.Icon" /> <MudIcon Icon="@item.Implementation.Icon" Color="Color.Info" />
<MudText Typo="Typo.body1">@item.Definition.DisplayName</MudText> <MudText Typo="Typo.body1">@item.Implementation.GetDisplayName()</MudText>
</MudStack> </MudStack>
<MudIconButton Icon="@Icons.Material.Filled.Settings" OnClick="@(async () => await this.OpenSettings(item.Definition.Id))" /> <MudIconButton Icon="@Icons.Material.Filled.Settings" OnClick="@(async () => await this.OpenSettings(item.Definition.Id))" />
</MudStack> </MudStack>
<MudText Typo="Typo.body2" Class="mt-2">@item.Implementation.GetDescription()</MudText>
@if (!isConfigured) @if (!isConfigured)
{ {
<MudText Typo="Typo.caption" Color="Color.Warning">@T("Required settings are missing. Configure this tool before enabling it.")</MudText> <MudText Typo="Typo.caption" Color="Color.Warning">@T("Required settings are missing. Configure this tool before enabling it.")</MudText>
@ -57,6 +58,7 @@
} }
</MudCardContent> </MudCardContent>
<MudCardActions> <MudCardActions>
<MudSpacer />
<MudButton Variant="Variant.Filled" OnClick="@this.Hide">@T("Close")</MudButton> <MudButton Variant="Variant.Filled" OnClick="@this.Hide">@T("Close")</MudButton>
</MudCardActions> </MudCardActions>
</MudCard> </MudCard>

View File

@ -4,8 +4,8 @@
<MudDialog> <MudDialog>
<TitleContent> <TitleContent>
<MudText Typo="Typo.h6" Class="d-flex align-center"> <MudText Typo="Typo.h6" Class="d-flex align-center">
<MudIcon Icon="@this.toolDefinition?.Icon" Class="mr-2" /> <MudIcon Icon="@this.implementation?.Icon" Class="mr-2" />
@(this.toolDefinition?.DisplayName ?? T("Tool Settings")) @(this.implementation?.GetDisplayName() ?? T("Tool Settings"))
</MudText> </MudText>
</TitleContent> </TitleContent>
<DialogContent> <DialogContent>
@ -15,13 +15,18 @@
} }
else else
{ {
<MudJustifiedText Typo="Typo.body1" Class="mb-4">
@this.implementation?.GetDescription()
</MudJustifiedText>
<MudPaper Class="pa-3 mb-4 border-dashed border rounded-lg">
@foreach (var property in this.toolDefinition.SettingsSchema.Properties) @foreach (var property in this.toolDefinition.SettingsSchema.Properties)
{ {
var fieldName = property.Key; var fieldName = property.Key;
var field = property.Value; var field = property.Value;
if (field.EnumValues.Count > 0) if (field.EnumValues.Count > 0)
{ {
<MudSelect T="string" Label="@field.Title" Value="@this.GetValue(fieldName)" ValueChanged="@(value => this.UpdateValue(fieldName, value))" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3"> <MudSelect T="string" Label="@this.GetFieldLabel(fieldName, field)" Value="@this.GetValue(fieldName)" ValueChanged="@(value => this.UpdateValue(fieldName, value))" Variant="Variant.Outlined" Margin="Margin.Dense" HelperText="@this.GetFieldDescription(fieldName, field)" Class="mb-3">
@foreach (var option in field.EnumValues) @foreach (var option in field.EnumValues)
{ {
<MudSelectItem T="string" Value="@option">@option</MudSelectItem> <MudSelectItem T="string" Value="@option">@option</MudSelectItem>
@ -30,9 +35,10 @@
} }
else else
{ {
<MudTextField T="string" Label="@field.Title" Value="@this.GetValue(fieldName)" ValueChanged="@(value => this.UpdateValue(fieldName, value))" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3" HelperText="@field.Description" InputType="@(field.Secret ? InputType.Password : InputType.Text)" /> <MudTextField T="string" Label="@this.GetFieldLabel(fieldName, field)" Value="@this.GetValue(fieldName)" ValueChanged="@(value => this.UpdateValue(fieldName, value))" Variant="Variant.Outlined" Margin="Margin.Dense" Class="mb-3" HelperText="@this.GetFieldDescription(fieldName, field)" InputType="@(field.Secret ? InputType.Password : InputType.Text)" />
} }
} }
</MudPaper>
} }
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>

View File

@ -16,6 +16,7 @@ public partial class ToolSettingsDialog : SettingsDialogBase
private ToolSettingsService ToolSettingsService { get; init; } = null!; private ToolSettingsService ToolSettingsService { get; init; } = null!;
private ToolDefinition? toolDefinition; private ToolDefinition? toolDefinition;
private IToolImplementation? implementation;
private Dictionary<string, string> values = new(StringComparer.Ordinal); private Dictionary<string, string> values = new(StringComparer.Ordinal);
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
@ -23,11 +24,20 @@ public partial class ToolSettingsDialog : SettingsDialogBase
await base.OnInitializedAsync(); await base.OnInitializedAsync();
this.toolDefinition = this.ToolRegistry.GetDefinition(this.ToolId); this.toolDefinition = this.ToolRegistry.GetDefinition(this.ToolId);
if (this.toolDefinition is not null) if (this.toolDefinition is not null)
{
this.implementation = this.ToolRegistry.GetImplementation(this.toolDefinition.ImplementationKey);
this.values = await this.ToolSettingsService.GetSettingsAsync(this.toolDefinition); this.values = await this.ToolSettingsService.GetSettingsAsync(this.toolDefinition);
}
} }
private string GetValue(string fieldName) => this.values.GetValueOrDefault(fieldName, string.Empty); private string GetValue(string fieldName) => this.values.GetValueOrDefault(fieldName, string.Empty);
private string GetFieldLabel(string fieldName, ToolSettingsFieldDefinition fieldDefinition) =>
this.implementation?.GetSettingsFieldLabel(fieldName, fieldDefinition) ?? fieldDefinition.Title;
private string GetFieldDescription(string fieldName, ToolSettingsFieldDefinition fieldDefinition) =>
this.implementation?.GetSettingsFieldDescription(fieldName, fieldDefinition) ?? fieldDefinition.Description;
private void UpdateValue(string fieldName, string? value) => this.values[fieldName] = value ?? string.Empty; private void UpdateValue(string fieldName, string? value) => this.values[fieldName] = value ?? string.Empty;
private async Task Save() private async Task Save()

View File

@ -668,7 +668,7 @@ public abstract class BaseProvider : IProvider, ISecretId
{ {
IsRunning = true, IsRunning = true,
ToolNames = responseMessage.ToolCalls ToolNames = responseMessage.ToolCalls
.Select(x => runnableTools.FirstOrDefault(tool => tool.Definition.Function.Name.Equals(x.Function.Name, StringComparison.Ordinal)).Definition?.DisplayName ?? x.Function.Name) .Select(x => runnableTools.FirstOrDefault(tool => tool.Definition.Function.Name.Equals(x.Function.Name, StringComparison.Ordinal)).Implementation?.GetDisplayName() ?? x.Function.Name)
.ToList(), .ToList(),
}; };
await currentAssistantContent.StreamingEvent(); await currentAssistantContent.StreamingEvent();

View File

@ -1,13 +1,33 @@
using System.Text.Json; using System.Text.Json;
using AIStudio.Tools.PluginSystem;
namespace AIStudio.Tools.ToolCallingSystem; namespace AIStudio.Tools.ToolCallingSystem;
public sealed class GetCurrentWeatherTool : IToolImplementation public sealed class GetCurrentWeatherTool : IToolImplementation
{ {
public string ImplementationKey => "get_current_weather"; public string ImplementationKey => "get_current_weather";
public string Icon => Icons.Material.Filled.Cloud;
public IReadOnlySet<string> SensitiveTraceArgumentNames => new HashSet<string>(StringComparer.Ordinal); public IReadOnlySet<string> SensitiveTraceArgumentNames => new HashSet<string>(StringComparer.Ordinal);
public string GetDisplayName() => I18N.I.T("Current Weather", typeof(GetCurrentWeatherTool).Namespace, nameof(GetCurrentWeatherTool));
public string GetDescription() => I18N.I.T("Use this demo tool to retrieve the current weather for a given city and state. It is primarily meant to demonstrate tool calling and tool settings in AI Studio.", typeof(GetCurrentWeatherTool).Namespace, nameof(GetCurrentWeatherTool));
public string GetSettingsFieldLabel(string fieldName, ToolSettingsFieldDefinition fieldDefinition) => fieldName switch
{
"demoLabel" => I18N.I.T("Demo Label", typeof(GetCurrentWeatherTool).Namespace, nameof(GetCurrentWeatherTool)),
_ => I18N.I.T(fieldDefinition.Title, typeof(GetCurrentWeatherTool).Namespace, nameof(GetCurrentWeatherTool)),
};
public string GetSettingsFieldDescription(string fieldName, ToolSettingsFieldDefinition fieldDefinition) => fieldName switch
{
"demoLabel" => I18N.I.T("Required demo setting for validating tool settings in tests. It does not affect the weather result.", typeof(GetCurrentWeatherTool).Namespace, nameof(GetCurrentWeatherTool)),
_ => I18N.I.T(fieldDefinition.Description, typeof(GetCurrentWeatherTool).Namespace, nameof(GetCurrentWeatherTool)),
};
public Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default) public Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default)
{ {
var city = arguments.TryGetProperty("city", out var cityValue) ? cityValue.GetString() ?? string.Empty : string.Empty; var city = arguments.TryGetProperty("city", out var cityValue) ? cityValue.GetString() ?? string.Empty : string.Empty;

View File

@ -1,14 +1,30 @@
using System.Text.Json; using System.Text.Json;
using AIStudio.Tools.PluginSystem;
namespace AIStudio.Tools.ToolCallingSystem; namespace AIStudio.Tools.ToolCallingSystem;
public interface IToolImplementation public interface IToolImplementation
{ {
public string ImplementationKey { get; } public string ImplementationKey { get; }
public string Icon => Icons.Material.Filled.Build;
public IReadOnlySet<string> SensitiveTraceArgumentNames { get; } public IReadOnlySet<string> SensitiveTraceArgumentNames { get; }
public string GetDisplayName() => this.T("Tool");
public string GetDescription() => this.T("Tool description");
public string GetSettingsFieldLabel(string fieldName, ToolSettingsFieldDefinition fieldDefinition) =>
this.T(fieldDefinition.Title);
public string GetSettingsFieldDescription(string fieldName, ToolSettingsFieldDefinition fieldDefinition) =>
this.T(fieldDefinition.Description);
public Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default); public Task<ToolExecutionResult> ExecuteAsync(JsonElement arguments, ToolExecutionContext context, CancellationToken token = default);
public string FormatTraceResult(string rawResult) => rawResult; public string FormatTraceResult(string rawResult) => rawResult;
private string T(string fallbackEN) => I18N.I.T(fallbackEN, this.GetType().Namespace, this.GetType().Name);
} }

View File

@ -85,6 +85,8 @@ public sealed class ToolCatalogItem
{ {
public required ToolDefinition Definition { get; init; } public required ToolDefinition Definition { get; init; }
public required IToolImplementation Implementation { get; init; }
public required ToolConfigurationState ConfigurationState { get; init; } public required ToolConfigurationState ConfigurationState { get; init; }
} }

View File

@ -46,8 +46,8 @@ public sealed class ToolExecutor(ToolSettingsService toolSettingsService)
{ {
Order = order, Order = order,
ToolId = definition.Id, ToolId = definition.Id,
ToolName = definition.DisplayName, ToolName = implementation.GetDisplayName(),
ToolIcon = definition.Icon, ToolIcon = implementation.Icon,
ToolCallId = toolCallId, ToolCallId = toolCallId,
Status = ToolInvocationTraceStatus.SUCCESS, Status = ToolInvocationTraceStatus.SUCCESS,
WasExecuted = true, WasExecuted = true,
@ -72,8 +72,8 @@ public sealed class ToolExecutor(ToolSettingsService toolSettingsService)
{ {
Order = order, Order = order,
ToolId = definition.Id, ToolId = definition.Id,
ToolName = definition.DisplayName, ToolName = implementation.GetDisplayName(),
ToolIcon = definition.Icon, ToolIcon = implementation.Icon,
ToolCallId = toolCallId, ToolCallId = toolCallId,
Status = ToolInvocationTraceStatus.ERROR, Status = ToolInvocationTraceStatus.ERROR,
StatusMessage = error, StatusMessage = error,

View File

@ -69,12 +69,12 @@ public sealed class ToolRegistry
var isChat = component is AIStudio.Tools.Components.CHAT; var isChat = component is AIStudio.Tools.Components.CHAT;
return this.definitionsById.Values return this.definitionsById.Values
.Where(x => isChat ? x.VisibleIn.Chat : x.VisibleIn.Assistants) .Where(x => isChat ? x.VisibleIn.Chat : x.VisibleIn.Assistants)
.OrderBy(x => x.DisplayName, StringComparer.OrdinalIgnoreCase) .OrderBy(x => this.implementationsByKey.GetValueOrDefault(x.ImplementationKey)?.GetDisplayName(), StringComparer.OrdinalIgnoreCase)
.ToList(); .ToList();
} }
public IReadOnlyList<ToolDefinition> GetAllDefinitions() => this.definitionsById.Values public IReadOnlyList<ToolDefinition> GetAllDefinitions() => this.definitionsById.Values
.OrderBy(x => x.DisplayName, StringComparer.OrdinalIgnoreCase) .OrderBy(x => this.implementationsByKey.GetValueOrDefault(x.ImplementationKey)?.GetDisplayName(), StringComparer.OrdinalIgnoreCase)
.ToList(); .ToList();
public ToolDefinition? GetDefinition(string toolId) => this.definitionsById.GetValueOrDefault(toolId); public ToolDefinition? GetDefinition(string toolId) => this.definitionsById.GetValueOrDefault(toolId);
@ -93,9 +93,13 @@ public sealed class ToolRegistry
var items = new List<ToolCatalogItem>(definitionList.Count); var items = new List<ToolCatalogItem>(definitionList.Count);
foreach (var definition in definitionList) foreach (var definition in definitionList)
{ {
if (!this.implementationsByKey.TryGetValue(definition.ImplementationKey, out var implementation))
continue;
items.Add(new ToolCatalogItem items.Add(new ToolCatalogItem
{ {
Definition = definition, Definition = definition,
Implementation = implementation,
ConfigurationState = await this.toolSettingsService.GetConfigurationStateAsync(definition), ConfigurationState = await this.toolSettingsService.GetConfigurationStateAsync(definition),
}); });
} }