MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / run

Method run

src/agent/loop.ts:903–2203  ·  view source on GitHub ↗
(
    messages: Message[],
    sessionId: string,
    options: AgentOptions,
  )

Source from the content-addressed store, hash-verified

901
902 // Expose backtrack/checkpoint to tools via the wired sandbox handle.
903 this.activeSandbox = sandbox;
904 let reachedFinal = false;
905 const firstUserMsg = [...messages].reverse().find(m => m.role === 'user')?.content ?? 'task';
906 // Flywheel: collect the reasoning trace + final answer from the event stream
907 // (no edits to run() needed — we observe what it already emits).
908 const flywheelEnabled = (this.config as any).flywheel?.enabled === true;
909 const reasoning: string[] = [];
910 let finalContent = '';
911 try {
912 yield { type: 'notice', data: { message: `🔒 Sandbox: working on ${sandbox.branch} (isolated)` } };
913 for await (const ev of this.run(messages, sessionId, options)) {
914 if (ev.type === 'final') { reachedFinal = true; finalContent = (ev as any).data?.content ?? ''; }
915 if (flywheelEnabled && (ev.type as string) === 'thinking') {
916 const c = (ev as any).data?.content;
917 if (typeof c === 'string' && !c.startsWith('(format correction')) reasoning.push(c);
918 }
919 yield ev;
920 }
921 } catch (e: any) {
922 logger.warn('runSandboxed: inner run threw — abandoning sandbox', { err: e?.message });
923 throw e;
924 } finally {
925 this.activeSandbox = null;
926 const commitMsg = `qodex: ${String(firstUserMsg).slice(0, 72).replace(/\n/g, ' ')}`;
927 // Capture the changed-file list from git BEFORE finishing (the sandbox
928 // branch still has the diff). Best-effort.
929 let changedFiles: string[] = [];
930 if ((flywheelEnabled || process.env.QODEX_RECEIPT_FILE) && reachedFinal) {
931 try {
932 const { git } = await import('../tools/git/git-runner.js');
933 const diff = await git(['diff', '--name-only', sandbox.baseCommitRef() ?? 'HEAD'], { cwd: this.cwd, signal: options.signal });
934 if (diff.exitCode === 0) changedFiles = diff.stdout.split('\n').map(s => s.trim()).filter(Boolean);
935 } catch { /* ignore */ }
936 }
937 // Capture the branch name BEFORE finish() (it nulls internal state) so we
938 // can point the user at their work if the merge fails.
939 const sandboxBranch = sandbox.branch;
940 const finishResult = await sandbox.finish(reachedFinal, commitMsg, options.signal)
941 .catch((e: any) => ({ merged: false as const, reason: 'error' as const, error: e?.message ? String(e.message) : undefined }));
942 const merged = finishResult.merged;
943 if (reachedFinal && merged) {
944 yield { type: 'notice', data: { message: '🔒 Sandbox: changes squash-merged onto your branch ✓' } };
945 // ── Data flywheel: record this successful trajectory (opt-in) ──
946 if (flywheelEnabled) {
947 try {
948 const { recordTrajectory } = await import('./trajectory.js');
949 await recordTrajectory(this.cwd, {
950 prompt: String(firstUserMsg),
951 reasoning,
952 filesChanged: changedFiles,
953 finalSummary: finalContent.slice(0, 500),
954 messages: [
955 { role: 'user', content: String(firstUserMsg) },
956 { role: 'assistant', content: finalContent },
957 ],
958 });
959 } catch (e: any) {
960 logger.debug('Flywheel record skipped', { err: e?.message });

Callers 4

runHeadlessFunction · 0.95
runTurnMethod · 0.95
runSubagentMethod · 0.95
runSandboxedMethod · 0.95

Calls 15

setSessionForSnapshotMethod · 0.95
estimateTokensMethod · 0.95
runCompactionMethod · 0.95
classifyTaskMethod · 0.95
pruneMessagesMethod · 0.95
executeToolCallMethod · 0.95
recordToolFailureMethod · 0.95
expandToolPatternsFunction · 0.85
detectProjectSignalsFunction · 0.85
gatherInfraSignalsFunction · 0.85
deriveAutoDisabledToolsFunction · 0.85
ratchetAutoDisabledFunction · 0.85

Tested by

no test coverage detected