open-agents-ai 0.50.0 → 0.52.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 +162 -23
- 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();
|
|
@@ -20941,27 +20979,36 @@ async function handleSlashCommand(input, ctx) {
|
|
|
20941
20979
|
ctx.telegramStatus?.();
|
|
20942
20980
|
return "handled";
|
|
20943
20981
|
}
|
|
20982
|
+
const isLocal = parts.includes("--local");
|
|
20944
20983
|
const keyIdx = parts.indexOf("--key");
|
|
20945
|
-
if (keyIdx !== -1) {
|
|
20946
|
-
const token = parts[keyIdx + 1];
|
|
20947
|
-
if (!token) {
|
|
20948
|
-
renderWarning("Usage: /telegram --key <bot-token>");
|
|
20949
|
-
renderInfo("Get a bot token from @BotFather on Telegram.");
|
|
20950
|
-
return "handled";
|
|
20951
|
-
}
|
|
20952
|
-
ctx.saveTelegramSettings?.({ key: token });
|
|
20953
|
-
renderInfo(`Telegram bot token saved (${token.slice(0, 6)}...). Use /telegram to start.`);
|
|
20954
|
-
return "handled";
|
|
20955
|
-
}
|
|
20956
20984
|
const adminIdx = parts.indexOf("--admin");
|
|
20957
|
-
if (adminIdx !== -1) {
|
|
20958
|
-
const
|
|
20959
|
-
|
|
20960
|
-
|
|
20961
|
-
|
|
20962
|
-
|
|
20963
|
-
|
|
20964
|
-
|
|
20985
|
+
if (keyIdx !== -1 || adminIdx !== -1) {
|
|
20986
|
+
const settings = { local: isLocal };
|
|
20987
|
+
const scope = isLocal ? "project" : "global";
|
|
20988
|
+
if (keyIdx !== -1) {
|
|
20989
|
+
const token = parts[keyIdx + 1];
|
|
20990
|
+
if (!token || token.startsWith("--")) {
|
|
20991
|
+
renderWarning("Usage: /telegram --key <bot-token> [--admin <id>] [--local]");
|
|
20992
|
+
renderInfo("Get a bot token from @BotFather on Telegram.");
|
|
20993
|
+
return "handled";
|
|
20994
|
+
}
|
|
20995
|
+
settings.key = token;
|
|
20996
|
+
}
|
|
20997
|
+
if (adminIdx !== -1) {
|
|
20998
|
+
const userId = parts[adminIdx + 1];
|
|
20999
|
+
if (!userId || userId.startsWith("--")) {
|
|
21000
|
+
renderWarning("Usage: /telegram --admin <user-id-or-username> [--key <token>] [--local]");
|
|
21001
|
+
return "handled";
|
|
21002
|
+
}
|
|
21003
|
+
settings.admin = userId;
|
|
21004
|
+
}
|
|
21005
|
+
ctx.saveTelegramSettings?.(settings);
|
|
21006
|
+
if (settings.key)
|
|
21007
|
+
renderInfo(`Telegram bot token saved to ${scope} settings (${settings.key.slice(0, 6)}...).`);
|
|
21008
|
+
if (settings.admin)
|
|
21009
|
+
renderInfo(`Telegram admin set to ${c2.bold(settings.admin)} (${scope}).`);
|
|
21010
|
+
if (!ctx.isTelegramActive?.() && settings.key)
|
|
21011
|
+
renderInfo("Use /telegram to start.");
|
|
20965
21012
|
return "handled";
|
|
20966
21013
|
}
|
|
20967
21014
|
if (!arg) {
|
|
@@ -20985,11 +21032,12 @@ async function handleSlashCommand(input, ctx) {
|
|
|
20985
21032
|
}
|
|
20986
21033
|
renderWarning(`Unknown argument: "${arg}"`);
|
|
20987
21034
|
renderInfo("Usage:");
|
|
20988
|
-
renderInfo(" /telegram --key <token> Save bot token");
|
|
20989
|
-
renderInfo(" /telegram --admin <id> Set admin
|
|
21035
|
+
renderInfo(" /telegram --key <token> Save bot token (global)");
|
|
21036
|
+
renderInfo(" /telegram --admin <id> Set admin filter (global)");
|
|
20990
21037
|
renderInfo(" /telegram Toggle on/off");
|
|
20991
21038
|
renderInfo(" /telegram stop Stop bridge");
|
|
20992
21039
|
renderInfo(" /telegram status Show status");
|
|
21040
|
+
renderInfo(" Add --local to scope settings to this project only");
|
|
20993
21041
|
return "handled";
|
|
20994
21042
|
}
|
|
20995
21043
|
default: {
|
|
@@ -27406,6 +27454,8 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27406
27454
|
toolPolicyConfig;
|
|
27407
27455
|
/** Command handler for admin DM slash commands (wired from interactive.ts) */
|
|
27408
27456
|
commandHandler = null;
|
|
27457
|
+
/** Callback to get active call session URL (wired from interactive.ts) */
|
|
27458
|
+
callUrlGetter = null;
|
|
27409
27459
|
/** Media cache — fileUniqueId → cache entry */
|
|
27410
27460
|
mediaCache = /* @__PURE__ */ new Map();
|
|
27411
27461
|
/** Media cache directory */
|
|
@@ -27439,6 +27489,10 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27439
27489
|
setCommandHandler(handler) {
|
|
27440
27490
|
this.commandHandler = handler;
|
|
27441
27491
|
}
|
|
27492
|
+
/** Register callback to get active call URL for /call button forwarding */
|
|
27493
|
+
setCallUrlGetter(getter) {
|
|
27494
|
+
this.callUrlGetter = getter;
|
|
27495
|
+
}
|
|
27442
27496
|
/** Register event handler for sub-agent activity (waterfall view) */
|
|
27443
27497
|
setOnSubAgentEvent(handler) {
|
|
27444
27498
|
this.onSubAgentEvent = handler;
|
|
@@ -27587,6 +27641,17 @@ with summary "no_reply" to silently skip without responding.
|
|
|
27587
27641
|
const isAdmin = this.isAdminUser(msg);
|
|
27588
27642
|
const toolContext = this.resolveToolContext(msg, isAdmin);
|
|
27589
27643
|
const isAdminDM = toolContext === "telegram-admin-dm";
|
|
27644
|
+
if (msg.text.trim().toLowerCase() === "/call" && this.callUrlGetter) {
|
|
27645
|
+
const callUrl = this.callUrlGetter();
|
|
27646
|
+
if (callUrl) {
|
|
27647
|
+
await this.sendCallButton(msg.chatId, callUrl);
|
|
27648
|
+
return;
|
|
27649
|
+
}
|
|
27650
|
+
if (!isAdmin) {
|
|
27651
|
+
await this.sendMessage(msg.chatId, "No active call session. Ask the admin to start one with /call.");
|
|
27652
|
+
return;
|
|
27653
|
+
}
|
|
27654
|
+
}
|
|
27590
27655
|
if (isAdminDM && msg.text.startsWith("/") && this.commandHandler) {
|
|
27591
27656
|
const cmdName = msg.text.split(/\s+/)[0].slice(1).toLowerCase();
|
|
27592
27657
|
if (cmdName !== "start") {
|
|
@@ -27994,6 +28059,26 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
|
|
|
27994
28059
|
}
|
|
27995
28060
|
}
|
|
27996
28061
|
}
|
|
28062
|
+
/** Send an inline keyboard button to start a voice call session */
|
|
28063
|
+
async sendCallButton(chatId, url) {
|
|
28064
|
+
try {
|
|
28065
|
+
const result = await this.apiCall("sendMessage", {
|
|
28066
|
+
chat_id: chatId,
|
|
28067
|
+
text: "\u{1F4DE} <b>Voice Call Session</b>\n\nTap the button below to join the live voice call with the agent.",
|
|
28068
|
+
parse_mode: "HTML",
|
|
28069
|
+
reply_markup: {
|
|
28070
|
+
inline_keyboard: [[
|
|
28071
|
+
{ text: "\u{1F50A} Start Call", url }
|
|
28072
|
+
]]
|
|
28073
|
+
}
|
|
28074
|
+
});
|
|
28075
|
+
this.state.messagesSent++;
|
|
28076
|
+
return result.result?.message_id ?? null;
|
|
28077
|
+
} catch (err) {
|
|
28078
|
+
renderWarning(`Failed to send call button: ${err instanceof Error ? err.message : String(err)}`);
|
|
28079
|
+
return null;
|
|
28080
|
+
}
|
|
28081
|
+
}
|
|
27997
28082
|
/**
|
|
27998
28083
|
* Send a voice message (WAV/OGG) to a Telegram chat using multipart form-data.
|
|
27999
28084
|
* Telegram requires OGG/Opus for sendVoice, but also accepts sendAudio with WAV.
|
|
@@ -30695,6 +30780,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
30695
30780
|
telegramBridge.setVoiceEngine(voiceEngine);
|
|
30696
30781
|
telegramBridge.voiceEnabled = true;
|
|
30697
30782
|
}
|
|
30783
|
+
telegramBridge.setCallUrlGetter(() => voiceSession?.tunnelUrl ?? null);
|
|
30698
30784
|
telegramBridge.setCommandHandler(async (input) => {
|
|
30699
30785
|
const captured = [];
|
|
30700
30786
|
const origWrite = process.stdout.write;
|
|
@@ -30753,10 +30839,15 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
30753
30839
|
if (settings.admin !== void 0) {
|
|
30754
30840
|
savedSettings.telegramAdmin = settings.admin;
|
|
30755
30841
|
}
|
|
30756
|
-
|
|
30842
|
+
const payload = {
|
|
30757
30843
|
...settings.key !== void 0 ? { telegramKey: settings.key } : {},
|
|
30758
30844
|
...settings.admin !== void 0 ? { telegramAdmin: settings.admin } : {}
|
|
30759
|
-
}
|
|
30845
|
+
};
|
|
30846
|
+
if (settings.local) {
|
|
30847
|
+
saveProjectSettings(repoRoot, payload);
|
|
30848
|
+
} else {
|
|
30849
|
+
saveGlobalSettings(payload);
|
|
30850
|
+
}
|
|
30760
30851
|
},
|
|
30761
30852
|
telegramStatus() {
|
|
30762
30853
|
const active = telegramBridge?.isActive ?? false;
|
|
@@ -30852,6 +30943,54 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
30852
30943
|
}
|
|
30853
30944
|
return text ? `Stopped. Last transcript: "${text}"` : "Stopped listening.";
|
|
30854
30945
|
},
|
|
30946
|
+
// Voice call session — standalone cloudflared tunnel for /call
|
|
30947
|
+
async callStart() {
|
|
30948
|
+
if (voiceSession?.isActive) {
|
|
30949
|
+
return voiceSession.tunnelUrl;
|
|
30950
|
+
}
|
|
30951
|
+
voiceSession = new VoiceSession();
|
|
30952
|
+
voiceSession.on("userConnected", (id, username) => {
|
|
30953
|
+
writeContent(() => renderVoiceSessionUser("connected", username));
|
|
30954
|
+
});
|
|
30955
|
+
voiceSession.on("userDisconnected", (id) => {
|
|
30956
|
+
writeContent(() => renderVoiceSessionUser("disconnected", id));
|
|
30957
|
+
});
|
|
30958
|
+
try {
|
|
30959
|
+
const tunnelUrl = await voiceSession.start();
|
|
30960
|
+
writeContent(() => renderVoiceSessionStart(tunnelUrl));
|
|
30961
|
+
if (telegramBridge?.isActive && savedSettings.telegramAdmin) {
|
|
30962
|
+
const adminChatId = parseInt(savedSettings.telegramAdmin, 10);
|
|
30963
|
+
if (!isNaN(adminChatId)) {
|
|
30964
|
+
telegramBridge.sendCallButton(adminChatId, tunnelUrl).catch(() => {
|
|
30965
|
+
});
|
|
30966
|
+
}
|
|
30967
|
+
}
|
|
30968
|
+
return tunnelUrl;
|
|
30969
|
+
} catch (err) {
|
|
30970
|
+
writeContent(() => renderWarning(`Voice session failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
30971
|
+
voiceSession = null;
|
|
30972
|
+
return null;
|
|
30973
|
+
}
|
|
30974
|
+
},
|
|
30975
|
+
async callStop() {
|
|
30976
|
+
if (voiceSession?.isActive) {
|
|
30977
|
+
const runtime = voiceSession.runtime;
|
|
30978
|
+
await voiceSession.stop();
|
|
30979
|
+
writeContent(() => renderVoiceSessionStop(runtime));
|
|
30980
|
+
voiceSession = null;
|
|
30981
|
+
}
|
|
30982
|
+
},
|
|
30983
|
+
isCallActive() {
|
|
30984
|
+
return voiceSession?.isActive ?? false;
|
|
30985
|
+
},
|
|
30986
|
+
getCallUrl() {
|
|
30987
|
+
return voiceSession?.tunnelUrl ?? null;
|
|
30988
|
+
},
|
|
30989
|
+
async sendCallButton(chatId, url) {
|
|
30990
|
+
if (telegramBridge?.isActive) {
|
|
30991
|
+
await telegramBridge.sendCallButton(chatId, url);
|
|
30992
|
+
}
|
|
30993
|
+
},
|
|
30855
30994
|
getEmojis: () => getEmojisEnabled(),
|
|
30856
30995
|
setEmojis: (enabled) => setEmojisEnabled(enabled),
|
|
30857
30996
|
getColors: () => getColorsEnabled(),
|
package/package.json
CHANGED