From 00f19aa2135382cc1b25414a8483e79912af013a Mon Sep 17 00:00:00 2001 From: Casey Waldren Date: Mon, 18 Nov 2024 15:41:49 -0800 Subject: [PATCH 1/4] feat: support multi-kind contexts in template interpolation --- pkgs/sdk/server-ai/src/LdAiClient.cs | 39 +++++++++++++++---- pkgs/sdk/server-ai/test/InterpolationTests.cs | 25 ++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/pkgs/sdk/server-ai/src/LdAiClient.cs b/pkgs/sdk/server-ai/src/LdAiClient.cs index ea227e7..522bcb6 100644 --- a/pkgs/sdk/server-ai/src/LdAiClient.cs +++ b/pkgs/sdk/server-ai/src/LdAiClient.cs @@ -97,6 +97,25 @@ public ILdAiConfigTracker ModelConfig(string key, Context context, LdAiConfig de } + + private static IDictionary AddSingleKindContextAttributes(Context context) + { + var attributes = new Dictionary + { + ["kind"] = context.Kind.ToString(), + ["key"] = context.Key, + ["anonymous"] = context.Anonymous + }; + + foreach (var key in context.OptionalAttributeNames) + { + attributes[key] = ValueToObject(context.GetValue(AttributeRef.FromLiteral(key))); + } + + return attributes; + } + + /// /// Retrieves all attributes from the given context, including private attributes. The attributes /// are converted into C# primitives recursively. @@ -105,17 +124,23 @@ public ILdAiConfigTracker ModelConfig(string key, Context context, LdAiConfig de /// the attributes private static IDictionary GetAllAttributes(Context context) { - var attributes = new Dictionary(); - foreach (var key in context.OptionalAttributeNames) + if (!context.Multiple) { - attributes[key] = ValueToObject(context.GetValue(AttributeRef.FromLiteral(key))); + return AddSingleKindContextAttributes(context); } - attributes["kind"] = context.Kind.ToString(); - attributes["key"] = context.Key; - attributes["anonymous"] = context.Anonymous; + var attrs = new Dictionary + { + ["kind"] = context.Kind, + ["key"] = context.FullyQualifiedKey + }; - return attributes; + foreach (var kind in context.MultiKindContexts) + { + attrs[kind.Kind.ToString()] = AddSingleKindContextAttributes(kind); + } + + return attrs; } /// diff --git a/pkgs/sdk/server-ai/test/InterpolationTests.cs b/pkgs/sdk/server-ai/test/InterpolationTests.cs index d7ddf16..e7bbe8a 100644 --- a/pkgs/sdk/server-ai/test/InterpolationTests.cs +++ b/pkgs/sdk/server-ai/test/InterpolationTests.cs @@ -170,4 +170,29 @@ public void TestInterpolationWithNestedContextAttributes() var result = Eval("I can ingest over {{ ldctx.stats.power }} tokens per second!", context, null); Assert.Equal("I can ingest over 9000 tokens per second!", result); } + + [Fact] + public void TestInterpolationWithMultiKindContext() + { + var user = Context.Builder(ContextKind.Default, "123") + .Set("cat_ownership", LdValue.ObjectFrom(new Dictionary + { + { "count", LdValue.Of(12) } + })).Build(); + + var cat= Context.Builder(ContextKind.Of("cat"), "456") + .Set("health", LdValue.ObjectFrom(new Dictionary + { + { "hunger", LdValue.Of("off the charts") } + })).Build(); + + var context = Context.MultiBuilder().Add(user).Add(cat).Build(); + + var nestedVars = Eval("As an owner of {{ ldctx.user.cat_ownership.count }} cats, I must report that my cat's hunger level is {{ ldctx.cat.health.hunger }}!", context, null); + Assert.Equal("As an owner of 12 cats, I must report that my cat's hunger level is off the charts!", nestedVars); + + var canonicalKeys = Eval("multi={{ ldctx.key }} user={{ ldctx.user.key }} cat={{ ldctx.cat.key }}", context, null); + Assert.Equal("multi=cat:456:user:123 user=123 cat=456", canonicalKeys); + + } } From ab7c41e67c01c6871c24b867641d0f8ae07d69e3 Mon Sep 17 00:00:00 2001 From: Casey Waldren Date: Mon, 18 Nov 2024 16:17:03 -0800 Subject: [PATCH 2/4] more tests --- pkgs/sdk/server-ai/test/InterpolationTests.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/pkgs/sdk/server-ai/test/InterpolationTests.cs b/pkgs/sdk/server-ai/test/InterpolationTests.cs index e7bbe8a..fe23d3a 100644 --- a/pkgs/sdk/server-ai/test/InterpolationTests.cs +++ b/pkgs/sdk/server-ai/test/InterpolationTests.cs @@ -193,6 +193,47 @@ public void TestInterpolationWithMultiKindContext() var canonicalKeys = Eval("multi={{ ldctx.key }} user={{ ldctx.user.key }} cat={{ ldctx.cat.key }}", context, null); Assert.Equal("multi=cat:456:user:123 user=123 cat=456", canonicalKeys); + } + + [Fact] + public void TestInterpolationMultiKindDoesNotHaveAnonymousAttribute() + { + var user = Context.Builder(ContextKind.Default, "123") + .Set("cat_ownership", LdValue.ObjectFrom(new Dictionary + { + { "count", LdValue.Of(12) } + })).Build(); + + var cat= Context.Builder(ContextKind.Of("cat"), "456") + .Set("health", LdValue.ObjectFrom(new Dictionary + { + { "hunger", LdValue.Of("off the charts") } + })).Build(); + + var context = Context.MultiBuilder().Add(user).Add(cat).Build(); + + var result = Eval("anonymous=<{{ ldctx.anonymous }}>", context, null); + Assert.Equal("anonymous=<>", result); + } + + [Fact] + public void TestInterpolationMultiKindContextHasKindMulti() + { + var user = Context.Builder(ContextKind.Default, "123") + .Set("cat_ownership", LdValue.ObjectFrom(new Dictionary + { + { "count", LdValue.Of(12) } + })).Build(); + + var cat= Context.Builder(ContextKind.Of("cat"), "456") + .Set("health", LdValue.ObjectFrom(new Dictionary + { + { "hunger", LdValue.Of("off the charts") } + })).Build(); + + var context = Context.MultiBuilder().Add(user).Add(cat).Build(); + var result = Eval("kind={{ ldctx.kind }}", context, null); + Assert.Equal("kind=multi", result); } } From 4eeaca681d6e7851437b79379413c40b88f47045 Mon Sep 17 00:00:00 2001 From: Casey Waldren Date: Tue, 19 Nov 2024 11:54:15 -0800 Subject: [PATCH 3/4] spacing' --- pkgs/sdk/server-ai/test/InterpolationTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/sdk/server-ai/test/InterpolationTests.cs b/pkgs/sdk/server-ai/test/InterpolationTests.cs index fe23d3a..87b18a1 100644 --- a/pkgs/sdk/server-ai/test/InterpolationTests.cs +++ b/pkgs/sdk/server-ai/test/InterpolationTests.cs @@ -180,7 +180,7 @@ public void TestInterpolationWithMultiKindContext() { "count", LdValue.Of(12) } })).Build(); - var cat= Context.Builder(ContextKind.Of("cat"), "456") + var cat = Context.Builder(ContextKind.Of("cat"), "456") .Set("health", LdValue.ObjectFrom(new Dictionary { { "hunger", LdValue.Of("off the charts") } @@ -225,7 +225,7 @@ public void TestInterpolationMultiKindContextHasKindMulti() { "count", LdValue.Of(12) } })).Build(); - var cat= Context.Builder(ContextKind.Of("cat"), "456") + var cat = Context.Builder(ContextKind.Of("cat"), "456") .Set("health", LdValue.ObjectFrom(new Dictionary { { "hunger", LdValue.Of("off the charts") } From 0e38f1eb969e9f1976e2c701a9bfbc151d26fd0d Mon Sep 17 00:00:00 2001 From: Casey Waldren Date: Tue, 19 Nov 2024 11:54:38 -0800 Subject: [PATCH 4/4] Update pkgs/sdk/server-ai/test/InterpolationTests.cs Co-authored-by: Matthew M. Keeler --- pkgs/sdk/server-ai/test/InterpolationTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/sdk/server-ai/test/InterpolationTests.cs b/pkgs/sdk/server-ai/test/InterpolationTests.cs index 87b18a1..eb5c6b4 100644 --- a/pkgs/sdk/server-ai/test/InterpolationTests.cs +++ b/pkgs/sdk/server-ai/test/InterpolationTests.cs @@ -204,7 +204,7 @@ public void TestInterpolationMultiKindDoesNotHaveAnonymousAttribute() { "count", LdValue.Of(12) } })).Build(); - var cat= Context.Builder(ContextKind.Of("cat"), "456") + var cat = Context.Builder(ContextKind.Of("cat"), "456") .Set("health", LdValue.ObjectFrom(new Dictionary { { "hunger", LdValue.Of("off the charts") }