J.A.R.V.I.S-rust/resources/commands/conversation/summary.lua
Bossiara13 df799b6cd2
Some checks are pending
Rust CI / cargo test (jarvis-core) (push) Waiting to run
Rust CI / cargo clippy (push) Waiting to run
Rust CI / cargo check (workspace) (push) Waiting to run
feat: Wave 5 — sysinfo speaks, smart reminders, outlook COM, time tracker, WOL, conversation tools
Voice sysinfo overhaul (6 scripts: battery/cpu/ram/disk/time/all):
- Now SPEAK the result via jarvis.cmd.ok instead of notify-only. Toast
  still fires for visual reference, but real Jarvis tells you out loud.
- `all` joins lines with commas so TTS doesn't over-pause on linebreaks.

Smart reminders (`reminders/set.lua` rewrite):
- Was: detached `Start-Sleep` PowerShell subprocesses that died on
  jarvis-app restart and spawned a hidden process per timer.
- Now: routes through `jarvis.scheduler.add(... type=speak ...)`. Persists
  to schedule.json, survives restart, no zombie processes. Trade-off:
  sub-minute timers round up to 1 min (rare in voice UX).
- Drops UA triggers from earlier UA-removal sweep.

Translation polish (`translate/translate.lua` + `clipboard.lua`):
- Drops UA target language; adds Italian, Polish, Turkish, French ru
  triggers + English target detectors.
- `language_iso()` helper picks the SAPI voice locale for the TARGET
  language (German translation → German SAPI voice if installed).

LLM system prompt (config.rs):
- New LLM_SYSTEM_PROMPT_EN counterpart. Both languages now mention the
  assistant's tooling (memory / scheduler / profiles / macros / vision /
  clipboard) so the LLM knows it can DO things, not suggest the user
  install something.
- `get_llm_system_prompt(lang)` picks EN/RU.

Conversation pack (NEW `conversation/`):
- 2 commands. `conversation.summary` ("о чём мы говорили") pulls the
  last 12 turns from persisted history, asks LLM for a 1-3 sentence
  recap in Jarvis tone. Falls back gracefully when offline.
- `conversation.repeat` ("повтори") re-speaks the last assistant message.
- New Lua API `jarvis.llm_history()` returns array of {role, content}
  tables, excluding the system prompt.

WOL pack (NEW `wol/`):
- Voice "разбуди сервер" / "wake server" fires a magic packet at a MAC
  stored in long-term memory under `wol_<alias>` (default alias "server").
- Setup via voice: "запомни wol_server AA:BB:CC:DD:EE:FF". Falls back to
  `JARVIS_WOL_TARGET` env if memory empty. Handles every standard MAC
  format (colons / dashes / dots / bare). Broadcast on UDP 9 via
  PowerShell System.Net.Sockets.UdpClient.

Outlook COM pack (NEW `outlook/`, via subagent):
- 4 commands: unread_count, latest, send_clipboard, summarize_inbox.
- PowerShell COM bridge `_outlook.ps1` with tab-delimited line protocol.
- summarize_inbox calls LLM for a one-paragraph summary. Graceful
  failure when Outlook isn't running.

Time tracker pack (NEW `time_tracker/`, via subagent):
- 5 commands: start, stop, today, week, reset.
- Persists via `jarvis.state` (structured object: current_session_start
  + sessions array of {start, end}).
- Local-calendar "today" boundary, full Russian pluralisation
  (час/часа/часов, минута/минуты/минут, сессия/сессии/сессий).

Tests: 139 rust (no regression), 81 python (60 → 81, +14 time_tracker
+7 outlook). Release build green for jarvis-app and jarvis-cli.

Pack count: 88 → 92 rust packs.
2026-05-16 14:34:29 +03:00

79 lines
3.4 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Summarise the last N turns of LLM conversation in 1-2 sentences.
--
-- Reads the persistent history via `jarvis.llm_history()`, builds a short
-- recap prompt, asks the LLM. If there's no history yet or the LLM is
-- unreachable, falls back to a polite "ничего не вспомнить" reply.
local lang = jarvis.context.language
local turns = jarvis.llm_history() or {}
-- Take only the last 12 user/assistant turns to keep prompt small.
local recent = {}
local start = math.max(1, #turns - 11)
for i = start, #turns do
if turns[i] then table.insert(recent, turns[i]) end
end
if #recent == 0 then
return jarvis.cmd.not_found(lang == "ru"
and "Мы пока ещё ни о чём не говорили, сэр."
or "We haven't talked about anything yet, sir.")
end
-- Render history as a compact "Пользователь: ... / Я: ..." dialogue.
local lines = {}
for _, m in ipairs(recent) do
local who = m.role == "assistant" and (lang == "ru" and "Я" or "Me")
or (lang == "ru" and "Пользователь" or "User")
table.insert(lines, who .. ": " .. (m.content or ""))
end
local transcript = table.concat(lines, "\n")
local token = jarvis.system.env("GROQ_TOKEN")
if not token or token == "" then
-- Offline path: just speak the user's last message back briefly.
return jarvis.cmd.ok(lang == "ru"
and ("Без сети, сэр. Последний раз вы спросили: " .. (recent[#recent].content or ""):sub(1, 200))
or ("No network, sir. Last topic: " .. (recent[#recent].content or ""):sub(1, 200)))
end
local base = jarvis.system.env("GROQ_BASE_URL")
if not base or base == "" then base = "https://api.groq.com/openai/v1" end
local model = jarvis.system.env("GROQ_MODEL")
if not model or model == "" then model = "llama-3.3-70b-versatile" end
local sys
if lang == "ru" then
sys = "Ты — J.A.R.V.I.S. По ниже идущему диалогу с пользователем составь короткое "
.. "напоминание (1-3 предложения), о чём шла речь. Говори от первого лица в "
.. "стиле британского дворецкого. Не пересказывай дословно — сожми суть."
else
sys = "You are J.A.R.V.I.S. From the dialogue below, write a brief recap "
.. "(1-3 sentences) of what we talked about. Use first person, British "
.. "butler tone. Don't quote verbatim — distil the essence."
end
local payload = {
model = model,
messages = {
{ role = "system", content = sys },
{ role = "user", content = transcript },
},
max_tokens = 200,
temperature = 0.4,
}
local res = jarvis.http.post_json(base .. "/chat/completions", payload,
{ Authorization = "Bearer " .. token })
if not res.ok then
return jarvis.cmd.error(lang == "ru" and "LLM не отвечает." or "LLM didn't respond.")
end
local content = (res.body or ""):match('"content"%s*:%s*"(.-[^\\])"')
if not content then
return jarvis.cmd.error(lang == "ru" and "Не смог разобрать ответ." or "Couldn't parse reply.")
end
content = content:gsub('\\n', ' '):gsub('\\"', '"'):gsub('\\\\', '\\')
content = content:gsub("%s+", " "):gsub("^%s+", ""):gsub("%s+$", "")
return jarvis.cmd.ok(content)