flowviant 0.125.29 → 0.125.31
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 +364 -0
- package/bin/cli.mjs +23 -0
- package/bin/lib/agentPlan.mjs +8 -0
- package/bin/lib/agentQueueContext.mjs +6 -0
- package/bin/lib/agentSplit.mjs +90 -0
- package/bin/lib/architectureContract.mjs +57 -0
- package/bin/lib/architectureReport.mjs +38 -0
- package/bin/lib/artifactContracts.mjs +21 -2
- package/bin/lib/claudeInput.mjs +1 -1
- package/bin/lib/claudeSubagents.mjs +46 -6
- package/bin/lib/claudeWorkflows.mjs +94 -0
- package/bin/lib/cliLimit.mjs +5 -0
- package/bin/lib/codexInput.mjs +191 -0
- package/bin/lib/codexSubagentEvents.mjs +3 -1
- package/bin/lib/codexSubagents.mjs +34 -9
- package/bin/lib/conversationOutput.mjs +14 -0
- package/bin/lib/crossCliChild.mjs +327 -0
- package/bin/lib/crossCliLaunch.mjs +92 -0
- package/bin/lib/crossCliPosture.mjs +55 -0
- package/bin/lib/crossCliResearch.mjs +19 -0
- package/bin/lib/environmentProcess.mjs +44 -0
- package/bin/lib/fixtures/workflow-ultracode.jsonl +22 -0
- package/bin/lib/fleet.mjs +2 -0
- package/bin/lib/linuxDesktopBridge.mjs +62 -0
- package/bin/lib/managedBrowser.mjs +50 -10
- package/bin/lib/mergeBatch.mjs +1 -1
- package/bin/lib/nativeAgentTools.mjs +12 -5
- package/bin/lib/noWindowEnv.mjs +4 -2
- package/bin/lib/orchestrator.mjs +24 -7
- package/bin/lib/orchestratorClient.mjs +8 -2
- package/bin/lib/orchestratorPrompt.mjs +13 -5
- package/bin/lib/orchestratorProtocol.mjs +18 -0
- package/bin/lib/outsideCli.mjs +124 -0
- package/bin/lib/projectToolRuntimes.mjs +4 -2
- package/bin/lib/projectTools.mjs +2 -2
- package/bin/lib/prompts.mjs +7 -5
- package/bin/lib/repositoryPlaces.mjs +1 -1
- package/bin/lib/repositorySetup.mjs +15 -24
- package/bin/lib/reviewBridge.mjs +110 -0
- package/bin/lib/reviewDatabase.mjs +112 -0
- package/bin/lib/reviewDesktop.mjs +153 -0
- package/bin/lib/reviewEnvironment.mjs +286 -0
- package/bin/lib/reviewEnvironmentConfig.mjs +104 -0
- package/bin/lib/reviewEnvironmentMain.mjs +38 -0
- package/bin/lib/reviewImage.mjs +58 -0
- package/bin/lib/reviewMcpClient.mjs +69 -0
- package/bin/lib/reviewProcess.mjs +51 -0
- package/bin/lib/reviewTargets.mjs +50 -0
- package/bin/lib/robloxReview.mjs +234 -0
- package/bin/lib/robloxStudioBridge.mjs +68 -0
- package/bin/lib/runTurn.mjs +30 -8
- package/bin/lib/runtimeClaude.mjs +7 -3
- package/bin/lib/runtimeCodex.mjs +12 -6
- package/bin/lib/runtimeLimits.mjs +59 -1
- package/bin/lib/runtimeReview.mjs +185 -0
- package/bin/lib/splitGate.mjs +115 -0
- package/bin/lib/subagentBounds.mjs +26 -0
- package/bin/lib/subagentLedger.mjs +110 -0
- package/bin/lib/trace.mjs +134 -6
- package/bin/lib/turnDeclaration.mjs +4 -4
- package/bin/lib/turnGaps.mjs +6 -2
- package/bin/lib/turnSubagents.mjs +23 -9
- package/bin/lib/uiReview.mjs +5 -2
- package/bin/lib/wikiDraft.mjs +9 -0
- package/bin/lib/work.mjs +22 -1
- package/bin/lib/workAgentCheck.mjs +24 -1
- package/bin/lib/workAgentResume.mjs +11 -2
- package/bin/lib/workAgentTools.mjs +6 -4
- package/bin/lib/workAgentTurnExecution.mjs +77 -9
- package/bin/lib/workAgentTurnOutcome.mjs +11 -0
- package/bin/lib/workAgentTurnReports.mjs +5 -2
- package/package.json +1 -1
|
@@ -30,6 +30,7 @@ import { finishRepositoryDelivery, allResolutionsCommitted } from './repositoryD
|
|
|
30
30
|
*/
|
|
31
31
|
import { MODEL, PROJECT_ID } from './config.mjs';
|
|
32
32
|
import { setRuntimeLimit } from './daemonState.mjs';
|
|
33
|
+
import { limitResetAt } from './runtimeLimits.mjs';
|
|
33
34
|
import { gitOrNull } from './git.mjs';
|
|
34
35
|
import { assertWorktree } from './worktreeHealth.mjs';
|
|
35
36
|
import { placeTurnLockedByLivePid, recordTurnLock } from './turnLock.mjs';
|
|
@@ -48,6 +49,7 @@ import { scrub as envScrub } from './uplinkScrub.mjs';
|
|
|
48
49
|
import { canRun, runtimeById } from './runtimes.mjs';
|
|
49
50
|
import { toolEventOf, CLAUDE_TOOL_PROSE_KINDS, scrubNativeText } from './runtimeEvents.mjs';
|
|
50
51
|
import { makeTraceRelay } from './trace.mjs';
|
|
52
|
+
import { createOutsideRuns } from './outsideCli.mjs';
|
|
51
53
|
import { createWebsiteTrace } from './websiteTrace.mjs';
|
|
52
54
|
import { prepareCardTools } from './workAgentTools.mjs';
|
|
53
55
|
import { runTurnResumingOnce } from './resumeLost.mjs';
|
|
@@ -62,6 +64,7 @@ import { agentTurnResume } from './workAgentResume.mjs';
|
|
|
62
64
|
import { createDeliveryReporter } from './workDelivery.mjs';
|
|
63
65
|
import { createLiveMessages } from './workLiveMessages.mjs';
|
|
64
66
|
import { createOrchestrator } from './orchestrator.mjs';
|
|
67
|
+
import { crossCliFor } from './crossCliLaunch.mjs';
|
|
65
68
|
import { claudeOrchestrationSafe } from './orchestratorHooks.mjs';
|
|
66
69
|
import { ORCHESTRATED_POSTURES, orchestratesPosture } from './orchestratorPrompt.mjs';
|
|
67
70
|
import { knownCodexModels } from './runtimeOfferings.mjs';
|
|
@@ -73,6 +76,12 @@ import { createVideoRender } from './videoRender.mjs';
|
|
|
73
76
|
import { createManagedBrowser } from './managedBrowser.mjs';
|
|
74
77
|
import { completeBrowserReview, browserHandoffPrompt } from './browserHandoff.mjs';
|
|
75
78
|
import { withUiReview, appendUiReviewEvidence } from './uiReviewTurn.mjs';
|
|
79
|
+
import { setupRepository } from './repositorySetup.mjs';
|
|
80
|
+
import { readEnvironmentRecipe } from './reviewEnvironmentConfig.mjs';
|
|
81
|
+
import { environmentInstructions, environmentOverlay, holdWorktreeEnvironment } from './reviewEnvironment.mjs';
|
|
82
|
+
import { environmentCredentialNames } from './reviewDatabase.mjs';
|
|
83
|
+
import { createRuntimeReview } from './runtimeReview.mjs';
|
|
84
|
+
import { splitBrain, splitPolicy } from './splitGate.mjs';
|
|
76
85
|
|
|
77
86
|
export function createAgentTurnExecution({
|
|
78
87
|
admit,
|
|
@@ -105,6 +114,7 @@ export function createAgentTurnExecution({
|
|
|
105
114
|
makeUiReview = createUiReview,
|
|
106
115
|
makeVideoRender = createVideoRender,
|
|
107
116
|
makeManagedBrowser = createManagedBrowser,
|
|
117
|
+
makeRuntimeReview = createRuntimeReview,
|
|
108
118
|
}) {
|
|
109
119
|
const reportDelivery = createDeliveryReporter();
|
|
110
120
|
/** How long the final flush may hold the settle. Bounded because the settle
|
|
@@ -126,6 +136,7 @@ export function createAgentTurnExecution({
|
|
|
126
136
|
* `interruptAgentTurns`); absent, nothing can interrupt it. */
|
|
127
137
|
const runAgentTurnInPlace = async (job, { turnId, agentId, place, releaseSlot, postAgentTurn, measured, run = { interrupted: false } }) => {
|
|
128
138
|
let repositoryRun = null;
|
|
139
|
+
const environmentReleases = [];
|
|
129
140
|
const setupController = new AbortController();
|
|
130
141
|
run.abortSetup = () => setupController.abort();
|
|
131
142
|
if (run.interrupted) setupController.abort();
|
|
@@ -286,7 +297,7 @@ export function createAgentTurnExecution({
|
|
|
286
297
|
|
|
287
298
|
// Which conversation this turn resumes, and the kept Codex home it is
|
|
288
299
|
// filed under: the agent's resume across turns (workAgentResume.mjs).
|
|
289
|
-
const agentResume = agentTurnResume({ rt, wt, agentId, sessionMetaPath });
|
|
300
|
+
const agentResume = agentTurnResume({ rt, wt, agentId, sessionMetaPath, turnId });
|
|
290
301
|
|
|
291
302
|
/**
|
|
292
303
|
* THE TURN'S FILES, ON DISK BEFORE THE PROMPT NAMES THEM (0.112.0) — the
|
|
@@ -363,7 +374,12 @@ export function createAgentTurnExecution({
|
|
|
363
374
|
post: postAgentTrace,
|
|
364
375
|
orchestrationVersion: orchestrating ? 2 : undefined,
|
|
365
376
|
scrub: envScrub,
|
|
377
|
+
// Each child's CLI, and the turns a resumed one appeared in (S4.1).
|
|
378
|
+
cli: rt,
|
|
379
|
+
runsOf: agentResume.subagents.runsOf ?? undefined,
|
|
366
380
|
});
|
|
381
|
+
// The lead's shell-outs to another CLI, shown as Outside rows (outsideCli.mjs).
|
|
382
|
+
const outsideRuns = createOutsideRuns(trace);
|
|
367
383
|
// A live Send can choose its path as soon as the CLI starts, including a
|
|
368
384
|
// silent solo turn. Do not leave a two-second first-flush race at spawn.
|
|
369
385
|
if (orchestrating) await trace.flush(1_000);
|
|
@@ -398,6 +414,8 @@ export function createAgentTurnExecution({
|
|
|
398
414
|
// run's children and contract: Claude always names --model (the daemon's
|
|
399
415
|
// pin when the card has none); Codex's unpinned default is its own.
|
|
400
416
|
const cardBrain = { model: brain.model ?? (rt === 'claude' ? MODEL : null), effort: brain.effort ?? null };
|
|
417
|
+
// The person's split answer or Always switch, when the server asks (splitGate.mjs).
|
|
418
|
+
const split = splitPolicy(job);
|
|
401
419
|
|
|
402
420
|
let out = '';
|
|
403
421
|
let child = null;
|
|
@@ -417,6 +435,8 @@ export function createAgentTurnExecution({
|
|
|
417
435
|
let browserNote = '';
|
|
418
436
|
let uiReviewNote = '';
|
|
419
437
|
let uiReviewEvidence = '';
|
|
438
|
+
let environmentNote = '', reviewEnv = null;
|
|
439
|
+
let runtimeReview = null, runtimeNote = '', runtimeEvidence = '';
|
|
420
440
|
// A video card's render tool (videoRender.mjs), and the words a turn
|
|
421
441
|
// gets when it could not be held, so it stops rather than guesses.
|
|
422
442
|
let videoRender = null;
|
|
@@ -430,6 +450,8 @@ export function createAgentTurnExecution({
|
|
|
430
450
|
args = withUiReview(args, uiReviewNote, uiReview?.env);
|
|
431
451
|
args = withUiReview(args, videoNote);
|
|
432
452
|
args = withUiReview(args, browserNote, managedBrowser?.env);
|
|
453
|
+
args = withUiReview(args, environmentNote, reviewEnv);
|
|
454
|
+
args = withUiReview(args, runtimeNote, runtimeReview?.env);
|
|
433
455
|
args.managedBrowser = Boolean(managedBrowser);
|
|
434
456
|
return runTurnImpl(args);
|
|
435
457
|
};
|
|
@@ -480,6 +502,22 @@ export function createAgentTurnExecution({
|
|
|
480
502
|
let orchestrator = null;
|
|
481
503
|
let intermediateDelivery = null;
|
|
482
504
|
try {
|
|
505
|
+
if (posture === 'build') {
|
|
506
|
+
const sources = repositoryRun?.sources ?? [{ wt, repoRoot: worktreeRepo, baseRef: baseRef() }];
|
|
507
|
+
const administrativeNames = new Set();
|
|
508
|
+
for (const source of sources) {
|
|
509
|
+
const snapshot = readEnvironmentRecipe(source.repoRoot, source.baseRef);
|
|
510
|
+
if (!snapshot) continue;
|
|
511
|
+
const environment = await setupRepository(source.repoRoot, source.wt, { snapshot, signal: setupController.signal,
|
|
512
|
+
onSpawn: ch => { workChildren.set(ch, agentId); groupKillChildren?.add(ch); },
|
|
513
|
+
onClose: ch => { workChildren.delete(ch); groupKillChildren?.delete(ch); } });
|
|
514
|
+
environmentReleases.push(holdWorktreeEnvironment(environment));
|
|
515
|
+
environmentNote += '\n' + environmentInstructions(environment);
|
|
516
|
+
for (const name of environmentCredentialNames(snapshot.recipe)) administrativeNames.add(name);
|
|
517
|
+
if (source.wt === wt) reviewEnv = environmentOverlay(environment);
|
|
518
|
+
}
|
|
519
|
+
if (administrativeNames.size) reviewEnv = { ...reviewEnv, ...Object.fromEntries([...administrativeNames].map(name => [name, undefined])) };
|
|
520
|
+
}
|
|
483
521
|
if (posture === 'build' && job.kind !== 'merge_resolve' && ['claude', 'codex'].includes(rt)) {
|
|
484
522
|
try {
|
|
485
523
|
managedBrowser = await makeManagedBrowser({ wt, turnId, signal: setupController.signal, onChild: ch => {
|
|
@@ -490,6 +528,14 @@ export function createAgentTurnExecution({
|
|
|
490
528
|
} catch (error) { browserNote = `The managed browser could not start: ${envScrub(error.message)}. Report interactive browser checks unavailable.`; }
|
|
491
529
|
}
|
|
492
530
|
if (posture === 'build' && job.kind !== 'merge_resolve') {
|
|
531
|
+
try {
|
|
532
|
+
runtimeReview = await makeRuntimeReview({ wt, repoRoot: worktreeRepo, baseRef: baseRef(), sources: repositoryRun?.sources ?? [],
|
|
533
|
+
browser: managedBrowser, signal: setupController.signal, onChild: ch => {
|
|
534
|
+
workChildren.set(ch, agentId); groupKillChildren?.add(ch);
|
|
535
|
+
return () => { workChildren.delete(ch); groupKillChildren?.delete(ch); };
|
|
536
|
+
} });
|
|
537
|
+
runtimeNote = runtimeReview?.instructions ?? '';
|
|
538
|
+
} catch (error) { runtimeNote = `Configured runtime review is unavailable: ${envScrub(error.message)}. Use the repository’s existing checks and report unavailable runtime verification.`; }
|
|
493
539
|
try {
|
|
494
540
|
uiReview = await makeUiReview({ wt, signal: setupController.signal, onChild: ch => {
|
|
495
541
|
workChildren.set(ch, agentId); groupKillChildren?.add(ch);
|
|
@@ -510,12 +556,19 @@ export function createAgentTurnExecution({
|
|
|
510
556
|
assignmentContext: () => agentChildScope(job),
|
|
511
557
|
// Codex's spawn takes only a catalog model (knownCodexModels, the
|
|
512
558
|
// measured models_cache.json rows the roster already reports).
|
|
513
|
-
children: { access: ORCHESTRATED_POSTURES[posture], ...cardBrain, ...(rt === 'codex' ? { catalog: knownCodexModels() } : {}) },
|
|
559
|
+
children: { access: ORCHESTRATED_POSTURES[posture], ...cardBrain, ...splitBrain(split, rt, cardBrain).brain, split, ...(rt === 'codex' ? { catalog: knownCodexModels() } : {}) },
|
|
514
560
|
// Whether the words reached the CLI; Codex reads its inbox from hooks.
|
|
515
561
|
notify: message => liveInput ? run.live?.inject(message) === true : false,
|
|
516
|
-
taken: id => run.live?.onTaken(id)
|
|
562
|
+
taken: id => run.live?.onTaken(id),
|
|
563
|
+
// Subagents on another CLI (crossCliLaunch.mjs), counted as live children while they run.
|
|
564
|
+
crossCli: crossCliFor({ rt, posture, wt, worktreeRepo, ledger: agentResume.subagents, trace, scrub: envScrub, onChild: ch => {
|
|
565
|
+
workChildren.set(ch, agentId); groupKillChildren?.add(ch);
|
|
566
|
+
return () => { workChildren.delete(ch); groupKillChildren?.delete(ch); };
|
|
567
|
+
} }) });
|
|
517
568
|
}
|
|
518
|
-
const tools = prepareCardTools({ rt, posture, wt, repoRoot, baseRef, sources: repositoryRun?.sources ?? [], repositoryTool: repositoryRun?.tool ?? null, orchestratorConfig: orchestrator?.config ?? null, uiReviewConfig: uiReview?.config, videoConfig: videoRender?.config ?? null, browserConfig: managedBrowser?.config, orchestrated: Boolean(orchestrator), codexHome: agentResume.codexHome
|
|
569
|
+
const tools = prepareCardTools({ rt, posture, wt, repoRoot, baseRef, sources: repositoryRun?.sources ?? [], repositoryTool: repositoryRun?.tool ?? null, orchestratorConfig: orchestrator?.config ?? null, uiReviewConfig: uiReview?.config, videoConfig: videoRender?.config ?? null, browserConfig: managedBrowser?.config, orchestrated: Boolean(orchestrator), codexHome: agentResume.codexHome,
|
|
570
|
+
runtimeConfig: runtimeReview?.config,
|
|
571
|
+
...(reviewEnv ? { env: { ...process.env, ...reviewEnv } } : {}) });
|
|
519
572
|
projectTools = tools.projectTools;
|
|
520
573
|
localCleanup?.begin(turnId);
|
|
521
574
|
const { toolsNote } = tools;
|
|
@@ -542,7 +595,7 @@ export function createAgentTurnExecution({
|
|
|
542
595
|
intermediateFiles,
|
|
543
596
|
researchIdentity: { projectId: PROJECT_ID, agentId, turnId, taskId: job.task?.id ?? job.repositoryTaskId },
|
|
544
597
|
prompt: agentKickoff(job, { cardFiles: files.card, messageFiles: files.message, intermediateFiles }),
|
|
545
|
-
system: agentTurnSystem({ taskKind, taskType: job.task?.taskType, runtimeLabel: runtimeById(rt)?.label, prerequisitesAccepted: job.prerequisitesAccepted === true, knowledgeDir: knowledgeDirFor(repoRoot), artifactsAccepted: getArtifactsAccepted(), toolsNote, artifactInstructions, toolInstructions: projectTools.instructions, repositoryRun, orchestration: orchestrator ? { posture, runtime: rt, ...cardBrain } : null }),
|
|
598
|
+
system: agentTurnSystem({ taskKind, taskType: job.task?.taskType, runtimeLabel: runtimeById(rt)?.label, prerequisitesAccepted: job.prerequisitesAccepted === true, knowledgeDir: knowledgeDirFor(repoRoot), artifactsAccepted: getArtifactsAccepted(), toolsNote, artifactInstructions, toolInstructions: projectTools.instructions, repositoryRun, orchestration: orchestrator ? { posture, runtime: rt, ...cardBrain, split, crossCli: orchestrator.crossCli() } : null }),
|
|
546
599
|
agentTools: projectTools,
|
|
547
600
|
writableDirs: repositoryRun?.writableDirs,
|
|
548
601
|
...((tools.envNeeded || repositoryRun?.tool || orchestrator) ? { mcpEnv: { ...tools.env, ...(repositoryRun?.tool?.env ?? {}), ...(orchestrator?.env ?? {}) } } : {}),
|
|
@@ -560,7 +613,9 @@ export function createAgentTurnExecution({
|
|
|
560
613
|
// build for code, the fenced design/research postures otherwise.
|
|
561
614
|
profile: posture,
|
|
562
615
|
cardTurn: Boolean(orchestrator),
|
|
563
|
-
|
|
616
|
+
onWorkflow: row => trace.workflow(row),
|
|
617
|
+
onSubagent: (update) => update.kind === 'workflow' || !orchestrator ? trace.agent(update) : orchestrator.observe(update),
|
|
618
|
+
...(rt === 'codex' ? { knownSubagents: agentResume.subagents.codexTargets() } : {}),
|
|
564
619
|
onSpawnResult: result => orchestrator?.spawnResult(result),
|
|
565
620
|
cwd: wt,
|
|
566
621
|
runtime: rt,
|
|
@@ -668,6 +723,7 @@ export function createAgentTurnExecution({
|
|
|
668
723
|
}
|
|
669
724
|
return;
|
|
670
725
|
}
|
|
726
|
+
outsideRuns.observe(name, input, meta);
|
|
671
727
|
brief?.append(meta?.result ? 'tool result' : 'tool call', meta?.result
|
|
672
728
|
? { id: meta.id, exitCode: meta.exitCode, isError: meta.isError, output: meta.output }
|
|
673
729
|
: { name, input });
|
|
@@ -677,7 +733,7 @@ export function createAgentTurnExecution({
|
|
|
677
733
|
trace.tool(toolEventOf(name, input, wt, envScrub));
|
|
678
734
|
},
|
|
679
735
|
// The CLI's own per-turn token counts, off the `result` event. One
|
|
680
|
-
//
|
|
736
|
+
// cumulative report per CLI invocation. Internal-wait recovery combines those
|
|
681
737
|
// counts before this callback; project accounting still happens
|
|
682
738
|
// SERVER-side, behind the settle's idempotent win,
|
|
683
739
|
// because a retried settle must not charge the same turn twice.
|
|
@@ -794,12 +850,15 @@ export function createAgentTurnExecution({
|
|
|
794
850
|
// owned by its review tool, then bind evidence to the final source
|
|
795
851
|
// before the existing artifact upload and delivery settlement.
|
|
796
852
|
try { await videoRender?.close(); } catch { /* a closed listener */ }
|
|
853
|
+
try { await runtimeReview?.close(); } catch { /* turn teardown continues */ }
|
|
797
854
|
try { await managedBrowser?.close(); } catch { /* turn teardown continues */ }
|
|
798
855
|
try { await uiReview?.close(); }
|
|
799
856
|
finally {
|
|
800
857
|
try { uiReviewEvidence = uiReview?.finalize() ?? uiReviewEvidence; }
|
|
801
858
|
catch (error) { uiReviewEvidence = `Local UI review final source/evidence measurement unavailable: ${envScrub(error.message)}. Earlier checks do not establish the final source.`; }
|
|
802
859
|
}
|
|
860
|
+
try { runtimeEvidence = runtimeReview?.finalize() ?? ''; }
|
|
861
|
+
catch { runtimeEvidence = 'Runtime review final source could not be measured; earlier results do not verify final source.'; }
|
|
803
862
|
await run.live?.stop();
|
|
804
863
|
await orchestrator?.close(run.interrupted);
|
|
805
864
|
await brief?.stop();
|
|
@@ -910,6 +969,7 @@ export function createAgentTurnExecution({
|
|
|
910
969
|
modelExports: intermediateDelivery?.modelExports,
|
|
911
970
|
});
|
|
912
971
|
appendUiReviewEvidence(body, uiReviewEvidence);
|
|
972
|
+
appendUiReviewEvidence(body, runtimeEvidence);
|
|
913
973
|
// The agent's own account of what it did not deliver, for the pre-review.
|
|
914
974
|
if (job.kind === 'task' && job.task && body.outcome === 'delivered' && res?.gaps)
|
|
915
975
|
stashGaps(sessionMetaPath(wt, 'flowviant-agent-cards', agentId), job.task.id, res.gaps);
|
|
@@ -931,6 +991,9 @@ export function createAgentTurnExecution({
|
|
|
931
991
|
if (body.outcome === 'delivered' && job.task?.taskType === 'tests' && res?.testFindings) {
|
|
932
992
|
body.testFindings = measureTestFindings(res.testFindings, repositoryRun?.sourcesNow() ?? [{ wt, baseRef: baseRef(), id: job.repos?.length === 1 ? job.repos[0] : null }], envScrub);
|
|
933
993
|
}
|
|
994
|
+
// The split this turn ran under, when the person approved it or Always is
|
|
995
|
+
// on: the batch's CLI, model and effort, as the job carried them.
|
|
996
|
+
if (orchestrator && split && split.mode !== 'ask') body.subagents = split;
|
|
934
997
|
if (limit) {
|
|
935
998
|
setRuntimeLimit(PROJECT_ID, rt, limit);
|
|
936
999
|
// Every agent ON THIS CLI parks, because that account is shared: one
|
|
@@ -938,7 +1001,9 @@ export function createAgentTurnExecution({
|
|
|
938
1001
|
// a machine can hold a Claude login and a Codex login, and a Codex
|
|
939
1002
|
// limit is no reason to stop the Claude agents. The turn itself is
|
|
940
1003
|
// reported as `nothing` — it did not deliver and it did not ask.
|
|
941
|
-
|
|
1004
|
+
// With the CLI's measured reset, when it said one (runtimeLimits.mjs).
|
|
1005
|
+
const codexEnv = agentResume.codexHome ? { ...process.env, CODEX_HOME: agentResume.codexHome } : undefined;
|
|
1006
|
+
await postAgentParked(limit, rt, await limitResetAt(rt, { threadId: agentResume.threadNow(), env: codexEnv }));
|
|
942
1007
|
}
|
|
943
1008
|
if (job.kind === 'merge_resolve') {
|
|
944
1009
|
const resolution = () => repositoryRun
|
|
@@ -965,7 +1030,10 @@ export function createAgentTurnExecution({
|
|
|
965
1030
|
// hold the lock on — see `runReviewEntry`. Only after the settle that may
|
|
966
1031
|
// say delivered: the three `nothing` settles never opened it.
|
|
967
1032
|
if (final && reply?.review === true) await runReviewEntry(agentId, wt, job.agentName, undefined, job);
|
|
968
|
-
} finally {
|
|
1033
|
+
} finally {
|
|
1034
|
+
for (const release of environmentReleases) release();
|
|
1035
|
+
await repositoryRun?.tool?.close();
|
|
1036
|
+
}
|
|
969
1037
|
};
|
|
970
1038
|
|
|
971
1039
|
return { runAgentTurnInPlace };
|
|
@@ -35,6 +35,7 @@ import { withoutTurnDeclaration } from './turnDeclaration.mjs';
|
|
|
35
35
|
import { ANSWER_DELIVERED_USES, researchUseOf, withResearchHeader } from './researchUse.mjs';
|
|
36
36
|
import { measuredModelExports } from './intermediateArtifacts.mjs';
|
|
37
37
|
import { gapsMarkdown } from './turnGaps.mjs';
|
|
38
|
+
import { blockedAnswer } from './agentAsk.mjs';
|
|
38
39
|
|
|
39
40
|
/** Materialization runs only for a declared delivery; settlement remains the
|
|
40
41
|
* sole parser and the sole authority deciding whether it really delivered. */
|
|
@@ -130,6 +131,16 @@ export function agentTurnSettlement({ turnId, job, kind, out, lastAnswer, usage,
|
|
|
130
131
|
*/
|
|
131
132
|
// Existing document deliveries default to the Markdown proof. Only an
|
|
132
133
|
// explicit temporary-use declaration can deliver through the stored answer.
|
|
134
|
+
const required = res.gaps?.filter(g => g.disposition === 'required') ?? [];
|
|
135
|
+
if (res.outcome === 'delivered' && required.length && job.gapContinuationAccepted !== true) {
|
|
136
|
+
return report({ turnId, outcome: 'question',
|
|
137
|
+
answer: blockedAnswer('Required work remains. Should I finish it in this agent before delivery?', {
|
|
138
|
+
context: required.map(g => `${g.item}${g.why ? `: ${g.why}` : ''}`).join('\n\n'),
|
|
139
|
+
options: ['Finish the required work', 'Explain the remaining scope'],
|
|
140
|
+
}, envScrub),
|
|
141
|
+
...(commits.length ? { commits } : {}), ...(usage ? { usage } : {}),
|
|
142
|
+
...(res.progress ? { progress: envScrub(res.progress) } : {}), branch, worktree: wt });
|
|
143
|
+
}
|
|
133
144
|
const briefUse = researchUseOf(job.task?.brief);
|
|
134
145
|
const researchUse = kind.posture === 'research' ? briefUse ?? res.researchUse : null;
|
|
135
146
|
const temporaryResearch = ANSWER_DELIVERED_USES.includes(researchUse);
|
|
@@ -148,7 +148,7 @@ export function createAgentTurnReports({ REJECT_RETRY_MS, baseDir = null }) {
|
|
|
148
148
|
}
|
|
149
149
|
};
|
|
150
150
|
|
|
151
|
-
const postAgentParked = async (reason, runtime) => {
|
|
151
|
+
const postAgentParked = async (reason, runtime, resetsAt = null) => {
|
|
152
152
|
try {
|
|
153
153
|
await fetch(AGENT_PARKED_URL, {
|
|
154
154
|
method: 'POST',
|
|
@@ -156,7 +156,10 @@ export function createAgentTurnReports({ REJECT_RETRY_MS, baseDir = null }) {
|
|
|
156
156
|
signal: AbortSignal.timeout(15_000),
|
|
157
157
|
// `runtime` scopes the park to that CLI's agents; a server that does
|
|
158
158
|
// not know the key parks every agent, which is what it always did.
|
|
159
|
-
|
|
159
|
+
// `resetsAt` is the CLI's measured reset (`limitResetAt`), sent only
|
|
160
|
+
// when measured: the server retries then, and an older server ignores
|
|
161
|
+
// the key and keeps its cooldown. A report, so no floor.
|
|
162
|
+
body: JSON.stringify({ reason, ...(runtime ? { runtime } : {}), ...(resetsAt ? { resetsAt } : {}) }),
|
|
160
163
|
});
|
|
161
164
|
} catch {
|
|
162
165
|
/* the next turn will hit the same limit and try again */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flowviant",
|
|
3
|
-
"version": "0.125.
|
|
3
|
+
"version": "0.125.31",
|
|
4
4
|
"description": "Run your own coding CLIs as build agents for Flowviant \u2014 Claude Code, Codex or Antigravity, on your own credentials. Holds your sessions, keeps a worktree per tab, and ships branches on your word.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|