@absolutejs/voice 0.0.22-beta.588 → 0.0.22-beta.589

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -613,6 +613,17 @@ export type VoiceRouteConfig<TContext = unknown, TSession extends VoiceSessionRe
613
613
  session: TSession;
614
614
  api: VoiceSessionHandle<TContext, TSession, TResult>;
615
615
  }) => Promise<void> | void;
616
+ /** Fires when a connect RESUMES an existing session (a reconnect, or a fresh
617
+ * process after a restart finding the session in a persistent store) instead
618
+ * of starting a new call — onCallStart/onSession do NOT fire on a resume.
619
+ * Use it to rebuild any per-session in-memory state (caller context, paced
620
+ * flags) that didn't survive the process, so the resumed call keeps the
621
+ * personalization the original had. Runs before the resume re-greeting. */
622
+ onResume?: (input: {
623
+ context: TContext;
624
+ session: TSession;
625
+ api: VoiceSessionHandle<TContext, TSession, TResult>;
626
+ }) => Promise<void> | void;
616
627
  correctTurn?: VoiceTurnCorrectionHandler<TContext, TSession, TResult>;
617
628
  onTurn: VoiceOnTurnHandler<TContext, TSession, TResult>;
618
629
  onComplete: (input: {
@@ -764,6 +775,9 @@ export type VoicePluginConfig<TContext = unknown, TSession extends VoiceSessionR
764
775
  greeting?: string | ((input: {
765
776
  session: TSession;
766
777
  }) => string | Promise<string>);
778
+ resumeGreeting?: string | ((input: {
779
+ session: TSession;
780
+ }) => string | Promise<string>);
767
781
  languageStrategy?: VoiceLanguageStrategy;
768
782
  lexicon?: VoiceLexiconEntry[] | VoiceLexiconResolver<TContext>;
769
783
  phraseHints?: VoicePhraseHint[] | VoicePhraseHintResolver<TContext>;
@@ -893,6 +907,14 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
893
907
  greeting?: string | ((input: {
894
908
  session: TSession;
895
909
  }) => string | Promise<string>);
910
+ /** Spoken on a RESUME (reconnect / restart) of a call that already had at
911
+ * least one committed turn — a short re-orientation ("Sorry, you cut out —
912
+ * you were telling me about X; go on") so the caller knows they're back,
913
+ * since the in-flight assistant audio didn't survive. Receives the session so
914
+ * it can reference the last turn. No resume greeting fires if unset. */
915
+ resumeGreeting?: string | ((input: {
916
+ session: TSession;
917
+ }) => string | Promise<string>);
896
918
  stt?: STTAdapter;
897
919
  realtime?: RealtimeAdapter;
898
920
  realtimeInputFormat?: AudioFormat;
package/dist/index.js CHANGED
@@ -6155,6 +6155,7 @@ var createVoiceSession = (options) => {
6155
6155
  type: "session"
6156
6156
  });
6157
6157
  await sendReplay(session);
6158
+ const isResume = !shouldFireOnSession;
6158
6159
  if (shouldFireOnSession) {
6159
6160
  await options.route.onCallStart?.({
6160
6161
  api,
@@ -6166,6 +6167,12 @@ var createVoiceSession = (options) => {
6166
6167
  context: options.context,
6167
6168
  session
6168
6169
  });
6170
+ } else {
6171
+ await options.route.onResume?.({
6172
+ api,
6173
+ context: options.context,
6174
+ session
6175
+ });
6169
6176
  }
6170
6177
  if (session.status === "completed") {
6171
6178
  await send({
@@ -6179,27 +6186,31 @@ var createVoiceSession = (options) => {
6179
6186
  warmTTSSession();
6180
6187
  kickCallSilenceWatchdog();
6181
6188
  startAmdEvaluationTimer();
6182
- if (shouldFireOnSession && options.greeting && session.turns.length === 0) {
6183
- const greetingText = typeof options.greeting === "function" ? await options.greeting({ session }) : options.greeting;
6184
- const greetingTurnId = createId();
6185
- await send({
6186
- text: greetingText,
6187
- turnId: greetingTurnId,
6188
- type: "assistant"
6189
- });
6189
+ const speakAssistantLine = async (text) => {
6190
+ if (!text.trim()) {
6191
+ return;
6192
+ }
6193
+ const lineTurnId = createId();
6194
+ await send({ text, turnId: lineTurnId, type: "assistant" });
6190
6195
  try {
6191
- const greetingTTSSession = await ensureTTSSession();
6192
- if (greetingTTSSession) {
6193
- activeTTSTurnId = greetingTurnId;
6194
- await greetingTTSSession.send(greetingText);
6196
+ const lineTTSSession = await ensureTTSSession();
6197
+ if (lineTTSSession) {
6198
+ activeTTSTurnId = lineTurnId;
6199
+ await lineTTSSession.send(text);
6195
6200
  lastTtsSendAt = Date.now();
6196
6201
  } else if (options.realtime) {
6197
- const greetingRealtimeSession = await ensureAdapter();
6198
- activeTTSTurnId = greetingTurnId;
6199
- await greetingRealtimeSession.send(greetingText);
6202
+ const lineRealtimeSession = await ensureAdapter();
6203
+ activeTTSTurnId = lineTurnId;
6204
+ await lineRealtimeSession.send(text);
6200
6205
  lastTtsSendAt = Date.now();
6201
6206
  }
6202
6207
  } catch {}
6208
+ };
6209
+ const resolveLine = async (line) => typeof line === "function" ? line({ session }) : line;
6210
+ if (options.greeting && session.turns.length === 0) {
6211
+ await speakAssistantLine(await resolveLine(options.greeting));
6212
+ } else if (isResume && options.resumeGreeting && session.turns.length > 0) {
6213
+ await speakAssistantLine(await resolveLine(options.resumeGreeting));
6203
6214
  }
6204
6215
  };
6205
6216
  const disconnectInternal = async (event) => {
@@ -39348,6 +39359,7 @@ var voice = (config) => {
39348
39359
  context,
39349
39360
  id: sessionId,
39350
39361
  greeting: config.greeting,
39362
+ resumeGreeting: config.resumeGreeting,
39351
39363
  handoff: config.handoff,
39352
39364
  languageStrategy: config.languageStrategy,
39353
39365
  lexicon,
@@ -8382,6 +8382,7 @@ var createVoiceSession = (options) => {
8382
8382
  type: "session"
8383
8383
  });
8384
8384
  await sendReplay(session);
8385
+ const isResume = !shouldFireOnSession;
8385
8386
  if (shouldFireOnSession) {
8386
8387
  await options.route.onCallStart?.({
8387
8388
  api,
@@ -8393,6 +8394,12 @@ var createVoiceSession = (options) => {
8393
8394
  context: options.context,
8394
8395
  session
8395
8396
  });
8397
+ } else {
8398
+ await options.route.onResume?.({
8399
+ api,
8400
+ context: options.context,
8401
+ session
8402
+ });
8396
8403
  }
8397
8404
  if (session.status === "completed") {
8398
8405
  await send({
@@ -8406,27 +8413,31 @@ var createVoiceSession = (options) => {
8406
8413
  warmTTSSession();
8407
8414
  kickCallSilenceWatchdog();
8408
8415
  startAmdEvaluationTimer();
8409
- if (shouldFireOnSession && options.greeting && session.turns.length === 0) {
8410
- const greetingText = typeof options.greeting === "function" ? await options.greeting({ session }) : options.greeting;
8411
- const greetingTurnId = createId();
8412
- await send({
8413
- text: greetingText,
8414
- turnId: greetingTurnId,
8415
- type: "assistant"
8416
- });
8416
+ const speakAssistantLine = async (text) => {
8417
+ if (!text.trim()) {
8418
+ return;
8419
+ }
8420
+ const lineTurnId = createId();
8421
+ await send({ text, turnId: lineTurnId, type: "assistant" });
8417
8422
  try {
8418
- const greetingTTSSession = await ensureTTSSession();
8419
- if (greetingTTSSession) {
8420
- activeTTSTurnId = greetingTurnId;
8421
- await greetingTTSSession.send(greetingText);
8423
+ const lineTTSSession = await ensureTTSSession();
8424
+ if (lineTTSSession) {
8425
+ activeTTSTurnId = lineTurnId;
8426
+ await lineTTSSession.send(text);
8422
8427
  lastTtsSendAt = Date.now();
8423
8428
  } else if (options.realtime) {
8424
- const greetingRealtimeSession = await ensureAdapter();
8425
- activeTTSTurnId = greetingTurnId;
8426
- await greetingRealtimeSession.send(greetingText);
8429
+ const lineRealtimeSession = await ensureAdapter();
8430
+ activeTTSTurnId = lineTurnId;
8431
+ await lineRealtimeSession.send(text);
8427
8432
  lastTtsSendAt = Date.now();
8428
8433
  }
8429
8434
  } catch {}
8435
+ };
8436
+ const resolveLine = async (line) => typeof line === "function" ? line({ session }) : line;
8437
+ if (options.greeting && session.turns.length === 0) {
8438
+ await speakAssistantLine(await resolveLine(options.greeting));
8439
+ } else if (isResume && options.resumeGreeting && session.turns.length > 0) {
8440
+ await speakAssistantLine(await resolveLine(options.resumeGreeting));
8430
8441
  }
8431
8442
  };
8432
8443
  const disconnectInternal = async (event) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.588",
3
+ "version": "0.0.22-beta.589",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",