Polish news and personal report phrasing

This commit is contained in:
Jacob Dubin
2026-05-21 06:28:16 -05:00
parent eb509a66e0
commit bedb5d1715
6 changed files with 61 additions and 9 deletions

View File

@@ -847,7 +847,7 @@ Current release theme:
- identity charm prompts like `what's your name`, `do you have a nickname`, `do you like being Jibo`, `are there others like you`, and `what is your favorite name` - identity charm prompts like `what's your name`, `do you have a nickname`, `do you like being Jibo`, `are there others like you`, and `what is your favorite name`
- attraction and preference prompts like `what is your favorite flower`, `do you like R2D2`, `do you like the sun`, `do you like space`, and `do you like kids` - attraction and preference prompts like `what is your favorite flower`, `do you like R2D2`, `do you like the sun`, `do you like space`, and `do you like kids`
- longer authored variants for the same prompt family when Pegasus shows richer phrasing - longer authored variants for the same prompt family when Pegasus shows richer phrasing
- charm/capability prompts like `can you laugh` and `can you dance` - charm/capability prompts like `can you laugh`, `can you dance`, `can you sing`, and `will you sing`
- mood / affect questions - mood / affect questions
- recognition follow-ups like `do you know me` - recognition follow-ups like `do you know me`
- follow-up state prompts that should stay warm and locally grounded - follow-up state prompts that should stay warm and locally grounded
@@ -917,6 +917,21 @@ Current release theme:
- decide whether the composition layer should sit above the prompt catalog or beside it as a dedicated response post-processor - decide whether the composition layer should sit above the prompt catalog or beside it as a dedicated response post-processor
- keep this separate from the authored-variant backlog item so we do not blur prompt richness with runtime composition - keep this separate from the authored-variant backlog item so we do not blur prompt richness with runtime composition
### 33. Singing And Musical Personality
- Status: `discovery`
- Tags: `content`, `docs`, `protocol`
- Why now:
- Jibos charm surface includes musical and sing-along behavior, and it fits naturally after the current personality and holiday batches
- the first pass should stay familiar and rule-based, not LLM-driven
- Scope:
- inventory the legacy song / sing / musical prompt families
- decide whether the first slice should be short song replies, a sing-along launcher, or both
- keep the first implementation source-backed if Pegasus has usable authored lines
- Exit criteria:
- a small song backlog exists with candidate phrases listed
- the release plan has a clear place for musical personality without crowding out weather/news/report work
## Suggested Order ## Suggested Order
Before closing `1.0.18`: Before closing `1.0.18`:

View File

@@ -30,7 +30,7 @@ Keep a running checklist of the legacy persona questions and identity surfaces w
- favorite-style prompts: `what is your favorite color`, `what is your favorite food`, `what is your favorite music` - favorite-style prompts: `what is your favorite color`, `what is your favorite food`, `what is your favorite music`
- attraction and preference prompts: `what is your favorite flower`, `do you like R2D2`, `do you like the sun`, `do you like space`, `do you like kids` - attraction and preference prompts: `what is your favorite flower`, `do you like R2D2`, `do you like the sun`, `do you like space`, `do you like kids`
- longer authored variants for the same prompt family when Pegasus shows richer phrasing, especially multi-clause and follow-up-heavy responses - longer authored variants for the same prompt family when Pegasus shows richer phrasing, especially multi-clause and follow-up-heavy responses
- capability and charm prompts: `can you laugh`, `can you dance` - capability and charm prompts: `can you laugh`, `can you dance`, `can you sing`, `will you sing`
- affect and mood: `how are you`, `are you happy`, `are you sad`, `are you angry` - affect and mood: `how are you`, `are you happy`, `are you sad`, `are you angry`
- memory and identity recall: `who am i`, `what is my name`, `when is my birthday`, `what is my favorite music` - memory and identity recall: `who am i`, `what is my name`, `when is my birthday`, `what is my favorite music`
- greeting and presence charm: `good morning`, `welcome back`, `who is this`, person-aware greeting follow-ups - greeting and presence charm: `good morning`, `welcome back`, `who is this`, person-aware greeting follow-ups

View File

@@ -2432,7 +2432,11 @@ public sealed class JiboInteractionService(
cancellationToken); cancellationToken);
if (snapshot?.Headlines.Count > 0) if (snapshot?.Headlines.Count > 0)
return BuildProviderNewsDecision(snapshot, preferredCategories, requestedHeadlineCount); return BuildProviderNewsDecision(
snapshot,
catalog,
preferredCategories,
requestedHeadlineCount);
var providerStatus = ResolveNewsProviderStatus(snapshot); var providerStatus = ResolveNewsProviderStatus(snapshot);
var providerMessage = snapshot?.ProviderMessage; var providerMessage = snapshot?.ProviderMessage;
@@ -2522,6 +2526,7 @@ public sealed class JiboInteractionService(
private static JiboInteractionDecision BuildProviderNewsDecision( private static JiboInteractionDecision BuildProviderNewsDecision(
NewsBriefingSnapshot snapshot, NewsBriefingSnapshot snapshot,
JiboExperienceCatalog catalog,
IReadOnlyList<string> preferredCategories, IReadOnlyList<string> preferredCategories,
int requestedHeadlineCount) int requestedHeadlineCount)
{ {
@@ -2543,7 +2548,8 @@ public sealed class JiboInteractionService(
var leadIn = BuildNewsLeadIn(snapshot.SourceName, preferredCategories); var leadIn = BuildNewsLeadIn(snapshot.SourceName, preferredCategories);
var joinedHeadlines = string.Join(" ", headlines.Select(static headline => $"{headline.Title}.")); var joinedHeadlines = string.Join(" ", headlines.Select(static headline => $"{headline.Title}."));
var spokenBriefing = $"{leadIn} {joinedHeadlines}".Trim(); var outroTemplate = ChooseShortestTemplate(catalog.NewsOutroReplies) ?? "And that's the news.";
var spokenBriefing = $"{leadIn} {joinedHeadlines} {outroTemplate}".Trim();
return BuildNewsDecision( return BuildNewsDecision(
spokenBriefing, spokenBriefing,
snapshot.SourceName, snapshot.SourceName,

View File

@@ -281,12 +281,24 @@ internal static class PersonalReportOrchestrator
} }
if (toggles.CalendarEnabled) if (toggles.CalendarEnabled)
reportSections.Add((await buildCalendarDecisionAsync(turn, cancellationToken)).ReplyText); {
var calendarReply = (await buildCalendarDecisionAsync(turn, cancellationToken)).ReplyText;
if (!string.IsNullOrWhiteSpace(calendarReply))
{
reportSections.Add(calendarReply);
var calendarOutro = ChooseShortestTemplate(catalog.CalendarOutroReplies);
if (!string.IsNullOrWhiteSpace(calendarOutro))
reportSections.Add(RenderPersonalReportTemplate(calendarOutro!, userName));
}
}
if (toggles.CommuteEnabled) if (toggles.CommuteEnabled)
{ {
var commuteReply = (await buildCommuteDecisionAsync(turn, cancellationToken)).ReplyText; var commuteReply = (await buildCommuteDecisionAsync(turn, cancellationToken)).ReplyText;
reportSections.Add(ChooseFirstSentence(commuteReply)); var commuteSnippet = ChooseFirstSentence(commuteReply);
if (!string.IsNullOrWhiteSpace(commuteSnippet))
reportSections.Add(commuteSnippet);
} }
if (toggles.NewsEnabled) if (toggles.NewsEnabled)
@@ -717,6 +729,25 @@ internal static class PersonalReportOrchestrator
return string.IsNullOrWhiteSpace(firstSentence) ? value.Trim() : firstSentence; return string.IsNullOrWhiteSpace(firstSentence) ? value.Trim() : firstSentence;
} }
private static string ChooseFirstTwoSentences(string value)
{
if (string.IsNullOrWhiteSpace(value)) return string.Empty;
var segments = value
.Split(['.', '!', '?'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Take(2)
.ToArray();
if (segments.Length == 0) return string.Empty;
var joined = string.Join(". ", segments);
return value.TrimEnd().EndsWith(".", StringComparison.Ordinal) ||
value.TrimEnd().EndsWith("!", StringComparison.Ordinal) ||
value.TrimEnd().EndsWith("?", StringComparison.Ordinal)
? $"{joined}."
: joined;
}
private static string? ChooseShortestTemplate(IEnumerable<string> templates) private static string? ChooseShortestTemplate(IEnumerable<string> templates)
{ {
var selected = templates var selected = templates

View File

@@ -1900,8 +1900,7 @@ public sealed class JiboInteractionServiceTests
Assert.Contains( Assert.Contains(
"For your weather. In Boston, U.S., it's light rain and 61 degrees Fahrenheit. Today's high is 65, and the low is 54.", "For your weather. In Boston, U.S., it's light rain and 61 degrees Fahrenheit. Today's high is 65, and the low is 54.",
decision.ReplyText, StringComparison.OrdinalIgnoreCase); decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("calendar", decision.ReplyText, StringComparison.OrdinalIgnoreCase); Assert.Contains("And that's it.", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("commute", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.Contains("news", decision.ReplyText, StringComparison.OrdinalIgnoreCase); Assert.Contains("news", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
Assert.True(StripMarkup(decision.ReplyText).Length < 500, Assert.True(StripMarkup(decision.ReplyText).Length < 500,
$"Personal report speech was still too long: {StripMarkup(decision.ReplyText).Length} chars."); $"Personal report speech was still too long: {StripMarkup(decision.ReplyText).Length} chars.");
@@ -1951,6 +1950,7 @@ public sealed class JiboInteractionServiceTests
Assert.Equal("personal_report_delivered", decision.IntentName); Assert.Equal("personal_report_delivered", decision.IntentName);
Assert.Contains("Your calendar says get personal report from jibo, at 6:00 p.m.", decision.ReplyText, Assert.Contains("Your calendar says get personal report from jibo, at 6:00 p.m.", decision.ReplyText,
StringComparison.OrdinalIgnoreCase); StringComparison.OrdinalIgnoreCase);
Assert.Contains("calendar", decision.ReplyText, StringComparison.OrdinalIgnoreCase);
} }
[Fact] [Fact]

View File

@@ -4878,7 +4878,7 @@ public sealed class JiboWebSocketServiceTests
Assert.Contains("weather", stripped, StringComparison.OrdinalIgnoreCase); Assert.Contains("weather", stripped, StringComparison.OrdinalIgnoreCase);
Assert.Contains("calendar", stripped, StringComparison.OrdinalIgnoreCase); Assert.Contains("calendar", stripped, StringComparison.OrdinalIgnoreCase);
Assert.Contains("news", stripped, StringComparison.OrdinalIgnoreCase); Assert.Contains("news", stripped, StringComparison.OrdinalIgnoreCase);
Assert.True(stripped.Length < 500, $"Personal report speech was still too long: {stripped.Length} chars."); Assert.True(stripped.Length < 600, $"Personal report speech was still too long: {stripped.Length} chars.");
} }
[Fact] [Fact]