| 906 | } |
| 907 | |
| 908 | async function runWithParallelism(args: { |
| 909 | client: OpencodeClient; |
| 910 | config: RunnerConfig; |
| 911 | workItems: Array<{ question: LongMemEvalQuestion; datasetIndex: number }>; |
| 912 | state: RunnerStateFile; |
| 913 | resultsMap: Map<string, QuestionResultRecord>; |
| 914 | }): Promise<void> { |
| 915 | const { client, config, workItems, state, resultsMap } = args; |
| 916 | let nextIndex = 0; |
| 917 | const workerCount = Math.max(config.parallelism, 1); |
| 918 | let fatalError: Error | null = null; |
| 919 | |
| 920 | async function worker(workerIndex: number): Promise<void> { |
| 921 | while (nextIndex < workItems.length && fatalError === null) { |
| 922 | const current = workItems[nextIndex]; |
| 923 | nextIndex += 1; |
| 924 | if (!current) break; |
| 925 | logLine(`Worker ${workerIndex} processing ${current.question.question_id}`); |
| 926 | try { |
| 927 | await processQuestion({ |
| 928 | client, |
| 929 | config, |
| 930 | question: current.question, |
| 931 | datasetIndex: current.datasetIndex, |
| 932 | state, |
| 933 | resultsMap, |
| 934 | }); |
| 935 | } catch (error) { |
| 936 | fatalError = asError(error); |
| 937 | await appendLog( |
| 938 | config.paths.logFile, |
| 939 | `Worker ${workerIndex} stopping due to failure on ${current.question.question_id}: ${fatalError.message}`, |
| 940 | ); |
| 941 | break; |
| 942 | } |
| 943 | } |
| 944 | } |
| 945 | |
| 946 | await Promise.all(Array.from({ length: workerCount }, (_value, index) => worker(index + 1))); |
| 947 | if (fatalError) { |
| 948 | throw fatalError; |
| 949 | } |
| 950 | } |
| 951 | |
| 952 | async function ensureOutputArea(config: RunnerConfig): Promise<void> { |
| 953 | await mkdir(config.paths.outputDir, { recursive: true }); |