@kbediako/codex-orchestrator 0.1.36 → 0.1.38
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 +16 -3
- package/dist/bin/codex-orchestrator.js +56 -0
- package/dist/orchestrator/src/cli/config/userConfig.js +17 -1
- package/dist/orchestrator/src/cli/doctorUsage.js +17 -1
- package/dist/orchestrator/src/cli/frontendTestingRunner.js +24 -6
- package/dist/orchestrator/src/cli/orchestrator.js +119 -16
- package/dist/orchestrator/src/cli/rlmRunner.js +27 -3
- package/dist/orchestrator/src/cli/run/manifest.js +19 -0
- package/dist/orchestrator/src/cli/runtime/codexCommand.js +39 -0
- package/dist/orchestrator/src/cli/runtime/index.js +3 -0
- package/dist/orchestrator/src/cli/runtime/mode.js +53 -0
- package/dist/orchestrator/src/cli/runtime/provider.js +205 -0
- package/dist/orchestrator/src/cli/runtime/types.js +1 -0
- package/dist/orchestrator/src/cli/services/commandRunner.js +20 -5
- package/dist/orchestrator/src/cli/services/runPreparation.js +2 -0
- package/dist/orchestrator/src/cli/services/runSummaryWriter.js +12 -0
- package/dist/scripts/run-review.js +55 -9
- package/docs/README.md +7 -4
- package/package.json +13 -3
- package/schemas/manifest.json +21 -0
- package/skills/chrome-devtools/SKILL.md +1 -1
- package/skills/codex-orchestrator/SKILL.md +83 -0
- package/skills/collab-subagents-first/SKILL.md +1 -0
- package/skills/delegation-usage/SKILL.md +1 -0
- package/templates/codex/.codex/agents/explorer-fast.toml +1 -0
|
@@ -21,7 +21,7 @@ import { PipelineResolver } from './services/pipelineResolver.js';
|
|
|
21
21
|
import { ControlPlaneService } from './services/controlPlaneService.js';
|
|
22
22
|
import { ControlWatcher } from './control/controlWatcher.js';
|
|
23
23
|
import { SchedulerService } from './services/schedulerService.js';
|
|
24
|
-
import { applyHandlesToRunSummary, applyPrivacyToRunSummary, applyCloudExecutionToRunSummary, applyCloudFallbackToRunSummary, applyUsageKpiToRunSummary, persistRunSummary } from './services/runSummaryWriter.js';
|
|
24
|
+
import { applyRuntimeToRunSummary, applyHandlesToRunSummary, applyPrivacyToRunSummary, applyCloudExecutionToRunSummary, applyCloudFallbackToRunSummary, applyUsageKpiToRunSummary, persistRunSummary } from './services/runSummaryWriter.js';
|
|
25
25
|
import { prepareRun, resolvePipelineForResume, overrideTaskEnvironment } from './services/runPreparation.js';
|
|
26
26
|
import { loadPackageConfig, loadUserConfig } from './config/userConfig.js';
|
|
27
27
|
import { formatRepoConfigRequiredError, isRepoConfigRequired } from './config/repoConfigPolicy.js';
|
|
@@ -35,6 +35,7 @@ import { CodexCloudTaskExecutor } from '../cloud/CodexCloudTaskExecutor.js';
|
|
|
35
35
|
import { persistPipelineExperience } from './services/pipelineExperience.js';
|
|
36
36
|
import { runCloudPreflight } from './utils/cloudPreflight.js';
|
|
37
37
|
import { writeJsonAtomic } from './utils/fs.js';
|
|
38
|
+
import { resolveRuntimeMode, resolveRuntimeSelection } from './runtime/index.js';
|
|
38
39
|
import { buildAutoScoutEvidence, resolveAdvancedAutopilotDecision } from './utils/advancedAutopilot.js';
|
|
39
40
|
const resolveBaseEnvironment = () => normalizeEnvironmentPaths(resolveEnvironmentPaths());
|
|
40
41
|
const CONFIG_OVERRIDE_ENV_KEYS = ['CODEX_CONFIG_OVERRIDES', 'CODEX_MCP_CONFIG_OVERRIDES'];
|
|
@@ -233,6 +234,11 @@ export class CodexOrchestrator {
|
|
|
233
234
|
planTargetFallback: null
|
|
234
235
|
});
|
|
235
236
|
const runId = generateRunId();
|
|
237
|
+
const runtimeModeResolution = resolveRuntimeMode({
|
|
238
|
+
flag: options.runtimeMode,
|
|
239
|
+
env: { ...process.env, ...(preparation.envOverrides ?? {}) },
|
|
240
|
+
configDefault: preparation.runtimeModeDefault
|
|
241
|
+
});
|
|
236
242
|
const { manifest, paths } = await bootstrapManifest(runId, {
|
|
237
243
|
env: preparation.env,
|
|
238
244
|
pipeline: preparation.pipeline,
|
|
@@ -241,6 +247,7 @@ export class CodexOrchestrator {
|
|
|
241
247
|
approvalPolicy: options.approvalPolicy ?? null,
|
|
242
248
|
planTargetId: preparation.planPreview?.targetId ?? preparation.plannerTargetId ?? null
|
|
243
249
|
});
|
|
250
|
+
this.applyRequestedRuntimeMode(manifest, runtimeModeResolution.mode);
|
|
244
251
|
if (preparation.configNotice) {
|
|
245
252
|
appendSummary(manifest, preparation.configNotice);
|
|
246
253
|
}
|
|
@@ -305,6 +312,8 @@ export class CodexOrchestrator {
|
|
|
305
312
|
onEventEntry,
|
|
306
313
|
persister,
|
|
307
314
|
envOverrides: preparation.envOverrides,
|
|
315
|
+
runtimeModeRequested: runtimeModeResolution.mode,
|
|
316
|
+
runtimeModeSource: runtimeModeResolution.source,
|
|
308
317
|
executionModeOverride: options.executionMode
|
|
309
318
|
});
|
|
310
319
|
}
|
|
@@ -362,6 +371,7 @@ export class CodexOrchestrator {
|
|
|
362
371
|
const preparation = await prepareRun({
|
|
363
372
|
baseEnv: actualEnv,
|
|
364
373
|
pipeline,
|
|
374
|
+
runtimeModeDefault: userConfig?.runtimeMode ?? null,
|
|
365
375
|
resolver,
|
|
366
376
|
taskIdOverride: manifest.task_id,
|
|
367
377
|
targetStageId: options.targetStageId,
|
|
@@ -371,6 +381,14 @@ export class CodexOrchestrator {
|
|
|
371
381
|
if (preparation.configNotice && !(manifest.summary ?? '').includes(preparation.configNotice)) {
|
|
372
382
|
appendSummary(manifest, preparation.configNotice);
|
|
373
383
|
}
|
|
384
|
+
const runtimeModeResolution = resolveRuntimeMode({
|
|
385
|
+
flag: options.runtimeMode,
|
|
386
|
+
env: { ...process.env, ...(preparation.envOverrides ?? {}) },
|
|
387
|
+
configDefault: preparation.runtimeModeDefault,
|
|
388
|
+
manifestMode: manifest.runtime_mode_requested ?? manifest.runtime_mode ?? null,
|
|
389
|
+
preferManifest: true
|
|
390
|
+
});
|
|
391
|
+
this.applyRequestedRuntimeMode(manifest, runtimeModeResolution.mode);
|
|
374
392
|
manifest.plan_target_id = preparation.planPreview?.targetId ?? preparation.plannerTargetId ?? null;
|
|
375
393
|
const persister = new ManifestPersister({
|
|
376
394
|
manifest,
|
|
@@ -433,7 +451,9 @@ export class CodexOrchestrator {
|
|
|
433
451
|
eventStream: stream,
|
|
434
452
|
onEventEntry,
|
|
435
453
|
persister,
|
|
436
|
-
envOverrides: preparation.envOverrides
|
|
454
|
+
envOverrides: preparation.envOverrides,
|
|
455
|
+
runtimeModeRequested: runtimeModeResolution.mode,
|
|
456
|
+
runtimeModeSource: runtimeModeResolution.source
|
|
437
457
|
});
|
|
438
458
|
}
|
|
439
459
|
finally {
|
|
@@ -582,21 +602,52 @@ export class CodexOrchestrator {
|
|
|
582
602
|
return Boolean(task.metadata?.execution?.parallel);
|
|
583
603
|
}
|
|
584
604
|
async executePipeline(options) {
|
|
605
|
+
const baseEnvOverrides = { ...(options.envOverrides ?? {}) };
|
|
606
|
+
const mergedEnv = { ...process.env, ...baseEnvOverrides };
|
|
607
|
+
let runtimeSelection;
|
|
608
|
+
try {
|
|
609
|
+
runtimeSelection = await resolveRuntimeSelection({
|
|
610
|
+
requestedMode: options.runtimeModeRequested,
|
|
611
|
+
source: options.runtimeModeSource,
|
|
612
|
+
executionMode: options.mode,
|
|
613
|
+
repoRoot: options.env.repoRoot,
|
|
614
|
+
env: mergedEnv,
|
|
615
|
+
runId: options.manifest.run_id
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
catch (error) {
|
|
619
|
+
const detail = `Runtime selection failed: ${error?.message ?? String(error)}`;
|
|
620
|
+
finalizeStatus(options.manifest, 'failed', 'runtime-selection-failed');
|
|
621
|
+
appendSummary(options.manifest, detail);
|
|
622
|
+
logger.error(detail);
|
|
623
|
+
return {
|
|
624
|
+
success: false,
|
|
625
|
+
notes: [detail],
|
|
626
|
+
manifest: options.manifest,
|
|
627
|
+
manifestPath: options.paths.manifestPath,
|
|
628
|
+
logPath: options.paths.logPath
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
this.applyRuntimeSelection(options.manifest, runtimeSelection);
|
|
632
|
+
const effectiveEnvOverrides = {
|
|
633
|
+
...baseEnvOverrides,
|
|
634
|
+
...runtimeSelection.env_overrides
|
|
635
|
+
};
|
|
636
|
+
const effectiveMergedEnv = { ...process.env, ...effectiveEnvOverrides };
|
|
585
637
|
if (options.mode === 'cloud') {
|
|
586
|
-
const environmentId = resolveCloudEnvironmentId(options.task, options.target,
|
|
587
|
-
const branch = readCloudString(
|
|
638
|
+
const environmentId = resolveCloudEnvironmentId(options.task, options.target, effectiveEnvOverrides);
|
|
639
|
+
const branch = readCloudString(effectiveEnvOverrides.CODEX_CLOUD_BRANCH) ??
|
|
588
640
|
readCloudString(process.env.CODEX_CLOUD_BRANCH);
|
|
589
|
-
const
|
|
590
|
-
const codexBin = resolveCodexCliBin(mergedEnv);
|
|
641
|
+
const codexBin = resolveCodexCliBin(effectiveMergedEnv);
|
|
591
642
|
const preflight = await runCloudPreflight({
|
|
592
643
|
repoRoot: options.env.repoRoot,
|
|
593
644
|
codexBin,
|
|
594
645
|
environmentId,
|
|
595
646
|
branch,
|
|
596
|
-
env:
|
|
647
|
+
env: effectiveMergedEnv
|
|
597
648
|
});
|
|
598
649
|
if (!preflight.ok) {
|
|
599
|
-
if (!allowCloudFallback(
|
|
650
|
+
if (!allowCloudFallback(effectiveEnvOverrides)) {
|
|
600
651
|
const detail = `Cloud preflight failed and cloud fallback is disabled. ` +
|
|
601
652
|
preflight.issues.map((issue) => issue.message).join(' ');
|
|
602
653
|
finalizeStatus(options.manifest, 'failed', 'cloud-preflight-failed');
|
|
@@ -621,21 +672,35 @@ export class CodexOrchestrator {
|
|
|
621
672
|
};
|
|
622
673
|
appendSummary(options.manifest, detail);
|
|
623
674
|
logger.warn(detail);
|
|
624
|
-
const fallback = await this.executePipeline({
|
|
675
|
+
const fallback = await this.executePipeline({
|
|
676
|
+
...options,
|
|
677
|
+
mode: 'mcp',
|
|
678
|
+
executionModeOverride: 'mcp',
|
|
679
|
+
runtimeModeRequested: runtimeSelection.selected_mode,
|
|
680
|
+
runtimeModeSource: runtimeSelection.source,
|
|
681
|
+
envOverrides: effectiveEnvOverrides
|
|
682
|
+
});
|
|
625
683
|
fallback.notes.unshift(detail);
|
|
626
684
|
return fallback;
|
|
627
685
|
}
|
|
628
|
-
return await this.executeCloudPipeline(options);
|
|
686
|
+
return await this.executeCloudPipeline({ ...options, envOverrides: effectiveEnvOverrides });
|
|
629
687
|
}
|
|
630
|
-
const { env, pipeline, manifest, paths, runEvents
|
|
688
|
+
const { env, pipeline, manifest, paths, runEvents } = options;
|
|
631
689
|
const notes = [];
|
|
632
690
|
let success = true;
|
|
633
691
|
manifest.guardrail_status = undefined;
|
|
692
|
+
if (runtimeSelection.fallback.occurred) {
|
|
693
|
+
const fallbackCode = runtimeSelection.fallback.code ?? 'runtime-fallback';
|
|
694
|
+
const fallbackReason = runtimeSelection.fallback.reason ?? 'runtime fallback occurred';
|
|
695
|
+
const fallbackSummary = `Runtime fallback (${fallbackCode}): ${fallbackReason}`;
|
|
696
|
+
appendSummary(manifest, fallbackSummary);
|
|
697
|
+
notes.push(fallbackSummary);
|
|
698
|
+
}
|
|
634
699
|
const advancedDecision = resolveAdvancedAutopilotDecision({
|
|
635
700
|
pipelineId: pipeline.id,
|
|
636
701
|
targetMetadata: (options.target.metadata ?? null),
|
|
637
702
|
taskMetadata: (options.task.metadata ?? null),
|
|
638
|
-
env:
|
|
703
|
+
env: effectiveMergedEnv
|
|
639
704
|
});
|
|
640
705
|
if (advancedDecision.enabled || advancedDecision.source !== 'default') {
|
|
641
706
|
const advancedSummary = `Advanced mode (${advancedDecision.mode}) ${advancedDecision.enabled ? 'enabled' : 'disabled'}: ${advancedDecision.reason}.`;
|
|
@@ -673,7 +738,7 @@ export class CodexOrchestrator {
|
|
|
673
738
|
pipeline,
|
|
674
739
|
target: options.target,
|
|
675
740
|
task: options.task,
|
|
676
|
-
envOverrides,
|
|
741
|
+
envOverrides: effectiveEnvOverrides,
|
|
677
742
|
advancedDecision
|
|
678
743
|
});
|
|
679
744
|
const scoutMessage = scoutOutcome.status === 'recorded'
|
|
@@ -719,7 +784,9 @@ export class CodexOrchestrator {
|
|
|
719
784
|
index: entry.index,
|
|
720
785
|
events: runEvents,
|
|
721
786
|
persister,
|
|
722
|
-
envOverrides
|
|
787
|
+
envOverrides: effectiveEnvOverrides,
|
|
788
|
+
runtimeMode: runtimeSelection.selected_mode,
|
|
789
|
+
runtimeSessionId: runtimeSelection.runtime_session_id
|
|
723
790
|
});
|
|
724
791
|
notes.push(`${stage.title}: ${result.summary}`);
|
|
725
792
|
const updatedEntry = manifest.commands[i];
|
|
@@ -769,7 +836,8 @@ export class CodexOrchestrator {
|
|
|
769
836
|
pipelineId: stage.pipeline,
|
|
770
837
|
parentRunId: manifest.run_id,
|
|
771
838
|
format: 'json',
|
|
772
|
-
executionMode: options.executionModeOverride
|
|
839
|
+
executionMode: options.executionModeOverride,
|
|
840
|
+
runtimeMode: options.runtimeModeRequested
|
|
773
841
|
});
|
|
774
842
|
entry.completed_at = isoTimestamp();
|
|
775
843
|
entry.sub_run_id = child.manifest.run_id;
|
|
@@ -1184,7 +1252,7 @@ export class CodexOrchestrator {
|
|
|
1184
1252
|
}
|
|
1185
1253
|
}
|
|
1186
1254
|
async performRunLifecycle(context) {
|
|
1187
|
-
const { env, pipeline, manifest, paths, planner, taskContext, runId, persister, envOverrides, executionModeOverride } = context;
|
|
1255
|
+
const { env, pipeline, manifest, paths, planner, taskContext, runId, persister, envOverrides, runtimeModeRequested, runtimeModeSource, executionModeOverride } = context;
|
|
1188
1256
|
let latestPipelineResult = null;
|
|
1189
1257
|
const executingByKey = new Map();
|
|
1190
1258
|
const executePipeline = async (input) => {
|
|
@@ -1199,6 +1267,8 @@ export class CodexOrchestrator {
|
|
|
1199
1267
|
manifest,
|
|
1200
1268
|
paths,
|
|
1201
1269
|
mode: input.mode,
|
|
1270
|
+
runtimeModeRequested,
|
|
1271
|
+
runtimeModeSource,
|
|
1202
1272
|
executionModeOverride,
|
|
1203
1273
|
target: input.target,
|
|
1204
1274
|
task: taskContext,
|
|
@@ -1254,6 +1324,7 @@ export class CodexOrchestrator {
|
|
|
1254
1324
|
persister
|
|
1255
1325
|
});
|
|
1256
1326
|
this.scheduler.applySchedulerToRunSummary(runSummary, schedulerPlan);
|
|
1327
|
+
applyRuntimeToRunSummary(runSummary, manifest);
|
|
1257
1328
|
applyHandlesToRunSummary(runSummary, manifest);
|
|
1258
1329
|
applyPrivacyToRunSummary(runSummary, manifest);
|
|
1259
1330
|
applyCloudExecutionToRunSummary(runSummary, manifest);
|
|
@@ -1283,6 +1354,25 @@ export class CodexOrchestrator {
|
|
|
1283
1354
|
});
|
|
1284
1355
|
});
|
|
1285
1356
|
}
|
|
1357
|
+
applyRequestedRuntimeMode(manifest, mode) {
|
|
1358
|
+
manifest.runtime_mode_requested = mode;
|
|
1359
|
+
manifest.runtime_mode = mode;
|
|
1360
|
+
manifest.runtime_provider = mode === 'appserver' ? 'AppServerRuntimeProvider' : 'CliRuntimeProvider';
|
|
1361
|
+
manifest.runtime_fallback = {
|
|
1362
|
+
occurred: false,
|
|
1363
|
+
code: null,
|
|
1364
|
+
reason: null,
|
|
1365
|
+
from_mode: null,
|
|
1366
|
+
to_mode: null,
|
|
1367
|
+
checked_at: isoTimestamp()
|
|
1368
|
+
};
|
|
1369
|
+
}
|
|
1370
|
+
applyRuntimeSelection(manifest, selection) {
|
|
1371
|
+
manifest.runtime_mode_requested = selection.requested_mode;
|
|
1372
|
+
manifest.runtime_mode = selection.selected_mode;
|
|
1373
|
+
manifest.runtime_provider = selection.provider;
|
|
1374
|
+
manifest.runtime_fallback = selection.fallback;
|
|
1375
|
+
}
|
|
1286
1376
|
async validateResumeToken(paths, manifest, provided) {
|
|
1287
1377
|
let stored = manifest.resume_token;
|
|
1288
1378
|
if (!stored) {
|
|
@@ -1311,6 +1401,10 @@ export class CodexOrchestrator {
|
|
|
1311
1401
|
activity,
|
|
1312
1402
|
commands: manifest.commands,
|
|
1313
1403
|
child_runs: manifest.child_runs,
|
|
1404
|
+
runtime_mode_requested: manifest.runtime_mode_requested,
|
|
1405
|
+
runtime_mode: manifest.runtime_mode,
|
|
1406
|
+
runtime_provider: manifest.runtime_provider,
|
|
1407
|
+
runtime_fallback: manifest.runtime_fallback ?? null,
|
|
1314
1408
|
cloud_execution: manifest.cloud_execution ?? null,
|
|
1315
1409
|
cloud_fallback: manifest.cloud_fallback ?? null
|
|
1316
1410
|
};
|
|
@@ -1321,6 +1415,15 @@ export class CodexOrchestrator {
|
|
|
1321
1415
|
logger.info(`Started: ${manifest.started_at}`);
|
|
1322
1416
|
logger.info(`Completed: ${manifest.completed_at ?? 'in-progress'}`);
|
|
1323
1417
|
logger.info(`Manifest: ${manifest.artifact_root}/manifest.json`);
|
|
1418
|
+
if (manifest.runtime_mode || manifest.runtime_mode_requested || manifest.runtime_provider) {
|
|
1419
|
+
const selectedMode = manifest.runtime_mode ?? 'unknown';
|
|
1420
|
+
logger.info(`Runtime: ${selectedMode}${manifest.runtime_mode_requested ? ` (requested ${manifest.runtime_mode_requested})` : ''}` +
|
|
1421
|
+
(manifest.runtime_provider ? ` via ${manifest.runtime_provider}` : ''));
|
|
1422
|
+
}
|
|
1423
|
+
if (manifest.runtime_fallback?.occurred) {
|
|
1424
|
+
const fallbackCode = manifest.runtime_fallback.code ?? 'runtime-fallback';
|
|
1425
|
+
logger.info(`Runtime fallback: ${fallbackCode} — ${manifest.runtime_fallback.reason ?? 'n/a'}`);
|
|
1426
|
+
}
|
|
1324
1427
|
if (activity.observed_at) {
|
|
1325
1428
|
const staleSuffix = activity.stale === null ? '' : activity.stale ? ' [stale]' : ' [active]';
|
|
1326
1429
|
const sourceLabel = activity.observed_source ? ` via ${activity.observed_source}` : '';
|
|
@@ -7,7 +7,7 @@ import { promisify } from 'node:util';
|
|
|
7
7
|
import { createInterface } from 'node:readline/promises';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
import { logger } from '../logger.js';
|
|
10
|
-
import {
|
|
10
|
+
import { createRuntimeCodexCommandContext, formatRuntimeSelectionSummary, parseRuntimeMode, resolveRuntimeCodexCommand } from './runtime/index.js';
|
|
11
11
|
import { detectValidator } from './rlm/validator.js';
|
|
12
12
|
import { buildRlmPrompt } from './rlm/prompt.js';
|
|
13
13
|
import { runRlmLoop } from './rlm/runner.js';
|
|
@@ -57,6 +57,8 @@ const COLLAB_FEATURE_CANONICAL = 'multi_agent';
|
|
|
57
57
|
const COLLAB_FEATURE_LEGACY = 'collab';
|
|
58
58
|
const COLLAB_ROLE_TAG_PATTERN = /^\s*\[(?:agent_type|role)\s*:\s*([a-z0-9._-]+)\]/i;
|
|
59
59
|
const COLLAB_ROLE_TOKEN_PATTERN = /^[a-z0-9._-]+$/;
|
|
60
|
+
let runtimeCodexContextPromise = null;
|
|
61
|
+
let runtimeCodexContextLogged = false;
|
|
60
62
|
function parseArgs(argv) {
|
|
61
63
|
const parsed = {};
|
|
62
64
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -332,8 +334,9 @@ async function runCodexAgent(input, env, repoRoot, nonInteractive, subagentsEnab
|
|
|
332
334
|
return { output };
|
|
333
335
|
}
|
|
334
336
|
async function runCodexExec(args, env, repoRoot, nonInteractive, subagentsEnabled, mirrorOutput) {
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
+
const runtimeContext = await resolveRlmRuntimeCodexContext(env, repoRoot);
|
|
338
|
+
const { command, args: resolvedArgs } = resolveRuntimeCodexCommand(args, runtimeContext);
|
|
339
|
+
const childEnv = { ...process.env, ...env, ...runtimeContext.env };
|
|
337
340
|
if (nonInteractive) {
|
|
338
341
|
childEnv.CODEX_NON_INTERACTIVE = childEnv.CODEX_NON_INTERACTIVE ?? '1';
|
|
339
342
|
childEnv.CODEX_NO_INTERACTIVE = childEnv.CODEX_NO_INTERACTIVE ?? '1';
|
|
@@ -370,6 +373,27 @@ async function runCodexExec(args, env, repoRoot, nonInteractive, subagentsEnable
|
|
|
370
373
|
});
|
|
371
374
|
return { stdout, stderr };
|
|
372
375
|
}
|
|
376
|
+
async function resolveRlmRuntimeCodexContext(env, repoRoot) {
|
|
377
|
+
if (!runtimeCodexContextPromise) {
|
|
378
|
+
const requestedMode = parseRuntimeMode(env.CODEX_ORCHESTRATOR_RUNTIME_MODE_ACTIVE ?? env.CODEX_ORCHESTRATOR_RUNTIME_MODE ?? null);
|
|
379
|
+
const runId = typeof env.CODEX_ORCHESTRATOR_RUN_ID === 'string' && env.CODEX_ORCHESTRATOR_RUN_ID.trim().length > 0
|
|
380
|
+
? env.CODEX_ORCHESTRATOR_RUN_ID.trim()
|
|
381
|
+
: `rlm-${Date.now()}`;
|
|
382
|
+
runtimeCodexContextPromise = createRuntimeCodexCommandContext({
|
|
383
|
+
requestedMode,
|
|
384
|
+
executionMode: 'mcp',
|
|
385
|
+
repoRoot,
|
|
386
|
+
env: { ...process.env, ...env },
|
|
387
|
+
runId
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
const runtimeContext = await runtimeCodexContextPromise;
|
|
391
|
+
if (!runtimeCodexContextLogged) {
|
|
392
|
+
logger.info(`[rlm-runtime] ${formatRuntimeSelectionSummary(runtimeContext.runtime)}`);
|
|
393
|
+
runtimeCodexContextLogged = true;
|
|
394
|
+
}
|
|
395
|
+
return runtimeContext;
|
|
396
|
+
}
|
|
373
397
|
async function runCodexCompletion(prompt, env, repoRoot, nonInteractive, subagentsEnabled, mirrorOutput) {
|
|
374
398
|
const { stdout, stderr } = await runCodexExec(['exec', prompt], env, repoRoot, nonInteractive, subagentsEnabled, mirrorOutput);
|
|
375
399
|
return [stdout.trim(), stderr.trim()].filter(Boolean).join('\n');
|
|
@@ -13,6 +13,19 @@ const HEARTBEAT_INTERVAL_SECONDS = 5;
|
|
|
13
13
|
const HEARTBEAT_STALE_AFTER_SECONDS = 30;
|
|
14
14
|
const MAX_ERROR_DETAIL_CHARS = 8 * 1024;
|
|
15
15
|
const DEFAULT_MIN_EXPERIENCE_REWARD = 0.1;
|
|
16
|
+
function createDefaultRuntimeFallback() {
|
|
17
|
+
return {
|
|
18
|
+
occurred: false,
|
|
19
|
+
code: null,
|
|
20
|
+
reason: null,
|
|
21
|
+
from_mode: null,
|
|
22
|
+
to_mode: null,
|
|
23
|
+
checked_at: isoTimestamp()
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function runtimeProviderForMode(mode) {
|
|
27
|
+
return mode === 'appserver' ? 'AppServerRuntimeProvider' : 'CliRuntimeProvider';
|
|
28
|
+
}
|
|
16
29
|
export async function bootstrapManifest(runId, options) {
|
|
17
30
|
const { env, pipeline, parentRunId = null, taskSlug, approvalPolicy = null } = options;
|
|
18
31
|
const paths = resolveRunPaths(env, runId);
|
|
@@ -57,6 +70,10 @@ export async function bootstrapManifest(runId, options) {
|
|
|
57
70
|
instructions_sources: [],
|
|
58
71
|
prompt_packs: [],
|
|
59
72
|
guardrails_required: pipeline.guardrailsRequired !== false,
|
|
73
|
+
runtime_mode_requested: 'appserver',
|
|
74
|
+
runtime_mode: 'appserver',
|
|
75
|
+
runtime_provider: runtimeProviderForMode('appserver'),
|
|
76
|
+
runtime_fallback: createDefaultRuntimeFallback(),
|
|
60
77
|
cloud_execution: null,
|
|
61
78
|
cloud_fallback: null,
|
|
62
79
|
learning: {
|
|
@@ -192,6 +209,8 @@ export function resetForResume(manifest) {
|
|
|
192
209
|
manifest.status = 'in_progress';
|
|
193
210
|
manifest.status_detail = 'resuming';
|
|
194
211
|
manifest.guardrail_status = undefined;
|
|
212
|
+
manifest.runtime_provider = runtimeProviderForMode(manifest.runtime_mode);
|
|
213
|
+
manifest.runtime_fallback = createDefaultRuntimeFallback();
|
|
195
214
|
manifest.cloud_execution = null;
|
|
196
215
|
manifest.cloud_fallback = null;
|
|
197
216
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { resolveCodexCommand } from '../utils/devtools.js';
|
|
2
|
+
import { resolveRuntimeMode } from './mode.js';
|
|
3
|
+
import { resolveRuntimeSelection } from './provider.js';
|
|
4
|
+
export async function createRuntimeCodexCommandContext(options) {
|
|
5
|
+
const runtimeEnv = options.env ?? process.env;
|
|
6
|
+
const modeResolution = resolveRuntimeMode({
|
|
7
|
+
flag: options.requestedMode,
|
|
8
|
+
env: runtimeEnv,
|
|
9
|
+
configDefault: options.configDefault
|
|
10
|
+
});
|
|
11
|
+
const runtime = await resolveRuntimeSelection({
|
|
12
|
+
requestedMode: modeResolution.mode,
|
|
13
|
+
source: modeResolution.source,
|
|
14
|
+
executionMode: options.executionMode ?? 'mcp',
|
|
15
|
+
repoRoot: options.repoRoot,
|
|
16
|
+
env: runtimeEnv,
|
|
17
|
+
runId: options.runId,
|
|
18
|
+
allowFallback: options.allowFallback
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
runtime,
|
|
22
|
+
env: {
|
|
23
|
+
...runtimeEnv,
|
|
24
|
+
...runtime.env_overrides
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export function resolveRuntimeCodexCommand(args, context) {
|
|
29
|
+
return resolveCodexCommand(args, context.env);
|
|
30
|
+
}
|
|
31
|
+
export function formatRuntimeSelectionSummary(selection) {
|
|
32
|
+
const base = `runtime requested=${selection.requested_mode} selected=${selection.selected_mode} provider=${selection.provider}`;
|
|
33
|
+
if (!selection.fallback.occurred) {
|
|
34
|
+
return base;
|
|
35
|
+
}
|
|
36
|
+
const code = selection.fallback.code ?? 'unknown';
|
|
37
|
+
const reason = selection.fallback.reason ?? 'fallback occurred';
|
|
38
|
+
return `${base} fallback=${code} (${reason})`;
|
|
39
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { parseRuntimeMode, resolveRuntimeMode, DEFAULT_RUNTIME_MODE, DEFAULT_RUNTIME_MODE_ENV_KEY } from './mode.js';
|
|
2
|
+
export { resolveRuntimeSelection } from './provider.js';
|
|
3
|
+
export { createRuntimeCodexCommandContext, resolveRuntimeCodexCommand, formatRuntimeSelectionSummary } from './codexCommand.js';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const RUNTIME_MODES = new Set(['cli', 'appserver']);
|
|
2
|
+
const DEFAULT_RUNTIME_MODE = 'appserver';
|
|
3
|
+
const DEFAULT_RUNTIME_MODE_ENV_KEY = 'CODEX_ORCHESTRATOR_RUNTIME_MODE';
|
|
4
|
+
function normalizeRuntimeMode(value) {
|
|
5
|
+
const normalized = value.trim().toLowerCase();
|
|
6
|
+
return RUNTIME_MODES.has(normalized) ? normalized : null;
|
|
7
|
+
}
|
|
8
|
+
function parseRuntimeModeFromSource(value, sourceLabel) {
|
|
9
|
+
const parsed = normalizeRuntimeMode(value);
|
|
10
|
+
if (!parsed) {
|
|
11
|
+
throw new Error(`Invalid runtime mode "${value}" from ${sourceLabel}. Expected one of: cli, appserver.`);
|
|
12
|
+
}
|
|
13
|
+
return parsed;
|
|
14
|
+
}
|
|
15
|
+
export function parseRuntimeMode(value) {
|
|
16
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return normalizeRuntimeMode(value);
|
|
20
|
+
}
|
|
21
|
+
export function resolveRuntimeMode(options = {}) {
|
|
22
|
+
if (typeof options.flag === 'string' && options.flag.trim().length > 0) {
|
|
23
|
+
return {
|
|
24
|
+
mode: parseRuntimeModeFromSource(options.flag, 'CLI flag'),
|
|
25
|
+
source: 'flag'
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const envKey = options.envKey ?? DEFAULT_RUNTIME_MODE_ENV_KEY;
|
|
29
|
+
const envValue = options.env?.[envKey] ?? process.env[envKey];
|
|
30
|
+
if (typeof envValue === 'string' && envValue.trim().length > 0) {
|
|
31
|
+
return {
|
|
32
|
+
mode: parseRuntimeModeFromSource(envValue, `env ${envKey}`),
|
|
33
|
+
source: 'env'
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (typeof options.configDefault === 'string' && options.configDefault.trim().length > 0) {
|
|
37
|
+
return {
|
|
38
|
+
mode: parseRuntimeModeFromSource(options.configDefault, 'config default'),
|
|
39
|
+
source: 'config'
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (options.preferManifest && typeof options.manifestMode === 'string' && options.manifestMode.trim().length > 0) {
|
|
43
|
+
return {
|
|
44
|
+
mode: parseRuntimeModeFromSource(options.manifestMode, 'manifest'),
|
|
45
|
+
source: 'manifest'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
mode: DEFAULT_RUNTIME_MODE,
|
|
50
|
+
source: 'default'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export { DEFAULT_RUNTIME_MODE, DEFAULT_RUNTIME_MODE_ENV_KEY };
|