open-agents-ai 0.51.0 → 0.53.0
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 +148 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17284,6 +17284,8 @@ function renderSlashHelp() {
|
|
|
17284
17284
|
["/listen manual", "Manual mode \u2014 press Enter to submit (turns off auto)"],
|
|
17285
17285
|
["/listen auto", "Auto-submit after 3s silence (blinking \u25CF indicator)"],
|
|
17286
17286
|
["/listen stop", "Stop listening"],
|
|
17287
|
+
["/call", "Start voice call session (cloudflared tunnel + PCM frontend)"],
|
|
17288
|
+
["/call stop", "Stop active call session"],
|
|
17287
17289
|
["/cost", "Show session token cost breakdown"],
|
|
17288
17290
|
["/evaluate", "Evaluate last completed task (LLM quality scoring)"],
|
|
17289
17291
|
["/task-type", "Set task type (code, document, analysis, plan, general, auto)"],
|
|
@@ -17672,6 +17674,7 @@ var init_render = __esm({
|
|
|
17672
17674
|
"/update",
|
|
17673
17675
|
"/voice",
|
|
17674
17676
|
"/listen",
|
|
17677
|
+
"/call",
|
|
17675
17678
|
"/stream",
|
|
17676
17679
|
"/verbose",
|
|
17677
17680
|
"/dream",
|
|
@@ -20711,6 +20714,41 @@ async function handleSlashCommand(input, ctx) {
|
|
|
20711
20714
|
renderInfo(msg);
|
|
20712
20715
|
return "handled";
|
|
20713
20716
|
}
|
|
20717
|
+
case "call": {
|
|
20718
|
+
if (!ctx.callStart) {
|
|
20719
|
+
renderWarning("Call mode not available in this context.");
|
|
20720
|
+
return "handled";
|
|
20721
|
+
}
|
|
20722
|
+
if (arg === "stop" || arg === "off") {
|
|
20723
|
+
if (ctx.isCallActive?.()) {
|
|
20724
|
+
await ctx.callStop?.();
|
|
20725
|
+
renderInfo("Call session ended.");
|
|
20726
|
+
} else {
|
|
20727
|
+
renderWarning("No active call session.");
|
|
20728
|
+
}
|
|
20729
|
+
return "handled";
|
|
20730
|
+
}
|
|
20731
|
+
if (ctx.isCallActive?.()) {
|
|
20732
|
+
const url = ctx.getCallUrl?.();
|
|
20733
|
+
if (url) {
|
|
20734
|
+
renderInfo(`Call session active: ${c2.bold(url)}`);
|
|
20735
|
+
} else {
|
|
20736
|
+
renderWarning("Call session active but no URL available yet.");
|
|
20737
|
+
}
|
|
20738
|
+
return "handled";
|
|
20739
|
+
}
|
|
20740
|
+
try {
|
|
20741
|
+
const url = await ctx.callStart();
|
|
20742
|
+
if (url) {
|
|
20743
|
+
renderInfo(`Call session started: ${c2.bold(url)}`);
|
|
20744
|
+
} else {
|
|
20745
|
+
renderWarning("Failed to start call session.");
|
|
20746
|
+
}
|
|
20747
|
+
} catch (err) {
|
|
20748
|
+
renderError(`Call error: ${err instanceof Error ? err.message : String(err)}`);
|
|
20749
|
+
}
|
|
20750
|
+
return "handled";
|
|
20751
|
+
}
|
|
20714
20752
|
case "bruteforce":
|
|
20715
20753
|
case "brute": {
|
|
20716
20754
|
const isOn = ctx.bruteForceToggle();
|
|
@@ -27416,6 +27454,10 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27416
27454
|
toolPolicyConfig;
|
|
27417
27455
|
/** Command handler for admin DM slash commands (wired from interactive.ts) */
|
|
27418
27456
|
commandHandler = null;
|
|
27457
|
+
/** Callback to get active call session URL (wired from interactive.ts) */
|
|
27458
|
+
callUrlGetter = null;
|
|
27459
|
+
/** Callback to write content into the scrollable TUI waterfall area (wired from interactive.ts) */
|
|
27460
|
+
writeContent = null;
|
|
27419
27461
|
/** Media cache — fileUniqueId → cache entry */
|
|
27420
27462
|
mediaCache = /* @__PURE__ */ new Map();
|
|
27421
27463
|
/** Media cache directory */
|
|
@@ -27449,6 +27491,14 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27449
27491
|
setCommandHandler(handler) {
|
|
27450
27492
|
this.commandHandler = handler;
|
|
27451
27493
|
}
|
|
27494
|
+
/** Register callback to get active call URL for /call button forwarding */
|
|
27495
|
+
setCallUrlGetter(getter) {
|
|
27496
|
+
this.callUrlGetter = getter;
|
|
27497
|
+
}
|
|
27498
|
+
/** Register callback to write content into the scrollable TUI area (status bar guard) */
|
|
27499
|
+
setWriteContent(fn) {
|
|
27500
|
+
this.writeContent = fn;
|
|
27501
|
+
}
|
|
27452
27502
|
/** Register event handler for sub-agent activity (waterfall view) */
|
|
27453
27503
|
setOnSubAgentEvent(handler) {
|
|
27454
27504
|
this.onSubAgentEvent = handler;
|
|
@@ -27462,6 +27512,14 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27462
27512
|
get botUsername() {
|
|
27463
27513
|
return this.state.botUsername;
|
|
27464
27514
|
}
|
|
27515
|
+
/** Write to the scrollable TUI waterfall area (respects status bar scroll region) */
|
|
27516
|
+
tuiWrite(fn) {
|
|
27517
|
+
if (this.writeContent) {
|
|
27518
|
+
this.writeContent(fn);
|
|
27519
|
+
} else {
|
|
27520
|
+
fn();
|
|
27521
|
+
}
|
|
27522
|
+
}
|
|
27465
27523
|
/** Start polling for Telegram messages */
|
|
27466
27524
|
async start() {
|
|
27467
27525
|
if (this.polling)
|
|
@@ -27597,10 +27655,21 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27597
27655
|
const isAdmin = this.isAdminUser(msg);
|
|
27598
27656
|
const toolContext = this.resolveToolContext(msg, isAdmin);
|
|
27599
27657
|
const isAdminDM = toolContext === "telegram-admin-dm";
|
|
27658
|
+
if (msg.text.trim().toLowerCase() === "/call" && this.callUrlGetter) {
|
|
27659
|
+
const callUrl = this.callUrlGetter();
|
|
27660
|
+
if (callUrl) {
|
|
27661
|
+
await this.sendCallButton(msg.chatId, callUrl);
|
|
27662
|
+
return;
|
|
27663
|
+
}
|
|
27664
|
+
if (!isAdmin) {
|
|
27665
|
+
await this.sendMessage(msg.chatId, "No active call session. Ask the admin to start one with /call.");
|
|
27666
|
+
return;
|
|
27667
|
+
}
|
|
27668
|
+
}
|
|
27600
27669
|
if (isAdminDM && msg.text.startsWith("/") && this.commandHandler) {
|
|
27601
27670
|
const cmdName = msg.text.split(/\s+/)[0].slice(1).toLowerCase();
|
|
27602
27671
|
if (cmdName !== "start") {
|
|
27603
|
-
renderTelegramSubAgentEvent(msg.username, `command: ${msg.text}`);
|
|
27672
|
+
this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, `command: ${msg.text}`));
|
|
27604
27673
|
try {
|
|
27605
27674
|
const result = await this.commandHandler(msg.text);
|
|
27606
27675
|
if (result) {
|
|
@@ -27620,7 +27689,7 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27620
27689
|
const existing = this.subAgents.get(msg.chatId);
|
|
27621
27690
|
if (existing && !existing.aborted) {
|
|
27622
27691
|
existing.runner.injectUserMessage(msg.text);
|
|
27623
|
-
renderTelegramSubAgentEvent(msg.username, "mid-conversation steering injected");
|
|
27692
|
+
this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "mid-conversation steering injected"));
|
|
27624
27693
|
return;
|
|
27625
27694
|
}
|
|
27626
27695
|
const subAgent = {
|
|
@@ -27638,7 +27707,7 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27638
27707
|
this.subAgents.set(msg.chatId, subAgent);
|
|
27639
27708
|
this.state.activeSubAgents = this.subAgents.size;
|
|
27640
27709
|
subAgent.typingInterval = this.startTypingIndicator(msg.chatId);
|
|
27641
|
-
renderTelegramSubAgentStart(msg.username, msg.text, isAdminDM);
|
|
27710
|
+
this.tuiWrite(() => renderTelegramSubAgentStart(msg.username, msg.text, isAdminDM));
|
|
27642
27711
|
try {
|
|
27643
27712
|
if (isAdminDM) {
|
|
27644
27713
|
const msgId = await this.sendLiveMessage(msg.chatId, "<i>\u23F3 Processing...</i>");
|
|
@@ -27654,7 +27723,7 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27654
27723
|
subAgent.typingInterval = null;
|
|
27655
27724
|
}
|
|
27656
27725
|
if (result === "no_reply" || result === "") {
|
|
27657
|
-
renderTelegramSubAgentEvent(msg.username, "discretion: skipped reply");
|
|
27726
|
+
this.tuiWrite(() => renderTelegramSubAgentEvent(msg.username, "discretion: skipped reply"));
|
|
27658
27727
|
return;
|
|
27659
27728
|
}
|
|
27660
27729
|
const finalText = result || "I couldn't generate a response. Please try again.";
|
|
@@ -27665,14 +27734,14 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27665
27734
|
} else {
|
|
27666
27735
|
await this.sendMessageHTML(msg.chatId, finalHtml, msg.chatType !== "private" ? msg.messageId : void 0);
|
|
27667
27736
|
}
|
|
27668
|
-
renderTelegramSubAgentComplete(msg.username, finalText);
|
|
27737
|
+
this.tuiWrite(() => renderTelegramSubAgentComplete(msg.username, finalText));
|
|
27669
27738
|
} catch (err) {
|
|
27670
27739
|
if (subAgent.typingInterval) {
|
|
27671
27740
|
clearInterval(subAgent.typingInterval);
|
|
27672
27741
|
subAgent.typingInterval = null;
|
|
27673
27742
|
}
|
|
27674
27743
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
27675
|
-
renderTelegramSubAgentError(msg.username, errMsg);
|
|
27744
|
+
this.tuiWrite(() => renderTelegramSubAgentError(msg.username, errMsg));
|
|
27676
27745
|
if (isAdminDM && subAgent.liveMessageId) {
|
|
27677
27746
|
await this.editLiveMessage(msg.chatId, subAgent.liveMessageId, `\u274C Error: ${errMsg}`).catch(() => {
|
|
27678
27747
|
});
|
|
@@ -27999,11 +28068,31 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
|
|
|
27999
28068
|
this.state.messagesSent++;
|
|
28000
28069
|
return result.result?.message_id ?? null;
|
|
28001
28070
|
} catch (err) {
|
|
28002
|
-
renderWarning(`Failed to send Telegram message: ${err instanceof Error ? err.message : String(err)}`);
|
|
28071
|
+
this.tuiWrite(() => renderWarning(`Failed to send Telegram message: ${err instanceof Error ? err.message : String(err)}`));
|
|
28003
28072
|
return null;
|
|
28004
28073
|
}
|
|
28005
28074
|
}
|
|
28006
28075
|
}
|
|
28076
|
+
/** Send an inline keyboard button to start a voice call session */
|
|
28077
|
+
async sendCallButton(chatId, url) {
|
|
28078
|
+
try {
|
|
28079
|
+
const result = await this.apiCall("sendMessage", {
|
|
28080
|
+
chat_id: chatId,
|
|
28081
|
+
text: "\u{1F4DE} <b>Voice Call Session</b>\n\nTap the button below to join the live voice call with the agent.",
|
|
28082
|
+
parse_mode: "HTML",
|
|
28083
|
+
reply_markup: {
|
|
28084
|
+
inline_keyboard: [[
|
|
28085
|
+
{ text: "\u{1F50A} Start Call", url }
|
|
28086
|
+
]]
|
|
28087
|
+
}
|
|
28088
|
+
});
|
|
28089
|
+
this.state.messagesSent++;
|
|
28090
|
+
return result.result?.message_id ?? null;
|
|
28091
|
+
} catch (err) {
|
|
28092
|
+
this.tuiWrite(() => renderWarning(`Failed to send call button: ${err instanceof Error ? err.message : String(err)}`));
|
|
28093
|
+
return null;
|
|
28094
|
+
}
|
|
28095
|
+
}
|
|
28007
28096
|
/**
|
|
28008
28097
|
* Send a voice message (WAV/OGG) to a Telegram chat using multipart form-data.
|
|
28009
28098
|
* Telegram requires OGG/Opus for sendVoice, but also accepts sendAudio with WAV.
|
|
@@ -28082,7 +28171,7 @@ ${caption}\r
|
|
|
28082
28171
|
}
|
|
28083
28172
|
return null;
|
|
28084
28173
|
} catch (err) {
|
|
28085
|
-
renderWarning(`Failed to send voice message: ${err instanceof Error ? err.message : String(err)}`);
|
|
28174
|
+
this.tuiWrite(() => renderWarning(`Failed to send voice message: ${err instanceof Error ? err.message : String(err)}`));
|
|
28086
28175
|
return null;
|
|
28087
28176
|
}
|
|
28088
28177
|
}
|
|
@@ -28219,7 +28308,7 @@ ${caption}\r
|
|
|
28219
28308
|
};
|
|
28220
28309
|
if (this.agentConfig && this.repoRoot) {
|
|
28221
28310
|
this.handleMessageWithSubAgent(msg).catch((err) => {
|
|
28222
|
-
renderWarning(`Telegram sub-agent error: ${err instanceof Error ? err.message : String(err)}`);
|
|
28311
|
+
this.tuiWrite(() => renderWarning(`Telegram sub-agent error: ${err instanceof Error ? err.message : String(err)}`));
|
|
28223
28312
|
});
|
|
28224
28313
|
} else {
|
|
28225
28314
|
this.onMessage(msg);
|
|
@@ -30683,6 +30772,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
30683
30772
|
if (adminId) {
|
|
30684
30773
|
telegramBridge.setAdmin(adminId);
|
|
30685
30774
|
}
|
|
30775
|
+
telegramBridge.setWriteContent(writeContent);
|
|
30686
30776
|
telegramBridge.setOnSubAgentEvent((chatId, username, event) => {
|
|
30687
30777
|
if (event.type === "tool_call" && event.toolName) {
|
|
30688
30778
|
const argsPreview = event.toolArgs ? JSON.stringify(event.toolArgs).slice(0, 60) : "";
|
|
@@ -30705,6 +30795,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
30705
30795
|
telegramBridge.setVoiceEngine(voiceEngine);
|
|
30706
30796
|
telegramBridge.voiceEnabled = true;
|
|
30707
30797
|
}
|
|
30798
|
+
telegramBridge.setCallUrlGetter(() => voiceSession?.tunnelUrl ?? null);
|
|
30708
30799
|
telegramBridge.setCommandHandler(async (input) => {
|
|
30709
30800
|
const captured = [];
|
|
30710
30801
|
const origWrite = process.stdout.write;
|
|
@@ -30867,6 +30958,54 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
30867
30958
|
}
|
|
30868
30959
|
return text ? `Stopped. Last transcript: "${text}"` : "Stopped listening.";
|
|
30869
30960
|
},
|
|
30961
|
+
// Voice call session — standalone cloudflared tunnel for /call
|
|
30962
|
+
async callStart() {
|
|
30963
|
+
if (voiceSession?.isActive) {
|
|
30964
|
+
return voiceSession.tunnelUrl;
|
|
30965
|
+
}
|
|
30966
|
+
voiceSession = new VoiceSession();
|
|
30967
|
+
voiceSession.on("userConnected", (id, username) => {
|
|
30968
|
+
writeContent(() => renderVoiceSessionUser("connected", username));
|
|
30969
|
+
});
|
|
30970
|
+
voiceSession.on("userDisconnected", (id) => {
|
|
30971
|
+
writeContent(() => renderVoiceSessionUser("disconnected", id));
|
|
30972
|
+
});
|
|
30973
|
+
try {
|
|
30974
|
+
const tunnelUrl = await voiceSession.start();
|
|
30975
|
+
writeContent(() => renderVoiceSessionStart(tunnelUrl));
|
|
30976
|
+
if (telegramBridge?.isActive && savedSettings.telegramAdmin) {
|
|
30977
|
+
const adminChatId = parseInt(savedSettings.telegramAdmin, 10);
|
|
30978
|
+
if (!isNaN(adminChatId)) {
|
|
30979
|
+
telegramBridge.sendCallButton(adminChatId, tunnelUrl).catch(() => {
|
|
30980
|
+
});
|
|
30981
|
+
}
|
|
30982
|
+
}
|
|
30983
|
+
return tunnelUrl;
|
|
30984
|
+
} catch (err) {
|
|
30985
|
+
writeContent(() => renderWarning(`Voice session failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
30986
|
+
voiceSession = null;
|
|
30987
|
+
return null;
|
|
30988
|
+
}
|
|
30989
|
+
},
|
|
30990
|
+
async callStop() {
|
|
30991
|
+
if (voiceSession?.isActive) {
|
|
30992
|
+
const runtime = voiceSession.runtime;
|
|
30993
|
+
await voiceSession.stop();
|
|
30994
|
+
writeContent(() => renderVoiceSessionStop(runtime));
|
|
30995
|
+
voiceSession = null;
|
|
30996
|
+
}
|
|
30997
|
+
},
|
|
30998
|
+
isCallActive() {
|
|
30999
|
+
return voiceSession?.isActive ?? false;
|
|
31000
|
+
},
|
|
31001
|
+
getCallUrl() {
|
|
31002
|
+
return voiceSession?.tunnelUrl ?? null;
|
|
31003
|
+
},
|
|
31004
|
+
async sendCallButton(chatId, url) {
|
|
31005
|
+
if (telegramBridge?.isActive) {
|
|
31006
|
+
await telegramBridge.sendCallButton(chatId, url);
|
|
31007
|
+
}
|
|
31008
|
+
},
|
|
30870
31009
|
getEmojis: () => getEmojisEnabled(),
|
|
30871
31010
|
setEmojis: (enabled) => setEmojisEnabled(enabled),
|
|
30872
31011
|
getColors: () => getColorsEnabled(),
|
package/package.json
CHANGED