@malayvuong/agent-orchestra-providers 2026.3.3 → 2026.4.4

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nguyen Minh Vuong
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ProviderOutput } from '@malayvuong/agent-orchestra-core';
2
+ export { getDefaultModelForProvider } from '@malayvuong/agent-orchestra-shared';
2
3
 
3
4
  /**
4
5
  * Input to an LLM provider adapter.
@@ -11,7 +12,7 @@ type ProviderInput = {
11
12
  systemPrompt: string;
12
13
  /** User-facing prompt content */
13
14
  userPrompt: string;
14
- /** Model identifier (e.g. 'gpt-4o', 'claude-sonnet-4-20250514') */
15
+ /** Model identifier (e.g. 'gpt-5.4', 'claude-sonnet-4-6') */
15
16
  model: string;
16
17
  /** Maximum tokens to generate */
17
18
  maxTokens?: number;
@@ -138,7 +139,7 @@ declare class AnthropicProvider implements AgentProvider {
138
139
  type ClaudeCliProviderConfig = {
139
140
  /** Path to the claude binary; defaults to 'claude' (from PATH) */
140
141
  command?: string;
141
- /** Default model; defaults to 'sonnet' */
142
+ /** Default model; defaults to 'claude-opus-4-6[1m]' (1M context) */
142
143
  defaultModel?: string;
143
144
  };
144
145
  /**
@@ -162,16 +163,17 @@ declare class ClaudeCliProvider implements AgentProvider {
162
163
  type CodexCliProviderConfig = {
163
164
  /** Path to the codex binary; defaults to 'codex' (from PATH) */
164
165
  command?: string;
165
- /** Default model; defaults to 'o4-mini' */
166
+ /** Default model; defaults to 'gpt-5.4' */
166
167
  defaultModel?: string;
167
168
  };
168
169
  /**
169
170
  * Provider adapter that uses the OpenAI Codex CLI (`codex`) as the LLM backend.
170
171
  *
171
- * Invokes `codex -p <prompt> --model <model>` as a subprocess.
172
+ * Invokes `codex exec --model <model> -` as a subprocess.
172
173
  * The CLI handles its own authentication — no API key required if already logged in.
173
174
  *
174
- * Prompts are passed via the -p flag with the full combined prompt.
175
+ * Prompts are passed via stdin, and the last agent message is collected via
176
+ * `--output-last-message` to avoid parsing progress output from stdout.
175
177
  */
176
178
  declare class CodexCliProvider implements AgentProvider {
177
179
  private readonly command;
package/dist/index.js CHANGED
@@ -1,3 +1,6 @@
1
+ // src/openai/adapter.ts
2
+ import { getDefaultModelForProvider } from "@malayvuong/agent-orchestra-shared";
3
+
1
4
  // src/types.ts
2
5
  var ProviderError = class extends Error {
3
6
  constructor(message, code, statusCode, retryable = false, retryAfterMs) {
@@ -12,6 +15,7 @@ var ProviderError = class extends Error {
12
15
 
13
16
  // src/openai/adapter.ts
14
17
  var MODEL_PRICING = {
18
+ "gpt-5.4": { input: 2.5, output: 10 },
15
19
  "gpt-4o": { input: 2.5, output: 10 },
16
20
  "gpt-4o-mini": { input: 0.15, output: 0.6 },
17
21
  "gpt-4-turbo": { input: 10, output: 30 },
@@ -27,7 +31,7 @@ var OpenAIProvider = class {
27
31
  constructor(config = {}) {
28
32
  this.apiKey = config.apiKey ?? process.env.OPENAI_API_KEY ?? "";
29
33
  this.baseUrl = (config.baseUrl ?? "https://api.openai.com").replace(/\/+$/, "");
30
- this.defaultModel = config.defaultModel ?? "gpt-4o";
34
+ this.defaultModel = config.defaultModel ?? getDefaultModelForProvider("openai");
31
35
  if (!this.apiKey) {
32
36
  throw new ProviderError(
33
37
  "OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass apiKey in config.",
@@ -185,9 +189,12 @@ var OpenAIProvider = class {
185
189
  };
186
190
 
187
191
  // src/anthropic/adapter.ts
192
+ import { getDefaultModelForProvider as getDefaultModelForProvider2 } from "@malayvuong/agent-orchestra-shared";
188
193
  var ANTHROPIC_API_URL = "https://api.anthropic.com";
189
194
  var ANTHROPIC_VERSION = "2023-06-01";
190
195
  var MODEL_PRICING2 = {
196
+ "claude-sonnet-4-6": { input: 3, output: 15 },
197
+ "claude-opus-4-6": { input: 15, output: 75 },
191
198
  "claude-sonnet-4-20250514": { input: 3, output: 15 },
192
199
  "claude-opus-4-20250514": { input: 15, output: 75 },
193
200
  "claude-3-5-sonnet-20241022": { input: 3, output: 15 },
@@ -202,7 +209,7 @@ var AnthropicProvider = class {
202
209
  defaultModel;
203
210
  constructor(config = {}) {
204
211
  this.apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
205
- this.defaultModel = config.defaultModel ?? "claude-sonnet-4-20250514";
212
+ this.defaultModel = config.defaultModel ?? getDefaultModelForProvider2("anthropic");
206
213
  if (!this.apiKey) {
207
214
  throw new ProviderError(
208
215
  "Anthropic API key is required. Set ANTHROPIC_API_KEY environment variable or pass apiKey in config.",
@@ -366,24 +373,45 @@ var AnthropicProvider = class {
366
373
 
367
374
  // src/cli/claude-cli.ts
368
375
  import { spawn } from "child_process";
376
+ import { getDefaultModelForProvider as getDefaultModelForProvider3 } from "@malayvuong/agent-orchestra-shared";
369
377
  var DEFAULT_TIMEOUT_MS3 = 9e5;
378
+ var MAX_PROMPT_CHARS_200K = 68e4;
379
+ var MAX_PROMPT_CHARS_1M = 34e5;
380
+ function maxPromptCharsForModel(model) {
381
+ return model.includes("[1m]") ? MAX_PROMPT_CHARS_1M : MAX_PROMPT_CHARS_200K;
382
+ }
370
383
  var ClaudeCliProvider = class {
371
384
  command;
372
385
  defaultModel;
373
386
  constructor(config = {}) {
374
387
  this.command = config.command ?? "claude";
375
- this.defaultModel = config.defaultModel ?? "sonnet";
388
+ this.defaultModel = config.defaultModel ?? getDefaultModelForProvider3("claude-cli");
376
389
  }
377
390
  async run(input) {
378
391
  const model = input.model || this.defaultModel;
379
392
  const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
380
393
  const startTime = Date.now();
381
- const combinedPrompt = `${input.systemPrompt}
382
-
383
- ---
384
-
385
- ${input.userPrompt}`;
394
+ const userPrompt = input.userPrompt;
395
+ const estimatedChars = (input.systemPrompt?.length ?? 0) + userPrompt.length;
396
+ const limit = maxPromptCharsForModel(model);
397
+ if (estimatedChars > limit) {
398
+ const hint = !model.includes("[1m]") ? ` Try using the 1M context model (e.g. claude-opus-4-6[1m]).` : "";
399
+ throw new ProviderError(
400
+ `Prompt too large for Claude CLI (${Math.round(estimatedChars / 1e3)}K chars, limit ~${Math.round(limit / 1e3)}K).${hint} Reduce target content or split across multiple reviews.`,
401
+ "invalid_response"
402
+ );
403
+ }
386
404
  const args = ["-p", "--model", model, "--output-format", "text"];
405
+ const SYSTEM_PROMPT_CLI_LIMIT = 2e5;
406
+ const systemPromptViaStdin = input.systemPrompt && input.systemPrompt.length > SYSTEM_PROMPT_CLI_LIMIT;
407
+ if (input.systemPrompt && !systemPromptViaStdin) {
408
+ args.push("--system-prompt", input.systemPrompt);
409
+ }
410
+ const stdinContent = systemPromptViaStdin ? `<system-instructions>
411
+ ${input.systemPrompt}
412
+ </system-instructions>
413
+
414
+ ${userPrompt}` : userPrompt;
387
415
  if (input.maxTokens) {
388
416
  args.push("--max-tokens", String(input.maxTokens));
389
417
  }
@@ -417,7 +445,7 @@ ${input.userPrompt}`;
417
445
  )
418
446
  );
419
447
  });
420
- child.stdin.end(combinedPrompt);
448
+ child.stdin.end(stdinContent);
421
449
  let stdout = "";
422
450
  let stderr = "";
423
451
  child.stdout.on("data", (chunk) => {
@@ -456,7 +484,9 @@ ${input.userPrompt}`;
456
484
  child.on("close", (code) => {
457
485
  const latencyMs = Date.now() - startTime;
458
486
  if (code !== 0) {
459
- if (stderr.includes("authentication") || stderr.includes("login") || stderr.includes("not logged in")) {
487
+ const combined = `${stderr}
488
+ ${stdout}`;
489
+ if (combined.includes("authentication") || combined.includes("login") || combined.includes("not logged in")) {
460
490
  rejectOnce(
461
491
  new ProviderError(
462
492
  `Claude CLI authentication failed. Run 'claude login' first. stderr: ${stderr.slice(0, 300)}`,
@@ -465,6 +495,15 @@ ${input.userPrompt}`;
465
495
  );
466
496
  return;
467
497
  }
498
+ if (combined.includes("Prompt is too long") || combined.includes("prompt is too long") || combined.includes("too many tokens")) {
499
+ rejectOnce(
500
+ new ProviderError(
501
+ `Prompt too large for Claude CLI context window. Reduce target content or split across multiple reviews.`,
502
+ "invalid_response"
503
+ )
504
+ );
505
+ return;
506
+ }
468
507
  if (code === null) {
469
508
  rejectOnce(
470
509
  new ProviderError(
@@ -476,9 +515,10 @@ ${input.userPrompt}`;
476
515
  );
477
516
  return;
478
517
  }
518
+ const errorDetail = stderr.trim() || stdout.trim();
479
519
  rejectOnce(
480
520
  new ProviderError(
481
- `Claude CLI exited with code ${code}. stderr: ${stderr.slice(0, 500)}`,
521
+ `Claude CLI exited with code ${code}. ${errorDetail ? `Output: ${errorDetail.slice(0, 500)}` : "(no output)"}`,
482
522
  "server_error",
483
523
  code,
484
524
  true
@@ -507,13 +547,21 @@ ${input.userPrompt}`;
507
547
 
508
548
  // src/cli/codex-cli.ts
509
549
  import { spawn as spawn2 } from "child_process";
550
+ import { mkdtemp, readFile, rm } from "fs/promises";
551
+ import { join } from "path";
552
+ import { tmpdir } from "os";
553
+
554
+ // src/default-models.ts
555
+ import { getDefaultModelForProvider as getDefaultModelForProvider4 } from "@malayvuong/agent-orchestra-shared";
556
+
557
+ // src/cli/codex-cli.ts
510
558
  var DEFAULT_TIMEOUT_MS4 = 3e5;
511
559
  var CodexCliProvider = class {
512
560
  command;
513
561
  defaultModel;
514
562
  constructor(config = {}) {
515
563
  this.command = config.command ?? "codex";
516
- this.defaultModel = config.defaultModel ?? "o4-mini";
564
+ this.defaultModel = config.defaultModel ?? getDefaultModelForProvider4("codex-cli");
517
565
  }
518
566
  async run(input) {
519
567
  const model = input.model || this.defaultModel;
@@ -524,94 +572,152 @@ var CodexCliProvider = class {
524
572
  ---
525
573
 
526
574
  ${input.userPrompt}`;
527
- const args = ["-p", combinedPrompt, "--model", model];
528
575
  return new Promise((resolve, reject) => {
529
- const child = spawn2(this.command, args, {
530
- stdio: ["ignore", "pipe", "pipe"],
531
- timeout: timeoutMs
532
- });
533
- let stdout = "";
534
- let stderr = "";
535
- child.stdout.on("data", (chunk) => {
536
- stdout += chunk.toString();
537
- });
538
- child.stderr.on("data", (chunk) => {
539
- stderr += chunk.toString();
540
- });
541
- if (input.abortSignal) {
542
- if (input.abortSignal.aborted) {
543
- child.kill("SIGTERM");
544
- } else {
545
- input.abortSignal.addEventListener(
546
- "abort",
547
- () => {
548
- child.kill("SIGTERM");
549
- },
550
- { once: true }
551
- );
552
- }
553
- }
554
- child.on("error", (err) => {
555
- if (err.code === "ENOENT") {
556
- reject(
576
+ let settled = false;
577
+ const resolveOnce = (value) => {
578
+ if (settled) return;
579
+ settled = true;
580
+ resolve(value);
581
+ };
582
+ const rejectOnce = (error) => {
583
+ if (settled) return;
584
+ settled = true;
585
+ reject(error);
586
+ };
587
+ const tempDirPromise = mkdtemp(join(tmpdir(), "ao-codex-cli-"));
588
+ void tempDirPromise.then(async (tempDir) => {
589
+ const outputPath = join(tempDir, "last-message.txt");
590
+ const cleanup = async () => {
591
+ await rm(tempDir, { recursive: true, force: true });
592
+ };
593
+ const args = ["exec", "--model", model, "--output-last-message", outputPath, "-"];
594
+ const child = spawn2(this.command, args, {
595
+ stdio: ["pipe", "pipe", "pipe"],
596
+ timeout: timeoutMs
597
+ });
598
+ child.stdin.on("error", (err) => {
599
+ const code = err.code;
600
+ if (code === "EPIPE" || code === "ERR_STREAM_DESTROYED") {
601
+ return;
602
+ }
603
+ rejectOnce(
557
604
  new ProviderError(
558
- `Codex CLI not found. Install it with 'npm install -g @openai/codex' or check your PATH.`,
559
- "auth_error"
605
+ `Codex CLI stdin error: ${err.message}`,
606
+ "server_error",
607
+ void 0,
608
+ true
560
609
  )
561
610
  );
562
- } else {
563
- reject(
564
- new ProviderError(`Codex CLI error: ${err.message}`, "server_error", void 0, true)
565
- );
611
+ });
612
+ child.stdin.end(combinedPrompt);
613
+ let stdout = "";
614
+ let stderr = "";
615
+ child.stdout.on("data", (chunk) => {
616
+ stdout += chunk.toString();
617
+ });
618
+ child.stderr.on("data", (chunk) => {
619
+ stderr += chunk.toString();
620
+ });
621
+ if (input.abortSignal) {
622
+ if (input.abortSignal.aborted) {
623
+ child.kill("SIGTERM");
624
+ } else {
625
+ input.abortSignal.addEventListener(
626
+ "abort",
627
+ () => {
628
+ child.kill("SIGTERM");
629
+ },
630
+ { once: true }
631
+ );
632
+ }
566
633
  }
567
- });
568
- child.on("close", (code) => {
569
- const latencyMs = Date.now() - startTime;
570
- if (code !== 0) {
571
- if (stderr.includes("authentication") || stderr.includes("API key") || stderr.includes("login")) {
572
- reject(
634
+ child.on("error", (err) => {
635
+ if (err.code === "ENOENT") {
636
+ void cleanup();
637
+ rejectOnce(
573
638
  new ProviderError(
574
- `Codex CLI authentication failed. Run 'codex login' or set OPENAI_API_KEY. stderr: ${stderr.slice(0, 300)}`,
639
+ `Codex CLI not found. Install it with 'npm install -g @openai/codex' or check your PATH.`,
575
640
  "auth_error"
576
641
  )
577
642
  );
578
- return;
579
- }
580
- if (code === null) {
581
- reject(
643
+ } else {
644
+ void cleanup();
645
+ rejectOnce(
582
646
  new ProviderError(
583
- `Codex CLI timed out after ${timeoutMs}ms`,
584
- "timeout",
647
+ `Codex CLI error: ${err.message}`,
648
+ "server_error",
585
649
  void 0,
586
650
  true
587
651
  )
588
652
  );
653
+ }
654
+ });
655
+ child.on("close", async (code) => {
656
+ const latencyMs = Date.now() - startTime;
657
+ if (code !== 0) {
658
+ if (stderr.includes("authentication") || stderr.includes("API key") || stderr.includes("login")) {
659
+ rejectOnce(
660
+ new ProviderError(
661
+ `Codex CLI authentication failed. Run 'codex login' or set OPENAI_API_KEY. stderr: ${stderr.slice(0, 300)}`,
662
+ "auth_error"
663
+ )
664
+ );
665
+ await cleanup();
666
+ return;
667
+ }
668
+ if (code === null) {
669
+ rejectOnce(
670
+ new ProviderError(
671
+ `Codex CLI timed out after ${timeoutMs}ms`,
672
+ "timeout",
673
+ void 0,
674
+ true
675
+ )
676
+ );
677
+ await cleanup();
678
+ return;
679
+ }
680
+ rejectOnce(
681
+ new ProviderError(
682
+ `Codex CLI exited with code ${code}. stderr: ${stderr.slice(0, 500)}`,
683
+ "server_error",
684
+ code,
685
+ true
686
+ )
687
+ );
688
+ await cleanup();
589
689
  return;
590
690
  }
591
- reject(
592
- new ProviderError(
593
- `Codex CLI exited with code ${code}. stderr: ${stderr.slice(0, 500)}`,
594
- "server_error",
595
- code,
596
- true
597
- )
598
- );
599
- return;
600
- }
601
- const warnings = [];
602
- if (stderr) {
603
- const filtered = stderr.trim();
604
- if (filtered) warnings.push(filtered.slice(0, 300));
605
- }
606
- resolve({
607
- rawText: stdout.trim(),
608
- warnings: warnings.length > 0 ? warnings : void 0,
609
- usage: {
610
- latencyMs
611
- },
612
- exitCode: code,
613
- stderrText: stderr || void 0
691
+ let finalText = stdout.trim();
692
+ try {
693
+ finalText = (await readFile(outputPath, "utf-8")).trim() || finalText;
694
+ } catch {
695
+ }
696
+ const warnings = [];
697
+ if (stderr) {
698
+ const filtered = stderr.trim();
699
+ if (filtered) warnings.push(filtered.slice(0, 300));
700
+ }
701
+ resolveOnce({
702
+ rawText: finalText,
703
+ warnings: warnings.length > 0 ? warnings : void 0,
704
+ usage: {
705
+ latencyMs
706
+ },
707
+ exitCode: code,
708
+ stderrText: stderr || void 0
709
+ });
710
+ await cleanup();
614
711
  });
712
+ }).catch((err) => {
713
+ rejectOnce(
714
+ new ProviderError(
715
+ `Codex CLI setup error: ${err instanceof Error ? err.message : String(err)}`,
716
+ "server_error",
717
+ void 0,
718
+ true
719
+ )
720
+ );
615
721
  });
616
722
  });
617
723
  }
@@ -691,5 +797,6 @@ export {
691
797
  ProviderError,
692
798
  ProviderRouter,
693
799
  detectCliProviders,
800
+ getDefaultModelForProvider4 as getDefaultModelForProvider,
694
801
  isCommandAvailable
695
802
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malayvuong/agent-orchestra-providers",
3
- "version": "2026.3.3",
3
+ "version": "2026.4.4",
4
4
  "description": "LLM provider adapters for Agent Orchestra",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,23 +21,22 @@
21
21
  },
22
22
  "repository": {
23
23
  "type": "git",
24
- "url": "https://github.com/nicemvp/agent-orchestra.git",
24
+ "url": "https://github.com/malayvuong/agent-orchestra.git",
25
25
  "directory": "packages/providers"
26
26
  },
27
- "homepage": "https://github.com/nicemvp/agent-orchestra#readme",
27
+ "homepage": "https://github.com/malayvuong/agent-orchestra#readme",
28
28
  "bugs": {
29
- "url": "https://github.com/nicemvp/agent-orchestra/issues"
29
+ "url": "https://github.com/malayvuong/agent-orchestra/issues"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"
33
33
  },
34
+ "dependencies": {
35
+ "@malayvuong/agent-orchestra-shared": "2026.4.4",
36
+ "@malayvuong/agent-orchestra-core": "2026.4.4"
37
+ },
34
38
  "scripts": {
35
39
  "build": "tsup",
36
- "typecheck": "tsc --noEmit",
37
- "prepublishOnly": "pnpm run build"
38
- },
39
- "dependencies": {
40
- "@malayvuong/agent-orchestra-core": "workspace:*",
41
- "@malayvuong/agent-orchestra-shared": "workspace:*"
40
+ "typecheck": "tsc --noEmit"
42
41
  }
43
- }
42
+ }