EInklappbare Prompts

This commit is contained in:
2026-07-28 11:16:58 +02:00
parent 3fa9bcd624
commit 9323ff1592
9 changed files with 134 additions and 18 deletions

View File

@@ -416,15 +416,9 @@
</TextBox.Style>
</TextBox>
<!-- Platzhalter für ausgeblendete Nachrichten (Message kommt vom Server als null) -->
<TextBlock
Padding="12,8,12,8"
FontSize="14"
FontStyle="Italic"
Foreground="#FF888888"
Text="{Binding HiddenMessageText}"
TextWrapping="Wrap">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<StackPanel Orientation="Vertical">
<StackPanel.Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ShowMessage}" Value="False">
@@ -432,8 +426,73 @@
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel.Style>
<!-- Titelzeile: Promptbaustein-Titel + Ausklapp-Button -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock
Padding="12,8,4,8"
VerticalAlignment="Center"
FontSize="14"
FontStyle="Italic"
Foreground="#FF888888"
Text="{Binding HiddenMessageText}"
TextWrapping="Wrap" />
<ToggleButton
x:Name="btnTogglePrompt"
Grid.Column="1"
Margin="4,4,8,4"
Padding="6,2,6,2"
VerticalAlignment="Center"
IsEnabled="{Binding ShowPrompt}"
ToolTipService.ShowOnDisabled="True">
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<!-- Nur anzeigen, wenn die Nachricht mittels Promptbaustein erstellt wurde -->
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Content" Value="Prompt ▼" />
<Style.Triggers>
<DataTrigger Binding="{Binding HasUsedPromptbaustein}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Content" Value="Prompt ▲" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="ToolTip" Value="Versteckt" />
</Trigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
</Grid>
<!-- Ausgeklappter Prompt-Inhalt -->
<Border
Margin="12,0,12,8"
Padding="4"
Background="#22000000"
CornerRadius="6">
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=btnTogglePrompt}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBox
Padding="8"
Style="{StaticResource MessageTextBoxStyle}"
Text="{Binding UsedPromptbausteinContent, Converter={StaticResource NewlineConverter}, Mode=OneWay}" />
</Border>
</StackPanel>
</Grid>
</Border>
<Button

View File

@@ -54,6 +54,18 @@ namespace BeWo.ViewModel
public bool ShowMessage => DataContract.ShowMessage;
public string UsedPromptbausteinTitle => DataContract.UsedPromptbausteinTitle;
/// <summary>True, wenn die Nachricht mittels Promptbaustein erstellt wurde (Titel gecacht).</summary>
public bool HasUsedPromptbaustein => !string.IsNullOrWhiteSpace(UsedPromptbausteinTitle);
/// <summary>Steuert, ob der Prompt ausklappbar ist. False => Button disabled + Tooltip "Versteckt".</summary>
public bool ShowPrompt => DataContract.ShowPrompt;
/// <summary>Prompt-Text des verwendeten Promptbausteins (nur befüllt, wenn ShowPrompt true).</summary>
public string UsedPromptbausteinContent => DataContract.UsedPromptbausteinContent;
/// <summary>Schrittnummer innerhalb der Routine (0-basiert), sonst null.</summary>
public int? StepCount => DataContract.StepCount;
/// <summary>Platzhalter für ausgeblendete Nachrichten: Promptbaustein-Titel, sonst Standardtext.</summary>
public string HiddenMessageText => string.IsNullOrWhiteSpace(UsedPromptbausteinTitle)
? "Nachricht ausgeblendet"

View File

@@ -23,5 +23,9 @@ namespace BeWo.Data.Entities
public virtual bool ShowMessage { get; set; }
/// <summary>Titel des verwendeten Promptbausteins (gecacht, falls sich der Titel später ändert)</summary>
public virtual string UsedPromptbausteinTitle { get; set; }
/// <summary>Verwendeter Promptbaustein, falls die Nachricht mittels Promptbaustein erstellt wurde (sonst null).</summary>
public virtual AiPromptbausteinPrompt UsedPromptbaustein { get; set; }
/// <summary>Schrittnummer (0-basiert) innerhalb der Routine, falls die Conversation innerhalb einer Routine ausgeführt wurde (sonst null).</summary>
public virtual int? StepCount { get; set; }
}
}

View File

@@ -20,8 +20,12 @@
<property name="ModelName"/>
<property name="ShowMessage"/>
<property name="UsedPromptbausteinTitle"/>
<property name="StepCount"/>
<many-to-one name="AiConversation"
column="AiConversationOid"
not-null="true"/>
<many-to-one name="UsedPromptbaustein"
column="UsedPromptbausteinOid"
class="BeWo.Data.Entities.AiPromptbausteinPrompt,BeWo.Data"/>
</class>
</hibernate-mapping>

View File

@@ -0,0 +1,14 @@
INSERT INTO `.executedscripts`
VALUES ('Changes_2026-07-28 AiConversationMessage Promptbausteinreferenz', CURDATE());
ALTER TABLE `aiconversationmessage`
ADD COLUMN `UsedPromptbausteinOid` BIGINT NULL DEFAULT NULL AFTER `UsedPromptbausteinTitle`,
ADD COLUMN `StepCount` INT NULL DEFAULT NULL AFTER `UsedPromptbausteinOid`,
ADD INDEX `FK_AICONVMESSAGE_USED_PROMPTBAUSTEIN_OID_idx` (`UsedPromptbausteinOid` ASC) VISIBLE;
;
ALTER TABLE `aiconversationmessage`
ADD CONSTRAINT `FK_AICONVMESSAGE_USED_PROMPTBAUSTEIN_OID`
FOREIGN KEY (`UsedPromptbausteinOid`)
REFERENCES `aipromptbausteinprompt` (`Oid`)
ON DELETE SET NULL
ON UPDATE CASCADE;

View File

@@ -23,6 +23,18 @@ namespace BeWo.Service.DCEntityMapper
pDataContract.ModelName = pEntity.ModelName;
pDataContract.ShowMessage = pEntity.ShowMessage;
pDataContract.UsedPromptbausteinTitle = pEntity.UsedPromptbausteinTitle;
pDataContract.StepCount = pEntity.StepCount;
if(pDataContract.Oid == 1616)
{
}
var promptbaustein = pEntity.UsedPromptbaustein;
// Sichtbar nur, wenn der Promptbaustein global (vgl. AiPromptbausteinPromptVM.IsPromptVisible).
pDataContract.ShowPrompt = promptbaustein != null && promptbaustein.ShowPrompt;
// Prompt-Inhalt nur ausliefern, wenn sichtbar (sonst "Versteckt").
pDataContract.UsedPromptbausteinContent = pDataContract.ShowPrompt ? promptbaustein.Prompt : null;
pDataContract.Message = pDataContract.ShowMessage ? pEntity.Message : null;

View File

@@ -207,6 +207,8 @@ namespace BeWo.Service.Plugins
clone_msg.ModelName = msg.ModelName;
clone_msg.ShowMessage = msg.ShowMessage;
clone_msg.UsedPromptbausteinTitle = msg.UsedPromptbausteinTitle;
clone_msg.UsedPromptbaustein = msg.UsedPromptbaustein;
clone_msg.StepCount = msg.StepCount;
clone_conv.Messages.Add(clone_msg);
clone_msg.AiConversation = clone_conv;
@@ -265,7 +267,7 @@ namespace BeWo.Service.Plugins
var prompt = step_ent.PromptReference;
return executePrompt(conversation, view_context, prompt.Oid.Value, routine_ent.RoutineType);
return executePrompt(conversation, view_context, prompt.Oid.Value, routine_ent.RoutineType, step);
}
public virtual bool CheckContextSize(AiActionType actionType, AiViewContextDC view_context)
@@ -422,7 +424,7 @@ namespace BeWo.Service.Plugins
return msg;
}
protected virtual AiConversationMessageDC[] sendNewMessage(AiConversation conv, string message, bool save = true, bool show_message = true, string used_promptbaustein_title = null)
protected virtual AiConversationMessageDC[] sendNewMessage(AiConversation conv, string message, bool save = true, AiPromptbausteinPrompt used_promptbaustein = null, int? step_count = null)
{
CheckPermissions(conv.ActionType);
@@ -445,8 +447,10 @@ namespace BeWo.Service.Plugins
user_msg.AiConversation = conv;
user_msg.Role = BS.Shared.AiConversationMessageRole.User;
user_msg.Created = DateTime.Now;
user_msg.ShowMessage = show_message;
user_msg.UsedPromptbausteinTitle = used_promptbaustein_title;
user_msg.ShowMessage = used_promptbaustein is null;
user_msg.UsedPromptbausteinTitle = used_promptbaustein?.Title;
user_msg.UsedPromptbaustein = used_promptbaustein;
user_msg.StepCount = step_count;
conv.Messages.Add(user_msg);
@@ -610,7 +614,7 @@ namespace BeWo.Service.Plugins
}
}
private AiConversationMessageDC[] executePrompt(long conversation_oid, AiViewContextDC view_context, long prompt_oid, AiRoutineType aiRoutineType)
private AiConversationMessageDC[] executePrompt(long conversation_oid, AiViewContextDC view_context, long prompt_oid, AiRoutineType aiRoutineType, int? step = null)
{
var ai_config = GetAiConfig();
@@ -638,7 +642,7 @@ namespace BeWo.Service.Plugins
}
// Server Request
sendNewMessage(new_conv, prompt.Prompt, false, false, prompt.Title).ToList();
sendNewMessage(new_conv, prompt.Prompt, false, prompt, step).ToList();
var result = new List<AiConversationMessage>
{

View File

@@ -23,7 +23,8 @@ namespace BeWo.Service.Status
"Changes_2026-06-18 AiModel default updaten",
"Changes_2026-07-08 AiConversation Promptreferenz",
"Changes_2026-07-10 AiConversationMessage ShowMessage",
"Changes_2026-07-22 AiConversationMessage UsedPromptbausteinTitle");
"Changes_2026-07-22 AiConversationMessage UsedPromptbausteinTitle",
"Changes_2026-07-28 AiConversationMessage Promptbausteinreferenz");
RegisterCheckup(CheckEndpointOneGetModels,
CheckEndpointOneSendMessage,

View File

@@ -19,5 +19,11 @@ namespace BS.Shared.DataContracts.Feature.AI
[DataMember] public int? Duration { get; set; }
[DataMember] public bool ShowMessage { get; set; }
[DataMember] public string UsedPromptbausteinTitle { get; set; }
/// <summary>True, wenn der verwendete Promptbaustein sichtbar ist (ShowPrompt und ShowPromptByTenant). Steuert den Ausklapp-Button.</summary>
[DataMember] public bool ShowPrompt { get; set; }
/// <summary>Prompt-Text des verwendeten Promptbausteins. Nur befüllt, wenn ShowPrompt true ist (sonst null / "Versteckt").</summary>
[DataMember] public string UsedPromptbausteinContent { get; set; }
/// <summary>Schrittnummer (0-basiert) innerhalb der Routine, falls die Conversation innerhalb einer Routine ausgeführt wurde (sonst null).</summary>
[DataMember] public int? StepCount { get; set; }
}
}