diff --git a/app/MindWork AI Studio/Chat/ChatThread.cs b/app/MindWork AI Studio/Chat/ChatThread.cs
index 7ecb6a20..8c5f3819 100644
--- a/app/MindWork AI Studio/Chat/ChatThread.cs
+++ b/app/MindWork AI Studio/Chat/ChatThread.cs
@@ -3,29 +3,35 @@ namespace AIStudio.Chat;
///
/// Data structure for a chat thread.
///
-/// The name of the chat thread.
-/// The seed for the chat thread. Some providers use this to generate deterministic results.
-/// The system prompt for the chat thread.
-/// The content blocks of the chat thread.
-public sealed class ChatThread(string name, int seed, string systemPrompt, IEnumerable blocks)
+public sealed class ChatThread
{
+ ///
+ /// The unique identifier of the chat thread.
+ ///
+ public Guid ChatId { get; init; }
+
+ ///
+ /// The unique identifier of the workspace.
+ ///
+ public Guid WorkspaceId { get; set; }
+
///
/// The name of the chat thread. Usually generated by an AI model or manually edited by the user.
///
- public string Name { get; set; } = name;
+ public string Name { get; set; } = string.Empty;
///
/// The seed for the chat thread. Some providers use this to generate deterministic results.
///
- public int Seed { get; set; } = seed;
+ public int Seed { get; init; }
///
/// The current system prompt for the chat thread.
///
- public string SystemPrompt { get; set; } = systemPrompt;
-
+ public string SystemPrompt { get; init; } = string.Empty;
+
///
/// The content blocks of the chat thread.
///
- public List Blocks { get; init; } = blocks.ToList();
+ public List Blocks { get; init; } = [];
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Chat/ContentBlock.cs b/app/MindWork AI Studio/Chat/ContentBlock.cs
index 65e1f290..05a6bd1f 100644
--- a/app/MindWork AI Studio/Chat/ContentBlock.cs
+++ b/app/MindWork AI Studio/Chat/ContentBlock.cs
@@ -3,25 +3,22 @@ namespace AIStudio.Chat;
///
/// A block of content in a chat thread. Might be any type of content, e.g., text, image, voice, etc.
///
-/// Time when the content block was created.
-/// Type of the content block, e.g., text, image, voice, etc.
-/// The content of the block.
-public class ContentBlock(DateTimeOffset time, ContentType type, IContent content)
+public class ContentBlock
{
///
/// Time when the content block was created.
///
- public DateTimeOffset Time => time;
+ public DateTimeOffset Time { get; init; }
///
/// Type of the content block, e.g., text, image, voice, etc.
///
- public ContentType ContentType => type;
+ public ContentType ContentType { get; init; } = ContentType.NONE;
///
/// The content of the block.
///
- public IContent Content => content;
+ public IContent? Content { get; init; } = null;
///
/// The role of the content block in the chat thread, e.g., user, AI, etc.
diff --git a/app/MindWork AI Studio/Chat/ContentImage.cs b/app/MindWork AI Studio/Chat/ContentImage.cs
index 247c4848..9afe4476 100644
--- a/app/MindWork AI Studio/Chat/ContentImage.cs
+++ b/app/MindWork AI Studio/Chat/ContentImage.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
using AIStudio.Provider;
using AIStudio.Settings;
@@ -11,15 +13,19 @@ public sealed class ContentImage : IContent
#region Implementation of IContent
///
+ [JsonIgnore]
public bool InitialRemoteWait { get; set; } = false;
///
+ [JsonIgnore]
public bool IsStreaming { get; set; } = false;
///
+ [JsonIgnore]
public Func StreamingDone { get; set; } = () => Task.CompletedTask;
///
+ [JsonIgnore]
public Func StreamingEvent { get; set; } = () => Task.CompletedTask;
///
diff --git a/app/MindWork AI Studio/Chat/ContentText.cs b/app/MindWork AI Studio/Chat/ContentText.cs
index 24c7b63b..f125d4b7 100644
--- a/app/MindWork AI Studio/Chat/ContentText.cs
+++ b/app/MindWork AI Studio/Chat/ContentText.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
using AIStudio.Provider;
using AIStudio.Settings;
@@ -17,14 +19,19 @@ public sealed class ContentText : IContent
#region Implementation of IContent
///
+ [JsonIgnore]
public bool InitialRemoteWait { get; set; }
///
+ // [JsonIgnore]
public bool IsStreaming { get; set; }
///
+ [JsonIgnore]
public Func StreamingDone { get; set; } = () => Task.CompletedTask;
+ ///
+ [JsonIgnore]
public Func StreamingEvent { get; set; } = () => Task.CompletedTask;
///
diff --git a/app/MindWork AI Studio/Chat/IContent.cs b/app/MindWork AI Studio/Chat/IContent.cs
index e8dcd4d6..8f6bc0ad 100644
--- a/app/MindWork AI Studio/Chat/IContent.cs
+++ b/app/MindWork AI Studio/Chat/IContent.cs
@@ -1,3 +1,5 @@
+using System.Text.Json.Serialization;
+
using AIStudio.Provider;
using AIStudio.Settings;
@@ -6,6 +8,8 @@ namespace AIStudio.Chat;
///
/// The interface for any content in the chat.
///
+[JsonDerivedType(typeof(ContentText), typeDiscriminator: "text")]
+[JsonDerivedType(typeof(ContentImage), typeDiscriminator: "image")]
public interface IContent
{
///
@@ -13,22 +17,26 @@ public interface IContent
/// Does not indicate that the stream is finished; it only indicates that we are
/// waiting for the first response, i.e., wait for the remote to pick up the request.
///
+ [JsonIgnore]
public bool InitialRemoteWait { get; set; }
///
/// Indicates whether the content is streaming right now. False, if the content is
/// either static or the stream has finished.
///
+ [JsonIgnore]
public bool IsStreaming { get; set; }
///
/// An action that is called when the content was changed during streaming.
///
+ [JsonIgnore]
public Func StreamingEvent { get; set; }
///
/// An action that is called when the streaming is done.
///
+ [JsonIgnore]
public Func StreamingDone { get; set; }
///
diff --git a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
index 0a166d69..50b50bb9 100644
--- a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
+++ b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
@@ -13,6 +13,7 @@ public readonly record struct Log(int Build, string Display, string Filename)
public static readonly Log[] LOGS =
[
+ new (160, "v0.7.0, build 160 (2024-07-13 08:21 UTC)", "v0.7.0.md"),
new (159, "v0.6.3, build 159 (2024-07-03 18:26 UTC)", "v0.6.3.md"),
new (158, "v0.6.2, build 158 (2024-07-01 18:03 UTC)", "v0.6.2.md"),
new (157, "v0.6.1, build 157 (2024-06-30 19:00 UTC)", "v0.6.1.md"),
diff --git a/app/MindWork AI Studio/Components/Blocks/ITreeItem.cs b/app/MindWork AI Studio/Components/Blocks/ITreeItem.cs
new file mode 100644
index 00000000..ad718e71
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/ITreeItem.cs
@@ -0,0 +1,3 @@
+namespace AIStudio.Components.Blocks;
+
+public interface ITreeItem;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor.cs b/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor.cs
index 4dee88c7..22483e78 100644
--- a/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor.cs
+++ b/app/MindWork AI Studio/Components/Blocks/InnerScrolling.razor.cs
@@ -51,6 +51,11 @@ protected override async Task OnInitializedAsync()
return Task.CompletedTask;
}
+ public override Task ProcessMessageWithResult(ComponentBase? sendingComponent, Event triggeredEvent, TPayload? data) where TResult : default where TPayload : default
+ {
+ return Task.FromResult(default(TResult));
+ }
+
#endregion
private string Height => $"height: calc(100vh - {this.HeaderHeight} - {this.MainLayout.AdditionalHeight});";
diff --git a/app/MindWork AI Studio/Components/Blocks/TreeButton.cs b/app/MindWork AI Studio/Components/Blocks/TreeButton.cs
new file mode 100644
index 00000000..ff7eaa5c
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/TreeButton.cs
@@ -0,0 +1,3 @@
+namespace AIStudio.Components.Blocks;
+
+public readonly record struct TreeButton(WorkspaceBranch Branch, int Depth, string Text, string Icon, Func Action) : ITreeItem;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/TreeDivider.cs b/app/MindWork AI Studio/Components/Blocks/TreeDivider.cs
new file mode 100644
index 00000000..6c311272
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/TreeDivider.cs
@@ -0,0 +1,3 @@
+namespace AIStudio.Components.Blocks;
+
+public readonly record struct TreeDivider : ITreeItem;
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/TreeItemData.cs b/app/MindWork AI Studio/Components/Blocks/TreeItemData.cs
new file mode 100644
index 00000000..aa96877a
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/TreeItemData.cs
@@ -0,0 +1,22 @@
+namespace AIStudio.Components.Blocks;
+
+public class TreeItemData : ITreeItem
+{
+ public WorkspaceBranch Branch { get; init; } = WorkspaceBranch.NONE;
+
+ public int Depth { get; init; }
+
+ public string Text { get; init; } = string.Empty;
+
+ public string ShortenedText => Text.Length > 30 ? this.Text[..30] + "..." : this.Text;
+
+ public string Icon { get; init; } = string.Empty;
+
+ public TreeItemType Type { get; init; }
+
+ public string Path { get; init; } = string.Empty;
+
+ public bool Expandable { get; init; } = true;
+
+ public HashSet Children { get; init; } = [];
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/TreeItemType.cs b/app/MindWork AI Studio/Components/Blocks/TreeItemType.cs
new file mode 100644
index 00000000..de860ab9
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/TreeItemType.cs
@@ -0,0 +1,9 @@
+namespace AIStudio.Components.Blocks;
+
+public enum TreeItemType
+{
+ NONE,
+
+ CHAT,
+ WORKSPACE,
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/WorkspaceBranch.cs b/app/MindWork AI Studio/Components/Blocks/WorkspaceBranch.cs
new file mode 100644
index 00000000..1b19bd34
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/WorkspaceBranch.cs
@@ -0,0 +1,9 @@
+namespace AIStudio.Components.Blocks;
+
+public enum WorkspaceBranch
+{
+ NONE,
+
+ WORKSPACES,
+ TEMPORARY_CHATS,
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/Workspaces.razor b/app/MindWork AI Studio/Components/Blocks/Workspaces.razor
new file mode 100644
index 00000000..e45fea7a
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/Workspaces.razor
@@ -0,0 +1,88 @@
+
+
+ @switch (item)
+ {
+ case TreeDivider:
+
+
+
+ break;
+
+ case TreeItemData treeItem:
+ @if (treeItem.Type is TreeItemType.CHAT)
+ {
+
+
+