@pixelbyte-software/pixcode 1.53.7 → 1.53.9
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/assets/{index-DM-KfWAm.js → index-nl5YZ8Wr.js} +142 -142
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +128 -21
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/services/telegram/control-center.js +126 -17
- package/dist-server/server/services/telegram/control-center.js.map +1 -1
- package/dist-server/server/services/telegram/translations.js +6 -0
- package/dist-server/server/services/telegram/translations.js.map +1 -1
- package/package.json +1 -1
- package/server/index.js +132 -17
- package/server/services/telegram/control-center.js +129 -17
- package/server/services/telegram/translations.js +6 -0
package/server/index.js
CHANGED
|
@@ -43,13 +43,19 @@ const DAEMON_COMMAND_CONTEXT = {
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
function resolveMonacoAssetsPath() {
|
|
46
|
+
const appParent = path.dirname(APP_ROOT);
|
|
47
|
+
const appGrandparent = path.dirname(appParent);
|
|
46
48
|
const candidates = [
|
|
47
49
|
path.join(APP_ROOT, 'node_modules', 'monaco-editor', 'min', 'vs'),
|
|
50
|
+
path.join(appParent, 'node_modules', 'monaco-editor', 'min', 'vs'),
|
|
51
|
+
path.join(appParent, 'monaco-editor', 'min', 'vs'),
|
|
52
|
+
path.join(appGrandparent, 'node_modules', 'monaco-editor', 'min', 'vs'),
|
|
53
|
+
path.join(appGrandparent, 'monaco-editor', 'min', 'vs'),
|
|
48
54
|
];
|
|
49
55
|
|
|
50
56
|
try {
|
|
51
57
|
const monacoPackagePath = require.resolve('monaco-editor/package.json', {
|
|
52
|
-
paths: [APP_ROOT, __dirname],
|
|
58
|
+
paths: [APP_ROOT, appParent, appGrandparent, __dirname, process.cwd()],
|
|
53
59
|
});
|
|
54
60
|
candidates.push(path.join(path.dirname(monacoPackagePath), 'min', 'vs'));
|
|
55
61
|
} catch {
|
|
@@ -1012,6 +1018,11 @@ const ptySessionsMap = new Map();
|
|
|
1012
1018
|
const PTY_SESSION_TIMEOUT = 30 * 60 * 1000;
|
|
1013
1019
|
const COMPLETED_PTY_SESSION_TTL = 5 * 60 * 1000;
|
|
1014
1020
|
const SHELL_URL_PARSE_BUFFER_LIMIT = 32768;
|
|
1021
|
+
const SHELL_OUTPUT_FLUSH_MAX_CHARS = 128 * 1024;
|
|
1022
|
+
const SHELL_WS_BACKPRESSURE_LIMIT = 8 * 1024 * 1024;
|
|
1023
|
+
const PTY_SESSION_BUFFER_MAX_BYTES = Number.parseInt(process.env.PIXCODE_PTY_BUFFER_MAX_BYTES || '', 10) || (2 * 1024 * 1024);
|
|
1024
|
+
const SHELL_INPUT_CHUNK_CHARS = 4096;
|
|
1025
|
+
const SHELL_PENDING_INPUT_MAX_BYTES = 2 * 1024 * 1024;
|
|
1015
1026
|
const SHELL_CLI_PROVIDERS = new Set(['claude', 'codex', 'cursor', 'gemini', 'qwen', 'opencode']);
|
|
1016
1027
|
import { stripAnsiSequences, normalizeDetectedUrl, extractUrlsFromText, shouldAutoOpenUrlFromOutput } from './utils/url-detection.js';
|
|
1017
1028
|
|
|
@@ -1156,12 +1167,23 @@ function resolveProviderTerminalState(session, provider, output) {
|
|
|
1156
1167
|
|
|
1157
1168
|
function appendPtySessionBuffer(session, data) {
|
|
1158
1169
|
if (!session) return;
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1170
|
+
let value = String(data || '');
|
|
1171
|
+
if (!value) return;
|
|
1172
|
+
|
|
1173
|
+
let valueBytes = Buffer.byteLength(value, 'utf8');
|
|
1174
|
+
if (valueBytes > PTY_SESSION_BUFFER_MAX_BYTES) {
|
|
1175
|
+
value = value.slice(-PTY_SESSION_BUFFER_MAX_BYTES);
|
|
1176
|
+
valueBytes = Buffer.byteLength(value, 'utf8');
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
session.buffer.push(value);
|
|
1180
|
+
session.bufferBytes = (session.bufferBytes || 0) + valueBytes;
|
|
1181
|
+
|
|
1182
|
+
while (session.buffer.length > 0 && session.bufferBytes > PTY_SESSION_BUFFER_MAX_BYTES) {
|
|
1183
|
+
const removed = session.buffer.shift();
|
|
1184
|
+
session.bufferBytes -= Buffer.byteLength(String(removed || ''), 'utf8');
|
|
1164
1185
|
}
|
|
1186
|
+
if (session.bufferBytes < 0) session.bufferBytes = 0;
|
|
1165
1187
|
}
|
|
1166
1188
|
|
|
1167
1189
|
function normalizeTerminalStartupInput(input) {
|
|
@@ -1258,6 +1280,26 @@ function writeTerminalStartupInput(session, startupInput, reason, delayMs = 500)
|
|
|
1258
1280
|
queueTerminalStartupInput(session, startupInput, reason, delayMs);
|
|
1259
1281
|
}
|
|
1260
1282
|
|
|
1283
|
+
function splitTerminalInput(data) {
|
|
1284
|
+
const value = String(data || '');
|
|
1285
|
+
if (!value) return [];
|
|
1286
|
+
const chunks = [];
|
|
1287
|
+
for (let index = 0; index < value.length; index += SHELL_INPUT_CHUNK_CHARS) {
|
|
1288
|
+
chunks.push(value.slice(index, index + SHELL_INPUT_CHUNK_CHARS));
|
|
1289
|
+
}
|
|
1290
|
+
return chunks;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
function writeTerminalInputChunks(ptyProcess, data) {
|
|
1294
|
+
if (!ptyProcess?.write) return false;
|
|
1295
|
+
const chunks = splitTerminalInput(data);
|
|
1296
|
+
if (chunks.length === 0) return false;
|
|
1297
|
+
for (const chunk of chunks) {
|
|
1298
|
+
ptyProcess.write(chunk);
|
|
1299
|
+
}
|
|
1300
|
+
return true;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1261
1303
|
function normalizeShellPermissionMode(value) {
|
|
1262
1304
|
return typeof value === 'string' ? value.trim() : '';
|
|
1263
1305
|
}
|
|
@@ -1541,7 +1583,7 @@ app.post('/api/shell/sessions/provider-input', authenticateToken, requireProject
|
|
|
1541
1583
|
|
|
1542
1584
|
const data = submit ? normalizeTerminalStartupInput(input) : input;
|
|
1543
1585
|
try {
|
|
1544
|
-
matchedSession.pty
|
|
1586
|
+
writeTerminalInputChunks(matchedSession.pty, data);
|
|
1545
1587
|
matchedSession.updatedAt = Date.now();
|
|
1546
1588
|
res.json({
|
|
1547
1589
|
ok: true,
|
|
@@ -3406,8 +3448,63 @@ function handleShellConnection(ws, request) {
|
|
|
3406
3448
|
let urlDetectionBuffer = '';
|
|
3407
3449
|
let outputBuffer = '';
|
|
3408
3450
|
let outputFlushTimer = null;
|
|
3451
|
+
let inputFlushTimer = null;
|
|
3452
|
+
let pendingInputBytes = 0;
|
|
3453
|
+
const pendingInputQueue = [];
|
|
3409
3454
|
const announcedAuthUrls = new Set();
|
|
3410
3455
|
|
|
3456
|
+
function getActiveShellPty() {
|
|
3457
|
+
const session = ptySessionKey ? ptySessionsMap.get(ptySessionKey) : null;
|
|
3458
|
+
return session?.pty || shellProcess;
|
|
3459
|
+
}
|
|
3460
|
+
|
|
3461
|
+
function scheduleInputFlush(delayMs = 0) {
|
|
3462
|
+
if (inputFlushTimer) return;
|
|
3463
|
+
inputFlushTimer = setTimeout(flushPendingInput, delayMs);
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
function flushPendingInput() {
|
|
3467
|
+
inputFlushTimer = null;
|
|
3468
|
+
if (pendingInputQueue.length === 0) return;
|
|
3469
|
+
|
|
3470
|
+
const activePty = getActiveShellPty();
|
|
3471
|
+
if (!activePty?.write) {
|
|
3472
|
+
scheduleInputFlush(100);
|
|
3473
|
+
return;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
const chunk = pendingInputQueue.shift();
|
|
3477
|
+
pendingInputBytes = Math.max(0, pendingInputBytes - Buffer.byteLength(chunk, 'utf8'));
|
|
3478
|
+
try {
|
|
3479
|
+
activePty.write(chunk);
|
|
3480
|
+
} catch (error) {
|
|
3481
|
+
console.error('Error writing to shell:', error);
|
|
3482
|
+
pendingInputQueue.length = 0;
|
|
3483
|
+
pendingInputBytes = 0;
|
|
3484
|
+
return;
|
|
3485
|
+
}
|
|
3486
|
+
|
|
3487
|
+
if (pendingInputQueue.length > 0) scheduleInputFlush(1);
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
function enqueueShellInput(data) {
|
|
3491
|
+
const chunks = splitTerminalInput(data);
|
|
3492
|
+
if (chunks.length === 0) return;
|
|
3493
|
+
|
|
3494
|
+
for (const chunk of chunks) {
|
|
3495
|
+
pendingInputQueue.push(chunk);
|
|
3496
|
+
pendingInputBytes += Buffer.byteLength(chunk, 'utf8');
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
while (pendingInputQueue.length > 0 && pendingInputBytes > SHELL_PENDING_INPUT_MAX_BYTES) {
|
|
3500
|
+
const dropped = pendingInputQueue.shift();
|
|
3501
|
+
pendingInputBytes -= Buffer.byteLength(String(dropped || ''), 'utf8');
|
|
3502
|
+
}
|
|
3503
|
+
if (pendingInputBytes < 0) pendingInputBytes = 0;
|
|
3504
|
+
|
|
3505
|
+
scheduleInputFlush();
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3411
3508
|
function flushOutputBuffer() {
|
|
3412
3509
|
if (!outputBuffer || !ptySessionKey) {
|
|
3413
3510
|
outputFlushTimer = null;
|
|
@@ -3424,7 +3521,17 @@ function handleShellConnection(ws, request) {
|
|
|
3424
3521
|
appendPtySessionBuffer(session, rawData);
|
|
3425
3522
|
|
|
3426
3523
|
if (session.ws && session.ws.readyState === WebSocket.OPEN) {
|
|
3524
|
+
if (session.ws.bufferedAmount > SHELL_WS_BACKPRESSURE_LIMIT) {
|
|
3525
|
+
session.droppedOutputBytes = (session.droppedOutputBytes || 0) + Buffer.byteLength(rawData, 'utf8');
|
|
3526
|
+
return;
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
const droppedOutputBytes = session.droppedOutputBytes || 0;
|
|
3530
|
+
session.droppedOutputBytes = 0;
|
|
3427
3531
|
let outputData = rawData;
|
|
3532
|
+
if (droppedOutputBytes > 0) {
|
|
3533
|
+
outputData = `\r\n\x1b[33m[Pixcode] ${droppedOutputBytes} bytes of terminal output were skipped because the browser connection was backpressured.\x1b[0m\r\n${outputData}`;
|
|
3534
|
+
}
|
|
3428
3535
|
|
|
3429
3536
|
const cleanChunk = stripAnsiSequences(rawData);
|
|
3430
3537
|
urlDetectionBuffer = `${urlDetectionBuffer}${cleanChunk}`.slice(-SHELL_URL_PARSE_BUFFER_LIMIT);
|
|
@@ -3786,6 +3893,8 @@ function handleShellConnection(ws, request) {
|
|
|
3786
3893
|
pty: shellProcess,
|
|
3787
3894
|
ws: ws,
|
|
3788
3895
|
buffer: [],
|
|
3896
|
+
bufferBytes: 0,
|
|
3897
|
+
droppedOutputBytes: 0,
|
|
3789
3898
|
timeoutId: null,
|
|
3790
3899
|
userId: ownerUserId,
|
|
3791
3900
|
projectPath,
|
|
@@ -3806,12 +3915,21 @@ function handleShellConnection(ws, request) {
|
|
|
3806
3915
|
if (terminalStartupInput && !isPlainShell) {
|
|
3807
3916
|
writeTerminalStartupInput(createdSession, terminalStartupInput, 'new provider session', 4500);
|
|
3808
3917
|
}
|
|
3918
|
+
scheduleInputFlush();
|
|
3809
3919
|
|
|
3810
3920
|
// Handle data output — batch rapid chunks so high-volume CLI
|
|
3811
3921
|
// output does not flood the WebSocket with one JSON frame per
|
|
3812
3922
|
// keystroke-sized chunk.
|
|
3813
3923
|
shellProcess.onData((data) => {
|
|
3814
3924
|
outputBuffer += data;
|
|
3925
|
+
if (outputBuffer.length >= SHELL_OUTPUT_FLUSH_MAX_CHARS) {
|
|
3926
|
+
if (outputFlushTimer) {
|
|
3927
|
+
clearTimeout(outputFlushTimer);
|
|
3928
|
+
outputFlushTimer = null;
|
|
3929
|
+
}
|
|
3930
|
+
flushOutputBuffer();
|
|
3931
|
+
return;
|
|
3932
|
+
}
|
|
3815
3933
|
if (!outputFlushTimer) {
|
|
3816
3934
|
outputFlushTimer = setTimeout(flushOutputBuffer, 8);
|
|
3817
3935
|
}
|
|
@@ -3878,16 +3996,7 @@ function handleShellConnection(ws, request) {
|
|
|
3878
3996
|
}
|
|
3879
3997
|
|
|
3880
3998
|
} else if (data.type === 'input') {
|
|
3881
|
-
|
|
3882
|
-
if (shellProcess && shellProcess.write) {
|
|
3883
|
-
try {
|
|
3884
|
-
shellProcess.write(data.data);
|
|
3885
|
-
} catch (error) {
|
|
3886
|
-
console.error('Error writing to shell:', error);
|
|
3887
|
-
}
|
|
3888
|
-
} else {
|
|
3889
|
-
console.warn('No active shell process to send input to');
|
|
3890
|
-
}
|
|
3999
|
+
enqueueShellInput(data.data);
|
|
3891
4000
|
} else if (data.type === 'resize') {
|
|
3892
4001
|
// Handle terminal resize
|
|
3893
4002
|
const session = ptySessionKey ? ptySessionsMap.get(ptySessionKey) : null;
|
|
@@ -3921,6 +4030,12 @@ function handleShellConnection(ws, request) {
|
|
|
3921
4030
|
clearTimeout(outputFlushTimer);
|
|
3922
4031
|
outputFlushTimer = null;
|
|
3923
4032
|
}
|
|
4033
|
+
if (inputFlushTimer) {
|
|
4034
|
+
clearTimeout(inputFlushTimer);
|
|
4035
|
+
inputFlushTimer = null;
|
|
4036
|
+
}
|
|
4037
|
+
pendingInputQueue.length = 0;
|
|
4038
|
+
pendingInputBytes = 0;
|
|
3924
4039
|
|
|
3925
4040
|
if (ptySessionKey) {
|
|
3926
4041
|
const session = ptySessionsMap.get(ptySessionKey);
|
|
@@ -27,11 +27,14 @@ const TERMINAL_RUN_STATES = new Set(['completed', 'failed', 'canceled']);
|
|
|
27
27
|
const CALLBACK_TTL_MS = 10 * 60 * 1000;
|
|
28
28
|
const MAX_CALLBACK_ACTIONS = 1000;
|
|
29
29
|
const MAX_TELEGRAM_TEXT = 3600;
|
|
30
|
+
const MAX_ACTIVITY_OUTPUT_CHARS = 48_000;
|
|
31
|
+
const MAX_SSE_BUFFER_CHARS = 256_000;
|
|
30
32
|
const ACTIVITY_EDIT_THROTTLE_MS = 1200;
|
|
31
33
|
const ACTIVITY_HEARTBEAT_MS = 8000;
|
|
32
34
|
const INTENT_ROUTER_TIMEOUT_MS = 45_000;
|
|
33
35
|
const callbackActions = new Map();
|
|
34
36
|
const runMonitors = new Map();
|
|
37
|
+
const activeLongTasks = new Map();
|
|
35
38
|
|
|
36
39
|
const MODEL_FALLBACKS = Object.fromEntries(
|
|
37
40
|
PROVIDERS.map((provider) => [provider, getStaticProviderModels(provider)]),
|
|
@@ -85,6 +88,14 @@ function truncate(text, max = MAX_TELEGRAM_TEXT) {
|
|
|
85
88
|
return value.length > max ? `${value.slice(0, max - 20)}\n\n…truncated…` : value;
|
|
86
89
|
}
|
|
87
90
|
|
|
91
|
+
function appendBoundedText(current, chunk, maxChars = MAX_ACTIVITY_OUTPUT_CHARS) {
|
|
92
|
+
const nextChunk = String(chunk || '');
|
|
93
|
+
if (!nextChunk) return { text: current || '', truncated: false };
|
|
94
|
+
const combined = `${current || ''}${nextChunk}`;
|
|
95
|
+
if (combined.length <= maxChars) return { text: combined, truncated: false };
|
|
96
|
+
return { text: combined.slice(-maxChars), truncated: true };
|
|
97
|
+
}
|
|
98
|
+
|
|
88
99
|
function languageFor(link) {
|
|
89
100
|
return SUPPORTED_LANGUAGES.includes(link?.language) ? link.language : 'en';
|
|
90
101
|
}
|
|
@@ -313,6 +324,9 @@ async function localAgentStream(userId, body, onEvent) {
|
|
|
313
324
|
const { done, value } = await reader.read();
|
|
314
325
|
if (done) break;
|
|
315
326
|
buffer += decoder.decode(value, { stream: true });
|
|
327
|
+
if (buffer.length > MAX_SSE_BUFFER_CHARS) {
|
|
328
|
+
buffer = buffer.slice(-MAX_SSE_BUFFER_CHARS);
|
|
329
|
+
}
|
|
316
330
|
let boundary = buffer.indexOf('\n\n');
|
|
317
331
|
while (boundary !== -1) {
|
|
318
332
|
const block = buffer.slice(0, boundary);
|
|
@@ -360,6 +374,7 @@ function createActivityState({ lang, type = 'agent', provider, project, prompt,
|
|
|
360
374
|
workflowId: null,
|
|
361
375
|
events: [],
|
|
362
376
|
output: '',
|
|
377
|
+
outputTruncated: false,
|
|
363
378
|
error: null,
|
|
364
379
|
};
|
|
365
380
|
}
|
|
@@ -386,6 +401,13 @@ function trimTelegramOutput(text, max, suffix = '') {
|
|
|
386
401
|
return `${value.slice(0, room).trim()}\n\n${ending}`;
|
|
387
402
|
}
|
|
388
403
|
|
|
404
|
+
function appendActivityOutput(activity, chunk) {
|
|
405
|
+
if (!activity) return;
|
|
406
|
+
const next = appendBoundedText(activity.output, chunk);
|
|
407
|
+
activity.output = next.text;
|
|
408
|
+
activity.outputTruncated = Boolean(activity.outputTruncated || next.truncated);
|
|
409
|
+
}
|
|
410
|
+
|
|
389
411
|
function renderActivity(activity, { finalText = null } = {}) {
|
|
390
412
|
const output = finalText || activity.output;
|
|
391
413
|
if (activity.type === 'agent' && output && !activity.error) {
|
|
@@ -393,7 +415,9 @@ function renderActivity(activity, { finalText = null } = {}) {
|
|
|
393
415
|
return trimTelegramOutput(
|
|
394
416
|
output,
|
|
395
417
|
3400,
|
|
396
|
-
|
|
418
|
+
activity.outputTruncated
|
|
419
|
+
? t(activity.lang, 'control.activity.outputHistoryTrimmed')
|
|
420
|
+
: t(activity.lang, 'control.activity.outputTooLong'),
|
|
397
421
|
);
|
|
398
422
|
}
|
|
399
423
|
|
|
@@ -839,13 +863,13 @@ function applyAgentStreamEvent(activity, event) {
|
|
|
839
863
|
if (event.kind === 'stream_delta' || event.kind === 'text') {
|
|
840
864
|
activity.status = 'running';
|
|
841
865
|
activity.phase = t(activity.lang, 'control.activity.responding');
|
|
842
|
-
activity
|
|
866
|
+
appendActivityOutput(activity, extractTextFromEvent(event));
|
|
843
867
|
return;
|
|
844
868
|
}
|
|
845
869
|
if (event.type === 'claude-response' && event.data?.type === 'assistant') {
|
|
846
870
|
activity.status = 'running';
|
|
847
871
|
activity.phase = t(activity.lang, 'control.activity.responding');
|
|
848
|
-
activity
|
|
872
|
+
appendActivityOutput(activity, extractTextFromEvent(event));
|
|
849
873
|
return;
|
|
850
874
|
}
|
|
851
875
|
if (event.kind === 'tool_use') {
|
|
@@ -975,6 +999,47 @@ async function runAgent({ bot, chatId, link, prompt, activity = null }) {
|
|
|
975
999
|
await editTelegramActivity({ bot, chatId, activity: active, force: true });
|
|
976
1000
|
}
|
|
977
1001
|
|
|
1002
|
+
function longTaskKey(chatId) {
|
|
1003
|
+
return String(chatId);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
async function launchLongTelegramTask({ bot, chatId, link, kind, activity = null, task }) {
|
|
1007
|
+
const key = longTaskKey(chatId);
|
|
1008
|
+
const existing = activeLongTasks.get(key);
|
|
1009
|
+
const lang = languageFor(link);
|
|
1010
|
+
if (existing) {
|
|
1011
|
+
await send(bot, chatId, t(lang, 'control.longTaskRunning', {
|
|
1012
|
+
kind: existing.kind,
|
|
1013
|
+
elapsed: formatElapsed(existing.startedAt),
|
|
1014
|
+
}), {
|
|
1015
|
+
editMessageId: activity?.messageId,
|
|
1016
|
+
parse_mode: undefined,
|
|
1017
|
+
});
|
|
1018
|
+
return true;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
const record = {
|
|
1022
|
+
kind,
|
|
1023
|
+
startedAt: Date.now(),
|
|
1024
|
+
};
|
|
1025
|
+
activeLongTasks.set(key, record);
|
|
1026
|
+
|
|
1027
|
+
Promise.resolve()
|
|
1028
|
+
.then(task)
|
|
1029
|
+
.catch(async (error) => {
|
|
1030
|
+
console.error('[telegram-control] long task failed:', error);
|
|
1031
|
+
await send(bot, chatId, t(lang, 'control.longTaskFailed'), {
|
|
1032
|
+
editMessageId: activity?.messageId,
|
|
1033
|
+
parse_mode: undefined,
|
|
1034
|
+
}).catch(() => {});
|
|
1035
|
+
})
|
|
1036
|
+
.finally(() => {
|
|
1037
|
+
if (activeLongTasks.get(key) === record) activeLongTasks.delete(key);
|
|
1038
|
+
});
|
|
1039
|
+
|
|
1040
|
+
return true;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
978
1043
|
export async function runWorkflow({ bot, chatId, link, input, activity = null }) {
|
|
979
1044
|
const lang = languageFor(link);
|
|
980
1045
|
const state = getState(link.user_id);
|
|
@@ -1188,8 +1253,14 @@ async function handleRoutedIntent({ bot, chatId, link, text, activity }) {
|
|
|
1188
1253
|
const editMessageId = activity?.messageId;
|
|
1189
1254
|
|
|
1190
1255
|
if (intent.action === 'agent_prompt') {
|
|
1191
|
-
|
|
1192
|
-
|
|
1256
|
+
return launchLongTelegramTask({
|
|
1257
|
+
bot,
|
|
1258
|
+
chatId,
|
|
1259
|
+
link,
|
|
1260
|
+
kind: 'agent',
|
|
1261
|
+
activity,
|
|
1262
|
+
task: () => runAgent({ bot, chatId, link, prompt: intent.prompt || text, activity }),
|
|
1263
|
+
});
|
|
1193
1264
|
}
|
|
1194
1265
|
if (intent.action === 'show_menu') {
|
|
1195
1266
|
await showMainMenu({ bot, chatId, link, editMessageId });
|
|
@@ -1266,8 +1337,14 @@ async function handleRoutedIntent({ bot, chatId, link, text, activity }) {
|
|
|
1266
1337
|
return true;
|
|
1267
1338
|
}
|
|
1268
1339
|
if (intent.action === 'run_workflow') {
|
|
1269
|
-
|
|
1270
|
-
|
|
1340
|
+
return launchLongTelegramTask({
|
|
1341
|
+
bot,
|
|
1342
|
+
chatId,
|
|
1343
|
+
link,
|
|
1344
|
+
kind: 'workflow',
|
|
1345
|
+
activity,
|
|
1346
|
+
task: () => runWorkflow({ bot, chatId, link, input: intent.workflowInput || text, activity }),
|
|
1347
|
+
});
|
|
1271
1348
|
}
|
|
1272
1349
|
if (intent.action === 'show_sessions') {
|
|
1273
1350
|
await showSessions({ bot, chatId, link, editMessageId });
|
|
@@ -1277,8 +1354,14 @@ async function handleRoutedIntent({ bot, chatId, link, text, activity }) {
|
|
|
1277
1354
|
await startNewChat({ bot, chatId, link, editMessageId });
|
|
1278
1355
|
return true;
|
|
1279
1356
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1357
|
+
return launchLongTelegramTask({
|
|
1358
|
+
bot,
|
|
1359
|
+
chatId,
|
|
1360
|
+
link,
|
|
1361
|
+
kind: 'agent',
|
|
1362
|
+
activity,
|
|
1363
|
+
task: () => runAgent({ bot, chatId, link, prompt: text, activity }),
|
|
1364
|
+
});
|
|
1282
1365
|
}
|
|
1283
1366
|
|
|
1284
1367
|
async function fetchRun(userId, runId) {
|
|
@@ -1493,12 +1576,22 @@ async function handleAwaitingInput({ bot, chatId, link, text }) {
|
|
|
1493
1576
|
updateTelegramControlState(link.user_id, { awaiting: null });
|
|
1494
1577
|
|
|
1495
1578
|
if (awaiting.type === 'agent_prompt') {
|
|
1496
|
-
|
|
1497
|
-
|
|
1579
|
+
return launchLongTelegramTask({
|
|
1580
|
+
bot,
|
|
1581
|
+
chatId,
|
|
1582
|
+
link,
|
|
1583
|
+
kind: 'agent',
|
|
1584
|
+
task: () => runAgent({ bot, chatId, link, prompt: text }),
|
|
1585
|
+
});
|
|
1498
1586
|
}
|
|
1499
1587
|
if (awaiting.type === 'workflow_prompt') {
|
|
1500
|
-
|
|
1501
|
-
|
|
1588
|
+
return launchLongTelegramTask({
|
|
1589
|
+
bot,
|
|
1590
|
+
chatId,
|
|
1591
|
+
link,
|
|
1592
|
+
kind: 'workflow',
|
|
1593
|
+
task: () => runWorkflow({ bot, chatId, link, input: text }),
|
|
1594
|
+
});
|
|
1502
1595
|
}
|
|
1503
1596
|
return false;
|
|
1504
1597
|
}
|
|
@@ -1592,8 +1685,13 @@ async function handleCommand({ bot, chatId, link, text }) {
|
|
|
1592
1685
|
await send(bot, chatId, t(lang, 'control.sendAgentPrompt'));
|
|
1593
1686
|
return true;
|
|
1594
1687
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1688
|
+
return launchLongTelegramTask({
|
|
1689
|
+
bot,
|
|
1690
|
+
chatId,
|
|
1691
|
+
link,
|
|
1692
|
+
kind: 'agent',
|
|
1693
|
+
task: () => runAgent({ bot, chatId, link, prompt: argText }),
|
|
1694
|
+
});
|
|
1597
1695
|
}
|
|
1598
1696
|
if (command === '/workflow' || command === '/orchestrate') {
|
|
1599
1697
|
if (!argText) {
|
|
@@ -1601,8 +1699,13 @@ async function handleCommand({ bot, chatId, link, text }) {
|
|
|
1601
1699
|
await send(bot, chatId, t(lang, 'control.sendWorkflowPrompt'));
|
|
1602
1700
|
return true;
|
|
1603
1701
|
}
|
|
1604
|
-
|
|
1605
|
-
|
|
1702
|
+
return launchLongTelegramTask({
|
|
1703
|
+
bot,
|
|
1704
|
+
chatId,
|
|
1705
|
+
link,
|
|
1706
|
+
kind: 'workflow',
|
|
1707
|
+
task: () => runWorkflow({ bot, chatId, link, input: argText }),
|
|
1708
|
+
});
|
|
1606
1709
|
}
|
|
1607
1710
|
if (command === '/cancel') {
|
|
1608
1711
|
if (!argText) {
|
|
@@ -1661,6 +1764,10 @@ export async function handleTelegramControlMessage(args) {
|
|
|
1661
1764
|
await send(args.bot, chatId, t(languageFor(args.link), 'error.generic')).catch(() => {});
|
|
1662
1765
|
return true;
|
|
1663
1766
|
}
|
|
1767
|
+
}).catch(async (error) => {
|
|
1768
|
+
console.error('[telegram-control] message job failed:', error);
|
|
1769
|
+
await send(args.bot, chatId, t(languageFor(args.link), 'error.generic')).catch(() => {});
|
|
1770
|
+
return true;
|
|
1664
1771
|
});
|
|
1665
1772
|
}
|
|
1666
1773
|
|
|
@@ -1849,5 +1956,10 @@ export async function handleTelegramControlCallback(args) {
|
|
|
1849
1956
|
await args.bot?.answerCallbackQuery(args.query?.id, { text: t(lang, 'error.generic') }).catch(() => {});
|
|
1850
1957
|
await send(args.bot, chatId, t(lang, 'error.generic')).catch(() => {});
|
|
1851
1958
|
}
|
|
1959
|
+
}).catch(async (error) => {
|
|
1960
|
+
console.error('[telegram-control] callback job failed:', error);
|
|
1961
|
+
const lang = languageFor(args.link);
|
|
1962
|
+
await args.bot?.answerCallbackQuery(args.query?.id, { text: t(lang, 'error.generic') }).catch(() => {});
|
|
1963
|
+
await send(args.bot, chatId, t(lang, 'error.generic')).catch(() => {});
|
|
1852
1964
|
});
|
|
1853
1965
|
}
|
|
@@ -140,7 +140,10 @@ const EN = {
|
|
|
140
140
|
'control.activity.tokens': 'Tokens',
|
|
141
141
|
'control.activity.liveFooter': 'Response is still streaming · {{elapsed}}',
|
|
142
142
|
'control.activity.outputShortened': 'Telegram output was shortened while the run continues.',
|
|
143
|
+
'control.activity.outputHistoryTrimmed': 'Earlier response output was trimmed to protect memory. Open the Pixcode session for the full output.',
|
|
143
144
|
'control.activity.outputTooLong': 'Long response shortened for Telegram. Open the session in Pixcode for the full output.',
|
|
145
|
+
'control.longTaskRunning': 'A {{kind}} task is already running in this chat · {{elapsed}}. You can still use /menu, /runs, or /settings.',
|
|
146
|
+
'control.longTaskFailed': 'The background Telegram task failed. Check Pixcode logs or try again.',
|
|
144
147
|
'notification.taskDone': '✅ {{title}} — task completed.',
|
|
145
148
|
'notification.taskFailed': '⚠️ {{title}} — task failed: {{error}}',
|
|
146
149
|
'notification.actionRequired': '❗ {{title}} — action required.',
|
|
@@ -281,7 +284,10 @@ const TR = {
|
|
|
281
284
|
'control.activity.tokens': 'Token',
|
|
282
285
|
'control.activity.liveFooter': 'Yanıt devam ediyor · {{elapsed}}',
|
|
283
286
|
'control.activity.outputShortened': 'Telegram çıktısı çalışma devam ederken kısaltıldı.',
|
|
287
|
+
'control.activity.outputHistoryTrimmed': 'Yanıtın önceki bölümü bellek koruması için kısaltıldı. Tam çıktı için Pixcode oturumunu aç.',
|
|
284
288
|
'control.activity.outputTooLong': 'Uzun yanıt Telegram için kısaltıldı. Tam çıktı için Pixcode oturumunu aç.',
|
|
289
|
+
'control.longTaskRunning': 'Bu sohbette zaten bir {{kind}} işi çalışıyor · {{elapsed}}. /menu, /runs veya /settings yine çalışır.',
|
|
290
|
+
'control.longTaskFailed': 'Arka plandaki Telegram işi hata verdi. Pixcode loglarını kontrol et veya tekrar dene.',
|
|
285
291
|
'notification.taskDone': '✅ {{title}} — görev tamamlandı.',
|
|
286
292
|
'notification.taskFailed': '⚠️ {{title}} — görev başarısız: {{error}}',
|
|
287
293
|
'notification.actionRequired': '❗ {{title}} — işlem gerekli.',
|