@gh-symphony/cli 0.0.19 → 0.0.20
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/{chunk-H2YXSYOZ.js → chunk-3AWF54PI.js} +1 -1
- package/dist/{chunk-GKENCODJ.js → chunk-EKKT5USP.js} +1 -1
- package/dist/{chunk-6CI3UUMH.js → chunk-HZVDTAPS.js} +19 -70
- package/dist/index.js +7 -7
- package/dist/{project-DNALEWO3.js → project-UUVHS3ZR.js} +3 -3
- package/dist/{recover-C3V2QAUB.js → recover-5KQI7WH5.js} +1 -1
- package/dist/{run-XI2S5Y4V.js → run-ETC5UTRA.js} +1 -1
- package/dist/{setup-K4CYYJBF.js → setup-VWB7RZUQ.js} +3 -3
- package/dist/{start-M6IQGRFO.js → start-ENFLZUI6.js} +2 -2
- package/dist/{upgrade-F4VE4XBS.js → upgrade-3YNF3VKY.js} +2 -2
- package/dist/{version-Y5RYNWMF.js → version-NUBTTOG7.js} +1 -1
- package/dist/worker-entry.js +47 -191
- package/package.json +3 -3
|
@@ -1384,8 +1384,6 @@ var DEFAULT_POLL_INTERVAL_MS = 3e4;
|
|
|
1384
1384
|
var DEFAULT_CONCURRENCY = 3;
|
|
1385
1385
|
var DEFAULT_RETRY_BACKOFF_MS = 3e4;
|
|
1386
1386
|
var CONTINUATION_RETRY_DELAY_MS = 1e3;
|
|
1387
|
-
var DEFAULT_GLOBAL_MAX_TURNS = 100;
|
|
1388
|
-
var DEFAULT_MAX_TOKENS = 256e3;
|
|
1389
1387
|
var DEFAULT_WORKER_COMMAND = "node packages/worker/dist/index.js";
|
|
1390
1388
|
var DEFAULT_MAX_NONPRODUCTIVE_TURNS = 3;
|
|
1391
1389
|
var LOW_RATE_LIMIT_WARNING_THRESHOLD = 0.05;
|
|
@@ -1650,9 +1648,6 @@ var OrchestratorService = class {
|
|
|
1650
1648
|
if (await this.isFailureRetrySuppressedIssue(tenant, issue, issueRecords, latestRunsByIssueId.get(issue.id) ?? null)) {
|
|
1651
1649
|
continue;
|
|
1652
1650
|
}
|
|
1653
|
-
if (isIssueBudgetExceeded(resolveIssueBudgetSnapshot(projectRunsAfterReconcile, issue.id), now)) {
|
|
1654
|
-
continue;
|
|
1655
|
-
}
|
|
1656
1651
|
const stateLimit = maxConcurrentByState[issue.state];
|
|
1657
1652
|
if (stateLimit !== void 0) {
|
|
1658
1653
|
const activeInState = activeByState.get(issue.state) ?? 0;
|
|
@@ -2014,7 +2009,7 @@ var OrchestratorService = class {
|
|
|
2014
2009
|
const resolution = await loadRepositoryWorkflow(repositoryDirectory, repository);
|
|
2015
2010
|
return this.resolveWorkflowResolution(repository, cacheRoot, resolution, changed);
|
|
2016
2011
|
}
|
|
2017
|
-
async startRun(tenant, issue
|
|
2012
|
+
async startRun(tenant, issue) {
|
|
2018
2013
|
if (this.shuttingDown || !this.running) {
|
|
2019
2014
|
throw new Error("Orchestrator is shutting down and cannot start new runs.");
|
|
2020
2015
|
}
|
|
@@ -2076,8 +2071,6 @@ var OrchestratorService = class {
|
|
|
2076
2071
|
if (!isUsableWorkflowResolution(workflow)) {
|
|
2077
2072
|
throw new Error(workflow.validationError ?? "Invalid repository WORKFLOW.md");
|
|
2078
2073
|
}
|
|
2079
|
-
const allProjectRuns = (await this.store.loadAllRuns()).filter((run) => run.projectId === tenant.projectId);
|
|
2080
|
-
const issueBudgetSnapshot = resolveIssueBudgetSnapshot(allProjectRuns, issue.id);
|
|
2081
2074
|
const promptVariables = buildPromptVariables(issue, {
|
|
2082
2075
|
attempt: null
|
|
2083
2076
|
// first execution
|
|
@@ -2147,17 +2140,19 @@ var OrchestratorService = class {
|
|
|
2147
2140
|
SYMPHONY_THREAD_SANDBOX: workflow.workflow.codex.threadSandbox ?? "",
|
|
2148
2141
|
SYMPHONY_TURN_SANDBOX_POLICY: workflow.workflow.codex.turnSandboxPolicy ?? "",
|
|
2149
2142
|
SYMPHONY_MAX_TURNS: String(workflow.workflow.agent.maxTurns),
|
|
2150
|
-
SYMPHONY_GLOBAL_MAX_TURNS: process.env.SYMPHONY_GLOBAL_MAX_TURNS ?? "",
|
|
2151
|
-
SYMPHONY_MAX_TOKENS: process.env.SYMPHONY_MAX_TOKENS ?? "",
|
|
2152
2143
|
SYMPHONY_MAX_NONPRODUCTIVE_TURNS: process.env.SYMPHONY_MAX_NONPRODUCTIVE_TURNS ?? String(DEFAULT_MAX_NONPRODUCTIVE_TURNS),
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2144
|
+
// Clear legacy resume/budget env so fresh worker sessions do not
|
|
2145
|
+
// inherit stale process-level values.
|
|
2146
|
+
SYMPHONY_GLOBAL_MAX_TURNS: "",
|
|
2147
|
+
SYMPHONY_MAX_TOKENS: "",
|
|
2148
|
+
SYMPHONY_SESSION_TIMEOUT_MS: "",
|
|
2149
|
+
SYMPHONY_RESUME_THREAD_ID: "",
|
|
2150
|
+
SYMPHONY_CUMULATIVE_TURN_COUNT: "0",
|
|
2151
|
+
SYMPHONY_CUMULATIVE_INPUT_TOKENS: "0",
|
|
2152
|
+
SYMPHONY_CUMULATIVE_OUTPUT_TOKENS: "0",
|
|
2153
|
+
SYMPHONY_CUMULATIVE_TOTAL_TOKENS: "0",
|
|
2154
|
+
SYMPHONY_LAST_TURN_SUMMARY: "",
|
|
2155
|
+
SYMPHONY_SESSION_STARTED_AT: "",
|
|
2161
2156
|
SYMPHONY_READ_TIMEOUT_MS: String(workflow.workflow.codex.readTimeoutMs),
|
|
2162
2157
|
SYMPHONY_TURN_TIMEOUT_MS: String(workflow.workflow.codex.turnTimeoutMs)
|
|
2163
2158
|
}),
|
|
@@ -2402,17 +2397,17 @@ var OrchestratorService = class {
|
|
|
2402
2397
|
}
|
|
2403
2398
|
return this.restartRun(tenant, run, issueRecords, now, workerSessionId);
|
|
2404
2399
|
}
|
|
2405
|
-
if (workerInfo.exitClassification === "
|
|
2400
|
+
if (workerInfo.exitClassification === "convergence-detected") {
|
|
2406
2401
|
const completedRun = {
|
|
2407
2402
|
...runWithTokens,
|
|
2408
|
-
status:
|
|
2403
|
+
status: "failed",
|
|
2409
2404
|
processId: null,
|
|
2410
2405
|
updatedAt: now.toISOString(),
|
|
2411
2406
|
completedAt: now.toISOString(),
|
|
2412
2407
|
nextRetryAt: null,
|
|
2413
2408
|
retryKind: null,
|
|
2414
|
-
lastError:
|
|
2415
|
-
runPhase: runWithTokens.runPhase ??
|
|
2409
|
+
lastError: runWithTokens.lastError,
|
|
2410
|
+
runPhase: runWithTokens.runPhase ?? "failed"
|
|
2416
2411
|
};
|
|
2417
2412
|
await this.store.saveRun(completedRun);
|
|
2418
2413
|
this.logVerbose(`[run-completed] ${completedRun.runId} status=${completedRun.status}`);
|
|
@@ -2749,9 +2744,6 @@ var OrchestratorService = class {
|
|
|
2749
2744
|
}
|
|
2750
2745
|
async resolveRetryRestartAction(tenant, run, trackerDependencies = {}) {
|
|
2751
2746
|
try {
|
|
2752
|
-
if (isIssueBudgetExceeded(resolveIssueBudgetSnapshot((await this.store.loadAllRuns()).filter((candidate) => candidate.projectId === tenant.projectId), run.issueId), this.now())) {
|
|
2753
|
-
return "release";
|
|
2754
|
-
}
|
|
2755
2747
|
const eligibleContext = await this.fetchTrackedIssueEligibilityContext(tenant, run.issueIdentifier, trackerDependencies);
|
|
2756
2748
|
if (!eligibleContext) {
|
|
2757
2749
|
return "release";
|
|
@@ -2863,18 +2855,14 @@ var OrchestratorService = class {
|
|
|
2863
2855
|
};
|
|
2864
2856
|
await this.store.saveRun(supersededRecord);
|
|
2865
2857
|
const issue = resolveTrackerAdapter2(tenant.tracker).reviveIssue(tenant, run);
|
|
2866
|
-
const restarted = await this.startRun(tenant, issue
|
|
2867
|
-
threadId: run.threadId ?? run.runtimeSession?.threadId ?? null,
|
|
2868
|
-
cumulativeTurnCount: resolvePersistedCumulativeTurnCount(run),
|
|
2869
|
-
lastTurnSummary: run.lastTurnSummary ?? null
|
|
2870
|
-
});
|
|
2858
|
+
const restarted = await this.startRun(tenant, issue);
|
|
2871
2859
|
const recoveredRecord = {
|
|
2872
2860
|
...restarted,
|
|
2873
2861
|
attempt: run.attempt,
|
|
2874
2862
|
retryKind: run.retryKind ?? "recovery",
|
|
2875
2863
|
createdAt: run.createdAt,
|
|
2876
2864
|
issueWorkspaceKey: run.issueWorkspaceKey,
|
|
2877
|
-
threadId:
|
|
2865
|
+
threadId: null,
|
|
2878
2866
|
cumulativeTurnCount: resolvePersistedCumulativeTurnCount(run),
|
|
2879
2867
|
lastTurnSummary: run.lastTurnSummary ?? null,
|
|
2880
2868
|
turnCount: 0
|
|
@@ -3279,45 +3267,6 @@ function hasConvergenceLockedRun(runs, issueId, issueState, issueUpdatedAt) {
|
|
|
3279
3267
|
}
|
|
3280
3268
|
return issueUpdatedAtMs <= convergedAtMs;
|
|
3281
3269
|
}
|
|
3282
|
-
function resolveIssueBudgetSnapshot(runs, issueId) {
|
|
3283
|
-
const issueRuns = runs.filter((run) => run.issueId === issueId);
|
|
3284
|
-
const startedAtCandidates = issueRuns.map((run) => run.startedAt).filter((value) => typeof value === "string");
|
|
3285
|
-
return {
|
|
3286
|
-
cumulativeTurnCount: issueRuns.reduce((total, run) => total + resolvePersistedCumulativeTurnCount(run), 0),
|
|
3287
|
-
tokenUsage: issueRuns.reduce((total, run) => ({
|
|
3288
|
-
inputTokens: total.inputTokens + (run.tokenUsage?.inputTokens ?? 0),
|
|
3289
|
-
outputTokens: total.outputTokens + (run.tokenUsage?.outputTokens ?? 0),
|
|
3290
|
-
totalTokens: total.totalTokens + (run.tokenUsage?.totalTokens ?? 0)
|
|
3291
|
-
}), {
|
|
3292
|
-
inputTokens: 0,
|
|
3293
|
-
outputTokens: 0,
|
|
3294
|
-
totalTokens: 0
|
|
3295
|
-
}),
|
|
3296
|
-
sessionStartedAt: startedAtCandidates.sort((left, right) => left.localeCompare(right))[0] ?? null
|
|
3297
|
-
};
|
|
3298
|
-
}
|
|
3299
|
-
function isIssueBudgetExceeded(snapshot, now, env = process.env) {
|
|
3300
|
-
const globalMaxTurns = parsePositiveInteger(env.SYMPHONY_GLOBAL_MAX_TURNS ?? "") ?? DEFAULT_GLOBAL_MAX_TURNS;
|
|
3301
|
-
if (snapshot.cumulativeTurnCount >= globalMaxTurns) {
|
|
3302
|
-
return true;
|
|
3303
|
-
}
|
|
3304
|
-
const maxTokens = parsePositiveInteger(env.SYMPHONY_MAX_TOKENS ?? "") ?? DEFAULT_MAX_TOKENS;
|
|
3305
|
-
if (snapshot.tokenUsage.totalTokens >= maxTokens) {
|
|
3306
|
-
return true;
|
|
3307
|
-
}
|
|
3308
|
-
const sessionTimeoutMs = parsePositiveInteger(env.SYMPHONY_SESSION_TIMEOUT_MS ?? "");
|
|
3309
|
-
if (sessionTimeoutMs === null || snapshot.sessionStartedAt === null) {
|
|
3310
|
-
return false;
|
|
3311
|
-
}
|
|
3312
|
-
return now.getTime() - new Date(snapshot.sessionStartedAt).getTime() >= sessionTimeoutMs;
|
|
3313
|
-
}
|
|
3314
|
-
function parsePositiveInteger(value) {
|
|
3315
|
-
const parsed = Number(value);
|
|
3316
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
3317
|
-
return null;
|
|
3318
|
-
}
|
|
3319
|
-
return Math.floor(parsed);
|
|
3320
|
-
}
|
|
3321
3270
|
function resolveCumulativeTurnCount(run, turnCount) {
|
|
3322
3271
|
const carriedTotal = resolvePersistedCumulativeTurnCount(run);
|
|
3323
3272
|
if (turnCount === null) {
|
package/dist/index.js
CHANGED
|
@@ -280,19 +280,19 @@ ${bashFunction}complete -F _gh_symphony_completion gh-symphony
|
|
|
280
280
|
var COMMANDS = {
|
|
281
281
|
workflow: () => import("./workflow-TBIFY5MO.js"),
|
|
282
282
|
init: () => import("./init-KZT6YNOH.js"),
|
|
283
|
-
setup: () => import("./setup-
|
|
283
|
+
setup: () => import("./setup-VWB7RZUQ.js"),
|
|
284
284
|
doctor: () => import("./doctor-IYHCFXOZ.js"),
|
|
285
|
-
upgrade: () => import("./upgrade-
|
|
286
|
-
start: () => import("./start-
|
|
285
|
+
upgrade: () => import("./upgrade-3YNF3VKY.js"),
|
|
286
|
+
start: () => import("./start-ENFLZUI6.js"),
|
|
287
287
|
stop: () => import("./stop-7MFCBQVW.js"),
|
|
288
288
|
status: () => import("./status-QSCFVGRQ.js"),
|
|
289
|
-
run: () => import("./run-
|
|
290
|
-
recover: () => import("./recover-
|
|
289
|
+
run: () => import("./run-ETC5UTRA.js"),
|
|
290
|
+
recover: () => import("./recover-5KQI7WH5.js"),
|
|
291
291
|
logs: () => import("./logs-6JKKYDGJ.js"),
|
|
292
|
-
project: () => import("./project-
|
|
292
|
+
project: () => import("./project-UUVHS3ZR.js"),
|
|
293
293
|
repo: () => import("./repo-HDDE7OUI.js"),
|
|
294
294
|
config: () => import("./config-cmd-DNXNL26Z.js"),
|
|
295
|
-
version: () => import("./version-
|
|
295
|
+
version: () => import("./version-NUBTTOG7.js")
|
|
296
296
|
};
|
|
297
297
|
function addGlobalOptions(command) {
|
|
298
298
|
return command.option("--config <dir>", "Config directory").addOption(new Option("--config-dir <dir>").hideHelp()).option("-v, --verbose", "Enable verbose output").option("--json", "Output in JSON format").option("--no-color", "Disable color output");
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
project_default,
|
|
4
4
|
promptProjectRegistrationOptions,
|
|
5
5
|
renderProjectRegistrationSummary
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-3AWF54PI.js";
|
|
7
7
|
import "./chunk-RN2PACNV.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-EKKT5USP.js";
|
|
9
|
+
import "./chunk-HZVDTAPS.js";
|
|
10
10
|
import "./chunk-M3IFVLQS.js";
|
|
11
11
|
import "./chunk-TILHWBP6.js";
|
|
12
12
|
import "./chunk-XN5ABWZ6.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
promptProjectRegistrationOptions,
|
|
4
4
|
renderProjectRegistrationSummary
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3AWF54PI.js";
|
|
6
6
|
import {
|
|
7
7
|
abortIfCancelled,
|
|
8
8
|
buildAutomaticStateMappings,
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
writeEcosystem,
|
|
17
17
|
writeWorkflowPlan
|
|
18
18
|
} from "./chunk-RN2PACNV.js";
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-EKKT5USP.js";
|
|
20
|
+
import "./chunk-HZVDTAPS.js";
|
|
21
21
|
import "./chunk-M3IFVLQS.js";
|
|
22
22
|
import {
|
|
23
23
|
GhAuthError,
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import {
|
|
3
3
|
shutdownForegroundOrchestrator,
|
|
4
4
|
start_default
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-EKKT5USP.js";
|
|
6
|
+
import "./chunk-HZVDTAPS.js";
|
|
7
7
|
import "./chunk-M3IFVLQS.js";
|
|
8
8
|
import "./chunk-TILHWBP6.js";
|
|
9
9
|
import "./chunk-MVRF7BES.js";
|
|
@@ -16,8 +16,8 @@ function execFileAsync(file, args, execFileImpl = execFileCallback) {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
function resolveCurrentCliVersion() {
|
|
19
|
-
if ("0.0.
|
|
20
|
-
return "0.0.
|
|
19
|
+
if ("0.0.20".length > 0) {
|
|
20
|
+
return "0.0.20";
|
|
21
21
|
}
|
|
22
22
|
const pkg = JSON.parse(
|
|
23
23
|
readFileSync(new URL("../../package.json", import.meta.url), "utf8")
|
package/dist/worker-entry.js
CHANGED
|
@@ -92,8 +92,7 @@ function buildCodexRuntimePlan(config) {
|
|
|
92
92
|
...gitCredentialHelper,
|
|
93
93
|
...tool.env
|
|
94
94
|
},
|
|
95
|
-
tools: [tool]
|
|
96
|
-
resumeThreadId: config.resumeThreadId?.trim() || null
|
|
95
|
+
tools: [tool]
|
|
97
96
|
};
|
|
98
97
|
}
|
|
99
98
|
function launchCodexAppServer(plan, spawnImpl = spawn) {
|
|
@@ -196,8 +195,7 @@ function resolveLocalRuntimeLaunchConfig(env = process.env) {
|
|
|
196
195
|
agentCredentialCachePath: env.AGENT_CREDENTIAL_CACHE_PATH,
|
|
197
196
|
githubProjectId: env.GITHUB_PROJECT_ID,
|
|
198
197
|
githubGraphqlApiUrl: env.GITHUB_GRAPHQL_API_URL,
|
|
199
|
-
agentCommand: env.SYMPHONY_AGENT_COMMAND
|
|
200
|
-
resumeThreadId: env.SYMPHONY_RESUME_THREAD_ID
|
|
198
|
+
agentCommand: env.SYMPHONY_AGENT_COMMAND
|
|
201
199
|
};
|
|
202
200
|
}
|
|
203
201
|
async function runLocalRuntimeLauncher(env = process.env) {
|
|
@@ -556,111 +554,20 @@ function resolveExitRunPhase(currentRunPhase, exit) {
|
|
|
556
554
|
return exit.code === 0 && !exit.signal ? "succeeded" : "failed";
|
|
557
555
|
}
|
|
558
556
|
|
|
559
|
-
// ../worker/dist/session-budget.js
|
|
560
|
-
function resolveSessionBudgetState(env) {
|
|
561
|
-
return {
|
|
562
|
-
cumulativeTurnCount: parseNonNegativeInteger(env.SYMPHONY_CUMULATIVE_TURN_COUNT),
|
|
563
|
-
tokenUsageBaseline: {
|
|
564
|
-
inputTokens: parseNonNegativeInteger(env.SYMPHONY_CUMULATIVE_INPUT_TOKENS),
|
|
565
|
-
outputTokens: parseNonNegativeInteger(env.SYMPHONY_CUMULATIVE_OUTPUT_TOKENS),
|
|
566
|
-
totalTokens: parseNonNegativeInteger(env.SYMPHONY_CUMULATIVE_TOTAL_TOKENS)
|
|
567
|
-
},
|
|
568
|
-
sessionStartedAt: normalizeTimestamp(env.SYMPHONY_SESSION_STARTED_AT),
|
|
569
|
-
globalMaxTurns: parsePositiveInteger(env.SYMPHONY_GLOBAL_MAX_TURNS),
|
|
570
|
-
maxTokens: parsePositiveInteger(env.SYMPHONY_MAX_TOKENS),
|
|
571
|
-
sessionTimeoutMs: parsePositiveInteger(env.SYMPHONY_SESSION_TIMEOUT_MS)
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
function resolveBudgetExceededReason(budget, currentSessionTurnCount, currentTokenUsage, now) {
|
|
575
|
-
const totalTurns = budget.cumulativeTurnCount + currentSessionTurnCount;
|
|
576
|
-
if (budget.globalMaxTurns !== null && totalTurns >= budget.globalMaxTurns) {
|
|
577
|
-
return "global-turns";
|
|
578
|
-
}
|
|
579
|
-
const totalTokens = budget.tokenUsageBaseline.totalTokens + currentTokenUsage.totalTokens;
|
|
580
|
-
if (budget.maxTokens !== null && totalTokens >= budget.maxTokens) {
|
|
581
|
-
return "tokens";
|
|
582
|
-
}
|
|
583
|
-
if (budget.sessionTimeoutMs !== null && budget.sessionStartedAt !== null && now.getTime() - new Date(budget.sessionStartedAt).getTime() >= budget.sessionTimeoutMs) {
|
|
584
|
-
return "session-timeout";
|
|
585
|
-
}
|
|
586
|
-
return null;
|
|
587
|
-
}
|
|
588
|
-
function parsePositiveInteger(value) {
|
|
589
|
-
if (!value) {
|
|
590
|
-
return null;
|
|
591
|
-
}
|
|
592
|
-
const parsed = Number(value);
|
|
593
|
-
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
594
|
-
return null;
|
|
595
|
-
}
|
|
596
|
-
return Math.floor(parsed);
|
|
597
|
-
}
|
|
598
|
-
function parseNonNegativeInteger(value) {
|
|
599
|
-
if (!value) {
|
|
600
|
-
return 0;
|
|
601
|
-
}
|
|
602
|
-
const parsed = Number(value);
|
|
603
|
-
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
604
|
-
return 0;
|
|
605
|
-
}
|
|
606
|
-
return Math.floor(parsed);
|
|
607
|
-
}
|
|
608
|
-
function normalizeTimestamp(value) {
|
|
609
|
-
if (!value) {
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
612
|
-
const parsed = Date.parse(value);
|
|
613
|
-
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
557
|
// ../worker/dist/thread-resume.js
|
|
617
558
|
var DEFAULT_CONTINUATION_GUIDANCE = "Continue working on the issue. Review your progress and complete any remaining tasks.";
|
|
618
|
-
function
|
|
559
|
+
function parseNonNegativeInteger(value) {
|
|
619
560
|
const parsed = typeof value === "number" ? value : Number.parseInt(value ?? "", 10);
|
|
620
561
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
621
562
|
return 0;
|
|
622
563
|
}
|
|
623
564
|
return Math.floor(parsed);
|
|
624
565
|
}
|
|
625
|
-
function resolveRemainingTurns(maxTurns, cumulativeTurnCount) {
|
|
626
|
-
return Math.max(0, parseNonNegativeInteger2(maxTurns) - parseNonNegativeInteger2(cumulativeTurnCount));
|
|
627
|
-
}
|
|
628
|
-
function buildInitialTurnInput({ renderedPrompt, mode, lastTurnSummary, cumulativeTurnCount = 0, continuationGuidance }) {
|
|
629
|
-
if (mode === "fresh") {
|
|
630
|
-
return renderedPrompt;
|
|
631
|
-
}
|
|
632
|
-
const renderedContinuationGuidance = buildContinuationTurnInput({
|
|
633
|
-
continuationGuidance,
|
|
634
|
-
lastTurnSummary,
|
|
635
|
-
cumulativeTurnCount
|
|
636
|
-
});
|
|
637
|
-
const normalizedSummary = normalizeContinuationVariable(lastTurnSummary) ?? "No previous turn summary was captured.";
|
|
638
|
-
const normalizedCumulativeTurnCount = Math.max(0, parseNonNegativeInteger2(cumulativeTurnCount));
|
|
639
|
-
if (mode === "resume") {
|
|
640
|
-
return [
|
|
641
|
-
"Resume work on this issue using the existing thread context.",
|
|
642
|
-
`Previous worker turns completed: ${normalizedCumulativeTurnCount}.`,
|
|
643
|
-
`Previous session summary: ${normalizedSummary}`,
|
|
644
|
-
renderedContinuationGuidance
|
|
645
|
-
].join("\n");
|
|
646
|
-
}
|
|
647
|
-
return [
|
|
648
|
-
"Resume work on this issue from a previous worker session.",
|
|
649
|
-
"",
|
|
650
|
-
"Original issue instructions:",
|
|
651
|
-
renderedPrompt,
|
|
652
|
-
"",
|
|
653
|
-
"Previous session summary:",
|
|
654
|
-
normalizedSummary,
|
|
655
|
-
"",
|
|
656
|
-
renderedContinuationGuidance
|
|
657
|
-
].join("\n");
|
|
658
|
-
}
|
|
659
566
|
function buildContinuationTurnInput({ continuationGuidance, lastTurnSummary, cumulativeTurnCount = 0 }) {
|
|
660
567
|
const template = continuationGuidance?.trim() || DEFAULT_CONTINUATION_GUIDANCE;
|
|
661
568
|
return renderContinuationGuidance(template, {
|
|
662
569
|
lastTurnSummary: normalizeContinuationVariable(lastTurnSummary) ?? "No previous turn summary was captured.",
|
|
663
|
-
cumulativeTurnCount: String(Math.max(0,
|
|
570
|
+
cumulativeTurnCount: String(Math.max(0, parseNonNegativeInteger(cumulativeTurnCount)))
|
|
664
571
|
});
|
|
665
572
|
}
|
|
666
573
|
function normalizeContinuationVariable(value) {
|
|
@@ -693,6 +600,29 @@ function renderContinuationGuidance(template, variables) {
|
|
|
693
600
|
return rendered;
|
|
694
601
|
}
|
|
695
602
|
|
|
603
|
+
// ../worker/dist/turn-limits.js
|
|
604
|
+
var DEFAULT_SESSION_MAX_TURNS = 20;
|
|
605
|
+
function resolveMaxTurns(value) {
|
|
606
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
607
|
+
if (!Number.isFinite(parsed)) {
|
|
608
|
+
return {
|
|
609
|
+
maxTurns: DEFAULT_SESSION_MAX_TURNS,
|
|
610
|
+
exhaustedBeforeStart: false
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
const normalized = Math.trunc(parsed);
|
|
614
|
+
if (normalized <= 0) {
|
|
615
|
+
return {
|
|
616
|
+
maxTurns: 0,
|
|
617
|
+
exhaustedBeforeStart: true
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
return {
|
|
621
|
+
maxTurns: normalized,
|
|
622
|
+
exhaustedBeforeStart: false
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
696
626
|
// ../worker/dist/token-usage.js
|
|
697
627
|
import { mkdir as mkdir2, writeFile as writeFile3 } from "fs/promises";
|
|
698
628
|
import { dirname as dirname2, join as join2 } from "path";
|
|
@@ -720,7 +650,6 @@ function resolveTokenUsageArtifactPath(env) {
|
|
|
720
650
|
|
|
721
651
|
// ../worker/dist/index.js
|
|
722
652
|
var launcherEnv = loadLauncherEnvironment(process.env);
|
|
723
|
-
var sessionBudgetState = resolveSessionBudgetState(launcherEnv);
|
|
724
653
|
var runtimeState = {
|
|
725
654
|
status: launcherEnv.SYMPHONY_RUN_ID ? "starting" : "idle",
|
|
726
655
|
executionPhase: null,
|
|
@@ -741,9 +670,9 @@ var runtimeState = {
|
|
|
741
670
|
lastError: null
|
|
742
671
|
} : null,
|
|
743
672
|
tokenUsage: {
|
|
744
|
-
inputTokens:
|
|
745
|
-
outputTokens:
|
|
746
|
-
totalTokens:
|
|
673
|
+
inputTokens: 0,
|
|
674
|
+
outputTokens: 0,
|
|
675
|
+
totalTokens: 0
|
|
747
676
|
},
|
|
748
677
|
lastEventAt: null,
|
|
749
678
|
rateLimits: null,
|
|
@@ -938,7 +867,7 @@ function resolveTurnTokenUsageDelta(baseline) {
|
|
|
938
867
|
};
|
|
939
868
|
}
|
|
940
869
|
function resolveSessionTokenUsageDelta() {
|
|
941
|
-
return
|
|
870
|
+
return cloneTokenUsageSnapshot();
|
|
942
871
|
}
|
|
943
872
|
async function persistSessionTokenUsageArtifact(env) {
|
|
944
873
|
await persistTokenUsageArtifact(env, resolveSessionTokenUsageDelta());
|
|
@@ -1071,17 +1000,13 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1071
1000
|
process.stderr.write("[worker] codex process has no stdio pipes; cannot run client protocol\n");
|
|
1072
1001
|
return;
|
|
1073
1002
|
}
|
|
1074
|
-
const maxTurns =
|
|
1075
|
-
const cumulativeTurnCount = parseNonNegativeInteger2(env.SYMPHONY_CUMULATIVE_TURN_COUNT);
|
|
1076
|
-
const remainingTurns = resolveRemainingTurns(maxTurns, cumulativeTurnCount);
|
|
1003
|
+
const { maxTurns, exhaustedBeforeStart } = resolveMaxTurns(env.SYMPHONY_MAX_TURNS);
|
|
1077
1004
|
const readTimeoutMs = Number(env.SYMPHONY_READ_TIMEOUT_MS) || 5e3;
|
|
1078
1005
|
const turnTimeoutMs = Number(env.SYMPHONY_TURN_TIMEOUT_MS) || 36e5;
|
|
1079
1006
|
const maxNonProductiveTurns = resolveMaxNonProductiveTurns(env);
|
|
1080
1007
|
const issueIdentifier = env.SYMPHONY_ISSUE_IDENTIFIER ?? "";
|
|
1081
|
-
const lastTurnSummary = env.SYMPHONY_LAST_TURN_SUMMARY ?? null;
|
|
1082
1008
|
const continuationGuidance = env.SYMPHONY_CONTINUATION_GUIDANCE ?? options.continuationGuidance;
|
|
1083
1009
|
const { approvalPolicy, threadSandbox, turnSandboxPolicy } = resolveCodexPolicySettings(env);
|
|
1084
|
-
const budgetState = resolveSessionBudgetState(env);
|
|
1085
1010
|
let previousTurnProgressSnapshot = {
|
|
1086
1011
|
...captureTurnWorkspaceSnapshot(plan.cwd),
|
|
1087
1012
|
lastError: runtimeState.run?.lastError ?? null
|
|
@@ -1101,16 +1026,8 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1101
1026
|
let userInputRequired = false;
|
|
1102
1027
|
let turnTerminalFailurePhase = null;
|
|
1103
1028
|
let activeTurnTelemetry = null;
|
|
1104
|
-
let budgetExceededReason = null;
|
|
1105
1029
|
let consecutiveNonProductiveTurns = 0;
|
|
1106
1030
|
let convergenceDetected = false;
|
|
1107
|
-
function checkSessionBudgets(currentSessionTurnCount) {
|
|
1108
|
-
return resolveBudgetExceededReason(budgetState, currentSessionTurnCount, {
|
|
1109
|
-
inputTokens: runtimeState.tokenUsage.inputTokens - budgetState.tokenUsageBaseline.inputTokens,
|
|
1110
|
-
outputTokens: runtimeState.tokenUsage.outputTokens - budgetState.tokenUsageBaseline.outputTokens,
|
|
1111
|
-
totalTokens: runtimeState.tokenUsage.totalTokens - budgetState.tokenUsageBaseline.totalTokens
|
|
1112
|
-
}, /* @__PURE__ */ new Date());
|
|
1113
|
-
}
|
|
1114
1031
|
function resolvePendingTurnCompletion() {
|
|
1115
1032
|
if (turnCompletedResolve) {
|
|
1116
1033
|
turnCompletedResolve();
|
|
@@ -1428,27 +1345,6 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1428
1345
|
env: t.env
|
|
1429
1346
|
};
|
|
1430
1347
|
}
|
|
1431
|
-
if (remainingTurns <= 0) {
|
|
1432
|
-
process.stderr.write(`[worker] max_turns already exhausted by previous sessions (${cumulativeTurnCount}/${maxTurns})
|
|
1433
|
-
`);
|
|
1434
|
-
runtimeState.status = "completed";
|
|
1435
|
-
runtimeState.runPhase = "succeeded";
|
|
1436
|
-
runtimeState.sessionInfo.exitClassification = classifySessionExit({
|
|
1437
|
-
runPhase: runtimeState.runPhase,
|
|
1438
|
-
userInputRequired: false,
|
|
1439
|
-
budgetExceeded: false,
|
|
1440
|
-
convergenceDetected: false,
|
|
1441
|
-
maxTurnsReached: true
|
|
1442
|
-
});
|
|
1443
|
-
stopOrchestratorHeartbeatTimer();
|
|
1444
|
-
emitOrchestratorHeartbeat();
|
|
1445
|
-
await persistSessionTokenUsageArtifact(env);
|
|
1446
|
-
await waitForPendingOrchestratorChannelFlush(resolveTerminalOrchestratorChannelFlushTimeoutMs());
|
|
1447
|
-
setTimeout(() => {
|
|
1448
|
-
process.exit(0);
|
|
1449
|
-
}, 1500);
|
|
1450
|
-
return;
|
|
1451
|
-
}
|
|
1452
1348
|
const baseThreadParams = {
|
|
1453
1349
|
cwd: plan.cwd,
|
|
1454
1350
|
developerInstructions: renderedPrompt,
|
|
@@ -1458,36 +1354,12 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1458
1354
|
mcp_servers: mcpServers
|
|
1459
1355
|
}
|
|
1460
1356
|
};
|
|
1461
|
-
const resumeThreadId = plan.resumeThreadId;
|
|
1462
|
-
let threadBootstrapMode = "fresh";
|
|
1463
1357
|
process.stderr.write(`[worker] starting codex thread (mcp_servers: ${Object.keys(mcpServers).join(", ")})
|
|
1464
1358
|
`);
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
try {
|
|
1470
|
-
threadResult = await sendRequestWithTimeout("thread-resume-1", "thread/resume", {
|
|
1471
|
-
...baseThreadParams,
|
|
1472
|
-
threadId: resumeThreadId
|
|
1473
|
-
});
|
|
1474
|
-
threadBootstrapMode = "resume";
|
|
1475
|
-
} catch (error) {
|
|
1476
|
-
const message = error instanceof Error ? error.message : String(error ?? "unknown");
|
|
1477
|
-
threadBootstrapMode = "soft-resume";
|
|
1478
|
-
process.stderr.write(`[worker] thread/resume failed for ${resumeThreadId}: ${message}; falling back to thread/start
|
|
1479
|
-
`);
|
|
1480
|
-
threadResult = await sendRequestWithTimeout("thread-1", "thread/start", {
|
|
1481
|
-
...baseThreadParams,
|
|
1482
|
-
ephemeral: false
|
|
1483
|
-
});
|
|
1484
|
-
}
|
|
1485
|
-
} else {
|
|
1486
|
-
threadResult = await sendRequestWithTimeout("thread-1", "thread/start", {
|
|
1487
|
-
...baseThreadParams,
|
|
1488
|
-
ephemeral: false
|
|
1489
|
-
});
|
|
1490
|
-
}
|
|
1359
|
+
const threadResult = await sendRequestWithTimeout("thread-1", "thread/start", {
|
|
1360
|
+
...baseThreadParams,
|
|
1361
|
+
ephemeral: false
|
|
1362
|
+
});
|
|
1491
1363
|
const threadId = threadResult.thread_id ?? threadResult.thread?.id;
|
|
1492
1364
|
runtimeState.sessionInfo.threadId = threadId ?? null;
|
|
1493
1365
|
runtimeState.sessionInfo.turnId = null;
|
|
@@ -1502,31 +1374,21 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1502
1374
|
}
|
|
1503
1375
|
let turnCount = 0;
|
|
1504
1376
|
let requestIdCounter = 0;
|
|
1505
|
-
let maxTurnsReached =
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
if (budgetExceededReason) {
|
|
1509
|
-
process.stderr.write(`[worker] session budget exceeded (${budgetExceededReason}) \u2014 exiting
|
|
1377
|
+
let maxTurnsReached = exhaustedBeforeStart;
|
|
1378
|
+
if (exhaustedBeforeStart) {
|
|
1379
|
+
process.stderr.write(`[worker] max_turns (${String(env.SYMPHONY_MAX_TURNS ?? maxTurns)}) does not allow any turns for this worker session \u2014 exiting
|
|
1510
1380
|
`);
|
|
1511
|
-
|
|
1512
|
-
|
|
1381
|
+
}
|
|
1382
|
+
for (let turn = 0; turn < maxTurns; turn++) {
|
|
1513
1383
|
turnCount = turn + 1;
|
|
1514
|
-
const globalTurnCount = cumulativeTurnCount + turnCount;
|
|
1515
1384
|
runtimeState.sessionInfo.turnCount = turnCount;
|
|
1516
1385
|
runtimeState.runPhase = "streaming_turn";
|
|
1517
1386
|
const isFirstTurn = turn === 0;
|
|
1518
|
-
const turnInput = isFirstTurn ?
|
|
1519
|
-
renderedPrompt,
|
|
1520
|
-
mode: threadBootstrapMode,
|
|
1521
|
-
lastTurnSummary,
|
|
1522
|
-
cumulativeTurnCount,
|
|
1523
|
-
continuationGuidance
|
|
1524
|
-
}) : buildContinuationTurnInput({
|
|
1387
|
+
const turnInput = isFirstTurn ? renderedPrompt : buildContinuationTurnInput({
|
|
1525
1388
|
continuationGuidance,
|
|
1526
|
-
|
|
1527
|
-
cumulativeTurnCount: globalTurnCount - 1
|
|
1389
|
+
cumulativeTurnCount: turn
|
|
1528
1390
|
});
|
|
1529
|
-
process.stderr.write(`[worker] starting codex turn ${
|
|
1391
|
+
process.stderr.write(`[worker] starting codex turn ${turnCount}/${maxTurns}${isFirstTurn ? " (initial)" : " (continuation)"}
|
|
1530
1392
|
`);
|
|
1531
1393
|
requestIdCounter += 1;
|
|
1532
1394
|
const turnRequestId = `turn-${requestIdCounter}`;
|
|
@@ -1566,15 +1428,9 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1566
1428
|
`);
|
|
1567
1429
|
break;
|
|
1568
1430
|
}
|
|
1569
|
-
|
|
1570
|
-
if (budgetExceededReason) {
|
|
1571
|
-
process.stderr.write(`[worker] session budget exceeded (${budgetExceededReason}) \u2014 exiting
|
|
1572
|
-
`);
|
|
1573
|
-
break;
|
|
1574
|
-
}
|
|
1575
|
-
if (turn + 1 >= remainingTurns) {
|
|
1431
|
+
if (turn + 1 >= maxTurns) {
|
|
1576
1432
|
maxTurnsReached = true;
|
|
1577
|
-
process.stderr.write(`[worker] max_turns (${maxTurns}) reached
|
|
1433
|
+
process.stderr.write(`[worker] max_turns (${maxTurns}) reached for this worker session \u2014 exiting
|
|
1578
1434
|
`);
|
|
1579
1435
|
break;
|
|
1580
1436
|
}
|
|
@@ -1622,7 +1478,7 @@ async function runCodexClientProtocol(child, plan, env, options) {
|
|
|
1622
1478
|
runtimeState.sessionInfo.exitClassification = classifySessionExit({
|
|
1623
1479
|
runPhase: runtimeState.runPhase,
|
|
1624
1480
|
userInputRequired,
|
|
1625
|
-
budgetExceeded:
|
|
1481
|
+
budgetExceeded: false,
|
|
1626
1482
|
convergenceDetected,
|
|
1627
1483
|
maxTurnsReached
|
|
1628
1484
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gh-symphony/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.20",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "hojinzs",
|
|
6
6
|
"description": "Interactive CLI for GitHub Symphony orchestration",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"@gh-symphony/core": "0.0.14",
|
|
45
45
|
"@gh-symphony/orchestrator": "0.0.14",
|
|
46
46
|
"@gh-symphony/dashboard": "0.0.14",
|
|
47
|
-
"@gh-symphony/
|
|
48
|
-
"@gh-symphony/
|
|
47
|
+
"@gh-symphony/tracker-github": "0.0.14",
|
|
48
|
+
"@gh-symphony/worker": "0.0.14"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "tsup",
|