@wayai/cli 0.3.173 → 0.3.174

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.
package/dist/index.js CHANGED
@@ -30200,6 +30200,23 @@ function pcmClip(buf) {
30200
30200
  for (let i = 0; i < samples.length; i++) samples[i] = buf.readInt16LE(2 * i);
30201
30201
  return { samples, sampleRate: OPENAI_PCM_SAMPLE_RATE };
30202
30202
  }
30203
+ function trailingSilenceMs(clip) {
30204
+ const frame = Math.max(1, Math.round(clip.sampleRate / 100));
30205
+ const frames = Math.ceil(clip.samples.length / frame);
30206
+ const rms = (f) => {
30207
+ let sum = 0;
30208
+ const end = Math.min(clip.samples.length, (f + 1) * frame);
30209
+ for (let i = f * frame; i < end; i++) sum += clip.samples[i] * clip.samples[i];
30210
+ return Math.sqrt(sum / Math.max(1, end - f * frame));
30211
+ };
30212
+ let loudest = 0;
30213
+ for (let f = 0; f < frames; f++) loudest = Math.max(loudest, rms(f));
30214
+ if (loudest === 0) return 0;
30215
+ let last = frames - 1;
30216
+ while (last > 0 && rms(last) < loudest / 10) last--;
30217
+ const spokenSamples = Math.min(clip.samples.length, (last + 1) * frame);
30218
+ return (clip.samples.length - spokenSamples) * 1e3 / clip.sampleRate;
30219
+ }
30203
30220
  function resample(clip, rate) {
30204
30221
  if (clip.sampleRate === rate) return clip.samples;
30205
30222
  const out = new Int16Array(Math.max(1, Math.round(clip.samples.length * rate / clip.sampleRate)));
@@ -30403,6 +30420,12 @@ var init_call_media = __esm({
30403
30420
  onsetAfter(afterMs) {
30404
30421
  return this.onsets.find((t) => t > afterMs) ?? null;
30405
30422
  }
30423
+ /** The utterances begun at or after `sinceMs`, in order; the last one's end is null while it goes on. */
30424
+ utterancesSince(sinceMs) {
30425
+ let first = this.onsets.length;
30426
+ while (first > 0 && this.onsets[first - 1] >= sinceMs) first--;
30427
+ return this.onsets.slice(first).map((startMs, i) => ({ startMs, endMs: this.offsets[first + i] ?? null }));
30428
+ }
30406
30429
  /** When the voice last stopped speaking; null while it speaks or before it has. */
30407
30430
  quietSince() {
30408
30431
  return this.isSpeaking ? null : this.offsets[this.offsets.length - 1] ?? null;
@@ -30530,14 +30553,19 @@ var init_call_media = __esm({
30530
30553
  await waitFor(() => this.voice.onsetAfter(afterMs) !== null || abort(), timeoutMs, this.clock);
30531
30554
  return this.voice.onsetAfter(afterMs);
30532
30555
  }
30533
- async waitForVoiceDone(sinceMs, quietMs, timeoutMs, abort = () => false, notBeforeMs = Number.NEGATIVE_INFINITY) {
30534
- const done = () => {
30535
- if (this.clock.now() < notBeforeMs || this.voice.onsetAfter(sinceMs - 1) === null) return false;
30556
+ async waitForVoiceDone(sinceMs, quietMs, timeoutMs, abort = () => false, owedUntil = () => Number.NEGATIVE_INFINITY) {
30557
+ let boundFrom = this.clock.now();
30558
+ const check = () => {
30559
+ const now = this.clock.now();
30560
+ const said = this.voice.utterancesSince(sinceMs);
30561
+ const owed = owedUntil(said);
30562
+ boundFrom = Math.max(boundFrom, owed);
30563
+ if (said.length === 0 || now < owed) return false;
30536
30564
  const quiet = this.voice.quietSince();
30537
- return quiet !== null && quiet > sinceMs && this.clock.now() - quiet >= quietMs;
30565
+ return quiet !== null && quiet > sinceMs && now - quiet >= quietMs;
30538
30566
  };
30539
- await waitFor(() => done() || abort(), timeoutMs + Math.max(0, notBeforeMs - this.clock.now()), this.clock);
30540
- return done();
30567
+ await waitFor(() => check() || abort() || this.clock.now() >= boundFrom + timeoutMs, Number.POSITIVE_INFINITY, this.clock);
30568
+ return check();
30541
30569
  }
30542
30570
  delegationsSeen() {
30543
30571
  return this.delegations.size;
@@ -31405,6 +31433,25 @@ var init_score = __esm({
31405
31433
  });
31406
31434
 
31407
31435
  // src/lib/call-eval/runner.ts
31436
+ function latestStretchBegan(said) {
31437
+ let k = said.length - 1;
31438
+ if (k < 0) return null;
31439
+ while (k > 0 && said[k].startMs - (said[k - 1].endMs ?? said[k].startMs) < SPEECH_STRETCH_GAP_MS) k--;
31440
+ return said[k].startMs;
31441
+ }
31442
+ function delegatedAnswerOwedUntil(speechEnd, progressCues, answerDueMs) {
31443
+ const dueAt = speechEnd + answerDueMs;
31444
+ if (!progressCues) return () => dueAt;
31445
+ return (said) => {
31446
+ const began = latestStretchBegan(said);
31447
+ if (began === null) return Number.NEGATIVE_INFINITY;
31448
+ const after = began - speechEnd;
31449
+ const cue = PROGRESS_CUES_HEARD_AT_MS.findIndex((at) => after >= at - CUE_HEARD_EARLY_MS && after <= at + CUE_HEARD_LATE_MS);
31450
+ if (cue < 0) return Number.NEGATIVE_INFINITY;
31451
+ const next = PROGRESS_CUES_HEARD_AT_MS[cue + 1];
31452
+ return next === void 0 ? dueAt : Math.min(dueAt, speechEnd + next + CUE_HEARD_LATE_MS);
31453
+ };
31454
+ }
31408
31455
  function runPassed(run) {
31409
31456
  return run.status === "completed" && run.score?.pass === true;
31410
31457
  }
@@ -31439,6 +31486,7 @@ async function runOneCall(options, run, clips) {
31439
31486
  cost: { connected_ms: 0, provider_usd: 0, operations: 0, operations_settled: false }
31440
31487
  };
31441
31488
  const quietAfter = (delegated) => delegated ? timings.delegatedAnswerQuietMs : timings.ownAnswerQuietMs;
31489
+ const speechTailsMs = clips.map(trailingSilenceMs);
31442
31490
  let media = null;
31443
31491
  let callStartedAt = null;
31444
31492
  let hungUp = false;
@@ -31463,8 +31511,10 @@ async function runOneCall(options, run, clips) {
31463
31511
  result.call_id = created.call_id;
31464
31512
  result.conversation_id = created.conversation_id;
31465
31513
  log(`run ${run}: call ${created.call_id} placed (at most ${created.max_call_seconds} s)`);
31466
- const silentWaitMs = created.progress_cues === false ? created.delegation_timeout_seconds * 1e3 + timings.silentWaitMarginMs : null;
31467
- if (silentWaitMs !== null) {
31514
+ const progressCues = created.progress_cues !== false;
31515
+ const answerDueMs = Number.isFinite(created.delegation_timeout_seconds) ? created.delegation_timeout_seconds * 1e3 + timings.answerTimeoutMarginMs : null;
31516
+ const answerOwedUntil = answerDueMs === null ? null : (speechEnd) => delegatedAnswerOwedUntil(speechEnd, progressCues, answerDueMs);
31517
+ if (!progressCues) {
31468
31518
  log(`run ${run}: progress cues are off: each delegated answer is awaited up to its ${created.delegation_timeout_seconds} s timeout`);
31469
31519
  }
31470
31520
  await port.connect(created.sdp_answer);
@@ -31488,20 +31538,22 @@ async function runOneCall(options, run, clips) {
31488
31538
  if (reason) result.stopped_by = reason;
31489
31539
  return reason !== null;
31490
31540
  };
31491
- const waitForAnswer = (lineEnd, delegated) => {
31492
- const notBeforeMs = delegated && silentWaitMs !== null ? lineEnd + silentWaitMs : void 0;
31493
- return port.waitForVoiceDone(lineEnd, quietAfter(delegated), timings.answerDoneTimeoutMs, stop, notBeforeMs);
31494
- };
31541
+ const waitForAnswer = (line) => port.waitForVoiceDone(
31542
+ line.endedAtMs,
31543
+ quietAfter(line.delegated),
31544
+ timings.answerDoneTimeoutMs,
31545
+ stop,
31546
+ line.delegated && answerOwedUntil ? answerOwedUntil(line.speechEnd) : void 0
31547
+ );
31495
31548
  await port.waitForVoiceDone(connectedAt, timings.ownAnswerQuietMs, timings.greetingTimeoutMs, stop);
31496
- let previousEnd = connectedAt;
31497
- let previousDelegated = false;
31549
+ let previous = { endedAtMs: connectedAt, speechEnd: connectedAt, delegated: false };
31498
31550
  for (const [i, line] of script.lines.entries()) {
31499
31551
  if (stop()) break;
31500
31552
  if (line.interrupt) {
31501
- const onset2 = await port.waitForVoiceOnset(previousEnd, timings.answerOnsetTimeoutMs, stop);
31553
+ const onset2 = await port.waitForVoiceOnset(previous.endedAtMs, timings.answerOnsetTimeoutMs, stop);
31502
31554
  if (onset2 !== null) await clock.sleep(Math.max(0, onset2 + timings.interruptAfterMs - clock.now()));
31503
31555
  } else if (i > 0) {
31504
- await waitForAnswer(previousEnd, previousDelegated);
31556
+ await waitForAnswer(previous);
31505
31557
  }
31506
31558
  if (stop()) break;
31507
31559
  const span = await port.play(clips[i], stop);
@@ -31509,11 +31561,10 @@ async function runOneCall(options, run, clips) {
31509
31561
  result.lines_said += 1;
31510
31562
  const onset = await port.waitForVoiceOnset(span.endedAtMs, timings.answerOnsetTimeoutMs, stop);
31511
31563
  result.timings.push({ n: line.n, started_at_ms: span.startedAtMs, ended_at_ms: span.endedAtMs, voice_onset_ms: onset });
31512
- previousEnd = span.endedAtMs;
31513
- previousDelegated = line.expect_delegation;
31564
+ previous = { endedAtMs: span.endedAtMs, speechEnd: span.endedAtMs - speechTailsMs[i], delegated: line.expect_delegation };
31514
31565
  }
31515
31566
  if (!result.stopped_by) {
31516
- await waitForAnswer(previousEnd, previousDelegated);
31567
+ await waitForAnswer(previous);
31517
31568
  }
31518
31569
  if (result.stopped_by) {
31519
31570
  result.status = "stopped";
@@ -31606,13 +31657,14 @@ async function runCallEvalSuite(options) {
31606
31657
  cost: { provider_usd: ledger.spentUsd, operations: ledger.spentOperations }
31607
31658
  };
31608
31659
  }
31609
- var systemRunnerClock, LONGEST_SPOKEN_LINE_MS, DEFAULT_RUNNER_TIMINGS, RECORD_SETTLE_TIMEOUT_MS, RECORD_POLL_MS;
31660
+ var systemRunnerClock, LONGEST_SPOKEN_LINE_MS, DEFAULT_RUNNER_TIMINGS, PROGRESS_CUES_HEARD_AT_MS, CUE_HEARD_EARLY_MS, CUE_HEARD_LATE_MS, SPEECH_STRETCH_GAP_MS, RECORD_SETTLE_TIMEOUT_MS, RECORD_POLL_MS;
31610
31661
  var init_runner = __esm({
31611
31662
  "src/lib/call-eval/runner.ts"() {
31612
31663
  "use strict";
31613
31664
  init_dist();
31614
31665
  init_contracts();
31615
31666
  init_errors2();
31667
+ init_caller_audio();
31616
31668
  init_cost_cap();
31617
31669
  init_score();
31618
31670
  systemRunnerClock = {
@@ -31625,10 +31677,14 @@ var init_runner = __esm({
31625
31677
  answerOnsetTimeoutMs: 2e4,
31626
31678
  answerDoneTimeoutMs: 45e3 + 2 * LONGEST_SPOKEN_LINE_MS,
31627
31679
  delegatedAnswerQuietMs: 5500,
31628
- silentWaitMarginMs: 3e3,
31680
+ answerTimeoutMarginMs: 3e3,
31629
31681
  ownAnswerQuietMs: 2e3,
31630
31682
  interruptAfterMs: 1e3
31631
31683
  };
31684
+ PROGRESS_CUES_HEARD_AT_MS = [5e3, 1e4];
31685
+ CUE_HEARD_EARLY_MS = 1e3;
31686
+ CUE_HEARD_LATE_MS = 2e3;
31687
+ SPEECH_STRETCH_GAP_MS = 1e3;
31632
31688
  RECORD_SETTLE_TIMEOUT_MS = 3e4;
31633
31689
  RECORD_POLL_MS = 1e3;
31634
31690
  }