appback-remoteagent 0.13.7 → 0.13.11
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/bot.js +61 -18
- package/dist/services/agent-memory-service.js +3 -1
- package/docs/ARCHITECTURE.md +11 -1
- package/docs/OPERATIONS.md +5 -4
- package/package.json +1 -1
package/dist/bot.js
CHANGED
|
@@ -58,13 +58,11 @@ const REPORT_PROTOCOL_PROMPT = [
|
|
|
58
58
|
"Do not say 'I will continue' or 'I can continue after you do X' unless the first line is REPORT:blocked.",
|
|
59
59
|
"After the first line, write only the user-facing report.",
|
|
60
60
|
"Do not stop at intent like 'I will' or 'I am going to'. Do the work first, then report progress/result, or report blocked.",
|
|
61
|
-
"Do not claim that a Telegram message or file was sent unless RemoteAgent explicitly confirmed that delivery step.",
|
|
62
61
|
"If REPORT:result claims code, DB, deploy, commit, push, file delivery, or verification work is complete, include concrete evidence such as file paths, commands, logs, commit IDs, digests, or line references.",
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"Do not claim Telegram message delivery unless RemoteAgent handled `TELEGRAM_FILE` delivery or you include concrete API response evidence from an explicit secret-managed Telegram send.",
|
|
62
|
+
"RemoteAgent owns conversational delivery: return text normally and RemoteAgent sends it to the current incoming chat.",
|
|
63
|
+
"RemoteAgent owns attachment delivery: include a separate line exactly like `TELEGRAM_FILE: /absolute/path/to/file` and RemoteAgent sends that file to the current incoming chat.",
|
|
64
|
+
"Product/service Telegram notifications are product code behavior; use the project's secret/config path and keep tokens out of output.",
|
|
65
|
+
"Use project secrets or `node \"$REMOTEAGENT_SECRET_BIN\" get <KEY>` for sensitive runtime values, and never print secret values.",
|
|
68
66
|
"REMOTEAGENT_SESSION_ID and REMOTEAGENT_PUBLIC_SESSION_ID are available during provider execution. For cron, persist the literal public session id in the cron command instead of assuming the env will still exist later.",
|
|
69
67
|
].join("\n");
|
|
70
68
|
const RECOGNIZED_COMMANDS = new Set([
|
|
@@ -1092,8 +1090,9 @@ async function runWithPendingAnimation(botToken, chatId, task) {
|
|
|
1092
1090
|
if (progressChunks.length === 0 && normalized.documents.length === 0) {
|
|
1093
1091
|
return;
|
|
1094
1092
|
}
|
|
1095
|
-
const
|
|
1096
|
-
|
|
1093
|
+
const rendered = formatProviderTelegramChunks(progressChunks, parseMode);
|
|
1094
|
+
const extra = rendered.parseMode ? { parse_mode: rendered.parseMode } : undefined;
|
|
1095
|
+
for (const chunk of rendered.chunks) {
|
|
1097
1096
|
await sendTelegramMessage(botToken, chatId, chunk, extra);
|
|
1098
1097
|
}
|
|
1099
1098
|
if (normalized.documents.length > 0) {
|
|
@@ -1104,12 +1103,13 @@ async function runWithPendingAnimation(botToken, chatId, task) {
|
|
|
1104
1103
|
const result = await task(helpers);
|
|
1105
1104
|
const normalized = await normalizeTelegramDelivery(result.chunks);
|
|
1106
1105
|
const chunks = flattenChunks(normalized.chunks, 3900);
|
|
1107
|
-
const extra = result.parseMode ? { parse_mode: result.parseMode } : undefined;
|
|
1108
1106
|
if (chunks.length === 0 && normalized.documents.length === 0) {
|
|
1109
1107
|
await sendTelegramMessage(botToken, chatId, "Response was empty.");
|
|
1110
1108
|
return;
|
|
1111
1109
|
}
|
|
1112
|
-
|
|
1110
|
+
const rendered = formatProviderTelegramChunks(chunks, result.parseMode);
|
|
1111
|
+
const extra = rendered.parseMode ? { parse_mode: rendered.parseMode } : undefined;
|
|
1112
|
+
for (const chunk of rendered.chunks) {
|
|
1113
1113
|
await sendTelegramMessage(botToken, chatId, chunk, extra);
|
|
1114
1114
|
}
|
|
1115
1115
|
if (normalized.documents.length > 0) {
|
|
@@ -1359,6 +1359,56 @@ function parseReportResponses(formattedBlocks, transform) {
|
|
|
1359
1359
|
const chunks = transform(parsedBlocks.map((item) => item.text));
|
|
1360
1360
|
return { kind, chunks };
|
|
1361
1361
|
}
|
|
1362
|
+
function formatProviderTelegramChunks(chunks, explicitParseMode) {
|
|
1363
|
+
if (explicitParseMode) {
|
|
1364
|
+
return { chunks, parseMode: explicitParseMode };
|
|
1365
|
+
}
|
|
1366
|
+
return {
|
|
1367
|
+
chunks: chunks.map((chunk) => renderTelegramHtml(chunk)),
|
|
1368
|
+
parseMode: "HTML",
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
function renderTelegramHtml(text) {
|
|
1372
|
+
const lines = text.split(/\r?\n/);
|
|
1373
|
+
const rendered = [];
|
|
1374
|
+
let codeFence;
|
|
1375
|
+
for (const line of lines) {
|
|
1376
|
+
if (/^```\w*\s*$/.test(line.trim())) {
|
|
1377
|
+
if (codeFence) {
|
|
1378
|
+
rendered.push(`<pre>${escapeTelegramHtml(codeFence.join("\n"))}</pre>`);
|
|
1379
|
+
codeFence = undefined;
|
|
1380
|
+
}
|
|
1381
|
+
else {
|
|
1382
|
+
codeFence = [];
|
|
1383
|
+
}
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
if (codeFence) {
|
|
1387
|
+
codeFence.push(line);
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
rendered.push(renderTelegramInlineHtml(line));
|
|
1391
|
+
}
|
|
1392
|
+
if (codeFence) {
|
|
1393
|
+
rendered.push(`<pre>${escapeTelegramHtml(codeFence.join("\n"))}</pre>`);
|
|
1394
|
+
}
|
|
1395
|
+
return rendered.join("\n");
|
|
1396
|
+
}
|
|
1397
|
+
function renderTelegramInlineHtml(line) {
|
|
1398
|
+
const parts = line.split(/(`[^`\n]+`)/g);
|
|
1399
|
+
return parts.map((part) => {
|
|
1400
|
+
if (part.startsWith("`") && part.endsWith("`") && part.length >= 2) {
|
|
1401
|
+
return `<code>${escapeTelegramHtml(part.slice(1, -1))}</code>`;
|
|
1402
|
+
}
|
|
1403
|
+
return escapeTelegramHtml(part);
|
|
1404
|
+
}).join("");
|
|
1405
|
+
}
|
|
1406
|
+
function escapeTelegramHtml(value) {
|
|
1407
|
+
return value
|
|
1408
|
+
.replace(/&/g, "&")
|
|
1409
|
+
.replace(/</g, "<")
|
|
1410
|
+
.replace(/>/g, ">");
|
|
1411
|
+
}
|
|
1362
1412
|
function looksLikeUntaggedIntentOnlyResponse(text) {
|
|
1363
1413
|
const normalized = text.trim();
|
|
1364
1414
|
if (!normalized) {
|
|
@@ -2083,12 +2133,8 @@ async function normalizeTelegramDelivery(chunks) {
|
|
|
2083
2133
|
}
|
|
2084
2134
|
return kept.join("\n").trim();
|
|
2085
2135
|
}));
|
|
2086
|
-
const nonEmptyChunks = normalizedChunks.filter(Boolean);
|
|
2087
|
-
if (documents.size === 0 && nonEmptyChunks.some((chunk) => mentionsTelegramDeliveryClaim(chunk))) {
|
|
2088
|
-
throw new Error("\ubaa8\ub378\uc774 \ud154\ub808\uadf8\ub7a8 \uc804\uc1a1 \uc644\ub8cc\ub97c \uc8fc\uc7a5\ud588\uc9c0\ub9cc, RemoteAgent\uac00 \ud655\uc778\ud55c \ud30c\uc77c \uc804\uc1a1 \uc9c0\uc2dc(`TELEGRAM_FILE: /absolute/path/to/file`)\ub294 \ud3ec\ud568\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \ud30c\uc77c\uc744 \ubcf4\ub0b4\ub824\uba74 \ud574\ub2f9 \ud615\uc2dd\uc73c\ub85c \uc808\ub300 \uacbd\ub85c\ub97c \uba85\uc2dc\ud574\uc57c \ud569\ub2c8\ub2e4.");
|
|
2089
|
-
}
|
|
2090
2136
|
return {
|
|
2091
|
-
chunks:
|
|
2137
|
+
chunks: normalizedChunks.filter(Boolean),
|
|
2092
2138
|
documents: [...documents.values()],
|
|
2093
2139
|
};
|
|
2094
2140
|
}
|
|
@@ -2104,9 +2150,6 @@ async function isReadableTelegramDocument(filePath) {
|
|
|
2104
2150
|
return false;
|
|
2105
2151
|
}
|
|
2106
2152
|
}
|
|
2107
|
-
function mentionsTelegramDeliveryClaim(text) {
|
|
2108
|
-
return /(telegram).*(sent|delivered|delivery)|((sent|delivered|delivery).*(telegram))/i.test(text);
|
|
2109
|
-
}
|
|
2110
2153
|
async function sendTelegramDocuments(botToken, chatId, documents) {
|
|
2111
2154
|
for (const document of documents) {
|
|
2112
2155
|
await sendTelegramDocument(botToken, chatId, document);
|
|
@@ -325,7 +325,9 @@ export class AgentMemoryService {
|
|
|
325
325
|
"- Treat the user message as the active instruction unless the user explicitly says otherwise.",
|
|
326
326
|
"- RemoteAgent state is guidance only; never refuse work because a TODO is missing.",
|
|
327
327
|
"- Use the workspace/memory/docs pointers before searching broadly.",
|
|
328
|
-
"- Do not claim external delivery, dashboard access, deployment, or file transfer without
|
|
328
|
+
"- Do not claim external delivery, dashboard access, deployment, or file transfer without concrete evidence.",
|
|
329
|
+
"- RemoteAgent sends normal provider text and TELEGRAM_FILE attachments to the current incoming chat.",
|
|
330
|
+
"- Product/service Telegram notifications belong to product code and should use the project's secret/config path. Never print tokens.",
|
|
329
331
|
"- If the same action or progress repeats 3 times, stop, mark the blocker, and report the exact blocker.",
|
|
330
332
|
"- A final report must include concrete evidence: changed files, relevant line references, git diff/status, command output, or log path.",
|
|
331
333
|
].join("\n"),
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -56,6 +56,16 @@ Responsibilities:
|
|
|
56
56
|
- accept attachments and route them to the active session
|
|
57
57
|
- gate privileged commands such as remote shell
|
|
58
58
|
|
|
59
|
+
### Telegram delivery ownership
|
|
60
|
+
|
|
61
|
+
RemoteAgent owns delivery for the conversation it is handling.
|
|
62
|
+
|
|
63
|
+
- normal provider text is sent by RemoteAgent to the current incoming bot and chat
|
|
64
|
+
- provider attachments are sent by RemoteAgent when the provider includes `TELEGRAM_FILE: /absolute/path/to/file`
|
|
65
|
+
- the provider does not choose a bot token or chat id for RemoteAgent replies or files
|
|
66
|
+
- product or service code Telegram notifications are separate application behavior and should use that project's own secret/config path
|
|
67
|
+
- Telegram tokens and other credentials must stay in secrets/config and must not be printed in provider output
|
|
68
|
+
|
|
59
69
|
### Telegram Mini App layer
|
|
60
70
|
|
|
61
71
|
Responsibilities:
|
|
@@ -167,4 +177,4 @@ Still improving:
|
|
|
167
177
|
- hosted multi-tenant control plane
|
|
168
178
|
- account pooling or resale
|
|
169
179
|
- pretending RemoteAgent is the official Codex or Claude desktop product
|
|
170
|
-
- treating Telegram itself as the execution backend
|
|
180
|
+
- treating Telegram itself as the execution backend
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -161,8 +161,9 @@ As of the latest stabilization work:
|
|
|
161
161
|
- Telegram image download works
|
|
162
162
|
- files are saved under `/home/au2223/.remoteagent/uploads/telegram/...`
|
|
163
163
|
- duplicate runtime startup has been blocked
|
|
164
|
-
-
|
|
165
|
-
-
|
|
164
|
+
- RemoteAgent-mediated file sending uses `TELEGRAM_FILE: /absolute/path/to/file`
|
|
165
|
+
- RemoteAgent sends conversation replies and `TELEGRAM_FILE` attachments only to the current incoming bot and chat
|
|
166
|
+
- product/service Telegram notifications are not RemoteAgent conversation delivery; they belong in that project's code and should use that project's secret/config path
|
|
166
167
|
|
|
167
168
|
Remaining work is still needed on attachment response policy and richer file UX.
|
|
168
169
|
The transport/runtime stability issue and the user-facing attachment response quality issue are separate concerns.
|
|
@@ -176,6 +177,6 @@ The deeper issues were runtime ownership and transport discipline:
|
|
|
176
177
|
- service-managed and manually-started processes overlapped
|
|
177
178
|
- PID state and actual live processes diverged
|
|
178
179
|
- Telegram responses could come from an unexpected process generation
|
|
179
|
-
-
|
|
180
|
+
- RemoteAgent conversation delivery needed a single current incoming bot/chat owner
|
|
180
181
|
|
|
181
|
-
The single-instance lock, `systemd`-first lifecycle, and runtime-
|
|
182
|
+
The single-instance lock, `systemd`-first lifecycle, and runtime-owned conversation delivery rules were added specifically to stop that class of bug from recurring.
|