Skip to content

Commit 7a6cfd5

Browse files
authored
fix: catch exceptions thrown by template interpolation (#43)
This is a first pass at catching exceptions generated by the interpolation process. It wraps each call to interpolate with a try/catch and individually reports an error via the logger.
1 parent 291b366 commit 7a6cfd5

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

pkgs/sdk/server-ai/src/LdAiClient.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,28 @@ public ILdAiConfigTracker ModelConfig(string key, Context context, LdAiConfig de
7373
}
7474

7575

76-
var prompt =
77-
parsed.Prompt?.Select(m => new LdAiConfig.Message(InterpolateTemplate(m.Content, mergedVariables), m.Role));
76+
var prompt = new List<LdAiConfig.Message>();
77+
78+
if (parsed.Prompt != null)
79+
{
80+
for (var i = 0; i < parsed.Prompt.Count; i++)
81+
{
82+
try
83+
{
84+
var content = InterpolateTemplate(parsed.Prompt[i].Content, mergedVariables);
85+
prompt.Add(new LdAiConfig.Message(content, parsed.Prompt[i].Role));
86+
}
87+
catch (Exception ex)
88+
{
89+
_logger.Error(
90+
$"AI model config prompt has malformed message at index {i}: {ex.Message} (returning default config, which will not contain interpolated prompt messages)");
91+
return new LdAiConfigTracker(_client, key, defaultValue, context);
92+
}
93+
}
94+
}
7895

7996
return new LdAiConfigTracker(_client, key, new LdAiConfig(parsed.Meta?.Enabled ?? false, prompt, parsed.Meta, parsed.Model), context);
97+
8098
}
8199

82100
/// <summary>
@@ -137,7 +155,8 @@ private AiConfig ParseConfig(LdValue value, string key)
137155
}
138156
catch (JsonException e)
139157
{
140-
_logger.Error("Unable to parse AI model config for key {0}: {1}", key, e.Message);
158+
_logger.Error(
159+
$"Unable to parse AI model config for key {key}: {e.Message} (returning default config, which will not contain interpolated prompt messages)");
141160
return null;
142161
}
143162
}

pkgs/sdk/server-ai/test/InterpolationTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.Text.Json;
34
using System.Text.Json.Serialization;
@@ -117,6 +118,37 @@ public void TestInterpolationWithArraySectionWorks()
117118
Assert.Equal("hello world ! ", result);
118119
}
119120

121+
[Fact]
122+
public void TestInterpolationMalformed()
123+
{
124+
var mockClient = new Mock<ILaunchDarklyClient>();
125+
var mockLogger = new Mock<ILogger>();
126+
127+
const string configJson = """
128+
{
129+
"_ldMeta": {"versionKey": "1", "enabled": true},
130+
"model": {},
131+
"prompt": [
132+
{
133+
"content": "This is a {{ malformed }]} prompt",
134+
"role": "System"
135+
}
136+
]
137+
}
138+
""";
139+
140+
141+
mockClient.Setup(x =>
142+
x.JsonVariation("foo", It.IsAny<Context>(), It.IsAny<LdValue>())).Returns(LdValue.Parse(configJson));
143+
144+
mockClient.Setup(x => x.GetLogger()).Returns(mockLogger.Object);
145+
146+
mockLogger.Setup(x => x.Error(It.IsAny<string>()));
147+
148+
var client = new LdAiClient(mockClient.Object);
149+
var tracker = client.ModelConfig("foo", Context.New("key"), LdAiConfig.Disabled);
150+
Assert.False(tracker.Config.Enabled);
151+
}
120152

121153
[Fact]
122154
public void TestInterpolationWithBasicContext()

0 commit comments

Comments
 (0)