Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions pkgs/sdk/server-ai/src/Config/ConfigFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ public LdAiCompletionConfig BuildCompletionConfig(

var (enabled, variationKey, version, mode) = ParseMeta(ldValue);

// A disabled variation is served as {"_ldMeta": {"enabled": false}} with no mode field,
// so check the disabled state before comparing mode. Otherwise the missing mode defaults
// to "completion" and trips the mode-mismatch path for agent and judge callers.
if (!enabled)
{
return new LdAiCompletionConfig(
key,
enabled: false,
variationKey,
version,
messages: new List<LdAiConfigTypes.Message>(),
tools: ImmutableDictionary<string, LdAiConfigTypes.Tool>.Empty,
judgeConfiguration: null,
model: null,
provider: null,
trackerFactory);
}

if (mode != LdAiCompletionConfig.Mode)
{
_logger.Warn(
Expand Down Expand Up @@ -117,6 +135,24 @@ public LdAiAgentConfig BuildAgentConfig(

var (enabled, variationKey, version, mode) = ParseMeta(ldValue);

// A disabled variation is served as {"_ldMeta": {"enabled": false}} with no mode field,
// so check the disabled state before comparing mode. Otherwise the missing mode defaults
// to "completion" and trips the mode-mismatch path for agent and judge callers.
if (!enabled)
{
return new LdAiAgentConfig(
key,
enabled: false,
variationKey,
version,
instructions: null,
tools: ImmutableDictionary<string, LdAiConfigTypes.Tool>.Empty,
model: null,
provider: null,
judgeConfiguration: null,
trackerFactory);
}

if (mode != LdAiAgentConfig.Mode)
{
_logger.Warn(
Expand Down Expand Up @@ -184,6 +220,23 @@ public LdAiJudgeConfig BuildJudgeConfig(

var (enabled, variationKey, version, mode) = ParseMeta(ldValue);

// A disabled variation is served as {"_ldMeta": {"enabled": false}} with no mode field,
// so check the disabled state before comparing mode. Otherwise the missing mode defaults
// to "completion" and trips the mode-mismatch path for agent and judge callers.
if (!enabled)
{
return new LdAiJudgeConfig(
key,
enabled: false,
variationKey,
version,
messages: new List<LdAiConfigTypes.Message>(),
evaluationMetricKey: null,
model: null,
provider: null,
trackerFactory);
}

if (mode != LdAiJudgeConfig.Mode)
{
_logger.Warn(
Expand Down
57 changes: 57 additions & 0 deletions pkgs/sdk/server-ai/test/LdAiClientAgentJudgeTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,33 @@ public void AgentConfig_ModeMismatch_ReturnsCallerDefault()
), Times.Once);
}

[Fact]
public void AgentConfig_DisabledVariation_ReturnsDisabledAgentWithoutModeMismatchWarning()
{
var (mockClient, mockLogger, client) = MakeClient();

// A disabled variation is served with no mode field, so its mode defaults to "completion".
const string json = """
{
"_ldMeta": {"variationKey": "v1", "enabled": false}
}
""";

mockClient.Setup(x => x.JsonVariation("agent-key", It.IsAny<Context>(), It.IsAny<LdValue>()))
.Returns(LdValue.Parse(json));

var defaultConfig = LdAiAgentConfigDefault.New().SetInstructions("fallback").Build();
var result = client.AgentConfig("agent-key", Context.New("user"), defaultConfig);

Assert.IsType<LdAiAgentConfig>(result);
Assert.False(result.Enabled);

mockLogger.Verify(x => x.Warn(
It.Is<string>(s => s.Contains("AI Config mode mismatch")),
It.IsAny<object[]>()
), Times.Never);
}

[Fact]
public void AgentConfig_InstructionsInterpolated()
{
Expand Down Expand Up @@ -276,6 +303,36 @@ public void JudgeConfig_ModeMismatch_ReturnsCallerDefault()
Assert.Equal("$ld:ai:judge:fallback", result.EvaluationMetricKey);
}

[Fact]
public void JudgeConfig_DisabledVariation_ReturnsDisabledJudgeWithoutModeMismatchWarning()
{
var (mockClient, mockLogger, client) = MakeClient();

// A disabled variation is served with no mode field, so its mode defaults to "completion".
const string json = """
{
"_ldMeta": {"variationKey": "v1", "enabled": false}
}
""";

mockClient.Setup(x => x.JsonVariation("judge-key", It.IsAny<Context>(), It.IsAny<LdValue>()))
.Returns(LdValue.Parse(json));

var defaultConfig = LdAiJudgeConfigDefault.New()
.SetEvaluationMetricKey("$ld:ai:judge:fallback")
.Build();

var result = client.JudgeConfig("judge-key", Context.New("user"), defaultConfig);

Assert.IsType<LdAiJudgeConfig>(result);
Assert.False(result.Enabled);

mockLogger.Verify(x => x.Warn(
It.Is<string>(s => s.Contains("AI Config mode mismatch")),
It.IsAny<object[]>()
), Times.Never);
}

[Fact]
public void JudgeConfig_FiresUsageEvent()
{
Expand Down
Loading