@mcoda/agents 0.1.35 → 0.1.36
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.
|
@@ -20,7 +20,7 @@ export class CodexAdapter {
|
|
|
20
20
|
async invoke(request) {
|
|
21
21
|
const health = cliHealthy(true);
|
|
22
22
|
const cliDetails = health.details;
|
|
23
|
-
const result = runCodexExec(request.input, this.config.model);
|
|
23
|
+
const result = await runCodexExec(request.input, this.config.model);
|
|
24
24
|
return {
|
|
25
25
|
output: result.output,
|
|
26
26
|
adapter: this.config.adapter ?? "codex-cli",
|
|
@@ -2,10 +2,10 @@ export declare const cliHealthy: (throwOnError?: boolean) => {
|
|
|
2
2
|
ok: boolean;
|
|
3
3
|
details?: Record<string, unknown>;
|
|
4
4
|
};
|
|
5
|
-
export declare const runCodexExec: (prompt: string, model?: string) => {
|
|
5
|
+
export declare const runCodexExec: (prompt: string, model?: string) => Promise<{
|
|
6
6
|
output: string;
|
|
7
7
|
raw: string;
|
|
8
|
-
}
|
|
8
|
+
}>;
|
|
9
9
|
export declare function runCodexExecStream(prompt: string, model?: string): AsyncGenerator<{
|
|
10
10
|
output: string;
|
|
11
11
|
raw: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodexCliRunner.d.ts","sourceRoot":"","sources":["../../../src/adapters/codex/CodexCliRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CodexCliRunner.d.ts","sourceRoot":"","sources":["../../../src/adapters/codex/CodexCliRunner.ts"],"names":[],"mappings":"AAuyBA,eAAO,MAAM,UAAU,GAAI,sBAAoB,KAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CA+BjG,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,QAAQ,MAAM,EAAE,QAAQ,MAAM,KAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAS1G,CAAC;AAEF,wBAAuB,kBAAkB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,cAAc,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAgEhE"}
|
|
@@ -7,6 +7,12 @@ const CODEX_STREAM_IO_ENV = "MCODA_STREAM_IO";
|
|
|
7
7
|
const CODEX_STREAM_IO_FORMAT_ENV = "MCODA_STREAM_IO_FORMAT";
|
|
8
8
|
const CODEX_STREAM_IO_COLOR_ENV = "MCODA_STREAM_IO_COLOR";
|
|
9
9
|
const CODEX_STREAM_IO_PREFIX = "codex-cli";
|
|
10
|
+
const CODEX_COMMAND_ENV = "MCODA_CODEX_COMMAND";
|
|
11
|
+
const CODEX_COMMAND_ARGS_ENV = "MCODA_CODEX_COMMAND_ARGS";
|
|
12
|
+
const CODEX_TIMEOUT_ENV = "MCODA_CODEX_TIMEOUT_MS";
|
|
13
|
+
const CODEX_EXIT_GRACE_ENV = "MCODA_CODEX_EXIT_GRACE_MS";
|
|
14
|
+
const CODEX_DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
|
|
15
|
+
const CODEX_DEFAULT_EXIT_GRACE_MS = 5000;
|
|
10
16
|
const ANSI = {
|
|
11
17
|
reset: "\u001b[0m",
|
|
12
18
|
bold: "\u001b[1m",
|
|
@@ -114,6 +120,94 @@ const extractItemText = (item) => {
|
|
|
114
120
|
}
|
|
115
121
|
return "";
|
|
116
122
|
};
|
|
123
|
+
const parseCommandArgs = (raw) => {
|
|
124
|
+
const trimmed = raw?.trim();
|
|
125
|
+
if (!trimmed)
|
|
126
|
+
return [];
|
|
127
|
+
if (trimmed.startsWith("[")) {
|
|
128
|
+
try {
|
|
129
|
+
const parsed = JSON.parse(trimmed);
|
|
130
|
+
if (Array.isArray(parsed)) {
|
|
131
|
+
return parsed
|
|
132
|
+
.map((entry) => (typeof entry === "string" ? entry.trim() : ""))
|
|
133
|
+
.filter(Boolean);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// fall through to whitespace parsing
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return trimmed.split(/\s+/).filter(Boolean);
|
|
141
|
+
};
|
|
142
|
+
const resolveCodexCommand = () => {
|
|
143
|
+
const command = process.env[CODEX_COMMAND_ENV]?.trim() || "codex";
|
|
144
|
+
const preArgs = parseCommandArgs(process.env[CODEX_COMMAND_ARGS_ENV]);
|
|
145
|
+
return { command, preArgs };
|
|
146
|
+
};
|
|
147
|
+
const parsePositiveIntEnv = (name, fallback) => {
|
|
148
|
+
const raw = process.env[name]?.trim();
|
|
149
|
+
if (!raw)
|
|
150
|
+
return fallback;
|
|
151
|
+
const parsed = Number(raw);
|
|
152
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.floor(parsed) : fallback;
|
|
153
|
+
};
|
|
154
|
+
const resolveCodexTimeoutMs = () => parsePositiveIntEnv(CODEX_TIMEOUT_ENV, CODEX_DEFAULT_TIMEOUT_MS);
|
|
155
|
+
const resolveCodexExitGraceMs = () => parsePositiveIntEnv(CODEX_EXIT_GRACE_ENV, CODEX_DEFAULT_EXIT_GRACE_MS);
|
|
156
|
+
const isIgnorableStdinError = (error) => error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED";
|
|
157
|
+
const safeKill = (child, signal) => {
|
|
158
|
+
try {
|
|
159
|
+
if (!child.killed) {
|
|
160
|
+
child.kill(signal);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
/* ignore kill errors */
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const scheduleHardKill = (child, delayMs = 250) => {
|
|
168
|
+
const timer = setTimeout(() => {
|
|
169
|
+
safeKill(child, "SIGKILL");
|
|
170
|
+
}, delayMs);
|
|
171
|
+
timer.unref();
|
|
172
|
+
};
|
|
173
|
+
const extractProtocolError = (parsed) => {
|
|
174
|
+
if (!parsed || typeof parsed !== "object")
|
|
175
|
+
return undefined;
|
|
176
|
+
const type = typeof parsed.type === "string" ? parsed.type : "";
|
|
177
|
+
if (type === "turn.failed") {
|
|
178
|
+
const message = parsed?.error?.message ?? parsed?.error;
|
|
179
|
+
return message ? String(message) : "codex turn failed";
|
|
180
|
+
}
|
|
181
|
+
if (type === "error" && parsed?.message) {
|
|
182
|
+
return String(parsed.message);
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
185
|
+
};
|
|
186
|
+
const isCompletionEvent = (parsed) => {
|
|
187
|
+
if (!parsed || typeof parsed !== "object")
|
|
188
|
+
return false;
|
|
189
|
+
const type = typeof parsed.type === "string" ? parsed.type : "";
|
|
190
|
+
return type === "turn.completed" || type === "response.completed";
|
|
191
|
+
};
|
|
192
|
+
const parseCodexOutput = (raw) => {
|
|
193
|
+
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
194
|
+
let message = "";
|
|
195
|
+
for (const line of lines) {
|
|
196
|
+
const parsed = safeJsonParse(line);
|
|
197
|
+
const event = extractAssistantText(parsed);
|
|
198
|
+
if (!event)
|
|
199
|
+
continue;
|
|
200
|
+
if (event.kind === "delta") {
|
|
201
|
+
message += event.text;
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
message = event.text;
|
|
205
|
+
}
|
|
206
|
+
if (!message) {
|
|
207
|
+
return lines[lines.length - 1] ?? "";
|
|
208
|
+
}
|
|
209
|
+
return message;
|
|
210
|
+
};
|
|
117
211
|
const normalizeValue = (value) => {
|
|
118
212
|
if (typeof value !== "string")
|
|
119
213
|
return value;
|
|
@@ -541,6 +635,155 @@ const extractAssistantText = (parsed) => {
|
|
|
541
635
|
}
|
|
542
636
|
return null;
|
|
543
637
|
};
|
|
638
|
+
const invokeCodexProcess = async (prompt, model, hooks) => {
|
|
639
|
+
const resolvedModel = model ?? "gpt-5.1-codex-max";
|
|
640
|
+
const sandboxArgs = resolveSandboxArgs();
|
|
641
|
+
const reasoningEffort = resolveReasoningEffort(resolvedModel);
|
|
642
|
+
const codexCommand = resolveCodexCommand();
|
|
643
|
+
const args = [...codexCommand.preArgs, ...sandboxArgs.args, "exec", "--model", resolvedModel, "--json"];
|
|
644
|
+
if (!sandboxArgs.bypass) {
|
|
645
|
+
args.push("--full-auto");
|
|
646
|
+
}
|
|
647
|
+
if (reasoningEffort) {
|
|
648
|
+
args.push("-c", `model_reasoning_effort=${reasoningEffort}`);
|
|
649
|
+
}
|
|
650
|
+
args.push("-");
|
|
651
|
+
const timeoutMs = resolveCodexTimeoutMs();
|
|
652
|
+
const exitGraceMs = resolveCodexExitGraceMs();
|
|
653
|
+
return await new Promise((resolve, reject) => {
|
|
654
|
+
const child = spawn(codexCommand.command, args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
655
|
+
let raw = "";
|
|
656
|
+
let stderr = "";
|
|
657
|
+
let lineBuffer = "";
|
|
658
|
+
let message = "";
|
|
659
|
+
let protocolError;
|
|
660
|
+
let settled = false;
|
|
661
|
+
let forcedExit = false;
|
|
662
|
+
let completionTimer;
|
|
663
|
+
const clearTimers = () => {
|
|
664
|
+
if (completionTimer) {
|
|
665
|
+
clearTimeout(completionTimer);
|
|
666
|
+
completionTimer = undefined;
|
|
667
|
+
}
|
|
668
|
+
clearTimeout(timeoutHandle);
|
|
669
|
+
};
|
|
670
|
+
const finalizeOutput = () => {
|
|
671
|
+
const parsedOutput = parseCodexOutput(raw).trim();
|
|
672
|
+
return parsedOutput || message.trim();
|
|
673
|
+
};
|
|
674
|
+
const finishResolve = () => {
|
|
675
|
+
if (settled)
|
|
676
|
+
return;
|
|
677
|
+
settled = true;
|
|
678
|
+
clearTimers();
|
|
679
|
+
resolve({ output: finalizeOutput(), raw, forcedExit });
|
|
680
|
+
};
|
|
681
|
+
const finishReject = (error) => {
|
|
682
|
+
if (settled)
|
|
683
|
+
return;
|
|
684
|
+
settled = true;
|
|
685
|
+
clearTimers();
|
|
686
|
+
reject(error);
|
|
687
|
+
};
|
|
688
|
+
const scheduleCompletionGrace = () => {
|
|
689
|
+
if (settled)
|
|
690
|
+
return;
|
|
691
|
+
if (completionTimer) {
|
|
692
|
+
clearTimeout(completionTimer);
|
|
693
|
+
}
|
|
694
|
+
completionTimer = setTimeout(() => {
|
|
695
|
+
if (settled)
|
|
696
|
+
return;
|
|
697
|
+
forcedExit = true;
|
|
698
|
+
safeKill(child, "SIGTERM");
|
|
699
|
+
scheduleHardKill(child);
|
|
700
|
+
finishResolve();
|
|
701
|
+
}, exitGraceMs);
|
|
702
|
+
completionTimer.unref();
|
|
703
|
+
};
|
|
704
|
+
const handleLine = (line) => {
|
|
705
|
+
const normalized = line.replace(/\r$/, "");
|
|
706
|
+
hooks?.onLine?.(normalized);
|
|
707
|
+
const parsed = safeJsonParse(normalized);
|
|
708
|
+
const event = extractAssistantText(parsed);
|
|
709
|
+
if (event) {
|
|
710
|
+
if (event.kind === "delta") {
|
|
711
|
+
message += event.text;
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
message = event.text;
|
|
715
|
+
scheduleCompletionGrace();
|
|
716
|
+
}
|
|
717
|
+
hooks?.onAssistantEvent?.(event, normalized);
|
|
718
|
+
}
|
|
719
|
+
const parsedError = extractProtocolError(parsed);
|
|
720
|
+
if (parsedError) {
|
|
721
|
+
protocolError = parsedError;
|
|
722
|
+
}
|
|
723
|
+
if (isCompletionEvent(parsed)) {
|
|
724
|
+
scheduleCompletionGrace();
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
const timeoutHandle = setTimeout(() => {
|
|
728
|
+
if (settled)
|
|
729
|
+
return;
|
|
730
|
+
forcedExit = true;
|
|
731
|
+
safeKill(child, "SIGTERM");
|
|
732
|
+
scheduleHardKill(child);
|
|
733
|
+
const detail = stderr.trim().length > 0 ? `: ${stderr.trim()}` : "";
|
|
734
|
+
finishReject(new Error(`AUTH_ERROR: codex CLI timed out after ${timeoutMs}ms${detail}`));
|
|
735
|
+
}, timeoutMs);
|
|
736
|
+
timeoutHandle.unref();
|
|
737
|
+
child.stdout?.setEncoding("utf8");
|
|
738
|
+
child.stdout?.on("data", (chunk) => {
|
|
739
|
+
const text = chunk.toString();
|
|
740
|
+
raw += text;
|
|
741
|
+
lineBuffer += text;
|
|
742
|
+
let idx;
|
|
743
|
+
while ((idx = lineBuffer.indexOf("\n")) !== -1) {
|
|
744
|
+
const line = lineBuffer.slice(0, idx);
|
|
745
|
+
lineBuffer = lineBuffer.slice(idx + 1);
|
|
746
|
+
handleLine(line);
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
child.stderr?.setEncoding("utf8");
|
|
750
|
+
child.stderr?.on("data", (chunk) => {
|
|
751
|
+
stderr += chunk.toString();
|
|
752
|
+
});
|
|
753
|
+
child.stdin?.on("error", (error) => {
|
|
754
|
+
if (settled || isIgnorableStdinError(error))
|
|
755
|
+
return;
|
|
756
|
+
finishReject(new Error(`AUTH_ERROR: codex CLI stdin failed (${error.message})`));
|
|
757
|
+
});
|
|
758
|
+
child.on("error", (error) => {
|
|
759
|
+
finishReject(new Error(`AUTH_ERROR: codex CLI failed (${error.message})`));
|
|
760
|
+
});
|
|
761
|
+
child.on("close", (code) => {
|
|
762
|
+
if (lineBuffer.trim()) {
|
|
763
|
+
handleLine(lineBuffer);
|
|
764
|
+
lineBuffer = "";
|
|
765
|
+
}
|
|
766
|
+
if (settled)
|
|
767
|
+
return;
|
|
768
|
+
if ((code ?? 0) !== 0) {
|
|
769
|
+
finishReject(new Error(`AUTH_ERROR: codex CLI failed (exit ${code ?? 0}): ${stderr || protocolError || "no output"}`));
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (protocolError && !finalizeOutput()) {
|
|
773
|
+
finishReject(new Error(`AUTH_ERROR: codex CLI failed (${protocolError})`));
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
finishResolve();
|
|
777
|
+
});
|
|
778
|
+
try {
|
|
779
|
+
child.stdin?.write(prompt);
|
|
780
|
+
child.stdin?.end();
|
|
781
|
+
}
|
|
782
|
+
catch (error) {
|
|
783
|
+
finishReject(new Error(`AUTH_ERROR: codex CLI stdin failed (${error.message})`));
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
};
|
|
544
787
|
export const cliHealthy = (throwOnError = false) => {
|
|
545
788
|
if (process.env.MCODA_CLI_STUB === "1") {
|
|
546
789
|
return { ok: true, details: { stub: true } };
|
|
@@ -548,7 +791,11 @@ export const cliHealthy = (throwOnError = false) => {
|
|
|
548
791
|
if (process.env.MCODA_SKIP_CLI_CHECKS === "1") {
|
|
549
792
|
return { ok: true, details: { skipped: true } };
|
|
550
793
|
}
|
|
551
|
-
const
|
|
794
|
+
const codexCommand = resolveCodexCommand();
|
|
795
|
+
const result = spawnSync(codexCommand.command, [...codexCommand.preArgs, "--version"], {
|
|
796
|
+
encoding: "utf8",
|
|
797
|
+
maxBuffer: CODEX_MAX_BUFFER_BYTES,
|
|
798
|
+
});
|
|
552
799
|
if (result.error) {
|
|
553
800
|
const details = { reason: "missing_cli", error: result.error.message };
|
|
554
801
|
if (throwOnError) {
|
|
@@ -569,62 +816,15 @@ export const cliHealthy = (throwOnError = false) => {
|
|
|
569
816
|
}
|
|
570
817
|
return { ok: true, details: { version: result.stdout?.toString().trim() } };
|
|
571
818
|
};
|
|
572
|
-
export const runCodexExec = (prompt, model) => {
|
|
819
|
+
export const runCodexExec = async (prompt, model) => {
|
|
573
820
|
if (process.env.MCODA_CLI_STUB === "1") {
|
|
574
821
|
const output = `qa-stub:${prompt}`;
|
|
575
822
|
const raw = JSON.stringify({ type: "item.completed", item: { type: "agent_message", text: output } });
|
|
576
823
|
return { output, raw };
|
|
577
824
|
}
|
|
578
|
-
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
const args = [...sandboxArgs.args, "exec", "--model", resolvedModel, "--json"];
|
|
582
|
-
if (!sandboxArgs.bypass) {
|
|
583
|
-
args.push("--full-auto");
|
|
584
|
-
}
|
|
585
|
-
const reasoningEffort = resolveReasoningEffort(resolvedModel);
|
|
586
|
-
if (reasoningEffort) {
|
|
587
|
-
args.push("-c", `model_reasoning_effort=${reasoningEffort}`);
|
|
588
|
-
}
|
|
589
|
-
args.push("-");
|
|
590
|
-
const result = spawnSync("codex", args, {
|
|
591
|
-
input: prompt,
|
|
592
|
-
encoding: "utf8",
|
|
593
|
-
maxBuffer: CODEX_MAX_BUFFER_BYTES,
|
|
594
|
-
});
|
|
595
|
-
if (result.error) {
|
|
596
|
-
const error = new Error(`AUTH_ERROR: codex CLI failed (${result.error.message})`);
|
|
597
|
-
error.details = { reason: "cli_error", cli: health.details };
|
|
598
|
-
throw error;
|
|
599
|
-
}
|
|
600
|
-
if (result.status !== 0) {
|
|
601
|
-
const error = new Error(`AUTH_ERROR: codex CLI failed (exit ${result.status}): ${result.stderr ?? result.stdout ?? ""}`);
|
|
602
|
-
error.details = { reason: "cli_error", exitCode: result.status, stderr: result.stderr };
|
|
603
|
-
throw error;
|
|
604
|
-
}
|
|
605
|
-
const raw = result.stdout?.toString() ?? "";
|
|
606
|
-
const lines = raw.split(/\r?\n/).filter((l) => l.trim().length > 0);
|
|
607
|
-
let message = "";
|
|
608
|
-
for (const line of lines) {
|
|
609
|
-
try {
|
|
610
|
-
const parsed = JSON.parse(line);
|
|
611
|
-
const event = extractAssistantText(parsed);
|
|
612
|
-
if (!event)
|
|
613
|
-
continue;
|
|
614
|
-
if (event.kind === "delta") {
|
|
615
|
-
message += event.text;
|
|
616
|
-
continue;
|
|
617
|
-
}
|
|
618
|
-
message = event.text;
|
|
619
|
-
}
|
|
620
|
-
catch {
|
|
621
|
-
/* ignore parse errors */
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
if (!message) {
|
|
625
|
-
message = lines[lines.length - 1] ?? "";
|
|
626
|
-
}
|
|
627
|
-
return { output: message.trim(), raw };
|
|
825
|
+
cliHealthy(true);
|
|
826
|
+
const result = await invokeCodexProcess(prompt, model);
|
|
827
|
+
return { output: result.output, raw: result.raw };
|
|
628
828
|
};
|
|
629
829
|
export async function* runCodexExecStream(prompt, model) {
|
|
630
830
|
if (process.env.MCODA_CLI_STUB === "1") {
|
|
@@ -635,103 +835,55 @@ export async function* runCodexExecStream(prompt, model) {
|
|
|
635
835
|
}
|
|
636
836
|
cliHealthy(true);
|
|
637
837
|
const resolvedModel = model ?? "gpt-5.1-codex-max";
|
|
638
|
-
const sandboxArgs = resolveSandboxArgs();
|
|
639
|
-
const args = [...sandboxArgs.args, "exec", "--model", resolvedModel, "--json"];
|
|
640
|
-
if (!sandboxArgs.bypass) {
|
|
641
|
-
args.push("--full-auto");
|
|
642
|
-
}
|
|
643
|
-
const reasoningEffort = resolveReasoningEffort(resolvedModel);
|
|
644
|
-
if (reasoningEffort) {
|
|
645
|
-
args.push("-c", `model_reasoning_effort=${reasoningEffort}`);
|
|
646
|
-
}
|
|
647
|
-
args.push("-");
|
|
648
|
-
const child = spawn("codex", args, { stdio: ["pipe", "pipe", "pipe"] });
|
|
649
|
-
child.stdin.write(prompt);
|
|
650
|
-
child.stdin.end();
|
|
651
|
-
let stderr = "";
|
|
652
|
-
child.stderr?.setEncoding("utf8");
|
|
653
|
-
child.stderr?.on("data", (chunk) => {
|
|
654
|
-
stderr += chunk.toString();
|
|
655
|
-
});
|
|
656
|
-
const closePromise = new Promise((resolve, reject) => {
|
|
657
|
-
child.on("error", (err) => reject(err));
|
|
658
|
-
child.on("close", (code) => resolve(code ?? 0));
|
|
659
|
-
});
|
|
660
|
-
const parseLine = (line) => {
|
|
661
|
-
try {
|
|
662
|
-
const parsed = JSON.parse(line);
|
|
663
|
-
return extractAssistantText(parsed);
|
|
664
|
-
}
|
|
665
|
-
catch {
|
|
666
|
-
return null;
|
|
667
|
-
}
|
|
668
|
-
};
|
|
669
|
-
const stream = child.stdout;
|
|
670
|
-
stream?.setEncoding("utf8");
|
|
671
838
|
const formatter = createStreamFormatter(resolvedModel);
|
|
672
|
-
|
|
839
|
+
const queue = [];
|
|
840
|
+
const waiters = [];
|
|
841
|
+
let done = false;
|
|
842
|
+
let failure;
|
|
673
843
|
let sawDelta = false;
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
buffer += chunk;
|
|
678
|
-
let idx;
|
|
679
|
-
while ((idx = buffer.indexOf("\n")) !== -1) {
|
|
680
|
-
const line = buffer.slice(0, idx);
|
|
681
|
-
buffer = buffer.slice(idx + 1);
|
|
682
|
-
const normalized = line.replace(/\r$/, "");
|
|
683
|
-
formatter.handleLine(normalized);
|
|
684
|
-
const parsed = parseLine(normalized);
|
|
685
|
-
if (!parsed)
|
|
686
|
-
continue;
|
|
687
|
-
if (parsed.kind === "delta") {
|
|
688
|
-
sawDelta = true;
|
|
689
|
-
yield { output: parsed.text, raw: normalized };
|
|
690
|
-
continue;
|
|
691
|
-
}
|
|
692
|
-
if (!sawDelta) {
|
|
693
|
-
const output = parsed.text.endsWith("\n") ? parsed.text : `${parsed.text}\n`;
|
|
694
|
-
yield { output, raw: normalized };
|
|
695
|
-
}
|
|
696
|
-
sawDelta = false;
|
|
697
|
-
}
|
|
844
|
+
const notify = () => {
|
|
845
|
+
while (waiters.length) {
|
|
846
|
+
waiters.shift()?.();
|
|
698
847
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
yield { output, raw: trailing };
|
|
711
|
-
sawDelta = false;
|
|
712
|
-
}
|
|
848
|
+
};
|
|
849
|
+
void invokeCodexProcess(prompt, model, {
|
|
850
|
+
onLine: (line) => {
|
|
851
|
+
formatter.handleLine(line);
|
|
852
|
+
},
|
|
853
|
+
onAssistantEvent: (event, rawLine) => {
|
|
854
|
+
if (event.kind === "delta") {
|
|
855
|
+
sawDelta = true;
|
|
856
|
+
queue.push({ output: event.text, raw: rawLine });
|
|
857
|
+
notify();
|
|
858
|
+
return;
|
|
713
859
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
}));
|
|
725
|
-
|
|
726
|
-
|
|
860
|
+
if (!sawDelta) {
|
|
861
|
+
const output = event.text.endsWith("\n") ? event.text : `${event.text}\n`;
|
|
862
|
+
queue.push({ output, raw: rawLine });
|
|
863
|
+
notify();
|
|
864
|
+
}
|
|
865
|
+
sawDelta = false;
|
|
866
|
+
},
|
|
867
|
+
})
|
|
868
|
+
.catch((error) => {
|
|
869
|
+
failure = error;
|
|
870
|
+
formatter.handleLine(JSON.stringify({ type: "error", message: failure.message }));
|
|
871
|
+
})
|
|
872
|
+
.finally(() => {
|
|
873
|
+
done = true;
|
|
727
874
|
formatter.end();
|
|
728
|
-
|
|
729
|
-
|
|
875
|
+
notify();
|
|
876
|
+
});
|
|
877
|
+
while (!done || queue.length > 0) {
|
|
878
|
+
if (queue.length > 0) {
|
|
879
|
+
yield queue.shift();
|
|
880
|
+
continue;
|
|
730
881
|
}
|
|
731
|
-
|
|
882
|
+
await new Promise((resolve) => {
|
|
883
|
+
waiters.push(resolve);
|
|
884
|
+
});
|
|
732
885
|
}
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
throw streamError;
|
|
886
|
+
if (failure) {
|
|
887
|
+
throw failure;
|
|
736
888
|
}
|
|
737
889
|
}
|
|
@@ -19,7 +19,7 @@ export class OpenAiCliAdapter {
|
|
|
19
19
|
}
|
|
20
20
|
async invoke(request) {
|
|
21
21
|
const cliDetails = codexCliHealthy(true);
|
|
22
|
-
const result = runCodexExec(request.input, this.config.model);
|
|
22
|
+
const result = await runCodexExec(request.input, this.config.model);
|
|
23
23
|
return {
|
|
24
24
|
output: result.output,
|
|
25
25
|
adapter: this.config.adapter ?? "codex-cli",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcoda/agents",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Agent registry and capabilities for mcoda.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@mcoda/shared": "0.1.
|
|
34
|
-
"@mcoda/db": "0.1.
|
|
33
|
+
"@mcoda/shared": "0.1.36",
|
|
34
|
+
"@mcoda/db": "0.1.36"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsc -p tsconfig.json",
|