appback-remoteagent 0.15.0 → 0.15.2
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 +73 -14
- package/package.json +1 -1
package/dist/bot.js
CHANGED
|
@@ -267,10 +267,30 @@ export function createBot(token, bridge, botManagement, botInfo) {
|
|
|
267
267
|
}
|
|
268
268
|
const botId = getBotId();
|
|
269
269
|
const chatId = String(ctx.chat.id);
|
|
270
|
-
await bridge.logSystem(botId, chatId, `Plan document reinforcement requested (${count}
|
|
270
|
+
await bridge.logSystem(botId, chatId, `Plan document reinforcement requested (${count} check/apply cycle max).`);
|
|
271
271
|
await runWithPendingAnimation(token, ctx.chat.id, async (helpers) => {
|
|
272
|
+
for (let cycle = 1; cycle <= count; cycle += 1) {
|
|
273
|
+
const checkChunks = await routeTelegramWorkLoop(bridge, botId, chatId, formatPlanDocumentCheckPrompt(cycle, count), `Plan document check ${cycle}`, botManagement, helpers, autoContinue, memoryService, (blocks) => blocks, { maxTurns: 1 });
|
|
274
|
+
const decision = classifyPlanReinforcementDecision(checkChunks.join("\n"));
|
|
275
|
+
await helpers.reportProgress(formatPlanCycleProgress("확인 결과", cycle, count, stripPlanReinforcementMarkers(checkChunks)));
|
|
276
|
+
if (decision === "none") {
|
|
277
|
+
return {
|
|
278
|
+
chunks: [`보강할 내용이 없다고 판단되어 ${cycle}/${count}회차에서 종료했습니다.`],
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (decision === "unknown") {
|
|
282
|
+
return {
|
|
283
|
+
chunks: [
|
|
284
|
+
"보강 필요 여부를 명확히 판정할 수 없어 중단했습니다.",
|
|
285
|
+
"계획문서 확인 응답에는 `PLAN_REINFORCE: needed` 또는 `PLAN_REINFORCE: none`이 포함되어야 합니다.",
|
|
286
|
+
],
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const applyChunks = await routeTelegramWorkLoop(bridge, botId, chatId, formatPlanDocumentApplyPrompt(cycle, count), `Plan document apply ${cycle}`, botManagement, helpers, autoContinue, memoryService, stripPlanReinforcementMarkers, { maxTurns: 1 });
|
|
290
|
+
await helpers.reportProgress(formatPlanCycleProgress("보강 결과", cycle, count, applyChunks));
|
|
291
|
+
}
|
|
272
292
|
return {
|
|
273
|
-
chunks:
|
|
293
|
+
chunks: [`최대 ${count}회 확인/보강 반복을 완료했습니다.`],
|
|
274
294
|
};
|
|
275
295
|
});
|
|
276
296
|
};
|
|
@@ -1631,6 +1651,9 @@ function classifyRetryableProviderIssue(message, retryAfterMs) {
|
|
|
1631
1651
|
if (isEmptyResponseError(message)) {
|
|
1632
1652
|
return { kind: "empty-response", retryAfterMs };
|
|
1633
1653
|
}
|
|
1654
|
+
if (/remote compact task|stream disconnected|websocket protocol error|connection reset without closing handshake/i.test(message)) {
|
|
1655
|
+
return { kind: "transport", retryAfterMs };
|
|
1656
|
+
}
|
|
1634
1657
|
return undefined;
|
|
1635
1658
|
}
|
|
1636
1659
|
function formatRetryableProviderRetryMessage(issue, attempt, maxAttempts) {
|
|
@@ -1640,6 +1663,8 @@ function formatRetryableProviderRetryMessage(issue, attempt, maxAttempts) {
|
|
|
1640
1663
|
return `선택한 모델이 capacity 상태라 ${waitSeconds}초 후 다시 시도합니다. (${attempt}/${maxAttempts})`;
|
|
1641
1664
|
case "empty-response":
|
|
1642
1665
|
return `후속 응답이 비어 있어 ${waitSeconds}초 후 다시 시도합니다. (${attempt}/${maxAttempts})`;
|
|
1666
|
+
case "transport":
|
|
1667
|
+
return `Codex 연결이 일시적으로 끊겨 ${waitSeconds}초 후 다시 시도합니다. (${attempt}/${maxAttempts})`;
|
|
1643
1668
|
}
|
|
1644
1669
|
}
|
|
1645
1670
|
function formatRetryableProviderFinalMessage(issue) {
|
|
@@ -1648,6 +1673,8 @@ function formatRetryableProviderFinalMessage(issue) {
|
|
|
1648
1673
|
return "선택한 모델이 capacity 상태라 자동 재시도를 모두 사용했습니다. 잠시 후 다시 시도하거나 `/model`로 다른 모델을 선택해 주세요.";
|
|
1649
1674
|
case "empty-response":
|
|
1650
1675
|
return "후속 응답이 반복해서 비어 자동 재시도를 중단했습니다. 같은 세션에서 다시 시도해 주세요.";
|
|
1676
|
+
case "transport":
|
|
1677
|
+
return "Codex 연결이 반복해서 끊겨 자동 재시도를 중단했습니다. 잠시 후 같은 세션에서 다시 시도해 주세요.";
|
|
1651
1678
|
}
|
|
1652
1679
|
}
|
|
1653
1680
|
function isProviderTimeoutError(message) {
|
|
@@ -1767,24 +1794,56 @@ function parseKoreanPlanReinforcementCommand(text, botId) {
|
|
|
1767
1794
|
const parsed = parsePlanReinforcementCount(maybeCount);
|
|
1768
1795
|
return parsed.kind === "valid" ? { kind: "matched", count: parsed.count } : { kind: "invalid" };
|
|
1769
1796
|
}
|
|
1770
|
-
function
|
|
1797
|
+
function formatPlanDocumentCheckPrompt(cycle, count) {
|
|
1798
|
+
return [
|
|
1799
|
+
"계획문서 처음부터 확인해서 보강해야할 내용 확인해",
|
|
1800
|
+
"",
|
|
1801
|
+
`현재 반복: ${cycle}/${count}`,
|
|
1802
|
+
"",
|
|
1803
|
+
"응답 규칙:",
|
|
1804
|
+
"- 첫 줄은 REPORT:result 또는 REPORT:blocked.",
|
|
1805
|
+
"- REPORT:result 본문 첫 줄은 반드시 `PLAN_REINFORCE: needed` 또는 `PLAN_REINFORCE: none`.",
|
|
1806
|
+
"- 보강할 내용이 있으면 `PLAN_REINFORCE: needed` 후 항목과 근거 파일을 답하세요.",
|
|
1807
|
+
"- 보강할 내용이 없으면 `PLAN_REINFORCE: none` 후 확인 근거 파일을 답하세요.",
|
|
1808
|
+
"- 이 단계에서는 문서를 수정하지 마세요. 확인과 답변만 하세요.",
|
|
1809
|
+
"- 권한, 정보, 파일 위치가 부족하면 REPORT:blocked로 정확한 blocker를 말하세요.",
|
|
1810
|
+
].join("\n");
|
|
1811
|
+
}
|
|
1812
|
+
function formatPlanDocumentApplyPrompt(cycle, count) {
|
|
1771
1813
|
return [
|
|
1772
|
-
|
|
1814
|
+
"보강해",
|
|
1773
1815
|
"",
|
|
1774
|
-
|
|
1775
|
-
"1. 계획문서와 관련 문서를 실제로 읽고 보강할 내용이 있는지 판단하세요.",
|
|
1776
|
-
"2. 보강할 내용이 있으면 직접 문서를 수정하세요.",
|
|
1777
|
-
"3. 수정 후 같은 기준으로 다시 점검하세요.",
|
|
1778
|
-
`4. 더 이상 보강할 내용이 없거나 ${count}회에 도달하면 종료하세요.`,
|
|
1816
|
+
`현재 반복: ${cycle}/${count}`,
|
|
1779
1817
|
"",
|
|
1780
|
-
"
|
|
1781
|
-
"
|
|
1782
|
-
"
|
|
1783
|
-
"-
|
|
1818
|
+
"방금 확인 응답에서 보강 필요하다고 답한 항목만 실제 문서에 반영하세요.",
|
|
1819
|
+
"",
|
|
1820
|
+
"응답 규칙:",
|
|
1821
|
+
"- 첫 줄은 REPORT:result 또는 REPORT:blocked.",
|
|
1822
|
+
"- REPORT:result 본문에는 변경한 파일 경로와 검증/확인 근거를 포함하세요.",
|
|
1823
|
+
"- 새 범위를 만들지 말고 방금 확인한 보강 항목만 처리하세요.",
|
|
1784
1824
|
"- 권한, 정보, 파일 위치가 부족하면 REPORT:blocked로 정확한 blocker를 말하세요.",
|
|
1785
|
-
"- 완료 시 확인한 문서, 변경한 문서, 남은 위험, 검증 결과를 짧게 보고하세요.",
|
|
1786
1825
|
].join("\n");
|
|
1787
1826
|
}
|
|
1827
|
+
function classifyPlanReinforcementDecision(text) {
|
|
1828
|
+
if (/PLAN_REINFORCE:\s*none/i.test(text)) {
|
|
1829
|
+
return "none";
|
|
1830
|
+
}
|
|
1831
|
+
if (/PLAN_REINFORCE:\s*needed/i.test(text)) {
|
|
1832
|
+
return "needed";
|
|
1833
|
+
}
|
|
1834
|
+
return "unknown";
|
|
1835
|
+
}
|
|
1836
|
+
function stripPlanReinforcementMarkers(blocks) {
|
|
1837
|
+
return blocks.map((block) => block
|
|
1838
|
+
.replace(/^PLAN_REINFORCE:\s*(needed|none)\s*\r?\n?/gim, "")
|
|
1839
|
+
.trim());
|
|
1840
|
+
}
|
|
1841
|
+
function formatPlanCycleProgress(label, cycle, count, chunks) {
|
|
1842
|
+
const prefix = `[보강 ${cycle}/${count}] ${label}`;
|
|
1843
|
+
return chunks.length > 0
|
|
1844
|
+
? chunks.map((chunk, index) => index === 0 ? `${prefix}\n${chunk}` : chunk)
|
|
1845
|
+
: [prefix];
|
|
1846
|
+
}
|
|
1788
1847
|
function commandTarget(args, rest) {
|
|
1789
1848
|
return (rest?.trim() || args.slice(1).join(" ").trim() || args[0]?.trim() || "");
|
|
1790
1849
|
}
|