appback-remoteagent 0.23.3 → 0.23.4
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/README.md
CHANGED
|
@@ -106,6 +106,7 @@ Current command surface implemented in `src/bot.ts`:
|
|
|
106
106
|
| `/switch <session>` | Rebinds this chat to an existing RemoteAgent session |
|
|
107
107
|
| `/status` | Shows current session, workspace, provider, and sandbox state |
|
|
108
108
|
| `/model [name]` | Lists selectable provider models or changes the current session model. New Codex sessions default to `gpt-6-astra`. Use `/model gpt-6-astra` for an existing session. |
|
|
109
|
+
| `/model restore` | Clears temporary Codex fallback after a usage reset or credit purchase. Server-wide; next execution uses each session's configured model. Running work is preserved. Also available through the model menu's restore button. |
|
|
109
110
|
| `/option reasoning [low\|medium\|high\|xhigh\|max]` | Shows or changes Astra reasoning for all bots on this server. Defaults to `medium`; persisted as `CODEX_REASONING_EFFORT`. Applies on the next execution without restarting. Running replies retain their actual execution effort in the header. |
|
|
110
111
|
| `/sandbox [codex <mode>]` | Lists Codex sandbox choices or changes the current session sandbox |
|
|
111
112
|
| `/option retry <count>` | Sets the automatic continuation turn limit and persists it to `~/.remoteagent/.env` |
|
package/dist/bot.js
CHANGED
|
@@ -27,7 +27,7 @@ const HELP_TEXT = [
|
|
|
27
27
|
"/batch start|send|cancel|status",
|
|
28
28
|
"/attach codex <thread_id>",
|
|
29
29
|
"/attach claude <session_id>",
|
|
30
|
-
"/model [name]",
|
|
30
|
+
"/model [name|restore]",
|
|
31
31
|
"/queue [remove <id>|del]",
|
|
32
32
|
"/stop",
|
|
33
33
|
"/sandbox codex <read-only|workspace-write|danger-full-access>",
|
|
@@ -547,16 +547,22 @@ ${bridge.formatStatus(mapping)}`);
|
|
|
547
547
|
const { args, rest } = parseCommand(ctx.message?.text, 1);
|
|
548
548
|
const model = args[0]?.trim();
|
|
549
549
|
if (rest?.trim()) {
|
|
550
|
-
await reply(ctx, "Usage: `/model
|
|
550
|
+
await reply(ctx, "Usage: `/model`, `/model <name|number>`, or `/model restore`", {
|
|
551
551
|
parse_mode: "Markdown",
|
|
552
552
|
});
|
|
553
553
|
return;
|
|
554
554
|
}
|
|
555
|
+
if (model?.toLowerCase() === "restore") {
|
|
556
|
+
await ensureOwnerControlAccess(ctx);
|
|
557
|
+
await reply(ctx, await bridge.restoreCodexModel());
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
555
560
|
if (!model) {
|
|
556
561
|
const selection = await bridge.getModelSelection(botId, chatId);
|
|
557
562
|
const rows = selection.presets.map((preset) => [
|
|
558
563
|
actionButton(ctx, `${preset === selection.currentModel ? "✓ " : ""}${preset}`, { kind: "model.set", model: preset }),
|
|
559
564
|
]);
|
|
565
|
+
rows.push([actionButton(ctx, "원래 모델 복귀", { kind: "model.restore" })]);
|
|
560
566
|
await reply(ctx, await bridge.formatModelSelection(botId, chatId), {
|
|
561
567
|
parse_mode: "Markdown",
|
|
562
568
|
...(keyboardOptions(rows) ?? {}),
|
|
@@ -1151,6 +1157,11 @@ ${bridge.formatStatus(mapping)}`);
|
|
|
1151
1157
|
await reply(ctx, await setChatModel(ctx, action.model));
|
|
1152
1158
|
return;
|
|
1153
1159
|
}
|
|
1160
|
+
if (action.kind === "model.restore") {
|
|
1161
|
+
await ensureOwnerControlAccess(ctx);
|
|
1162
|
+
await reply(ctx, await bridge.restoreCodexModel());
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1154
1165
|
if (action.kind === "macro.run") {
|
|
1155
1166
|
const result = await runMacro(ctx, action.alias);
|
|
1156
1167
|
if (result) {
|
|
@@ -195,12 +195,17 @@ export class BridgeService {
|
|
|
195
195
|
...presets.map((item, index) => ` ${index + 1}. ${item}`),
|
|
196
196
|
"",
|
|
197
197
|
"Use `/model <name>` or `/model <number>` to change it.",
|
|
198
|
+
"Use `/model restore` to clear temporary Codex fallback for all bots on this server. The next execution uses each session's configured model.",
|
|
198
199
|
];
|
|
199
200
|
if (presets.length === 0) {
|
|
200
201
|
lines.splice(3, 1, "availablePresets: none");
|
|
201
202
|
}
|
|
202
203
|
return lines.join("\n");
|
|
203
204
|
}
|
|
205
|
+
async restoreCodexModel() {
|
|
206
|
+
await this.codexUsageFallback.clear();
|
|
207
|
+
return "이 서버의 Codex 임시 전환 상태를 해제했습니다. 다음 실행부터 각 세션에 설정된 원래 모델을 사용합니다.\n진행 중인 작업과 세션의 모델 설정은 유지됩니다. 실제 사용 한도가 남아 있으면 다시 임시 전환될 수 있습니다.";
|
|
208
|
+
}
|
|
204
209
|
async getModelSelection(botId, chatId) {
|
|
205
210
|
const chatSession = await this.requireChat(botId, chatId);
|
|
206
211
|
const provider = chatSession.session.mode;
|
package/package.json
CHANGED
|
@@ -121,6 +121,14 @@ try {
|
|
|
121
121
|
);
|
|
122
122
|
assert.deepEqual(calls.map((call) => call.model), [primaryModel, CODEX_USAGE_FALLBACK_MODEL]);
|
|
123
123
|
|
|
124
|
+
await bridge.restoreCodexModel();
|
|
125
|
+
await assert.rejects(fs.stat(fallbackStatePath), { code: "ENOENT" });
|
|
126
|
+
failPrimaryWithUsageLimit = false;
|
|
127
|
+
calls.length = 0;
|
|
128
|
+
await bridge.routeMessage("test-bot", "test-chat", "after coupon reset");
|
|
129
|
+
assert.deepEqual(calls.map(call => call.model), [primaryModel]);
|
|
130
|
+
assert.equal((await store.getChatSession("test-bot", "test-chat"))?.session.sessionId, originalSessionId);
|
|
131
|
+
|
|
124
132
|
console.log(JSON.stringify({
|
|
125
133
|
ok: true,
|
|
126
134
|
detectedExactUsageError: true,
|
|
@@ -130,6 +138,7 @@ try {
|
|
|
130
138
|
fallbackSharedAcrossSessions: true,
|
|
131
139
|
primaryRestoredAfterSuccessfulProbe: true,
|
|
132
140
|
fallbackAttemptLimit: 1,
|
|
141
|
+
manualRestoreUsesPrimary: true,
|
|
133
142
|
}, null, 2));
|
|
134
143
|
} finally {
|
|
135
144
|
await fs.rm(root, { recursive: true, force: true });
|
|
@@ -531,6 +531,20 @@ await waitForTelegramCall((call) => call.text.includes("Switched this chat to se
|
|
|
531
531
|
|
|
532
532
|
await send("/model");
|
|
533
533
|
const modelListCall = await waitForTelegramCall((call) => call.text.includes("availablePresets:"));
|
|
534
|
+
const restoreButton = findInlineButton(modelListCall, "원래 모델 복귀");
|
|
535
|
+
if (!restoreButton?.callback_data) throw new Error("Model restore button missing");
|
|
536
|
+
const fallbackPath = path.join(dataDir, "codex-usage-fallback.json");
|
|
537
|
+
const fallbackFixture = JSON.stringify({fallbackModel: "gpt-5.3-codex-spark", activatedAt: new Date().toISOString(), resetAt: "2099-01-01T00:00:00Z"});
|
|
538
|
+
const beforeRestore = await fs.readFile(path.join(dataDir, "state.json"), "utf8");
|
|
539
|
+
await fs.writeFile(fallbackPath, fallbackFixture);
|
|
540
|
+
await click(restoreButton.callback_data);
|
|
541
|
+
if (await pathExists(fallbackPath)) throw new Error("Restore button did not clear fallback");
|
|
542
|
+
await fs.writeFile(fallbackPath, fallbackFixture);
|
|
543
|
+
await send("/model restore");
|
|
544
|
+
await send("/model restore");
|
|
545
|
+
if (await pathExists(fallbackPath)) throw new Error("Restore command did not clear fallback");
|
|
546
|
+
const afterRestore = await fs.readFile(path.join(dataDir, "state.json"), "utf8");
|
|
547
|
+
if (JSON.stringify(JSON.parse(beforeRestore).sessions) !== JSON.stringify(JSON.parse(afterRestore).sessions)) throw new Error("Restore changed sessions");
|
|
534
548
|
const modelButton = findInlineButton(modelListCall, "gpt-5.6-terra");
|
|
535
549
|
if (!modelButton?.callback_data) {
|
|
536
550
|
throw new Error(`Model selection button is missing: ${modelListCall.reply_markup}`);
|