@grinev/opencode-telegram-bot 0.14.1 → 0.15.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/.env.example +12 -0
- package/README.md +44 -26
- package/dist/agent/manager.js +34 -6
- package/dist/agent/types.js +7 -1
- package/dist/bot/commands/commands.js +2 -2
- package/dist/bot/commands/definitions.js +1 -0
- package/dist/bot/commands/new.js +3 -2
- package/dist/bot/commands/projects.js +3 -2
- package/dist/bot/commands/sessions.js +3 -0
- package/dist/bot/commands/status.js +5 -2
- package/dist/bot/commands/tts.js +13 -0
- package/dist/bot/handlers/agent.js +3 -4
- package/dist/bot/handlers/model.js +3 -2
- package/dist/bot/handlers/prompt.js +22 -5
- package/dist/bot/handlers/variant.js +3 -2
- package/dist/bot/index.js +26 -5
- package/dist/bot/message-patterns.js +2 -2
- package/dist/bot/streaming/tool-call-streamer.js +31 -24
- package/dist/bot/utils/keyboard.js +6 -6
- package/dist/bot/utils/send-tts-response.js +37 -0
- package/dist/config.js +7 -0
- package/dist/i18n/de.js +17 -9
- package/dist/i18n/en.js +17 -9
- package/dist/i18n/es.js +17 -9
- package/dist/i18n/fr.js +17 -9
- package/dist/i18n/ru.js +17 -9
- package/dist/i18n/zh.js +17 -9
- package/dist/pinned/manager.js +66 -4
- package/dist/settings/manager.js +7 -0
- package/dist/summary/formatter.js +10 -1
- package/dist/tts/client.js +59 -0
- package/package.json +1 -1
package/dist/bot/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import { renameCommand, handleRenameCancel, handleRenameTextAnswer } from "./com
|
|
|
23
23
|
import { handleTaskCallback, handleTaskTextInput, taskCommand } from "./commands/task.js";
|
|
24
24
|
import { handleTaskListCallback, taskListCommand } from "./commands/tasklist.js";
|
|
25
25
|
import { commandsCommand, handleCommandsCallback, handleCommandTextArguments, } from "./commands/commands.js";
|
|
26
|
+
import { ttsCommand } from "./commands/tts.js";
|
|
26
27
|
import { handleQuestionCallback, showCurrentQuestion, handleQuestionTextAnswer, } from "./handlers/question.js";
|
|
27
28
|
import { handlePermissionCallback, showPermissionRequest } from "./handlers/permission.js";
|
|
28
29
|
import { handleAgentSelect, showAgentSelectionMenu } from "./handlers/agent.js";
|
|
@@ -46,11 +47,12 @@ import { safeBackgroundTask } from "../utils/safe-background-task.js";
|
|
|
46
47
|
import { withTelegramRateLimitRetry } from "../utils/telegram-rate-limit-retry.js";
|
|
47
48
|
import { pinnedMessageManager } from "../pinned/manager.js";
|
|
48
49
|
import { t } from "../i18n/index.js";
|
|
49
|
-
import { processUserPrompt } from "./handlers/prompt.js";
|
|
50
|
+
import { clearPromptResponseMode, processUserPrompt } from "./handlers/prompt.js";
|
|
50
51
|
import { handleVoiceMessage } from "./handlers/voice.js";
|
|
51
52
|
import { handleDocumentMessage } from "./handlers/document.js";
|
|
52
53
|
import { downloadTelegramFile, toDataUri } from "./utils/file-download.js";
|
|
53
54
|
import { finalizeAssistantResponse } from "./utils/finalize-assistant-response.js";
|
|
55
|
+
import { sendTtsResponseForSession } from "./utils/send-tts-response.js";
|
|
54
56
|
import { deliverThinkingMessage } from "./utils/thinking-message.js";
|
|
55
57
|
import { sendBotText } from "./utils/telegram-text.js";
|
|
56
58
|
import { getModelCapabilities, supportsInput } from "../model/capabilities.js";
|
|
@@ -242,6 +244,12 @@ const toolCallStreamer = new ToolCallStreamer({
|
|
|
242
244
|
});
|
|
243
245
|
},
|
|
244
246
|
});
|
|
247
|
+
function getToolStreamKey(tool) {
|
|
248
|
+
if (tool === "todowrite") {
|
|
249
|
+
return "todo";
|
|
250
|
+
}
|
|
251
|
+
return "default";
|
|
252
|
+
}
|
|
245
253
|
async function ensureCommandsInitialized(ctx, next) {
|
|
246
254
|
if (commandsInitialized || !ctx.from || ctx.from.id !== config.telegram.allowedUserId) {
|
|
247
255
|
await next();
|
|
@@ -297,6 +305,7 @@ async function ensureEventSubscription(directory) {
|
|
|
297
305
|
summaryAggregator.setOnComplete(async (sessionId, messageId, messageText) => {
|
|
298
306
|
if (!botInstance || !chatIdInstance) {
|
|
299
307
|
logger.error("Bot or chat ID not available for sending message");
|
|
308
|
+
clearPromptResponseMode(sessionId);
|
|
300
309
|
responseStreamer.clearMessage(sessionId, messageId, "bot_context_missing");
|
|
301
310
|
toolCallStreamer.clearSession(sessionId, "bot_context_missing");
|
|
302
311
|
foregroundSessionState.markIdle(sessionId);
|
|
@@ -304,6 +313,7 @@ async function ensureEventSubscription(directory) {
|
|
|
304
313
|
}
|
|
305
314
|
const currentSession = getCurrentSession();
|
|
306
315
|
if (currentSession?.id !== sessionId) {
|
|
316
|
+
clearPromptResponseMode(sessionId);
|
|
307
317
|
responseStreamer.clearMessage(sessionId, messageId, "session_mismatch");
|
|
308
318
|
toolCallStreamer.clearSession(sessionId, "session_mismatch");
|
|
309
319
|
foregroundSessionState.markIdle(sessionId);
|
|
@@ -348,8 +358,15 @@ async function ensureEventSubscription(directory) {
|
|
|
348
358
|
}
|
|
349
359
|
},
|
|
350
360
|
});
|
|
361
|
+
await sendTtsResponseForSession({
|
|
362
|
+
api: botApi,
|
|
363
|
+
sessionId,
|
|
364
|
+
chatId,
|
|
365
|
+
text: messageText,
|
|
366
|
+
});
|
|
351
367
|
}
|
|
352
368
|
catch (err) {
|
|
369
|
+
clearPromptResponseMode(sessionId);
|
|
353
370
|
logger.error("Failed to send message to Telegram:", err);
|
|
354
371
|
// Stop processing events after critical error to prevent infinite loop
|
|
355
372
|
logger.error("[Bot] CRITICAL: Stopping event processing due to error");
|
|
@@ -379,7 +396,7 @@ async function ensureEventSubscription(directory) {
|
|
|
379
396
|
try {
|
|
380
397
|
const message = formatToolInfo(toolInfo);
|
|
381
398
|
if (message) {
|
|
382
|
-
toolCallStreamer.append(toolInfo.sessionId, message);
|
|
399
|
+
toolCallStreamer.append(toolInfo.sessionId, message, getToolStreamKey(toolInfo.tool));
|
|
383
400
|
}
|
|
384
401
|
}
|
|
385
402
|
catch (err) {
|
|
@@ -402,7 +419,7 @@ async function ensureEventSubscription(directory) {
|
|
|
402
419
|
if (!renderedCards) {
|
|
403
420
|
return;
|
|
404
421
|
}
|
|
405
|
-
toolCallStreamer.replaceByPrefix(sessionId, SUBAGENT_STREAM_PREFIX, renderedCards);
|
|
422
|
+
toolCallStreamer.replaceByPrefix(sessionId, SUBAGENT_STREAM_PREFIX, renderedCards, "subagent");
|
|
406
423
|
}
|
|
407
424
|
catch (err) {
|
|
408
425
|
logger.error("Failed to render subagent activity for Telegram:", err);
|
|
@@ -553,11 +570,13 @@ async function ensureEventSubscription(directory) {
|
|
|
553
570
|
});
|
|
554
571
|
summaryAggregator.setOnSessionError(async (sessionId, message) => {
|
|
555
572
|
if (!botInstance || !chatIdInstance) {
|
|
573
|
+
clearPromptResponseMode(sessionId);
|
|
556
574
|
foregroundSessionState.markIdle(sessionId);
|
|
557
575
|
return;
|
|
558
576
|
}
|
|
559
577
|
const currentSession = getCurrentSession();
|
|
560
578
|
if (!currentSession || currentSession.id !== sessionId) {
|
|
579
|
+
clearPromptResponseMode(sessionId);
|
|
561
580
|
responseStreamer.clearSession(sessionId, "session_error_not_current");
|
|
562
581
|
toolCallStreamer.clearSession(sessionId, "session_error_not_current");
|
|
563
582
|
foregroundSessionState.markIdle(sessionId);
|
|
@@ -565,6 +584,7 @@ async function ensureEventSubscription(directory) {
|
|
|
565
584
|
return;
|
|
566
585
|
}
|
|
567
586
|
responseStreamer.clearSession(sessionId, "session_error");
|
|
587
|
+
clearPromptResponseMode(sessionId);
|
|
568
588
|
await Promise.all([
|
|
569
589
|
toolMessageBatcher.flushSession(sessionId, "session_error"),
|
|
570
590
|
toolCallStreamer.flushSession(sessionId, "session_error"),
|
|
@@ -712,6 +732,7 @@ export function createBot() {
|
|
|
712
732
|
bot.command("start", startCommand);
|
|
713
733
|
bot.command("help", helpCommand);
|
|
714
734
|
bot.command("status", statusCommand);
|
|
735
|
+
bot.command("tts", ttsCommand);
|
|
715
736
|
bot.command("opencode_start", opencodeStartCommand);
|
|
716
737
|
bot.command("opencode_stop", opencodeStopCommand);
|
|
717
738
|
bot.command("projects", projectsCommand);
|
|
@@ -768,9 +789,9 @@ export function createBot() {
|
|
|
768
789
|
await ctx.answerCallbackQuery({ text: t("callback.processing_error") }).catch(() => { });
|
|
769
790
|
}
|
|
770
791
|
});
|
|
771
|
-
// Handle Reply Keyboard button press (agent
|
|
792
|
+
// Handle Reply Keyboard button press (agent indicator)
|
|
772
793
|
bot.hears(AGENT_MODE_BUTTON_TEXT_PATTERN, async (ctx) => {
|
|
773
|
-
logger.debug(`[Bot] Agent
|
|
794
|
+
logger.debug(`[Bot] Agent button pressed: ${ctx.message?.text}`);
|
|
774
795
|
try {
|
|
775
796
|
if (await blockMenuWhileInteractionActive(ctx)) {
|
|
776
797
|
return;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const AGENT_MODE_BUTTON_TEXT_PATTERN = /^(📋|🛠️|💬|🔍|📝|📄|📦|🤖)\s.+\
|
|
2
|
-
export const MODEL_BUTTON_TEXT_PATTERN = /^🤖\s(?!.*\
|
|
1
|
+
export const AGENT_MODE_BUTTON_TEXT_PATTERN = /^(📋|🛠️|💬|🔍|📝|📄|📦|🤖)\s.+\s(?:Mode|Agent)$/;
|
|
2
|
+
export const MODEL_BUTTON_TEXT_PATTERN = /^🤖\s(?!.*\s(?:Mode|Agent)$)[\s\S]+$/;
|
|
3
3
|
// Keep support for both legacy "💭" and current "💡" prefix.
|
|
4
4
|
export const VARIANT_BUTTON_TEXT_PATTERN = /^(💡|💭)\s.+$/;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { logger } from "../../utils/logger.js";
|
|
2
2
|
const TELEGRAM_MESSAGE_SAFE_LENGTH = 4000;
|
|
3
|
+
const DEFAULT_STREAM_KEY = "default";
|
|
3
4
|
function getErrorMessage(error) {
|
|
4
5
|
if (error instanceof Error) {
|
|
5
6
|
return error.message;
|
|
@@ -68,23 +69,23 @@ export class ToolCallStreamer {
|
|
|
68
69
|
this.editText = options.editText;
|
|
69
70
|
this.deleteText = options.deleteText;
|
|
70
71
|
}
|
|
71
|
-
append(sessionId, text) {
|
|
72
|
+
append(sessionId, text, streamKey = DEFAULT_STREAM_KEY) {
|
|
72
73
|
const normalizedText = text.trim();
|
|
73
74
|
if (!sessionId || !normalizedText) {
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
76
|
-
const state = this.getOrCreateState(sessionId);
|
|
77
|
+
const state = this.getOrCreateState(sessionId, streamKey);
|
|
77
78
|
state.entries.push({ text: normalizedText });
|
|
78
79
|
state.latestParts = buildParts(state.entries);
|
|
79
80
|
this.ensureTimer(state);
|
|
80
81
|
}
|
|
81
|
-
replaceByPrefix(sessionId, prefix, text) {
|
|
82
|
+
replaceByPrefix(sessionId, prefix, text, streamKey = DEFAULT_STREAM_KEY) {
|
|
82
83
|
const normalizedPrefix = prefix.trim();
|
|
83
84
|
const normalizedText = text.trim();
|
|
84
85
|
if (!sessionId || !normalizedPrefix || !normalizedText) {
|
|
85
86
|
return;
|
|
86
87
|
}
|
|
87
|
-
const state = this.getOrCreateState(sessionId);
|
|
88
|
+
const state = this.getOrCreateState(sessionId, streamKey);
|
|
88
89
|
const existingEntry = state.entries.find((entry) => entry.prefix === normalizedPrefix);
|
|
89
90
|
if (existingEntry) {
|
|
90
91
|
existingEntry.text = normalizedText;
|
|
@@ -96,24 +97,21 @@ export class ToolCallStreamer {
|
|
|
96
97
|
this.ensureTimer(state);
|
|
97
98
|
}
|
|
98
99
|
async flushSession(sessionId, reason) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
await this.enqueueTask(state, () => this.syncState(state, reason));
|
|
100
|
+
const states = this.getStatesForSession(sessionId);
|
|
101
|
+
await Promise.all(states.map(async (state) => {
|
|
102
|
+
this.clearTimer(state);
|
|
103
|
+
await this.enqueueTask(state, () => this.syncState(state, reason));
|
|
104
|
+
}));
|
|
105
105
|
}
|
|
106
106
|
async breakSession(sessionId, reason) {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
const states = this.getStatesForSession(sessionId);
|
|
108
|
+
for (const state of states) {
|
|
109
|
+
state.isBreaking = true;
|
|
110
|
+
this.clearTimer(state);
|
|
111
|
+
await this.enqueueTask(state, () => this.syncState(state, reason));
|
|
112
|
+
this.cancelState(state);
|
|
113
|
+
this.removeState(state);
|
|
110
114
|
}
|
|
111
|
-
state.isBreaking = true;
|
|
112
|
-
this.getOrCreateState(sessionId);
|
|
113
|
-
this.clearTimer(state);
|
|
114
|
-
await this.enqueueTask(state, () => this.syncState(state, reason));
|
|
115
|
-
this.cancelState(state);
|
|
116
|
-
this.removeState(state);
|
|
117
115
|
logger.debug(`[ToolCallStreamer] Broke session stream: session=${sessionId}, reason=${reason}`);
|
|
118
116
|
}
|
|
119
117
|
clearSession(sessionId, reason) {
|
|
@@ -141,8 +139,15 @@ export class ToolCallStreamer {
|
|
|
141
139
|
logger.debug(`[ToolCallStreamer] Cleared all streams: count=${count}, reason=${reason}`);
|
|
142
140
|
}
|
|
143
141
|
}
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
getStateId(sessionId, streamKey) {
|
|
143
|
+
return `${sessionId}:${streamKey}`;
|
|
144
|
+
}
|
|
145
|
+
getStatesForSession(sessionId) {
|
|
146
|
+
return Array.from(this.allStates).filter((state) => state.sessionId === sessionId);
|
|
147
|
+
}
|
|
148
|
+
getOrCreateState(sessionId, streamKey = DEFAULT_STREAM_KEY) {
|
|
149
|
+
const stateId = this.getStateId(sessionId, streamKey);
|
|
150
|
+
const existing = this.states.get(stateId);
|
|
146
151
|
if (existing && !existing.isBroken && !existing.cancelled && !existing.isBreaking) {
|
|
147
152
|
return existing;
|
|
148
153
|
}
|
|
@@ -151,6 +156,7 @@ export class ToolCallStreamer {
|
|
|
151
156
|
this.removeState(existing);
|
|
152
157
|
}
|
|
153
158
|
const state = {
|
|
159
|
+
key: streamKey,
|
|
154
160
|
sessionId,
|
|
155
161
|
entries: [],
|
|
156
162
|
latestParts: [],
|
|
@@ -164,7 +170,7 @@ export class ToolCallStreamer {
|
|
|
164
170
|
fatalErrorMessage: null,
|
|
165
171
|
fatalErrorLogged: false,
|
|
166
172
|
};
|
|
167
|
-
this.states.set(
|
|
173
|
+
this.states.set(stateId, state);
|
|
168
174
|
this.allStates.add(state);
|
|
169
175
|
return state;
|
|
170
176
|
}
|
|
@@ -202,8 +208,9 @@ export class ToolCallStreamer {
|
|
|
202
208
|
this.clearTimer(state);
|
|
203
209
|
}
|
|
204
210
|
removeState(state) {
|
|
205
|
-
|
|
206
|
-
|
|
211
|
+
const stateId = this.getStateId(state.sessionId, state.key);
|
|
212
|
+
if (this.states.get(stateId) === state) {
|
|
213
|
+
this.states.delete(stateId);
|
|
207
214
|
}
|
|
208
215
|
this.allStates.delete(state);
|
|
209
216
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Keyboard } from "grammy";
|
|
2
|
-
import {
|
|
2
|
+
import { getAgentButtonLabel } from "../../agent/types.js";
|
|
3
3
|
import { formatModelForButton } from "../../model/types.js";
|
|
4
4
|
import { t } from "../../i18n/index.js";
|
|
5
5
|
/**
|
|
@@ -33,7 +33,7 @@ function formatContextForButton(contextInfo) {
|
|
|
33
33
|
*/
|
|
34
34
|
export function createMainKeyboard(currentAgent, currentModel, contextInfo, variantName) {
|
|
35
35
|
const keyboard = new Keyboard();
|
|
36
|
-
const agentText =
|
|
36
|
+
const agentText = getAgentButtonLabel(currentAgent);
|
|
37
37
|
// Format model with compact provider/model text and icon
|
|
38
38
|
const modelText = formatModelForButton(currentModel.providerID, currentModel.modelID);
|
|
39
39
|
// Context text - show "0" if no data available
|
|
@@ -49,15 +49,15 @@ export function createMainKeyboard(currentAgent, currentModel, contextInfo, vari
|
|
|
49
49
|
return keyboard.resized().persistent();
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
* Create Reply Keyboard with agent
|
|
52
|
+
* Create Reply Keyboard with agent indicator
|
|
53
53
|
* @param currentAgent Current agent name (e.g., "build", "plan")
|
|
54
|
-
* @returns Reply Keyboard with single button showing current
|
|
54
|
+
* @returns Reply Keyboard with single button showing current agent
|
|
55
55
|
* @deprecated Use createMainKeyboard instead
|
|
56
56
|
*/
|
|
57
57
|
export function createAgentKeyboard(currentAgent) {
|
|
58
58
|
const keyboard = new Keyboard();
|
|
59
|
-
const displayName =
|
|
60
|
-
// Single button with current agent
|
|
59
|
+
const displayName = getAgentButtonLabel(currentAgent);
|
|
60
|
+
// Single button with current agent
|
|
61
61
|
keyboard.text(displayName).row();
|
|
62
62
|
return keyboard.resized().persistent();
|
|
63
63
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { InputFile } from "grammy";
|
|
2
|
+
import { consumePromptResponseMode } from "../handlers/prompt.js";
|
|
3
|
+
import { isTtsConfigured, synthesizeSpeech } from "../../tts/client.js";
|
|
4
|
+
import { t } from "../../i18n/index.js";
|
|
5
|
+
import { logger } from "../../utils/logger.js";
|
|
6
|
+
const MAX_TTS_INPUT_CHARS = 4_000;
|
|
7
|
+
export async function sendTtsResponseForSession({ api, sessionId, chatId, text, consumeResponseMode: consumeResponseModeImpl = consumePromptResponseMode, isTtsConfigured: isTtsConfiguredImpl = isTtsConfigured, synthesizeSpeech: synthesizeSpeechImpl = synthesizeSpeech, }) {
|
|
8
|
+
const responseMode = consumeResponseModeImpl(sessionId);
|
|
9
|
+
if (responseMode !== "text_and_tts") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
const normalizedText = text.trim();
|
|
13
|
+
if (!normalizedText) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
if (!isTtsConfiguredImpl()) {
|
|
17
|
+
logger.info(`[TTS] Skipping audio reply for session ${sessionId}: TTS is not configured`);
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (normalizedText.length > MAX_TTS_INPUT_CHARS) {
|
|
21
|
+
logger.warn(`[TTS] Skipping audio reply for session ${sessionId}: text length ${normalizedText.length} exceeds limit ${MAX_TTS_INPUT_CHARS}`);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const speech = await synthesizeSpeechImpl(normalizedText);
|
|
26
|
+
await api.sendAudio(chatId, new InputFile(speech.buffer, speech.filename));
|
|
27
|
+
logger.info(`[TTS] Sent audio reply for session ${sessionId}`);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
logger.warn(`[TTS] Failed to send audio reply for session ${sessionId}`, error);
|
|
32
|
+
await api.sendMessage(chatId, t("tts.failed")).catch((sendError) => {
|
|
33
|
+
logger.warn(`[TTS] Failed to send audio error message for session ${sessionId}`, sendError);
|
|
34
|
+
});
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/config.js
CHANGED
|
@@ -74,6 +74,7 @@ export const config = {
|
|
|
74
74
|
commandsListLimit: getOptionalPositiveIntEnvVar("COMMANDS_LIST_LIMIT", 10),
|
|
75
75
|
taskLimit: getOptionalPositiveIntEnvVar("TASK_LIMIT", 10),
|
|
76
76
|
responseStreamThrottleMs: getOptionalPositiveIntEnvVar("RESPONSE_STREAM_THROTTLE_MS", 500),
|
|
77
|
+
bashToolDisplayMaxLength: getOptionalPositiveIntEnvVar("BASH_TOOL_DISPLAY_MAX_LENGTH", 128),
|
|
77
78
|
locale: getOptionalLocaleEnvVar("BOT_LOCALE", "en"),
|
|
78
79
|
hideThinkingMessages: getOptionalBooleanEnvVar("HIDE_THINKING_MESSAGES", false),
|
|
79
80
|
hideToolCallMessages: getOptionalBooleanEnvVar("HIDE_TOOL_CALL_MESSAGES", false),
|
|
@@ -88,4 +89,10 @@ export const config = {
|
|
|
88
89
|
model: getEnvVar("STT_MODEL", false) || "whisper-large-v3-turbo",
|
|
89
90
|
language: getEnvVar("STT_LANGUAGE", false),
|
|
90
91
|
},
|
|
92
|
+
tts: {
|
|
93
|
+
apiUrl: getEnvVar("TTS_API_URL", false),
|
|
94
|
+
apiKey: getEnvVar("TTS_API_KEY", false),
|
|
95
|
+
model: getEnvVar("TTS_MODEL", false) || "gpt-4o-mini-tts",
|
|
96
|
+
voice: getEnvVar("TTS_VOICE", false) || "alloy",
|
|
97
|
+
},
|
|
91
98
|
};
|
package/dist/i18n/de.js
CHANGED
|
@@ -3,6 +3,7 @@ export const de = {
|
|
|
3
3
|
"cmd.description.new": "Neue Sitzung erstellen",
|
|
4
4
|
"cmd.description.stop": "Aktuelle Aktion stoppen",
|
|
5
5
|
"cmd.description.sessions": "Sitzungen auflisten",
|
|
6
|
+
"cmd.description.tts": "Audioantworten umschalten",
|
|
6
7
|
"cmd.description.projects": "Projekte auflisten",
|
|
7
8
|
"cmd.description.task": "Geplante Aufgabe erstellen",
|
|
8
9
|
"cmd.description.tasklist": "Geplante Aufgaben anzeigen",
|
|
@@ -32,8 +33,8 @@ export const de = {
|
|
|
32
33
|
"inline.cancelled_callback": "Abgebrochen",
|
|
33
34
|
"common.unknown": "unbekannt",
|
|
34
35
|
"common.unknown_error": "unbekannter Fehler",
|
|
35
|
-
"start.welcome": "👋 Willkommen beim OpenCode Telegram Bot!\n\nNutze Befehle:\n/projects — Projekt auswählen\n/sessions — Sitzungsliste\n/new — neue Sitzung\n/task — geplante Aufgabe\n/tasklist — geplante Aufgaben\n/status — Status\n/help — Hilfe\n\nNutze die unteren Buttons, um
|
|
36
|
-
"help.keyboard_hint": "💡 Nutze die unteren Buttons für
|
|
36
|
+
"start.welcome": "👋 Willkommen beim OpenCode Telegram Bot!\n\nNutze Befehle:\n/projects — Projekt auswählen\n/sessions — Sitzungsliste\n/new — neue Sitzung\n/task — geplante Aufgabe\n/tasklist — geplante Aufgaben\n/status — Status\n/help — Hilfe\n\nNutze die unteren Buttons, um Agent, Modell und Variante zu wählen.",
|
|
37
|
+
"help.keyboard_hint": "💡 Nutze die unteren Buttons für Agent, Modell, Variante und Kontextaktionen.",
|
|
37
38
|
"help.text": "📖 **Hilfe**\n\n/status - Serverstatus prüfen\n/sessions - Sitzungsliste\n/new - Neue Sitzung erstellen\n/help - Hilfe",
|
|
38
39
|
"bot.thinking": "💭 Denke...",
|
|
39
40
|
"bot.project_not_selected": "🏗 Projekt ist nicht ausgewählt.\n\nWähle zuerst ein Projekt mit /projects.",
|
|
@@ -65,8 +66,11 @@ export const de = {
|
|
|
65
66
|
"status.line.managed_no": "Vom Bot gestartet: Nein",
|
|
66
67
|
"status.line.pid": "PID: {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Betriebszeit: {seconds} s",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agent: {mode}",
|
|
69
70
|
"status.line.model": "Modell: {model}",
|
|
71
|
+
"status.line.tts": "TTS-Antworten: {tts}",
|
|
72
|
+
"status.tts.on": "Ein",
|
|
73
|
+
"status.tts.off": "Aus",
|
|
70
74
|
"status.agent_not_set": "nicht gesetzt",
|
|
71
75
|
"status.project_selected": "Projekt: {project}",
|
|
72
76
|
"status.project_not_selected": "Projekt: nicht ausgewählt",
|
|
@@ -75,6 +79,10 @@ export const de = {
|
|
|
75
79
|
"status.session_not_selected": "Aktuelle Sitzung: nicht ausgewählt",
|
|
76
80
|
"status.session_hint": "Nutze /sessions zur Auswahl oder /new zum Erstellen",
|
|
77
81
|
"status.server_unavailable": "🔴 OpenCode-Server ist nicht verfügbar\n\nNutze /opencode_start, um den Server zu starten.",
|
|
82
|
+
"tts.enabled": "🔊 Audioantworten global aktiviert.",
|
|
83
|
+
"tts.not_configured": "⚠️ Audioantworten sind nicht verfugbar. Setze zuerst `TTS_API_URL` und `TTS_API_KEY`.",
|
|
84
|
+
"tts.disabled": "🔇 Audioantworten global deaktiviert.",
|
|
85
|
+
"tts.failed": "⚠️ Audioreply konnte nicht erzeugt werden.",
|
|
78
86
|
"projects.empty": "📭 Keine Projekte gefunden.\n\nÖffne ein Verzeichnis in OpenCode und erstelle mindestens eine Sitzung, dann erscheint es hier.",
|
|
79
87
|
"projects.select": "Projekt auswählen:",
|
|
80
88
|
"projects.select_with_current": "Projekt auswählen:\n\nAktuell: 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const de = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 OpenCode-Server konnte nicht gestoppt werden\n\nFehler: {error}",
|
|
128
136
|
"opencode_stop.success": "✅ OpenCode-Server erfolgreich gestoppt",
|
|
129
137
|
"opencode_stop.error": "🔴 Beim Stoppen des Servers ist ein Fehler aufgetreten.\n\nSiehe Anwendungslogs für Details.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "
|
|
133
|
-
"agent.menu.current": "Aktueller
|
|
134
|
-
"agent.menu.select": "
|
|
138
|
+
"agent.changed_callback": "Agent geändert: {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agent geändert zu: {name}",
|
|
140
|
+
"agent.change_error_callback": "Agent konnte nicht geändert werden",
|
|
141
|
+
"agent.menu.current": "Aktueller Agent: {name}\n\nAgent auswählen:",
|
|
142
|
+
"agent.menu.select": "Agent auswählen:",
|
|
135
143
|
"agent.menu.empty": "⚠️ Keine verfügbaren Agenten",
|
|
136
144
|
"agent.menu.error": "🔴 Agentenliste konnte nicht geladen werden",
|
|
137
145
|
"model.changed_callback": "Modell geändert: {name}",
|
|
@@ -205,7 +213,7 @@ export const de = {
|
|
|
205
213
|
"question.summary.title": "✅ Umfrage abgeschlossen!\n\n",
|
|
206
214
|
"question.summary.question": "Frage {index}:\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Antwort:\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji} {name}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
package/dist/i18n/en.js
CHANGED
|
@@ -3,6 +3,7 @@ export const en = {
|
|
|
3
3
|
"cmd.description.new": "Create a new session",
|
|
4
4
|
"cmd.description.stop": "Stop current action",
|
|
5
5
|
"cmd.description.sessions": "List sessions",
|
|
6
|
+
"cmd.description.tts": "Toggle audio replies",
|
|
6
7
|
"cmd.description.projects": "List projects",
|
|
7
8
|
"cmd.description.task": "Create a scheduled task",
|
|
8
9
|
"cmd.description.tasklist": "List scheduled tasks",
|
|
@@ -32,8 +33,8 @@ export const en = {
|
|
|
32
33
|
"inline.cancelled_callback": "Cancelled",
|
|
33
34
|
"common.unknown": "unknown",
|
|
34
35
|
"common.unknown_error": "unknown error",
|
|
35
|
-
"start.welcome": "👋 Welcome to OpenCode Telegram Bot!\n\nUse commands:\n/projects — select project\n/sessions — session list\n/new — new session\n/task — scheduled task\n/tasklist — scheduled tasks\n/status — status\n/help — help\n\nUse the bottom buttons to select agent
|
|
36
|
-
"help.keyboard_hint": "💡 Use the bottom keyboard buttons for agent
|
|
36
|
+
"start.welcome": "👋 Welcome to OpenCode Telegram Bot!\n\nUse commands:\n/projects — select project\n/sessions — session list\n/new — new session\n/task — scheduled task\n/tasklist — scheduled tasks\n/status — status\n/help — help\n\nUse the bottom buttons to select the agent, model, and variant.",
|
|
37
|
+
"help.keyboard_hint": "💡 Use the bottom keyboard buttons for the agent, model, variant, and context actions.",
|
|
37
38
|
"help.text": "📖 **Help**\n\n/status - Check server status\n/sessions - Session list\n/new - Create new session\n/help - Help",
|
|
38
39
|
"bot.thinking": "💭 Thinking...",
|
|
39
40
|
"bot.project_not_selected": "🏗 Project is not selected.\n\nFirst select a project with /projects.",
|
|
@@ -65,8 +66,11 @@ export const en = {
|
|
|
65
66
|
"status.line.managed_no": "Started by bot: No",
|
|
66
67
|
"status.line.pid": "PID: {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Uptime: {seconds} sec",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agent: {mode}",
|
|
69
70
|
"status.line.model": "Model: {model}",
|
|
71
|
+
"status.line.tts": "TTS replies: {tts}",
|
|
72
|
+
"status.tts.on": "On",
|
|
73
|
+
"status.tts.off": "Off",
|
|
70
74
|
"status.agent_not_set": "not set",
|
|
71
75
|
"status.project_selected": "Project: {project}",
|
|
72
76
|
"status.project_not_selected": "Project: not selected",
|
|
@@ -75,6 +79,10 @@ export const en = {
|
|
|
75
79
|
"status.session_not_selected": "Current session: not selected",
|
|
76
80
|
"status.session_hint": "Use /sessions to select one or /new to create one",
|
|
77
81
|
"status.server_unavailable": "🔴 OpenCode Server is unavailable\n\nUse /opencode_start to start the server.",
|
|
82
|
+
"tts.enabled": "🔊 Audio replies enabled globally.",
|
|
83
|
+
"tts.not_configured": "⚠️ Audio replies are unavailable. Set `TTS_API_URL` and `TTS_API_KEY` first.",
|
|
84
|
+
"tts.disabled": "🔇 Audio replies disabled globally.",
|
|
85
|
+
"tts.failed": "⚠️ Failed to generate audio reply.",
|
|
78
86
|
"projects.empty": "📭 No projects found.\n\nOpen a directory in OpenCode and create at least one session, then it will appear here.",
|
|
79
87
|
"projects.select": "Select a project:",
|
|
80
88
|
"projects.select_with_current": "Select a project:\n\nCurrent: 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const en = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 Failed to stop OpenCode Server\n\nError: {error}",
|
|
128
136
|
"opencode_stop.success": "✅ OpenCode Server stopped successfully",
|
|
129
137
|
"opencode_stop.error": "🔴 An error occurred while stopping server.\n\nCheck application logs for details.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "Failed to change
|
|
133
|
-
"agent.menu.current": "Current
|
|
134
|
-
"agent.menu.select": "Select
|
|
138
|
+
"agent.changed_callback": "Agent changed: {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agent changed to: {name}",
|
|
140
|
+
"agent.change_error_callback": "Failed to change agent",
|
|
141
|
+
"agent.menu.current": "Current agent: {name}\n\nSelect agent:",
|
|
142
|
+
"agent.menu.select": "Select agent:",
|
|
135
143
|
"agent.menu.empty": "⚠️ No available agents",
|
|
136
144
|
"agent.menu.error": "🔴 Failed to get agents list",
|
|
137
145
|
"model.changed_callback": "Model changed: {name}",
|
|
@@ -205,7 +213,7 @@ export const en = {
|
|
|
205
213
|
"question.summary.title": "✅ Poll completed!\n\n",
|
|
206
214
|
"question.summary.question": "Question {index}:\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Answer:\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji} {name}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
package/dist/i18n/es.js
CHANGED
|
@@ -3,6 +3,7 @@ export const es = {
|
|
|
3
3
|
"cmd.description.new": "Crear una sesión nueva",
|
|
4
4
|
"cmd.description.stop": "Detener la acción actual",
|
|
5
5
|
"cmd.description.sessions": "Listar sesiones",
|
|
6
|
+
"cmd.description.tts": "Alternar respuestas de audio",
|
|
6
7
|
"cmd.description.projects": "Listar proyectos",
|
|
7
8
|
"cmd.description.task": "Crear tarea programada",
|
|
8
9
|
"cmd.description.tasklist": "Ver tareas programadas",
|
|
@@ -32,8 +33,8 @@ export const es = {
|
|
|
32
33
|
"inline.cancelled_callback": "Cancelado",
|
|
33
34
|
"common.unknown": "desconocido",
|
|
34
35
|
"common.unknown_error": "error desconocido",
|
|
35
|
-
"start.welcome": "👋 ¡Bienvenido a OpenCode Telegram Bot!\n\nUsa los comandos:\n/projects — seleccionar proyecto\n/sessions — lista de sesiones\n/new — sesión nueva\n/task — tarea programada\n/tasklist — tareas programadas\n/status — estado\n/help — ayuda\n\nUsa los botones inferiores para elegir
|
|
36
|
-
"help.keyboard_hint": "💡 Usa los botones inferiores para
|
|
36
|
+
"start.welcome": "👋 ¡Bienvenido a OpenCode Telegram Bot!\n\nUsa los comandos:\n/projects — seleccionar proyecto\n/sessions — lista de sesiones\n/new — sesión nueva\n/task — tarea programada\n/tasklist — tareas programadas\n/status — estado\n/help — ayuda\n\nUsa los botones inferiores para elegir agente, modelo y variante.",
|
|
37
|
+
"help.keyboard_hint": "💡 Usa los botones inferiores para agente, modelo, variante y acciones de contexto.",
|
|
37
38
|
"help.text": "📖 **Ayuda**\n\n/status - Ver estado del servidor\n/sessions - Lista de sesiones\n/new - Crear una sesión nueva\n/help - Ayuda",
|
|
38
39
|
"bot.thinking": "💭 Pensando...",
|
|
39
40
|
"bot.project_not_selected": "🏗 No hay un proyecto seleccionado.\n\nPrimero selecciona un proyecto con /projects.",
|
|
@@ -65,8 +66,11 @@ export const es = {
|
|
|
65
66
|
"status.line.managed_no": "Iniciado por el bot: No",
|
|
66
67
|
"status.line.pid": "PID: {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Tiempo activo: {seconds} s",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agente: {mode}",
|
|
69
70
|
"status.line.model": "Modelo: {model}",
|
|
71
|
+
"status.line.tts": "Respuestas TTS: {tts}",
|
|
72
|
+
"status.tts.on": "Activadas",
|
|
73
|
+
"status.tts.off": "Desactivadas",
|
|
70
74
|
"status.agent_not_set": "no configurado",
|
|
71
75
|
"status.project_selected": "Proyecto: {project}",
|
|
72
76
|
"status.project_not_selected": "Proyecto: no seleccionado",
|
|
@@ -75,6 +79,10 @@ export const es = {
|
|
|
75
79
|
"status.session_not_selected": "Sesión actual: no seleccionada",
|
|
76
80
|
"status.session_hint": "Usa /sessions para elegir una o /new para crear una",
|
|
77
81
|
"status.server_unavailable": "🔴 OpenCode Server no está disponible\n\nUsa /opencode_start para iniciar el servidor.",
|
|
82
|
+
"tts.enabled": "🔊 Respuestas de audio activadas globalmente.",
|
|
83
|
+
"tts.not_configured": "⚠️ Las respuestas de audio no estan disponibles. Configura primero `TTS_API_URL` y `TTS_API_KEY`.",
|
|
84
|
+
"tts.disabled": "🔇 Respuestas de audio desactivadas globalmente.",
|
|
85
|
+
"tts.failed": "⚠️ No se pudo generar la respuesta de audio.",
|
|
78
86
|
"projects.empty": "📭 No se encontraron proyectos.\n\nAbre un directorio en OpenCode y crea al menos una sesión; entonces aparecerá aquí.",
|
|
79
87
|
"projects.select": "Selecciona un proyecto:",
|
|
80
88
|
"projects.select_with_current": "Selecciona un proyecto:\n\nActual: 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const es = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 No se pudo detener OpenCode Server\n\nError: {error}",
|
|
128
136
|
"opencode_stop.success": "✅ OpenCode Server detenido correctamente",
|
|
129
137
|
"opencode_stop.error": "🔴 Ocurrió un error al detener el servidor.\n\nRevisa los logs de la aplicación para más detalles.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "No se pudo cambiar el
|
|
133
|
-
"agent.menu.current": "
|
|
134
|
-
"agent.menu.select": "Selecciona el
|
|
138
|
+
"agent.changed_callback": "Agente cambiado: {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agente cambiado a: {name}",
|
|
140
|
+
"agent.change_error_callback": "No se pudo cambiar el agente",
|
|
141
|
+
"agent.menu.current": "Agente actual: {name}\n\nSelecciona el agente:",
|
|
142
|
+
"agent.menu.select": "Selecciona el agente:",
|
|
135
143
|
"agent.menu.empty": "⚠️ No hay agentes disponibles",
|
|
136
144
|
"agent.menu.error": "🔴 No se pudo obtener la lista de agentes",
|
|
137
145
|
"model.changed_callback": "Modelo cambiado: {name}",
|
|
@@ -205,7 +213,7 @@ export const es = {
|
|
|
205
213
|
"question.summary.title": "✅ ¡Encuesta completada!\n\n",
|
|
206
214
|
"question.summary.question": "Pregunta {index}:\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Respuesta:\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|
package/dist/i18n/fr.js
CHANGED
|
@@ -3,6 +3,7 @@ export const fr = {
|
|
|
3
3
|
"cmd.description.new": "Créer une nouvelle session",
|
|
4
4
|
"cmd.description.stop": "Arrêter l'action en cours",
|
|
5
5
|
"cmd.description.sessions": "Lister les sessions",
|
|
6
|
+
"cmd.description.tts": "Basculer les réponses audio",
|
|
6
7
|
"cmd.description.projects": "Lister les projets",
|
|
7
8
|
"cmd.description.task": "Créer une tâche planifiée",
|
|
8
9
|
"cmd.description.tasklist": "Afficher les tâches planifiées",
|
|
@@ -32,8 +33,8 @@ export const fr = {
|
|
|
32
33
|
"inline.cancelled_callback": "Annulé",
|
|
33
34
|
"common.unknown": "inconnu",
|
|
34
35
|
"common.unknown_error": "erreur inconnue",
|
|
35
|
-
"start.welcome": "👋 Bienvenue dans OpenCode Telegram Bot !\n\nUtilisez les commandes :\n/projects — sélectionner un projet\n/sessions — liste des sessions\n/new — nouvelle session\n/task — tâche planifiée\n/tasklist — tâches planifiées\n/status — statut\n/help — aide\n\nUtilisez les boutons du bas pour choisir
|
|
36
|
-
"help.keyboard_hint": "💡 Utilisez les boutons du bas pour
|
|
36
|
+
"start.welcome": "👋 Bienvenue dans OpenCode Telegram Bot !\n\nUtilisez les commandes :\n/projects — sélectionner un projet\n/sessions — liste des sessions\n/new — nouvelle session\n/task — tâche planifiée\n/tasklist — tâches planifiées\n/status — statut\n/help — aide\n\nUtilisez les boutons du bas pour choisir l'agent, le modèle et la variante.",
|
|
37
|
+
"help.keyboard_hint": "💡 Utilisez les boutons du bas pour l'agent, le modèle, la variante et les actions de contexte.",
|
|
37
38
|
"help.text": "📖 **Aide**\n\n/status - Vérifier l'état du serveur\n/sessions - Liste des sessions\n/new - Créer une nouvelle session\n/help - Aide",
|
|
38
39
|
"bot.thinking": "💭 Réflexion en cours...",
|
|
39
40
|
"bot.project_not_selected": "🏗 Aucun projet n'est sélectionné.\n\nSélectionnez d'abord un projet avec /projects.",
|
|
@@ -65,8 +66,11 @@ export const fr = {
|
|
|
65
66
|
"status.line.managed_no": "Démarré par le bot : Non",
|
|
66
67
|
"status.line.pid": "PID : {pid}",
|
|
67
68
|
"status.line.uptime_sec": "Temps de fonctionnement : {seconds} sec",
|
|
68
|
-
"status.line.mode": "
|
|
69
|
+
"status.line.mode": "Agent : {mode}",
|
|
69
70
|
"status.line.model": "Modèle : {model}",
|
|
71
|
+
"status.line.tts": "Réponses TTS : {tts}",
|
|
72
|
+
"status.tts.on": "Activées",
|
|
73
|
+
"status.tts.off": "Désactivées",
|
|
70
74
|
"status.agent_not_set": "non défini",
|
|
71
75
|
"status.project_selected": "Projet : {project}",
|
|
72
76
|
"status.project_not_selected": "Projet : non sélectionné",
|
|
@@ -75,6 +79,10 @@ export const fr = {
|
|
|
75
79
|
"status.session_not_selected": "Session actuelle : non sélectionnée",
|
|
76
80
|
"status.session_hint": "Utilisez /sessions pour en sélectionner une ou /new pour en créer une",
|
|
77
81
|
"status.server_unavailable": "🔴 Le serveur OpenCode est indisponible\n\nUtilisez /opencode_start pour démarrer le serveur.",
|
|
82
|
+
"tts.enabled": "🔊 Réponses audio activées globalement.",
|
|
83
|
+
"tts.not_configured": "⚠️ Les réponses audio ne sont pas disponibles. Définissez d'abord `TTS_API_URL` et `TTS_API_KEY`.",
|
|
84
|
+
"tts.disabled": "🔇 Réponses audio désactivées globalement.",
|
|
85
|
+
"tts.failed": "⚠️ Impossible de générer la réponse audio.",
|
|
78
86
|
"projects.empty": "📭 Aucun projet trouvé.\n\nOuvrez un répertoire dans OpenCode et créez au moins une session, il apparaîtra ensuite ici.",
|
|
79
87
|
"projects.select": "Sélectionnez un projet :",
|
|
80
88
|
"projects.select_with_current": "Sélectionnez un projet :\n\nActuel : 🏗 {project}",
|
|
@@ -127,11 +135,11 @@ export const fr = {
|
|
|
127
135
|
"opencode_stop.stop_error": "🔴 Impossible d'arrêter le serveur OpenCode\n\nErreur : {error}",
|
|
128
136
|
"opencode_stop.success": "✅ Serveur OpenCode arrêté avec succès",
|
|
129
137
|
"opencode_stop.error": "🔴 Une erreur s'est produite lors de l'arrêt du serveur.\n\nConsultez les logs de l'application pour plus de détails.",
|
|
130
|
-
"agent.changed_callback": "
|
|
131
|
-
"agent.changed_message": "✅
|
|
132
|
-
"agent.change_error_callback": "Impossible de modifier
|
|
133
|
-
"agent.menu.current": "
|
|
134
|
-
"agent.menu.select": "Sélectionnez un
|
|
138
|
+
"agent.changed_callback": "Agent modifié : {name}",
|
|
139
|
+
"agent.changed_message": "✅ Agent défini sur : {name}",
|
|
140
|
+
"agent.change_error_callback": "Impossible de modifier l'agent",
|
|
141
|
+
"agent.menu.current": "Agent actuel : {name}\n\nSélectionnez un agent :",
|
|
142
|
+
"agent.menu.select": "Sélectionnez un agent :",
|
|
135
143
|
"agent.menu.empty": "⚠️ Aucun mode disponible",
|
|
136
144
|
"agent.menu.error": "🔴 Impossible de récupérer la liste des modes",
|
|
137
145
|
"model.changed_callback": "Modèle modifié : {name}",
|
|
@@ -205,7 +213,7 @@ export const fr = {
|
|
|
205
213
|
"question.summary.title": "✅ Sondage terminé !\n\n",
|
|
206
214
|
"question.summary.question": "Question {index} :\n{question}\n\n",
|
|
207
215
|
"question.summary.answer": "Réponse :\n{answer}\n\n",
|
|
208
|
-
"keyboard.agent_mode": "{emoji}
|
|
216
|
+
"keyboard.agent_mode": "{emoji} {name} Agent",
|
|
209
217
|
"keyboard.context": "📊 {used} / {limit} ({percent}%)",
|
|
210
218
|
"keyboard.context_empty": "📊 0",
|
|
211
219
|
"keyboard.variant": "💭 {name}",
|