@almightygpt/core 0.2.0

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.
Files changed (126) hide show
  1. package/dist/adapters/claude.d.ts +31 -0
  2. package/dist/adapters/claude.d.ts.map +1 -0
  3. package/dist/adapters/claude.js +90 -0
  4. package/dist/adapters/claude.js.map +1 -0
  5. package/dist/adapters/gemini.d.ts +42 -0
  6. package/dist/adapters/gemini.d.ts.map +1 -0
  7. package/dist/adapters/gemini.js +133 -0
  8. package/dist/adapters/gemini.js.map +1 -0
  9. package/dist/adapters/index.d.ts +16 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters/index.js +15 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/mock.d.ts +23 -0
  14. package/dist/adapters/mock.d.ts.map +1 -0
  15. package/dist/adapters/mock.js +107 -0
  16. package/dist/adapters/mock.js.map +1 -0
  17. package/dist/adapters/openai.d.ts +38 -0
  18. package/dist/adapters/openai.d.ts.map +1 -0
  19. package/dist/adapters/openai.js +105 -0
  20. package/dist/adapters/openai.js.map +1 -0
  21. package/dist/adapters/types.d.ts +65 -0
  22. package/dist/adapters/types.d.ts.map +1 -0
  23. package/dist/adapters/types.js +26 -0
  24. package/dist/adapters/types.js.map +1 -0
  25. package/dist/config/load.d.ts +15 -0
  26. package/dist/config/load.d.ts.map +1 -0
  27. package/dist/config/load.js +46 -0
  28. package/dist/config/load.js.map +1 -0
  29. package/dist/config/schema.d.ts +260 -0
  30. package/dist/config/schema.d.ts.map +1 -0
  31. package/dist/config/schema.js +58 -0
  32. package/dist/config/schema.js.map +1 -0
  33. package/dist/context/manifest.d.ts +58 -0
  34. package/dist/context/manifest.d.ts.map +1 -0
  35. package/dist/context/manifest.js +49 -0
  36. package/dist/context/manifest.js.map +1 -0
  37. package/dist/context/redact.d.ts +26 -0
  38. package/dist/context/redact.d.ts.map +1 -0
  39. package/dist/context/redact.js +67 -0
  40. package/dist/context/redact.js.map +1 -0
  41. package/dist/git/status.d.ts +48 -0
  42. package/dist/git/status.d.ts.map +1 -0
  43. package/dist/git/status.js +79 -0
  44. package/dist/git/status.js.map +1 -0
  45. package/dist/index.d.ts +33 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +38 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/review/budget.d.ts +46 -0
  50. package/dist/review/budget.d.ts.map +1 -0
  51. package/dist/review/budget.js +83 -0
  52. package/dist/review/budget.js.map +1 -0
  53. package/dist/review/diff.d.ts +21 -0
  54. package/dist/review/diff.d.ts.map +1 -0
  55. package/dist/review/diff.js +55 -0
  56. package/dist/review/diff.js.map +1 -0
  57. package/dist/review/events.d.ts +76 -0
  58. package/dist/review/events.d.ts.map +1 -0
  59. package/dist/review/events.js +13 -0
  60. package/dist/review/events.js.map +1 -0
  61. package/dist/review/memory.d.ts +23 -0
  62. package/dist/review/memory.d.ts.map +1 -0
  63. package/dist/review/memory.js +42 -0
  64. package/dist/review/memory.js.map +1 -0
  65. package/dist/review/prompts.d.ts +34 -0
  66. package/dist/review/prompts.d.ts.map +1 -0
  67. package/dist/review/prompts.js +174 -0
  68. package/dist/review/prompts.js.map +1 -0
  69. package/dist/review/run-diff-review.d.ts +52 -0
  70. package/dist/review/run-diff-review.d.ts.map +1 -0
  71. package/dist/review/run-diff-review.js +258 -0
  72. package/dist/review/run-diff-review.js.map +1 -0
  73. package/dist/review/run-worker-reviewer.d.ts +72 -0
  74. package/dist/review/run-worker-reviewer.d.ts.map +1 -0
  75. package/dist/review/run-worker-reviewer.js +407 -0
  76. package/dist/review/run-worker-reviewer.js.map +1 -0
  77. package/dist/review/write.d.ts +44 -0
  78. package/dist/review/write.d.ts.map +1 -0
  79. package/dist/review/write.js +152 -0
  80. package/dist/review/write.js.map +1 -0
  81. package/dist/runs/decide.d.ts +45 -0
  82. package/dist/runs/decide.d.ts.map +1 -0
  83. package/dist/runs/decide.js +93 -0
  84. package/dist/runs/decide.js.map +1 -0
  85. package/dist/runs/folder.d.ts +42 -0
  86. package/dist/runs/folder.d.ts.map +1 -0
  87. package/dist/runs/folder.js +82 -0
  88. package/dist/runs/folder.js.map +1 -0
  89. package/dist/runs/list.d.ts +58 -0
  90. package/dist/runs/list.d.ts.map +1 -0
  91. package/dist/runs/list.js +117 -0
  92. package/dist/runs/list.js.map +1 -0
  93. package/dist/runs/types.d.ts +96 -0
  94. package/dist/runs/types.d.ts.map +1 -0
  95. package/dist/runs/types.js +13 -0
  96. package/dist/runs/types.js.map +1 -0
  97. package/dist/templates/install.d.ts +49 -0
  98. package/dist/templates/install.d.ts.map +1 -0
  99. package/dist/templates/install.js +154 -0
  100. package/dist/templates/install.js.map +1 -0
  101. package/package.json +34 -0
  102. package/src/adapters/claude.ts +133 -0
  103. package/src/adapters/gemini.ts +183 -0
  104. package/src/adapters/index.ts +21 -0
  105. package/src/adapters/mock.ts +125 -0
  106. package/src/adapters/openai.ts +150 -0
  107. package/src/adapters/types.ts +73 -0
  108. package/src/config/load.ts +61 -0
  109. package/src/config/schema.ts +64 -0
  110. package/src/context/manifest.ts +94 -0
  111. package/src/context/redact.ts +93 -0
  112. package/src/git/status.ts +108 -0
  113. package/src/index.ts +127 -0
  114. package/src/review/budget.ts +116 -0
  115. package/src/review/diff.ts +85 -0
  116. package/src/review/events.ts +86 -0
  117. package/src/review/memory.ts +57 -0
  118. package/src/review/prompts.ts +208 -0
  119. package/src/review/run-diff-review.ts +353 -0
  120. package/src/review/run-worker-reviewer.ts +528 -0
  121. package/src/review/write.ts +208 -0
  122. package/src/runs/decide.ts +153 -0
  123. package/src/runs/folder.ts +137 -0
  124. package/src/runs/list.ts +152 -0
  125. package/src/runs/types.ts +98 -0
  126. package/src/templates/install.ts +198 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Anthropic / Claude adapter — second real provider in MVP 1.
3
+ *
4
+ * Reads ANTHROPIC_API_KEY from the environment. Never stores or logs the key.
5
+ * Default model: claude-3-5-sonnet-latest (best Worker default; strong on
6
+ * code reasoning, fast enough for interactive use).
7
+ *
8
+ * Pricing (USD per 1M tokens, as of 2026-05):
9
+ * claude-3-5-sonnet: 3.00 in / 15.00 out
10
+ * claude-3-5-haiku: 0.80 in / 4.00 out
11
+ * claude-3-opus: 15.00 in / 75.00 out
12
+ */
13
+ import { type Adapter, type AdapterInput, type AdapterOutput } from "./types.js";
14
+ export interface ClaudeAdapterOptions {
15
+ apiKey?: string;
16
+ defaultModel?: string;
17
+ defaultMaxOutputTokens?: number;
18
+ defaultTimeoutMs?: number;
19
+ }
20
+ export declare class ClaudeAdapter implements Adapter {
21
+ readonly name: string;
22
+ readonly provider = "anthropic";
23
+ private readonly client;
24
+ private readonly defaultModel;
25
+ private readonly defaultMaxOutputTokens;
26
+ private readonly defaultTimeoutMs;
27
+ constructor(name?: string, options?: ClaudeAdapterOptions);
28
+ isAvailable(): Promise<boolean>;
29
+ execute(input: AdapterInput): Promise<AdapterOutput>;
30
+ }
31
+ //# sourceMappingURL=claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAUpB,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAc,YAAW,OAAO;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,IAAI,SAAW,EAAE,OAAO,GAAE,oBAAyB;IAUzD,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CA2D3D"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Anthropic / Claude adapter — second real provider in MVP 1.
3
+ *
4
+ * Reads ANTHROPIC_API_KEY from the environment. Never stores or logs the key.
5
+ * Default model: claude-3-5-sonnet-latest (best Worker default; strong on
6
+ * code reasoning, fast enough for interactive use).
7
+ *
8
+ * Pricing (USD per 1M tokens, as of 2026-05):
9
+ * claude-3-5-sonnet: 3.00 in / 15.00 out
10
+ * claude-3-5-haiku: 0.80 in / 4.00 out
11
+ * claude-3-opus: 15.00 in / 75.00 out
12
+ */
13
+ import Anthropic from "@anthropic-ai/sdk";
14
+ import { AdapterError, } from "./types.js";
15
+ const PRICING_USD_PER_1M = {
16
+ "claude-3-5-sonnet": { input: 3.0, output: 15.0 },
17
+ "claude-3-5-haiku": { input: 0.8, output: 4.0 },
18
+ "claude-3-opus": { input: 15.0, output: 75.0 },
19
+ };
20
+ const DEFAULT_MODEL = "claude-3-5-sonnet-latest";
21
+ export class ClaudeAdapter {
22
+ name;
23
+ provider = "anthropic";
24
+ client;
25
+ defaultModel;
26
+ defaultMaxOutputTokens;
27
+ defaultTimeoutMs;
28
+ constructor(name = "claude", options = {}) {
29
+ this.name = name;
30
+ this.defaultModel = options.defaultModel ?? DEFAULT_MODEL;
31
+ this.defaultMaxOutputTokens = options.defaultMaxOutputTokens ?? 4096;
32
+ this.defaultTimeoutMs = options.defaultTimeoutMs ?? 120_000;
33
+ const apiKey = options.apiKey ?? process.env["ANTHROPIC_API_KEY"];
34
+ this.client = apiKey ? new Anthropic({ apiKey }) : null;
35
+ }
36
+ async isAvailable() {
37
+ return this.client !== null;
38
+ }
39
+ async execute(input) {
40
+ if (!this.client) {
41
+ throw new AdapterError("ANTHROPIC_API_KEY is not set. Export it in your environment.", this.name);
42
+ }
43
+ const model = input.model ?? this.defaultModel;
44
+ const maxOutputTokens = input.maxOutputTokens ?? this.defaultMaxOutputTokens;
45
+ const timeoutMs = input.timeoutMs ?? this.defaultTimeoutMs;
46
+ const start = Date.now();
47
+ let response;
48
+ try {
49
+ response = await this.client.messages.create({
50
+ model,
51
+ max_tokens: maxOutputTokens,
52
+ system: input.systemPrompt,
53
+ messages: [{ role: "user", content: input.userMessage }],
54
+ }, { timeout: timeoutMs });
55
+ }
56
+ catch (err) {
57
+ throw new AdapterError(`Anthropic call failed: ${err instanceof Error ? err.message : String(err)}`, this.name, err);
58
+ }
59
+ // Anthropic returns content as a typed array; we want text blocks only.
60
+ const content = response.content
61
+ .filter((block) => block.type === "text")
62
+ .map((b) => b.text)
63
+ .join("\n");
64
+ if (!content) {
65
+ throw new AdapterError("Anthropic returned no text content (tool-use or empty response).", this.name);
66
+ }
67
+ const tokensIn = response.usage.input_tokens;
68
+ const tokensOut = response.usage.output_tokens;
69
+ const costUsd = estimateCostUsd(model, tokensIn, tokensOut);
70
+ return {
71
+ content,
72
+ tokensIn,
73
+ tokensOut,
74
+ costUsd,
75
+ latencyMs: Date.now() - start,
76
+ modelUsed: response.model,
77
+ provider: this.provider,
78
+ };
79
+ }
80
+ }
81
+ function estimateCostUsd(model, tokensIn, tokensOut) {
82
+ const key = Object.keys(PRICING_USD_PER_1M).find((k) => model.toLowerCase().startsWith(k));
83
+ if (!key)
84
+ return 0;
85
+ const rates = PRICING_USD_PER_1M[key];
86
+ if (!rates)
87
+ return 0;
88
+ return (tokensIn / 1_000_000) * rates.input + (tokensOut / 1_000_000) * rates.output;
89
+ }
90
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Google / Gemini adapter — third real provider.
3
+ *
4
+ * Reads GOOGLE_API_KEY (or GEMINI_API_KEY as a fallback) from the
5
+ * environment. Never stores or logs the key.
6
+ *
7
+ * Default model: gemini-2.5-pro. Configurable per-call. Earlier
8
+ * gemini-1.5-* models have been retired from the v1beta API as of
9
+ * late 2025/early 2026.
10
+ *
11
+ * Pricing (USD per 1M tokens, approximate as of 2026-05):
12
+ * gemini-2.5-pro: 1.25 in / 10.00 out
13
+ * gemini-2.5-flash: 0.30 in / 2.50 out
14
+ * gemini-2.0-flash: 0.10 in / 0.40 out
15
+ * gemini-3.x-*: pricing TBD — falls back to conservative defaults
16
+ *
17
+ * Pricing changes frequently — verify at ai.google.dev/pricing if cost
18
+ * accuracy matters for a given run.
19
+ *
20
+ * Note on system prompts: the @google/generative-ai SDK accepts a
21
+ * `systemInstruction` field on getGenerativeModel(). We use that
22
+ * instead of stitching system text into the user message.
23
+ */
24
+ import { type Adapter, type AdapterInput, type AdapterOutput } from "./types.js";
25
+ export interface GeminiAdapterOptions {
26
+ apiKey?: string;
27
+ defaultModel?: string;
28
+ defaultMaxOutputTokens?: number;
29
+ defaultTimeoutMs?: number;
30
+ }
31
+ export declare class GeminiAdapter implements Adapter {
32
+ readonly name: string;
33
+ readonly provider = "google";
34
+ private readonly client;
35
+ private readonly defaultModel;
36
+ private readonly defaultMaxOutputTokens;
37
+ private readonly defaultTimeoutMs;
38
+ constructor(name?: string, options?: GeminiAdapterOptions);
39
+ isAvailable(): Promise<boolean>;
40
+ execute(input: AdapterInput): Promise<AdapterOutput>;
41
+ }
42
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/adapters/gemini.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAmBpB,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,aAAc,YAAW,OAAO;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,IAAI,SAAW,EAAE,OAAO,GAAE,oBAAyB;IAkBzD,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CAiF3D"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Google / Gemini adapter — third real provider.
3
+ *
4
+ * Reads GOOGLE_API_KEY (or GEMINI_API_KEY as a fallback) from the
5
+ * environment. Never stores or logs the key.
6
+ *
7
+ * Default model: gemini-2.5-pro. Configurable per-call. Earlier
8
+ * gemini-1.5-* models have been retired from the v1beta API as of
9
+ * late 2025/early 2026.
10
+ *
11
+ * Pricing (USD per 1M tokens, approximate as of 2026-05):
12
+ * gemini-2.5-pro: 1.25 in / 10.00 out
13
+ * gemini-2.5-flash: 0.30 in / 2.50 out
14
+ * gemini-2.0-flash: 0.10 in / 0.40 out
15
+ * gemini-3.x-*: pricing TBD — falls back to conservative defaults
16
+ *
17
+ * Pricing changes frequently — verify at ai.google.dev/pricing if cost
18
+ * accuracy matters for a given run.
19
+ *
20
+ * Note on system prompts: the @google/generative-ai SDK accepts a
21
+ * `systemInstruction` field on getGenerativeModel(). We use that
22
+ * instead of stitching system text into the user message.
23
+ */
24
+ import { GoogleGenerativeAI } from "@google/generative-ai";
25
+ import { AdapterError, } from "./types.js";
26
+ const PRICING_USD_PER_1M = {
27
+ "gemini-2.5-pro": { input: 1.25, output: 10.0 },
28
+ "gemini-2.5-flash": { input: 0.3, output: 2.5 },
29
+ "gemini-2.0-flash": { input: 0.1, output: 0.4 },
30
+ // Older models kept for reproducibility on saved runs:
31
+ "gemini-1.5-pro": { input: 1.25, output: 5.0 },
32
+ "gemini-1.5-flash": { input: 0.075, output: 0.3 },
33
+ };
34
+ // Defaulting to flash, not pro, because Google's free tier typically has
35
+ // zero quota on the pro models but allows real usage on flash. Users with
36
+ // paid billing can override via the `model` field in config.yaml (when that
37
+ // field lands in v0.3) or by constructing the adapter directly. For code
38
+ // review of typical-sized diffs, flash quality is sufficient — pro pays for
39
+ // itself only on very large diffs or complex reasoning chains.
40
+ const DEFAULT_MODEL = "gemini-2.5-flash";
41
+ export class GeminiAdapter {
42
+ name;
43
+ provider = "google";
44
+ client;
45
+ defaultModel;
46
+ defaultMaxOutputTokens;
47
+ defaultTimeoutMs;
48
+ constructor(name = "gemini", options = {}) {
49
+ this.name = name;
50
+ this.defaultModel = options.defaultModel ?? DEFAULT_MODEL;
51
+ // Bigger than other adapters by design: gemini-2.5-* spends a portion
52
+ // of the output budget on internal "thinking" tokens before producing
53
+ // visible output. 8192 leaves ~4-6k for the actual response after the
54
+ // model finishes its reasoning. We also disable thinking explicitly
55
+ // below to make sure the visible response gets the full budget.
56
+ this.defaultMaxOutputTokens = options.defaultMaxOutputTokens ?? 8192;
57
+ this.defaultTimeoutMs = options.defaultTimeoutMs ?? 120_000;
58
+ const apiKey = options.apiKey ??
59
+ process.env["GOOGLE_API_KEY"] ??
60
+ process.env["GEMINI_API_KEY"];
61
+ this.client = apiKey ? new GoogleGenerativeAI(apiKey) : null;
62
+ }
63
+ async isAvailable() {
64
+ return this.client !== null;
65
+ }
66
+ async execute(input) {
67
+ if (!this.client) {
68
+ throw new AdapterError("GOOGLE_API_KEY (or GEMINI_API_KEY) is not set. " +
69
+ "Export one in your environment.", this.name);
70
+ }
71
+ const model = input.model ?? this.defaultModel;
72
+ const maxOutputTokens = input.maxOutputTokens ?? this.defaultMaxOutputTokens;
73
+ const timeoutMs = input.timeoutMs ?? this.defaultTimeoutMs;
74
+ // gemini-2.5-* "thinks" before responding. Without an explicit cap the
75
+ // model can consume most/all of maxOutputTokens on internal reasoning
76
+ // tokens, leaving the user-facing response truncated mid-sentence. We
77
+ // pass thinkingConfig via a type-relaxed cast because @google/generative-ai
78
+ // 0.21 doesn't declare it on GenerationConfig yet, but the v1beta REST
79
+ // API accepts it.
80
+ const generationConfig = {
81
+ maxOutputTokens,
82
+ thinkingConfig: { thinkingBudget: 0 },
83
+ };
84
+ if (input.responseFormat === "json_object") {
85
+ generationConfig["responseMimeType"] = "application/json";
86
+ }
87
+ const generative = this.client.getGenerativeModel({
88
+ model,
89
+ systemInstruction: input.systemPrompt,
90
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
+ generationConfig: generationConfig,
92
+ });
93
+ const start = Date.now();
94
+ let response;
95
+ try {
96
+ // The SDK doesn't expose a per-call timeout option, so we race manually.
97
+ response = await Promise.race([
98
+ generative.generateContent(input.userMessage),
99
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Gemini call exceeded timeout of ${timeoutMs}ms`)), timeoutMs)),
100
+ ]);
101
+ }
102
+ catch (err) {
103
+ throw new AdapterError(`Gemini call failed: ${err instanceof Error ? err.message : String(err)}`, this.name, err);
104
+ }
105
+ const content = response.response.text();
106
+ if (!content) {
107
+ throw new AdapterError("Gemini returned no text content (filtered, empty, or tool-only response).", this.name);
108
+ }
109
+ const usage = response.response.usageMetadata;
110
+ const tokensIn = usage?.promptTokenCount ?? 0;
111
+ const tokensOut = usage?.candidatesTokenCount ?? 0;
112
+ const costUsd = estimateCostUsd(model, tokensIn, tokensOut);
113
+ return {
114
+ content,
115
+ tokensIn,
116
+ tokensOut,
117
+ costUsd,
118
+ latencyMs: Date.now() - start,
119
+ modelUsed: model,
120
+ provider: this.provider,
121
+ };
122
+ }
123
+ }
124
+ function estimateCostUsd(model, tokensIn, tokensOut) {
125
+ const key = Object.keys(PRICING_USD_PER_1M).find((k) => model.toLowerCase().startsWith(k));
126
+ if (!key)
127
+ return 0;
128
+ const rates = PRICING_USD_PER_1M[key];
129
+ if (!rates)
130
+ return 0;
131
+ return (tokensIn / 1_000_000) * rates.input + (tokensOut / 1_000_000) * rates.output;
132
+ }
133
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/adapters/gemini.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EACL,YAAY,GAIb,MAAM,YAAY,CAAC;AAEpB,MAAM,kBAAkB,GAAsD;IAC5E,gBAAgB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAC/C,kBAAkB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IAC/C,kBAAkB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IAC/C,uDAAuD;IACvD,gBAAgB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IAC9C,kBAAkB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE;CAClD,CAAC;AAEF,yEAAyE;AACzE,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,4EAA4E;AAC5E,+DAA+D;AAC/D,MAAM,aAAa,GAAG,kBAAkB,CAAC;AASzC,MAAM,OAAO,aAAa;IACf,IAAI,CAAS;IACb,QAAQ,GAAG,QAAQ,CAAC;IAEZ,MAAM,CAA4B;IAClC,YAAY,CAAS;IACrB,sBAAsB,CAAS;IAC/B,gBAAgB,CAAS;IAE1C,YAAY,IAAI,GAAG,QAAQ,EAAE,UAAgC,EAAE;QAC7D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,aAAa,CAAC;QAC1D,sEAAsE;QACtE,sEAAsE;QACtE,sEAAsE;QACtE,oEAAoE;QACpE,gEAAgE;QAChE,IAAI,CAAC,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,IAAI,IAAI,CAAC;QACrE,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,OAAO,CAAC;QAE5D,MAAM,MAAM,GACV,OAAO,CAAC,MAAM;YACd,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAmB;QAC/B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,YAAY,CACpB,iDAAiD;gBAC/C,iCAAiC,EACnC,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC;QAC/C,MAAM,eAAe,GAAG,KAAK,CAAC,eAAe,IAAI,IAAI,CAAC,sBAAsB,CAAC;QAC7E,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,gBAAgB,CAAC;QAE3D,uEAAuE;QACvE,sEAAsE;QACtE,sEAAsE;QACtE,4EAA4E;QAC5E,uEAAuE;QACvE,kBAAkB;QAClB,MAAM,gBAAgB,GAA4B;YAChD,eAAe;YACf,cAAc,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE;SACtC,CAAC;QACF,IAAI,KAAK,CAAC,cAAc,KAAK,aAAa,EAAE,CAAC;YAC3C,gBAAgB,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;QAC5D,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAChD,KAAK;YACL,iBAAiB,EAAE,KAAK,CAAC,YAAY;YACrC,8DAA8D;YAC9D,gBAAgB,EAAE,gBAAuB;SAC1C,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,QAAQ,CAAC;QACb,IAAI,CAAC;YACH,yEAAyE;YACzE,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC;gBAC5B,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC;gBAC7C,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/B,UAAU,CACR,GAAG,EAAE,CACH,MAAM,CACJ,IAAI,KAAK,CAAC,mCAAmC,SAAS,IAAI,CAAC,CAC5D,EACH,SAAS,CACV,CACF;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,YAAY,CACpB,uBAAuB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACzE,IAAI,CAAC,IAAI,EACT,GAAG,CACJ,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,YAAY,CACpB,2EAA2E,EAC3E,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC;QAC9C,MAAM,QAAQ,GAAG,KAAK,EAAE,gBAAgB,IAAI,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,KAAK,EAAE,oBAAoB,IAAI,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAE5D,OAAO;YACL,OAAO;YACP,QAAQ;YACR,SAAS;YACT,OAAO;YACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;YAC7B,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC;IACJ,CAAC;CACF;AAED,SAAS,eAAe,CACtB,KAAa,EACb,QAAgB,EAChB,SAAiB;IAEjB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACrD,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAClC,CAAC;IACF,IAAI,CAAC,GAAG;QAAE,OAAO,CAAC,CAAC;IACnB,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;AACvF,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Adapter exports.
3
+ *
4
+ * Add new adapters here as they're implemented:
5
+ * - Claude (Anthropic) — task #15
6
+ * - Gemini — post-MVP 1
7
+ * - OpenRouter — post-MVP 1 (for cost-conscious users; see
8
+ * docs/claude/competitor-ai-council.md)
9
+ */
10
+ export type { Adapter, AdapterInput, AdapterOutput, AgentRole, } from "./types.js";
11
+ export { AdapterError } from "./types.js";
12
+ export { MockAdapter } from "./mock.js";
13
+ export { OpenAIAdapter, type OpenAIAdapterOptions } from "./openai.js";
14
+ export { ClaudeAdapter, type ClaudeAdapterOptions } from "./claude.js";
15
+ export { GeminiAdapter, type GeminiAdapterOptions } from "./gemini.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EACV,OAAO,EACP,YAAY,EACZ,aAAa,EACb,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Adapter exports.
3
+ *
4
+ * Add new adapters here as they're implemented:
5
+ * - Claude (Anthropic) — task #15
6
+ * - Gemini — post-MVP 1
7
+ * - OpenRouter — post-MVP 1 (for cost-conscious users; see
8
+ * docs/claude/competitor-ai-council.md)
9
+ */
10
+ export { AdapterError } from "./types.js";
11
+ export { MockAdapter } from "./mock.js";
12
+ export { OpenAIAdapter } from "./openai.js";
13
+ export { ClaudeAdapter } from "./claude.js";
14
+ export { GeminiAdapter } from "./gemini.js";
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAA6B,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,aAAa,EAA6B,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,aAAa,EAA6B,MAAM,aAAa,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Mock adapter — produces deterministic, realistic-shaped output without
3
+ * calling any external API. Used for end-to-end testing, demos without
4
+ * API keys, and to exercise the review pipeline in CI.
5
+ *
6
+ * The mock is deliberately "good enough to look real" so we can spot
7
+ * format problems. It is not a substitute for real model output.
8
+ */
9
+ import type { Adapter, AdapterInput, AdapterOutput } from "./types.js";
10
+ export declare class MockAdapter implements Adapter {
11
+ private readonly opts;
12
+ readonly name = "mock";
13
+ readonly provider = "mock";
14
+ constructor(opts?: {
15
+ /** Optional simulated latency in ms. Default 50. */
16
+ latencyMs?: number;
17
+ });
18
+ isAvailable(): Promise<boolean>;
19
+ execute(input: AdapterInput): Promise<AdapterOutput>;
20
+ private mockReview;
21
+ private mockWork;
22
+ }
23
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/adapters/mock.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE,qBAAa,WAAY,YAAW,OAAO;IAKvC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,QAAQ,CAAC,IAAI,UAAU;IACvB,QAAQ,CAAC,QAAQ,UAAU;gBAGR,IAAI,GAAE;QACrB,oDAAoD;QACpD,SAAS,CAAC,EAAE,MAAM,CAAC;KACf;IAGF,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IA4B1D,OAAO,CAAC,UAAU;IAqDlB,OAAO,CAAC,QAAQ;CAiBjB"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Mock adapter — produces deterministic, realistic-shaped output without
3
+ * calling any external API. Used for end-to-end testing, demos without
4
+ * API keys, and to exercise the review pipeline in CI.
5
+ *
6
+ * The mock is deliberately "good enough to look real" so we can spot
7
+ * format problems. It is not a substitute for real model output.
8
+ */
9
+ export class MockAdapter {
10
+ opts;
11
+ name = "mock";
12
+ provider = "mock";
13
+ constructor(opts = {}) {
14
+ this.opts = opts;
15
+ }
16
+ async isAvailable() {
17
+ return true;
18
+ }
19
+ async execute(input) {
20
+ const start = Date.now();
21
+ const latency = this.opts.latencyMs ?? 50;
22
+ await new Promise((r) => setTimeout(r, latency));
23
+ const content = input.role === "reviewer"
24
+ ? this.mockReview(input.userMessage)
25
+ : this.mockWork(input.userMessage);
26
+ // Token counts are rough — 4 chars/token heuristic. Cost is always 0
27
+ // because the mock never bills anyone.
28
+ const tokensIn = Math.ceil((input.systemPrompt.length + input.userMessage.length) / 4);
29
+ const tokensOut = Math.ceil(content.length / 4);
30
+ return {
31
+ content,
32
+ tokensIn,
33
+ tokensOut,
34
+ costUsd: 0,
35
+ latencyMs: Date.now() - start,
36
+ modelUsed: "mock-1",
37
+ provider: "mock",
38
+ };
39
+ }
40
+ mockReview(userMessage) {
41
+ // Extract any file paths the user mentioned to make the mock look at-the-code.
42
+ const fileHints = Array.from(userMessage.matchAll(/[\w./-]+\.(ts|js|tsx|jsx|py|go|rb|md|json|yaml)/g))
43
+ .slice(0, 3)
44
+ .map((m) => m[0]);
45
+ const refs = fileHints.length
46
+ ? fileHints
47
+ : ["src/index.ts", "src/lib/foo.ts", "src/utils/bar.ts"];
48
+ return [
49
+ "## Decision Required",
50
+ "Needs changes before merge. Three concrete issues identified.",
51
+ "",
52
+ "## Highest-Risk Findings",
53
+ "",
54
+ `### 1. (mock) Missing input validation in ${refs[0]}`,
55
+ "**Severity:** High",
56
+ "**Where:** entry point of the diff",
57
+ "**Why:** Untrusted input flows into a parser without bounds checks.",
58
+ "**Suggested fix:** Add a Zod schema at the boundary; reject malformed input early.",
59
+ "",
60
+ `### 2. (mock) Unhandled rejection in ${refs[1] ?? refs[0]}`,
61
+ "**Severity:** Medium",
62
+ "**Where:** the awaited call without try/catch",
63
+ "**Why:** A network failure here will surface as an uncaught promise rejection.",
64
+ "**Suggested fix:** Wrap in try/catch, log to the audit channel, return a typed error.",
65
+ "",
66
+ `### 3. (mock) Missing test coverage on ${refs[2] ?? refs[0]}`,
67
+ "**Severity:** Medium",
68
+ "**Where:** the branch added in this diff",
69
+ "**Why:** The new conditional has no exercise in the test suite.",
70
+ "**Suggested fix:** Add a unit test that exercises the new branch with a representative payload.",
71
+ "",
72
+ "## Concrete Weaknesses",
73
+ `1. ${refs[0]}: input validation gap (see Finding 1).`,
74
+ `2. ${refs[1] ?? refs[0]}: unhandled promise rejection (see Finding 2).`,
75
+ `3. ${refs[2] ?? refs[0]}: no test coverage for the new branch (see Finding 3).`,
76
+ "",
77
+ "## Test Plan",
78
+ "- Run the existing unit suite; expect no regressions.",
79
+ "- Add the test described in Finding 3 and verify it fails before fix, passes after.",
80
+ "- Manually trigger the network-error path described in Finding 2.",
81
+ "",
82
+ "## Human Decision",
83
+ "_(blank — record via `almightygpt decide`)_",
84
+ "",
85
+ "---",
86
+ "_Mock adapter output — no real model was invoked. Replace `--reviewer mock` with `--reviewer codex` or another real adapter for production review._",
87
+ ].join("\n");
88
+ }
89
+ mockWork(userMessage) {
90
+ return [
91
+ "## Plan",
92
+ "1. Understand the change requested.",
93
+ "2. Identify affected files and surfaces.",
94
+ "3. Write the implementation in small, testable steps.",
95
+ "4. Add or update tests.",
96
+ "5. Verify locally.",
97
+ "",
98
+ "## Notes",
99
+ "_(mock worker output — real Worker adapters produce code or detailed plans here.)_",
100
+ "",
101
+ `## Echo of input (first 200 chars):`,
102
+ "",
103
+ "> " + userMessage.slice(0, 200) + (userMessage.length > 200 ? "…" : ""),
104
+ ].join("\n");
105
+ }
106
+ }
107
+ //# sourceMappingURL=mock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/adapters/mock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * OpenAI adapter — first real provider in MVP 1.
3
+ *
4
+ * Reads OPENAI_API_KEY from the environment. Never stores or logs the key.
5
+ * Default model: gpt-4o (best balance of quality and structured-output maturity
6
+ * for the Reviewer's JSON schema needs in later tasks). Configurable per-call.
7
+ *
8
+ * Pricing as of 2026-05 (USD per 1M tokens, gpt-4o):
9
+ * input: 2.50
10
+ * output: 10.00
11
+ * These are recorded in PRICING_USD_PER_1M below. Update when OpenAI changes
12
+ * their published rates.
13
+ */
14
+ import { type Adapter, type AdapterInput, type AdapterOutput } from "./types.js";
15
+ export interface OpenAIAdapterOptions {
16
+ /** Override the API key source. Defaults to process.env.OPENAI_API_KEY. */
17
+ apiKey?: string;
18
+ /** Default model used when execute() does not supply one. */
19
+ defaultModel?: string;
20
+ /** Default response token cap. */
21
+ defaultMaxOutputTokens?: number;
22
+ /** Default wall-clock timeout. */
23
+ defaultTimeoutMs?: number;
24
+ /** OpenAI organization id (optional). */
25
+ organization?: string;
26
+ }
27
+ export declare class OpenAIAdapter implements Adapter {
28
+ readonly name: string;
29
+ readonly provider = "openai";
30
+ private readonly client;
31
+ private readonly defaultModel;
32
+ private readonly defaultMaxOutputTokens;
33
+ private readonly defaultTimeoutMs;
34
+ constructor(name?: string, options?: OpenAIAdapterOptions);
35
+ isAvailable(): Promise<boolean>;
36
+ execute(input: AdapterInput): Promise<AdapterOutput>;
37
+ }
38
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/adapters/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAgB,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAY/F,MAAM,WAAW,oBAAoB;IACnC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,kCAAkC;IAClC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,aAAc,YAAW,OAAO;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAGxC,IAAI,SAAU,EACd,OAAO,GAAE,oBAAyB;IAkB9B,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;CA6D3D"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * OpenAI adapter — first real provider in MVP 1.
3
+ *
4
+ * Reads OPENAI_API_KEY from the environment. Never stores or logs the key.
5
+ * Default model: gpt-4o (best balance of quality and structured-output maturity
6
+ * for the Reviewer's JSON schema needs in later tasks). Configurable per-call.
7
+ *
8
+ * Pricing as of 2026-05 (USD per 1M tokens, gpt-4o):
9
+ * input: 2.50
10
+ * output: 10.00
11
+ * These are recorded in PRICING_USD_PER_1M below. Update when OpenAI changes
12
+ * their published rates.
13
+ */
14
+ import OpenAI from "openai";
15
+ import { AdapterError } from "./types.js";
16
+ /** USD per 1M tokens, by model. Lowercased keys. */
17
+ const PRICING_USD_PER_1M = {
18
+ "gpt-4o": { input: 2.5, output: 10.0 },
19
+ "gpt-4o-mini": { input: 0.15, output: 0.6 },
20
+ "gpt-4-turbo": { input: 10.0, output: 30.0 },
21
+ "gpt-3.5-turbo": { input: 0.5, output: 1.5 },
22
+ };
23
+ const DEFAULT_MODEL = "gpt-4o";
24
+ export class OpenAIAdapter {
25
+ name;
26
+ provider = "openai";
27
+ client;
28
+ defaultModel;
29
+ defaultMaxOutputTokens;
30
+ defaultTimeoutMs;
31
+ constructor(name = "codex", options = {}) {
32
+ this.name = name;
33
+ this.defaultModel = options.defaultModel ?? DEFAULT_MODEL;
34
+ this.defaultMaxOutputTokens = options.defaultMaxOutputTokens ?? 4096;
35
+ this.defaultTimeoutMs = options.defaultTimeoutMs ?? 120_000;
36
+ const apiKey = options.apiKey ?? process.env["OPENAI_API_KEY"];
37
+ if (apiKey && apiKey.length > 0) {
38
+ this.client = new OpenAI({
39
+ apiKey,
40
+ ...(options.organization ? { organization: options.organization } : {}),
41
+ });
42
+ }
43
+ else {
44
+ this.client = null;
45
+ }
46
+ }
47
+ async isAvailable() {
48
+ return this.client !== null;
49
+ }
50
+ async execute(input) {
51
+ if (!this.client) {
52
+ throw new AdapterError("OPENAI_API_KEY is not set. Export it in your environment or pass it " +
53
+ "via the adapter constructor.", this.name);
54
+ }
55
+ const model = input.model ?? this.defaultModel;
56
+ const maxOutputTokens = input.maxOutputTokens ?? this.defaultMaxOutputTokens;
57
+ const timeoutMs = input.timeoutMs ?? this.defaultTimeoutMs;
58
+ const start = Date.now();
59
+ let response;
60
+ try {
61
+ response = await this.client.chat.completions.create({
62
+ model,
63
+ max_tokens: maxOutputTokens,
64
+ messages: [
65
+ { role: "system", content: input.systemPrompt },
66
+ { role: "user", content: input.userMessage },
67
+ ],
68
+ ...(input.responseFormat === "json_object"
69
+ ? { response_format: { type: "json_object" } }
70
+ : {}),
71
+ }, { timeout: timeoutMs });
72
+ }
73
+ catch (err) {
74
+ throw new AdapterError(`OpenAI call failed: ${err instanceof Error ? err.message : String(err)}`, this.name, err);
75
+ }
76
+ const choice = response.choices[0];
77
+ if (!choice || !choice.message.content) {
78
+ throw new AdapterError("OpenAI returned an empty response (no choices or empty content).", this.name);
79
+ }
80
+ const content = choice.message.content;
81
+ const tokensIn = response.usage?.prompt_tokens ?? 0;
82
+ const tokensOut = response.usage?.completion_tokens ?? 0;
83
+ const costUsd = estimateCostUsd(model, tokensIn, tokensOut);
84
+ return {
85
+ content,
86
+ tokensIn,
87
+ tokensOut,
88
+ costUsd,
89
+ latencyMs: Date.now() - start,
90
+ modelUsed: response.model ?? model,
91
+ provider: this.provider,
92
+ };
93
+ }
94
+ }
95
+ function estimateCostUsd(model, tokensIn, tokensOut) {
96
+ // Match by prefix so versioned model names (gpt-4o-2024-08-06) still resolve.
97
+ const key = Object.keys(PRICING_USD_PER_1M).find((k) => model.toLowerCase().startsWith(k));
98
+ if (!key)
99
+ return 0;
100
+ const rates = PRICING_USD_PER_1M[key];
101
+ if (!rates)
102
+ return 0;
103
+ return (tokensIn / 1_000_000) * rates.input + (tokensOut / 1_000_000) * rates.output;
104
+ }
105
+ //# sourceMappingURL=openai.js.map