mirror of
https://github.com/R0m1k3/EveFlow.git
synced 2026-10-18 20:59:11 +02:00
fix: keep Hermes session across runs and speak long replies as a digest (2.5.3)
Over the runs transport Hermes never reports the session it attached to a
run in the SSE stream, only in GET /v1/runs/{id}. EveFlow only read it in the
polling fallback, so the locally generated id was sent again and again and
each message opened a fresh Hermes session, losing the conversation context.
The client now adopts the run's session id after every run.
Long answers are now spoken as a digest: the first sentences (configurable,
4 by default) plus the closing question, followed by a short notice that the
full text is on screen. The default instructions ask Hermes to open long
replies with the essentials and to rely on the ongoing conversation.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln4KL1feHtnV4nee4sZFhM
This commit is contained in:
12 files changed
+256
-16
No files matched your search
@@ -129,6 +129,33 @@ export function chunkForSpeech(text: string, maxLength = 220): string[] {
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Last speakable chunk of a reply when it is a question (« Tu veux que je… ? »), else null. */
|
||||
export function closingQuestion(text: string): string | null {
|
||||
const parts = speakableChunks(text);
|
||||
const last = parts[parts.length - 1];
|
||||
return last && /\?\s*$/.test(last) ? last : null;
|
||||
}
|
||||
|
||||
/** Chunks of the spoken form of a text (markdown and code already stripped), letters only. */
|
||||
function speakableChunks(text: string): string[] {
|
||||
return chunkForSpeech(cleanForSpeech(text)).filter((part) => /[\p{L}\p{N}]/u.test(part));
|
||||
}
|
||||
|
||||
/**
|
||||
* Spoken digest of a long reply: the first `maxSentences` speakable chunks plus the closing
|
||||
* question when there is one, so a long answer stays short to listen to but the conversation
|
||||
* can go on. `truncated` tells the caller that the screen holds more than what is spoken.
|
||||
*/
|
||||
export function spokenDigest(text: string, maxSentences: number): { text: string; truncated: boolean } {
|
||||
const parts = speakableChunks(text);
|
||||
const limit = Math.max(1, Math.floor(maxSentences));
|
||||
if (parts.length <= limit) return { text: parts.join(' '), truncated: false };
|
||||
const head = parts.slice(0, limit);
|
||||
const question = closingQuestion(text);
|
||||
if (question && !head.includes(question)) head.push(question);
|
||||
return { text: head.join(' '), truncated: true };
|
||||
}
|
||||
|
||||
export function previewText(value: string, max = 96): string {
|
||||
const flat = value.replace(/\s+/g, ' ').trim();
|
||||
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
||||
|
||||
Reference in new issue
Block a user