Skip to content

Commit f276506

Browse files
authored
Remove Default term from the connection specific deployment names (#319)
1 parent ec88ce9 commit f276506

File tree

32 files changed

+348
-137
lines changed

32 files changed

+348
-137
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using System.Text.Json;
2+
using System.Text.Json.Nodes;
3+
using System.Text.Json.Serialization;
4+
using CrestApps.OrchardCore.AI.Models;
5+
6+
namespace CrestApps.OrchardCore.AI.Json;
7+
8+
public sealed class AIProviderConnectionJsonConverter : JsonConverter<AIProviderConnection>
9+
{
10+
public override AIProviderConnection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
11+
{
12+
var node = JsonNode.Parse(ref reader)?.AsObject();
13+
14+
if (node == null)
15+
{
16+
return null;
17+
}
18+
19+
var connection = new AIProviderConnection
20+
{
21+
ItemId = GetString(node, nameof(AIProviderConnection.ItemId)),
22+
Source = GetString(node, nameof(AIProviderConnection.Source))
23+
?? GetString(node, "ProviderName"),
24+
Name = GetString(node, nameof(AIProviderConnection.Name)),
25+
DisplayText = GetString(node, nameof(AIProviderConnection.DisplayText)),
26+
ChatDeploymentName = GetString(node, nameof(AIProviderConnection.ChatDeploymentName))
27+
?? GetString(node, "DefaultDeploymentName"),
28+
EmbeddingDeploymentName = GetString(node, nameof(AIProviderConnection.EmbeddingDeploymentName))
29+
?? GetString(node, "DefaultEmbeddingDeploymentName"),
30+
ImagesDeploymentName = GetString(node, nameof(AIProviderConnection.ImagesDeploymentName))
31+
?? GetString(node, "DefaultImagesDeploymentName"),
32+
UtilityDeploymentName = GetString(node, nameof(AIProviderConnection.UtilityDeploymentName))
33+
?? GetString(node, "DefaultUtilityDeploymentName"),
34+
IsDefault = GetBool(node, nameof(AIProviderConnection.IsDefault)),
35+
CreatedUtc = GetDateTime(node, nameof(AIProviderConnection.CreatedUtc)),
36+
Author = GetString(node, nameof(AIProviderConnection.Author)),
37+
OwnerId = GetString(node, nameof(AIProviderConnection.OwnerId)),
38+
};
39+
40+
if (node.TryGetPropertyValue(nameof(AIProviderConnection.Properties), out var propertiesNode)
41+
&& propertiesNode is JsonObject properties)
42+
{
43+
// Detach from parent before assigning.
44+
node.Remove(nameof(AIProviderConnection.Properties));
45+
connection.Properties = properties;
46+
}
47+
48+
return connection;
49+
}
50+
51+
public override void Write(Utf8JsonWriter writer, AIProviderConnection value, JsonSerializerOptions options)
52+
{
53+
writer.WriteStartObject();
54+
55+
WriteString(writer, nameof(AIProviderConnection.ItemId), value.ItemId);
56+
WriteString(writer, nameof(AIProviderConnection.Source), value.Source);
57+
WriteString(writer, nameof(AIProviderConnection.Name), value.Name);
58+
WriteString(writer, nameof(AIProviderConnection.DisplayText), value.DisplayText);
59+
WriteString(writer, nameof(AIProviderConnection.ChatDeploymentName), value.ChatDeploymentName);
60+
WriteString(writer, nameof(AIProviderConnection.EmbeddingDeploymentName), value.EmbeddingDeploymentName);
61+
WriteString(writer, nameof(AIProviderConnection.ImagesDeploymentName), value.ImagesDeploymentName);
62+
WriteString(writer, nameof(AIProviderConnection.UtilityDeploymentName), value.UtilityDeploymentName);
63+
writer.WriteBoolean(nameof(AIProviderConnection.IsDefault), value.IsDefault);
64+
writer.WriteString(nameof(AIProviderConnection.CreatedUtc), value.CreatedUtc);
65+
WriteString(writer, nameof(AIProviderConnection.Author), value.Author);
66+
WriteString(writer, nameof(AIProviderConnection.OwnerId), value.OwnerId);
67+
68+
writer.WritePropertyName(nameof(AIProviderConnection.Properties));
69+
70+
if (value.Properties != null)
71+
{
72+
value.Properties.WriteTo(writer, options);
73+
}
74+
else
75+
{
76+
writer.WriteStartObject();
77+
writer.WriteEndObject();
78+
}
79+
80+
writer.WriteEndObject();
81+
}
82+
83+
private static string GetString(JsonObject node, string name)
84+
{
85+
if (node.TryGetPropertyValue(name, out var value) && value != null)
86+
{
87+
return value.GetValue<string>();
88+
}
89+
90+
return null;
91+
}
92+
93+
private static bool GetBool(JsonObject node, string name)
94+
{
95+
if (node.TryGetPropertyValue(name, out var value) && value != null)
96+
{
97+
return value.GetValue<bool>();
98+
}
99+
100+
return false;
101+
}
102+
103+
private static DateTime GetDateTime(JsonObject node, string name)
104+
{
105+
if (node.TryGetPropertyValue(name, out var value) && value != null)
106+
{
107+
return value.GetValue<DateTime>();
108+
}
109+
110+
return default;
111+
}
112+
113+
private static void WriteString(Utf8JsonWriter writer, string name, string value)
114+
{
115+
if (value != null)
116+
{
117+
writer.WriteString(name, value);
118+
}
119+
else
120+
{
121+
writer.WriteNull(name);
122+
}
123+
}
124+
}
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
using System.Text.Json.Nodes;
21
using System.Text.Json.Serialization;
2+
using CrestApps.OrchardCore.AI.Json;
33
using CrestApps.OrchardCore.Models;
44
using CrestApps.OrchardCore.Services;
55

66
namespace CrestApps.OrchardCore.AI.Models;
77

8+
[JsonConverter(typeof(AIProviderConnectionJsonConverter))]
89
public sealed class AIProviderConnection : SourceCatalogEntry, INameAwareModel, IDisplayTextAwareModel, ICloneable<AIProviderConnection>
910
{
1011
public string Name { get; set; }
1112

1213
public string DisplayText { get; set; }
1314

14-
public string DefaultDeploymentName { get; set; }
15+
public string ChatDeploymentName { get; set; }
1516

16-
public string DefaultEmbeddingDeploymentName { get; set; }
17+
public string EmbeddingDeploymentName { get; set; }
1718

18-
public string DefaultImagesDeploymentName { get; set; }
19+
public string ImagesDeploymentName { get; set; }
1920

20-
public string DefaultUtilityDeploymentName { get; set; }
21+
public string UtilityDeploymentName { get; set; }
2122

2223
public bool IsDefault { get; set; }
2324

@@ -28,13 +29,6 @@ public string ProviderName
2829
set => Source = value;
2930
}
3031

31-
[JsonInclude]
32-
[JsonPropertyName(nameof(ProviderName))]
33-
private string _providerNameBackingField
34-
{
35-
set => Source = value;
36-
}
37-
3832
public DateTime CreatedUtc { get; set; }
3933

4034
public string Author { get; set; }
@@ -50,14 +44,14 @@ public AIProviderConnection Clone()
5044
Name = Name,
5145
DisplayText = DisplayText,
5246
IsDefault = IsDefault,
53-
DefaultDeploymentName = DefaultDeploymentName,
54-
DefaultEmbeddingDeploymentName = DefaultEmbeddingDeploymentName,
55-
DefaultImagesDeploymentName = DefaultImagesDeploymentName,
56-
DefaultUtilityDeploymentName = DefaultUtilityDeploymentName,
47+
ChatDeploymentName = ChatDeploymentName,
48+
EmbeddingDeploymentName = EmbeddingDeploymentName,
49+
ImagesDeploymentName = ImagesDeploymentName,
50+
UtilityDeploymentName = UtilityDeploymentName,
5751
CreatedUtc = CreatedUtc,
5852
Author = Author,
5953
OwnerId = OwnerId,
60-
Properties = Properties.Clone(),
54+
Properties = Properties.DeepClone().AsObject(),
6155
};
6256
}
6357
}

src/Abstractions/CrestApps.OrchardCore.AI.Abstractions/Models/AIProviderOptions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ public sealed class AIProvider
1313
{
1414
public string DefaultConnectionName { get; set; }
1515

16-
public string DefaultDeploymentName { get; set; }
16+
public string DefaultChatDeploymentName { get; set; }
17+
18+
public string DefaultEmbeddingDeploymentName { get; set; }
19+
20+
public string DefaultImagesDeploymentName { get; set; }
21+
22+
public string DefaultUtilityDeploymentName { get; set; }
1723

1824
public IDictionary<string, AIProviderConnectionEntry> Connections { get; set; }
1925
}

src/Core/CrestApps.OrchardCore.AI.Core/DictionaryExtensions.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,34 @@ public static Uri GetEndpoint(this IDictionary<string, object> entry, bool throw
2525
return uri;
2626
}
2727

28-
public static string GetDefaultDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
29-
=> entry.GetStringValue("DefaultDeploymentName", throwException);
28+
public static string GetChatDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
29+
=> entry.GetStringValue("ChatDeploymentName", throwException);
3030

31-
public static string GetDefaultEmbeddingDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
32-
=> entry.GetStringValue("DefaultEmbeddingDeploymentName", throwException);
31+
public static string GetEmbeddingDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
32+
=> entry.GetStringValue("EmbeddingDeploymentName", throwException);
3333

34-
public static string GetDefaultImagesDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
35-
=> entry.GetStringValue("DefaultImagesDeploymentName", throwException);
34+
public static string GetImagesDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
35+
=> entry.GetStringValue("ImagesDeploymentName", throwException);
3636

37-
public static string GetDefaultUtilityDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
38-
=> entry.GetStringValue("DefaultUtilityDeploymentName", throwException);
37+
public static string GetUtilityDeploymentName(this IDictionary<string, object> entry, bool throwException = true)
38+
=> entry.GetStringValue("UtilityDeploymentName", throwException);
39+
40+
public static string GetChatDeploymentOrDefaultName(this IDictionary<string, object> entry, bool throwException = true)
41+
=> entry.GetStringValue("ChatDeploymentName", false)
42+
?? entry.GetStringValue("DeploymentName", false)
43+
?? entry.GetStringValue("DefaultDeploymentName", throwException);
44+
45+
public static string GetEmbeddingDeploymentOrDefaultName(this IDictionary<string, object> entry, bool throwException = true)
46+
=> entry.GetStringValue("EmbeddingDeploymentName", false)
47+
?? entry.GetStringValue("DefaultEmbeddingDeploymentName", throwException);
48+
49+
public static string GetImagesDeploymentOrDefaultName(this IDictionary<string, object> entry, bool throwException = true)
50+
=> entry.GetStringValue("ImagesDeploymentName", false)
51+
?? entry.GetStringValue("DefaultImagesDeploymentName", throwException);
52+
53+
public static string GetUtilityDeploymentOrDefaultName(this IDictionary<string, object> entry, bool throwException = true)
54+
=> entry.GetStringValue("UtilityDeploymentName", false)
55+
?? entry.GetStringValue("DefaultUtilityDeploymentName", throwException);
3956

4057
public static string GetStringValue(this IDictionary<string, object> entry, string key, bool throwException = false)
4158
{

src/Core/CrestApps.OrchardCore.AI.Core/Handlers/AIProviderConnectionHandler.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ public override async Task ValidatingAsync(ValidatingContext<AIProviderConnectio
6666
context.Result.Fail(new ValidationResult(S["Invalid source."], [nameof(AIProviderConnection.Source)]));
6767
}
6868

69-
if (string.IsNullOrWhiteSpace(context.Model.DefaultDeploymentName))
69+
if (string.IsNullOrWhiteSpace(context.Model.ChatDeploymentName))
7070
{
71-
context.Result.Fail(new ValidationResult(S["Deployment name is required."], [nameof(AIProviderConnection.DefaultDeploymentName)]));
71+
context.Result.Fail(new ValidationResult(S["Chat Deployment name is required."], [nameof(AIProviderConnection.ChatDeploymentName)]));
7272
}
7373
}
7474

@@ -99,18 +99,32 @@ private static Task PopulateAsync(AIProviderConnection connection, JsonNode data
9999
}
100100
}
101101

102-
var defaultDeploymentName = data[nameof(AIProviderConnection.DefaultDeploymentName)]?.GetValue<string>()?.Trim();
102+
var defaultDeploymentName = data[nameof(AIProviderConnection.ChatDeploymentName)]?.GetValue<string>()?.Trim();
103103

104104
if (!string.IsNullOrEmpty(defaultDeploymentName))
105105
{
106-
connection.DefaultDeploymentName = defaultDeploymentName;
106+
connection.ChatDeploymentName = defaultDeploymentName;
107107
}
108108

109-
var defaultUtilityDeploymentName = data[nameof(AIProviderConnection.DefaultUtilityDeploymentName)]?.GetValue<string>()?.Trim();
109+
var defaultUtilityDeploymentName = data[nameof(AIProviderConnection.UtilityDeploymentName)]?.GetValue<string>()?.Trim();
110110

111111
if (!string.IsNullOrEmpty(defaultUtilityDeploymentName))
112112
{
113-
connection.DefaultUtilityDeploymentName = defaultUtilityDeploymentName;
113+
connection.UtilityDeploymentName = defaultUtilityDeploymentName;
114+
}
115+
116+
var embeddingDeploymentName = data[nameof(AIProviderConnection.EmbeddingDeploymentName)]?.GetValue<string>()?.Trim();
117+
118+
if (!string.IsNullOrEmpty(embeddingDeploymentName))
119+
{
120+
connection.EmbeddingDeploymentName = embeddingDeploymentName;
121+
}
122+
123+
var imagesDeploymentName = data[nameof(AIProviderConnection.ImagesDeploymentName)]?.GetValue<string>()?.Trim();
124+
125+
if (!string.IsNullOrEmpty(imagesDeploymentName))
126+
{
127+
connection.ImagesDeploymentName = imagesDeploymentName;
114128
}
115129

116130
var isDefault = data[nameof(AIProviderConnection.IsDefault)]?.GetValue<bool>();

src/Core/CrestApps.OrchardCore.AI.Core/Orchestration/DefaultOrchestrator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -443,11 +443,11 @@ private async Task<IChatClient> TryCreateUtilityChatClientAsync(OrchestrationCon
443443
}
444444

445445
// Prefer the utility deployment, fall back to the default deployment.
446-
var deploymentName = connection.GetDefaultUtilityDeploymentName(throwException: false);
446+
var deploymentName = connection.GetUtilityDeploymentOrDefaultName(throwException: false);
447447

448448
if (string.IsNullOrEmpty(deploymentName))
449449
{
450-
deploymentName = connection.GetDefaultDeploymentName(throwException: false);
450+
deploymentName = connection.GetChatDeploymentOrDefaultName(throwException: false);
451451
}
452452

453453
if (string.IsNullOrEmpty(deploymentName))

src/Core/CrestApps.OrchardCore.AI.Core/Services/AIClientProviderBase.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public ValueTask<IChatClient> GetChatClientAsync(AIProviderConnectionEntry conne
1919
{
2020
if (string.IsNullOrEmpty(deploymentName))
2121
{
22-
deploymentName = connection.GetDefaultDeploymentName(false);
22+
deploymentName = connection.GetChatDeploymentOrDefaultName(false);
2323
}
2424

2525
if (string.IsNullOrEmpty(deploymentName))
@@ -38,7 +38,7 @@ public ValueTask<IEmbeddingGenerator<string, Embedding<float>>> GetEmbeddingGene
3838
{
3939
if (string.IsNullOrEmpty(deploymentName))
4040
{
41-
deploymentName = connection.GetDefaultEmbeddingDeploymentName(false);
41+
deploymentName = connection.GetEmbeddingDeploymentOrDefaultName(false);
4242
}
4343

4444
if (string.IsNullOrEmpty(deploymentName))
@@ -59,7 +59,7 @@ public ValueTask<IImageGenerator> GetImageGeneratorAsync(AIProviderConnectionEnt
5959
{
6060
if (string.IsNullOrEmpty(deploymentName))
6161
{
62-
deploymentName = connection.GetDefaultImagesDeploymentName(false);
62+
deploymentName = connection.GetImagesDeploymentOrDefaultName(false);
6363
}
6464

6565
if (string.IsNullOrEmpty(deploymentName))

src/Core/CrestApps.OrchardCore.AI.Core/Services/AICompletionServiceBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ protected virtual string GetDefaultDeploymentName(AIProvider provider, string co
2525
{
2626
if (connectionName is not null && provider.Connections.TryGetValue(connectionName, out var connection))
2727
{
28-
var deploymentName = connection.GetDefaultDeploymentName();
28+
var deploymentName = connection.GetChatDeploymentOrDefaultName();
2929

3030
if (!string.IsNullOrEmpty(deploymentName))
3131
{
3232
return deploymentName;
3333
}
3434
}
3535

36-
return provider.DefaultDeploymentName;
36+
return provider.DefaultChatDeploymentName;
3737
}
3838

3939
protected static int GetTotalMessagesToSkip(int totalMessages, int pastMessageCount)

src/Core/CrestApps.OrchardCore.AI.Core/Services/AIProviderConnectionsOptionsConfiguration.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,10 @@ public void Configure(AIProviderOptions options)
6464
defaultConnection = connection;
6565
}
6666

67-
mappingContext.Values["DefaultDeploymentName"] = connection.DefaultDeploymentName;
68-
mappingContext.Values["DefaultEmbeddingDeploymentName"] = connection.DefaultEmbeddingDeploymentName;
69-
mappingContext.Values["DefaultUtilityDeploymentName"] = connection.DefaultUtilityDeploymentName;
67+
mappingContext.Values["ChatDeploymentName"] = connection.ChatDeploymentName;
68+
mappingContext.Values["EmbeddingDeploymentName"] = connection.EmbeddingDeploymentName;
69+
mappingContext.Values["UtilityDeploymentName"] = connection.UtilityDeploymentName;
70+
mappingContext.Values["ImagesDeploymentName"] = connection.ImagesDeploymentName;
7071
mappingContext.Values["ConnectionNameAlias"] = connection.Name;
7172

7273
_handlers.Invoke((handler, ctx) => handler.Initializing(ctx), mappingContext, _logger);
@@ -77,13 +78,13 @@ public void Configure(AIProviderOptions options)
7778
if (defaultConnection is not null)
7879
{
7980
provider.DefaultConnectionName = defaultConnection.ItemId;
80-
provider.DefaultDeploymentName = defaultConnection.DefaultDeploymentName;
81+
provider.DefaultChatDeploymentName = defaultConnection.ChatDeploymentName;
8182
}
8283
else
8384
{
84-
if (string.IsNullOrEmpty(provider.DefaultDeploymentName))
85+
if (string.IsNullOrEmpty(provider.DefaultChatDeploymentName))
8586
{
86-
provider.DefaultDeploymentName = provider.Connections.FirstOrDefault().Value.GetDefaultDeploymentName();
87+
provider.DefaultChatDeploymentName = provider.Connections.FirstOrDefault().Value.GetChatDeploymentOrDefaultName();
8788
}
8889

8990
if (string.IsNullOrEmpty(provider.DefaultConnectionName))

src/Core/CrestApps.OrchardCore.AI.Core/Services/PreemptiveSearchQueryProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,11 @@ private async Task<IChatClient> TryCreateUtilityChatClientAsync(OrchestrationCon
193193
}
194194

195195
// Prefer the utility deployment, fall back to the default deployment.
196-
var deploymentName = connection.GetDefaultUtilityDeploymentName(throwException: false);
196+
var deploymentName = connection.GetUtilityDeploymentOrDefaultName(throwException: false);
197197

198198
if (string.IsNullOrEmpty(deploymentName))
199199
{
200-
deploymentName = connection.GetDefaultDeploymentName(throwException: false);
200+
deploymentName = connection.GetChatDeploymentOrDefaultName(throwException: false);
201201
}
202202

203203
if (string.IsNullOrEmpty(deploymentName))

0 commit comments

Comments
 (0)