agents-reverse-engineer 0.3.6 → 0.4.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.
- package/dist/ai/backends/claude.d.ts +92 -0
- package/dist/ai/backends/claude.d.ts.map +1 -0
- package/dist/ai/backends/claude.js +213 -0
- package/dist/ai/backends/claude.js.map +1 -0
- package/dist/ai/backends/gemini.d.ts +53 -0
- package/dist/ai/backends/gemini.d.ts.map +1 -0
- package/dist/ai/backends/gemini.js +66 -0
- package/dist/ai/backends/gemini.js.map +1 -0
- package/dist/ai/backends/opencode.d.ts +53 -0
- package/dist/ai/backends/opencode.d.ts.map +1 -0
- package/dist/ai/backends/opencode.js +66 -0
- package/dist/ai/backends/opencode.js.map +1 -0
- package/dist/ai/index.d.ts +39 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +54 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/pricing.d.ts +84 -0
- package/dist/ai/pricing.d.ts.map +1 -0
- package/dist/ai/pricing.js +149 -0
- package/dist/ai/pricing.js.map +1 -0
- package/dist/ai/pricing.test.d.ts +2 -0
- package/dist/ai/pricing.test.d.ts.map +1 -0
- package/dist/ai/pricing.test.js +164 -0
- package/dist/ai/pricing.test.js.map +1 -0
- package/dist/ai/registry.d.ts +128 -0
- package/dist/ai/registry.d.ts.map +1 -0
- package/dist/ai/registry.js +192 -0
- package/dist/ai/registry.js.map +1 -0
- package/dist/ai/retry.d.ts +77 -0
- package/dist/ai/retry.d.ts.map +1 -0
- package/dist/ai/retry.js +100 -0
- package/dist/ai/retry.js.map +1 -0
- package/dist/ai/service.d.ts +124 -0
- package/dist/ai/service.d.ts.map +1 -0
- package/dist/ai/service.js +239 -0
- package/dist/ai/service.js.map +1 -0
- package/dist/ai/subprocess.d.ts +45 -0
- package/dist/ai/subprocess.d.ts.map +1 -0
- package/dist/ai/subprocess.js +90 -0
- package/dist/ai/subprocess.js.map +1 -0
- package/dist/ai/telemetry/cleanup.d.ts +30 -0
- package/dist/ai/telemetry/cleanup.d.ts.map +1 -0
- package/dist/ai/telemetry/cleanup.js +56 -0
- package/dist/ai/telemetry/cleanup.js.map +1 -0
- package/dist/ai/telemetry/logger.d.ts +76 -0
- package/dist/ai/telemetry/logger.d.ts.map +1 -0
- package/dist/ai/telemetry/logger.js +130 -0
- package/dist/ai/telemetry/logger.js.map +1 -0
- package/dist/ai/telemetry/run-log.d.ts +29 -0
- package/dist/ai/telemetry/run-log.d.ts.map +1 -0
- package/dist/ai/telemetry/run-log.js +43 -0
- package/dist/ai/telemetry/run-log.js.map +1 -0
- package/dist/ai/types.d.ts +235 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +34 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/cli/discover.d.ts.map +1 -1
- package/dist/cli/discover.js +0 -2
- package/dist/cli/discover.js.map +1 -1
- package/dist/cli/generate.d.ts +22 -14
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +91 -50
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/index.js +12 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/update.d.ts +13 -4
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +93 -131
- package/dist/cli/update.js.map +1 -1
- package/dist/config/defaults.d.ts +2 -2
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +2 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +175 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +36 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/generation/executor.d.ts.map +1 -1
- package/dist/generation/executor.js +2 -5
- package/dist/generation/executor.js.map +1 -1
- package/dist/generation/prompts/builder.d.ts +10 -0
- package/dist/generation/prompts/builder.d.ts.map +1 -1
- package/dist/generation/prompts/builder.js +77 -1
- package/dist/generation/prompts/builder.js.map +1 -1
- package/dist/generation/prompts/index.d.ts +1 -1
- package/dist/generation/prompts/index.d.ts.map +1 -1
- package/dist/generation/prompts/index.js +1 -1
- package/dist/generation/prompts/index.js.map +1 -1
- package/dist/generation/prompts/templates.d.ts +5 -0
- package/dist/generation/prompts/templates.d.ts.map +1 -1
- package/dist/generation/prompts/templates.js +94 -7
- package/dist/generation/prompts/templates.js.map +1 -1
- package/dist/generation/prompts/types.d.ts +2 -2
- package/dist/generation/prompts/types.js +1 -1
- package/dist/generation/writers/agents-md.d.ts +3 -59
- package/dist/generation/writers/agents-md.d.ts.map +1 -1
- package/dist/generation/writers/agents-md.js +11 -249
- package/dist/generation/writers/agents-md.js.map +1 -1
- package/dist/generation/writers/index.d.ts +1 -1
- package/dist/generation/writers/index.d.ts.map +1 -1
- package/dist/generation/writers/index.js +1 -1
- package/dist/generation/writers/index.js.map +1 -1
- package/dist/orchestration/index.d.ts +27 -0
- package/dist/orchestration/index.d.ts.map +1 -0
- package/dist/orchestration/index.js +34 -0
- package/dist/orchestration/index.js.map +1 -0
- package/dist/orchestration/pool.d.ts +62 -0
- package/dist/orchestration/pool.d.ts.map +1 -0
- package/dist/orchestration/pool.js +75 -0
- package/dist/orchestration/pool.js.map +1 -0
- package/dist/orchestration/progress.d.ts +124 -0
- package/dist/orchestration/progress.d.ts.map +1 -0
- package/dist/orchestration/progress.js +214 -0
- package/dist/orchestration/progress.js.map +1 -0
- package/dist/orchestration/runner.d.ts +76 -0
- package/dist/orchestration/runner.d.ts.map +1 -0
- package/dist/orchestration/runner.js +494 -0
- package/dist/orchestration/runner.js.map +1 -0
- package/dist/orchestration/types.d.ts +123 -0
- package/dist/orchestration/types.d.ts.map +1 -0
- package/dist/orchestration/types.js +11 -0
- package/dist/orchestration/types.js.map +1 -0
- package/dist/quality/density/validator.d.ts +38 -0
- package/dist/quality/density/validator.d.ts.map +1 -0
- package/dist/quality/density/validator.js +61 -0
- package/dist/quality/density/validator.js.map +1 -0
- package/dist/quality/inconsistency/code-vs-code.d.ts +26 -0
- package/dist/quality/inconsistency/code-vs-code.d.ts.map +1 -0
- package/dist/quality/inconsistency/code-vs-code.js +51 -0
- package/dist/quality/inconsistency/code-vs-code.js.map +1 -0
- package/dist/quality/inconsistency/code-vs-doc.d.ts +35 -0
- package/dist/quality/inconsistency/code-vs-doc.d.ts.map +1 -0
- package/dist/quality/inconsistency/code-vs-doc.js +59 -0
- package/dist/quality/inconsistency/code-vs-doc.js.map +1 -0
- package/dist/quality/inconsistency/code-vs-doc.test.d.ts +2 -0
- package/dist/quality/inconsistency/code-vs-doc.test.d.ts.map +1 -0
- package/dist/quality/inconsistency/code-vs-doc.test.js +196 -0
- package/dist/quality/inconsistency/code-vs-doc.test.js.map +1 -0
- package/dist/quality/inconsistency/reporter.d.ts +49 -0
- package/dist/quality/inconsistency/reporter.d.ts.map +1 -0
- package/dist/quality/inconsistency/reporter.js +99 -0
- package/dist/quality/inconsistency/reporter.js.map +1 -0
- package/dist/quality/index.d.ts +15 -0
- package/dist/quality/index.d.ts.map +1 -0
- package/dist/quality/index.js +25 -0
- package/dist/quality/index.js.map +1 -0
- package/dist/quality/types.d.ts +63 -0
- package/dist/quality/types.d.ts.map +1 -0
- package/dist/quality/types.js +5 -0
- package/dist/quality/types.js.map +1 -0
- package/dist/update/orchestrator.d.ts.map +1 -1
- package/dist/update/orchestrator.js +2 -1
- package/dist/update/orchestrator.js.map +1 -1
- package/dist/update/orphan-cleaner.js +1 -1
- package/dist/update/orphan-cleaner.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAkBH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,aAAa,EACb,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE9D,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost estimation engine with pricing table, prefix matching, and format helpers.
|
|
3
|
+
*
|
|
4
|
+
* Provides hardcoded per-model pricing for major AI providers (Claude, GPT, Gemini)
|
|
5
|
+
* and utility functions for estimating, looking up, and formatting costs.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
/** Per-model pricing rates in cost per million tokens. */
|
|
10
|
+
export interface ModelPricing {
|
|
11
|
+
/** Cost in USD per 1 million input tokens */
|
|
12
|
+
inputCostPerMTok: number;
|
|
13
|
+
/** Cost in USD per 1 million output tokens */
|
|
14
|
+
outputCostPerMTok: number;
|
|
15
|
+
}
|
|
16
|
+
/** Source of a cost estimate. */
|
|
17
|
+
export type CostSource = 'cli-reported' | 'estimated' | 'unavailable';
|
|
18
|
+
/** Result of a cost estimation with provenance tracking. */
|
|
19
|
+
export interface CostEstimate {
|
|
20
|
+
/** Estimated cost in USD (0 when unavailable) */
|
|
21
|
+
costUsd: number;
|
|
22
|
+
/** How the cost was determined */
|
|
23
|
+
source: CostSource;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hardcoded pricing for major AI models.
|
|
27
|
+
*
|
|
28
|
+
* Keys are model ID prefixes. Models with date suffixes (e.g.
|
|
29
|
+
* `claude-opus-4-5-20251101`) are matched via prefix lookup against these keys.
|
|
30
|
+
*
|
|
31
|
+
* Prices are in USD per million tokens, verified as of 2026-02-07.
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_MODEL_PRICING: Record<string, ModelPricing>;
|
|
34
|
+
/**
|
|
35
|
+
* Look up pricing for a model ID, with optional config overrides.
|
|
36
|
+
*
|
|
37
|
+
* Resolution order:
|
|
38
|
+
* 1. Exact match in merged table (overrides spread over defaults)
|
|
39
|
+
* 2. Prefix match with longest-key-first ordering to avoid ambiguity
|
|
40
|
+
* 3. `undefined` if no match found
|
|
41
|
+
*
|
|
42
|
+
* @param model - Model identifier (e.g. `"claude-opus-4-5-20251101"`)
|
|
43
|
+
* @param overrides - Optional pricing overrides from user config
|
|
44
|
+
* @returns Pricing rates or `undefined` for unknown models
|
|
45
|
+
*/
|
|
46
|
+
export declare function lookupPricing(model: string, overrides?: Record<string, ModelPricing>): ModelPricing | undefined;
|
|
47
|
+
/**
|
|
48
|
+
* Estimate the cost of an AI call.
|
|
49
|
+
*
|
|
50
|
+
* Resolution order:
|
|
51
|
+
* 1. CLI-reported cost (when available and > 0)
|
|
52
|
+
* 2. Pricing table estimate (input + output token costs)
|
|
53
|
+
* 3. Unavailable (unknown model, no CLI cost)
|
|
54
|
+
*
|
|
55
|
+
* All costs are rounded to 4 decimal places.
|
|
56
|
+
*
|
|
57
|
+
* @param model - Model identifier
|
|
58
|
+
* @param inputTokens - Number of input tokens consumed
|
|
59
|
+
* @param outputTokens - Number of output tokens generated
|
|
60
|
+
* @param cliReportedCost - Cost reported by the CLI (if available)
|
|
61
|
+
* @param overrides - Optional pricing overrides from user config
|
|
62
|
+
* @returns Cost estimate with source provenance
|
|
63
|
+
*/
|
|
64
|
+
export declare function estimateCost(model: string, inputTokens: number, outputTokens: number, cliReportedCost?: number, overrides?: Record<string, ModelPricing>): CostEstimate;
|
|
65
|
+
/**
|
|
66
|
+
* Format a cost value for display.
|
|
67
|
+
*
|
|
68
|
+
* @param costUsd - Cost in USD
|
|
69
|
+
* @param available - Whether the cost is available (false returns "N/A")
|
|
70
|
+
* @returns Formatted cost string (e.g. `"$0.1234"` or `"N/A"`)
|
|
71
|
+
*/
|
|
72
|
+
export declare function formatCost(costUsd: number, available: boolean): string;
|
|
73
|
+
/**
|
|
74
|
+
* Format a token count for display with appropriate suffix.
|
|
75
|
+
*
|
|
76
|
+
* - >= 1,000,000: `"1.5M"`
|
|
77
|
+
* - >= 1,000: `"42K"`
|
|
78
|
+
* - < 1,000: `"500"`
|
|
79
|
+
*
|
|
80
|
+
* @param count - Number of tokens
|
|
81
|
+
* @returns Formatted token count string
|
|
82
|
+
*/
|
|
83
|
+
export declare function formatTokens(count: number): string;
|
|
84
|
+
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/ai/pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,0DAA0D;AAC1D,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,gBAAgB,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,iCAAiC;AACjC,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,WAAW,GAAG,aAAa,CAAC;AAEtE,4DAA4D;AAC5D,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,MAAM,EAAE,UAAU,CAAC;CACpB;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAqB9D,CAAC;AAMF;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACvC,YAAY,GAAG,SAAS,CAoB1B;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,EACxB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACvC,YAAY,CAoBd;AAMD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAKtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWlD"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost estimation engine with pricing table, prefix matching, and format helpers.
|
|
3
|
+
*
|
|
4
|
+
* Provides hardcoded per-model pricing for major AI providers (Claude, GPT, Gemini)
|
|
5
|
+
* and utility functions for estimating, looking up, and formatting costs.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Default pricing table
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* Hardcoded pricing for major AI models.
|
|
14
|
+
*
|
|
15
|
+
* Keys are model ID prefixes. Models with date suffixes (e.g.
|
|
16
|
+
* `claude-opus-4-5-20251101`) are matched via prefix lookup against these keys.
|
|
17
|
+
*
|
|
18
|
+
* Prices are in USD per million tokens, verified as of 2026-02-07.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_MODEL_PRICING = {
|
|
21
|
+
// Claude (Anthropic) - verified 2026-02-07
|
|
22
|
+
'claude-opus-4-6': { inputCostPerMTok: 5, outputCostPerMTok: 25 },
|
|
23
|
+
'claude-opus-4-5': { inputCostPerMTok: 5, outputCostPerMTok: 25 },
|
|
24
|
+
'claude-opus-4-1': { inputCostPerMTok: 15, outputCostPerMTok: 75 },
|
|
25
|
+
'claude-opus-4': { inputCostPerMTok: 15, outputCostPerMTok: 75 },
|
|
26
|
+
'claude-sonnet-4-5': { inputCostPerMTok: 3, outputCostPerMTok: 15 },
|
|
27
|
+
'claude-sonnet-4': { inputCostPerMTok: 3, outputCostPerMTok: 15 },
|
|
28
|
+
'claude-haiku-4-5': { inputCostPerMTok: 1, outputCostPerMTok: 5 },
|
|
29
|
+
'claude-haiku-3-5': { inputCostPerMTok: 0.80, outputCostPerMTok: 4 },
|
|
30
|
+
'claude-haiku-3': { inputCostPerMTok: 0.25, outputCostPerMTok: 1.25 },
|
|
31
|
+
// OpenAI GPT - from web search 2026-02-07
|
|
32
|
+
'gpt-4o': { inputCostPerMTok: 2.50, outputCostPerMTok: 10 },
|
|
33
|
+
'gpt-4o-mini': { inputCostPerMTok: 0.15, outputCostPerMTok: 0.60 },
|
|
34
|
+
'gpt-4': { inputCostPerMTok: 30, outputCostPerMTok: 60 },
|
|
35
|
+
// Google Gemini - from web search 2026-02-07
|
|
36
|
+
'gemini-2.5-flash': { inputCostPerMTok: 0.15, outputCostPerMTok: 0.60 },
|
|
37
|
+
'gemini-2.5-pro': { inputCostPerMTok: 1.25, outputCostPerMTok: 10 },
|
|
38
|
+
'gemini-3-flash': { inputCostPerMTok: 0.50, outputCostPerMTok: 3 },
|
|
39
|
+
};
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Lookup
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Look up pricing for a model ID, with optional config overrides.
|
|
45
|
+
*
|
|
46
|
+
* Resolution order:
|
|
47
|
+
* 1. Exact match in merged table (overrides spread over defaults)
|
|
48
|
+
* 2. Prefix match with longest-key-first ordering to avoid ambiguity
|
|
49
|
+
* 3. `undefined` if no match found
|
|
50
|
+
*
|
|
51
|
+
* @param model - Model identifier (e.g. `"claude-opus-4-5-20251101"`)
|
|
52
|
+
* @param overrides - Optional pricing overrides from user config
|
|
53
|
+
* @returns Pricing rates or `undefined` for unknown models
|
|
54
|
+
*/
|
|
55
|
+
export function lookupPricing(model, overrides) {
|
|
56
|
+
const table = {
|
|
57
|
+
...DEFAULT_MODEL_PRICING,
|
|
58
|
+
...overrides,
|
|
59
|
+
};
|
|
60
|
+
// Exact match
|
|
61
|
+
if (table[model] !== undefined) {
|
|
62
|
+
return table[model];
|
|
63
|
+
}
|
|
64
|
+
// Prefix match: sort keys longest-first so longer prefixes win
|
|
65
|
+
const keys = Object.keys(table).sort((a, b) => b.length - a.length);
|
|
66
|
+
for (const key of keys) {
|
|
67
|
+
if (model.startsWith(key)) {
|
|
68
|
+
return table[key];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Cost estimation
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
/**
|
|
77
|
+
* Estimate the cost of an AI call.
|
|
78
|
+
*
|
|
79
|
+
* Resolution order:
|
|
80
|
+
* 1. CLI-reported cost (when available and > 0)
|
|
81
|
+
* 2. Pricing table estimate (input + output token costs)
|
|
82
|
+
* 3. Unavailable (unknown model, no CLI cost)
|
|
83
|
+
*
|
|
84
|
+
* All costs are rounded to 4 decimal places.
|
|
85
|
+
*
|
|
86
|
+
* @param model - Model identifier
|
|
87
|
+
* @param inputTokens - Number of input tokens consumed
|
|
88
|
+
* @param outputTokens - Number of output tokens generated
|
|
89
|
+
* @param cliReportedCost - Cost reported by the CLI (if available)
|
|
90
|
+
* @param overrides - Optional pricing overrides from user config
|
|
91
|
+
* @returns Cost estimate with source provenance
|
|
92
|
+
*/
|
|
93
|
+
export function estimateCost(model, inputTokens, outputTokens, cliReportedCost, overrides) {
|
|
94
|
+
// CLI-reported cost takes precedence when available and non-zero
|
|
95
|
+
if (cliReportedCost !== undefined && cliReportedCost > 0) {
|
|
96
|
+
return {
|
|
97
|
+
costUsd: Number(cliReportedCost.toFixed(4)),
|
|
98
|
+
source: 'cli-reported',
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
// Fall back to pricing table
|
|
102
|
+
const pricing = lookupPricing(model, overrides);
|
|
103
|
+
if (pricing === undefined) {
|
|
104
|
+
return { costUsd: 0, source: 'unavailable' };
|
|
105
|
+
}
|
|
106
|
+
const inputCost = (pricing.inputCostPerMTok * inputTokens) / 1_000_000;
|
|
107
|
+
const outputCost = (pricing.outputCostPerMTok * outputTokens) / 1_000_000;
|
|
108
|
+
const totalCost = Number((inputCost + outputCost).toFixed(4));
|
|
109
|
+
return { costUsd: totalCost, source: 'estimated' };
|
|
110
|
+
}
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
// Formatting helpers
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
/**
|
|
115
|
+
* Format a cost value for display.
|
|
116
|
+
*
|
|
117
|
+
* @param costUsd - Cost in USD
|
|
118
|
+
* @param available - Whether the cost is available (false returns "N/A")
|
|
119
|
+
* @returns Formatted cost string (e.g. `"$0.1234"` or `"N/A"`)
|
|
120
|
+
*/
|
|
121
|
+
export function formatCost(costUsd, available) {
|
|
122
|
+
if (!available) {
|
|
123
|
+
return 'N/A';
|
|
124
|
+
}
|
|
125
|
+
return `$${costUsd.toFixed(4)}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Format a token count for display with appropriate suffix.
|
|
129
|
+
*
|
|
130
|
+
* - >= 1,000,000: `"1.5M"`
|
|
131
|
+
* - >= 1,000: `"42K"`
|
|
132
|
+
* - < 1,000: `"500"`
|
|
133
|
+
*
|
|
134
|
+
* @param count - Number of tokens
|
|
135
|
+
* @returns Formatted token count string
|
|
136
|
+
*/
|
|
137
|
+
export function formatTokens(count) {
|
|
138
|
+
if (count >= 1_000_000) {
|
|
139
|
+
const millions = count / 1_000_000;
|
|
140
|
+
// Remove trailing zeros: 1.0 -> 1, 1.5 -> 1.5
|
|
141
|
+
return `${parseFloat(millions.toFixed(1))}M`;
|
|
142
|
+
}
|
|
143
|
+
if (count >= 1_000) {
|
|
144
|
+
const thousands = count / 1_000;
|
|
145
|
+
return `${parseFloat(thousands.toFixed(1))}K`;
|
|
146
|
+
}
|
|
147
|
+
return `${count}`;
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/ai/pricing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.test.d.ts","sourceRoot":"","sources":["../../src/ai/pricing.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { DEFAULT_MODEL_PRICING, lookupPricing, estimateCost, formatCost, formatTokens, } from './pricing.js';
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// DEFAULT_MODEL_PRICING
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
describe('DEFAULT_MODEL_PRICING', () => {
|
|
7
|
+
it('contains 15 models across Claude, GPT, and Gemini families', () => {
|
|
8
|
+
const keys = Object.keys(DEFAULT_MODEL_PRICING);
|
|
9
|
+
expect(keys).toHaveLength(15);
|
|
10
|
+
const claudeKeys = keys.filter((k) => k.startsWith('claude-'));
|
|
11
|
+
const gptKeys = keys.filter((k) => k.startsWith('gpt-'));
|
|
12
|
+
const geminiKeys = keys.filter((k) => k.startsWith('gemini-'));
|
|
13
|
+
expect(claudeKeys.length).toBe(9);
|
|
14
|
+
expect(gptKeys.length).toBe(3);
|
|
15
|
+
expect(geminiKeys.length).toBe(3);
|
|
16
|
+
});
|
|
17
|
+
it('has correct pricing for claude-sonnet-4', () => {
|
|
18
|
+
const pricing = DEFAULT_MODEL_PRICING['claude-sonnet-4'];
|
|
19
|
+
expect(pricing).toBeDefined();
|
|
20
|
+
expect(pricing.inputCostPerMTok).toBe(3);
|
|
21
|
+
expect(pricing.outputCostPerMTok).toBe(15);
|
|
22
|
+
});
|
|
23
|
+
it('has correct pricing for gpt-4o', () => {
|
|
24
|
+
const pricing = DEFAULT_MODEL_PRICING['gpt-4o'];
|
|
25
|
+
expect(pricing).toBeDefined();
|
|
26
|
+
expect(pricing.inputCostPerMTok).toBe(2.5);
|
|
27
|
+
expect(pricing.outputCostPerMTok).toBe(10);
|
|
28
|
+
});
|
|
29
|
+
it('has correct pricing for gemini-2.5-pro', () => {
|
|
30
|
+
const pricing = DEFAULT_MODEL_PRICING['gemini-2.5-pro'];
|
|
31
|
+
expect(pricing).toBeDefined();
|
|
32
|
+
expect(pricing.inputCostPerMTok).toBe(1.25);
|
|
33
|
+
expect(pricing.outputCostPerMTok).toBe(10);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// lookupPricing
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
describe('lookupPricing', () => {
|
|
40
|
+
it('returns exact match for known model', () => {
|
|
41
|
+
const result = lookupPricing('claude-opus-4-5');
|
|
42
|
+
expect(result).toBeDefined();
|
|
43
|
+
expect(result.inputCostPerMTok).toBe(5);
|
|
44
|
+
expect(result.outputCostPerMTok).toBe(25);
|
|
45
|
+
});
|
|
46
|
+
it('returns prefix match for model with date suffix', () => {
|
|
47
|
+
const result = lookupPricing('claude-opus-4-5-20251101');
|
|
48
|
+
expect(result).toBeDefined();
|
|
49
|
+
expect(result.inputCostPerMTok).toBe(5);
|
|
50
|
+
expect(result.outputCostPerMTok).toBe(25);
|
|
51
|
+
});
|
|
52
|
+
it('prefers longer prefix key over shorter one', () => {
|
|
53
|
+
// 'claude-opus-4-5' should match before 'claude-opus-4'
|
|
54
|
+
const result = lookupPricing('claude-opus-4-5-20251101');
|
|
55
|
+
expect(result).toBeDefined();
|
|
56
|
+
// claude-opus-4-5 has input=5, claude-opus-4 has input=15
|
|
57
|
+
expect(result.inputCostPerMTok).toBe(5);
|
|
58
|
+
});
|
|
59
|
+
it('returns undefined for unknown model', () => {
|
|
60
|
+
const result = lookupPricing('custom-model');
|
|
61
|
+
expect(result).toBeUndefined();
|
|
62
|
+
});
|
|
63
|
+
it('uses config overrides over defaults', () => {
|
|
64
|
+
const overrides = {
|
|
65
|
+
'my-model': { inputCostPerMTok: 1, outputCostPerMTok: 5 },
|
|
66
|
+
};
|
|
67
|
+
const result = lookupPricing('my-model', overrides);
|
|
68
|
+
expect(result).toBeDefined();
|
|
69
|
+
expect(result.inputCostPerMTok).toBe(1);
|
|
70
|
+
expect(result.outputCostPerMTok).toBe(5);
|
|
71
|
+
});
|
|
72
|
+
it('config overrides take precedence over hardcoded defaults', () => {
|
|
73
|
+
const overrides = {
|
|
74
|
+
'claude-sonnet-4': { inputCostPerMTok: 99, outputCostPerMTok: 99 },
|
|
75
|
+
};
|
|
76
|
+
const result = lookupPricing('claude-sonnet-4', overrides);
|
|
77
|
+
expect(result).toBeDefined();
|
|
78
|
+
expect(result.inputCostPerMTok).toBe(99);
|
|
79
|
+
expect(result.outputCostPerMTok).toBe(99);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// estimateCost
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
describe('estimateCost', () => {
|
|
86
|
+
it('returns CLI-reported cost when available and non-zero', () => {
|
|
87
|
+
const result = estimateCost('claude-sonnet-4', 1000, 100, 0.018);
|
|
88
|
+
expect(result.costUsd).toBe(0.018);
|
|
89
|
+
expect(result.source).toBe('cli-reported');
|
|
90
|
+
});
|
|
91
|
+
it('falls back to pricing table when CLI cost is zero', () => {
|
|
92
|
+
// claude-sonnet-4: input=3, output=15
|
|
93
|
+
// cost = (3 * 1_000_000 / 1_000_000) + (15 * 100_000 / 1_000_000) = 3 + 1.5 = 4.5
|
|
94
|
+
const result = estimateCost('claude-sonnet-4', 1_000_000, 100_000, 0);
|
|
95
|
+
expect(result.costUsd).toBe(4.5);
|
|
96
|
+
expect(result.source).toBe('estimated');
|
|
97
|
+
});
|
|
98
|
+
it('falls back to pricing table when CLI cost is undefined', () => {
|
|
99
|
+
const result = estimateCost('claude-sonnet-4', 1_000_000, 100_000);
|
|
100
|
+
expect(result.costUsd).toBe(4.5);
|
|
101
|
+
expect(result.source).toBe('estimated');
|
|
102
|
+
});
|
|
103
|
+
it('returns unavailable source when model is not in pricing table', () => {
|
|
104
|
+
const result = estimateCost('unknown-model', 1000, 100);
|
|
105
|
+
expect(result.costUsd).toBe(0);
|
|
106
|
+
expect(result.source).toBe('unavailable');
|
|
107
|
+
});
|
|
108
|
+
it('uses 4-decimal precision for estimated costs', () => {
|
|
109
|
+
// claude-haiku-3-5: input=0.80, output=4
|
|
110
|
+
// cost = (0.80 * 1234 / 1_000_000) + (4 * 567 / 1_000_000)
|
|
111
|
+
// = 0.0009872 + 0.002268 = 0.0032552
|
|
112
|
+
// rounded to 4 decimals = 0.0033
|
|
113
|
+
const result = estimateCost('claude-haiku-3-5', 1234, 567);
|
|
114
|
+
expect(result.costUsd).toBe(0.0033);
|
|
115
|
+
expect(result.source).toBe('estimated');
|
|
116
|
+
});
|
|
117
|
+
it('passes overrides to lookupPricing', () => {
|
|
118
|
+
const overrides = {
|
|
119
|
+
'my-custom': { inputCostPerMTok: 10, outputCostPerMTok: 20 },
|
|
120
|
+
};
|
|
121
|
+
// cost = (10 * 1_000_000 / 1_000_000) + (20 * 500_000 / 1_000_000) = 10 + 10 = 20
|
|
122
|
+
const result = estimateCost('my-custom', 1_000_000, 500_000, undefined, overrides);
|
|
123
|
+
expect(result.costUsd).toBe(20);
|
|
124
|
+
expect(result.source).toBe('estimated');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// formatCost
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
describe('formatCost', () => {
|
|
131
|
+
it('returns $X.XXXX with 4-decimal precision for available costs', () => {
|
|
132
|
+
expect(formatCost(0.1234, true)).toBe('$0.1234');
|
|
133
|
+
});
|
|
134
|
+
it('returns N/A when cost is unavailable', () => {
|
|
135
|
+
expect(formatCost(0, false)).toBe('N/A');
|
|
136
|
+
});
|
|
137
|
+
it('pads to 4 decimal places', () => {
|
|
138
|
+
expect(formatCost(1.5, true)).toBe('$1.5000');
|
|
139
|
+
});
|
|
140
|
+
it('rounds to 4 decimal places', () => {
|
|
141
|
+
expect(formatCost(0.123456, true)).toBe('$0.1235');
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
// formatTokens
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
describe('formatTokens', () => {
|
|
148
|
+
it('formats millions with M suffix', () => {
|
|
149
|
+
expect(formatTokens(1_500_000)).toBe('1.5M');
|
|
150
|
+
});
|
|
151
|
+
it('formats thousands with K suffix', () => {
|
|
152
|
+
expect(formatTokens(42_000)).toBe('42K');
|
|
153
|
+
});
|
|
154
|
+
it('formats small numbers without suffix', () => {
|
|
155
|
+
expect(formatTokens(500)).toBe('500');
|
|
156
|
+
});
|
|
157
|
+
it('formats exact million', () => {
|
|
158
|
+
expect(formatTokens(1_000_000)).toBe('1M');
|
|
159
|
+
});
|
|
160
|
+
it('formats exact thousand', () => {
|
|
161
|
+
expect(formatTokens(1_000)).toBe('1K');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
//# sourceMappingURL=pricing.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../../src/ai/pricing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend registry, factory, and auto-detection.
|
|
3
|
+
*
|
|
4
|
+
* Manages the set of registered AI CLI backends, selects the appropriate
|
|
5
|
+
* backend at runtime via auto-detection or explicit request, and provides
|
|
6
|
+
* actionable error messages when no CLI is found.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { AIBackend } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Registry of available AI CLI backends.
|
|
13
|
+
*
|
|
14
|
+
* Stores backends in insertion order, which determines the priority for
|
|
15
|
+
* auto-detection. Use {@link createBackendRegistry} to get a pre-populated
|
|
16
|
+
* registry with all supported backends.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const registry = createBackendRegistry();
|
|
21
|
+
* const claude = registry.get('claude');
|
|
22
|
+
* const all = registry.getAll(); // [ClaudeBackend, GeminiBackend, OpenCodeBackend]
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class BackendRegistry {
|
|
26
|
+
private readonly backends;
|
|
27
|
+
/**
|
|
28
|
+
* Register a backend adapter.
|
|
29
|
+
*
|
|
30
|
+
* @param backend - The backend to register (keyed by its `name` property)
|
|
31
|
+
*/
|
|
32
|
+
register(backend: AIBackend): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get a specific backend by name.
|
|
35
|
+
*
|
|
36
|
+
* @param name - The backend name (e.g., "claude", "gemini", "opencode")
|
|
37
|
+
* @returns The backend, or `undefined` if not registered
|
|
38
|
+
*/
|
|
39
|
+
get(name: string): AIBackend | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Get all registered backends in priority order.
|
|
42
|
+
*
|
|
43
|
+
* @returns Array of all registered backends
|
|
44
|
+
*/
|
|
45
|
+
getAll(): AIBackend[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Create a new backend registry pre-populated with all supported backends.
|
|
49
|
+
*
|
|
50
|
+
* Registration order determines auto-detection priority:
|
|
51
|
+
* 1. Claude (recommended, fully implemented)
|
|
52
|
+
* 2. Gemini (experimental, stub)
|
|
53
|
+
* 3. OpenCode (experimental, stub)
|
|
54
|
+
*
|
|
55
|
+
* @returns A populated {@link BackendRegistry}
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const registry = createBackendRegistry();
|
|
60
|
+
* const backend = await detectBackend(registry);
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function createBackendRegistry(): BackendRegistry;
|
|
64
|
+
/**
|
|
65
|
+
* Detect the first available backend on PATH in priority order.
|
|
66
|
+
*
|
|
67
|
+
* Iterates all registered backends and calls `isAvailable()` on each.
|
|
68
|
+
* Returns the first backend whose CLI is found, or `null` if none are
|
|
69
|
+
* available.
|
|
70
|
+
*
|
|
71
|
+
* Priority order is determined by registration order in
|
|
72
|
+
* {@link createBackendRegistry}: Claude > Gemini > OpenCode.
|
|
73
|
+
*
|
|
74
|
+
* @param registry - The backend registry to search
|
|
75
|
+
* @returns The first available backend, or `null` if none found
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* const registry = createBackendRegistry();
|
|
80
|
+
* const backend = await detectBackend(registry);
|
|
81
|
+
* if (backend) {
|
|
82
|
+
* console.log(`Using ${backend.name} backend`);
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export declare function detectBackend(registry: BackendRegistry): Promise<AIBackend | null>;
|
|
87
|
+
/**
|
|
88
|
+
* Get formatted install instructions for all registered backends.
|
|
89
|
+
*
|
|
90
|
+
* Returns a multi-line string suitable for error messages when no CLI
|
|
91
|
+
* is found. Matches the error message template from RESEARCH.md.
|
|
92
|
+
*
|
|
93
|
+
* @param registry - The backend registry
|
|
94
|
+
* @returns Formatted install instructions string
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const instructions = getInstallInstructions(registry);
|
|
99
|
+
* console.error(`No AI CLI found.\n\nInstall one of the following:\n\n${instructions}`);
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare function getInstallInstructions(registry: BackendRegistry): string;
|
|
103
|
+
/**
|
|
104
|
+
* Resolve a backend by name or auto-detect the best available one.
|
|
105
|
+
*
|
|
106
|
+
* - If `requested` is `'auto'`: runs {@link detectBackend} and throws with
|
|
107
|
+
* install instructions if nothing is found.
|
|
108
|
+
* - If `requested` is a specific name: looks it up in the registry, checks
|
|
109
|
+
* availability, and throws if not found or not available.
|
|
110
|
+
*
|
|
111
|
+
* @param registry - The backend registry
|
|
112
|
+
* @param requested - Backend name or `'auto'` for auto-detection
|
|
113
|
+
* @returns The resolved backend adapter
|
|
114
|
+
* @throws {AIServiceError} With code `CLI_NOT_FOUND` if no backend is available
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const registry = createBackendRegistry();
|
|
119
|
+
*
|
|
120
|
+
* // Auto-detect
|
|
121
|
+
* const backend = await resolveBackend(registry, 'auto');
|
|
122
|
+
*
|
|
123
|
+
* // Explicit selection
|
|
124
|
+
* const claude = await resolveBackend(registry, 'claude');
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export declare function resolveBackend(registry: BackendRegistry, requested: string | 'auto'): Promise<AIBackend>;
|
|
128
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/ai/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAU5C;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgC;IAEzD;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAIlC;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS;IAIxC;;;;OAIG;IACH,MAAM,IAAI,SAAS,EAAE;CAGtB;AAMD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAMvD;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOxF;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAKxE;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,OAAO,CAAC,SAAS,CAAC,CAmCpB"}
|