appback-remoteagent 0.23.1 → 0.23.3
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 +2 -1
- package/dist/adapters/codex-adapter.js +7 -0
- package/dist/bot.js +21 -2
- package/dist/services/bridge-service.js +9 -3
- package/dist/services/codex-reasoning.js +8 -0
- package/package.json +1 -1
- package/scripts/selftest-codex-stream.mjs +10 -0
- package/scripts/selftest-model-fallback.mjs +5 -1
- package/scripts/selftest-telegram-update.mjs +7 -0
package/README.md
CHANGED
|
@@ -105,7 +105,8 @@ Current command surface implemented in `src/bot.ts`:
|
|
|
105
105
|
| `/new` | Creates and binds a new session using the saved default mode in a new managed workspace |
|
|
106
106
|
| `/switch <session>` | Rebinds this chat to an existing RemoteAgent session |
|
|
107
107
|
| `/status` | Shows current session, workspace, provider, and sandbox state |
|
|
108
|
-
| `/model [name]` | Lists selectable provider models or changes the current session model |
|
|
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
|
+
| `/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. |
|
|
109
110
|
| `/sandbox [codex <mode>]` | Lists Codex sandbox choices or changes the current session sandbox |
|
|
110
111
|
| `/option retry <count>` | Sets the automatic continuation turn limit and persists it to `~/.remoteagent/.env` |
|
|
111
112
|
| `/option timeout <seconds>` | Sets the provider execution timeout and persists it to `~/.remoteagent/.env` |
|
|
@@ -3,6 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { spawnWithPlatformShell } from "./windows-shell.js";
|
|
6
|
+
import { getAstraReasoning } from "../services/codex-reasoning.js";
|
|
6
7
|
export class CodexAdapter {
|
|
7
8
|
codexBin;
|
|
8
9
|
timeoutMs;
|
|
@@ -67,6 +68,9 @@ export class CodexAdapter {
|
|
|
67
68
|
if (request.model) {
|
|
68
69
|
args.push("-m", request.model);
|
|
69
70
|
}
|
|
71
|
+
if (request.model === "gpt-6-astra") {
|
|
72
|
+
args.push("-c", `model_reasoning_effort=${JSON.stringify(request.reasoningEffort ?? getAstraReasoning())}`);
|
|
73
|
+
}
|
|
70
74
|
this.appendSandboxArgs(args, sandboxMode);
|
|
71
75
|
args.push("-o", outputPath, "-C", request.cwd);
|
|
72
76
|
this.appendPromptStdinArg(args);
|
|
@@ -82,6 +86,9 @@ export class CodexAdapter {
|
|
|
82
86
|
if (request.model) {
|
|
83
87
|
args.push("-m", request.model);
|
|
84
88
|
}
|
|
89
|
+
if (request.model === "gpt-6-astra") {
|
|
90
|
+
args.push("-c", `model_reasoning_effort=${JSON.stringify(request.reasoningEffort ?? getAstraReasoning())}`);
|
|
91
|
+
}
|
|
85
92
|
this.appendSandboxArgs(args, sandboxMode);
|
|
86
93
|
args.push("-o", outputPath, request.sessionId);
|
|
87
94
|
this.appendPromptStdinArg(args);
|
package/dist/bot.js
CHANGED
|
@@ -3,6 +3,7 @@ import fsSync from "node:fs";
|
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
6
7
|
import { randomUUID } from "node:crypto";
|
|
7
8
|
import { promisify } from "node:util";
|
|
8
9
|
import { Bot, GrammyError, HttpError } from "grammy";
|
|
@@ -13,6 +14,7 @@ import { AgentMemoryService } from "./services/agent-memory-service.js";
|
|
|
13
14
|
import { WorkspaceCleanupService } from "./services/workspace-cleanup-service.js";
|
|
14
15
|
import { exportSecrets } from "./services/secret-transfer-service.js";
|
|
15
16
|
import { deleteTelegramCommandMenu, setTelegramCommandMenu } from "./telegram-command-menu.js";
|
|
17
|
+
import { ASTRA_REASONING_LEVELS, getAstraReasoning, isAstraReasoning } from "./services/codex-reasoning.js";
|
|
16
18
|
const execFileAsync = promisify(execFile);
|
|
17
19
|
const HELP_TEXT = [
|
|
18
20
|
"Commands:",
|
|
@@ -30,7 +32,7 @@ const HELP_TEXT = [
|
|
|
30
32
|
"/stop",
|
|
31
33
|
"/sandbox codex <read-only|workspace-write|danger-full-access>",
|
|
32
34
|
"/status",
|
|
33
|
-
"/option [retry <count>|timeout <seconds>|intent <count>|command-menu <on|off|refresh>]",
|
|
35
|
+
"/option [retry <count>|timeout <seconds>|intent <count>|reasoning <low|medium|high|xhigh|max>|command-menu <on|off|refresh>]",
|
|
34
36
|
"/state [clear|note <text>]",
|
|
35
37
|
"/artifacts list|cleanup <days>",
|
|
36
38
|
"/cleanup",
|
|
@@ -642,12 +644,13 @@ ${bridge.formatStatus(mapping)}`);
|
|
|
642
644
|
],
|
|
643
645
|
[
|
|
644
646
|
actionButton(ctx, "Intent", { kind: "option.show", option: "intent" }),
|
|
647
|
+
actionButton(ctx, "Reasoning", { kind: "option.show", option: "reasoning" }),
|
|
645
648
|
actionButton(ctx, "Command menu", { kind: "option.show", option: "command-menu" }),
|
|
646
649
|
],
|
|
647
650
|
]));
|
|
648
651
|
return;
|
|
649
652
|
}
|
|
650
|
-
if (option !== "retry" && option !== "timeout" && option !== "intent" && option !== "command-menu") {
|
|
653
|
+
if (option !== "retry" && option !== "timeout" && option !== "intent" && option !== "reasoning" && option !== "command-menu") {
|
|
651
654
|
await reply(ctx, "Usage: `/option retry <count>`, `/option timeout <seconds>`, `/option intent <count>`, or `/option command-menu <on|off|refresh>`\n\n`retry` controls automatic continuation turns. `timeout` controls one provider execution limit. `intent` controls retries for untagged intent-only provider replies. `command-menu` controls Telegram slash-command autocomplete for all configured bots.", {
|
|
652
655
|
parse_mode: "Markdown",
|
|
653
656
|
});
|
|
@@ -659,6 +662,17 @@ ${bridge.formatStatus(mapping)}`);
|
|
|
659
662
|
});
|
|
660
663
|
return;
|
|
661
664
|
}
|
|
665
|
+
if (option === "reasoning") {
|
|
666
|
+
const effort = value.toLowerCase();
|
|
667
|
+
if (!isAstraReasoning(effort)) {
|
|
668
|
+
await reply(ctx, `Invalid reasoning effort. Use /option reasoning <${ASTRA_REASONING_LEVELS.join("|")}>.`);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
await upsertInstalledEnvValue("CODEX_REASONING_EFFORT", effort);
|
|
672
|
+
process.env.CODEX_REASONING_EFFORT = effort;
|
|
673
|
+
await reply(ctx, `Set Astra reasoning effort to ${effort}. Applies to the next Astra execution for all bots on this server; running executions keep their current effort.\n\nSaved: CODEX_REASONING_EFFORT=${effort}`);
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
662
676
|
if (option === "command-menu") {
|
|
663
677
|
const action = value.toLowerCase();
|
|
664
678
|
if (!["on", "off", "refresh"].includes(action)) {
|
|
@@ -2507,12 +2521,14 @@ function formatRuntimeOptions() {
|
|
|
2507
2521
|
`- retry: ${formatRetryLimit(config.telegramAutoProgressMaxTurns)} (TELEGRAM_AUTO_PROGRESS_MAX_TURNS)`,
|
|
2508
2522
|
`- timeout: ${formatTimeoutSeconds(config.commandTimeoutMs)} (COMMAND_TIMEOUT_MS)`,
|
|
2509
2523
|
`- intent: ${formatRetryLimit(config.telegramUntaggedIntentRetries)} (TELEGRAM_UNTAGGED_INTENT_RETRIES)`,
|
|
2524
|
+
`- reasoning: ${getAstraReasoning()} (Astra, server-wide, CODEX_REASONING_EFFORT)`,
|
|
2510
2525
|
`- command-menu: ${config.telegramCommandMenuEnabled ? "on" : "off"} (TELEGRAM_COMMAND_MENU_ENABLED)`,
|
|
2511
2526
|
"",
|
|
2512
2527
|
"Usage:",
|
|
2513
2528
|
"/option retry <count>",
|
|
2514
2529
|
"/option timeout <seconds>",
|
|
2515
2530
|
"/option intent <count>",
|
|
2531
|
+
"/option reasoning <low|medium|high|xhigh|max>",
|
|
2516
2532
|
"/option command-menu <on|off|refresh>",
|
|
2517
2533
|
"",
|
|
2518
2534
|
"`retry 0` disables the automatic continuation limit.",
|
|
@@ -2521,6 +2537,9 @@ function formatRuntimeOptions() {
|
|
|
2521
2537
|
].join("\n");
|
|
2522
2538
|
}
|
|
2523
2539
|
function formatRuntimeOptionDetail(option) {
|
|
2540
|
+
if (option === "reasoning") {
|
|
2541
|
+
return `Current Astra reasoning effort: ${getAstraReasoning()}\n\nUsage: /option reasoning <low|medium|high|xhigh|max>\nApplies to the next Astra execution for all bots on this server. No restart required.`;
|
|
2542
|
+
}
|
|
2524
2543
|
if (option === "retry") {
|
|
2525
2544
|
return `Current automatic continuation retry limit: ${formatRetryLimit(config.telegramAutoProgressMaxTurns)}\n\nUsage: \`/option retry <count>\``;
|
|
2526
2545
|
}
|
|
@@ -2,13 +2,14 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { getAstraReasoning } from "./codex-reasoning.js";
|
|
5
6
|
import { stopSpawnedExecution } from "../adapters/windows-shell.js";
|
|
6
7
|
import { CODEX_USAGE_FALLBACK_MODEL, CodexUsageFallbackService, parseCodexUsageLimit, } from "./codex-usage-fallback-service.js";
|
|
7
8
|
const MODEL_PRESETS = {
|
|
8
|
-
codex: ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.6", "gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark", "gpt-5.2", "gpt-5.1-codex-max"],
|
|
9
|
+
codex: ["gpt-6-astra", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.6", "gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark", "gpt-5.2", "gpt-5.1-codex-max"],
|
|
9
10
|
claude: ["sonnet", "opus", "haiku"],
|
|
10
11
|
};
|
|
11
|
-
const DEFAULT_CODEX_MODEL = "gpt-
|
|
12
|
+
const DEFAULT_CODEX_MODEL = "gpt-6-astra";
|
|
12
13
|
export class BridgeService {
|
|
13
14
|
store;
|
|
14
15
|
adapters;
|
|
@@ -367,7 +368,8 @@ export class BridgeService {
|
|
|
367
368
|
return responses.map((response) => {
|
|
368
369
|
const sessionLabel = response.publicSessionId ?? response.sessionId;
|
|
369
370
|
const modelLabel = response.model?.trim() || this.defaultModelFor(response.provider);
|
|
370
|
-
const
|
|
371
|
+
const effortLabel = response.provider === "codex" && modelLabel === "gpt-6-astra" ? ` | ${response.reasoningEffort ?? getAstraReasoning()}` : "";
|
|
372
|
+
const header = `[${response.provider.toUpperCase()} | ${modelLabel}${effortLabel} | ${sessionLabel}]`;
|
|
371
373
|
return `${header}\n${response.output}`;
|
|
372
374
|
});
|
|
373
375
|
}
|
|
@@ -498,8 +500,10 @@ export class BridgeService {
|
|
|
498
500
|
? await this.codexUsageFallback.selectExecutionModel(primaryModel)
|
|
499
501
|
: { model: primaryModel, recoveryProbe: false };
|
|
500
502
|
let executionModel = selection.model;
|
|
503
|
+
const reasoningEffort = getAstraReasoning();
|
|
501
504
|
const forwardProgress = async (output, model) => {
|
|
502
505
|
const progressResponse = {
|
|
506
|
+
reasoningEffort: provider === "codex" && model === "gpt-6-astra" ? reasoningEffort : undefined,
|
|
503
507
|
provider,
|
|
504
508
|
sessionId: providerSession.sessionId ?? session.sessionId,
|
|
505
509
|
publicSessionId: session.publicId,
|
|
@@ -520,6 +524,7 @@ export class BridgeService {
|
|
|
520
524
|
await onProgress?.(progressResponse);
|
|
521
525
|
};
|
|
522
526
|
const sendWithModel = (model) => this.adapters[provider].send({
|
|
527
|
+
reasoningEffort: provider === "codex" && model === "gpt-6-astra" ? reasoningEffort : undefined,
|
|
523
528
|
botId,
|
|
524
529
|
chatId: chatId ?? requestSource,
|
|
525
530
|
remoteSessionId: session.sessionId,
|
|
@@ -610,6 +615,7 @@ export class BridgeService {
|
|
|
610
615
|
...response,
|
|
611
616
|
publicSessionId: session.publicId,
|
|
612
617
|
model: executionModel,
|
|
618
|
+
reasoningEffort: provider === "codex" && executionModel === "gpt-6-astra" ? reasoningEffort : undefined,
|
|
613
619
|
});
|
|
614
620
|
}
|
|
615
621
|
return responses;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const ASTRA_REASONING_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
2
|
+
export function isAstraReasoning(value) {
|
|
3
|
+
return ASTRA_REASONING_LEVELS.includes(value);
|
|
4
|
+
}
|
|
5
|
+
export function getAstraReasoning() {
|
|
6
|
+
const value = process.env.CODEX_REASONING_EFFORT ?? "medium";
|
|
7
|
+
return isAstraReasoning(value) ? value : "medium";
|
|
8
|
+
}
|
package/package.json
CHANGED
|
@@ -34,6 +34,16 @@ await fs.chmod(fakeCodex, 0o755);
|
|
|
34
34
|
|
|
35
35
|
const { CodexAdapter } = await import(path.join(root, "dist", "adapters", "codex-adapter.js"));
|
|
36
36
|
const adapter = new CodexAdapter(fakeCodex, 5000, "read-only");
|
|
37
|
+
for (const method of ["buildExecArgs", "buildResumeArgs"]) {
|
|
38
|
+
for (const reasoningEffort of ["low", "medium", "high", "xhigh", "max"]) {
|
|
39
|
+
const args = adapter[method]({model: "gpt-6-astra", reasoningEffort, cwd: tmp, sessionId: "stream-thread"}, path.join(tmp, "output"), "read-only");
|
|
40
|
+
if (!args.includes(`model_reasoning_effort="${reasoningEffort}"`)) throw new Error(`Missing ${reasoningEffort} in ${method}`);
|
|
41
|
+
}
|
|
42
|
+
const args = adapter[method]({model: "gpt-6-astra", cwd: tmp, sessionId: "stream-thread"}, path.join(tmp, "output"), "read-only");
|
|
43
|
+
if (args[args.indexOf("-m") + 1] !== "gpt-6-astra" || !args.some((arg, i) => arg === "-c" && args[i + 1] === 'model_reasoning_effort="medium"')) {
|
|
44
|
+
throw new Error(`Astra medium missing from ${method}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
37
47
|
const progress = [];
|
|
38
48
|
let settled = false;
|
|
39
49
|
const responsePromise = adapter.send({
|
|
@@ -18,7 +18,7 @@ const dataDir = path.join(root, "data");
|
|
|
18
18
|
const workspaceRoot = path.join(root, "workspaces");
|
|
19
19
|
const defaultWorkspace = path.join(root, "default-workspace");
|
|
20
20
|
const fallbackStatePath = path.join(dataDir, "codex-usage-fallback.json");
|
|
21
|
-
const primaryModel = "gpt-
|
|
21
|
+
const primaryModel = "gpt-6-astra";
|
|
22
22
|
const usageError = "You've hit your usage limit. Visit https://chatgpt.com/codex/settings/usage to purchase more credits or try again at Aug 27th, 2099 3:52 AM.";
|
|
23
23
|
|
|
24
24
|
try {
|
|
@@ -63,6 +63,10 @@ try {
|
|
|
63
63
|
);
|
|
64
64
|
|
|
65
65
|
let bridge = createBridge();
|
|
66
|
+
process.env.CODEX_REASONING_EFFORT = "max";
|
|
67
|
+
assert.match(bridge.formatResponses([{provider: "codex", model: primaryModel, reasoningEffort: "high", publicSessionId: "S081", output: "done"}])[0], /\| high \| S081/);
|
|
68
|
+
process.env.CODEX_REASONING_EFFORT = "medium";
|
|
69
|
+
assert.equal(bridge.formatResponses([{provider: "codex", model: primaryModel, publicSessionId: "S081", output: "done"}])[0], "[CODEX | gpt-6-astra | medium | S081]\ndone");
|
|
66
70
|
const started = await bridge.startSession("test-bot", "test-chat", "codex");
|
|
67
71
|
const originalSessionId = started.session.sessionId;
|
|
68
72
|
const first = await bridge.routeMessage("test-bot", "test-chat", "first request", async (response) => {
|
|
@@ -323,6 +323,13 @@ await send("/start codex");
|
|
|
323
323
|
await send("/option retry 6");
|
|
324
324
|
await send("/option timeout 600");
|
|
325
325
|
await send("/option intent 4");
|
|
326
|
+
await send("/option reasoning high");
|
|
327
|
+
if (process.env.CODEX_REASONING_EFFORT !== "high" || !(await fs.readFile(path.join(dataDir, ".env"), "utf8")).includes("CODEX_REASONING_EFFORT=high")) {
|
|
328
|
+
throw new Error("Reasoning option was not applied and persisted");
|
|
329
|
+
}
|
|
330
|
+
await send("/option reasoning invalid");
|
|
331
|
+
if (process.env.CODEX_REASONING_EFFORT !== "high") throw new Error("Invalid reasoning changed runtime setting");
|
|
332
|
+
await send("/option reasoning medium");
|
|
326
333
|
await send("/secret set REMOTEAGENT_TRANSFER_PASSPHRASE correct-horse-battery-staple");
|
|
327
334
|
await send("/secret set API_TOKEN telegram-secret-export-value");
|
|
328
335
|
await send("/secret export REMOTEAGENT_TRANSFER_PASSPHRASE API_TOKEN");
|