open-agents-ai 0.137.0 → 0.138.1
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 +140 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21583,8 +21583,55 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
|
|
|
21583
21583
|
break;
|
|
21584
21584
|
}
|
|
21585
21585
|
if (/does not support tools|HTTP 400.*tools/i.test(errMsg)) {
|
|
21586
|
-
this.emit({
|
|
21587
|
-
|
|
21586
|
+
this.emit({
|
|
21587
|
+
type: "status",
|
|
21588
|
+
content: `Model lacks native tool support \u2014 switching to prompt-injected tool mode`,
|
|
21589
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
21590
|
+
});
|
|
21591
|
+
const toolDescriptions = Array.from(this.tools.values()).map((t) => `- ${t.name}: ${t.description}`).join("\n");
|
|
21592
|
+
const toolInjectMsg = [
|
|
21593
|
+
"\n\n[TOOL MODE \u2014 PROMPT INJECTION]",
|
|
21594
|
+
"This model does not have native tool-calling. To use tools, output a JSON block:",
|
|
21595
|
+
"```json",
|
|
21596
|
+
'{"tool": "tool_name", "args": {"param": "value"}}',
|
|
21597
|
+
"```",
|
|
21598
|
+
"\nAvailable tools:",
|
|
21599
|
+
toolDescriptions,
|
|
21600
|
+
"\nOutput EXACTLY ONE tool call per response in the JSON format above.",
|
|
21601
|
+
"After seeing the tool result, continue or call another tool.",
|
|
21602
|
+
'When done, output: {"tool": "task_complete", "args": {"summary": "what you did"}}'
|
|
21603
|
+
].join("\n");
|
|
21604
|
+
messages.push({ role: "system", content: toolInjectMsg });
|
|
21605
|
+
chatRequest.tools = [];
|
|
21606
|
+
try {
|
|
21607
|
+
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
21608
|
+
const content = response.choices?.[0]?.message?.content ?? "";
|
|
21609
|
+
const jsonMatch = content.match(/```json\s*\n?([\s\S]*?)```/);
|
|
21610
|
+
if (jsonMatch) {
|
|
21611
|
+
try {
|
|
21612
|
+
const parsed = JSON.parse(jsonMatch[1]);
|
|
21613
|
+
if (parsed.tool && this.tools.has(parsed.tool)) {
|
|
21614
|
+
const tool = this.tools.get(parsed.tool);
|
|
21615
|
+
const result = await tool.execute(parsed.args ?? {});
|
|
21616
|
+
messages.push({ role: "assistant", content });
|
|
21617
|
+
messages.push({ role: "user", content: `Tool result (${parsed.tool}): ${result.output.slice(0, 2e3)}` });
|
|
21618
|
+
if (parsed.tool === "task_complete") {
|
|
21619
|
+
completed = true;
|
|
21620
|
+
summary = String(parsed.args?.summary ?? content);
|
|
21621
|
+
}
|
|
21622
|
+
toolCallCount++;
|
|
21623
|
+
continue;
|
|
21624
|
+
}
|
|
21625
|
+
} catch {
|
|
21626
|
+
}
|
|
21627
|
+
}
|
|
21628
|
+
messages.push({ role: "assistant", content });
|
|
21629
|
+
continue;
|
|
21630
|
+
} catch (retryErr2) {
|
|
21631
|
+
const msg2 = retryErr2 instanceof Error ? retryErr2.message : String(retryErr2);
|
|
21632
|
+
this.emit({ type: "error", content: `Prompt-injected tool mode also failed: ${msg2}`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
21633
|
+
break;
|
|
21634
|
+
}
|
|
21588
21635
|
}
|
|
21589
21636
|
messages.push({ role: "user", content: "[System: backend request failed, retrying on next turn. The previous request was lost.]" });
|
|
21590
21637
|
continue;
|
|
@@ -38718,20 +38765,21 @@ var init_voice = __esm({
|
|
|
38718
38765
|
speak(text, emotion) {
|
|
38719
38766
|
const pitchBias = emotion ? emotionToPitchBias(emotion, this.starkMode, this.autistMode) : 0;
|
|
38720
38767
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
38721
|
-
this.enqueueSpeech(text, 1, 1 + pitchBias, speedFactor);
|
|
38768
|
+
this.enqueueSpeech(text, 1, 1 + pitchBias, speedFactor, 0.6);
|
|
38722
38769
|
}
|
|
38723
38770
|
/**
|
|
38724
|
-
* Speak text at reduced volume with
|
|
38771
|
+
* Speak text at reduced volume with narrow stereo placement to indicate
|
|
38725
38772
|
* subordinate/secondary output (sub-agent activity, tool narration, etc.).
|
|
38726
|
-
* Volume: 55% of primary.
|
|
38727
|
-
*
|
|
38773
|
+
* Volume: 55% of primary. Stereo delay: 0.15ms (narrow — "recessed/behind").
|
|
38774
|
+
* No pitch shift — depth is conveyed by stereo narrowness + lower volume.
|
|
38775
|
+
* Emotion still modulates pitch and speed on top.
|
|
38728
38776
|
*/
|
|
38729
38777
|
speakSubordinate(text, emotion) {
|
|
38730
38778
|
const pitchBias = emotion ? emotionToPitchBias(emotion, this.starkMode, this.autistMode) : 0;
|
|
38731
38779
|
const speedFactor = emotion ? emotionToSpeedFactor(emotion, this.starkMode, this.autistMode) : 1;
|
|
38732
|
-
this.enqueueSpeech(text, 0.55,
|
|
38780
|
+
this.enqueueSpeech(text, 0.55, 1 + pitchBias, speedFactor, 0.15);
|
|
38733
38781
|
}
|
|
38734
|
-
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1) {
|
|
38782
|
+
enqueueSpeech(text, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
38735
38783
|
if (!this.enabled || !this.ready)
|
|
38736
38784
|
return;
|
|
38737
38785
|
const chunks = this.chunkText(text);
|
|
@@ -38739,7 +38787,7 @@ var init_voice = __esm({
|
|
|
38739
38787
|
this.speakQueue.length = 0;
|
|
38740
38788
|
}
|
|
38741
38789
|
for (const chunk of chunks) {
|
|
38742
|
-
this.speakQueue.push({ text: chunk, volume, pitchFactor, speedFactor });
|
|
38790
|
+
this.speakQueue.push({ text: chunk, volume, pitchFactor, speedFactor, stereoDelayMs });
|
|
38743
38791
|
}
|
|
38744
38792
|
if (!this.speaking) {
|
|
38745
38793
|
this.drainQueue().catch(() => {
|
|
@@ -38919,7 +38967,7 @@ var init_voice = __esm({
|
|
|
38919
38967
|
}
|
|
38920
38968
|
isFirst = false;
|
|
38921
38969
|
try {
|
|
38922
|
-
await this.synthesizeAndPlay(item.text, item.volume, item.pitchFactor, item.speedFactor);
|
|
38970
|
+
await this.synthesizeAndPlay(item.text, item.volume, item.pitchFactor, item.speedFactor, item.stereoDelayMs);
|
|
38923
38971
|
} catch {
|
|
38924
38972
|
}
|
|
38925
38973
|
}
|
|
@@ -38931,9 +38979,9 @@ var init_voice = __esm({
|
|
|
38931
38979
|
// -------------------------------------------------------------------------
|
|
38932
38980
|
// Synthesis pipeline
|
|
38933
38981
|
// -------------------------------------------------------------------------
|
|
38934
|
-
async synthesizeAndPlay(text, volume = 1, pitchFactor = 1, speedFactor = 1) {
|
|
38982
|
+
async synthesizeAndPlay(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
38935
38983
|
if (this.luxttsActive) {
|
|
38936
|
-
await this.synthesizeWithLuxtts(text, volume, pitchFactor, speedFactor);
|
|
38984
|
+
await this.synthesizeWithLuxtts(text, volume, pitchFactor, speedFactor, stereoDelayMs);
|
|
38937
38985
|
return;
|
|
38938
38986
|
}
|
|
38939
38987
|
if (this.mlxActive) {
|
|
@@ -38979,6 +39027,7 @@ var init_voice = __esm({
|
|
|
38979
39027
|
if (pitchFactor !== 1) {
|
|
38980
39028
|
audioData = this.resamplePitch(audioData, pitchFactor);
|
|
38981
39029
|
}
|
|
39030
|
+
const stereo = this.applyStereoDelay(audioData, sampleRate, stereoDelayMs);
|
|
38982
39031
|
if (this.onPCMOutput) {
|
|
38983
39032
|
const int16 = new Int16Array(audioData.length);
|
|
38984
39033
|
for (let i = 0; i < audioData.length; i++) {
|
|
@@ -38988,7 +39037,7 @@ var init_voice = __esm({
|
|
|
38988
39037
|
this.onPCMOutput(Buffer.from(int16.buffer), sampleRate);
|
|
38989
39038
|
}
|
|
38990
39039
|
const wavPath = join50(tmpdir9(), `oa-voice-${Date.now()}.wav`);
|
|
38991
|
-
this.
|
|
39040
|
+
this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
|
|
38992
39041
|
await this.playWav(wavPath);
|
|
38993
39042
|
try {
|
|
38994
39043
|
unlinkSync8(wavPath);
|
|
@@ -39049,6 +39098,63 @@ var init_voice = __esm({
|
|
|
39049
39098
|
}
|
|
39050
39099
|
return out;
|
|
39051
39100
|
}
|
|
39101
|
+
/**
|
|
39102
|
+
* Apply interaural time delay (ITD) to create stereo depth from mono audio.
|
|
39103
|
+
*
|
|
39104
|
+
* The right channel is delayed by `delayMs` milliseconds relative to the left.
|
|
39105
|
+
* This creates a perceived spatial position — wider delay = more "present/forward",
|
|
39106
|
+
* narrower delay = more "recessed/behind". Based on Blauert's duplex theory:
|
|
39107
|
+
* ITDs below ~1.5ms produce lateralization without audible echo.
|
|
39108
|
+
*
|
|
39109
|
+
* Typical values:
|
|
39110
|
+
* 0.6ms — primary voice, wide stereo presence ("speaking to you")
|
|
39111
|
+
* 0.15ms — secondary voice, narrow/centered ("background, recessed")
|
|
39112
|
+
*/
|
|
39113
|
+
applyStereoDelay(mono, sampleRate, delayMs) {
|
|
39114
|
+
const delaySamples = Math.round(delayMs / 1e3 * sampleRate);
|
|
39115
|
+
const outLen = mono.length + delaySamples;
|
|
39116
|
+
const left = new Float32Array(outLen);
|
|
39117
|
+
const right = new Float32Array(outLen);
|
|
39118
|
+
left.set(mono, 0);
|
|
39119
|
+
right.set(mono, delaySamples);
|
|
39120
|
+
return { left, right };
|
|
39121
|
+
}
|
|
39122
|
+
/**
|
|
39123
|
+
* Write a stereo (2-channel interleaved) WAV file from left/right Float32 channels.
|
|
39124
|
+
* PCM 16-bit, same sample rate as the model output.
|
|
39125
|
+
*/
|
|
39126
|
+
writeStereoWav(left, right, sampleRate, path) {
|
|
39127
|
+
const numChannels = 2;
|
|
39128
|
+
const bitsPerSample = 16;
|
|
39129
|
+
const numSamples = Math.min(left.length, right.length);
|
|
39130
|
+
const byteRate = sampleRate * numChannels * (bitsPerSample / 8);
|
|
39131
|
+
const blockAlign = numChannels * (bitsPerSample / 8);
|
|
39132
|
+
const dataSize = numSamples * numChannels * (bitsPerSample / 8);
|
|
39133
|
+
const buffer = Buffer.alloc(44 + dataSize);
|
|
39134
|
+
buffer.write("RIFF", 0);
|
|
39135
|
+
buffer.writeUInt32LE(36 + dataSize, 4);
|
|
39136
|
+
buffer.write("WAVE", 8);
|
|
39137
|
+
buffer.write("fmt ", 12);
|
|
39138
|
+
buffer.writeUInt32LE(16, 16);
|
|
39139
|
+
buffer.writeUInt16LE(1, 20);
|
|
39140
|
+
buffer.writeUInt16LE(numChannels, 22);
|
|
39141
|
+
buffer.writeUInt32LE(sampleRate, 24);
|
|
39142
|
+
buffer.writeUInt32LE(byteRate, 28);
|
|
39143
|
+
buffer.writeUInt16LE(blockAlign, 32);
|
|
39144
|
+
buffer.writeUInt16LE(bitsPerSample, 34);
|
|
39145
|
+
buffer.write("data", 36);
|
|
39146
|
+
buffer.writeUInt32LE(dataSize, 40);
|
|
39147
|
+
let pos = 44;
|
|
39148
|
+
for (let i = 0; i < numSamples; i++) {
|
|
39149
|
+
const lSample = Math.max(-1, Math.min(1, left[i]));
|
|
39150
|
+
const rSample = Math.max(-1, Math.min(1, right[i]));
|
|
39151
|
+
buffer.writeInt16LE(lSample < 0 ? lSample * 32768 : lSample * 32767, pos);
|
|
39152
|
+
pos += 2;
|
|
39153
|
+
buffer.writeInt16LE(rSample < 0 ? rSample * 32768 : rSample * 32767, pos);
|
|
39154
|
+
pos += 2;
|
|
39155
|
+
}
|
|
39156
|
+
writeFileSync14(path, buffer);
|
|
39157
|
+
}
|
|
39052
39158
|
// -------------------------------------------------------------------------
|
|
39053
39159
|
// Phonemization
|
|
39054
39160
|
// -------------------------------------------------------------------------
|
|
@@ -39743,9 +39849,9 @@ if __name__ == '__main__':
|
|
|
39743
39849
|
/**
|
|
39744
39850
|
* Synthesize and play audio using LuxTTS voice cloning.
|
|
39745
39851
|
* Speed is passed natively to LuxTTS. Pitch is post-processed via resampling.
|
|
39746
|
-
* Volume is applied via WAV sample scaling.
|
|
39852
|
+
* Volume is applied via WAV sample scaling. Stereo ITD applied for depth.
|
|
39747
39853
|
*/
|
|
39748
|
-
async synthesizeWithLuxtts(text, volume = 1, pitchFactor = 1, speedFactor = 1) {
|
|
39854
|
+
async synthesizeWithLuxtts(text, volume = 1, pitchFactor = 1, speedFactor = 1, stereoDelayMs = 0.6) {
|
|
39749
39855
|
if (!this.luxttsCloneRef || !existsSync35(this.luxttsCloneRef)) {
|
|
39750
39856
|
return;
|
|
39751
39857
|
}
|
|
@@ -39810,6 +39916,25 @@ if __name__ == '__main__':
|
|
|
39810
39916
|
} catch {
|
|
39811
39917
|
}
|
|
39812
39918
|
}
|
|
39919
|
+
if (stereoDelayMs > 0) {
|
|
39920
|
+
try {
|
|
39921
|
+
const wavData = readFileSync24(wavPath);
|
|
39922
|
+
if (wavData.length > 44) {
|
|
39923
|
+
const sampleRate = wavData.readUInt32LE(24);
|
|
39924
|
+
const numChannels = wavData.readUInt16LE(22);
|
|
39925
|
+
if (numChannels === 1) {
|
|
39926
|
+
const int16 = new Int16Array(wavData.buffer, wavData.byteOffset + 44, (wavData.length - 44) / 2);
|
|
39927
|
+
const float32 = new Float32Array(int16.length);
|
|
39928
|
+
for (let i = 0; i < int16.length; i++) {
|
|
39929
|
+
float32[i] = int16[i] / 32768;
|
|
39930
|
+
}
|
|
39931
|
+
const stereo = this.applyStereoDelay(float32, sampleRate, stereoDelayMs);
|
|
39932
|
+
this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
|
|
39933
|
+
}
|
|
39934
|
+
}
|
|
39935
|
+
} catch {
|
|
39936
|
+
}
|
|
39937
|
+
}
|
|
39813
39938
|
await this.playWav(wavPath);
|
|
39814
39939
|
try {
|
|
39815
39940
|
unlinkSync8(wavPath);
|
package/package.json
CHANGED