@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 +77 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,
|
|
30534
|
-
|
|
30535
|
-
|
|
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 &&
|
|
30565
|
+
return quiet !== null && quiet > sinceMs && now - quiet >= quietMs;
|
|
30538
30566
|
};
|
|
30539
|
-
await waitFor(() =>
|
|
30540
|
-
return
|
|
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
|
|
31467
|
-
|
|
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 = (
|
|
31492
|
-
|
|
31493
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
}
|