Extract proactivity decisions into partial

This commit is contained in:
Jacob Dubin
2026-05-22 07:45:14 -05:00
parent 2357e82ae3
commit 2455fcfe17
2 changed files with 106 additions and 97 deletions

View File

@@ -0,0 +1,106 @@
using System.Linq;
using Jibo.Cloud.Application.Abstractions;
using Jibo.Cloud.Domain.Models;
using Jibo.Runtime.Abstractions;
namespace Jibo.Cloud.Application.Services;
public sealed partial class JiboInteractionService
{
private static readonly string[] PizzaPreferenceCategories =
[
"food",
"meal",
"dish",
"dinner",
"lunch",
"snack"
];
private JiboInteractionDecision BuildSurpriseDecision(
JiboExperienceCatalog catalog,
TurnContext turn,
DateTimeOffset? referenceLocalTime)
{
var tenantScope = ResolveTenantScope(turn);
var candidates = BuildProactivityCandidates(tenantScope, referenceLocalTime);
if (candidates.Count == 0)
return new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies));
var highestWeight = candidates.Max(static candidate => candidate.Weight);
var topCandidates = candidates
.Where(candidate => candidate.Weight == highestWeight)
.ToArray();
var selected = topCandidates.Length == 1
? topCandidates[0]
: randomizer.Choose(topCandidates);
return selected.IntentName switch
{
"proactive_pizza_day" => BuildProactivePizzaDayDecision(referenceLocalTime),
"proactive_pizza_preference" => BuildProactivePizzaPreferenceDecision(),
"proactive_offer_pizza_fact" => BuildProactivePizzaFactOfferDecision(),
"proactive_fun_fact" => BuildProactiveFunFactDecision(catalog),
"proactive_joke" => BuildProactiveJokeDecision(catalog),
_ => new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies))
};
}
private List<ProactivityCandidate> BuildProactivityCandidates(
PersonalMemoryTenantScope tenantScope,
DateTimeOffset? referenceLocalTime)
{
var candidates = new List<ProactivityCandidate>();
var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date;
var pizzaSignal = ResolvePizzaSignal(tenantScope);
if (pizzaSignal.Affinity == PersonalAffinity.Dislike) return candidates;
if (referenceDate is { Month: 2, Day: 9 })
{
var holidayWeight = pizzaSignal.Affinity switch
{
PersonalAffinity.Love => 170,
PersonalAffinity.Like => 160,
_ => 150
};
candidates.Add(new ProactivityCandidate("proactive_pizza_day", holidayWeight));
}
if (pizzaSignal.Affinity is PersonalAffinity.Love or PersonalAffinity.Like)
{
var preferenceWeight = pizzaSignal.Affinity == PersonalAffinity.Love ? 140 : 120;
candidates.Add(new ProactivityCandidate("proactive_pizza_preference", preferenceWeight));
candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", preferenceWeight - 5));
return candidates;
}
candidates.Add(new ProactivityCandidate("proactive_fun_fact", 90));
candidates.Add(new ProactivityCandidate("proactive_joke", 90));
candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", 90));
return candidates;
}
private PizzaSignal ResolvePizzaSignal(PersonalMemoryTenantScope tenantScope)
{
var pizzaAffinity = personalMemoryStore.GetAffinity(tenantScope, "pizza");
if (pizzaAffinity is not null) return new PizzaSignal(pizzaAffinity);
var affinityMatch = personalMemoryStore.GetAffinities(tenantScope)
.Where(pair => pair.Key.Contains("pizza", StringComparison.OrdinalIgnoreCase))
.OrderByDescending(static pair =>
pair.Value == PersonalAffinity.Love ? 2 : pair.Value == PersonalAffinity.Like ? 1 : 0)
.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(affinityMatch.Key)) return new PizzaSignal(affinityMatch.Value);
foreach (var category in PizzaPreferenceCategories)
{
var preference = personalMemoryStore.GetPreference(tenantScope, category);
if (!string.IsNullOrWhiteSpace(preference) &&
preference.Contains("pizza", StringComparison.OrdinalIgnoreCase))
return new PizzaSignal(PersonalAffinity.Like);
}
return new PizzaSignal(null);
}
}

View File

@@ -262,16 +262,6 @@ public sealed partial class JiboInteractionService(
("what do i think about ", null)
];
private static readonly string[] PizzaPreferenceCategories =
[
"food",
"meal",
"dish",
"dinner",
"lunch",
"snack"
];
private static readonly HashSet<string> GenericWeatherLocationTerms = new(StringComparer.OrdinalIgnoreCase)
{
"my area",
@@ -1002,93 +992,6 @@ public sealed partial class JiboInteractionService(
SkillPayload: new Dictionary<string, object?> { ["esml"] = OpenJiboCloudBuildInfo.EsmlVersion });
}
private JiboInteractionDecision BuildSurpriseDecision(
JiboExperienceCatalog catalog,
TurnContext turn,
DateTimeOffset? referenceLocalTime)
{
var tenantScope = ResolveTenantScope(turn);
var candidates = BuildProactivityCandidates(tenantScope, referenceLocalTime);
if (candidates.Count == 0)
return new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies));
var highestWeight = candidates.Max(static candidate => candidate.Weight);
var topCandidates = candidates
.Where(candidate => candidate.Weight == highestWeight)
.ToArray();
var selected = topCandidates.Length == 1
? topCandidates[0]
: randomizer.Choose(topCandidates);
return selected.IntentName switch
{
"proactive_pizza_day" => BuildProactivePizzaDayDecision(referenceLocalTime),
"proactive_pizza_preference" => BuildProactivePizzaPreferenceDecision(),
"proactive_offer_pizza_fact" => BuildProactivePizzaFactOfferDecision(),
"proactive_fun_fact" => BuildProactiveFunFactDecision(catalog),
"proactive_joke" => BuildProactiveJokeDecision(catalog),
_ => new JiboInteractionDecision("surprise", randomizer.Choose(catalog.SurpriseReplies))
};
}
private List<ProactivityCandidate> BuildProactivityCandidates(
PersonalMemoryTenantScope tenantScope,
DateTimeOffset? referenceLocalTime)
{
var candidates = new List<ProactivityCandidate>();
var referenceDate = (referenceLocalTime ?? DateTimeOffset.UtcNow).Date;
var pizzaSignal = ResolvePizzaSignal(tenantScope);
if (pizzaSignal.Affinity == PersonalAffinity.Dislike) return candidates;
if (referenceDate is { Month: 2, Day: 9 })
{
var holidayWeight = pizzaSignal.Affinity switch
{
PersonalAffinity.Love => 170,
PersonalAffinity.Like => 160,
_ => 150
};
candidates.Add(new ProactivityCandidate("proactive_pizza_day", holidayWeight));
}
if (pizzaSignal.Affinity is PersonalAffinity.Love or PersonalAffinity.Like)
{
var preferenceWeight = pizzaSignal.Affinity == PersonalAffinity.Love ? 140 : 120;
candidates.Add(new ProactivityCandidate("proactive_pizza_preference", preferenceWeight));
candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", preferenceWeight - 5));
return candidates;
}
candidates.Add(new ProactivityCandidate("proactive_fun_fact", 90));
candidates.Add(new ProactivityCandidate("proactive_joke", 90));
candidates.Add(new ProactivityCandidate("proactive_offer_pizza_fact", 90));
return candidates;
}
private PizzaSignal ResolvePizzaSignal(PersonalMemoryTenantScope tenantScope)
{
var pizzaAffinity = personalMemoryStore.GetAffinity(tenantScope, "pizza");
if (pizzaAffinity is not null) return new PizzaSignal(pizzaAffinity);
var affinityMatch = personalMemoryStore.GetAffinities(tenantScope)
.Where(pair => pair.Key.Contains("pizza", StringComparison.OrdinalIgnoreCase))
.OrderByDescending(static pair =>
pair.Value == PersonalAffinity.Love ? 2 : pair.Value == PersonalAffinity.Like ? 1 : 0)
.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(affinityMatch.Key)) return new PizzaSignal(affinityMatch.Value);
foreach (var category in PizzaPreferenceCategories)
{
var preference = personalMemoryStore.GetPreference(tenantScope, category);
if (!string.IsNullOrWhiteSpace(preference) &&
preference.Contains("pizza", StringComparison.OrdinalIgnoreCase))
return new PizzaSignal(PersonalAffinity.Like);
}
return new PizzaSignal(null);
}
private static string ResolveSemanticIntent(
string loweredTranscript,
DateTimeOffset? referenceLocalTime,