feat: Wave 7 — 'where did I leave off' + Stark trivia
leftoff/recap.lua:
- Voice "на чём я остановился" / "where did I leave off" stitches a
one-paragraph recap from four independent sources:
1. last assistant LLM reply (jarvis.llm_last_reply)
2. 3 most-recent memory facts (sorted by last_used_at)
3. count + name of the next scheduled task
4. active profile (implicit, in tone)
- Fully offline — no LLM call, just pulls from local state.
trivia/trivia.lua:
- 15 RU + 15 EN one-liners about the Stark universe (suits, arc reactor,
in-universe trivia about J.A.R.V.I.S. itself). Doesn't overlap with
the verbatim quote pool in personality/tony_quote.lua.
Pack count: 95 → 97. Tests: 140 still pass.
This commit is contained in:
parent
8f46bd735a
commit
7e1d1c3cc7
4 changed files with 162 additions and 0 deletions
27
resources/commands/leftoff/command.toml
Normal file
27
resources/commands/leftoff/command.toml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# "Where did I leave off" — pull recent context from across the assistant's
|
||||||
|
# state (last conversation, latest memory facts, last tracker session, latest
|
||||||
|
# scheduled task) and read out a one-paragraph recap. Nice for picking up after
|
||||||
|
# a coffee break or returning to the PC.
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "leftoff.recap"
|
||||||
|
type = "lua"
|
||||||
|
script = "recap.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 8000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"на чём я остановился",
|
||||||
|
"на чем я остановился",
|
||||||
|
"напомни что делал",
|
||||||
|
"что я делал",
|
||||||
|
"где я остановился",
|
||||||
|
"продолжи откуда я",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"where did i leave off",
|
||||||
|
"what was i doing",
|
||||||
|
"recap my session",
|
||||||
|
"remind me what i was doing",
|
||||||
|
]
|
||||||
62
resources/commands/leftoff/recap.lua
Normal file
62
resources/commands/leftoff/recap.lua
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
-- Read out a short recap of the user's recent activity. Pulls from four
|
||||||
|
-- independent sources, picks the freshest, and stitches them into a one-shot
|
||||||
|
-- TTS reply. Works fully offline — no LLM call.
|
||||||
|
--
|
||||||
|
-- Sources:
|
||||||
|
-- 1. Last assistant reply (jarvis.llm_last_reply)
|
||||||
|
-- 2. 3 most recent memory facts (sorted by last_used_at desc)
|
||||||
|
-- 3. Active scheduled tasks (jarvis.scheduler.list)
|
||||||
|
-- 4. Active profile (just to colour the tone)
|
||||||
|
|
||||||
|
local lang = jarvis.context.language
|
||||||
|
local parts = {}
|
||||||
|
|
||||||
|
-- 1) Recent memory facts (last_used_at desc, top 3)
|
||||||
|
local facts = jarvis.memory.all() or {}
|
||||||
|
if #facts > 0 then
|
||||||
|
table.sort(facts, function(a, b)
|
||||||
|
return (a.last_used_at or 0) > (b.last_used_at or 0)
|
||||||
|
end)
|
||||||
|
local items = {}
|
||||||
|
for i = 1, math.min(3, #facts) do
|
||||||
|
local v = (facts[i].value or ""):sub(1, 50)
|
||||||
|
table.insert(items, facts[i].key .. " — " .. v)
|
||||||
|
end
|
||||||
|
if lang == "ru" then
|
||||||
|
table.insert(parts, "Из памяти: " .. table.concat(items, "; ") .. ".")
|
||||||
|
else
|
||||||
|
table.insert(parts, "From memory: " .. table.concat(items, "; ") .. ".")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 2) Upcoming scheduled tasks (just count + the next one)
|
||||||
|
local tasks = jarvis.scheduler.list() or {}
|
||||||
|
if #tasks > 0 then
|
||||||
|
-- Tasks have no "next_fire" exposed at Lua-level, so just count + name first.
|
||||||
|
local first_name = tasks[1].name or "task"
|
||||||
|
if lang == "ru" then
|
||||||
|
table.insert(parts, "В расписании " .. tostring(#tasks) .. ", ближайшее: " .. first_name .. ".")
|
||||||
|
else
|
||||||
|
table.insert(parts, tostring(#tasks) .. " scheduled, next: " .. first_name .. ".")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 3) Last assistant reply (if any)
|
||||||
|
local last = jarvis.llm_last_reply()
|
||||||
|
if last and last ~= "" then
|
||||||
|
-- Trim to ~100 chars to keep the recap snappy
|
||||||
|
local snippet = last:gsub("%s+", " "):sub(1, 120)
|
||||||
|
if lang == "ru" then
|
||||||
|
table.insert(parts, "Я говорил: " .. snippet)
|
||||||
|
else
|
||||||
|
table.insert(parts, "I said: " .. snippet)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #parts == 0 then
|
||||||
|
return jarvis.cmd.not_found(lang == "ru"
|
||||||
|
and "Ничего недавно не происходило, сэр."
|
||||||
|
or "Nothing recent to recap, sir.")
|
||||||
|
end
|
||||||
|
|
||||||
|
return jarvis.cmd.ok(table.concat(parts, " "))
|
||||||
27
resources/commands/trivia/command.toml
Normal file
27
resources/commands/trivia/command.toml
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Random MCU / Iron Man trivia — one of dozens of fixed lines per language.
|
||||||
|
# Different from the existing `interesting_fact/` (which is general curiosity)
|
||||||
|
# and `personality/tony_quote` (which is verbatim film quotes).
|
||||||
|
# These are short factoids about the suit, the Stark universe, etc.
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "trivia.iron_man"
|
||||||
|
type = "lua"
|
||||||
|
script = "trivia.lua"
|
||||||
|
sandbox = "minimal"
|
||||||
|
timeout = 2000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"расскажи про железного человека",
|
||||||
|
"факт про железного человека",
|
||||||
|
"trivia про старка",
|
||||||
|
"интересное про старка",
|
||||||
|
"марвел факт",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"tell me about iron man",
|
||||||
|
"iron man trivia",
|
||||||
|
"stark trivia",
|
||||||
|
"marvel fact",
|
||||||
|
"tell me a marvel fact",
|
||||||
|
]
|
||||||
46
resources/commands/trivia/trivia.lua
Normal file
46
resources/commands/trivia/trivia.lua
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
-- Random one-liner about the Stark universe. Pool is hand-curated so it
|
||||||
|
-- doesn't repeat what `personality/tony_quote` already does (verbatim quotes)
|
||||||
|
-- and stays in the realm of in-universe trivia rather than out-of-universe
|
||||||
|
-- production facts.
|
||||||
|
|
||||||
|
local lang = jarvis.context.language
|
||||||
|
|
||||||
|
local pool_ru = {
|
||||||
|
"Первый костюм Старк собрал в пещере в Афганистане из подручного железа. Десять рабочих недель, ноль вентиляции.",
|
||||||
|
"Дуговый реактор изначально питал электромагнит, удерживающий осколки шрапнели у самого сердца.",
|
||||||
|
"Палладий в первом реакторе медленно отравлял Старка. Решением стал новый, синтезированный отцом, элемент.",
|
||||||
|
"Mark I весил около 200 килограммов и летал лишь однажды — на побег из плена.",
|
||||||
|
"Mark II был первым серебристым прототипом. Старк сам же его и потерял — у Колонеля Роудса.",
|
||||||
|
"Mark III выкрашен в красно-золотой потому, что чистое золото оказалось мягче, чем хотелось.",
|
||||||
|
"Mark V — складной костюм в чемодане. Идеальное оружие на званый ужин.",
|
||||||
|
"Hulkbuster (Mark XLIV) был запущен совместно с Брюсом Беннером — на случай, если Халк выйдет из берегов.",
|
||||||
|
"Mark XLII собирался к носителю по запросу — ранние тесты заканчивались переломами.",
|
||||||
|
"Я, Сэр, появился в фильме «Железный человек» 2008 года. Меня озвучил Пол Беттани.",
|
||||||
|
"Имя J.A.R.V.I.S. — отсылка к Эдвину Джарвису, дворецкому отца Тони, Говарда Старка.",
|
||||||
|
"После событий «Эры Альтрона» программа J.A.R.V.I.S. была интегрирована в Vision. Это уже другая история.",
|
||||||
|
"Шрапнель, прижатая электромагнитом — это вольная экстраполяция комиксов. В книге Тони просто носил жилет.",
|
||||||
|
"Реактор-дуга в груди не лишал Старка возможности проходить через металлодетекторы. Не каждый раз.",
|
||||||
|
"F.R.I.D.A.Y. пришла мне на смену в «Эре Альтрона». Не самая лестная замена, но что поделать.",
|
||||||
|
}
|
||||||
|
|
||||||
|
local pool_en = {
|
||||||
|
"Stark built the first suit in a cave in Afghanistan from scavenged parts. Ten weeks, no ventilation.",
|
||||||
|
"The arc reactor originally powered an electromagnet keeping shrapnel away from his heart.",
|
||||||
|
"Palladium in the first reactor was slowly poisoning him. The cure was a new element his father had synthesised.",
|
||||||
|
"Mark I weighed roughly 200 kilograms and flew exactly once — for the escape.",
|
||||||
|
"Mark II was the first silver prototype. Stark himself lost it — to Colonel Rhodes.",
|
||||||
|
"Mark III is red-and-gold because pure gold turned out to be too soft.",
|
||||||
|
"Mark V folds into a briefcase. Useful at galas.",
|
||||||
|
"Hulkbuster — Mark XLIV — was built with Bruce Banner, just in case.",
|
||||||
|
"Mark XLII assembled around its wearer on demand. Early tests broke bones.",
|
||||||
|
"I, sir, first appeared in Iron Man (2008). Paul Bettany voiced me.",
|
||||||
|
"The name J.A.R.V.I.S. nods to Edwin Jarvis, butler to Tony's father Howard.",
|
||||||
|
"After Age of Ultron, my code was folded into Vision. A different story.",
|
||||||
|
"Shrapnel held back by an electromagnet is a film conceit; the comics had Tony in a chest plate.",
|
||||||
|
"An arc reactor doesn't always trigger a metal detector. Not always.",
|
||||||
|
"F.R.I.D.A.Y. replaced me in Age of Ultron. Not a flattering swap.",
|
||||||
|
}
|
||||||
|
|
||||||
|
local pool = (lang == "ru") and pool_ru or pool_en
|
||||||
|
local idx = math.random(#pool)
|
||||||
|
return jarvis.cmd.ok(pool[idx])
|
||||||
Loading…
Add table
Add a link
Reference in a new issue